Import Upstream version 1.0.33

This commit is contained in:
Guus Sliepen 2019-08-26 13:44:48 +02:00
parent e0e55285b8
commit 5969674c46
109 changed files with 5599 additions and 5444 deletions

View file

@ -1,3 +1,45 @@
Version 1.0.33 November 04 2017
------------------------------------------------------------------------
Guus Sliepen (31):
Udpate THANKS.
Fix a potential memory leak.
Use AC_CONFIG_MACRO_DIR().
Give absolute path for #include to AC_CHECK_HEADERS().
Prepare for automatic code formatting using Artistic Style.
Never remove items from cmdline_conf.
Use stack-allocated strings for temporary filenames.
Fix a few minor memory leaks.
Remove unused/obsolete checks from configure.ac.
Use getcwd() instead of get_current_dir_name().
Remove xmalloc.c, backport xalloc.h from tinc 1.1.
Update all header guards.
Convert sizeof foo to sizeof(foo).
Reformat all code using astyle.
Don't call ERR_remove_state().
Unconditionally include stdbool.h and inttypes.h.
Remove more obsolete autoconf checks.
Remove obsolete m4/README.
Fix some "make distcheck" errors.
Add some information about the requirements of a chroot environment.
Handle tun/tap device returning EPERM or EBUSY.
Disable PMTU discovery when TCPOnly is used.
Fix all -Wall -W compiler warnings.
Realign comments.
Remove unused functions.
Ensure all parameters have names in header files.
Support autoconf's --runstatedir option.
Const correctness.
Fix compilation errors when --enable-uml is used.
Update THANKS.
Releasing 1.0.33.
Rafael Sadowski (1):
fix tinc.conf for OpenBSD
nemunaire (1):
Allow compilation from a build directory
Version 1.0.32 September 02 2017 Version 1.0.32 September 02 2017
------------------------------------------------------------------------ ------------------------------------------------------------------------
@ -183,7 +225,20 @@ VittGam (1):
Version 1.0.24 May 11 2014 Version 1.0.24 May 11 2014
------------------------------------------------------------------------ ------------------------------------------------------------------------
Guus Sliepen (13): Guus Sliepen (26):
Mention in the manual that multiple Address staments are allowed.
If no Port is specified, set myport to actual port of first listening socket.
Enable compiler hardening flags by default.
Update support for Solaris.
Include <limits.h> for PATH_MAX.
Stricter check for raw socket support.
Use hardcoded value for TUNNEWPPA if net/if_tun.h is missing on Solaris.
Fix incorrectly merged bits from 80cd2ff73071941a5356555b85a00ee90dfd0e16.
Don't enable -fstack-protector-all.
Remove or lower the priority of some debug messages.
Clarify StrictSubnets.
Attribution for various contributors.
Handle errors from TAP-Win32/64 adapter in a better way.
Remove useless variable 'hard' from try_harder(). Remove useless variable 'hard' from try_harder().
Merge pull request #14 from luckyhacky/master Merge pull request #14 from luckyhacky/master
Add an autoconf check for res_init(). Add an autoconf check for res_init().
@ -203,40 +258,22 @@ Steffan Karger (3):
Use cryptographically strong random when generating keys. Use cryptographically strong random when generating keys.
Check RAND_bytes() return value, fail when getting random fails. Check RAND_bytes() return value, fail when getting random fails.
Florent Clairambault (2):
Adding "conf.d" configuration dir support.
Adding some documentation around the /etc/tinc/$NET/conf.d directory.
Armin Fisslthaler (1): Armin Fisslthaler (1):
reload /etc/resolv.conf in SIGALRM handler reload /etc/resolv.conf in SIGALRM handler
Loic Dachary (1): Loic Dachary (1):
fix documentation typo fix documentation typo
luckyhacky (1):
update to openssl version 1.0.1g due to lack of heartbleed bug in prior version of openssl
refs/tags/1.0.23-android-1 March 11 2014
------------------------------------------------------------------------
Guus Sliepen (13):
Mention in the manual that multiple Address staments are allowed.
If no Port is specified, set myport to actual port of first listening socket.
Enable compiler hardening flags by default.
Update support for Solaris.
Include <limits.h> for PATH_MAX.
Stricter check for raw socket support.
Use hardcoded value for TUNNEWPPA if net/if_tun.h is missing on Solaris.
Fix incorrectly merged bits from 80cd2ff73071941a5356555b85a00ee90dfd0e16.
Don't enable -fstack-protector-all.
Remove or lower the priority of some debug messages.
Clarify StrictSubnets.
Attribution for various contributors.
Handle errors from TAP-Win32/64 adapter in a better way.
Florent Clairambault (2):
Adding "conf.d" configuration dir support.
Adding some documentation around the /etc/tinc/$NET/conf.d directory.
Vilbrekin (1): Vilbrekin (1):
Update android build instructions. Disable PIE as this is not supported on some devices. Update android build instructions. Disable PIE as this is not supported on some devices.
luckyhacky (1):
update to openssl version 1.0.1g due to lack of heartbleed bug in prior version of openssl
Version 1.0.23 October 19 2013 Version 1.0.23 October 19 2013
------------------------------------------------------------------------ ------------------------------------------------------------------------

View file

@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS = gnu AUTOMAKE_OPTIONS = gnu
SUBDIRS = m4 src doc distro SUBDIRS = src doc distro
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
@ -10,3 +10,6 @@ EXTRA_DIST = COPYING.README README.android
ChangeLog: ChangeLog:
git log > ChangeLog git log > ChangeLog
astyle:
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]

View file

@ -239,7 +239,6 @@ LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@ LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@ LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@ MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@ MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@ OBJEXT = @OBJEXT@
@ -311,7 +310,7 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = gnu AUTOMAKE_OPTIONS = gnu
SUBDIRS = m4 src doc distro SUBDIRS = src doc distro
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = COPYING.README README.android EXTRA_DIST = COPYING.README README.android
all: config.h all: config.h
@ -320,7 +319,7 @@ all: config.h
.SUFFIXES: .SUFFIXES:
am--refresh: Makefile am--refresh: Makefile
@: @:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \ @for dep in $?; do \
case '$(am__configure_deps)' in \ case '$(am__configure_deps)' in \
*$$dep*) \ *$$dep*) \
@ -346,9 +345,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck $(SHELL) ./config.status --recheck
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(top_srcdir)/configure: $(am__configure_deps)
$(am__cd) $(srcdir) && $(AUTOCONF) $(am__cd) $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(ACLOCAL_M4): $(am__aclocal_m4_deps)
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
$(am__aclocal_m4_deps): $(am__aclocal_m4_deps):
@ -359,7 +358,7 @@ config.h: stamp-h1
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1 @rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status config.h cd $(top_builddir) && $(SHELL) ./config.status config.h
$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(srcdir)/config.h.in: $(am__configure_deps)
($(am__cd) $(top_srcdir) && $(AUTOHEADER)) ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
rm -f stamp-h1 rm -f stamp-h1
touch $@ touch $@
@ -795,6 +794,9 @@ uninstall-am:
ChangeLog: ChangeLog:
git log > ChangeLog git log > ChangeLog
astyle:
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]
# Tell versions [3.59,3.63) of GNU make to not export all variables. # Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded. # Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT: .NOEXPORT:

9
NEWS
View file

@ -1,3 +1,12 @@
Version 1.0.33 November 4 2017
* Allow compilation from a build directory.
* Source code cleanups.
* Fix some options specified on the command line not surviving a HUP signal.
* Handle tun/tap device returning EPERM or EBUSY.
* Disable PMTUDiscovery when TCPOnly is used.
* Support the --runstatedir option of the autoconf 2.70.
Version 1.0.32 September 2 2017 Version 1.0.32 September 2 2017
* Fix segmentation fault when using Cipher = none. * Fix segmentation fault when using Cipher = none.

2
README
View file

@ -1,4 +1,4 @@
This is the README file for tinc version 1.0.32. Installation This is the README file for tinc version 1.0.33. Installation
instructions may be found in the INSTALL file. instructions may be found in the INSTALL file.
tinc is Copyright (C) 1998-2017 by: tinc is Copyright (C) 1998-2017 by:

30
THANKS
View file

@ -1,25 +1,36 @@
We would like to thank the following people for their contributions to tinc: We would like to thank the following people for their contributions to tinc:
* Alexander Reil and Gemeinde Berg * Alexander Reil and Gemeinde Berg
* Alexander Ried
* Alexis Hildebrandt * Alexis Hildebrandt
* Allesandro Gatti * Allesandro Gatti
* Andreas van Cranenburgh * Andreas van Cranenburgh
* Anthony G. Basile * Anthony G. Basile
* Armin Fisslthaler
* Armijn Hemel * Armijn Hemel
* Armin Fisslthaler
* Aron Cowan
* Ashish Bajaj
* Baptiste Jonglez * Baptiste Jonglez
* Borg * Borg
* Brandon Black * Brandon Black
* Cheng LI
* Cris van Pelt * Cris van Pelt
* Darius Jahandarie * Darius Jahandarie
* Dato Simó
* David Pflug * David Pflug
* Delf Eldkraft * Delf Eldkraft
* Dennis Joachimsthaler
* dnk * dnk
* Élie Bouttier * Élie Bouttier
* Enrique Zanardi * Enrique Zanardi
* Erik Tews
* Etienne Dechamps
* Florent Clairambault * Florent Clairambault
* Florian Forster
* Florian Klink
* Florian Weik * Florian Weik
* Flynn Marquardt * Flynn Marquardt
* Franz Pletz
* Gary Kessler and Claudia Gonzalez * Gary Kessler and Claudia Gonzalez
* Grzegorz Dymarek * Grzegorz Dymarek
* Gusariev Oleksandr * Gusariev Oleksandr
@ -43,6 +54,7 @@ We would like to thank the following people for their contributions to tinc:
* Loïc Dachary * Loïc Dachary
* Loïc Grenié * Loïc Grenié
* Lubomír Bulej * Lubomír Bulej
* luckyhacky
* LunarShaddow * LunarShaddow
* Mads Kiilerich * Mads Kiilerich
* Marc A. Lehmann * Marc A. Lehmann
@ -52,6 +64,7 @@ We would like to thank the following people for their contributions to tinc:
* Martin Kihlgren * Martin Kihlgren
* Martin Schobert * Martin Schobert
* Martin Schürrer * Martin Schürrer
* Martin Weinelt
* Matias Carrasco * Matias Carrasco
* Max Rijevski * Max Rijevski
* Menno Smits * Menno Smits
@ -59,14 +72,21 @@ We would like to thank the following people for their contributions to tinc:
* Michael Tokarev * Michael Tokarev
* Miles Nordin * Miles Nordin
* Nathan Stratton Treadway * Nathan Stratton Treadway
* Murat Donmez
* Nick Hibma * Nick Hibma
* Nick Patavalis * Nick Patavalis
* Paul Littlefield * Paul Littlefield
* Philipp Babel * Philipp Babel
* Pierre Emeriaud
* Pierre-Olivier Mercier
* Rafael Sadowski
* Rafał Leśniak
* Rhosyn Celyn * Rhosyn Celyn
* Robert van der Meulen * Robert van der Meulen
* Rumko * Rumko
* Ryan Miller
* Sam Bryan * Sam Bryan
* Samuel Thibault
* Saverio Proto * Saverio Proto
* Scott Lamb * Scott Lamb
* Steffan Karger * Steffan Karger
@ -82,12 +102,16 @@ We would like to thank the following people for their contributions to tinc:
* Ulrich Seifert * Ulrich Seifert
* Vil Brekin * Vil Brekin
* Vittorio Gambaletta * Vittorio Gambaletta
* Wendy Willard
* Wessel Dankers * Wessel Dankers
* William A. Kennington III
* William McArthur * William McArthur
* Wouter van Heyst * Wouter van Heyst
* xentec
* 戴 鸣 * 戴 鸣
And everyone we forgot (if we did, please let us know). Thank you! And everyone we forgot (if we did, please let us know). Thank you!
Ivo Timmermans ---
Guus Sliepen Ivo Timmermans,
Guus Sliepen.

36
aclocal.m4 vendored
View file

@ -921,42 +921,6 @@ fi
rmdir .tst 2>/dev/null rmdir .tst 2>/dev/null
AC_SUBST([am__leading_dot])]) AC_SUBST([am__leading_dot])])
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
# From Jim Meyering
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_MAINTAINER_MODE([DEFAULT-MODE])
# ----------------------------------
# Control maintainer-specific portions of Makefiles.
# Default is to disable them, unless 'enable' is passed literally.
# For symmetry, 'disable' may be passed as well. Anyway, the user
# can override the default with the --enable/--disable switch.
AC_DEFUN([AM_MAINTAINER_MODE],
[m4_case(m4_default([$1], [disable]),
[enable], [m4_define([am_maintainer_other], [disable])],
[disable], [m4_define([am_maintainer_other], [enable])],
[m4_define([am_maintainer_other], [enable])
m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
dnl maintainer-mode's default is 'disable' unless 'enable' is passed
AC_ARG_ENABLE([maintainer-mode],
[AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
am_maintainer_other[ make rules and dependencies not useful
(and sometimes confusing) to the casual installer])],
[USE_MAINTAINER_MODE=$enableval],
[USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
MAINT=$MAINTAINER_MODE_TRUE
AC_SUBST([MAINT])dnl
]
)
# Check to see how 'make' treats includes. -*- Autoconf -*- # Check to see how 'make' treats includes. -*- Autoconf -*-
# Copyright (C) 2001-2017 Free Software Foundation, Inc. # Copyright (C) 2001-2017 Free Software Foundation, Inc.

View file

@ -73,9 +73,6 @@
/* DragonFly */ /* DragonFly */
#undef HAVE_DRAGONFLY #undef HAVE_DRAGONFLY
/* Define to 1 if you have the `ERR_remove_state' function. */
#undef HAVE_ERR_REMOVE_STATE
/* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */ /* Define to 1 if you have the `EVP_CIPHER_CTX_new' function. */
#undef HAVE_EVP_CIPHER_CTX_NEW #undef HAVE_EVP_CIPHER_CTX_NEW
@ -97,9 +94,6 @@
/* FreeBSD */ /* FreeBSD */
#undef HAVE_FREEBSD #undef HAVE_FREEBSD
/* Define to 1 if you have the `ftime' function. */
#undef HAVE_FTIME
/* Define to 1 if you have the <getopt.h> header file. */ /* Define to 1 if you have the <getopt.h> header file. */
#undef HAVE_GETOPT_H #undef HAVE_GETOPT_H
@ -109,9 +103,6 @@
/* Define to 1 if you have the `gettimeofday' function. */ /* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY #undef HAVE_GETTIMEOFDAY
/* Define to 1 if you have the `get_current_dir_name' function. */
#undef HAVE_GET_CURRENT_DIR_NAME
/* Define to 1 if you have the <inttypes.h> header file. */ /* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H #undef HAVE_INTTYPES_H
@ -247,9 +238,6 @@
/* Define to 1 if you have the `putenv' function. */ /* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV #undef HAVE_PUTENV
/* Define to 1 if you have the `random' function. */
#undef HAVE_RANDOM
/* Define to 1 if you have the `RAND_bytes' function. */ /* Define to 1 if you have the `RAND_bytes' function. */
#undef HAVE_RAND_BYTES #undef HAVE_RAND_BYTES
@ -259,30 +247,18 @@
/* Define to 1 if you have the `RSA_set0_key' function. */ /* Define to 1 if you have the `RSA_set0_key' function. */
#undef HAVE_RSA_SET0_KEY #undef HAVE_RSA_SET0_KEY
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if the system has the type `socklen_t'. */ /* Define to 1 if the system has the type `socklen_t'. */
#undef HAVE_SOCKLEN_T #undef HAVE_SOCKLEN_T
/* Solaris/SunOS */ /* Solaris/SunOS */
#undef HAVE_SOLARIS #undef HAVE_SOLARIS
/* Define to 1 if you have the <stdbool.h> header file. */
#undef HAVE_STDBOOL_H
/* Define to 1 if you have the <stdint.h> header file. */ /* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H #undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */ /* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H #undef HAVE_STDLIB_H
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */ /* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H #undef HAVE_STRINGS_H
@ -292,9 +268,6 @@
/* Define to 1 if you have the `strsignal' function. */ /* Define to 1 if you have the `strsignal' function. */
#undef HAVE_STRSIGNAL #undef HAVE_STRSIGNAL
/* Define to 1 if you have the `strtol' function. */
#undef HAVE_STRTOL
/* Define to 1 if the system has the type `struct addrinfo'. */ /* Define to 1 if the system has the type `struct addrinfo'. */
#undef HAVE_STRUCT_ADDRINFO #undef HAVE_STRUCT_ADDRINFO
@ -373,9 +346,6 @@
/* Define to 1 if you have the <sys/wait.h> header file. */ /* Define to 1 if you have the <sys/wait.h> header file. */
#undef HAVE_SYS_WAIT_H #undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the <time.h> header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the <unistd.h> header file. */ /* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H #undef HAVE_UNISTD_H
@ -388,9 +358,6 @@
/* Define to 1 if you have the `vsyslog' function. */ /* Define to 1 if you have the `vsyslog' function. */
#undef HAVE_VSYSLOG #undef HAVE_VSYSLOG
/* Define to 1 if you have the `writev' function. */
#undef HAVE_WRITEV
/* have zlib compression support */ /* have zlib compression support */
#undef HAVE_ZLIB #undef HAVE_ZLIB
@ -427,12 +394,6 @@
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS #undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
/* Enable extensions on AIX 3, Interix. */ /* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE #ifndef _ALL_SOURCE
# undef _ALL_SOURCE # undef _ALL_SOURCE
@ -477,15 +438,5 @@
/* Defined if the __malloc__ attribute is not supported. */ /* Defined if the __malloc__ attribute is not supported. */
#undef __malloc__ #undef __malloc__
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> does not define. */ /* Define to `int' if <sys/types.h> does not define. */
#undef pid_t #undef pid_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
#undef volatile

417
configure vendored
View file

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for tinc 1.0.32. # Generated by GNU Autoconf 2.69 for tinc 1.0.33.
# #
# #
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -577,8 +577,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='tinc' PACKAGE_NAME='tinc'
PACKAGE_TARNAME='tinc' PACKAGE_TARNAME='tinc'
PACKAGE_VERSION='1.0.32' PACKAGE_VERSION='1.0.33'
PACKAGE_STRING='tinc 1.0.32' PACKAGE_STRING='tinc 1.0.33'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
PACKAGE_URL='' PACKAGE_URL=''
@ -675,9 +675,6 @@ CPPFLAGS
LDFLAGS LDFLAGS
CFLAGS CFLAGS
CC CC
MAINT
MAINTAINER_MODE_FALSE
MAINTAINER_MODE_TRUE
AM_BACKSLASH AM_BACKSLASH
AM_DEFAULT_VERBOSITY AM_DEFAULT_VERBOSITY
AM_DEFAULT_V AM_DEFAULT_V
@ -748,7 +745,6 @@ ac_subst_files=''
ac_user_opts=' ac_user_opts='
enable_option_checking enable_option_checking
enable_silent_rules enable_silent_rules
enable_maintainer_mode
enable_dependency_tracking enable_dependency_tracking
enable_uml enable_uml
enable_vde enable_vde
@ -1331,7 +1327,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures tinc 1.0.32 to adapt to many kinds of systems. \`configure' configures tinc 1.0.33 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1402,7 +1398,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of tinc 1.0.32:";; short | recursive ) echo "Configuration of tinc 1.0.33:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1412,9 +1408,6 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-silent-rules less verbose build output (undo: "make V=1") --enable-silent-rules less verbose build output (undo: "make V=1")
--disable-silent-rules verbose build output (undo: "make V=0") --disable-silent-rules verbose build output (undo: "make V=0")
--enable-maintainer-mode
enable make rules and dependencies not useful (and
sometimes confusing) to the casual installer
--enable-dependency-tracking --enable-dependency-tracking
do not reject slow dependency extractors do not reject slow dependency extractors
--disable-dependency-tracking --disable-dependency-tracking
@ -1528,7 +1521,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
tinc configure 1.0.32 tinc configure 1.0.33
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -1993,7 +1986,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by tinc $as_me 1.0.32, which was It was created by tinc $as_me 1.0.33, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -2857,7 +2850,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='tinc' PACKAGE='tinc'
VERSION='1.0.32' VERSION='1.0.33'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -2953,28 +2946,6 @@ fi
ac_config_headers="$ac_config_headers config.h" ac_config_headers="$ac_config_headers config.h"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
# Check whether --enable-maintainer-mode was given.
if test "${enable_maintainer_mode+set}" = set; then :
enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
else
USE_MAINTAINER_MODE=no
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
$as_echo "$USE_MAINTAINER_MODE" >&6; }
if test $USE_MAINTAINER_MODE = yes; then
MAINTAINER_MODE_TRUE=
MAINTAINER_MODE_FALSE='#'
else
MAINTAINER_MODE_TRUE='#'
MAINTAINER_MODE_FALSE=
fi
MAINT=$MAINTAINER_MODE_TRUE
# Check whether --enable-silent-rules was given. # Check whether --enable-silent-rules was given.
if test "${enable_silent_rules+set}" = set; then : if test "${enable_silent_rules+set}" = set; then :
enableval=$enable_silent_rules; enableval=$enable_silent_rules;
@ -5786,119 +5757,7 @@ fi;
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 for ac_header in syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/wait.h netdb.h arpa/inet.h arpa/nameser.h dirent.h getopt.h
$as_echo_n "checking for ANSI C header files... " >&6; }
if ${ac_cv_header_stdc+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_header_stdc=yes
else
ac_cv_header_stdc=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <string.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "memchr" >/dev/null 2>&1; then :
else
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdlib.h>
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "free" >/dev/null 2>&1; then :
else
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
if test "$cross_compiling" = yes; then :
:
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ctype.h>
#include <stdlib.h>
#if ((' ' & 0x0FF) == 0x020)
# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#else
# define ISLOWER(c) \
(('a' <= (c) && (c) <= 'i') \
|| ('j' <= (c) && (c) <= 'r') \
|| ('s' <= (c) && (c) <= 'z'))
# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
#endif
#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int
main ()
{
int i;
for (i = 0; i < 256; i++)
if (XOR (islower (i), ISLOWER (i))
|| toupper (i) != TOUPPER (i))
return 2;
return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
else
ac_cv_header_stdc=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
$as_echo "$ac_cv_header_stdc" >&6; }
if test $ac_cv_header_stdc = yes; then
$as_echo "#define STDC_HEADERS 1" >>confdefs.h
fi
for ac_header in stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h time.h sys/uio.h sys/wait.h netdb.h arpa/inet.h arpa/nameser.h dirent.h getopt.h
do : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@ -5914,7 +5773,7 @@ done
for ac_header in net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h for ac_header in net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h
do : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"src/have.h\" ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"$srcdir/src/have.h\"
" "
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
@ -5929,7 +5788,7 @@ done
for ac_header in netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h for ac_header in netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h
do : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"src/have.h\" ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"$srcdir/src/have.h\"
" "
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
@ -5944,7 +5803,7 @@ done
for ac_header in netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h for ac_header in netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h
do : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"src/have.h\" ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include \"$srcdir/src/have.h\"
" "
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
@ -5957,121 +5816,6 @@ fi
done done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
if ${ac_cv_c_const+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
#ifndef __cplusplus
/* Ultrix mips cc rejects this sort of thing. */
typedef int charset[2];
const charset cs = { 0, 0 };
/* SunOS 4.1.1 cc rejects this. */
char const *const *pcpcc;
char **ppc;
/* NEC SVR4.0.2 mips cc rejects this. */
struct point {int x, y;};
static struct point const zero = {0,0};
/* AIX XL C 1.02.0.0 rejects this.
It does not let you subtract one const X* pointer from another in
an arm of an if-expression whose if-part is not a constant
expression */
const char *g = "string";
pcpcc = &g + (g ? g-g : 0);
/* HPUX 7.0 cc rejects these. */
++pcpcc;
ppc = (char**) pcpcc;
pcpcc = (char const *const *) ppc;
{ /* SCO 3.2v4 cc rejects this sort of thing. */
char tx;
char *t = &tx;
char const *s = 0 ? (char *) 0 : (char const *) 0;
*t++ = 0;
if (s) return 0;
}
{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
int x[] = {25, 17};
const int *foo = &x[0];
++foo;
}
{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
typedef const int *iptr;
iptr p = 0;
++p;
}
{ /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
"k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
struct s { int j; const int *ap[3]; } bx;
struct s *b = &bx; b->j = 5;
}
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
const int foo = 10;
if (!foo) return 0;
}
return !cs[0] && !zero.x;
#endif
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_c_const=yes
else
ac_cv_c_const=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
$as_echo "$ac_cv_c_const" >&6; }
if test $ac_cv_c_const = no; then
$as_echo "#define const /**/" >>confdefs.h
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5
$as_echo_n "checking for working volatile... " >&6; }
if ${ac_cv_c_volatile+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
volatile int x;
int * volatile y = (int *) 0;
return !x && !y;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_c_volatile=yes
else
ac_cv_c_volatile=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5
$as_echo "$ac_cv_c_volatile" >&6; }
if test $ac_cv_c_volatile = no; then
$as_echo "#define volatile /**/" >>confdefs.h
fi
ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default"
if test "x$ac_cv_type_pid_t" = xyes; then : if test "x$ac_cv_type_pid_t" = xyes; then :
@ -6081,87 +5825,6 @@ cat >>confdefs.h <<_ACEOF
#define pid_t int #define pid_t int
_ACEOF _ACEOF
fi
ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
if test "x$ac_cv_type_size_t" = xyes; then :
else
cat >>confdefs.h <<_ACEOF
#define size_t unsigned int
_ACEOF
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
if ${ac_cv_header_time+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
int
main ()
{
if ((struct tm *) 0)
return 0;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_header_time=yes
else
ac_cv_header_time=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
$as_echo "$ac_cv_header_time" >&6; }
if test $ac_cv_header_time = yes; then
$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
if ${ac_cv_struct_tm+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
#include <time.h>
int
main ()
{
struct tm tm;
int *p = &tm.tm_sec;
return !p;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_struct_tm=time.h
else
ac_cv_struct_tm=sys/time.h
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5
$as_echo "$ac_cv_struct_tm" >&6; }
if test $ac_cv_struct_tm = sys/time.h; then
$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h
fi fi
@ -6200,7 +5863,7 @@ $as_echo "#define __malloc__ /**/" >>confdefs.h
fi fi
ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_socklen_t" = xyes; then : if test "x$ac_cv_type_socklen_t" = xyes; then :
@ -6211,7 +5874,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct ether_header" "ac_cv_type_struct_ether_header" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct ether_header" "ac_cv_type_struct_ether_header" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_ether_header" = xyes; then : if test "x$ac_cv_type_struct_ether_header" = xyes; then :
@ -6222,7 +5885,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct arphdr" "ac_cv_type_struct_arphdr" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct arphdr" "ac_cv_type_struct_arphdr" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_arphdr" = xyes; then : if test "x$ac_cv_type_struct_arphdr" = xyes; then :
@ -6233,7 +5896,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct ether_arp" "ac_cv_type_struct_ether_arp" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct ether_arp" "ac_cv_type_struct_ether_arp" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_ether_arp" = xyes; then : if test "x$ac_cv_type_struct_ether_arp" = xyes; then :
@ -6244,7 +5907,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct in_addr" "ac_cv_type_struct_in_addr" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct in_addr" "ac_cv_type_struct_in_addr" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_in_addr" = xyes; then : if test "x$ac_cv_type_struct_in_addr" = xyes; then :
@ -6255,7 +5918,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct addrinfo" "ac_cv_type_struct_addrinfo" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct addrinfo" "ac_cv_type_struct_addrinfo" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_addrinfo" = xyes; then : if test "x$ac_cv_type_struct_addrinfo" = xyes; then :
@ -6266,7 +5929,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct ip" "ac_cv_type_struct_ip" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct ip" "ac_cv_type_struct_ip" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_ip" = xyes; then : if test "x$ac_cv_type_struct_ip" = xyes; then :
@ -6277,7 +5940,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct icmp" "ac_cv_type_struct_icmp" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct icmp" "ac_cv_type_struct_icmp" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_icmp" = xyes; then : if test "x$ac_cv_type_struct_icmp" = xyes; then :
@ -6288,7 +5951,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_in6_addr" = xyes; then : if test "x$ac_cv_type_struct_in6_addr" = xyes; then :
@ -6299,7 +5962,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct sockaddr_in6" "ac_cv_type_struct_sockaddr_in6" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_sockaddr_in6" = xyes; then : if test "x$ac_cv_type_struct_sockaddr_in6" = xyes; then :
@ -6310,7 +5973,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct ip6_hdr" "ac_cv_type_struct_ip6_hdr" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct ip6_hdr" "ac_cv_type_struct_ip6_hdr" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_ip6_hdr" = xyes; then : if test "x$ac_cv_type_struct_ip6_hdr" = xyes; then :
@ -6321,7 +5984,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct icmp6_hdr" "ac_cv_type_struct_icmp6_hdr" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct icmp6_hdr" "ac_cv_type_struct_icmp6_hdr" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_icmp6_hdr" = xyes; then : if test "x$ac_cv_type_struct_icmp6_hdr" = xyes; then :
@ -6332,7 +5995,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct nd_neighbor_solicit" "ac_cv_type_struct_nd_neighbor_solicit" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct nd_neighbor_solicit" "ac_cv_type_struct_nd_neighbor_solicit" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_nd_neighbor_solicit" = xyes; then : if test "x$ac_cv_type_struct_nd_neighbor_solicit" = xyes; then :
@ -6343,7 +6006,7 @@ _ACEOF
fi fi
ac_fn_c_check_type "$LINENO" "struct nd_opt_hdr" "ac_cv_type_struct_nd_opt_hdr" "#include \"src/have.h\" ac_fn_c_check_type "$LINENO" "struct nd_opt_hdr" "ac_cv_type_struct_nd_opt_hdr" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_type_struct_nd_opt_hdr" = xyes; then : if test "x$ac_cv_type_struct_nd_opt_hdr" = xyes; then :
@ -6389,7 +6052,7 @@ cat >>confdefs.h <<_ACEOF
_ACEOF _ACEOF
for ac_func in asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall pselect putenv random select strdup strerror strsignal strtol system unsetenv usleep vsyslog writev devname fdevname for ac_func in asprintf daemon fchmod flock fork gettimeofday mlockall pselect putenv strsignal system unsetenv usleep vsyslog devname fdevname
do : do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -6528,7 +6191,7 @@ fi
fi fi
ac_fn_c_check_decl "$LINENO" "freeaddrinfo" "ac_cv_have_decl_freeaddrinfo" "#include \"src/have.h\" ac_fn_c_check_decl "$LINENO" "freeaddrinfo" "ac_cv_have_decl_freeaddrinfo" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_have_decl_freeaddrinfo" = xyes; then : if test "x$ac_cv_have_decl_freeaddrinfo" = xyes; then :
@ -6540,7 +6203,7 @@ fi
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_FREEADDRINFO $ac_have_decl #define HAVE_DECL_FREEADDRINFO $ac_have_decl
_ACEOF _ACEOF
ac_fn_c_check_decl "$LINENO" "gai_strerror" "ac_cv_have_decl_gai_strerror" "#include \"src/have.h\" ac_fn_c_check_decl "$LINENO" "gai_strerror" "ac_cv_have_decl_gai_strerror" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_have_decl_gai_strerror" = xyes; then : if test "x$ac_cv_have_decl_gai_strerror" = xyes; then :
@ -6552,7 +6215,7 @@ fi
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_GAI_STRERROR $ac_have_decl #define HAVE_DECL_GAI_STRERROR $ac_have_decl
_ACEOF _ACEOF
ac_fn_c_check_decl "$LINENO" "getaddrinfo" "ac_cv_have_decl_getaddrinfo" "#include \"src/have.h\" ac_fn_c_check_decl "$LINENO" "getaddrinfo" "ac_cv_have_decl_getaddrinfo" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_have_decl_getaddrinfo" = xyes; then : if test "x$ac_cv_have_decl_getaddrinfo" = xyes; then :
@ -6564,7 +6227,7 @@ fi
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_GETADDRINFO $ac_have_decl #define HAVE_DECL_GETADDRINFO $ac_have_decl
_ACEOF _ACEOF
ac_fn_c_check_decl "$LINENO" "getnameinfo" "ac_cv_have_decl_getnameinfo" "#include \"src/have.h\" ac_fn_c_check_decl "$LINENO" "getnameinfo" "ac_cv_have_decl_getnameinfo" "#include \"$srcdir/src/have.h\"
" "
if test "x$ac_cv_have_decl_getnameinfo" = xyes; then : if test "x$ac_cv_have_decl_getnameinfo" = xyes; then :
@ -7204,7 +6867,7 @@ else
fi fi
for ac_func in BN_GENCB_new ERR_remove_state RSA_set0_key for ac_func in BN_GENCB_new RSA_set0_key
do : do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -7230,7 +6893,12 @@ fi
fi fi
ac_config_files="$ac_config_files Makefile src/Makefile doc/Makefile m4/Makefile distro/Makefile" if test "x$runstatedir" = "x"; then
runstatedir='${localstatedir}/run'
fi
ac_config_files="$ac_config_files Makefile src/Makefile doc/Makefile distro/Makefile"
cat >confcache <<\_ACEOF cat >confcache <<\_ACEOF
@ -7358,10 +7026,6 @@ else
am__EXEEXT_FALSE= am__EXEEXT_FALSE=
fi fi
if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
as_fn_error $? "conditional \"AMDEP\" was never defined. as_fn_error $? "conditional \"AMDEP\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@ -7807,7 +7471,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by tinc $as_me 1.0.32, which was This file was extended by tinc $as_me 1.0.33, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -7873,7 +7537,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
tinc config.status 1.0.32 tinc config.status 1.0.33
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"
@ -8007,7 +7671,6 @@ do
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
"m4/Makefile") CONFIG_FILES="$CONFIG_FILES m4/Makefile" ;;
"distro/Makefile") CONFIG_FILES="$CONFIG_FILES distro/Makefile" ;; "distro/Makefile") CONFIG_FILES="$CONFIG_FILES distro/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;

View file

@ -1,11 +1,11 @@
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT([tinc], [1.0.32]) AC_INIT([tinc], [1.0.33])
AC_CONFIG_SRCDIR([src/tincd.c]) AC_CONFIG_SRCDIR([src/tincd.c])
AM_INIT_AUTOMAKE([1.11 check-news std-options subdir-objects nostdinc silent-rules -Wall]) AM_INIT_AUTOMAKE([1.11 check-news std-options subdir-objects nostdinc silent-rules -Wall info-in-builddir])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AM_MAINTAINER_MODE AC_CONFIG_MACRO_DIR([m4])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
# Enable GNU extensions. # Enable GNU extensions.
@ -179,36 +179,30 @@ dnl Checks for libraries.
dnl Checks for header files. dnl Checks for header files.
dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies. dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.
AC_HEADER_STDC AC_CHECK_HEADERS([syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/wait.h netdb.h arpa/inet.h arpa/nameser.h dirent.h getopt.h])
AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h time.h sys/uio.h sys/wait.h netdb.h arpa/inet.h arpa/nameser.h dirent.h getopt.h])
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h], AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h],
[], [], [#include "src/have.h"] [], [], [#include "$srcdir/src/have.h"]
) )
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h], AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h],
[], [], [#include "src/have.h"] [], [], [#include "$srcdir/src/have.h"]
) )
AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h], AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h],
[], [], [#include "src/have.h"] [], [], [#include "$srcdir/src/have.h"]
) )
dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_VOLATILE
AC_TYPE_PID_T AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_STRUCT_TM
tinc_ATTRIBUTE(__malloc__) tinc_ATTRIBUTE(__malloc__)
AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp, struct in_addr, struct addrinfo, struct ip, struct icmp, struct in6_addr, struct sockaddr_in6, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , , AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp, struct in_addr, struct addrinfo, struct ip, struct icmp, struct in6_addr, struct sockaddr_in6, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , ,
[#include "src/have.h"] [#include "$srcdir/src/have.h"]
) )
dnl Checks for library functions. dnl Checks for library functions.
AC_TYPE_SIGNAL AC_TYPE_SIGNAL
AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall pselect putenv random select strdup strerror strsignal strtol system unsetenv usleep vsyslog writev devname fdevname], AC_CHECK_FUNCS([asprintf daemon fchmod flock fork gettimeofday mlockall pselect putenv strsignal system unsetenv usleep vsyslog devname fdevname],
[], [], [#include "src/have.h"] [], [], [#include "$srcdir/src/have.h"]
) )
AC_CHECK_FUNC(getopt_long, [getopt=true; AC_DEFINE(HAVE_GETOPT_LONG, 1, [getopt_long()])], [getopt=false]) AC_CHECK_FUNC(getopt_long, [getopt=true; AC_DEFINE(HAVE_GETOPT_LONG, 1, [getopt_long()])], [getopt=false])
@ -224,7 +218,7 @@ AC_CHECK_FUNC(gethostbyname, [], [
]) ])
AC_CHECK_DECLS([freeaddrinfo, gai_strerror, getaddrinfo, getnameinfo], AC_CHECK_DECLS([freeaddrinfo, gai_strerror, getaddrinfo, getnameinfo],
[], [], [#include "src/have.h"] [], [], [#include "$srcdir/src/have.h"]
) )
AC_CHECK_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [ AC_CHECK_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [
@ -248,6 +242,11 @@ AC_ARG_ENABLE(jumbograms,
] ]
) )
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile m4/Makefile distro/Makefile]) dnl Ensure runstatedir is set if we are using a version of autoconf that does not suppport it
if test "x$runstatedir" = "x"; then
AC_SUBST([runstatedir], ['${localstatedir}/run'])
fi
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile distro/Makefile])
AC_OUTPUT AC_OUTPUT

View file

@ -186,7 +186,6 @@ LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@ LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@ LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@ MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@ MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@ OBJEXT = @OBJEXT@
@ -268,7 +267,7 @@ EXTRA_DIST = \
all: all-am all: all-am
.SUFFIXES: .SUFFIXES:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \ @for dep in $?; do \
case '$(am__configure_deps)' in \ case '$(am__configure_deps)' in \
*$$dep*) \ *$$dep*) \
@ -292,9 +291,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps): $(am__aclocal_m4_deps):
install-systemdsystemunitDATA: $(systemdsystemunit_DATA) install-systemdsystemunitDATA: $(systemdsystemunit_DATA)

View file

@ -4,23 +4,12 @@ info_TEXINFOS = tinc.texi
man_MANS = tincd.8 tinc.conf.5 man_MANS = tincd.8 tinc.conf.5
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config.tar.gz EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config
CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi
# Use `ginstall' in the definition of man_MANS to avoid
# confusion with the `install' target. The install rule transforms `ginstall'
# to install before applying any user-specified name transformations.
transform = s/ginstall/install/; @program_transform_name@
# For additional rules usually of interest only to the maintainer,
# see GNUmakefile and Makefile.maint.
sample-config.tar.gz: sample-config
$(AM_V_GEN)GZIP=$(GZIP_ENV) $(AMTAR) chozf sample-config.tar.gz --exclude .svn sample-config
texi2html: tinc.texi texi2html: tinc.texi
$(AM_V_GEN)texi2html -split=chapter tinc.texi $(AM_V_GEN)texi2html -split=chapter $<
tincd.8.html: tincd.8 tincd.8.html: tincd.8
$(AM_V_GEN)w3mman2html $< > $@ $(AM_V_GEN)w3mman2html $< > $@
@ -32,15 +21,16 @@ substitute = sed \
-e s,'@PACKAGE\@',"$(PACKAGE)",g \ -e s,'@PACKAGE\@',"$(PACKAGE)",g \
-e s,'@VERSION\@',"$(VERSION)",g \ -e s,'@VERSION\@',"$(VERSION)",g \
-e s,'@sysconfdir\@',"$(sysconfdir)",g \ -e s,'@sysconfdir\@',"$(sysconfdir)",g \
-e s,'@runstatedir\@',"$(runstatedir)",g \
-e s,'@localstatedir\@',"$(localstatedir)",g -e s,'@localstatedir\@',"$(localstatedir)",g
tincd.8: tincd.8.in tincd.8: $(srcdir)/tincd.8.in
$(AM_V_GEN)$(substitute) tincd.8.in > tincd.8 $(AM_V_GEN)$(substitute) $< > $@
tinc.conf.5: tinc.conf.5.in tinc.conf.5: $(srcdir)/tinc.conf.5.in
$(AM_V_GEN)$(substitute) tinc.conf.5.in > tinc.conf.5 $(AM_V_GEN)$(substitute) $< > $@
tincinclude.texi: tincinclude.texi.in tincinclude.texi: $(srcdir)/tincinclude.texi.in
$(AM_V_GEN)$(substitute) tincinclude.texi.in > tincinclude.texi $(AM_V_GEN)$(substitute) $< > $@
tinc.texi: tincinclude.texi tinc.texi: tincinclude.texi

View file

@ -78,6 +78,7 @@ install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA) INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = : NORMAL_INSTALL = :
PRE_INSTALL = : PRE_INSTALL = :
POST_INSTALL = : POST_INSTALL = :
@ -145,7 +146,7 @@ AM_V_texidevnull = $(am__v_texidevnull_@AM_V@)
am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@) am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@)
am__v_texidevnull_0 = > /dev/null am__v_texidevnull_0 = > /dev/null
am__v_texidevnull_1 = am__v_texidevnull_1 =
INFO_DEPS = $(srcdir)/tinc.info INFO_DEPS = tinc.info
am__TEXINFO_TEX_DIR = $(srcdir) am__TEXINFO_TEX_DIR = $(srcdir)
DVIS = tinc.dvi DVIS = tinc.dvi
PDFS = tinc.pdf PDFS = tinc.pdf
@ -198,11 +199,6 @@ MANS = $(man_MANS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
am__DIST_COMMON = $(srcdir)/Makefile.in texinfo.tex am__DIST_COMMON = $(srcdir)/Makefile.in texinfo.tex
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
# Use `ginstall' in the definition of man_MANS to avoid
# confusion with the `install' target. The install rule transforms `ginstall'
# to install before applying any user-specified name transformations.
transform = s/ginstall/install/; @program_transform_name@
ACLOCAL = @ACLOCAL@ ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@ AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
@ -233,7 +229,6 @@ LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@ LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@ LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@ MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@ MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@ OBJEXT = @OBJEXT@
@ -306,19 +301,20 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
info_TEXINFOS = tinc.texi info_TEXINFOS = tinc.texi
man_MANS = tincd.8 tinc.conf.5 man_MANS = tincd.8 tinc.conf.5
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config.tar.gz EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config
CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi
substitute = sed \ substitute = sed \
-e s,'@PACKAGE\@',"$(PACKAGE)",g \ -e s,'@PACKAGE\@',"$(PACKAGE)",g \
-e s,'@VERSION\@',"$(VERSION)",g \ -e s,'@VERSION\@',"$(VERSION)",g \
-e s,'@sysconfdir\@',"$(sysconfdir)",g \ -e s,'@sysconfdir\@',"$(sysconfdir)",g \
-e s,'@runstatedir\@',"$(runstatedir)",g \
-e s,'@localstatedir\@',"$(localstatedir)",g -e s,'@localstatedir\@',"$(localstatedir)",g
all: all-am all: all-am
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .dvi .html .info .pdf .ps .texi .SUFFIXES: .dvi .ps
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \ @for dep in $?; do \
case '$(am__configure_deps)' in \ case '$(am__configure_deps)' in \
*$$dep*) \ *$$dep*) \
@ -342,59 +338,51 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps): $(am__aclocal_m4_deps):
.texi.info: tinc.info: tinc.texi
$(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \
am__cwd=`pwd` && $(am__cd) $(srcdir) && \
rm -rf $$backupdir && mkdir $$backupdir && \ rm -rf $$backupdir && mkdir $$backupdir && \
if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
done; \ done; \
else :; fi && \ else :; fi && \
cd "$$am__cwd"; \
if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
-o $@ $<; \ -o $@ `test -f 'tinc.texi' || echo '$(srcdir)/'`tinc.texi; \
then \ then \
rc=0; \ rc=0; \
$(am__cd) $(srcdir); \
else \ else \
rc=$$?; \ rc=$$?; \
$(am__cd) $(srcdir) && \
$$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
fi; \ fi; \
rm -rf $$backupdir; exit $$rc rm -rf $$backupdir; exit $$rc
.texi.dvi: tinc.dvi: tinc.texi
$(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
$(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \
$< `test -f 'tinc.texi' || echo '$(srcdir)/'`tinc.texi
.texi.pdf: tinc.pdf: tinc.texi
$(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
$(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \
$< `test -f 'tinc.texi' || echo '$(srcdir)/'`tinc.texi
.texi.html: tinc.html: tinc.texi
$(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp)
$(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
-o $(@:.html=.htp) $<; \ -o $(@:.html=.htp) `test -f 'tinc.texi' || echo '$(srcdir)/'`tinc.texi; \
then \ then \
rm -rf $@ && mv $(@:.html=.htp) $@; \ rm -rf $@ && mv $(@:.html=.htp) $@; \
else \ else \
rm -rf $(@:.html=.htp); exit 1; \ rm -rf $(@:.html=.htp); exit 1; \
fi fi
$(srcdir)/tinc.info: tinc.texi
tinc.dvi: tinc.texi
tinc.pdf: tinc.texi
tinc.html: tinc.texi
.dvi.ps: .dvi.ps:
$(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
$(DVIPS) $(AM_V_texinfo) -o $@ $< $(DVIPS) $(AM_V_texinfo) -o $@ $<
@ -833,14 +821,8 @@ uninstall-man: uninstall-man5 uninstall-man8
.PRECIOUS: Makefile .PRECIOUS: Makefile
# For additional rules usually of interest only to the maintainer,
# see GNUmakefile and Makefile.maint.
sample-config.tar.gz: sample-config
$(AM_V_GEN)GZIP=$(GZIP_ENV) $(AMTAR) chozf sample-config.tar.gz --exclude .svn sample-config
texi2html: tinc.texi texi2html: tinc.texi
$(AM_V_GEN)texi2html -split=chapter tinc.texi $(AM_V_GEN)texi2html -split=chapter $<
tincd.8.html: tincd.8 tincd.8.html: tincd.8
$(AM_V_GEN)w3mman2html $< > $@ $(AM_V_GEN)w3mman2html $< > $@
@ -848,14 +830,14 @@ tincd.8.html: tincd.8
tinc.conf.5.html: tinc.conf.5 tinc.conf.5.html: tinc.conf.5
$(AM_V_GEN)w3mman2html $< > $@ $(AM_V_GEN)w3mman2html $< > $@
tincd.8: tincd.8.in tincd.8: $(srcdir)/tincd.8.in
$(AM_V_GEN)$(substitute) tincd.8.in > tincd.8 $(AM_V_GEN)$(substitute) $< > $@
tinc.conf.5: tinc.conf.5.in tinc.conf.5: $(srcdir)/tinc.conf.5.in
$(AM_V_GEN)$(substitute) tinc.conf.5.in > tinc.conf.5 $(AM_V_GEN)$(substitute) $< > $@
tincinclude.texi: tincinclude.texi.in tincinclude.texi: $(srcdir)/tincinclude.texi.in
$(AM_V_GEN)$(substitute) tincinclude.texi.in > tincinclude.texi $(AM_V_GEN)$(substitute) $< > $@
tinc.texi: tincinclude.texi tinc.texi: tincinclude.texi

Binary file not shown.

View file

@ -0,0 +1,15 @@
# Sample host configuration file
# The real IP address of this tinc host. Can be used by other tinc hosts.
Address = 123.234.35.67
# Portnumber for incoming connections. Default is 655.
Port = 655
# Subnet on the virtual private network that is local for this host.
Subnet = 192.168.1.0/24
# The public key generated by `tincd -n example -K' is stored here
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----

View file

@ -0,0 +1,16 @@
# Sample host configuration file
# This file was generated by host beta.
# The real IP address of this tinc host. Can be used by other tinc hosts.
Address = 123.45.67.189
# Portnumber for incoming connections. Default is 655.
Port = 6500
# Subnet on the virtual private network that is local for this host.
Subnet = 192.168.2.0/24
# The public key generated by `tincd -n example -K' is stored here
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----

View file

@ -0,0 +1 @@
# Generate this file with `tincd -n example -K`

View file

@ -0,0 +1,4 @@
#!/bin/sh
# This file closes down the tap device.
ifconfig $INTERFACE down

11
doc/sample-config/tinc-up Normal file
View file

@ -0,0 +1,11 @@
#!/bin/sh
# This file sets up the tap device.
# It gives you the freedom to do anything you want with it.
# Use the correct name for the tap device:
# The environment variable $INTERFACE is set to the right name
# on most platforms, but if it doesn't work try to set it manually.
# Give it the right ip and netmask. Remember, the subnet of the
# tap device must be larger than that of the individual Subnets
# as defined in the host configuration file!
ifconfig $INTERFACE 192.168.1.1 netmask 255.255.0.0

View file

@ -0,0 +1,22 @@
# Sample tinc configuration file
# This is a comment.
# Spaces and tabs are eliminated.
# The = sign isn't strictly necessary any longer, though you may want
# to leave it in as it improves readability :)
# Variable names are treated case insensitive.
# The name of this tinc host. Required.
Name = alpha
# The internet host to connect with.
# Comment these out to make yourself a listen-only connection
# You must use the name of another tinc host.
# May be used multiple times for redundance.
ConnectTo = beta
# The tap device tinc will use.
# /dev/tap0 for ethertap, FreeBSD or OpenBSD
# /dev/tun0 for Solaris
# /dev/net/tun for Linux tun/tap
Device = /dev/net/tun

View file

@ -222,7 +222,7 @@ Also note that this can cause decrypted VPN packets to be sent out on a real net
Create a UNIX socket with the filename specified by Create a UNIX socket with the filename specified by
.Va Device , .Va Device ,
or or
.Pa @localstatedir@/run/ Ns Ar NETNAME Ns Pa .umlsocket .Pa @runstatedir@/ Ns Ar NETNAME Ns Pa .umlsocket
if not specified. if not specified.
.Nm tinc .Nm tinc
will wait for a User Mode Linux instance to connect to this socket. will wait for a User Mode Linux instance to connect to this socket.
@ -231,7 +231,7 @@ Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
using the UNIX socket specified by using the UNIX socket specified by
.Va Device , .Va Device ,
or or
.Pa @localstatedir@/run/vde.ctl .Pa @runstatedir@/vde.ctl
if not specified. if not specified.
.El .El
Also, in case tinc does not seem to correctly interpret packets received from the virtual network device, Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,

View file

@ -1,11 +1,11 @@
This is tinc.info, produced by makeinfo version 6.4.90 from tinc.texi. This is tinc.info, produced by makeinfo version 6.5 from tinc.texi.
INFO-DIR-SECTION Networking tools INFO-DIR-SECTION Networking tools
START-INFO-DIR-ENTRY START-INFO-DIR-ENTRY
* tinc: (tinc). The tinc Manual. * tinc: (tinc). The tinc Manual.
END-INFO-DIR-ENTRY END-INFO-DIR-ENTRY
This is the info manual for tinc version 1.0.31, a Virtual Private This is the info manual for tinc version 1.0.33, a Virtual Private
Network daemon. Network daemon.
Copyright (C) 1998-2017 Ivo Timmermans, Guus Sliepen Copyright (C) 1998-2017 Ivo Timmermans, Guus Sliepen
@ -791,13 +791,13 @@ DeviceType = <TYPE> (platform dependent)
uml (not compiled in by default) uml (not compiled in by default)
Create a UNIX socket with the filename specified by DEVICE, or Create a UNIX socket with the filename specified by DEVICE, or
'/var/run/NETNAME.umlsocket' if not specified. Tinc will wait '/run/NETNAME.umlsocket' if not specified. Tinc will wait for
for a User Mode Linux instance to connect to this socket. a User Mode Linux instance to connect to this socket.
vde (not compiled in by default) vde (not compiled in by default)
Uses the libvdeplug library to connect to a Virtual Uses the libvdeplug library to connect to a Virtual
Distributed Ethernet switch, using the UNIX socket specified Distributed Ethernet switch, using the UNIX socket specified
by DEVICE, or '/var/run/vde.ctl' if not specified. by DEVICE, or '/run/vde.ctl' if not specified.
Also, in case tinc does not seem to correctly interpret packets Also, in case tinc does not seem to correctly interpret packets
received from the virtual network device, it can be used to change received from the virtual network device, it can be used to change
@ -1597,7 +1597,7 @@ command line options.
'/var/log/tinc.NETNAME.log'. '/var/log/tinc.NETNAME.log'.
'--pidfile=FILE' '--pidfile=FILE'
Write PID to FILE instead of '/var/run/tinc.NETNAME.pid'. Write PID to FILE instead of '/run/tinc.NETNAME.pid'.
'--bypass-security' '--bypass-security'
Disables encryption and authentication. Only useful for debugging. Disables encryption and authentication. Only useful for debugging.
@ -1609,12 +1609,16 @@ command line options.
chroot is performed after all the initialization is done, after chroot is performed after all the initialization is done, after
writing pid files and opening network sockets. writing pid files and opening network sockets.
Note that this option alone does not do any good without -U/-user, This option is best used in combination with the -U/-user option
below. described below.
Note also that tinc can't run scripts anymore (such as tinc-down or You will need to ensure the chroot environment contains all the
host-up), unless it's setup to be runnable inside chroot files necessary for tinc to run correctly. Most importantly, for
environment. tinc to be able to resolve hostnames inside the chroot environment,
you must copy '/etc/resolv.conf' into the chroot directory. If you
want to be able to run scripts other than 'tinc-up' in the chroot,
you must ensure the appropriate shell is also installed in the
chroot, along with all its dependencies.
'-U, --user=USER' '-U, --user=USER'
Switch to the given USER after initialization, at the same time as Switch to the given USER after initialization, at the same time as
@ -2650,66 +2654,66 @@ Concept Index
 
Tag Table: Tag Table:
Node: Top809 Node: Top806
Node: Introduction1108 Node: Introduction1105
Node: Virtual Private Networks1918 Node: Virtual Private Networks1915
Node: tinc3642 Node: tinc3639
Node: Supported platforms5169 Node: Supported platforms5166
Node: Preparations5870 Node: Preparations5867
Node: Configuring the kernel6126 Node: Configuring the kernel6123
Node: Configuration of Linux kernels6536 Node: Configuration of Linux kernels6533
Node: Configuration of FreeBSD kernels7391 Node: Configuration of FreeBSD kernels7388
Node: Configuration of OpenBSD kernels7856 Node: Configuration of OpenBSD kernels7853
Node: Configuration of NetBSD kernels8213 Node: Configuration of NetBSD kernels8210
Node: Configuration of Solaris kernels8618 Node: Configuration of Solaris kernels8615
Node: Configuration of Darwin (Mac OS X) kernels9281 Node: Configuration of Darwin (Mac OS X) kernels9278
Node: Configuration of Windows10100 Node: Configuration of Windows10097
Node: Libraries10640 Node: Libraries10637
Node: LibreSSL/OpenSSL11049 Node: LibreSSL/OpenSSL11046
Node: zlib13591 Node: zlib13588
Node: lzo14623 Node: lzo14620
Node: Installation15606 Node: Installation15603
Node: Building and installing tinc16516 Node: Building and installing tinc16513
Node: Darwin (Mac OS X) build environment17176 Node: Darwin (Mac OS X) build environment17173
Node: Cygwin (Windows) build environment17741 Node: Cygwin (Windows) build environment17738
Node: MinGW (Windows) build environment18330 Node: MinGW (Windows) build environment18327
Node: System files18924 Node: System files18921
Node: Device files19189 Node: Device files19186
Node: Other files19605 Node: Other files19602
Node: Configuration20218 Node: Configuration20215
Node: Configuration introduction20529 Node: Configuration introduction20526
Node: Multiple networks21797 Node: Multiple networks21794
Node: How connections work23223 Node: How connections work23220
Node: Configuration files24445 Node: Configuration files24442
Node: Main configuration variables25939 Node: Main configuration variables25936
Node: Host configuration variables42195 Node: Host configuration variables42184
Node: Scripts47727 Node: Scripts47716
Node: How to configure50993 Node: How to configure50982
Node: Generating keypairs52251 Node: Generating keypairs52240
Node: Network interfaces52750 Node: Network interfaces52739
Node: Example configuration54598 Node: Example configuration54587
Node: Running tinc59923 Node: Running tinc59912
Node: Runtime options60513 Node: Runtime options60502
Node: Signals63815 Node: Signals64127
Node: Debug levels65006 Node: Debug levels65318
Node: Solving problems65942 Node: Solving problems66254
Node: Error messages67494 Node: Error messages67806
Node: Sending bug reports71503 Node: Sending bug reports71815
Node: Technical information72450 Node: Technical information72762
Node: The connection72681 Node: The connection72993
Node: The UDP tunnel72993 Node: The UDP tunnel73305
Node: The meta-connection76054 Node: The meta-connection76366
Node: The meta-protocol77523 Node: The meta-protocol77835
Node: Security82540 Node: Security82852
Node: Authentication protocol83682 Node: Authentication protocol83994
Node: Encryption of network packets88727 Node: Encryption of network packets89039
Node: Security issues90103 Node: Security issues90415
Node: Platform specific information91742 Node: Platform specific information92054
Node: Interface configuration91970 Node: Interface configuration92282
Node: Routes94441 Node: Routes94753
Node: About us96455 Node: About us96767
Node: Contact information96630 Node: Contact information96942
Node: Authors97033 Node: Authors97345
Node: Concept Index97438 Node: Concept Index97750
 
End Tag Table End Tag Table

View file

@ -860,7 +860,7 @@ Also note that this can cause decrypted VPN packets to be sent out on a real net
@cindex UML @cindex UML
@item uml (not compiled in by default) @item uml (not compiled in by default)
Create a UNIX socket with the filename specified by Create a UNIX socket with the filename specified by
@var{Device}, or @file{@value{localstatedir}/run/@var{netname}.umlsocket} @var{Device}, or @file{@value{runstatedir}/@var{netname}.umlsocket}
if not specified. if not specified.
Tinc will wait for a User Mode Linux instance to connect to this socket. Tinc will wait for a User Mode Linux instance to connect to this socket.
@ -868,7 +868,7 @@ Tinc will wait for a User Mode Linux instance to connect to this socket.
@item vde (not compiled in by default) @item vde (not compiled in by default)
Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch, Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
using the UNIX socket specified by using the UNIX socket specified by
@var{Device}, or @file{@value{localstatedir}/run/vde.ctl} @var{Device}, or @file{@value{runstatedir}/vde.ctl}
if not specified. if not specified.
@end table @end table
@ -1730,7 +1730,7 @@ Write log entries to a file instead of to the system logging facility.
If @var{file} is omitted, the default is @file{@value{localstatedir}/log/tinc.@var{netname}.log}. If @var{file} is omitted, the default is @file{@value{localstatedir}/log/tinc.@var{netname}.log}.
@item --pidfile=@var{file} @item --pidfile=@var{file}
Write PID to @var{file} instead of @file{@value{localstatedir}/run/tinc.@var{netname}.pid}. Write PID to @var{file} instead of @file{@value{runstatedir}/tinc.@var{netname}.pid}.
@item --bypass-security @item --bypass-security
Disables encryption and authentication. Disables encryption and authentication.
@ -1743,10 +1743,14 @@ located (@file{@value{sysconfdir}/tinc/@var{netname}/} as determined by
The chroot is performed after all the initialization is done, after The chroot is performed after all the initialization is done, after
writing pid files and opening network sockets. writing pid files and opening network sockets.
Note that this option alone does not do any good without -U/--user, below. This option is best used in combination with the -U/--user option described below.
Note also that tinc can't run scripts anymore (such as tinc-down or host-up), You will need to ensure the chroot environment contains all the files necessary
unless it's setup to be runnable inside chroot environment. for tinc to run correctly.
Most importantly, for tinc to be able to resolve hostnames inside the chroot environment,
you must copy @file{/etc/resolv.conf} into the chroot directory.
If you want to be able to run scripts other than @file{tinc-up} in the chroot,
you must ensure the appropriate shell is also installed in the chroot, along with all its dependencies.
@item -U, --user=@var{user} @item -U, --user=@var{user}
Switch to the given @var{user} after initialization, at the same time as Switch to the given @var{user} after initialization, at the same time as

View file

@ -109,7 +109,7 @@ is omitted, the default is
Write PID to Write PID to
.Ar FILE .Ar FILE
instead of instead of
.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .pid. .Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid.
Under Windows this option will be ignored. Under Windows this option will be ignored.
.It Fl -bypass-security .It Fl -bypass-security
Disables encryption and authentication of the meta protocol. Disables encryption and authentication of the meta protocol.
@ -190,7 +190,7 @@ This will log all network traffic over the virtual private network.
Directory containing the configuration files tinc uses. Directory containing the configuration files tinc uses.
For more information, see For more information, see
.Xr tinc.conf 5 . .Xr tinc.conf 5 .
.It Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .pid .It Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid
The PID of the currently running The PID of the currently running
.Nm .Nm
is stored in this file. is stored in this file.

View file

@ -2,3 +2,4 @@
@set PACKAGE @PACKAGE@ @set PACKAGE @PACKAGE@
@set sysconfdir @sysconfdir@ @set sysconfdir @sysconfdir@
@set localstatedir @localstatedir@ @set localstatedir @localstatedir@
@set runstatedir @runstatedir@

View file

@ -1,4 +0,0 @@
## Process this file with automake to produce Makefile.in -*-Makefile-*-
EXTRA_DIST = README *.m4

View file

@ -1,418 +0,0 @@
# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = m4
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
$(top_srcdir)/m4/ax_append_flag.m4 \
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_check_link_flag.m4 \
$(top_srcdir)/m4/ax_require_defined.m4 $(top_srcdir)/m4/lzo.m4 \
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/zlib.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
am__DIST_COMMON = $(srcdir)/Makefile.in README
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
systemdsystemunitdir = @systemdsystemunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
EXTRA_DIST = README *.m4
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu m4/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu m4/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
tags TAGS:
ctags CTAGS:
cscope cscopelist:
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
ctags-am distclean distclean-generic distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
pdf-am ps ps-am tags-am uninstall uninstall-am
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View file

@ -1,8 +0,0 @@
These files are used by a program called aclocal (part of the GNU automake
package). aclocal uses these files to create aclocal.m4 which is in turn
used by autoconf to create the configure script at the the top level in
this distribution.
The Makefile.am file in this directory is automatically generated
from the template file, Makefile.am.in. The generation will fail
if you don't have all the right tools.

View file

@ -54,5 +54,5 @@ AC_DEFUN([tinc_OPENSSL],
[#include <openssl/evp.h>] [#include <openssl/evp.h>]
) )
AC_CHECK_FUNCS([BN_GENCB_new ERR_remove_state RSA_set0_key], , , [#include <openssl/rsa.h>]) AC_CHECK_FUNCS([BN_GENCB_new RSA_set0_key], , , [#include <openssl/rsa.h>])
]) ])

View file

@ -14,7 +14,6 @@ tincd_SOURCES = \
edge.c edge.h \ edge.c edge.h \
ethernet.h \ ethernet.h \
event.c event.h \ event.c event.h \
fake-gai-errnos.h \
fake-getaddrinfo.c fake-getaddrinfo.h \ fake-getaddrinfo.c fake-getaddrinfo.h \
fake-getnameinfo.c fake-getnameinfo.h \ fake-getnameinfo.c fake-getnameinfo.h \
graph.c graph.h \ graph.c graph.h \
@ -44,8 +43,7 @@ tincd_SOURCES = \
subnet.c subnet.h \ subnet.c subnet.h \
tincd.c \ tincd.c \
utils.c utils.h \ utils.c utils.h \
xalloc.h \ xalloc.h
xmalloc.c
if !GETOPT if !GETOPT
tincd_SOURCES += \ tincd_SOURCES += \
@ -88,4 +86,4 @@ if TUNEMU
LIBS += -lpcap LIBS += -lpcap
endif endif
AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -I $(abs_top_builddir)/

View file

@ -124,19 +124,18 @@ PROGRAMS = $(sbin_PROGRAMS)
am__tincd_SOURCES_DIST = have.h system.h avl_tree.c avl_tree.h conf.c \ am__tincd_SOURCES_DIST = have.h system.h avl_tree.c avl_tree.h conf.c \
conf.h connection.c connection.h device.h dropin.c dropin.h \ conf.h connection.c connection.h device.h dropin.c dropin.h \
dummy_device.c edge.c edge.h ethernet.h event.c event.h \ dummy_device.c edge.c edge.h ethernet.h event.c event.h \
fake-gai-errnos.h fake-getaddrinfo.c fake-getaddrinfo.h \ fake-getaddrinfo.c fake-getaddrinfo.h fake-getnameinfo.c \
fake-getnameinfo.c fake-getnameinfo.h graph.c graph.h ipv4.h \ fake-getnameinfo.h graph.c graph.h ipv4.h ipv6.h list.c list.h \
ipv6.h list.c list.h logger.c logger.h meta.c meta.h \ logger.c logger.h meta.c meta.h multicast_device.c net.c net.h \
multicast_device.c net.c net.h net_packet.c net_setup.c \ net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \
net_socket.c netutl.c netutl.h node.c node.h pidfile.c \ node.h pidfile.c pidfile.h process.c process.h protocol.c \
pidfile.h process.c process.h protocol.c protocol.h \ protocol.h protocol_auth.c protocol_edge.c protocol_misc.c \
protocol_auth.c protocol_edge.c protocol_misc.c protocol_key.c \ protocol_key.c protocol_subnet.c proxy.c proxy.h \
protocol_subnet.c proxy.c proxy.h raw_socket_device.c route.c \ raw_socket_device.c route.c route.h subnet.c subnet.h tincd.c \
route.h subnet.c subnet.h tincd.c utils.c utils.h xalloc.h \ utils.c utils.h xalloc.h getopt.c getopt.h getopt1.c \
xmalloc.c getopt.c getopt.h getopt1.c linux/device.c \ linux/device.c bsd/device.c bsd/tunemu.c bsd/tunemu.h \
bsd/device.c bsd/tunemu.c bsd/tunemu.h solaris/device.c \ solaris/device.c mingw/device.c mingw/common.h cygwin/device.c \
mingw/device.c mingw/common.h cygwin/device.c uml_device.c \ uml_device.c vde_device.c
vde_device.c
@GETOPT_FALSE@am__objects_1 = getopt.$(OBJEXT) getopt1.$(OBJEXT) @GETOPT_FALSE@am__objects_1 = getopt.$(OBJEXT) getopt1.$(OBJEXT)
am__dirstamp = $(am__leading_dot)dirstamp am__dirstamp = $(am__leading_dot)dirstamp
@LINUX_TRUE@am__objects_2 = linux/device.$(OBJEXT) @LINUX_TRUE@am__objects_2 = linux/device.$(OBJEXT)
@ -159,10 +158,10 @@ am_tincd_OBJECTS = avl_tree.$(OBJEXT) conf.$(OBJEXT) \
protocol_misc.$(OBJEXT) protocol_key.$(OBJEXT) \ protocol_misc.$(OBJEXT) protocol_key.$(OBJEXT) \
protocol_subnet.$(OBJEXT) proxy.$(OBJEXT) \ protocol_subnet.$(OBJEXT) proxy.$(OBJEXT) \
raw_socket_device.$(OBJEXT) route.$(OBJEXT) subnet.$(OBJEXT) \ raw_socket_device.$(OBJEXT) route.$(OBJEXT) subnet.$(OBJEXT) \
tincd.$(OBJEXT) utils.$(OBJEXT) xmalloc.$(OBJEXT) \ tincd.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \
$(am__objects_1) $(am__objects_2) $(am__objects_3) \ $(am__objects_2) $(am__objects_3) $(am__objects_4) \
$(am__objects_4) $(am__objects_5) $(am__objects_6) \ $(am__objects_5) $(am__objects_6) $(am__objects_7) \
$(am__objects_7) $(am__objects_8) $(am__objects_9) $(am__objects_8) $(am__objects_9)
tincd_OBJECTS = $(am_tincd_OBJECTS) tincd_OBJECTS = $(am_tincd_OBJECTS)
tincd_LDADD = $(LDADD) tincd_LDADD = $(LDADD)
AM_V_P = $(am__v_P_@AM_V@) AM_V_P = $(am__v_P_@AM_V@)
@ -251,7 +250,6 @@ LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@ LIBOBJS = @LIBOBJS@
LIBS = @LIBS@ $(am__append_10) LIBS = @LIBS@ $(am__append_10)
LTLIBOBJS = @LTLIBOBJS@ LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@ MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@ MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@ OBJEXT = @OBJEXT@
@ -325,24 +323,24 @@ top_srcdir = @top_srcdir@
tincd_SOURCES = have.h system.h avl_tree.c avl_tree.h conf.c conf.h \ tincd_SOURCES = have.h system.h avl_tree.c avl_tree.h conf.c conf.h \
connection.c connection.h device.h dropin.c dropin.h \ connection.c connection.h device.h dropin.c dropin.h \
dummy_device.c edge.c edge.h ethernet.h event.c event.h \ dummy_device.c edge.c edge.h ethernet.h event.c event.h \
fake-gai-errnos.h fake-getaddrinfo.c fake-getaddrinfo.h \ fake-getaddrinfo.c fake-getaddrinfo.h fake-getnameinfo.c \
fake-getnameinfo.c fake-getnameinfo.h graph.c graph.h ipv4.h \ fake-getnameinfo.h graph.c graph.h ipv4.h ipv6.h list.c list.h \
ipv6.h list.c list.h logger.c logger.h meta.c meta.h \ logger.c logger.h meta.c meta.h multicast_device.c net.c net.h \
multicast_device.c net.c net.h net_packet.c net_setup.c \ net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \
net_socket.c netutl.c netutl.h node.c node.h pidfile.c \ node.h pidfile.c pidfile.h process.c process.h protocol.c \
pidfile.h process.c process.h protocol.c protocol.h \ protocol.h protocol_auth.c protocol_edge.c protocol_misc.c \
protocol_auth.c protocol_edge.c protocol_misc.c protocol_key.c \ protocol_key.c protocol_subnet.c proxy.c proxy.h \
protocol_subnet.c proxy.c proxy.h raw_socket_device.c route.c \ raw_socket_device.c route.c route.h subnet.c subnet.h tincd.c \
route.h subnet.c subnet.h tincd.c utils.c utils.h xalloc.h \ utils.c utils.h xalloc.h $(am__append_1) $(am__append_2) \
xmalloc.c $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_3) $(am__append_4) $(am__append_5) \
$(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_6) $(am__append_7) $(am__append_8) \
$(am__append_7) $(am__append_8) $(am__append_9) $(am__append_9)
AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -I $(abs_top_builddir)/
all: all-am all: all-am
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .c .o .obj .SUFFIXES: .c .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \ @for dep in $?; do \
case '$(am__configure_deps)' in \ case '$(am__configure_deps)' in \
*$$dep*) \ *$$dep*) \
@ -366,9 +364,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps): $(am__aclocal_m4_deps):
install-sbinPROGRAMS: $(sbin_PROGRAMS) install-sbinPROGRAMS: $(sbin_PROGRAMS)
@ -525,7 +523,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uml_device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uml_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmalloc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/tunemu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/tunemu.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@cygwin/$(DEPDIR)/device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cygwin/$(DEPDIR)/device.Po@am__quote@

View file

@ -50,14 +50,14 @@
#endif #endif
#ifndef AVL_DEPTH #ifndef AVL_DEPTH
static int lg(unsigned int u) __attribute__ ((__const__)); static int lg(unsigned int u) __attribute__((__const__));
static int lg(unsigned int u) static int lg(unsigned int u) {
{
int r = 1; int r = 1;
if(!u) if(!u) {
return 0; return 0;
}
if(u & 0xffff0000) { if(u & 0xffff0000) {
u >>= 16; u >>= 16;
@ -79,8 +79,9 @@ static int lg(unsigned int u)
r += 2; r += 2;
} }
if(u & 0x00000002) if(u & 0x00000002) {
r++; r++;
}
return r; return r;
} }
@ -88,8 +89,7 @@ static int lg(unsigned int u)
/* Internal helper functions */ /* Internal helper functions */
static int avl_check_balance(const avl_node_t *node) static int avl_check_balance(const avl_node_t *node) {
{
#ifdef AVL_DEPTH #ifdef AVL_DEPTH
int d; int d;
@ -97,27 +97,28 @@ static int avl_check_balance(const avl_node_t *node)
return d < -1 ? -1 : d > 1 ? 1 : 0; return d < -1 ? -1 : d > 1 ? 1 : 0;
#else #else
/* int d; /* int d;
* d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node)); * d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
* d = d<-1?-1:d>1?1:0; * d = d<-1?-1:d>1?1:0;
*/ */
int pl, r; int pl, r;
pl = lg(AVL_L_COUNT(node)); pl = lg(AVL_L_COUNT(node));
r = AVL_R_COUNT(node); r = AVL_R_COUNT(node);
if(r >> pl + 1) if(r >> pl + 1) {
return 1; return 1;
}
if(pl < 2 || r >> pl - 2) if(pl < 2 || r >> pl - 2) {
return 0; return 0;
}
return -1; return -1;
#endif #endif
} }
static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
{
avl_node_t *child; avl_node_t *child;
avl_node_t *gchild; avl_node_t *gchild;
avl_node_t *parent; avl_node_t *parent;
@ -127,135 +128,154 @@ static void avl_rebalance(avl_tree_t *tree, avl_node_t *node)
parent = node->parent; parent = node->parent;
superparent = superparent =
parent ? node == parent ? node ==
parent->left ? &parent->left : &parent->right : &tree->root; parent->left ? &parent->left : &parent->right : &tree->root;
switch (avl_check_balance(node)) { switch(avl_check_balance(node)) {
case -1: case -1:
child = node->left; child = node->left;
#ifdef AVL_DEPTH #ifdef AVL_DEPTH
if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
#else #else
if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
#endif #endif
node->left = child->right; node->left = child->right;
if(node->left)
node->left->parent = node;
child->right = node; if(node->left) {
node->parent = child; node->left->parent = node;
*superparent = child;
child->parent = parent;
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
#endif
} else {
gchild = child->right;
node->left = gchild->right;
if(node->left)
node->left->parent = node;
child->right = gchild->left;
if(child->right)
child->right->parent = child;
gchild->right = node;
gchild->right->parent = gchild;
gchild->left = child;
gchild->left->parent = gchild;
*superparent = gchild;
gchild->parent = parent;
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
gchild->count = AVL_CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
gchild->depth = AVL_CALC_DEPTH(gchild);
#endif
} }
break;
case 1: child->right = node;
child = node->right; node->parent = child;
#ifdef AVL_DEPTH *superparent = child;
if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) { child->parent = parent;
#else
if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
#endif
node->right = child->left;
if(node->right)
node->right->parent = node;
child->left = node;
node->parent = child;
*superparent = child;
child->parent = parent;
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
#endif
} else {
gchild = child->left;
node->right = gchild->left;
if(node->right)
node->right->parent = node;
child->left = gchild->right;
if(child->left)
child->left->parent = child;
gchild->left = node;
gchild->left->parent = gchild;
gchild->right = child;
gchild->right->parent = gchild;
*superparent = gchild;
gchild->parent = parent;
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
gchild->count = AVL_CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
gchild->depth = AVL_CALC_DEPTH(gchild);
#endif
}
break;
default:
#ifdef AVL_COUNT #ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node); node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
#endif #endif
#ifdef AVL_DEPTH #ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node); node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
#endif
} else {
gchild = child->right;
node->left = gchild->right;
if(node->left) {
node->left->parent = node;
}
child->right = gchild->left;
if(child->right) {
child->right->parent = child;
}
gchild->right = node;
gchild->right->parent = gchild;
gchild->left = child;
gchild->left->parent = gchild;
*superparent = gchild;
gchild->parent = parent;
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
gchild->count = AVL_CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
gchild->depth = AVL_CALC_DEPTH(gchild);
#endif
}
break;
case 1:
child = node->right;
#ifdef AVL_DEPTH
if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
#else
if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
#endif
node->right = child->left;
if(node->right) {
node->right->parent = node;
}
child->left = node;
node->parent = child;
*superparent = child;
child->parent = parent;
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
#endif
} else {
gchild = child->left;
node->right = gchild->left;
if(node->right) {
node->right->parent = node;
}
child->left = gchild->right;
if(child->left) {
child->left->parent = child;
}
gchild->left = node;
gchild->left->parent = gchild;
gchild->right = child;
gchild->right->parent = gchild;
*superparent = gchild;
gchild->parent = parent;
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
child->count = AVL_CALC_COUNT(child);
gchild->count = AVL_CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
child->depth = AVL_CALC_DEPTH(child);
gchild->depth = AVL_CALC_DEPTH(gchild);
#endif
}
break;
default:
#ifdef AVL_COUNT
node->count = AVL_CALC_COUNT(node);
#endif
#ifdef AVL_DEPTH
node->depth = AVL_CALC_DEPTH(node);
#endif #endif
} }
node = parent; node = parent;
} }
} }
/* (De)constructors */ /* (De)constructors */
avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) {
{
avl_tree_t *tree; avl_tree_t *tree;
tree = xmalloc_and_zero(sizeof(avl_tree_t)); tree = xmalloc_and_zero(sizeof(avl_tree_t));
@ -265,28 +285,25 @@ avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete)
return tree; return tree;
} }
void avl_free_tree(avl_tree_t *tree) void avl_free_tree(avl_tree_t *tree) {
{
free(tree); free(tree);
} }
avl_node_t *avl_alloc_node(void) avl_node_t *avl_alloc_node(void) {
{
return xmalloc_and_zero(sizeof(avl_node_t)); return xmalloc_and_zero(sizeof(avl_node_t));
} }
void avl_free_node(avl_tree_t *tree, avl_node_t *node) void avl_free_node(avl_tree_t *tree, avl_node_t *node) {
{ if(node->data && tree->delete) {
if(node->data && tree->delete)
tree->delete(node->data); tree->delete(node->data);
}
free(node); free(node);
} }
/* Searching */ /* Searching */
void *avl_search(const avl_tree_t *tree, const void *data) void *avl_search(const avl_tree_t *tree, const void *data) {
{
avl_node_t *node; avl_node_t *node;
node = avl_search_node(tree, data); node = avl_search_node(tree, data);
@ -294,8 +311,7 @@ void *avl_search(const avl_tree_t *tree, const void *data)
return node ? node->data : NULL; return node ? node->data : NULL;
} }
void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) {
{
avl_node_t *node; avl_node_t *node;
node = avl_search_closest_node(tree, data, result); node = avl_search_closest_node(tree, data, result);
@ -303,8 +319,7 @@ void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result)
return node ? node->data : NULL; return node ? node->data : NULL;
} }
void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) {
{
avl_node_t *node; avl_node_t *node;
node = avl_search_closest_smaller_node(tree, data); node = avl_search_closest_smaller_node(tree, data);
@ -312,8 +327,7 @@ void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data)
return node ? node->data : NULL; return node ? node->data : NULL;
} }
void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) {
{
avl_node_t *node; avl_node_t *node;
node = avl_search_closest_greater_node(tree, data); node = avl_search_closest_greater_node(tree, data);
@ -321,8 +335,7 @@ void *avl_search_closest_greater(const avl_tree_t *tree, const void *data)
return node ? node->data : NULL; return node ? node->data : NULL;
} }
avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) {
{
avl_node_t *node; avl_node_t *node;
int result; int result;
@ -332,16 +345,17 @@ avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data)
} }
avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
int *result) int *result) {
{
avl_node_t *node; avl_node_t *node;
int c; int c;
node = tree->root; node = tree->root;
if(!node) { if(!node) {
if(result) if(result) {
*result = 0; *result = 0;
}
return NULL; return NULL;
} }
@ -349,24 +363,30 @@ avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
c = tree->compare(data, node->data); c = tree->compare(data, node->data);
if(c < 0) { if(c < 0) {
if(node->left) if(node->left) {
node = node->left; node = node->left;
else { } else {
if(result) if(result) {
*result = -1; *result = -1;
}
break; break;
} }
} else if(c > 0) { } else if(c > 0) {
if(node->right) if(node->right) {
node = node->right; node = node->right;
else { } else {
if(result) if(result) {
*result = 1; *result = 1;
}
break; break;
} }
} else { } else {
if(result) if(result) {
*result = 0; *result = 0;
}
break; break;
} }
} }
@ -375,37 +395,36 @@ avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
} }
avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree, avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
const void *data) const void *data) {
{
avl_node_t *node; avl_node_t *node;
int result; int result;
node = avl_search_closest_node(tree, data, &result); node = avl_search_closest_node(tree, data, &result);
if(result < 0) if(result < 0) {
node = node->prev; node = node->prev;
}
return node; return node;
} }
avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree, avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
const void *data) const void *data) {
{
avl_node_t *node; avl_node_t *node;
int result; int result;
node = avl_search_closest_node(tree, data, &result); node = avl_search_closest_node(tree, data, &result);
if(result > 0) if(result > 0) {
node = node->next; node = node->next;
}
return node; return node;
} }
/* Insertion and deletion */ /* Insertion and deletion */
avl_node_t *avl_insert(avl_tree_t *tree, void *data) avl_node_t *avl_insert(avl_tree_t *tree, void *data) {
{
avl_node_t *closest, *new; avl_node_t *closest, *new;
int result; int result;
@ -416,21 +435,21 @@ avl_node_t *avl_insert(avl_tree_t *tree, void *data)
} else { } else {
closest = avl_search_closest_node(tree, data, &result); closest = avl_search_closest_node(tree, data, &result);
switch (result) { switch(result) {
case -1: case -1:
new = avl_alloc_node(); new = avl_alloc_node();
new->data = data; new->data = data;
avl_insert_before(tree, closest, new); avl_insert_before(tree, closest, new);
break; break;
case 1: case 1:
new = avl_alloc_node(); new = avl_alloc_node();
new->data = data; new->data = data;
avl_insert_after(tree, closest, new); avl_insert_after(tree, closest, new);
break; break;
default: default:
return NULL; return NULL;
} }
} }
@ -444,27 +463,26 @@ avl_node_t *avl_insert(avl_tree_t *tree, void *data)
return new; return new;
} }
avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) {
{
avl_node_t *closest; avl_node_t *closest;
int result; int result;
if(!tree->root) if(!tree->root) {
avl_insert_top(tree, node); avl_insert_top(tree, node);
else { } else {
closest = avl_search_closest_node(tree, node->data, &result); closest = avl_search_closest_node(tree, node->data, &result);
switch (result) { switch(result) {
case -1: case -1:
avl_insert_before(tree, closest, node); avl_insert_before(tree, closest, node);
break; break;
case 1: case 1:
avl_insert_after(tree, closest, node); avl_insert_after(tree, closest, node);
break; break;
case 0: case 0:
return NULL; return NULL;
} }
} }
@ -478,20 +496,20 @@ avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node)
return node; return node;
} }
void avl_insert_top(avl_tree_t *tree, avl_node_t *node) void avl_insert_top(avl_tree_t *tree, avl_node_t *node) {
{
node->prev = node->next = node->parent = NULL; node->prev = node->next = node->parent = NULL;
tree->head = tree->tail = tree->root = node; tree->head = tree->tail = tree->root = node;
} }
void avl_insert_before(avl_tree_t *tree, avl_node_t *before, void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
avl_node_t *node) avl_node_t *node) {
{
if(!before) { if(!before) {
if(tree->tail) if(tree->tail) {
avl_insert_after(tree, tree->tail, node); avl_insert_after(tree, tree->tail, node);
else } else {
avl_insert_top(tree, node); avl_insert_top(tree, node);
}
return; return;
} }
@ -504,10 +522,11 @@ void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
return; return;
} }
if(before->prev) if(before->prev) {
before->prev->next = node; before->prev->next = node;
else } else {
tree->head = node; tree->head = node;
}
before->prev = node; before->prev = node;
before->left = node; before->left = node;
@ -515,13 +534,14 @@ void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
avl_rebalance(tree, before); avl_rebalance(tree, before);
} }
void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
{
if(!after) { if(!after) {
if(tree->head) if(tree->head) {
avl_insert_before(tree, tree->head, node); avl_insert_before(tree, tree->head, node);
else } else {
avl_insert_top(tree, node); avl_insert_top(tree, node);
}
return; return;
} }
@ -534,10 +554,11 @@ void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node)
node->parent = after; node->parent = after;
node->next = after->next; node->next = after->next;
if(after->next) if(after->next) {
after->next->prev = node; after->next->prev = node;
else } else {
tree->tail = node; tree->tail = node;
}
after->next = node; after->next = node;
after->right = node; after->right = node;
@ -545,47 +566,51 @@ void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node)
avl_rebalance(tree, after); avl_rebalance(tree, after);
} }
avl_node_t *avl_unlink(avl_tree_t *tree, void *data) avl_node_t *avl_unlink(avl_tree_t *tree, void *data) {
{
avl_node_t *node; avl_node_t *node;
node = avl_search_node(tree, data); node = avl_search_node(tree, data);
if(node) if(node) {
avl_unlink_node(tree, node); avl_unlink_node(tree, node);
}
return node; return node;
} }
void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
{
avl_node_t *parent; avl_node_t *parent;
avl_node_t **superparent; avl_node_t **superparent;
avl_node_t *subst, *left, *right; avl_node_t *subst, *left, *right;
avl_node_t *balnode; avl_node_t *balnode;
if(node->prev) if(node->prev) {
node->prev->next = node->next; node->prev->next = node->next;
else } else {
tree->head = node->next; tree->head = node->next;
if(node->next) }
if(node->next) {
node->next->prev = node->prev; node->next->prev = node->prev;
else } else {
tree->tail = node->prev; tree->tail = node->prev;
}
parent = node->parent; parent = node->parent;
superparent = superparent =
parent ? node == parent ? node ==
parent->left ? &parent->left : &parent->right : &tree->root; parent->left ? &parent->left : &parent->right : &tree->root;
left = node->left; left = node->left;
right = node->right; right = node->right;
if(!left) { if(!left) {
*superparent = right; *superparent = right;
if(right) if(right) {
right->parent = parent; right->parent = parent;
}
balnode = parent; balnode = parent;
} else if(!right) { } else if(!right) {
@ -594,8 +619,10 @@ void avl_unlink_node(avl_tree_t *tree, avl_node_t *node)
balnode = parent; balnode = parent;
} else { } else {
subst = node->prev; subst = node->prev;
if(!subst) // This only happens if node is not actually in a tree at all.
if(!subst) { // This only happens if node is not actually in a tree at all.
abort(); abort();
}
if(subst == left) { if(subst == left) {
balnode = subst; balnode = subst;
@ -603,8 +630,9 @@ void avl_unlink_node(avl_tree_t *tree, avl_node_t *node)
balnode = subst->parent; balnode = subst->parent;
balnode->right = subst->left; balnode->right = subst->left;
if(balnode->right) if(balnode->right) {
balnode->right->parent = balnode; balnode->right->parent = balnode;
}
subst->left = left; subst->left = left;
left->parent = subst; left->parent = subst;
@ -628,26 +656,24 @@ void avl_unlink_node(avl_tree_t *tree, avl_node_t *node)
#endif #endif
} }
void avl_delete_node(avl_tree_t *tree, avl_node_t *node) void avl_delete_node(avl_tree_t *tree, avl_node_t *node) {
{
avl_unlink_node(tree, node); avl_unlink_node(tree, node);
avl_free_node(tree, node); avl_free_node(tree, node);
} }
void avl_delete(avl_tree_t *tree, void *data) void avl_delete(avl_tree_t *tree, void *data) {
{
avl_node_t *node; avl_node_t *node;
node = avl_search_node(tree, data); node = avl_search_node(tree, data);
if(node) if(node) {
avl_delete_node(tree, node); avl_delete_node(tree, node);
}
} }
/* Fast tree cleanup */ /* Fast tree cleanup */
void avl_delete_tree(avl_tree_t *tree) void avl_delete_tree(avl_tree_t *tree) {
{
avl_node_t *node, *next; avl_node_t *node, *next;
for(node = tree->head; node; node = next) { for(node = tree->head; node; node = next) {
@ -660,8 +686,7 @@ void avl_delete_tree(avl_tree_t *tree)
/* Tree walking */ /* Tree walking */
void avl_foreach(const avl_tree_t *tree, avl_action_t action) void avl_foreach(const avl_tree_t *tree, avl_action_t action) {
{
avl_node_t *node, *next; avl_node_t *node, *next;
for(node = tree->head; node; node = next) { for(node = tree->head; node; node = next) {
@ -670,8 +695,7 @@ void avl_foreach(const avl_tree_t *tree, avl_action_t action)
} }
} }
void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) {
{
avl_node_t *node, *next; avl_node_t *node, *next;
for(node = tree->head; node; node = next) { for(node = tree->head; node; node = next) {
@ -683,13 +707,11 @@ void avl_foreach_node(const avl_tree_t *tree, avl_action_t action)
/* Indexing */ /* Indexing */
#ifdef AVL_COUNT #ifdef AVL_COUNT
unsigned int avl_count(const avl_tree_t *tree) unsigned int avl_count(const avl_tree_t *tree) {
{
return AVL_NODE_COUNT(tree->root); return AVL_NODE_COUNT(tree->root);
} }
avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) {
{
avl_node_t *node; avl_node_t *node;
unsigned int c; unsigned int c;
@ -711,16 +733,17 @@ avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index)
return NULL; return NULL;
} }
unsigned int avl_index(const avl_node_t *node) unsigned int avl_index(const avl_node_t *node) {
{
avl_node_t *next; avl_node_t *next;
unsigned int index; unsigned int index;
index = AVL_L_COUNT(node); index = AVL_L_COUNT(node);
while((next = node->parent)) { while((next = node->parent)) {
if(node == next->right) if(node == next->right) {
index += AVL_L_COUNT(next) + 1; index += AVL_L_COUNT(next) + 1;
}
node = next; node = next;
} }
@ -728,8 +751,7 @@ unsigned int avl_index(const avl_node_t *node)
} }
#endif #endif
#ifdef AVL_DEPTH #ifdef AVL_DEPTH
unsigned int avl_depth(const avl_tree_t *tree) unsigned int avl_depth(const avl_tree_t *tree) {
{
return AVL_NODE_DEPTH(tree->root); return AVL_NODE_DEPTH(tree->root);
} }
#endif #endif

View file

@ -1,3 +1,6 @@
#ifndef TINC_AVL_TREE_H
#define TINC_AVL_TREE_H
/* /*
avl_tree.h -- header file for avl_tree.c avl_tree.h -- header file for avl_tree.c
Copyright (C) 1998 Michael H. Buselli Copyright (C) 1998 Michael H. Buselli
@ -30,10 +33,6 @@
Guus Sliepen <guus@tinc-vpn.org>. Guus Sliepen <guus@tinc-vpn.org>.
*/ */
#ifndef __AVL_TREE_H__
#define __AVL_TREE_H__
#ifndef AVL_DEPTH #ifndef AVL_DEPTH
#ifndef AVL_COUNT #ifndef AVL_COUNT
#define AVL_DEPTH #define AVL_DEPTH
@ -66,9 +65,9 @@ typedef struct avl_node_t {
} avl_node_t; } avl_node_t;
typedef int (*avl_compare_t)(const void *, const void *); typedef int (*avl_compare_t)(const void *data1, const void *data2);
typedef void (*avl_action_t)(const void *); typedef void (*avl_action_t)(const void *data);
typedef void (*avl_action_node_t)(const avl_node_t *); typedef void (*avl_action_node_t)(const avl_node_t *node);
typedef struct avl_tree_t { typedef struct avl_tree_t {
@ -88,56 +87,56 @@ typedef struct avl_tree_t {
/* (De)constructors */ /* (De)constructors */
extern avl_tree_t *avl_alloc_tree(avl_compare_t, avl_action_t); extern avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete);
extern void avl_free_tree(avl_tree_t *); extern void avl_free_tree(avl_tree_t *tree);
extern avl_node_t *avl_alloc_node(void); extern avl_node_t *avl_alloc_node(void);
extern void avl_free_node(avl_tree_t *tree, avl_node_t *); extern void avl_free_node(avl_tree_t *tree, avl_node_t *node);
/* Insertion and deletion */ /* Insertion and deletion */
extern avl_node_t *avl_insert(avl_tree_t *, void *); extern avl_node_t *avl_insert(avl_tree_t *tree, void *data);
extern avl_node_t *avl_insert_node(avl_tree_t *, avl_node_t *); extern avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node);
extern void avl_insert_top(avl_tree_t *, avl_node_t *); extern void avl_insert_top(avl_tree_t *tree, avl_node_t *node);
extern void avl_insert_before(avl_tree_t *, avl_node_t *, avl_node_t *); extern void avl_insert_before(avl_tree_t *tree, avl_node_t *before, avl_node_t *node);
extern void avl_insert_after(avl_tree_t *, avl_node_t *, avl_node_t *); extern void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node);
extern avl_node_t *avl_unlink(avl_tree_t *, void *); extern avl_node_t *avl_unlink(avl_tree_t *tree, void *data);
extern void avl_unlink_node(avl_tree_t *tree, avl_node_t *); extern void avl_unlink_node(avl_tree_t *tree, avl_node_t *node);
extern void avl_delete(avl_tree_t *, void *); extern void avl_delete(avl_tree_t *tree, void *data);
extern void avl_delete_node(avl_tree_t *, avl_node_t *); extern void avl_delete_node(avl_tree_t *tree, avl_node_t *node);
/* Fast tree cleanup */ /* Fast tree cleanup */
extern void avl_delete_tree(avl_tree_t *); extern void avl_delete_tree(avl_tree_t *tree);
/* Searching */ /* Searching */
extern void *avl_search(const avl_tree_t *, const void *); extern void *avl_search(const avl_tree_t *tree, const void *data);
extern void *avl_search_closest(const avl_tree_t *, const void *, int *); extern void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result);
extern void *avl_search_closest_smaller(const avl_tree_t *, const void *); extern void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data);
extern void *avl_search_closest_greater(const avl_tree_t *, const void *); extern void *avl_search_closest_greater(const avl_tree_t *tree, const void *data);
extern avl_node_t *avl_search_node(const avl_tree_t *, const void *); extern avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data);
extern avl_node_t *avl_search_closest_node(const avl_tree_t *, const void *, int *); extern avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, int *result);
extern avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *, const void *); extern avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree, const void *data);
extern avl_node_t *avl_search_closest_greater_node(const avl_tree_t *, const void *); extern avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree, const void *data);
/* Tree walking */ /* Tree walking */
extern void avl_foreach(const avl_tree_t *, avl_action_t); extern void avl_foreach(const avl_tree_t *tree, avl_action_t action);
extern void avl_foreach_node(const avl_tree_t *, avl_action_t); extern void avl_foreach_node(const avl_tree_t *tree, avl_action_t action);
/* Indexing */ /* Indexing */
#ifdef AVL_COUNT #ifdef AVL_COUNT
extern unsigned int avl_count(const avl_tree_t *); extern unsigned int avl_count(const avl_tree_t *tree);
extern avl_node_t *avl_get_node(const avl_tree_t *, unsigned int); extern avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index);
extern unsigned int avl_index(const avl_node_t *); extern unsigned int avl_index(const avl_node_t *node);
#endif #endif
#ifdef AVL_DEPTH #ifdef AVL_DEPTH
extern unsigned int avl_depth(const avl_tree_t *); extern unsigned int avl_depth(const avl_tree_t *tree);
#endif #endif
#endif /* __AVL_TREE_H__ */ #endif

View file

@ -55,7 +55,7 @@ typedef enum device_type {
int device_fd = -1; int device_fd = -1;
char *device = NULL; char *device = NULL;
char *iface = NULL; char *iface = NULL;
static char *device_info = NULL; static const char *device_info = "OS X utun device";
static uint64_t device_total_in = 0; static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0; static uint64_t device_total_out = 0;
#if defined(ENABLE_TUNEMU) #if defined(ENABLE_TUNEMU)
@ -69,13 +69,15 @@ static device_type_t device_type = DEVICE_TYPE_TUN;
#ifdef HAVE_NET_IF_UTUN_H #ifdef HAVE_NET_IF_UTUN_H
static bool setup_utun(void) { static bool setup_utun(void) {
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if(device_fd == -1) { if(device_fd == -1) {
logger(LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno)); logger(LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
return false; return false;
} }
struct ctl_info info = {}; struct ctl_info info = {};
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof info.ctl_name);
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name));
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) { if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
logger(LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno)); logger(LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
@ -84,15 +86,18 @@ static bool setup_utun(void) {
int unit = -1; int unit = -1;
char *p = strstr(device, "utun"), *e = NULL; char *p = strstr(device, "utun"), *e = NULL;
if(p) { if(p) {
unit = strtol(p + 4, &e, 10); unit = strtol(p + 4, &e, 10);
if(!e)
if(!e) {
unit = -1; unit = -1;
}
} }
struct sockaddr_ctl sc = { struct sockaddr_ctl sc = {
.sc_id = info.ctl_id, .sc_id = info.ctl_id,
.sc_len = sizeof sc, .sc_len = sizeof(sc),
.sc_family = AF_SYSTEM, .sc_family = AF_SYSTEM,
.ss_sysaddr = AF_SYS_CONTROL, .ss_sysaddr = AF_SYS_CONTROL,
.sc_unit = unit + 1, .sc_unit = unit + 1,
@ -104,15 +109,14 @@ static bool setup_utun(void) {
} }
char name[64] = ""; char name[64] = "";
socklen_t len = sizeof name; socklen_t len = sizeof(name);
if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) { if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) {
iface = xstrdup(device); iface = xstrdup(device);
} else { } else {
iface = xstrdup(name); iface = xstrdup(name);
} }
device_info = "OS X utun device";
logger(LOG_INFO, "%s is a %s", device, device_info); logger(LOG_INFO, "%s is a %s", device, device_info);
return true; return true;
@ -123,10 +127,11 @@ static bool setup_device(void) {
// Find out which device file to open // Find out which device file to open
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
if(routing_mode == RMODE_ROUTER) if(routing_mode == RMODE_ROUTER) {
device = xstrdup(DEFAULT_TUN_DEVICE); device = xstrdup(DEFAULT_TUN_DEVICE);
else } else {
device = xstrdup(DEFAULT_TAP_DEVICE); device = xstrdup(DEFAULT_TAP_DEVICE);
}
} }
// Find out if it's supposed to be a tun or a tap device // Find out if it's supposed to be a tun or a tap device
@ -136,32 +141,39 @@ static bool setup_device(void) {
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "tun")) if(!strcasecmp(type, "tun"))
/* use default */; /* use default */;
#ifdef ENABLE_TUNEMU #ifdef ENABLE_TUNEMU
else if(!strcasecmp(type, "tunemu")) else if(!strcasecmp(type, "tunemu")) {
device_type = DEVICE_TYPE_TUNEMU; device_type = DEVICE_TYPE_TUNEMU;
}
#endif #endif
#ifdef HAVE_NET_IF_UTUN_H #ifdef HAVE_NET_IF_UTUN_H
else if(!strcasecmp(type, "utun")) else if(!strcasecmp(type, "utun")) {
device_type = DEVICE_TYPE_UTUN; device_type = DEVICE_TYPE_UTUN;
}
#endif #endif
else if(!strcasecmp(type, "tunnohead")) else if(!strcasecmp(type, "tunnohead")) {
device_type = DEVICE_TYPE_TUN; device_type = DEVICE_TYPE_TUN;
else if(!strcasecmp(type, "tunifhead")) } else if(!strcasecmp(type, "tunifhead")) {
device_type = DEVICE_TYPE_TUNIFHEAD; device_type = DEVICE_TYPE_TUNIFHEAD;
else if(!strcasecmp(type, "tap")) } else if(!strcasecmp(type, "tap")) {
device_type = DEVICE_TYPE_TAP; device_type = DEVICE_TYPE_TAP;
else { } else {
logger(LOG_ERR, "Unknown device type %s!", type); logger(LOG_ERR, "Unknown device type %s!", type);
return false; return false;
} }
} else { } else {
#ifdef HAVE_NET_IF_UTUN_H #ifdef HAVE_NET_IF_UTUN_H
if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0)
if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0) {
device_type = DEVICE_TYPE_UTUN; device_type = DEVICE_TYPE_UTUN;
else } else
#endif #endif
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) {
device_type = DEVICE_TYPE_TAP; device_type = DEVICE_TYPE_TAP;
}
} }
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) { if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) {
@ -173,18 +185,21 @@ static bool setup_device(void) {
switch(device_type) { switch(device_type) {
#ifdef ENABLE_TUNEMU #ifdef ENABLE_TUNEMU
case DEVICE_TYPE_TUNEMU: {
char dynamic_name[256] = ""; case DEVICE_TYPE_TUNEMU: {
device_fd = tunemu_open(dynamic_name); char dynamic_name[256] = "";
} device_fd = tunemu_open(dynamic_name);
break; }
break;
#endif #endif
#ifdef HAVE_NET_IF_UTUN_H #ifdef HAVE_NET_IF_UTUN_H
case DEVICE_TYPE_UTUN:
return setup_utun(); case DEVICE_TYPE_UTUN:
return setup_utun();
#endif #endif
default:
device_fd = open(device, O_RDWR | O_NONBLOCK); default:
device_fd = open(device, O_RDWR | O_NONBLOCK);
} }
if(device_fd < 0) { if(device_fd < 0) {
@ -204,87 +219,108 @@ static bool setup_device(void) {
realname = fdevname(device_fd); realname = fdevname(device_fd);
#elif defined(HAVE_DEVNAME) #elif defined(HAVE_DEVNAME)
struct stat buf; struct stat buf;
if(!fstat(device_fd, &buf))
if(!fstat(device_fd, &buf)) {
realname = devname(buf.st_rdev, S_IFCHR); realname = devname(buf.st_rdev, S_IFCHR);
}
#endif #endif
if(!realname) if(!realname) {
realname = device; realname = device;
}
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) {
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname); iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname)) } else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname)) {
logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly."); logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
}
// Configure the device as best as we can // Configure the device as best as we can
switch(device_type) { switch(device_type) {
default: default:
device_type = DEVICE_TYPE_TUN; device_type = DEVICE_TYPE_TUN;
case DEVICE_TYPE_TUN:
case DEVICE_TYPE_TUN:
#ifdef TUNSIFHEAD #ifdef TUNSIFHEAD
{ {
const int zero = 0; const int zero = 0;
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof(zero)) == -1) {
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno)); logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
return false; return false;
} }
} }
#endif #endif
#if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST) #if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST)
{ {
const int mode = IFF_BROADCAST | IFF_MULTICAST; const int mode = IFF_BROADCAST | IFF_MULTICAST;
ioctl(device_fd, TUNSIFMODE, &mode, sizeof mode); ioctl(device_fd, TUNSIFMODE, &mode, sizeof(mode));
} }
#endif #endif
device_info = "Generic BSD tun device"; device_info = "Generic BSD tun device";
break; break;
case DEVICE_TYPE_TUNIFHEAD:
case DEVICE_TYPE_TUNIFHEAD:
#ifdef TUNSIFHEAD #ifdef TUNSIFHEAD
{ {
const int one = 1; const int one = 1;
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof(one)) == -1) {
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno)); logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
return false; return false;
} }
} }
#endif #endif
#if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST) #if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST)
{ {
const int mode = IFF_BROADCAST | IFF_MULTICAST; const int mode = IFF_BROADCAST | IFF_MULTICAST;
ioctl(device_fd, TUNSIFMODE, &mode, sizeof mode); ioctl(device_fd, TUNSIFMODE, &mode, sizeof(mode));
} }
#endif #endif
device_info = "Generic BSD tun device"; device_info = "Generic BSD tun device";
break; break;
case DEVICE_TYPE_TAP:
if(routing_mode == RMODE_ROUTER) case DEVICE_TYPE_TAP:
overwrite_mac = true; if(routing_mode == RMODE_ROUTER) {
device_info = "Generic BSD tap device"; overwrite_mac = true;
}
device_info = "Generic BSD tap device";
#ifdef TAPGIFNAME #ifdef TAPGIFNAME
{ {
struct ifreq ifr; struct ifreq ifr;
if(ioctl(device_fd, TAPGIFNAME, (void*)&ifr) == 0) {
if(iface) if(ioctl(device_fd, TAPGIFNAME, (void *)&ifr) == 0) {
free(iface); if(iface) {
iface = xstrdup(ifr.ifr_name); free(iface);
} }
iface = xstrdup(ifr.ifr_name);
} }
}
#endif #endif
break; break;
#ifdef ENABLE_TUNEMU #ifdef ENABLE_TUNEMU
case DEVICE_TYPE_TUNEMU:
device_info = "BSD tunemu device"; case DEVICE_TYPE_TUNEMU:
break; device_info = "BSD tunemu device";
break;
#endif #endif
} }
#ifdef SIOCGIFADDR #ifdef SIOCGIFADDR
if(overwrite_mac)
if(overwrite_mac) {
ioctl(device_fd, SIOCGIFADDR, mymac.x); ioctl(device_fd, SIOCGIFADDR, mymac.x);
}
#endif #endif
logger(LOG_INFO, "%s is a %s", device, device_info); logger(LOG_INFO, "%s is a %s", device, device_info);
@ -295,12 +331,14 @@ static bool setup_device(void) {
static void close_device(void) { static void close_device(void) {
switch(device_type) { switch(device_type) {
#ifdef ENABLE_TUNEMU #ifdef ENABLE_TUNEMU
case DEVICE_TYPE_TUNEMU:
tunemu_close(device_fd); case DEVICE_TYPE_TUNEMU:
break; tunemu_close(device_fd);
break;
#endif #endif
default:
close(device_fd); default:
close(device_fd);
} }
free(device); free(device);
@ -311,154 +349,165 @@ static bool read_packet(vpn_packet_t *packet) {
int lenin; int lenin;
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
#ifdef ENABLE_TUNEMU #ifdef ENABLE_TUNEMU
case DEVICE_TYPE_TUNEMU: case DEVICE_TYPE_TUNEMU:
if(device_type == DEVICE_TYPE_TUNEMU) if(device_type == DEVICE_TYPE_TUNEMU) {
lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14); lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
else } else
#endif #endif
lenin = read(device_fd, packet->data + 14, MTU - 14); lenin = read(device_fd, packet->data + 14, MTU - 14);
if(lenin <= 0) { if(lenin <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno)); device, strerror(errno));
return false; return false;
}
switch(packet->data[14] >> 4) {
case 4:
packet->data[12] = 0x08;
packet->data[13] = 0x00;
break;
case 6:
packet->data[12] = 0x86;
packet->data[13] = 0xDD;
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false;
}
memset(packet->data, 0, 12);
packet->len = lenin + 14;
break;
case DEVICE_TYPE_UTUN:
case DEVICE_TYPE_TUNIFHEAD: {
if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
switch(packet->data[14] >> 4) {
case 4:
packet->data[12] = 0x08;
packet->data[13] = 0x00;
break;
case 6:
packet->data[12] = 0x86;
packet->data[13] = 0xDD;
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false;
}
memset(packet->data, 0, 12);
packet->len = lenin + 10;
break;
} }
case DEVICE_TYPE_TAP: switch(packet->data[14] >> 4) {
if((lenin = read(device_fd, packet->data, MTU)) <= 0) { case 4:
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, packet->data[12] = 0x08;
device, strerror(errno)); packet->data[13] = 0x00;
return false; break;
}
packet->len = lenin; case 6:
packet->data[12] = 0x86;
packet->data[13] = 0xDD;
break; break;
default: default:
ifdebug(TRAFFIC) logger(LOG_ERR,
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false; return false;
}
memset(packet->data, 0, 12);
packet->len = lenin + 14;
break;
case DEVICE_TYPE_UTUN:
case DEVICE_TYPE_TUNIFHEAD: {
if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
switch(packet->data[14] >> 4) {
case 4:
packet->data[12] = 0x08;
packet->data[13] = 0x00;
break;
case 6:
packet->data[12] = 0x86;
packet->data[13] = 0xDD;
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
"Unknown IP version %d while reading packet from %s %s",
packet->data[14] >> 4, device_info, device);
return false;
}
memset(packet->data, 0, 12);
packet->len = lenin + 10;
break;
}
case DEVICE_TYPE_TAP:
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno));
return false;
}
packet->len = lenin;
break;
default:
return false;
} }
device_total_in += packet->len; device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
packet->len, device_info); packet->len, device_info);
return true; return true;
} }
static bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info); packet->len, device_info);
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) { if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno)); device, strerror(errno));
return false; return false;
}
break;
case DEVICE_TYPE_UTUN:
case DEVICE_TYPE_TUNIFHEAD: {
int af = (packet->data[12] << 8) + packet->data[13];
uint32_t type;
switch (af) {
case 0x0800:
type = htonl(AF_INET);
break;
case 0x86DD:
type = htonl(AF_INET6);
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR,
"Unknown address family %x while writing packet to %s %s",
af, device_info, device);
return false;
}
memcpy(packet->data + 10, &type, sizeof type);
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
} }
case DEVICE_TYPE_TAP: break;
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, case DEVICE_TYPE_UTUN:
device, strerror(errno)); case DEVICE_TYPE_TUNIFHEAD: {
return false; int af = (packet->data[12] << 8) + packet->data[13];
} uint32_t type;
switch(af) {
case 0x0800:
type = htonl(AF_INET);
break; break;
#ifdef ENABLE_TUNEMU case 0x86DD:
case DEVICE_TYPE_TUNEMU: type = htonl(AF_INET6);
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
break; break;
#endif
default: default:
ifdebug(TRAFFIC) logger(LOG_ERR,
"Unknown address family %x while writing packet to %s %s",
af, device_info, device);
return false; return false;
}
memcpy(packet->data + 10, &type, sizeof(type));
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
}
case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
break;
#ifdef ENABLE_TUNEMU
case DEVICE_TYPE_TUNEMU:
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
device, strerror(errno));
return false;
}
break;
#endif
default:
return false;
} }
device_total_out += packet->len; device_total_out += packet->len;

View file

@ -36,37 +36,34 @@
#define PPPPROTO_CTL 1 #define PPPPROTO_CTL 1
#define PPP_IP 0x21 #define PPP_IP 0x21
#define PPP_IPV6 0x57 #define PPP_IPV6 0x57
#define SC_LOOP_TRAFFIC 0x00000200 #define SC_LOOP_TRAFFIC 0x00000200
#define PPPIOCNEWUNIT _IOWR('t', 62, int) #define PPPIOCNEWUNIT _IOWR('t', 62, int)
#define PPPIOCSFLAGS _IOW('t', 89, int) #define PPPIOCSFLAGS _IOW('t', 89, int)
#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) #define PPPIOCSNPMODE _IOW('t', 75, struct npioctl)
#define PPPIOCATTCHAN _IOW('t', 56, int) #define PPPIOCATTCHAN _IOW('t', 56, int)
#define PPPIOCGCHAN _IOR('t', 55, int) #define PPPIOCGCHAN _IOR('t', 55, int)
#define PPPIOCCONNECT _IOW('t', 58, int) #define PPPIOCCONNECT _IOW('t', 58, int)
#define PPPIOCGUNIT _IOR('t', 86, int) #define PPPIOCGUNIT _IOR('t', 86, int)
struct sockaddr_ppp struct sockaddr_ppp {
{
u_int8_t ppp_len; u_int8_t ppp_len;
u_int8_t ppp_family; u_int8_t ppp_family;
u_int16_t ppp_proto; u_int16_t ppp_proto;
u_int32_t ppp_cookie; u_int32_t ppp_cookie;
}; };
enum NPmode enum NPmode {
{
NPMODE_PASS, NPMODE_PASS,
NPMODE_DROP, NPMODE_DROP,
NPMODE_ERROR, NPMODE_ERROR,
NPMODE_QUEUE NPMODE_QUEUE
}; };
struct npioctl struct npioctl {
{
int protocol; int protocol;
enum NPmode mode; enum NPmode mode;
}; };
@ -83,58 +80,55 @@ static pcap_t *pcap = NULL;
static int data_buffer_length = 0; static int data_buffer_length = 0;
static char *data_buffer = NULL; static char *data_buffer = NULL;
static void tun_error(char *format, ...) static void tun_error(char *format, ...) {
{
va_list vl; va_list vl;
va_start(vl, format); va_start(vl, format);
vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl); vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl);
va_end(vl); va_end(vl);
} }
static void tun_noerror() static void tun_noerror() {
{
*tunemu_error = 0; *tunemu_error = 0;
} }
static void closeall() static void closeall() {
{ int fd = getdtablesize();
int fd = getdtablesize();
while (fd--)
close(fd);
open("/dev/null", O_RDWR, 0); while(fd--) {
dup(0); close(fd);
dup(0); }
open("/dev/null", O_RDWR, 0);
dup(0);
dup(0);
} }
static int ppp_load_kext() static int ppp_load_kext() {
{
int pid = fork(); int pid = fork();
if (pid < 0)
{ if(pid < 0) {
tun_error("fork for ppp kext: %s", strerror(errno)); tun_error("fork for ppp kext: %s", strerror(errno));
return -1; return -1;
} }
if (pid == 0) if(pid == 0) {
{
closeall(); closeall();
execle("/sbin/kextload", "kextload", PPP_KEXT_PATH, NULL, NULL); execle("/sbin/kextload", "kextload", PPP_KEXT_PATH, NULL, NULL);
exit(1); exit(1);
} }
int status; int status;
while (waitpid(pid, &status, 0) < 0)
{ while(waitpid(pid, &status, 0) < 0) {
if (errno == EINTR) if(errno == EINTR) {
continue; continue;
}
tun_error("waitpid for ppp kext: %s", strerror(errno)); tun_error("waitpid for ppp kext: %s", strerror(errno));
return -1; return -1;
} }
if (WEXITSTATUS(status) != 0) if(WEXITSTATUS(status) != 0) {
{
tun_error("could not load ppp kext \"%s\"", PPP_KEXT_PATH); tun_error("could not load ppp kext \"%s\"", PPP_KEXT_PATH);
return -1; return -1;
} }
@ -143,74 +137,73 @@ static int ppp_load_kext()
return 0; return 0;
} }
static int ppp_new_instance() static int ppp_new_instance() {
{
// create ppp socket // create ppp socket
int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
if (ppp_sockfd < 0)
{ if(ppp_sockfd < 0) {
if (ppp_load_kext() < 0) if(ppp_load_kext() < 0) {
return -1; return -1;
}
ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL); ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
if (ppp_sockfd < 0)
{ if(ppp_sockfd < 0) {
tun_error("creating ppp socket: %s", strerror(errno)); tun_error("creating ppp socket: %s", strerror(errno));
return -1; return -1;
} }
} }
// connect to ppp procotol // connect to ppp procotol
struct sockaddr_ppp pppaddr; struct sockaddr_ppp pppaddr;
pppaddr.ppp_len = sizeof(struct sockaddr_ppp); pppaddr.ppp_len = sizeof(struct sockaddr_ppp);
pppaddr.ppp_family = AF_PPP; pppaddr.ppp_family = AF_PPP;
pppaddr.ppp_proto = PPPPROTO_CTL; pppaddr.ppp_proto = PPPPROTO_CTL;
pppaddr.ppp_cookie = 0; pppaddr.ppp_cookie = 0;
if (connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0)
{ if(connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) {
tun_error("connecting ppp socket: %s", strerror(errno)); tun_error("connecting ppp socket: %s", strerror(errno));
close(ppp_sockfd); close(ppp_sockfd);
return -1; return -1;
} }
tun_noerror(); tun_noerror();
return ppp_sockfd; return ppp_sockfd;
} }
static int ppp_new_unit(int *unit_number) static int ppp_new_unit(int *unit_number) {
{
int fd = ppp_new_instance(); int fd = ppp_new_instance();
if (fd < 0)
if(fd < 0) {
return -1; return -1;
}
// create ppp unit // create ppp unit
if (ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0) if(ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0) {
{
tun_error("creating ppp unit: %s", strerror(errno)); tun_error("creating ppp unit: %s", strerror(errno));
close(fd); close(fd);
return -1; return -1;
} }
tun_noerror(); tun_noerror();
return fd; return fd;
} }
static int ppp_setup_unit(int unit_fd) static int ppp_setup_unit(int unit_fd) {
{
// send traffic to program // send traffic to program
int flags = SC_LOOP_TRAFFIC; int flags = SC_LOOP_TRAFFIC;
if (ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0)
{ if(ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0) {
tun_error("setting ppp loopback mode: %s", strerror(errno)); tun_error("setting ppp loopback mode: %s", strerror(errno));
return -1; return -1;
} }
// allow packets // allow packets
struct npioctl npi; struct npioctl npi;
npi.protocol = PPP_IP; npi.protocol = PPP_IP;
npi.mode = NPMODE_PASS; npi.mode = NPMODE_PASS;
if (ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0)
{ if(ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0) {
tun_error("starting ppp unit: %s", strerror(errno)); tun_error("starting ppp unit: %s", strerror(errno));
return -1; return -1;
} }
@ -219,10 +212,8 @@ static int ppp_setup_unit(int unit_fd)
return 0; return 0;
} }
static int open_pcap() static int open_pcap() {
{ if(pcap != NULL) {
if (pcap != NULL)
{
pcap_use_count++; pcap_use_count++;
return 0; return 0;
} }
@ -231,8 +222,7 @@ static int open_pcap()
pcap = pcap_open_live("lo0", BUFSIZ, 0, 1, errbuf); pcap = pcap_open_live("lo0", BUFSIZ, 0, 1, errbuf);
pcap_use_count = 1; pcap_use_count = 1;
if (pcap == NULL) if(pcap == NULL) {
{
tun_error("opening pcap: %s", errbuf); tun_error("opening pcap: %s", errbuf);
return -1; return -1;
} }
@ -241,59 +231,57 @@ static int open_pcap()
return 0; return 0;
} }
static void close_pcap() static void close_pcap() {
{ if(pcap == NULL) {
if (pcap == NULL)
return; return;
}
pcap_use_count--; pcap_use_count--;
if (pcap_use_count == 0)
{ if(pcap_use_count == 0) {
pcap_close(pcap); pcap_close(pcap);
pcap = NULL; pcap = NULL;
} }
} }
static void allocate_data_buffer(int size) static void allocate_data_buffer(int size) {
{ if(data_buffer_length < size) {
if (data_buffer_length < size)
{
free(data_buffer); free(data_buffer);
data_buffer_length = size; data_buffer_length = size;
data_buffer = malloc(data_buffer_length); data_buffer = malloc(data_buffer_length);
} }
} }
static void make_device_name(tunemu_device device, int unit_number) static void make_device_name(tunemu_device device, int unit_number) {
{
snprintf(device, sizeof(tunemu_device), "ppp%d", unit_number); snprintf(device, sizeof(tunemu_device), "ppp%d", unit_number);
} }
static int check_device_name(tunemu_device device) static int check_device_name(tunemu_device device) {
{ if(strlen(device) < 4) {
if (strlen(device) < 4)
return -1; return -1;
}
int unit_number = atoi(device + 3); int unit_number = atoi(device + 3);
if (unit_number < 0 || unit_number > 999)
if(unit_number < 0 || unit_number > 999) {
return -1; return -1;
}
tunemu_device compare; tunemu_device compare;
make_device_name(compare, unit_number); make_device_name(compare, unit_number);
if (strcmp(device, compare) != 0) if(strcmp(device, compare) != 0) {
return -1; return -1;
}
return 0; return 0;
} }
int tunemu_open(tunemu_device device) int tunemu_open(tunemu_device device) {
{
int ppp_unit_number = -1; int ppp_unit_number = -1;
if (device[0] != 0)
{ if(device[0] != 0) {
if (check_device_name(device) < 0) if(check_device_name(device) < 0) {
{
tun_error("invalid device name \"%s\"", device); tun_error("invalid device name \"%s\"", device);
return -1; return -1;
} }
@ -302,17 +290,17 @@ int tunemu_open(tunemu_device device)
} }
int ppp_unit_fd = ppp_new_unit(&ppp_unit_number); int ppp_unit_fd = ppp_new_unit(&ppp_unit_number);
if (ppp_unit_fd < 0)
return -1;
if (ppp_setup_unit(ppp_unit_fd) < 0) if(ppp_unit_fd < 0) {
{ return -1;
}
if(ppp_setup_unit(ppp_unit_fd) < 0) {
close(ppp_unit_fd); close(ppp_unit_fd);
return -1; return -1;
} }
if (open_pcap() < 0) if(open_pcap() < 0) {
{
close(ppp_unit_fd); close(ppp_unit_fd);
return -1; return -1;
} }
@ -322,39 +310,40 @@ int tunemu_open(tunemu_device device)
return ppp_unit_fd; return ppp_unit_fd;
} }
int tunemu_close(int ppp_sockfd) int tunemu_close(int ppp_sockfd) {
{
int ret = close(ppp_sockfd); int ret = close(ppp_sockfd);
if (ret == 0) if(ret == 0) {
close_pcap(); close_pcap();
}
return ret; return ret;
} }
int tunemu_read(int ppp_sockfd, char *buffer, int length) int tunemu_read(int ppp_sockfd, char *buffer, int length) {
{
allocate_data_buffer(length + 2); allocate_data_buffer(length + 2);
length = read(ppp_sockfd, data_buffer, length + 2); length = read(ppp_sockfd, data_buffer, length + 2);
if (length < 0)
{ if(length < 0) {
tun_error("reading packet: %s", strerror(errno)); tun_error("reading packet: %s", strerror(errno));
return length; return length;
} }
tun_noerror(); tun_noerror();
length -= 2; length -= 2;
if (length < 0)
if(length < 0) {
return 0; return 0;
}
memcpy(buffer, data_buffer + 2, length); memcpy(buffer, data_buffer + 2, length);
return length; return length;
} }
int tunemu_write(int ppp_sockfd, char *buffer, int length) int tunemu_write(int ppp_sockfd, char *buffer, int length) {
{
allocate_data_buffer(length + 4); allocate_data_buffer(length + 4);
data_buffer[0] = 0x02; data_buffer[0] = 0x02;
@ -364,23 +353,25 @@ int tunemu_write(int ppp_sockfd, char *buffer, int length)
memcpy(data_buffer + 4, buffer, length); memcpy(data_buffer + 4, buffer, length);
if (pcap == NULL) if(pcap == NULL) {
{
tun_error("pcap not open"); tun_error("pcap not open");
return -1; return -1;
} }
length = pcap_inject(pcap, data_buffer, length + 4); length = pcap_inject(pcap, data_buffer, length + 4);
if (length < 0)
{ if(length < 0) {
tun_error("injecting packet: %s", pcap_geterr(pcap)); tun_error("injecting packet: %s", pcap_geterr(pcap));
return length; return length;
} }
tun_noerror(); tun_noerror();
length -= 4; length -= 4;
if (length < 0)
if(length < 0) {
return 0; return 0;
}
return length; return length;
} }

View file

@ -4,7 +4,7 @@
1998-2005 Ivo Timmermans 1998-2005 Ivo Timmermans
2000-2014 Guus Sliepen <guus@tinc-vpn.org> 2000-2014 Guus Sliepen <guus@tinc-vpn.org>
2010-2011 Julien Muchembled <jm@jmuchemb.eu> 2010-2011 Julien Muchembled <jm@jmuchemb.eu>
2000 Cris van Pelt 2000 Cris van Pelt
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -28,18 +28,18 @@
#include "conf.h" #include "conf.h"
#include "list.h" #include "list.h"
#include "logger.h" #include "logger.h"
#include "netutl.h" /* for str2address */ #include "netutl.h" /* for str2address */
#include "protocol.h" #include "protocol.h"
#include "utils.h" /* for cp */ #include "utils.h" /* for cp */
#include "xalloc.h" #include "xalloc.h"
avl_tree_t *config_tree; avl_tree_t *config_tree;
int pinginterval = 0; /* seconds between pings */ int pinginterval = 0; /* seconds between pings */
int pingtimeout = 0; /* seconds to wait for response */ int pingtimeout = 0; /* seconds to wait for response */
char *confbase = NULL; /* directory in which all config files are */ char *confbase = NULL; /* directory in which all config files are */
char *netname = NULL; /* name of the vpn network */ char *netname = NULL; /* name of the vpn network */
list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */ list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */
static int config_compare(const config_t *a, const config_t *b) { static int config_compare(const config_t *a, const config_t *b) {
@ -47,27 +47,31 @@ static int config_compare(const config_t *a, const config_t *b) {
result = strcasecmp(a->variable, b->variable); result = strcasecmp(a->variable, b->variable);
if(result) if(result) {
return result; return result;
}
/* give priority to command line options */ /* give priority to command line options */
result = !b->file - !a->file; result = !b->file - !a->file;
if (result)
if(result) {
return result; return result;
}
result = a->line - b->line; result = a->line - b->line;
if(result) if(result) {
return result; return result;
else } else {
return a->file ? strcmp(a->file, b->file) : 0; return a->file ? strcmp(a->file, b->file) : 0;
}
} }
void init_configuration(avl_tree_t ** config_tree) { void init_configuration(avl_tree_t **config_tree) {
*config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config); *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
} }
void exit_configuration(avl_tree_t ** config_tree) { void exit_configuration(avl_tree_t **config_tree) {
avl_delete_tree(*config_tree); avl_delete_tree(*config_tree);
*config_tree = NULL; *config_tree = NULL;
} }
@ -77,14 +81,17 @@ config_t *new_config(void) {
} }
void free_config(config_t *cfg) { void free_config(config_t *cfg) {
if(cfg->variable) if(cfg->variable) {
free(cfg->variable); free(cfg->variable);
}
if(cfg->value) if(cfg->value) {
free(cfg->value); free(cfg->value);
}
if(cfg->file) if(cfg->file) {
free(cfg->file); free(cfg->file);
}
free(cfg); free(cfg);
} }
@ -102,11 +109,13 @@ config_t *lookup_config(const avl_tree_t *config_tree, char *variable) {
found = avl_search_closest_greater(config_tree, &cfg); found = avl_search_closest_greater(config_tree, &cfg);
if(!found) if(!found) {
return NULL; return NULL;
}
if(strcasecmp(found->variable, variable)) if(strcasecmp(found->variable, variable)) {
return NULL; return NULL;
}
return found; return found;
} }
@ -121,8 +130,9 @@ config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg)
if(node->next) { if(node->next) {
found = node->next->data; found = node->next->data;
if(!strcasecmp(found->variable, cfg->variable)) if(!strcasecmp(found->variable, cfg->variable)) {
return found; return found;
}
} }
} }
@ -130,8 +140,9 @@ config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg)
} }
bool get_config_bool(const config_t *cfg, bool *result) { bool get_config_bool(const config_t *cfg, bool *result) {
if(!cfg) if(!cfg) {
return false; return false;
}
if(!strcasecmp(cfg->value, "yes")) { if(!strcasecmp(cfg->value, "yes")) {
*result = true; *result = true;
@ -142,27 +153,30 @@ bool get_config_bool(const config_t *cfg, bool *result) {
} }
logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d", logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line); cfg->variable, cfg->file, cfg->line);
return false; return false;
} }
bool get_config_int(const config_t *cfg, int *result) { bool get_config_int(const config_t *cfg, int *result) {
if(!cfg) if(!cfg) {
return false; return false;
}
if(sscanf(cfg->value, "%d", result) == 1) if(sscanf(cfg->value, "%d", result) == 1) {
return true; return true;
}
logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d", logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line); cfg->variable, cfg->file, cfg->line);
return false; return false;
} }
bool get_config_string(const config_t *cfg, char **result) { bool get_config_string(const config_t *cfg, char **result) {
if(!cfg) if(!cfg) {
return false; return false;
}
*result = xstrdup(cfg->value); *result = xstrdup(cfg->value);
@ -172,8 +186,9 @@ bool get_config_string(const config_t *cfg, char **result) {
bool get_config_address(const config_t *cfg, struct addrinfo **result) { bool get_config_address(const config_t *cfg, struct addrinfo **result) {
struct addrinfo *ai; struct addrinfo *ai;
if(!cfg) if(!cfg) {
return false; return false;
}
ai = str2addrinfo(cfg->value, NULL, 0); ai = str2addrinfo(cfg->value, NULL, 0);
@ -183,31 +198,32 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) {
} }
logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d", logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line); cfg->variable, cfg->file, cfg->line);
return false; return false;
} }
bool get_config_subnet(const config_t *cfg, subnet_t ** result) { bool get_config_subnet(const config_t *cfg, subnet_t **result) {
subnet_t subnet = {NULL}; subnet_t subnet = {};
if(!cfg) if(!cfg) {
return false; return false;
}
if(!str2net(&subnet, cfg->value)) { if(!str2net(&subnet, cfg->value)) {
logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d", logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line); cfg->variable, cfg->file, cfg->line);
return false; return false;
} }
/* Teach newbies what subnets are... */ /* Teach newbies what subnets are... */
if(((subnet.type == SUBNET_IPV4) if(((subnet.type == SUBNET_IPV4)
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t))) && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
|| ((subnet.type == SUBNET_IPV6) || ((subnet.type == SUBNET_IPV6)
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) { && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d", logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
cfg->variable, cfg->file, cfg->line); cfg->variable, cfg->file, cfg->line);
return false; return false;
} }
@ -219,26 +235,31 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
/* /*
Read exactly one line and strip the trailing newline if any. Read exactly one line and strip the trailing newline if any.
*/ */
static char *readline(FILE * fp, char *buf, size_t buflen) { static char *readline(FILE *fp, char *buf, size_t buflen) {
char *newline = NULL; char *newline = NULL;
char *p; char *p;
if(feof(fp)) if(feof(fp)) {
return NULL; return NULL;
}
p = fgets(buf, buflen, fp); p = fgets(buf, buflen, fp);
if(!p) if(!p) {
return NULL; return NULL;
}
newline = strchr(p, '\n'); newline = strchr(p, '\n');
if(!newline) if(!newline) {
return buf; return buf;
}
*newline = '\0'; /* kill newline */ *newline = '\0'; /* kill newline */
if(newline > p && newline[-1] == '\r') /* and carriage return if necessary */
if(newline > p && newline[-1] == '\r') { /* and carriage return if necessary */
newline[-1] = '\0'; newline[-1] = '\0';
}
return buf; return buf;
} }
@ -250,26 +271,32 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
variable = value = line; variable = value = line;
eol = line + strlen(line); eol = line + strlen(line);
while(strchr("\t ", *--eol))
while(strchr("\t ", *--eol)) {
*eol = '\0'; *eol = '\0';
}
len = strcspn(value, "\t ="); len = strcspn(value, "\t =");
value += len; value += len;
value += strspn(value, "\t "); value += strspn(value, "\t ");
if(*value == '=') { if(*value == '=') {
value++; value++;
value += strspn(value, "\t "); value += strspn(value, "\t ");
} }
variable[len] = '\0'; variable[len] = '\0';
if(!*value) { if(!*value) {
const char err[] = "No value for variable"; const char err[] = "No value for variable";
if (fname)
if(fname)
logger(LOG_ERR, "%s `%s' on line %d while reading config file %s", logger(LOG_ERR, "%s `%s' on line %d while reading config file %s",
err, variable, lineno, fname); err, variable, lineno, fname);
else else
logger(LOG_ERR, "%s `%s' in command line option %d", logger(LOG_ERR, "%s `%s' in command line option %d",
err, variable, lineno); err, variable, lineno);
return NULL; return NULL;
} }
@ -303,22 +330,27 @@ bool read_config_file(avl_tree_t *config_tree, const char *fname) {
} }
for(;;) { for(;;) {
line = readline(fp, buffer, sizeof buffer); line = readline(fp, buffer, sizeof(buffer));
if(!line) { if(!line) {
if(feof(fp)) if(feof(fp)) {
result = true; result = true;
}
break; break;
} }
lineno++; lineno++;
if(!*line || *line == '#') if(!*line || *line == '#') {
continue; continue;
}
if(ignore) { if(ignore) {
if(!strncmp(line, "-----END", 8)) if(!strncmp(line, "-----END", 8)) {
ignore = false; ignore = false;
}
continue; continue;
} }
@ -328,8 +360,11 @@ bool read_config_file(avl_tree_t *config_tree, const char *fname) {
} }
cfg = parse_config_line(line, fname, lineno); cfg = parse_config_line(line, fname, lineno);
if (!cfg)
if(!cfg) {
break; break;
}
config_add(config_tree, cfg); config_add(config_tree, cfg);
} }
@ -339,86 +374,88 @@ bool read_config_file(avl_tree_t *config_tree, const char *fname) {
} }
void read_config_options(avl_tree_t *config_tree, const char *prefix) { void read_config_options(avl_tree_t *config_tree, const char *prefix) {
list_node_t *node, *next;
size_t prefix_len = prefix ? strlen(prefix) : 0; size_t prefix_len = prefix ? strlen(prefix) : 0;
for(node = cmdline_conf->tail; node; node = next) { for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
config_t *orig_cfg, *cfg = (config_t *)node->data; const config_t *cfg = node->data;
next = node->prev;
if(!prefix) { if(!prefix) {
if(strchr(cfg->variable, '.')) if(strchr(cfg->variable, '.')) {
continue; continue;
node->data = NULL; }
list_unlink_node(cmdline_conf, node);
} else { } else {
if(strncmp(prefix, cfg->variable, prefix_len) || if(strncmp(prefix, cfg->variable, prefix_len) ||
cfg->variable[prefix_len] != '.') cfg->variable[prefix_len] != '.') {
continue; continue;
/* Because host configuration is parsed again when }
reconnecting, nodes must not be freed when a prefix
is given. */
orig_cfg = cfg;
cfg = new_config();
cfg->variable = xstrdup(orig_cfg->variable + prefix_len + 1);
cfg->value = xstrdup(orig_cfg->value);
cfg->file = NULL;
cfg->line = orig_cfg->line;
} }
config_add(config_tree, cfg);
config_t *new = new_config();
if(prefix) {
new->variable = xstrdup(cfg->variable + prefix_len + 1);
} else {
new->variable = xstrdup(cfg->variable);
}
new->value = xstrdup(cfg->value);
new->file = NULL;
new->line = cfg->line;
config_add(config_tree, new);
} }
} }
bool read_server_config(void) { bool read_server_config(void) {
char *fname; char fname[PATH_MAX];
bool x; bool x;
read_config_options(config_tree, NULL); read_config_options(config_tree, NULL);
xasprintf(&fname, "%s/tinc.conf", confbase); snprintf(fname, sizeof(fname), "%s/tinc.conf", confbase);
errno = 0;
x = read_config_file(config_tree, fname); x = read_config_file(config_tree, fname);
// We will try to read the conf files in the "conf.d" dir // We will try to read the conf files in the "conf.d" dir
if (x) { if(x) {
char * dname; char dname[PATH_MAX];
xasprintf(&dname, "%s/conf.d", confbase); snprintf(dname, sizeof(dname), "%s/conf.d", confbase);
DIR *dir = opendir (dname); DIR *dir = opendir(dname);
// If we can find this dir // If we can find this dir
if (dir) { if(dir) {
struct dirent *ep; struct dirent *ep;
// We list all the files in it // We list all the files in it
while (x && (ep = readdir (dir))) { while(x && (ep = readdir(dir))) {
size_t l = strlen(ep->d_name); size_t l = strlen(ep->d_name);
// And we try to read the ones that end with ".conf" // And we try to read the ones that end with ".conf"
if (l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) { if(l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) {
free(fname); snprintf(fname, sizeof(fname), "%s/%s", dname, ep->d_name);
xasprintf(&fname, "%s/%s", dname, ep->d_name);
x = read_config_file(config_tree, fname); x = read_config_file(config_tree, fname);
} }
} }
closedir (dir);
closedir(dir);
} }
free(dname);
} }
if(!x) { /* System error: complain */ if(!x && errno) {
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno)); logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
} }
free(fname);
return x; return x;
} }
bool read_connection_config(connection_t *c) { bool read_connection_config(connection_t *c) {
char *fname; char fname[PATH_MAX];
bool x; bool x;
read_config_options(c->config_tree, c->name); read_config_options(c->config_tree, c->name);
xasprintf(&fname, "%s/hosts/%s", confbase, c->name); snprintf(fname, sizeof(fname), "%s/hosts/%s", confbase, c->name);
x = read_config_file(c->config_tree, fname); x = read_config_file(c->config_tree, fname);
free(fname);
return x; return x;
} }
@ -430,34 +467,38 @@ static void disable_old_keys(const char *filename) {
FILE *r, *w; FILE *r, *w;
r = fopen(filename, "r"); r = fopen(filename, "r");
if(!r)
return;
snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename); if(!r) {
return;
}
snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
w = fopen(tmpfile, "w"); w = fopen(tmpfile, "w");
while(fgets(buf, sizeof buf, r)) { while(fgets(buf, sizeof(buf), r)) {
if(!strncmp(buf, "-----BEGIN RSA", 14)) { if(!strncmp(buf, "-----BEGIN RSA", 14)) {
buf[11] = 'O'; buf[11] = 'O';
buf[12] = 'L'; buf[12] = 'L';
buf[13] = 'D'; buf[13] = 'D';
disabled = true; disabled = true;
} } else if(!strncmp(buf, "-----END RSA", 12)) {
else if(!strncmp(buf, "-----END RSA", 12)) {
buf[ 9] = 'O'; buf[ 9] = 'O';
buf[10] = 'L'; buf[10] = 'L';
buf[11] = 'D'; buf[11] = 'D';
disabled = true; disabled = true;
} }
if(w && fputs(buf, w) < 0) { if(w && fputs(buf, w) < 0) {
disabled = false; disabled = false;
break; break;
} }
} }
if(w) if(w) {
fclose(w); fclose(w);
}
fclose(r); fclose(r);
if(!w && disabled) { if(!w && disabled) {
@ -469,10 +510,12 @@ static void disable_old_keys(const char *filename) {
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
// We cannot atomically replace files on Windows. // We cannot atomically replace files on Windows.
char bakfile[PATH_MAX] = ""; char bakfile[PATH_MAX] = "";
snprintf(bakfile, sizeof bakfile, "%s.bak", filename); snprintf(bakfile, sizeof(bakfile), "%s.bak", filename);
if(rename(filename, bakfile) || rename(tmpfile, filename)) { if(rename(filename, bakfile) || rename(tmpfile, filename)) {
rename(bakfile, filename); rename(bakfile, filename);
#else #else
if(rename(tmpfile, filename)) { if(rename(tmpfile, filename)) {
#endif #endif
fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n"); fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
@ -489,8 +532,9 @@ static void disable_old_keys(const char *filename) {
FILE *ask_and_open(const char *filename, const char *what) { FILE *ask_and_open(const char *filename, const char *what) {
FILE *r; FILE *r;
char *directory; char directory[PATH_MAX];
char line[PATH_MAX]; char line[PATH_MAX];
char abspath[PATH_MAX];
const char *fn; const char *fn;
/* Check stdin and stdout */ /* Check stdin and stdout */
@ -502,37 +546,38 @@ FILE *ask_and_open(const char *filename, const char *what) {
} else { } else {
/* Ask for a file and/or directory name. */ /* Ask for a file and/or directory name. */
fprintf(stdout, "Please enter a file to save %s to [%s]: ", fprintf(stdout, "Please enter a file to save %s to [%s]: ",
what, filename); what, filename);
fflush(stdout); fflush(stdout);
fn = readline(stdin, line, sizeof line); fn = readline(stdin, line, sizeof(line));
if(!fn) { if(!fn) {
fprintf(stderr, "Error while reading stdin: %s\n", fprintf(stderr, "Error while reading stdin: %s\n",
strerror(errno)); strerror(errno));
return NULL; return NULL;
} }
if(!strlen(fn)) if(!strlen(fn))
/* User just pressed enter. */ /* User just pressed enter. */
{
fn = filename; fn = filename;
}
} }
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) { if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
#else #else
if(fn[0] != '/') { if(fn[0] != '/') {
#endif #endif
/* The directory is a relative path or a filename. */ /* The directory is a relative path or a filename. */
char *p; getcwd(directory, sizeof(directory));
snprintf(abspath, sizeof(abspath), "%s/%s", directory, fn);
directory = get_current_dir_name(); fn = abspath;
xasprintf(&p, "%s/%s", directory, fn);
free(directory);
fn = p;
} }
umask(0077); /* Disallow everything for group and other */ umask(0077); /* Disallow everything for group and other */
disable_old_keys(fn); disable_old_keys(fn);
@ -542,7 +587,7 @@ FILE *ask_and_open(const char *filename, const char *what) {
if(!r) { if(!r) {
fprintf(stderr, "Error opening file `%s': %s\n", fprintf(stderr, "Error opening file `%s': %s\n",
fn, strerror(errno)); fn, strerror(errno));
return NULL; return NULL;
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_CONF_H
#define TINC_CONF_H
/* /*
conf.h -- header for conf.c conf.h -- header for conf.c
Copyright (C) 1998-2005 Ivo Timmermans Copyright (C) 1998-2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_CONF_H__
#define __TINC_CONF_H__
#include "avl_tree.h" #include "avl_tree.h"
#include "list.h" #include "list.h"
@ -44,25 +44,24 @@ extern char *confbase;
extern char *netname; extern char *netname;
extern list_t *cmdline_conf; extern list_t *cmdline_conf;
extern void init_configuration(avl_tree_t **); extern void init_configuration(avl_tree_t **config_tree);
extern void exit_configuration(avl_tree_t **); extern void exit_configuration(avl_tree_t **config_tree);
extern config_t *new_config(void) __attribute__ ((__malloc__)); extern config_t *new_config(void) __attribute__((__malloc__));
extern void free_config(config_t *); extern void free_config(config_t *cfg);
extern void config_add(avl_tree_t *, config_t *); extern void config_add(avl_tree_t *config_tree, config_t *cfg);
extern config_t *lookup_config(const avl_tree_t *, char *); extern config_t *lookup_config(const avl_tree_t *config_tree, char *variable);
extern config_t *lookup_config_next(const avl_tree_t *, const config_t *); extern config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg);
extern bool get_config_bool(const config_t *, bool *); extern bool get_config_bool(const config_t *cfg, bool *result);
extern bool get_config_int(const config_t *, int *); extern bool get_config_int(const config_t *cfg, int *result);
extern bool get_config_string(const config_t *, char **); extern bool get_config_string(const config_t *cfg, char **result);
extern bool get_config_address(const config_t *, struct addrinfo **); extern bool get_config_address(const config_t *cfg, struct addrinfo **result);
extern bool get_config_subnet(const config_t *, struct subnet_t **); extern bool get_config_subnet(const config_t *cfg, struct subnet_t **result);
extern config_t *parse_config_line(char *, const char *, int); extern config_t *parse_config_line(char *line, const char *fname, int lineno);
extern bool read_config_file(avl_tree_t *, const char *); extern bool read_config_file(avl_tree_t *config_tree, const char *fname);
extern void read_config_options(avl_tree_t *, const char *); extern void read_config_options(avl_tree_t *config_tree, const char *prefix);
extern bool read_server_config(void); extern bool read_server_config(void);
extern bool read_connection_config(struct connection_t *); extern bool read_connection_config(struct connection_t *c);
extern FILE *ask_and_open(const char *, const char *); extern FILE *ask_and_open(const char *fname, const char *what);
extern bool is_safe_path(const char *);
#endif /* __TINC_CONF_H__ */ #endif

View file

@ -28,7 +28,7 @@
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
avl_tree_t *connection_tree; /* Meta connections */ avl_tree_t *connection_tree; /* Meta connections */
connection_t *everyone; connection_t *everyone;
static int connection_compare(const connection_t *a, const connection_t *b) { static int connection_compare(const connection_t *a, const connection_t *b) {
@ -52,8 +52,9 @@ connection_t *new_connection(void) {
c = xmalloc_and_zero(sizeof(connection_t)); c = xmalloc_and_zero(sizeof(connection_t));
if(!c) if(!c) {
return NULL; return NULL;
}
gettimeofday(&c->start, NULL); gettimeofday(&c->start, NULL);
@ -118,8 +119,9 @@ void free_connection(connection_t *c) {
free(c->name); free(c->name);
free(c->hostname); free(c->hostname);
if(c->config_tree) if(c->config_tree) {
exit_configuration(&c->config_tree); exit_configuration(&c->config_tree);
}
free(c); free(c);
} }
@ -141,8 +143,8 @@ void dump_connections(void) {
for(node = connection_tree->head; node; node = node->next) { for(node = connection_tree->head; node; node = node->next) {
c = node->data; c = node->data;
logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d", logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d",
c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof c->status), c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof(c->status)),
c->outbufsize, c->outbufstart, c->outbuflen); c->outbufsize, c->outbufstart, c->outbuflen);
} }
logger(LOG_DEBUG, "End of connections."); logger(LOG_DEBUG, "End of connections.");

View file

@ -1,3 +1,6 @@
#ifndef TINC_CONNECTION_H
#define TINC_CONNECTION_H
/* /*
connection.h -- header for connection.c connection.h -- header for connection.c
Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>,
@ -18,31 +21,28 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_CONNECTION_H__
#define __TINC_CONNECTION_H__
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include "avl_tree.h" #include "avl_tree.h"
#define OPTION_INDIRECT 0x0001 #define OPTION_INDIRECT 0x0001
#define OPTION_TCPONLY 0x0002 #define OPTION_TCPONLY 0x0002
#define OPTION_PMTU_DISCOVERY 0x0004 #define OPTION_PMTU_DISCOVERY 0x0004
#define OPTION_CLAMP_MSS 0x0008 #define OPTION_CLAMP_MSS 0x0008
typedef struct connection_status_t { typedef struct connection_status_t {
unsigned int pinged:1; /* sent ping */ unsigned int pinged: 1; /* sent ping */
unsigned int active:1; /* 1 if active.. */ unsigned int active: 1; /* 1 if active.. */
unsigned int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */ unsigned int connecting: 1; /* 1 if we are waiting for a non-blocking connect() to finish */
unsigned int unused_termreq:1; /* the termination of this connection was requested */ unsigned int unused_termreq: 1; /* the termination of this connection was requested */
unsigned int remove:1; /* Set to 1 if you want this connection removed */ unsigned int remove: 1; /* Set to 1 if you want this connection removed */
unsigned int timeout:1; /* 1 if gotten timeout */ unsigned int timeout: 1; /* 1 if gotten timeout */
unsigned int encryptout:1; /* 1 if we can encrypt outgoing traffic */ unsigned int encryptout: 1; /* 1 if we can encrypt outgoing traffic */
unsigned int decryptin:1; /* 1 if we have to decrypt incoming traffic */ unsigned int decryptin: 1; /* 1 if we have to decrypt incoming traffic */
unsigned int mst:1; /* 1 if this connection is part of a minimum spanning tree */ unsigned int mst: 1; /* 1 if this connection is part of a minimum spanning tree */
unsigned int proxy_passed:1; /* 1 if we are connecting via a proxy and we have finished talking with it */ unsigned int proxy_passed: 1; /* 1 if we are connecting via a proxy and we have finished talking with it */
unsigned int unused:22; unsigned int unused: 22;
} connection_status_t; } connection_status_t;
#include "edge.h" #include "edge.h"
@ -50,57 +50,57 @@ typedef struct connection_status_t {
#include "node.h" #include "node.h"
typedef struct connection_t { typedef struct connection_t {
char *name; /* name he claims to have */ char *name; /* name he claims to have */
union sockaddr_t address; /* his real (internet) ip */ union sockaddr_t address; /* his real (internet) ip */
char *hostname; /* the hostname of its real ip */ char *hostname; /* the hostname of its real ip */
int protocol_version; /* used protocol */ int protocol_version; /* used protocol */
int socket; /* socket used for this connection */ int socket; /* socket used for this connection */
uint32_t options; /* options for this connection */ uint32_t options; /* options for this connection */
connection_status_t status; /* status info */ connection_status_t status; /* status info */
int estimated_weight; /* estimation for the weight of the edge for this connection */ int estimated_weight; /* estimation for the weight of the edge for this connection */
struct timeval start; /* time this connection was started, used for above estimation */ struct timeval start; /* time this connection was started, used for above estimation */
struct outgoing_t *outgoing; /* used to keep track of outgoing connections */ struct outgoing_t *outgoing; /* used to keep track of outgoing connections */
struct node_t *node; /* node associated with the other end */ struct node_t *node; /* node associated with the other end */
struct edge_t *edge; /* edge associated with this connection */ struct edge_t *edge; /* edge associated with this connection */
RSA *rsa_key; /* his public/private key */ RSA *rsa_key; /* his public/private key */
const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */ const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */
const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */ const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */
EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */ EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */
EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */ EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */
uint64_t inbudget; /* Encrypted bytes send budget */ uint64_t inbudget; /* Encrypted bytes send budget */
uint64_t outbudget; /* Encrypted bytes receive budget */ uint64_t outbudget; /* Encrypted bytes receive budget */
char *inkey; /* His symmetric meta key + iv */ char *inkey; /* His symmetric meta key + iv */
char *outkey; /* Our symmetric meta key + iv */ char *outkey; /* Our symmetric meta key + iv */
int inkeylength; /* Length of his key + iv */ int inkeylength; /* Length of his key + iv */
int outkeylength; /* Length of our key + iv */ int outkeylength; /* Length of our key + iv */
const EVP_MD *indigest; const EVP_MD *indigest;
const EVP_MD *outdigest; const EVP_MD *outdigest;
int inmaclength; int inmaclength;
int outmaclength; int outmaclength;
int incompression; int incompression;
int outcompression; int outcompression;
char *mychallenge; /* challenge we received from him */ char *mychallenge; /* challenge we received from him */
char *hischallenge; /* challenge we sent to him */ char *hischallenge; /* challenge we sent to him */
char buffer[MAXBUFSIZE]; /* metadata input buffer */ char buffer[MAXBUFSIZE]; /* metadata input buffer */
int buflen; /* bytes read into buffer */ int buflen; /* bytes read into buffer */
int reqlen; /* length of incoming request */ int reqlen; /* length of incoming request */
int tcplen; /* length of incoming TCPpacket */ length_t tcplen; /* length of incoming TCPpacket */
int allow_request; /* defined if there's only one request possible */ int allow_request; /* defined if there's only one request possible */
char *outbuf; /* metadata output buffer */ char *outbuf; /* metadata output buffer */
int outbufstart; /* index of first meaningful byte in output buffer */ int outbufstart; /* index of first meaningful byte in output buffer */
int outbuflen; /* number of meaningful bytes in output buffer */ int outbuflen; /* number of meaningful bytes in output buffer */
int outbufsize; /* number of bytes allocated to output buffer */ int outbufsize; /* number of bytes allocated to output buffer */
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */ time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */
time_t last_flushed_time; /* last time buffer was empty. Only meaningful if outbuflen > 0 */ time_t last_flushed_time; /* last time buffer was empty. Only meaningful if outbuflen > 0 */
avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */ avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
} connection_t; } connection_t;
extern avl_tree_t *connection_tree; extern avl_tree_t *connection_tree;
@ -108,11 +108,11 @@ extern connection_t *everyone;
extern void init_connections(void); extern void init_connections(void);
extern void exit_connections(void); extern void exit_connections(void);
extern connection_t *new_connection(void) __attribute__ ((__malloc__)); extern connection_t *new_connection(void) __attribute__((__malloc__));
extern void free_connection(connection_t *); extern void free_connection(connection_t *c);
extern void free_connection_partially(connection_t *); extern void free_connection_partially(connection_t *c);
extern void connection_add(connection_t *); extern void connection_add(connection_t *c);
extern void connection_del(connection_t *); extern void connection_del(connection_t *c);
extern void dump_connections(void); extern void dump_connections(void);
#endif /* __TINC_CONNECTION_H__ */ #endif

View file

@ -37,7 +37,7 @@ int device_fd = -1;
static HANDLE device_handle = INVALID_HANDLE_VALUE; static HANDLE device_handle = INVALID_HANDLE_VALUE;
char *device = NULL; char *device = NULL;
char *iface = NULL; char *iface = NULL;
static char *device_info = NULL; static const char *device_info = "Windows tap device";
static uint64_t device_total_in = 0; static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0; static uint64_t device_total_out = 0;
@ -61,8 +61,9 @@ static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device); get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface); get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(device && iface) if(device && iface) {
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
}
/* Open registry and look for network adapters */ /* Open registry and look for network adapters */
@ -71,44 +72,51 @@ static bool setup_device(void) {
return false; return false;
} }
for (i = 0; ; i++) { for(i = 0; ; i++) {
len = sizeof(adapterid); len = sizeof(adapterid);
if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) {
break; break;
}
/* Find out more about this adapter */ /* Find out more about this adapter */
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid); snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) {
continue; continue;
}
len = sizeof(adaptername); len = sizeof(adaptername);
err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len); err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
RegCloseKey(key2); RegCloseKey(key2);
if(err) if(err) {
continue; continue;
}
if(device) { if(device) {
if(!strcmp(device, adapterid)) { if(!strcmp(device, adapterid)) {
found = true; found = true;
break; break;
} else } else {
continue; continue;
}
} }
if(iface) { if(iface) {
if(!strcmp(iface, adaptername)) { if(!strcmp(iface, adaptername)) {
found = true; found = true;
break; break;
} else } else {
continue; continue;
}
} }
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
if(device_handle != INVALID_HANDLE_VALUE) { if(device_handle != INVALID_HANDLE_VALUE) {
CloseHandle(device_handle); CloseHandle(device_handle);
found = true; found = true;
@ -123,11 +131,13 @@ static bool setup_device(void) {
return false; return false;
} }
if(!device) if(!device) {
device = xstrdup(adapterid); device = xstrdup(adapterid);
}
if(!iface) if(!iface) {
iface = xstrdup(adaptername); iface = xstrdup(adaptername);
}
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device); snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
@ -142,7 +152,7 @@ static bool setup_device(void) {
/* The parent opens the tap device for writing. */ /* The parent opens the tap device for writing. */
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0); device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
if(device_handle == INVALID_HANDLE_VALUE) { if(device_handle == INVALID_HANDLE_VALUE) {
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError())); logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
@ -205,13 +215,12 @@ static bool setup_device(void) {
} }
read(device_fd, &gelukt, 1); read(device_fd, &gelukt, 1);
if(gelukt != 1) { if(gelukt != 1) {
logger(LOG_DEBUG, "Tap reader failed!"); logger(LOG_DEBUG, "Tap reader failed!");
return false; return false;
} }
device_info = "Windows tap device";
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info); logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true; return true;
@ -233,7 +242,7 @@ static bool read_packet(vpn_packet_t *packet) {
if((lenin = read(sp[0], packet->data, MTU)) <= 0) { if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno)); device, strerror(errno));
return false; return false;
} }
@ -242,7 +251,7 @@ static bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len; device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info); device_info);
return true; return true;
} }
@ -251,9 +260,9 @@ static bool write_packet(vpn_packet_t *packet) {
long lenout; long lenout;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info); packet->len, device_info);
if(!WriteFile (device_handle, packet->data, packet->len, &lenout, NULL)) { if(!WriteFile(device_handle, packet->data, packet->len, &lenout, NULL)) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError())); logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
return false; return false;
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_DEVICE_H
#define TINC_DEVICE_H
/* /*
device.h -- generic header for device.c device.h -- generic header for device.c
Copyright (C) 2001-2005 Ivo Timmermans Copyright (C) 2001-2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_DEVICE_H__
#define __TINC_DEVICE_H__
#include "net.h" #include "net.h"
extern int device_fd; extern int device_fd;
@ -31,8 +31,8 @@ extern char *iface;
typedef struct devops_t { typedef struct devops_t {
bool (*setup)(void); bool (*setup)(void);
void (*close)(void); void (*close)(void);
bool (*read)(struct vpn_packet_t *); bool (*read)(struct vpn_packet_t *packet);
bool (*write)(struct vpn_packet_t *); bool (*write)(struct vpn_packet_t *packet);
void (*dump_stats)(void); void (*dump_stats)(void);
} devops_t; } devops_t;
@ -44,4 +44,4 @@ extern const devops_t uml_devops;
extern const devops_t vde_devops; extern const devops_t vde_devops;
extern devops_t devops; extern devops_t devops;
#endif /* __TINC_DEVICE_H__ */ #endif

View file

@ -50,8 +50,9 @@ int daemon(int nochdir, int noclose) {
} }
/* If we are the parent, terminate */ /* If we are the parent, terminate */
if(pid) if(pid) {
exit(0); exit(0);
}
/* Detach by becoming the new process group leader */ /* Detach by becoming the new process group leader */
if(setsid() < 0) { if(setsid() < 0) {
@ -86,40 +87,6 @@ int daemon(int nochdir, int noclose) {
} }
#endif #endif
#ifndef HAVE_GET_CURRENT_DIR_NAME
/*
Replacement for the GNU get_current_dir_name function:
get_current_dir_name will malloc(3) an array big enough to hold the
current directory name. If the environment variable PWD is set, and
its value is correct, then that value will be returned.
*/
char *get_current_dir_name(void) {
size_t size;
char *buf;
char *r;
/* Start with 100 bytes. If this turns out to be insufficient to
contain the working directory, double the size. */
size = 100;
buf = xmalloc(size);
errno = 0; /* Success */
r = getcwd(buf, size);
/* getcwd returns NULL and sets errno to ERANGE if the bufferspace
is insufficient to contain the entire working directory. */
while(r == NULL && errno == ERANGE) {
free(buf);
size <<= 1; /* double the size */
buf = xmalloc(size);
r = getcwd(buf, size);
}
return buf;
}
#endif
#ifndef HAVE_ASPRINTF #ifndef HAVE_ASPRINTF
int asprintf(char **buf, const char *fmt, ...) { int asprintf(char **buf, const char *fmt, ...) {
int result; int result;
@ -143,8 +110,9 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
buf[len - 1] = 0; buf[len - 1] = 0;
va_end(aq); va_end(aq);
if(status >= 0) if(status >= 0) {
*buf = xrealloc(*buf, status + 1); *buf = xrealloc(*buf, status + 1);
}
if(status > len - 1) { if(status > len - 1) {
len = status; len = status;

View file

@ -1,3 +1,6 @@
#ifndef TINC_DROPIN_H
#define TINC_DROPIN_H
/* /*
dropin.h -- header file for dropin.c dropin.h -- header file for dropin.c
Copyright (C) 2000-2005 Ivo Timmermans, Copyright (C) 2000-2005 Ivo Timmermans,
@ -18,14 +21,11 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __DROPIN_H__
#define __DROPIN_H__
#include "fake-getaddrinfo.h" #include "fake-getaddrinfo.h"
#include "fake-getnameinfo.h" #include "fake-getnameinfo.h"
#ifndef HAVE_DAEMON #ifndef HAVE_DAEMON
extern int daemon(int, int); extern int daemon(int nochdir, int noclose);
#endif #endif
#ifndef HAVE_GET_CURRENT_DIR_NAME #ifndef HAVE_GET_CURRENT_DIR_NAME
@ -33,16 +33,16 @@ extern char *get_current_dir_name(void);
#endif #endif
#ifndef HAVE_ASPRINTF #ifndef HAVE_ASPRINTF
extern int asprintf(char **, const char *, ...); extern int asprintf(char **buf, const char *fmt, ...);
extern int vasprintf(char **, const char *, va_list ap); extern int vasprintf(char **buf, const char *fmt, va_list ap);
#endif #endif
#ifndef HAVE_GETTIMEOFDAY #ifndef HAVE_GETTIMEOFDAY
extern int gettimeofday(struct timeval *, void *); extern int gettimeofday(struct timeval *tv, void *tz);
#endif #endif
#ifndef HAVE_USLEEP #ifndef HAVE_USLEEP
extern int usleep(long long); extern int usleep(long long usec);
#endif #endif
#endif /* __DROPIN_H__ */ #endif

View file

@ -22,15 +22,16 @@
#include "device.h" #include "device.h"
#include "logger.h" #include "logger.h"
#include "net.h" #include "net.h"
#include "xalloc.h"
static char *device_info = "dummy device"; static const char *device_info = "dummy device";
static uint64_t device_total_in = 0; static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0; static uint64_t device_total_out = 0;
static bool setup_device(void) { static bool setup_device(void) {
device = "dummy"; device = xstrdup("dummy");
iface = "dummy"; iface = xstrdup("dummy");
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info); logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true; return true;
} }
@ -39,6 +40,7 @@ static void close_device(void) {
} }
static bool read_packet(vpn_packet_t *packet) { static bool read_packet(vpn_packet_t *packet) {
(void)packet;
return false; return false;
} }

View file

@ -28,7 +28,7 @@
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */ avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
static int edge_compare(const edge_t *a, const edge_t *b) { static int edge_compare(const edge_t *a, const edge_t *b) {
return strcmp(a->to->name, b->to->name); return strcmp(a->to->name, b->to->name);
@ -39,13 +39,15 @@ static int edge_weight_compare(const edge_t *a, const edge_t *b) {
result = a->weight - b->weight; result = a->weight - b->weight;
if(result) if(result) {
return result; return result;
}
result = strcmp(a->from->name, b->from->name); result = strcmp(a->from->name, b->from->name);
if(result) if(result) {
return result; return result;
}
return strcmp(a->to->name, b->to->name); return strcmp(a->to->name, b->to->name);
} }
@ -84,13 +86,15 @@ void edge_add(edge_t *e) {
e->reverse = lookup_edge(e->to, e->from); e->reverse = lookup_edge(e->to, e->from);
if(e->reverse) if(e->reverse) {
e->reverse->reverse = e; e->reverse->reverse = e;
}
} }
void edge_del(edge_t *e) { void edge_del(edge_t *e) {
if(e->reverse) if(e->reverse) {
e->reverse->reverse = NULL; e->reverse->reverse = NULL;
}
avl_delete(edge_weight_tree, e); avl_delete(edge_weight_tree, e);
avl_delete(e->from->edge_tree, e); avl_delete(e->from->edge_tree, e);
@ -115,11 +119,12 @@ void dump_edges(void) {
for(node = node_tree->head; node; node = node->next) { for(node = node_tree->head; node; node = node->next) {
n = node->data; n = node->data;
for(node2 = n->edge_tree->head; node2; node2 = node2->next) { for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
e = node2->data; e = node2->data;
address = sockaddr2hostname(&e->address); address = sockaddr2hostname(&e->address);
logger(LOG_DEBUG, " %s to %s at %s options %x weight %d", logger(LOG_DEBUG, " %s to %s at %s options %x weight %d",
e->from->name, e->to->name, address, e->options, e->weight); e->from->name, e->to->name, address, e->options, e->weight);
free(address); free(address);
} }
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_EDGE_H
#define TINC_EDGE_H
/* /*
edge.h -- header for edge.c edge.h -- header for edge.c
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_EDGE_H__
#define __TINC_EDGE_H__
#include "avl_tree.h" #include "avl_tree.h"
#include "connection.h" #include "connection.h"
#include "net.h" #include "net.h"
@ -31,24 +31,24 @@ typedef struct edge_t {
struct node_t *to; struct node_t *to;
sockaddr_t address; sockaddr_t address;
uint32_t options; /* options turned on for this edge */ uint32_t options; /* options turned on for this edge */
int weight; /* weight of this edge */ int weight; /* weight of this edge */
struct connection_t *connection; /* connection associated with this edge, if available */ struct connection_t *connection; /* connection associated with this edge, if available */
struct edge_t *reverse; /* edge in the opposite direction, if available */ struct edge_t *reverse; /* edge in the opposite direction, if available */
} edge_t; } edge_t;
extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */ extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
extern void init_edges(void); extern void init_edges(void);
extern void exit_edges(void); extern void exit_edges(void);
extern edge_t *new_edge(void) __attribute__ ((__malloc__)); extern edge_t *new_edge(void) __attribute__((__malloc__));
extern void free_edge(edge_t *); extern void free_edge(edge_t *e);
extern avl_tree_t *new_edge_tree(void) __attribute__ ((__malloc__)); extern avl_tree_t *new_edge_tree(void) __attribute__((__malloc__));
extern void free_edge_tree(avl_tree_t *); extern void free_edge_tree(avl_tree_t *edge_tree);
extern void edge_add(edge_t *); extern void edge_add(edge_t *e);
extern void edge_del(edge_t *); extern void edge_del(edge_t *e);
extern edge_t *lookup_edge(struct node_t *, struct node_t *); extern edge_t *lookup_edge(struct node_t *from, struct node_t *to);
extern void dump_edges(void); extern void dump_edges(void);
#endif /* __TINC_EDGE_H__ */ #endif

View file

@ -1,3 +1,6 @@
#ifndef TINC_ETHERNET_H
#define TINC_ETHERNET_H
/* /*
ethernet.h -- missing Ethernet related definitions ethernet.h -- missing Ethernet related definitions
Copyright (C) 2005 Ivo Timmermans Copyright (C) 2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_ETHERNET_H__
#define __TINC_ETHERNET_H__
#ifndef ETH_ALEN #ifndef ETH_ALEN
#define ETH_ALEN 6 #define ETH_ALEN 6
#endif #endif
@ -50,7 +50,7 @@ struct ether_header {
uint8_t ether_dhost[ETH_ALEN]; uint8_t ether_dhost[ETH_ALEN];
uint8_t ether_shost[ETH_ALEN]; uint8_t ether_shost[ETH_ALEN];
uint16_t ether_type; uint16_t ether_type;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#endif #endif
#ifndef HAVE_STRUCT_ARPHDR #ifndef HAVE_STRUCT_ARPHDR
@ -60,7 +60,7 @@ struct arphdr {
uint8_t ar_hln; uint8_t ar_hln;
uint8_t ar_pln; uint8_t ar_pln;
uint16_t ar_op; uint16_t ar_op;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#define ARPOP_REQUEST 1 #define ARPOP_REQUEST 1
#define ARPOP_REPLY 2 #define ARPOP_REPLY 2
@ -78,7 +78,7 @@ struct ether_arp {
uint8_t arp_spa[4]; uint8_t arp_spa[4];
uint8_t arp_tha[ETH_ALEN]; uint8_t arp_tha[ETH_ALEN];
uint8_t arp_tpa[4]; uint8_t arp_tpa[4];
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#define arp_hrd ea_hdr.ar_hrd #define arp_hrd ea_hdr.ar_hrd
#define arp_pro ea_hdr.ar_pro #define arp_pro ea_hdr.ar_pro
#define arp_hln ea_hdr.ar_hln #define arp_hln ea_hdr.ar_hln
@ -86,4 +86,4 @@ struct ether_arp {
#define arp_op ea_hdr.ar_op #define arp_op ea_hdr.ar_op
#endif #endif
#endif /* __TINC_ETHERNET_H__ */ #endif

View file

@ -31,11 +31,13 @@ extern time_t now;
static int id; static int id;
static int event_compare(const event_t *a, const event_t *b) { static int event_compare(const event_t *a, const event_t *b) {
if(a->time > b->time) if(a->time > b->time) {
return 1; return 1;
}
if(a->time < b->time) if(a->time < b->time) {
return -1; return -1;
}
return a->id - b->id; return a->id - b->id;
} }
@ -55,15 +57,18 @@ void expire_events(void) {
/* /*
* Make all events appear expired by substracting the difference between * Make all events appear expired by substracting the difference between
* the expiration time of the last event and the current time. * the expiration time of the last event and the current time.
*/ */
if(!event_tree->tail) if(!event_tree->tail) {
return; return;
}
event = event_tree->tail->data; event = event_tree->tail->data;
if(event->time <= now)
if(event->time <= now) {
return; return;
}
diff = event->time - now; diff = event->time - now;
@ -108,7 +113,9 @@ event_t *get_expired_event(void) {
} }
event_t *peek_next_event(void) { event_t *peek_next_event(void) {
if (event_tree->head) if(event_tree->head) {
return event_tree->head->data; return event_tree->head->data;
}
return NULL; return NULL;
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_EVENT_H
#define TINC_EVENT_H
/* /*
event.h -- header for event.c event.h -- header for event.c
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_EVENT_H__
#define __TINC_EVENT_H__
#include "avl_tree.h" #include "avl_tree.h"
extern avl_tree_t *event_tree; extern avl_tree_t *event_tree;
@ -37,11 +37,11 @@ typedef struct event {
extern void init_events(void); extern void init_events(void);
extern void exit_events(void); extern void exit_events(void);
extern void expire_events(void); extern void expire_events(void);
extern event_t *new_event(void) __attribute__ ((__malloc__)); extern event_t *new_event(void) __attribute__((__malloc__));
extern void free_event(event_t *); extern void free_event(event_t *event);
extern void event_add(event_t *); extern void event_add(event_t *event);
extern void event_del(event_t *); extern void event_del(event_t *event);
extern event_t *get_expired_event(void); extern event_t *get_expired_event(void);
extern event_t *peek_next_event(void); extern event_t *peek_next_event(void);
#endif /* __TINC_EVENT_H__ */ #endif

View file

@ -1,19 +0,0 @@
/*
* fake library for ssh
*
* This file is included in getaddrinfo.c and getnameinfo.c.
* See getaddrinfo.c and getnameinfo.c.
*/
/* for old netdb.h */
#ifndef EAI_NODATA
#define EAI_NODATA 1
#endif
#ifndef EAI_MEMORY
#define EAI_MEMORY 2
#endif
#ifndef EAI_FAMILY
#define EAI_FAMILY 3
#endif

View file

@ -17,24 +17,25 @@
#include "xalloc.h" #include "xalloc.h"
#if !HAVE_DECL_GAI_STRERROR #if !HAVE_DECL_GAI_STRERROR
char *gai_strerror(int ecode) char *gai_strerror(int ecode) {
{ switch(ecode) {
switch (ecode) { case EAI_NODATA:
case EAI_NODATA: return "No address associated with hostname";
return "No address associated with hostname";
case EAI_MEMORY: case EAI_MEMORY:
return "Memory allocation failure"; return "Memory allocation failure";
case EAI_FAMILY:
return "Address family not supported"; case EAI_FAMILY:
default: return "Address family not supported";
return "Unknown error";
default:
return "Unknown error";
} }
} }
#endif /* !HAVE_GAI_STRERROR */ #endif /* !HAVE_GAI_STRERROR */
#if !HAVE_DECL_FREEADDRINFO #if !HAVE_DECL_FREEADDRINFO
void freeaddrinfo(struct addrinfo *ai) void freeaddrinfo(struct addrinfo *ai) {
{
struct addrinfo *next; struct addrinfo *next;
while(ai) { while(ai) {
@ -46,8 +47,7 @@ void freeaddrinfo(struct addrinfo *ai)
#endif /* !HAVE_FREEADDRINFO */ #endif /* !HAVE_FREEADDRINFO */
#if !HAVE_DECL_GETADDRINFO #if !HAVE_DECL_GETADDRINFO
static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
{
struct addrinfo *ai; struct addrinfo *ai;
ai = xmalloc_and_zero(sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); ai = xmalloc_and_zero(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
@ -62,40 +62,43 @@ static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr)
return ai; return ai;
} }
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
{
struct addrinfo *prev = NULL; struct addrinfo *prev = NULL;
struct hostent *hp; struct hostent *hp;
struct in_addr in = {0}; struct in_addr in = {0};
int i; int i;
uint16_t port = 0; uint16_t port = 0;
if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) {
return EAI_FAMILY; return EAI_FAMILY;
}
if (servname) if(servname) {
port = htons(atoi(servname)); port = htons(atoi(servname));
}
if (hints && hints->ai_flags & AI_PASSIVE) { if(hints && hints->ai_flags & AI_PASSIVE) {
*res = malloc_ai(port, htonl(0x00000000)); *res = malloc_ai(port, htonl(0x00000000));
return 0; return 0;
} }
if (!hostname) { if(!hostname) {
*res = malloc_ai(port, htonl(0x7f000001)); *res = malloc_ai(port, htonl(0x7f000001));
return 0; return 0;
} }
hp = gethostbyname(hostname); hp = gethostbyname(hostname);
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) {
return EAI_NODATA; return EAI_NODATA;
}
for (i = 0; hp->h_addr_list[i]; i++) { for(i = 0; hp->h_addr_list[i]; i++) {
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr); *res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
if(prev) if(prev) {
prev->ai_next = *res; prev->ai_next = *res;
}
prev = *res; prev = *res;
} }

View file

@ -1,7 +1,17 @@
#ifndef _FAKE_GETADDRINFO_H #ifndef TINC_FAKE_GETADDRINFO_H
#define _FAKE_GETADDRINFO_H #define TINC_FAKE_GETADDRINFO_H
#include "fake-gai-errnos.h" #ifndef EAI_NODATA
#define EAI_NODATA 1
#endif
#ifndef EAI_MEMORY
#define EAI_MEMORY 2
#endif
#ifndef EAI_FAMILY
#define EAI_FAMILY 3
#endif
#ifndef AI_PASSIVE #ifndef AI_PASSIVE
# define AI_PASSIVE 1 # define AI_PASSIVE 1
@ -20,14 +30,14 @@
#ifndef HAVE_STRUCT_ADDRINFO #ifndef HAVE_STRUCT_ADDRINFO
struct addrinfo { struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
int ai_family; /* PF_xxx */ int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */ int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
size_t ai_addrlen; /* length of ai_addr */ size_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for hostname */ char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* binary address */ struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */ struct addrinfo *ai_next; /* next structure in linked list */
}; };
#endif /* !HAVE_STRUCT_ADDRINFO */ #endif /* !HAVE_STRUCT_ADDRINFO */
@ -44,4 +54,4 @@ char *gai_strerror(int ecode);
void freeaddrinfo(struct addrinfo *ai); void freeaddrinfo(struct addrinfo *ai);
#endif /* !HAVE_FREEADDRINFO */ #endif /* !HAVE_FREEADDRINFO */
#endif /* _FAKE_GETADDRINFO_H */ #endif

View file

@ -16,39 +16,48 @@
#if !HAVE_DECL_GETNAMEINFO #if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa; struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct hostent *hp; struct hostent *hp;
int len; int len;
if(sa->sa_family != AF_INET) if(sa->sa_family != AF_INET) {
return EAI_FAMILY; return EAI_FAMILY;
}
if(serv && servlen) { if(serv && servlen) {
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
if(len < 0 || len >= servlen)
if(len < 0 || len >= servlen) {
return EAI_MEMORY; return EAI_MEMORY;
}
} }
if(!host || !hostlen) if(!host || !hostlen) {
return 0; return 0;
}
if(flags & NI_NUMERICHOST) { if(flags & NI_NUMERICHOST) {
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr)); len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
if(len < 0 || len >= hostlen)
if(len < 0 || len >= hostlen) {
return EAI_MEMORY; return EAI_MEMORY;
}
return 0; return 0;
} }
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET); hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
if(!hp || !hp->h_name || !hp->h_name[0]) if(!hp || !hp->h_name || !hp->h_name[0]) {
return EAI_NODATA; return EAI_NODATA;
}
len = snprintf(host, hostlen, "%s", hp->h_name); len = snprintf(host, hostlen, "%s", hp->h_name);
if(len < 0 || len >= hostlen)
if(len < 0 || len >= hostlen) {
return EAI_MEMORY; return EAI_MEMORY;
}
return 0; return 0;
} }

View file

@ -1,5 +1,5 @@
#ifndef _FAKE_GETNAMEINFO_H #ifndef TINC_FAKE_GETNAMEINFO_H
#define _FAKE_GETNAMEINFO_H #define TINC_FAKE_GETNAMEINFO_H
#if !HAVE_DECL_GETNAMEINFO #if !HAVE_DECL_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
@ -13,4 +13,4 @@ int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
# define NI_MAXHOST 1025 # define NI_MAXHOST 1025
#endif /* !NI_MAXHOST */ #endif /* !NI_MAXHOST */
#endif /* _FAKE_GETNAMEINFO_H */ #endif

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,6 @@
#ifndef TINC_GETOPT_H
#define TINC_GETOPT_H
/* Declarations for getopt. /* Declarations for getopt.
Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
@ -19,115 +22,111 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef _GETOPT_H #ifdef cplusplus
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* For communication from `getopt' to the caller. /* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument, When `getopt' finds an option that takes an argument,
the argument value is returned here. the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER, Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */ each non-option ARGV-element is returned here. */
extern char *optarg; extern char *optarg;
/* Index in ARGV of the next element to be scanned. /* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller This is used for communication to and from the caller
and for communication between successive calls to `getopt'. and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize. On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan. non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */ how much of ARGV has been scanned so far. */
extern int optind; extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints /* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */ for unrecognized options. */
extern int opterr; extern int opterr;
/* Set to an option character which was unrecognized. */ /* Set to an option character which was unrecognized. */
extern int optopt; extern int optopt;
/* Describe the long-named options requested by the application. /* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is of `struct option' terminated by an element containing a name which is
zero. zero.
The field `has_arg' is: The field `has_arg' is:
no_argument (or 0) if the option does not take an argument, no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument, required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument. optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but to the value given in the field `val' when the option is found, but
left unchanged if the option is not found. left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt' one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */ returns the contents of the `val' field. */
struct option struct option {
{ #if defined (STDC) && STDC
#if defined (__STDC__) && __STDC__ const char *name;
const char *name;
#else #else
char *name; char *name;
#endif #endif
/* has_arg can't be an enum because some compilers complain about /* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */ type mismatches in all the code that assumes it is an int. */
int has_arg; int has_arg;
int *flag; int *flag;
int val; int val;
}; };
/* Names for the values of the `has_arg' field of `struct option'. */ /* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0 #define no_argument 0
#define required_argument 1 #define required_argument 1
#define optional_argument 2 #define optional_argument 2
#if defined (__STDC__) && __STDC__ #if defined (STDC) && STDC
#ifdef __GNU_LIBRARY__ #ifdef GNU_LIBRARY
/* Many other libraries have conflicting prototypes for getopt, with /* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */ errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts); extern int getopt(int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */ #else /* not GNU_LIBRARY */
extern int getopt (); extern int getopt();
#endif /* __GNU_LIBRARY__ */ #endif /* GNU_LIBRARY */
extern int getopt_long (int argc, char *const *argv, const char *shortopts, extern int getopt_long(int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind); const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv, extern int getopt_long_only(int argc, char *const *argv,
const char *shortopts, const char *shortopts,
const struct option *longopts, int *longind); const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */ /* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv, extern int _getopt_internal(int argc, char *const *argv,
const char *shortopts, const char *shortopts,
const struct option *longopts, int *longind, const struct option *longopts, int *longind,
int long_only); int long_only);
#else /* not __STDC__ */ #else /* not STDC */
extern int getopt (); extern int getopt();
extern int getopt_long (); extern int getopt_long();
extern int getopt_long_only (); extern int getopt_long_only();
extern int _getopt_internal (); extern int _getopt_internal();
#endif /* __STDC__ */ #endif /* STDC */
#ifdef __cplusplus #ifdef cplusplus
} }
#endif #endif
#endif /* _GETOPT_H */ #endif

View file

@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "getopt.h" #include "getopt.h"
#if !defined (__STDC__) || !__STDC__ #if !defined (STDC) || !STDC
/* This is a separate conditional since some stdc systems /* This is a separate conditional since some stdc systems
reject `defined (const)'. */ reject `defined (const)'. */
#ifndef const #ifndef const
@ -44,7 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
it is simpler to just do this in the source for each such file. */ it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2 #define GETOPT_INTERFACE_VERSION 2
#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 #if !defined (_LIBC) && defined (GLIBC) && GLIBC >= 2
#include <gnu-versions.h> #include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE #define ELIDE_CODE
@ -55,24 +55,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/* This needs to come after some library #include /* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */ to get GNU_LIBRARY defined. */
#ifdef __GNU_LIBRARY__ #ifdef GNU_LIBRARY
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#ifndef NULL #ifndef NULL
#define NULL 0 #define NULL 0
#endif #endif
int int
getopt_long (argc, argv, options, long_options, opt_index) getopt_long(argc, argv, options, long_options, opt_index)
int argc; int argc;
char *const *argv; char *const *argv;
const char *options; const char *options;
const struct option *long_options; const struct option *long_options;
int *opt_index; int *opt_index;
{ {
return _getopt_internal (argc, argv, options, long_options, opt_index, 0); return _getopt_internal(argc, argv, options, long_options, opt_index, 0);
} }
/* Like getopt_long, but '-' as well as '--' can indicate a long option. /* Like getopt_long, but '-' as well as '--' can indicate a long option.
@ -81,109 +81,115 @@ getopt_long (argc, argv, options, long_options, opt_index)
instead. */ instead. */
int int
getopt_long_only (argc, argv, options, long_options, opt_index) getopt_long_only(argc, argv, options, long_options, opt_index)
int argc; int argc;
char *const *argv; char *const *argv;
const char *options; const char *options;
const struct option *long_options; const struct option *long_options;
int *opt_index; int *opt_index;
{ {
return _getopt_internal (argc, argv, options, long_options, opt_index, 1); return _getopt_internal(argc, argv, options, long_options, opt_index, 1);
} }
#endif /* Not ELIDE_CODE. */ #endif /* Not ELIDE_CODE. */
#ifdef TEST #ifdef TEST
#include <stdio.h> #include <stdio.h>
int int
main (argc, argv) main(argc, argv)
int argc; int argc;
char **argv; char **argv;
{ {
int c; int c;
int digit_optind = 0; int digit_optind = 0;
while (1) while(1) {
{ int this_option_optind = optind ? optind : 1;
int this_option_optind = optind ? optind : 1; int option_index = 0;
int option_index = 0; static struct option long_options[] = {
static struct option long_options[] = {"add", 1, 0, 0},
{ {"append", 0, 0, 0},
{"add", 1, 0, 0}, {"delete", 1, 0, 0},
{"append", 0, 0, 0}, {"verbose", 0, 0, 0},
{"delete", 1, 0, 0}, {"create", 0, 0, 0},
{"verbose", 0, 0, 0}, {"file", 1, 0, 0},
{"create", 0, 0, 0}, {0, 0, 0, 0}
{"file", 1, 0, 0}, };
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789", c = getopt_long(argc, argv, "abc:d:0123456789",
long_options, &option_index); long_options, &option_index);
if (c == -1)
break;
switch (c) if(c == -1) {
{ break;
case 0: }
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0': switch(c) {
case '1': case 0:
case '2': printf("option %s", long_options[option_index].name);
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a': if(optarg) {
printf ("option a\n"); printf(" with arg %s", optarg);
break; }
case 'b': printf("\n");
printf ("option b\n"); break;
break;
case 'c': case '0':
printf ("option c with value `%s'\n", optarg); case '1':
break; case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if(digit_optind != 0 && digit_optind != this_option_optind) {
printf("digits occur in two different argv-elements.\n");
}
case 'd': digit_optind = this_option_optind;
printf ("option d with value `%s'\n", optarg); printf("option %c\n", c);
break; break;
case '?': case 'a':
break; printf("option a\n");
break;
default: case 'b':
printf ("?? getopt returned character code 0%o ??\n", c); printf("option b\n");
break;
case 'c':
printf("option c with value `%s'\n", optarg);
break;
case 'd':
printf("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
} }
}
if (optind < argc) if(optind < argc) {
{ printf("non-option ARGV-elements: ");
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0); while(optind < argc) {
printf("%s ", argv[optind++]);
}
printf("\n");
}
exit(0);
} }
#endif /* TEST */ #endif /* TEST */

View file

@ -84,8 +84,9 @@ static void mst_kruskal(void) {
/* Do we have something to do at all? */ /* Do we have something to do at all? */
if(!edge_weight_tree->head) if(!edge_weight_tree->head) {
return; return;
}
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:"); ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
@ -101,6 +102,7 @@ static void mst_kruskal(void) {
for(node = edge_weight_tree->head; node; node = node->next) { for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data; e = node->data;
if(e->from->status.reachable) { if(e->from->status.reachable) {
e->from->status.visited = true; e->from->status.visited = true;
break; break;
@ -121,16 +123,18 @@ static void mst_kruskal(void) {
e->from->status.visited = true; e->from->status.visited = true;
e->to->status.visited = true; e->to->status.visited = true;
if(e->connection) if(e->connection) {
e->connection->status.mst = true; e->connection->status.mst = true;
}
if(e->reverse->connection) if(e->reverse->connection) {
e->reverse->connection->status.mst = true; e->reverse->connection->status.mst = true;
}
safe_edges++; safe_edges++;
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name, ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
e->to->name, e->weight); e->to->name, e->weight);
if(skipped) { if(skipped) {
skipped = false; skipped = false;
@ -140,7 +144,7 @@ static void mst_kruskal(void) {
} }
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes, ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes,
safe_edges); safe_edges);
} }
/* Implementation of a simple breadth-first search algorithm. /* Implementation of a simple breadth-first search algorithm.
@ -180,22 +184,23 @@ static void sssp_bfs(void) {
/* Loop while todo_list is filled */ /* Loop while todo_list is filled */
for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */ for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */
n = from->data; n = from->data;
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */ for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
e = to->data; e = to->data;
if(!e->reverse) if(!e->reverse) {
continue; continue;
}
/* Situation: /* Situation:
/ /
/ /
----->(n)---e-->(e->to) ----->(n)---e-->(e->to)
\ \
\ \
Where e is an edge, (n) and (e->to) are nodes. Where e is an edge, (n) and (e->to) are nodes.
n->address is set to the e->address of the edge left of n to n. n->address is set to the e->address of the edge left of n to n.
@ -209,13 +214,15 @@ static void sssp_bfs(void) {
indirect = n->status.indirect || e->options & OPTION_INDIRECT; indirect = n->status.indirect || e->options & OPTION_INDIRECT;
if(e->to->status.visited if(e->to->status.visited
&& (!e->to->status.indirect || indirect)) && (!e->to->status.indirect || indirect)) {
continue; continue;
}
// Only update nexthop the first time we visit this node. // Only update nexthop the first time we visit this node.
if(!e->to->status.visited) if(!e->to->status.visited) {
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop; e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
}
e->to->status.visited = true; e->to->status.visited = true;
e->to->status.indirect = indirect; e->to->status.indirect = indirect;
@ -223,8 +230,9 @@ static void sssp_bfs(void) {
e->to->via = indirect ? n->via : e->to; e->to->via = indirect ? n->via : e->to;
e->to->options = e->options; e->to->options = e->options;
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN) if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN) {
update_node_udp(e->to, &e->address); update_node_udp(e->to, &e->address);
}
list_insert_tail(todo_list, e->to); list_insert_tail(todo_list, e->to);
} }
@ -246,10 +254,10 @@ static void sssp_bfs(void) {
if(n->status.reachable) { if(n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
n->name, n->hostname); n->name, n->hostname);
} else { } else {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
n->name, n->hostname); n->name, n->hostname);
} }
/* TODO: only clear status.validkey if node is unreachable? */ /* TODO: only clear status.validkey if node is unreachable? */
@ -278,22 +286,23 @@ static void sssp_bfs(void) {
execute_script(n->status.reachable ? "host-up" : "host-down", envp); execute_script(n->status.reachable ? "host-up" : "host-down", envp);
xasprintf(&name, xasprintf(&name,
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
n->name); n->name);
execute_script(name, envp); execute_script(name, envp);
free(name); free(name);
free(address); free(address);
free(port); free(port);
for(i = 0; i < 7; i++) for(i = 0; i < 7; i++) {
free(envp[i]); free(envp[i]);
}
subnet_update(n, NULL, n->status.reachable); subnet_update(n, NULL, n->status.reachable);
if(!n->status.reachable) { if(!n->status.reachable) {
update_node_udp(n, NULL); update_node_udp(n, NULL);
memset(&n->status, 0, sizeof n->status); memset(&n->status, 0, sizeof(n->status));
n->options = 0; n->options = 0;
} else if(n->connection) { } else if(n->connection) {
send_ans_key(n); send_ans_key(n);
@ -324,8 +333,9 @@ void dump_graph(void) {
char *filename = NULL, *tmpname = NULL; char *filename = NULL, *tmpname = NULL;
FILE *file, *pipe = NULL; FILE *file, *pipe = NULL;
if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) {
return; return;
}
graph_changed = false; graph_changed = false;
@ -368,8 +378,11 @@ void dump_graph(void) {
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
unlink(filename); unlink(filename);
#endif #endif
if(rename(tmpname, filename))
if(rename(tmpname, filename)) {
logger(LOG_ERR, "Could not rename %s to %s: %s\n", tmpname, filename, strerror(errno)); logger(LOG_ERR, "Could not rename %s to %s: %s\n", tmpname, filename, strerror(errno));
}
free(tmpname); free(tmpname);
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_GRAPH_H
#define TINC_GRAPH_H
/* /*
graph.h -- header for graph.c graph.h -- header for graph.c
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
@ -18,10 +21,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_GRAPH_H__
#define __TINC_GRAPH_H__
extern void graph(void); extern void graph(void);
extern void dump_graph(void); extern void dump_graph(void);
#endif /* __TINC_GRAPH_H__ */ #endif

View file

@ -1,3 +1,6 @@
#ifndef TINC_HAVE_H
#define TINC_HAVE_H
/* /*
have.h -- include headers which are known to exist have.h -- include headers which are known to exist
Copyright (C) 1998-2005 Ivo Timmermans Copyright (C) 1998-2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_HAVE_H__
#define __TINC_HAVE_H__
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
#ifdef WITH_WINDOWS2000 #ifdef WITH_WINDOWS2000
#define WINVER Windows2000 #define WINVER Windows2000
@ -30,15 +30,19 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <signal.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <signal.h>
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
#include <w32api.h> #include <w32api.h>
@ -55,10 +59,6 @@
#include <termios.h> #include <termios.h>
#endif #endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef HAVE_ALLOCA_H #ifdef HAVE_ALLOCA_H
#include <alloca.h> #include <alloca.h>
#endif #endif
@ -211,4 +211,4 @@
#include <linux/if_tun.h> #include <linux/if_tun.h>
#endif #endif
#endif /* __TINC_SYSTEM_H__ */ #endif

View file

@ -1,3 +1,6 @@
#ifndef TINC_IPV4_H
#define TINC_IPV4_H
/* /*
ipv4.h -- missing IPv4 related definitions ipv4.h -- missing IPv4 related definitions
Copyright (C) 2005 Ivo Timmermans Copyright (C) 2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_IPV4_H__
#define __TINC_IPV4_H__
#ifndef AF_INET #ifndef AF_INET
#define AF_INET 2 #define AF_INET 2
#endif #endif
@ -63,12 +63,12 @@
#ifndef HAVE_STRUCT_IP #ifndef HAVE_STRUCT_IP
struct ip { struct ip {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if BYTE_ORDER == LITTLE_ENDIAN
unsigned int ip_hl:4; unsigned int ip_hl: 4;
unsigned int ip_v:4; unsigned int ip_v: 4;
#else #else
unsigned int ip_v:4; unsigned int ip_v: 4;
unsigned int ip_hl:4; unsigned int ip_hl: 4;
#endif #endif
uint8_t ip_tos; uint8_t ip_tos;
uint16_t ip_len; uint16_t ip_len;
@ -81,7 +81,7 @@ struct ip {
uint8_t ip_p; uint8_t ip_p;
uint16_t ip_sum; uint16_t ip_sum;
struct in_addr ip_src, ip_dst; struct in_addr ip_src, ip_dst;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#endif #endif
#ifndef IP_OFFMASK #ifndef IP_OFFMASK
@ -143,7 +143,7 @@ struct icmp {
#define icmp_radv icmp_dun.id_radv #define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask #define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data #define icmp_data icmp_dun.id_data
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#endif #endif
#endif /* __TINC_IPV4_H__ */ #endif

View file

@ -1,3 +1,6 @@
#ifndef TINC_IPV6_H
#define TINC_IPV6_H
/* /*
ipv6.h -- missing IPv6 related definitions ipv6.h -- missing IPv6 related definitions
Copyright (C) 2005 Ivo Timmermans Copyright (C) 2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_IPV6_H__
#define __TINC_IPV6_H__
#ifndef AF_INET6 #ifndef AF_INET6
#define AF_INET6 10 #define AF_INET6 10
#endif #endif
@ -36,7 +36,7 @@ struct in6_addr {
uint16_t u6_addr16[8]; uint16_t u6_addr16[8];
uint32_t u6_addr32[4]; uint32_t u6_addr32[4];
} in6_u; } in6_u;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#define s6_addr in6_u.u6_addr8 #define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_addr16 #define s6_addr16 in6_u.u6_addr16
#define s6_addr32 in6_u.u6_addr32 #define s6_addr32 in6_u.u6_addr32
@ -49,14 +49,14 @@ struct sockaddr_in6 {
uint32_t sin6_flowinfo; uint32_t sin6_flowinfo;
struct in6_addr sin6_addr; struct in6_addr sin6_addr;
uint32_t sin6_scope_id; uint32_t sin6_scope_id;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#endif #endif
#ifndef IN6_IS_ADDR_V4MAPPED #ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED(a) \ #define IN6_IS_ADDR_V4MAPPED(a) \
((((__const uint32_t *) (a))[0] == 0) \ ((((const uint32_t *) (a))[0] == 0) \
&& (((__const uint32_t *) (a))[1] == 0) \ && (((const uint32_t *) (a))[1] == 0) \
&& (((__const uint32_t *) (a))[2] == htonl (0xffff))) && (((const uint32_t *) (a))[2] == htonl (0xffff)))
#endif #endif
#ifndef HAVE_STRUCT_IP6_HDR #ifndef HAVE_STRUCT_IP6_HDR
@ -72,7 +72,7 @@ struct ip6_hdr {
} ip6_ctlun; } ip6_ctlun;
struct in6_addr ip6_src; struct in6_addr ip6_src;
struct in6_addr ip6_dst; struct in6_addr ip6_dst;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_vfc ip6_ctlun.ip6_un2_vfc
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
@ -91,7 +91,7 @@ struct icmp6_hdr {
uint16_t icmp6_un_data16[2]; uint16_t icmp6_un_data16[2];
uint8_t icmp6_un_data8[4]; uint8_t icmp6_un_data8[4];
} icmp6_dataun; } icmp6_dataun;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#define ICMP6_DST_UNREACH_NOROUTE 0 #define ICMP6_DST_UNREACH_NOROUTE 0
#define ICMP6_DST_UNREACH 1 #define ICMP6_DST_UNREACH 1
#define ICMP6_PACKET_TOO_BIG 2 #define ICMP6_PACKET_TOO_BIG 2
@ -111,7 +111,7 @@ struct icmp6_hdr {
struct nd_neighbor_solicit { struct nd_neighbor_solicit {
struct icmp6_hdr nd_ns_hdr; struct icmp6_hdr nd_ns_hdr;
struct in6_addr nd_ns_target; struct in6_addr nd_ns_target;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#define ND_OPT_SOURCE_LINKADDR 1 #define ND_OPT_SOURCE_LINKADDR 1
#define ND_OPT_TARGET_LINKADDR 2 #define ND_OPT_TARGET_LINKADDR 2
#define nd_ns_type nd_ns_hdr.icmp6_type #define nd_ns_type nd_ns_hdr.icmp6_type
@ -124,7 +124,7 @@ struct nd_neighbor_solicit {
struct nd_opt_hdr { struct nd_opt_hdr {
uint8_t nd_opt_type; uint8_t nd_opt_type;
uint8_t nd_opt_len; uint8_t nd_opt_len;
} __attribute__ ((__packed__)); } __attribute__((__packed__));
#endif #endif
#endif /* __TINC_IPV6_H__ */ #endif

View file

@ -47,7 +47,7 @@ char *device = NULL;
char *iface = NULL; char *iface = NULL;
static char *type = NULL; static char *type = NULL;
static char ifrname[IFNAMSIZ]; static char ifrname[IFNAMSIZ];
static char *device_info; static const char *device_info;
static uint64_t device_total_in = 0; static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0; static uint64_t device_total_out = 0;
@ -56,13 +56,16 @@ static bool setup_device(void) {
struct ifreq ifr; struct ifreq ifr;
bool t1q = false; bool t1q = false;
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
device = xstrdup(DEFAULT_DEVICE); device = xstrdup(DEFAULT_DEVICE);
}
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
#ifdef HAVE_LINUX_IF_TUN_H #ifdef HAVE_LINUX_IF_TUN_H
if (netname != NULL) if(netname != NULL) {
iface = xstrdup(netname); iface = xstrdup(netname);
}
#else #else
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device); iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
#endif #endif
@ -94,17 +97,22 @@ static bool setup_device(void) {
device_type = DEVICE_TYPE_TUN; device_type = DEVICE_TYPE_TUN;
device_info = "Linux tun/tap device (tun mode)"; device_info = "Linux tun/tap device (tun mode)";
} else { } else {
if (routing_mode == RMODE_ROUTER) if(routing_mode == RMODE_ROUTER) {
overwrite_mac = true; overwrite_mac = true;
}
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
device_type = DEVICE_TYPE_TAP; device_type = DEVICE_TYPE_TAP;
device_info = "Linux tun/tap device (tap mode)"; device_info = "Linux tun/tap device (tap mode)";
} }
#ifdef IFF_ONE_QUEUE #ifdef IFF_ONE_QUEUE
/* Set IFF_ONE_QUEUE flag... */ /* Set IFF_ONE_QUEUE flag... */
if(get_config_bool(lookup_config(config_tree, "IffOneQueue"), &t1q) && t1q) if(get_config_bool(lookup_config(config_tree, "IffOneQueue"), &t1q) && t1q) {
ifr.ifr_flags |= IFF_ONE_QUEUE; ifr.ifr_flags |= IFF_ONE_QUEUE;
}
#endif #endif
if(iface) { if(iface) {
@ -117,6 +125,9 @@ static bool setup_device(void) {
ifrname[IFNAMSIZ - 1] = 0; ifrname[IFNAMSIZ - 1] = 0;
free(iface); free(iface);
iface = xstrdup(ifrname); iface = xstrdup(ifrname);
} else if(errno == EPERM || errno == EBUSY) {
logger(LOG_ERR, "Error while trying to configure %s: %s", device, strerror(errno));
return false;
} else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) { } else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) {
logger(LOG_WARNING, "Old ioctl() request was needed for %s", device); logger(LOG_WARNING, "Old ioctl() request was needed for %s", device);
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ); strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
@ -126,16 +137,19 @@ static bool setup_device(void) {
} else } else
#endif #endif
{ {
if(routing_mode == RMODE_ROUTER) if(routing_mode == RMODE_ROUTER) {
overwrite_mac = true; overwrite_mac = true;
}
device_info = "Linux ethertap device"; device_info = "Linux ethertap device";
device_type = DEVICE_TYPE_ETHERTAP; device_type = DEVICE_TYPE_ETHERTAP;
free(iface); free(iface);
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device); iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
} }
if(overwrite_mac && !ioctl(device_fd, SIOCGIFHWADDR, &ifr)) if(overwrite_mac && !ioctl(device_fd, SIOCGIFHWADDR, &ifr)) {
memcpy(mymac.x, ifr.ifr_hwaddr.sa_data, ETH_ALEN); memcpy(mymac.x, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
}
logger(LOG_INFO, "%s is a %s", device, device_info); logger(LOG_INFO, "%s is a %s", device, device_info);
@ -154,79 +168,87 @@ static bool read_packet(vpn_packet_t *packet) {
int lenin; int lenin;
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
lenin = read(device_fd, packet->data + 10, MTU - 10); lenin = read(device_fd, packet->data + 10, MTU - 10);
if(lenin <= 0) { if(lenin <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", logger(LOG_ERR, "Error while reading from %s %s: %s",
device_info, device, strerror(errno)); device_info, device, strerror(errno));
return false; return false;
} }
memset(packet->data, 0, 12); memset(packet->data, 0, 12);
packet->len = lenin + 10; packet->len = lenin + 10;
break; break;
case DEVICE_TYPE_TAP:
lenin = read(device_fd, packet->data, MTU);
if(lenin <= 0) { case DEVICE_TYPE_TAP:
logger(LOG_ERR, "Error while reading from %s %s: %s", lenin = read(device_fd, packet->data, MTU);
device_info, device, strerror(errno));
return false;
}
packet->len = lenin; if(lenin <= 0) {
break; logger(LOG_ERR, "Error while reading from %s %s: %s",
case DEVICE_TYPE_ETHERTAP: device_info, device, strerror(errno));
lenin = read(device_fd, packet->data - 2, MTU + 2); return false;
}
if(lenin <= 0) { packet->len = lenin;
logger(LOG_ERR, "Error while reading from %s %s: %s", break;
device_info, device, strerror(errno));
return false;
}
packet->len = lenin - 2; case DEVICE_TYPE_ETHERTAP:
break; lenin = read(device_fd, packet->data - 2, MTU + 2);
if(lenin <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s",
device_info, device, strerror(errno));
return false;
}
packet->len = lenin - 2;
break;
} }
device_total_in += packet->len; device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info); device_info);
return true; return true;
} }
static bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info); packet->len, device_info);
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
packet->data[10] = packet->data[11] = 0; packet->data[10] = packet->data[11] = 0;
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
case DEVICE_TYPE_ETHERTAP:
memcpy(packet->data - 2, &packet->len, 2);
if(write(device_fd, packet->data - 2, packet->len + 2) < 0) { if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno)); strerror(errno));
return false; return false;
} }
break;
break;
case DEVICE_TYPE_TAP:
if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
case DEVICE_TYPE_ETHERTAP:
memcpy(packet->data - 2, &packet->len, 2);
if(write(device_fd, packet->data - 2, packet->len + 2) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno));
return false;
}
break;
} }
device_total_out += packet->len; device_total_out += packet->len;

View file

@ -43,8 +43,9 @@ list_node_t *list_alloc_node(void) {
} }
void list_free_node(list_t *list, list_node_t *node) { void list_free_node(list_t *list, list_node_t *node) {
if(node->data && list->delete) if(node->data && list->delete) {
list->delete(node->data); list->delete(node->data);
}
free(node); free(node);
} }
@ -61,10 +62,11 @@ list_node_t *list_insert_head(list_t *list, void *data) {
node->next = list->head; node->next = list->head;
list->head = node; list->head = node;
if(node->next) if(node->next) {
node->next->prev = node; node->next->prev = node;
else } else {
list->tail = node; list->tail = node;
}
list->count++; list->count++;
@ -81,10 +83,11 @@ list_node_t *list_insert_tail(list_t *list, void *data) {
node->prev = list->tail; node->prev = list->tail;
list->tail = node; list->tail = node;
if(node->prev) if(node->prev) {
node->prev->next = node; node->prev->next = node;
else } else {
list->head = node; list->head = node;
}
list->count++; list->count++;
@ -92,15 +95,17 @@ list_node_t *list_insert_tail(list_t *list, void *data) {
} }
void list_unlink_node(list_t *list, list_node_t *node) { void list_unlink_node(list_t *list, list_node_t *node) {
if(node->prev) if(node->prev) {
node->prev->next = node->next; node->prev->next = node->next;
else } else {
list->head = node->next; list->head = node->next;
}
if(node->next) if(node->next) {
node->next->prev = node->prev; node->next->prev = node->prev;
else } else {
list->tail = node->prev; list->tail = node->prev;
}
list->count--; list->count--;
} }
@ -121,17 +126,19 @@ void list_delete_tail(list_t *list) {
/* Head/tail lookup */ /* Head/tail lookup */
void *list_get_head(list_t *list) { void *list_get_head(list_t *list) {
if(list->head) if(list->head) {
return list->head->data; return list->head->data;
else } else {
return NULL; return NULL;
}
} }
void *list_get_tail(list_t *list) { void *list_get_tail(list_t *list) {
if(list->tail) if(list->tail) {
return list->tail->data; return list->tail->data;
else } else {
return NULL; return NULL;
}
} }
/* Fast list deletion */ /* Fast list deletion */
@ -163,7 +170,9 @@ void list_foreach(list_t *list, list_action_t action) {
for(node = list->head; node; node = next) { for(node = list->head; node; node = next) {
next = node->next; next = node->next;
if(node->data)
if(node->data) {
action(node->data); action(node->data);
}
} }
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_LIST_H
#define TINC_LIST_H
/* /*
list.h -- header file for list.c list.h -- header file for list.c
Copyright (C) 2000-2005 Ivo Timmermans Copyright (C) 2000-2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_LIST_H__
#define __TINC_LIST_H__
typedef struct list_node_t { typedef struct list_node_t {
struct list_node_t *prev; struct list_node_t *prev;
struct list_node_t *next; struct list_node_t *next;
@ -45,34 +45,34 @@ typedef struct list_t {
/* (De)constructors */ /* (De)constructors */
extern list_t *list_alloc(list_action_t) __attribute__ ((__malloc__)); extern list_t *list_alloc(list_action_t) __attribute__((__malloc__));
extern void list_free(list_t *); extern void list_free(list_t *list);
extern list_node_t *list_alloc_node(void); extern list_node_t *list_alloc_node(void);
extern void list_free_node(list_t *, list_node_t *); extern void list_free_node(list_t *list, list_node_t *node);
/* Insertion and deletion */ /* Insertion and deletion */
extern list_node_t *list_insert_head(list_t *, void *); extern list_node_t *list_insert_head(list_t *list, void *data);
extern list_node_t *list_insert_tail(list_t *, void *); extern list_node_t *list_insert_tail(list_t *list, void *data);
extern void list_unlink_node(list_t *, list_node_t *); extern void list_unlink_node(list_t *list, list_node_t *node);
extern void list_delete_node(list_t *, list_node_t *); extern void list_delete_node(list_t *list, list_node_t *node);
extern void list_delete_head(list_t *); extern void list_delete_head(list_t *list);
extern void list_delete_tail(list_t *); extern void list_delete_tail(list_t *list);
/* Head/tail lookup */ /* Head/tail lookup */
extern void *list_get_head(list_t *); extern void *list_get_head(list_t *list);
extern void *list_get_tail(list_t *); extern void *list_get_tail(list_t *list);
/* Fast list deletion */ /* Fast list deletion */
extern void list_delete_list(list_t *); extern void list_delete_list(list_t *list);
/* Traversing */ /* Traversing */
extern void list_foreach(list_t *, list_action_t); extern void list_foreach(list_t *list, list_action_t action);
extern void list_foreach_node(list_t *, list_action_node_t); extern void list_foreach_node(list_t *list, list_action_node_t action);
#endif /* __TINC_LIST_H__ */ #endif

View file

@ -38,46 +38,56 @@ void openlogger(const char *ident, logmode_t mode) {
logmode = mode; logmode = mode;
switch(mode) { switch(mode) {
case LOGMODE_STDERR: case LOGMODE_STDERR:
logpid = getpid(); logpid = getpid();
break; break;
case LOGMODE_FILE:
logpid = getpid(); case LOGMODE_FILE:
logfile = fopen(logfilename, "a"); logpid = getpid();
if(!logfile) { logfile = fopen(logfilename, "a");
fprintf(stderr, "Could not open log file %s: %s\n", logfilename, strerror(errno));
logmode = LOGMODE_NULL; if(!logfile) {
} fprintf(stderr, "Could not open log file %s: %s\n", logfilename, strerror(errno));
break; logmode = LOGMODE_NULL;
case LOGMODE_SYSLOG: }
break;
case LOGMODE_SYSLOG:
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
loghandle = RegisterEventSource(NULL, logident); loghandle = RegisterEventSource(NULL, logident);
if(!loghandle) {
fprintf(stderr, "Could not open log handle!"); if(!loghandle) {
logmode = LOGMODE_NULL; fprintf(stderr, "Could not open log handle!");
} logmode = LOGMODE_NULL;
break; }
break;
#else #else
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
openlog(logident, LOG_CONS | LOG_PID, LOG_DAEMON); openlog(logident, LOG_CONS | LOG_PID, LOG_DAEMON);
break; break;
#endif #endif
#endif #endif
case LOGMODE_NULL:
break; case LOGMODE_NULL:
break;
} }
} }
void reopenlogger() { void reopenlogger() {
if(logmode != LOGMODE_FILE) if(logmode != LOGMODE_FILE) {
return; return;
}
fflush(logfile); fflush(logfile);
FILE *newfile = fopen(logfilename, "a"); FILE *newfile = fopen(logfilename, "a");
if(!newfile) { if(!newfile) {
logger(LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno)); logger(LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno));
return; return;
} }
fclose(logfile); fclose(logfile);
logfile = newfile; logfile = newfile;
} }
@ -90,44 +100,48 @@ void logger(int priority, const char *format, ...) {
va_start(ap, format); va_start(ap, format);
switch(logmode) { switch(logmode) {
case LOGMODE_STDERR: case LOGMODE_STDERR:
vfprintf(stderr, format, ap); vfprintf(stderr, format, ap);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fflush(stderr); fflush(stderr);
break; break;
case LOGMODE_FILE:
now = time(NULL); case LOGMODE_FILE:
strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now)); now = time(NULL);
fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid); strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now));
vfprintf(logfile, format, ap); fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid);
fprintf(logfile, "\n"); vfprintf(logfile, format, ap);
fflush(logfile); fprintf(logfile, "\n");
break; fflush(logfile);
case LOGMODE_SYSLOG: break;
case LOGMODE_SYSLOG:
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
{ {
char message[4096]; char message[4096];
const char *messages[] = {message}; const char *messages[] = {message};
vsnprintf(message, sizeof(message), format, ap); vsnprintf(message, sizeof(message), format, ap);
message[sizeof message - 1] = 0; message[sizeof(message) - 1] = 0;
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL); ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
} }
#else #else
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
#ifdef HAVE_VSYSLOG #ifdef HAVE_VSYSLOG
vsyslog(priority, format, ap); vsyslog(priority, format, ap);
#else #else
{ {
char message[4096]; char message[4096];
vsnprintf(message, sizeof(message), format, ap); vsnprintf(message, sizeof(message), format, ap);
syslog(priority, "%s", message); syslog(priority, "%s", message);
} }
#endif #endif
break; break;
#endif #endif
#endif #endif
case LOGMODE_NULL:
break; case LOGMODE_NULL:
break;
} }
va_end(ap); va_end(ap);
@ -135,22 +149,24 @@ void logger(int priority, const char *format, ...) {
void closelogger(void) { void closelogger(void) {
switch(logmode) { switch(logmode) {
case LOGMODE_FILE: case LOGMODE_FILE:
fclose(logfile); fclose(logfile);
break; break;
case LOGMODE_SYSLOG:
case LOGMODE_SYSLOG:
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
DeregisterEventSource(loghandle); DeregisterEventSource(loghandle);
break; break;
#else #else
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
closelog(); closelog();
break; break;
#endif #endif
#endif #endif
case LOGMODE_NULL:
case LOGMODE_STDERR: case LOGMODE_NULL:
break; case LOGMODE_STDERR:
break; break;
break;
} }
} }

View file

@ -1,17 +1,36 @@
#ifndef __TINC_LOGGER_H__ #ifndef TINC_LOGGER_H
#define __TINC_LOGGER_H__ #define TINC_LOGGER_H
/*
logger.h -- header file for logger.c
Copyright (C) 2003-2016 Guus Sliepen <guus@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
typedef enum debug_t { typedef enum debug_t {
DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */ DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */
DEBUG_ALWAYS = 0, DEBUG_ALWAYS = 0,
DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */ DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */
DEBUG_ERROR = 2, /* Show error messages received from other hosts */ DEBUG_ERROR = 2, /* Show error messages received from other hosts */
DEBUG_STATUS = 2, /* Show status messages received from other hosts */ DEBUG_STATUS = 2, /* Show status messages received from other hosts */
DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */ DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */
DEBUG_META = 4, /* Show contents of every request that is sent/received */ DEBUG_META = 4, /* Show contents of every request that is sent/received */
DEBUG_TRAFFIC = 5, /* Show network traffic information */ DEBUG_TRAFFIC = 5, /* Show network traffic information */
DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */ DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */
DEBUG_SCARY_THINGS = 10 /* You have been warned */ DEBUG_SCARY_THINGS = 10, /* You have been warned */
} debug_t; } debug_t;
typedef enum logmode_t { typedef enum logmode_t {
@ -46,11 +65,11 @@ enum {
#endif #endif
extern debug_t debug_level; extern debug_t debug_level;
extern void openlogger(const char *, logmode_t); extern void openlogger(const char *ident, logmode_t mode);
extern void reopenlogger(void); extern void reopenlogger(void);
extern void logger(int, const char *, ...) __attribute__ ((__format__(printf, 2, 3))); extern void logger(int priority, const char *format, ...) __attribute__((__format__(printf, 2, 3)));
extern void closelogger(void); extern void closelogger(void);
#define ifdebug(l) if(debug_level >= DEBUG_##l) #define ifdebug(l) if(debug_level >= DEBUG_##l)
#endif /* __TINC_LOGGER_H__ */ #endif

View file

@ -38,16 +38,12 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
int outlen; int outlen;
int result; int result;
if(!c) {
logger(LOG_ERR, "send_meta() called with NULL pointer!");
abort();
}
ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length, ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
c->name, c->hostname); c->name, c->hostname);
if(!c->outbuflen) if(!c->outbuflen) {
c->last_flushed_time = now; c->last_flushed_time = now;
}
/* Find room in connection's buffer */ /* Find room in connection's buffer */
if(length + c->outbuflen > c->outbufsize) { if(length + c->outbuflen > c->outbufsize) {
@ -63,7 +59,7 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
/* Add our data to buffer */ /* Add our data to buffer */
if(c->status.encryptout) { if(c->status.encryptout) {
/* Check encryption limits */ /* Check encryption limits */
if(length > c->outbudget) { if((uint64_t)length > c->outbudget) {
ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname); ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname);
return false; return false;
} else { } else {
@ -71,15 +67,17 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
} }
result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen, result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen,
&outlen, (unsigned char *)buffer, length); &outlen, (unsigned char *)buffer, length);
if(!result || outlen < length) { if(!result || outlen < length) {
logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s", logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} else if(outlen > length) { } else if(outlen > length) {
logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!"); logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!");
abort(); abort();
} }
c->outbuflen += outlen; c->outbuflen += outlen;
} else { } else {
memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length); memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length);
@ -93,23 +91,24 @@ bool flush_meta(connection_t *c) {
int result; int result;
ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)", ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)",
c->outbuflen, c->name, c->hostname); c->outbuflen, c->name, c->hostname);
while(c->outbuflen) { while(c->outbuflen) {
result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0); result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0);
if(result <= 0) { if(result <= 0) {
if(!errno || errno == EPIPE) { if(!errno || errno == EPIPE) {
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
c->name, c->hostname); c->name, c->hostname);
} else if(errno == EINTR) { } else if(errno == EINTR) {
continue; continue;
} else if(sockwouldblock(sockerrno)) { } else if(sockwouldblock(sockerrno)) {
ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block", ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block",
c->outbuflen, c->name, c->hostname); c->outbuflen, c->name, c->hostname);
return true; return true;
} else { } else {
logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name, logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name,
c->hostname, sockstrerror(sockerrno)); c->hostname, sockstrerror(sockerrno));
} }
return false; return false;
@ -130,8 +129,9 @@ void broadcast_meta(connection_t *from, const char *buffer, int length) {
for(node = connection_tree->head; node; node = node->next) { for(node = connection_tree->head; node; node = node->next) {
c = node->data; c = node->data;
if(c != from && c->status.active) if(c != from && c->status.active) {
send_meta(c, buffer, length); send_meta(c, buffer, length);
}
} }
} }
@ -155,12 +155,12 @@ bool receive_meta(connection_t *c) {
if(lenin <= 0) { if(lenin <= 0) {
if(!lenin || !errno) { if(!lenin || !errno) {
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
c->name, c->hostname); c->name, c->hostname);
} else if(sockwouldblock(sockerrno)) } else if(sockwouldblock(sockerrno)) {
return true; return true;
else } else
logger(LOG_ERR, "Metadata socket read error for %s (%s): %s", logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
c->name, c->hostname, sockstrerror(sockerrno)); c->name, c->hostname, sockstrerror(sockerrno));
return false; return false;
} }
@ -174,9 +174,12 @@ bool receive_meta(connection_t *c) {
/* Is it proxy metadata? */ /* Is it proxy metadata? */
if(c->allow_request == PROXY) { if(c->allow_request == PROXY) {
reqlen = receive_proxy_meta(c, oldlen, lenin); reqlen = receive_proxy_meta(c);
if(reqlen < 0)
if(reqlen < 0) {
return false; return false;
}
goto consume; goto consume;
} }
@ -184,7 +187,7 @@ bool receive_meta(connection_t *c) {
if(c->status.decryptin && !decrypted) { if(c->status.decryptin && !decrypted) {
/* Check decryption limits */ /* Check decryption limits */
if(lenin > c->inbudget) { if((uint64_t)lenin > c->inbudget) {
ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for decryption from %s (%s)", c->name, c->hostname); ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for decryption from %s (%s)", c->name, c->hostname);
return false; return false;
} else { } else {
@ -192,11 +195,13 @@ bool receive_meta(connection_t *c) {
} }
result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin); result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin);
if(!result || lenout != lenin) { if(!result || lenout != lenin) {
logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s", logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
memcpy(c->buffer + oldlen, inbuf, lenin); memcpy(c->buffer + oldlen, inbuf, lenin);
decrypted = true; decrypted = true;
} }
@ -219,17 +224,19 @@ bool receive_meta(connection_t *c) {
for(i = oldlen; i < c->buflen; i++) { for(i = oldlen; i < c->buflen; i++) {
if(c->buffer[i] == '\n') { if(c->buffer[i] == '\n') {
c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */ c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */
c->reqlen = reqlen = i + 1; c->reqlen = reqlen = i + 1;
break; break;
} }
} }
if(reqlen && !receive_request(c)) if(reqlen && !receive_request(c)) {
return false; return false;
}
} }
consume: consume:
if(reqlen) { if(reqlen) {
c->buflen -= reqlen; c->buflen -= reqlen;
lenin -= reqlen - oldlen; lenin -= reqlen - oldlen;
@ -243,7 +250,7 @@ consume:
if(c->buflen >= MAXBUFSIZE) { if(c->buflen >= MAXBUFSIZE) {
logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)", logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)",
c->name, c->hostname); c->name, c->hostname);
return false; return false;
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_META_H
#define TINC_META_H
/* /*
meta.h -- header for meta.c meta.h -- header for meta.c
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
@ -18,14 +21,11 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_META_H__
#define __TINC_META_H__
#include "connection.h" #include "connection.h"
extern bool send_meta(struct connection_t *, const char *, int); extern bool send_meta(struct connection_t *c, const char *buffer, int length);
extern void broadcast_meta(struct connection_t *, const char *, int); extern void broadcast_meta(struct connection_t *c, const char *buffer, int length);
extern bool flush_meta(struct connection_t *); extern bool flush_meta(struct connection_t *c);
extern bool receive_meta(struct connection_t *); extern bool receive_meta(struct connection_t *c);
#endif /* __TINC_META_H__ */ #endif

View file

@ -37,7 +37,7 @@
//============= //=============
#define TAP_CONTROL_CODE(request,method) \ #define TAP_CONTROL_CODE(request,method) \
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) #define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)

View file

@ -37,7 +37,7 @@ int device_fd = -1;
static HANDLE device_handle = INVALID_HANDLE_VALUE; static HANDLE device_handle = INVALID_HANDLE_VALUE;
char *device = NULL; char *device = NULL;
char *iface = NULL; char *iface = NULL;
static char *device_info = NULL; static const char *device_info = "Windows tap device";
static uint64_t device_total_in = 0; static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0; static uint64_t device_total_out = 0;
@ -66,17 +66,21 @@ static DWORD WINAPI tapreader(void *bla) {
if(!status) { if(!status) {
if(GetLastError() == ERROR_IO_PENDING) { if(GetLastError() == ERROR_IO_PENDING) {
WaitForSingleObject(r_overlapped.hEvent, INFINITE); WaitForSingleObject(r_overlapped.hEvent, INFINITE);
if(!GetOverlappedResult(device_handle, &r_overlapped, &len, FALSE))
if(!GetOverlappedResult(device_handle, &r_overlapped, &len, FALSE)) {
continue; continue;
}
} else { } else {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno)); device, strerror(errno));
errors++; errors++;
if(errors >= 10) { if(errors >= 10) {
EnterCriticalSection(&mutex); EnterCriticalSection(&mutex);
running = false; running = false;
LeaveCriticalSection(&mutex); LeaveCriticalSection(&mutex);
} }
usleep(1000000); usleep(1000000);
continue; continue;
} }
@ -113,8 +117,9 @@ static bool setup_device(void) {
get_config_string(lookup_config(config_tree, "Device"), &device); get_config_string(lookup_config(config_tree, "Device"), &device);
get_config_string(lookup_config(config_tree, "Interface"), &iface); get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(device && iface) if(device && iface) {
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected"); logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
}
/* Open registry and look for network adapters */ /* Open registry and look for network adapters */
@ -123,44 +128,51 @@ static bool setup_device(void) {
return false; return false;
} }
for (i = 0; ; i++) { for(i = 0; ; i++) {
len = sizeof(adapterid); len = sizeof(adapterid);
if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) {
break; break;
}
/* Find out more about this adapter */ /* Find out more about this adapter */
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid); snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) {
continue; continue;
}
len = sizeof(adaptername); len = sizeof(adaptername);
err = RegQueryValueEx(key2, "Name", 0, 0, (LPBYTE)adaptername, &len); err = RegQueryValueEx(key2, "Name", 0, 0, (LPBYTE)adaptername, &len);
RegCloseKey(key2); RegCloseKey(key2);
if(err) if(err) {
continue; continue;
}
if(device) { if(device) {
if(!strcmp(device, adapterid)) { if(!strcmp(device, adapterid)) {
found = true; found = true;
break; break;
} else } else {
continue; continue;
}
} }
if(iface) { if(iface) {
if(!strcmp(iface, adaptername)) { if(!strcmp(iface, adaptername)) {
found = true; found = true;
break; break;
} else } else {
continue; continue;
}
} }
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if(device_handle != INVALID_HANDLE_VALUE) { if(device_handle != INVALID_HANDLE_VALUE) {
found = true; found = true;
break; break;
@ -174,11 +186,13 @@ static bool setup_device(void) {
return false; return false;
} }
if(!device) if(!device) {
device = xstrdup(adapterid); device = xstrdup(adapterid);
}
if(!iface) if(!iface) {
iface = xstrdup(adaptername); iface = xstrdup(adaptername);
}
/* Try to open the corresponding tap device */ /* Try to open the corresponding tap device */
@ -222,8 +236,6 @@ static bool setup_device(void) {
status = true; status = true;
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL); DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
device_info = "Windows tap device";
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info); logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
return true; return true;
@ -245,18 +257,20 @@ static bool write_packet(vpn_packet_t *packet) {
static vpn_packet_t queue; static vpn_packet_t queue;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info); packet->len, device_info);
/* Check if there is something in progress */ /* Check if there is something in progress */
if(queue.len) { if(queue.len) {
DWORD size; DWORD size;
BOOL success = GetOverlappedResult(device_handle, &w_overlapped, &size, FALSE); BOOL success = GetOverlappedResult(device_handle, &w_overlapped, &size, FALSE);
if(success) { if(success) {
ResetEvent(&w_overlapped); ResetEvent(&w_overlapped);
queue.len = 0; queue.len = 0;
} else { } else {
int err = GetLastError(); int err = GetLastError();
if(err != ERROR_IO_INCOMPLETE) { if(err != ERROR_IO_INCOMPLETE) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error completing previously queued write: %s", winerror(err)); ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error completing previously queued write: %s", winerror(err));
ResetEvent(&w_overlapped); ResetEvent(&w_overlapped);
@ -275,10 +289,12 @@ static bool write_packet(vpn_packet_t *packet) {
if(!WriteFile(device_handle, queue.data, packet->len, &lenout, &w_overlapped)) { if(!WriteFile(device_handle, queue.data, packet->len, &lenout, &w_overlapped)) {
int err = GetLastError(); int err = GetLastError();
if(err != ERROR_IO_PENDING) { if(err != ERROR_IO_PENDING) {
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(err)); logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(err));
return false; return false;
} }
// Write is being done asynchronously. // Write is being done asynchronously.
queue.len = packet->len; queue.len = packet->len;
} else { } else {

View file

@ -29,7 +29,7 @@
#include "route.h" #include "route.h"
#include "xalloc.h" #include "xalloc.h"
static char *device_info; static const char *device_info = "multicast socket";
static uint64_t device_total_in = 0; static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0; static uint64_t device_total_out = 0;
@ -43,8 +43,6 @@ static bool setup_device(void) {
char *space; char *space;
int ttl = 1; int ttl = 1;
device_info = "multicast socket";
get_config_string(lookup_config(config_tree, "Interface"), &iface); get_config_string(lookup_config(config_tree, "Interface"), &iface);
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
@ -54,6 +52,7 @@ static bool setup_device(void) {
host = xstrdup(device); host = xstrdup(device);
space = strchr(host, ' '); space = strchr(host, ' ');
if(!space) { if(!space) {
logger(LOG_ERR, "Port number required for %s", device_info); logger(LOG_ERR, "Port number required for %s", device_info);
free(host); free(host);
@ -70,10 +69,14 @@ static bool setup_device(void) {
} }
ai = str2addrinfo(host, port, SOCK_DGRAM); ai = str2addrinfo(host, port, SOCK_DGRAM);
if(!ai)
if(!ai) {
free(host);
return false; return false;
}
device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP); device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
if(device_fd < 0) { if(device_fd < 0) {
logger(LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno)); logger(LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
free(host); free(host);
@ -85,7 +88,7 @@ static bool setup_device(void) {
#endif #endif
static const int one = 1; static const int one = 1;
setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof one); setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) { if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) {
closesocket(device_fd); closesocket(device_fd);
@ -96,54 +99,62 @@ static bool setup_device(void) {
switch(ai->ai_family) { switch(ai->ai_family) {
#ifdef IP_ADD_MEMBERSHIP #ifdef IP_ADD_MEMBERSHIP
case AF_INET: {
struct ip_mreq mreq;
struct sockaddr_in in;
memcpy(&in, ai->ai_addr, sizeof in);
mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof mreq)) {
logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
closesocket(device_fd);
free(host);
return false;
}
#ifdef IP_MULTICAST_LOOP
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof one);
#endif
#ifdef IP_MULTICAST_TTL
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof ttl);
#endif
} break;
#endif
#ifdef IPV6_JOIN_GROUP case AF_INET: {
case AF_INET6: { struct ip_mreq mreq;
struct ipv6_mreq mreq; struct sockaddr_in in;
struct sockaddr_in6 in6; memcpy(&in, ai->ai_addr, sizeof(in));
memcpy(&in6, ai->ai_addr, sizeof in6); mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr;
memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof mreq.ipv6mr_multiaddr); mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.ipv6mr_interface = in6.sin6_scope_id;
if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof mreq)) {
logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
closesocket(device_fd);
free(host);
return false;
}
#ifdef IPV6_MULTICAST_LOOP
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof one);
#endif
#ifdef IPV6_MULTICAST_HOPS
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof ttl);
#endif
} break;
#endif
default: if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq))) {
logger(LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family); logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
closesocket(device_fd); closesocket(device_fd);
free(host); free(host);
return false; return false;
}
#ifdef IP_MULTICAST_LOOP
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof(one));
#endif
#ifdef IP_MULTICAST_TTL
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof(ttl));
#endif
}
break;
#endif
#ifdef IPV6_JOIN_GROUP
case AF_INET6: {
struct ipv6_mreq mreq;
struct sockaddr_in6 in6;
memcpy(&in6, ai->ai_addr, sizeof(in6));
memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof(mreq.ipv6mr_multiaddr));
mreq.ipv6mr_interface = in6.sin6_scope_id;
if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof(mreq))) {
logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
closesocket(device_fd);
free(host);
return false;
}
#ifdef IPV6_MULTICAST_LOOP
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof(one));
#endif
#ifdef IPV6_MULTICAST_HOPS
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof(ttl));
#endif
}
break;
#endif
default:
logger(LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family);
closesocket(device_fd);
free(host);
return false;
} }
free(host); free(host);
@ -158,8 +169,9 @@ static void close_device(void) {
free(device); free(device);
free(iface); free(iface);
if(ai) if(ai) {
freeaddrinfo(ai); freeaddrinfo(ai);
}
} }
static bool read_packet(vpn_packet_t *packet) { static bool read_packet(vpn_packet_t *packet) {
@ -167,11 +179,11 @@ static bool read_packet(vpn_packet_t *packet) {
if((lenin = recv(device_fd, (void *)packet->data, MTU, 0)) <= 0) { if((lenin = recv(device_fd, (void *)packet->data, MTU, 0)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno)); device, strerror(errno));
return false; return false;
} }
if(!memcmp(&ignore_src, packet->data + 6, sizeof ignore_src)) { if(!memcmp(&ignore_src, packet->data + 6, sizeof(ignore_src))) {
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info); ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
packet->len = 0; packet->len = 0;
return true; return true;
@ -182,24 +194,24 @@ static bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len; device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info); device_info);
return true; return true;
} }
static bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info); packet->len, device_info);
if(sendto(device_fd, (void *)packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) { if(sendto(device_fd, (void *)packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno)); strerror(errno));
return false; return false;
} }
device_total_out += packet->len; device_total_out += packet->len;
memcpy(&ignore_src, packet->data + 6, sizeof ignore_src); memcpy(&ignore_src, packet->data + 6, sizeof(ignore_src));
return true; return true;
} }

155
src/net.c
View file

@ -3,7 +3,7 @@
Copyright (C) 1998-2005 Ivo Timmermans, Copyright (C) 1998-2005 Ivo Timmermans,
2000-2015 Guus Sliepen <guus@tinc-vpn.org> 2000-2015 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org> 2006 Scott Lamb <slamb@slamb.org>
2011 Loïc Grenié <loic.grenie@gmail.com> 2011 Loïc Grenié <loic.grenie@gmail.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -70,21 +70,26 @@ static void purge(void) {
if(!n->status.reachable) { if(!n->status.reachable) {
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name, ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name,
n->hostname); n->hostname);
for(snode = n->subnet_tree->head; snode; snode = snext) { for(snode = n->subnet_tree->head; snode; snode = snext) {
snext = snode->next; snext = snode->next;
s = snode->data; s = snode->data;
send_del_subnet(everyone, s); send_del_subnet(everyone, s);
if(!strictsubnets)
if(!strictsubnets) {
subnet_del(n, s); subnet_del(n, s);
}
} }
for(enode = n->edge_tree->head; enode; enode = enext) { for(enode = n->edge_tree->head; enode; enode = enext) {
enext = enode->next; enext = enode->next;
e = enode->data; e = enode->data;
if(!tunnelserver)
if(!tunnelserver) {
send_del_edge(everyone, e); send_del_edge(everyone, e);
}
edge_del(e); edge_del(e);
} }
} }
@ -101,13 +106,16 @@ static void purge(void) {
enext = enode->next; enext = enode->next;
e = enode->data; e = enode->data;
if(e->to == n) if(e->to == n) {
break; break;
}
} }
if(!enode && (!strictsubnets || !n->subnet_tree->head)) if(!enode && (!strictsubnets || !n->subnet_tree->head))
/* in strictsubnets mode do not delete nodes with subnets */ /* in strictsubnets mode do not delete nodes with subnets */
{
node_del(n); node_del(n);
}
} }
} }
} }
@ -130,30 +138,44 @@ static int build_fdset(fd_set *readset, fd_set *writeset) {
if(c->status.remove) { if(c->status.remove) {
connection_del(c); connection_del(c);
if(!connection_tree->head)
if(!connection_tree->head) {
purge(); purge();
}
} else { } else {
FD_SET(c->socket, readset); FD_SET(c->socket, readset);
if(c->outbuflen > 0 || c->status.connecting)
if(c->outbuflen > 0 || c->status.connecting) {
FD_SET(c->socket, writeset); FD_SET(c->socket, writeset);
if(c->socket > max) }
if(c->socket > max) {
max = c->socket; max = c->socket;
}
} }
} }
for(i = 0; i < listen_sockets; i++) { for(i = 0; i < listen_sockets; i++) {
FD_SET(listen_socket[i].tcp, readset); FD_SET(listen_socket[i].tcp, readset);
if(listen_socket[i].tcp > max)
if(listen_socket[i].tcp > max) {
max = listen_socket[i].tcp; max = listen_socket[i].tcp;
}
FD_SET(listen_socket[i].udp, readset); FD_SET(listen_socket[i].udp, readset);
if(listen_socket[i].udp > max)
if(listen_socket[i].udp > max) {
max = listen_socket[i].udp; max = listen_socket[i].udp;
}
} }
if(device_fd >= 0) if(device_fd >= 0) {
FD_SET(device_fd, readset); FD_SET(device_fd, readset);
if(device_fd > max) }
if(device_fd > max) {
max = device_fd; max = device_fd;
}
return max; return max;
} }
@ -166,20 +188,23 @@ static int build_fdset(fd_set *readset, fd_set *writeset) {
- Deactivate the host - Deactivate the host
*/ */
void terminate_connection(connection_t *c, bool report) { void terminate_connection(connection_t *c, bool report) {
if(c->status.remove) if(c->status.remove) {
return; return;
}
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)", ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)",
c->name, c->hostname); c->name, c->hostname);
c->status.remove = true; c->status.remove = true;
c->status.active = false; c->status.active = false;
if(c->node) if(c->node) {
c->node->connection = NULL; c->node->connection = NULL;
}
if(c->socket) if(c->socket) {
closesocket(c->socket); closesocket(c->socket);
}
if(c->edge) { if(c->edge) {
if(!c->node) { if(!c->node) {
@ -188,8 +213,9 @@ void terminate_connection(connection_t *c, bool report) {
abort(); abort();
} }
if(report && !tunnelserver) if(report && !tunnelserver) {
send_del_edge(everyone, c->edge); send_del_edge(everyone, c->edge);
}
edge_del(c->edge); edge_del(c->edge);
@ -202,9 +228,12 @@ void terminate_connection(connection_t *c, bool report) {
if(report && !c->node->status.reachable) { if(report && !c->node->status.reachable) {
edge_t *e; edge_t *e;
e = lookup_edge(c->node, myself); e = lookup_edge(c->node, myself);
if(e) { if(e) {
if(!tunnelserver) if(!tunnelserver) {
send_del_edge(everyone, e); send_del_edge(everyone, e);
}
edge_del(e); edge_del(e);
} }
} }
@ -223,6 +252,7 @@ void terminate_connection(connection_t *c, bool report) {
/* Clean up dead proxy processes */ /* Clean up dead proxy processes */
while(waitpid(-1, NULL, WNOHANG) > 0); while(waitpid(-1, NULL, WNOHANG) > 0);
#endif #endif
} }
@ -246,7 +276,7 @@ static void check_dead_connections(void) {
if(c->status.active) { if(c->status.active) {
if(c->status.pinged) { if(c->status.pinged) {
ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
c->name, c->hostname, (long)(now - c->last_ping_time)); c->name, c->hostname, (long)(now - c->last_ping_time));
c->status.timeout = true; c->status.timeout = true;
terminate_connection(c, true); terminate_connection(c, true);
} else if(c->last_ping_time + pinginterval <= now) { } else if(c->last_ping_time + pinginterval <= now) {
@ -255,12 +285,14 @@ static void check_dead_connections(void) {
} else { } else {
if(c->status.remove) { if(c->status.remove) {
logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...", logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...",
c->name, c->hostname, bitfield_to_int(&c->status, sizeof c->status)); c->name, c->hostname, bitfield_to_int(&c->status, sizeof(c->status)));
connection_del(c); connection_del(c);
continue; continue;
} }
ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication", ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication",
c->name, c->hostname); c->name, c->hostname);
if(c->status.connecting) { if(c->status.connecting) {
c->status.connecting = false; c->status.connecting = false;
closesocket(c->socket); closesocket(c->socket);
@ -274,8 +306,8 @@ static void check_dead_connections(void) {
if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout <= now) { if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout <= now) {
if(c->status.active) { if(c->status.active) {
ifdebug(CONNECTIONS) logger(LOG_INFO, ifdebug(CONNECTIONS) logger(LOG_INFO,
"%s (%s) could not flush for %ld seconds (%d bytes remaining)", "%s (%s) could not flush for %ld seconds (%d bytes remaining)",
c->name, c->hostname, (long)(now - c->last_flushed_time), c->outbuflen); c->name, c->hostname, (long)(now - c->last_flushed_time), c->outbuflen);
c->status.timeout = true; c->status.timeout = true;
terminate_connection(c, true); terminate_connection(c, true);
} }
@ -287,7 +319,7 @@ static void check_dead_connections(void) {
check all connections to see if anything check all connections to see if anything
happened on their sockets happened on their sockets
*/ */
static void check_network_activity(fd_set * readset, fd_set * writeset) { static void check_network_activity(fd_set *readset, fd_set *writeset) {
connection_t *c; connection_t *c;
avl_node_t *node; avl_node_t *node;
int result, i; int result, i;
@ -306,6 +338,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
} else { } else {
usleep(errors * 50000); usleep(errors * 50000);
errors++; errors++;
if(errors > 10) { if(errors > 10) {
logger(LOG_ERR, "Too many errors from %s, exiting!", device); logger(LOG_ERR, "Too many errors from %s, exiting!", device);
running = false; running = false;
@ -317,20 +350,21 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
for(node = connection_tree->head; node; node = node->next) { for(node = connection_tree->head; node; node = node->next) {
c = node->data; c = node->data;
if(c->status.remove) if(c->status.remove) {
continue; continue;
}
if(FD_ISSET(c->socket, writeset)) { if(FD_ISSET(c->socket, writeset)) {
if(c->status.connecting) { if(c->status.connecting) {
c->status.connecting = false; c->status.connecting = false;
getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len); getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);
if(!result) if(!result) {
finish_connecting(c); finish_connecting(c);
else { } else {
ifdebug(CONNECTIONS) logger(LOG_DEBUG, ifdebug(CONNECTIONS) logger(LOG_DEBUG,
"Error while connecting to %s (%s): %s", "Error while connecting to %s (%s): %s",
c->name, c->hostname, sockstrerror(result)); c->name, c->hostname, sockstrerror(result));
closesocket(c->socket); closesocket(c->socket);
do_outgoing_connection(c); do_outgoing_connection(c);
continue; continue;
@ -352,11 +386,13 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
} }
for(i = 0; i < listen_sockets; i++) { for(i = 0; i < listen_sockets; i++) {
if(FD_ISSET(listen_socket[i].udp, readset)) if(FD_ISSET(listen_socket[i].udp, readset)) {
handle_incoming_vpn_data(i); handle_incoming_vpn_data(i);
}
if(FD_ISSET(listen_socket[i].tcp, readset)) if(FD_ISSET(listen_socket[i].tcp, readset)) {
handle_new_meta_connection(listen_socket[i].tcp); handle_new_meta_connection(listen_socket[i].tcp);
}
} }
} }
@ -383,8 +419,11 @@ int main_loop(void) {
srand(now); srand(now);
#ifdef HAVE_PSELECT #ifdef HAVE_PSELECT
if(lookup_config(config_tree, "GraphDumpFile"))
if(lookup_config(config_tree, "GraphDumpFile")) {
graph_dump = true; graph_dump = true;
}
/* Block SIGHUP & SIGALRM */ /* Block SIGHUP & SIGALRM */
sigemptyset(&block_mask); sigemptyset(&block_mask);
sigaddset(&block_mask, SIGHUP); sigaddset(&block_mask, SIGHUP);
@ -397,16 +436,21 @@ int main_loop(void) {
while(running) { while(running) {
#ifdef HAVE_PSELECT #ifdef HAVE_PSELECT
next_event = last_ping_check + pingtimeout; next_event = last_ping_check + pingtimeout;
if(graph_dump && next_event > last_graph_dump + 60)
if(graph_dump && next_event > last_graph_dump + 60) {
next_event = last_graph_dump + 60; next_event = last_graph_dump + 60;
}
if((event = peek_next_event()) && next_event > event->time) if((event = peek_next_event()) && next_event > event->time) {
next_event = event->time; next_event = event->time;
}
if(next_event <= now) if(next_event <= now) {
tv.tv_sec = 0; tv.tv_sec = 0;
else } else {
tv.tv_sec = next_event - now; tv.tv_sec = next_event - now;
}
tv.tv_nsec = 0; tv.tv_nsec = 0;
#else #else
tv.tv_sec = 1; tv.tv_sec = 1;
@ -436,8 +480,9 @@ int main_loop(void) {
} }
} }
if(r > 0) if(r > 0) {
check_network_activity(&readset, &writeset); check_network_activity(&readset, &writeset);
}
if(do_purge) { if(do_purge) {
purge(); purge();
@ -450,8 +495,9 @@ int main_loop(void) {
check_dead_connections(); check_dead_connections();
last_ping_check = now; last_ping_check = now;
if(routing_mode == RMODE_SWITCH) if(routing_mode == RMODE_SWITCH) {
age_subnets(); age_subnets();
}
age_past_requests(); age_past_requests();
@ -465,6 +511,7 @@ int main_loop(void) {
for(node = node_tree->head; node; node = node->next) { for(node = node_tree->head; node; node = node->next) {
n = node->data; n = node->data;
if(n->inkey) { if(n->inkey) {
free(n->inkey); free(n->inkey);
n->inkey = NULL; n->inkey = NULL;
@ -484,12 +531,16 @@ int main_loop(void) {
logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime); logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
usleep(sleeptime * 1000000LL); usleep(sleeptime * 1000000LL);
sleeptime *= 2; sleeptime *= 2;
if(sleeptime < 0)
if(sleeptime < 0) {
sleeptime = 3600; sleeptime = 3600;
}
} else { } else {
sleeptime /= 2; sleeptime /= 2;
if(sleeptime < 10)
if(sleeptime < 10) {
sleeptime = 10; sleeptime = 10;
}
} }
contradicting_add_edge = 0; contradicting_add_edge = 0;
@ -500,11 +551,15 @@ int main_loop(void) {
avl_node_t *node; avl_node_t *node;
logger(LOG_INFO, "Flushing event queue"); logger(LOG_INFO, "Flushing event queue");
expire_events(); expire_events();
for(node = connection_tree->head; node; node = node->next) { for(node = connection_tree->head; node; node = node->next) {
connection_t *c = node->data; connection_t *c = node->data;
if(c->status.active)
if(c->status.active) {
send_ping(c); send_ping(c);
}
} }
sigalrm = false; sigalrm = false;
} }
@ -552,8 +607,9 @@ int main_loop(void) {
for(list_node_t *node = outgoing_list->head; node; node = node->next) { for(list_node_t *node = outgoing_list->head; node; node = node->next) {
outgoing_t *outgoing = node->data; outgoing_t *outgoing = node->data;
if(outgoing->event) if(outgoing->event) {
event_del(outgoing->event); event_del(outgoing->event);
}
} }
list_delete_list(outgoing_list); list_delete_list(outgoing_list);
@ -564,8 +620,11 @@ int main_loop(void) {
c = node->data; c = node->data;
xasprintf(&fname, "%s/hosts/%s", confbase, c->name); xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
if(stat(fname, &s) || s.st_mtime > last_config_check)
if(stat(fname, &s) || s.st_mtime > last_config_check) {
terminate_connection(c, c->status.active); terminate_connection(c, c->status.active);
}
free(fname); free(fname);
} }
@ -586,17 +645,23 @@ int main_loop(void) {
for(node = subnet_tree->head; node; node = next) { for(node = subnet_tree->head; node; node = next) {
next = node->next; next = node->next;
subnet = node->data; subnet = node->data;
if(subnet->expires == 1) { if(subnet->expires == 1) {
send_del_subnet(everyone, subnet); send_del_subnet(everyone, subnet);
if(subnet->owner->status.reachable)
if(subnet->owner->status.reachable) {
subnet_update(subnet->owner, subnet, false); subnet_update(subnet->owner, subnet, false);
}
subnet_del(subnet->owner, subnet); subnet_del(subnet->owner, subnet);
} else if(subnet->expires == -1) { } else if(subnet->expires == -1) {
subnet->expires = 0; subnet->expires = 0;
} else { } else {
send_add_subnet(everyone, subnet); send_add_subnet(everyone, subnet);
if(subnet->owner->status.reachable)
if(subnet->owner->status.reachable) {
subnet_update(subnet->owner, subnet, true); subnet_update(subnet->owner, subnet, true);
}
} }
} }
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_NET_H
#define TINC_NET_H
/* /*
net.h -- header for net.c net.h -- header for net.c
Copyright (C) 1998-2005 Ivo Timmermans Copyright (C) 1998-2005 Ivo Timmermans
@ -18,23 +21,20 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_NET_H__
#define __TINC_NET_H__
#include <openssl/evp.h> #include <openssl/evp.h>
#include "ipv6.h" #include "ipv6.h"
#ifdef ENABLE_JUMBOGRAMS #ifdef ENABLE_JUMBOGRAMS
#define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ #define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
#else #else
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ #define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
#endif #endif
#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */ #define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */ #define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */
#define MAXSOCKETS 128 /* Overkill... */ #define MAXSOCKETS 128 /* Overkill... */
typedef struct mac_t { typedef struct mac_t {
uint8_t x[6]; uint8_t x[6];
@ -48,7 +48,7 @@ typedef struct ipv6_t {
uint16_t x[8]; uint16_t x[8];
} ipv6_t; } ipv6_t;
typedef short length_t; typedef uint16_t length_t;
#define AF_UNKNOWN 255 #define AF_UNKNOWN 255
@ -77,9 +77,9 @@ typedef union sockaddr_t {
#endif #endif
typedef struct vpn_packet_t { typedef struct vpn_packet_t {
length_t len; /* the actual number of bytes in the `data' field */ length_t len; /* the actual number of bytes in the `data' field */
int priority; /* priority or TOS */ int priority; /* priority or TOS */
uint32_t seqno; /* 32 bits sequence number (network byte order of course) */ uint32_t seqno; /* 32 bits sequence number (network byte order of course) */
uint8_t data[MAXSIZE]; uint8_t data[MAXSIZE];
} vpn_packet_t; } vpn_packet_t;
@ -129,26 +129,26 @@ extern volatile bool running;
#include "connection.h" #include "connection.h"
#include "node.h" #include "node.h"
extern void retry_outgoing(outgoing_t *); extern void retry_outgoing(outgoing_t *outgoing);
extern void handle_incoming_vpn_data(int); extern void handle_incoming_vpn_data(int sock);
extern void finish_connecting(struct connection_t *); extern void finish_connecting(struct connection_t *c);
extern void do_outgoing_connection(struct connection_t *); extern void do_outgoing_connection(struct connection_t *c);
extern bool handle_new_meta_connection(int); extern bool handle_new_meta_connection(int sock);
extern int setup_listen_socket(const sockaddr_t *); extern int setup_listen_socket(const sockaddr_t *sa);
extern int setup_vpn_in_socket(const sockaddr_t *); extern int setup_vpn_in_socket(const sockaddr_t *sa);
extern void send_packet(const struct node_t *, vpn_packet_t *); extern void send_packet(const struct node_t *n, vpn_packet_t *packet);
extern void receive_tcppacket(struct connection_t *, const char *, int); extern void receive_tcppacket(struct connection_t *c, const char *buffer, length_t len);
extern void broadcast_packet(const struct node_t *, vpn_packet_t *); extern void broadcast_packet(const struct node_t *, vpn_packet_t *packet);
extern char *get_name(void); extern char *get_name(void);
extern bool setup_network(void); extern bool setup_network(void);
extern void setup_outgoing_connection(struct outgoing_t *); extern void setup_outgoing_connection(struct outgoing_t *outgoing);
extern void try_outgoing_connections(void); extern void try_outgoing_connections(void);
extern void close_network_connections(void); extern void close_network_connections(void);
extern int main_loop(void); extern int main_loop(void);
extern void terminate_connection(struct connection_t *, bool); extern void terminate_connection(struct connection_t *c, bool report);
extern void flush_queue(struct node_t *); extern void flush_queue(struct node_t *n);
extern bool read_rsa_public_key(struct connection_t *); extern bool read_rsa_public_key(struct connection_t *c);
extern void send_mtu_probe(struct node_t *); extern void send_mtu_probe(struct node_t *n);
extern void load_all_subnets(void); extern void load_all_subnets(void);
#ifndef HAVE_MINGW #ifndef HAVE_MINGW
@ -157,4 +157,4 @@ extern void load_all_subnets(void);
extern CRITICAL_SECTION mutex; extern CRITICAL_SECTION mutex;
#endif #endif
#endif /* __TINC_NET_H__ */ #endif

View file

@ -114,10 +114,12 @@ void send_mtu_probe(node_t *n) {
} }
if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) { if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
if(n->minmtu > n->maxmtu) if(n->minmtu > n->maxmtu) {
n->minmtu = n->maxmtu; n->minmtu = n->maxmtu;
else } else {
n->maxmtu = n->minmtu; n->maxmtu = n->minmtu;
}
n->mtu = n->minmtu; n->mtu = n->minmtu;
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes); ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
n->mtuprobes = 31; n->mtuprobes = 31;
@ -132,8 +134,10 @@ void send_mtu_probe(node_t *n) {
for(i = 0; i < 4 + localdiscovery; i++) { for(i = 0; i < 4 + localdiscovery; i++) {
if(i == 0) { if(i == 0) {
if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) {
continue; continue;
}
len = n->maxmtu + 8; len = n->maxmtu + 8;
} else if(n->maxmtu <= n->minmtu) { } else if(n->maxmtu <= n->minmtu) {
len = n->maxmtu; len = n->maxmtu;
@ -141,16 +145,19 @@ void send_mtu_probe(node_t *n) {
len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu); len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
} }
if(len < 64) if(len < 64) {
len = 64; len = 64;
}
memset(packet.data, 0, 14); memset(packet.data, 0, 14);
RAND_bytes(packet.data + 14, len - 14); RAND_bytes(packet.data + 14, len - 14);
packet.len = len; packet.len = len;
if(i >= 4 && n->mtuprobes <= 10)
if(i >= 4 && n->mtuprobes <= 10) {
packet.priority = -1; packet.priority = -1;
else } else {
packet.priority = 0; packet.priority = 0;
}
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname); ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
@ -173,23 +180,27 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
send_udppacket(n, packet); send_udppacket(n, packet);
} else { } else {
if(n->mtuprobes > 30) { if(n->mtuprobes > 30) {
if (len == n->maxmtu + 8) { if(len == n->maxmtu + 8) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname); ifdebug(TRAFFIC) logger(LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname);
n->maxmtu = MTU; n->maxmtu = MTU;
n->mtuprobes = 10; n->mtuprobes = 10;
return; return;
} }
if(n->minmtu) if(n->minmtu) {
n->mtuprobes = 30; n->mtuprobes = 30;
else } else {
n->mtuprobes = 1; n->mtuprobes = 1;
}
} }
if(len > n->maxmtu) if(len > n->maxmtu) {
len = n->maxmtu; len = n->maxmtu;
if(n->minmtu < len) }
if(n->minmtu < len) {
n->minmtu = len; n->minmtu = len;
}
} }
} }
@ -203,27 +214,28 @@ static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t l
lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem); lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem);
return lzolen; return lzolen;
#else #else
return -1; return 0;
#endif #endif
} else if(level < 10) { } else if(level < 10) {
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
unsigned long destlen = MAXSIZE; unsigned long destlen = MAXSIZE;
if(compress2(dest, &destlen, source, len, level) == Z_OK)
if(compress2(dest, &destlen, source, len, level) == Z_OK) {
return destlen; return destlen;
else } else
#endif #endif
return -1; return 0;
} else { } else {
#ifdef HAVE_LZO #ifdef HAVE_LZO
lzo_uint lzolen = MAXSIZE; lzo_uint lzolen = MAXSIZE;
lzo1x_999_compress(source, len, dest, &lzolen, lzo_wrkmem); lzo1x_999_compress(source, len, dest, &lzolen, lzo_wrkmem);
return lzolen; return lzolen;
#else #else
return -1; return 0;
#endif #endif
} }
return -1; return 0;
} }
static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) { static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
@ -233,20 +245,25 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
} else if(level > 9) { } else if(level > 9) {
#ifdef HAVE_LZO #ifdef HAVE_LZO
lzo_uint lzolen = MAXSIZE; lzo_uint lzolen = MAXSIZE;
if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK)
if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK) {
return lzolen; return lzolen;
else } else
#endif #endif
return -1; return 0;
} }
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
else { else {
unsigned long destlen = MAXSIZE; unsigned long destlen = MAXSIZE;
if(uncompress(dest, &destlen, source, len) == Z_OK)
if(uncompress(dest, &destlen, source, len) == Z_OK) {
return destlen; return destlen;
else } else {
return -1; return 0;
}
} }
#endif #endif
return -1; return -1;
@ -256,7 +273,7 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
static void receive_packet(node_t *n, vpn_packet_t *packet) { static void receive_packet(node_t *n, vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
packet->len, n->name, n->hostname); packet->len, n->name, n->hostname);
route(n, packet); route(n, packet);
} }
@ -264,8 +281,9 @@ static void receive_packet(node_t *n, vpn_packet_t *packet) {
static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) { static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) {
unsigned char hmac[EVP_MAX_MD_SIZE]; unsigned char hmac[EVP_MAX_MD_SIZE];
if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof inpkt->seqno + n->inmaclength) if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
return false; return false;
}
HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL); HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL);
@ -279,11 +297,10 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
vpn_packet_t *outpkt; vpn_packet_t *outpkt;
int outlen, outpad; int outlen, outpad;
unsigned char hmac[EVP_MAX_MD_SIZE]; unsigned char hmac[EVP_MAX_MD_SIZE];
int i;
if(!n->inkey) { if(!n->inkey) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
n->name, n->hostname); n->name, n->hostname);
return; return;
} }
@ -291,7 +308,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) { if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)",
n->name, n->hostname); n->name, n->hostname);
return; return;
} }
@ -300,11 +317,11 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(n->indigest && n->inmaclength) { if(n->indigest && n->inmaclength) {
inpkt->len -= n->inmaclength; inpkt->len -= n->inmaclength;
HMAC(n->indigest, n->inkey, n->inkeylength, HMAC(n->indigest, n->inkey, n->inkeylength,
(unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL); (unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
if(memcmp_constant_time(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) { if(memcmp_constant_time(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)",
n->name, n->hostname); n->name, n->hostname);
return; return;
} }
} }
@ -315,11 +332,11 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
if(!EVP_DecryptInit_ex(n->inctx, NULL, NULL, NULL, NULL) if(!EVP_DecryptInit_ex(n->inctx, NULL, NULL, NULL, NULL)
|| !EVP_DecryptUpdate(n->inctx, (unsigned char *) &outpkt->seqno, &outlen, || !EVP_DecryptUpdate(n->inctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len) (unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_DecryptFinal_ex(n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) { || !EVP_DecryptFinal_ex(n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s): %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s): %s",
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL)); n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
return; return;
} }
@ -337,21 +354,23 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(inpkt->seqno >= n->received_seqno + replaywin * 8) { if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
if(n->farfuture++ < replaywin >> 2) { if(n->farfuture++ < replaywin >> 2) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)", ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture); n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
return; return;
} }
ifdebug(TRAFFIC) logger(LOG_WARNING, "Lost %d packets from %s (%s)", ifdebug(TRAFFIC) logger(LOG_WARNING, "Lost %d packets from %s (%s)",
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname); inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin); memset(n->late, 0, replaywin);
} else if (inpkt->seqno <= n->received_seqno) { } else if(inpkt->seqno <= n->received_seqno) {
if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) { if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d", ifdebug(TRAFFIC) logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, inpkt->seqno, n->received_seqno); n->name, n->hostname, inpkt->seqno, n->received_seqno);
return; return;
} }
} else { } else {
for(i = n->received_seqno + 1; i < inpkt->seqno; i++) for(uint32_t i = n->received_seqno + 1; i < inpkt->seqno; i++) {
n->late[(i / 8) % replaywin] |= 1 << i % 8; n->late[(i / 8) % replaywin] |= 1 << i % 8;
}
} }
} }
@ -359,11 +378,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8); n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
} }
if(inpkt->seqno > n->received_seqno) if(inpkt->seqno > n->received_seqno) {
n->received_seqno = inpkt->seqno; n->received_seqno = inpkt->seqno;
}
if(n->received_seqno > MAX_SEQNO) if(n->received_seqno > MAX_SEQNO) {
keyexpires = 0; keyexpires = 0;
}
/* Decompress the packet */ /* Decompress the packet */
@ -372,36 +393,41 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(n->incompression) { if(n->incompression) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) { if(!(outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression))) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)", ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)",
n->name, n->hostname); n->name, n->hostname);
return; return;
} }
inpkt = outpkt; inpkt = outpkt;
origlen -= MTU/64 + 20; origlen -= MTU / 64 + 20;
} }
inpkt->priority = 0; inpkt->priority = 0;
if(!inpkt->data[12] && !inpkt->data[13]) if(!inpkt->data[12] && !inpkt->data[13]) {
mtu_probe_h(n, inpkt, origlen); mtu_probe_h(n, inpkt, origlen);
else } else {
receive_packet(n, inpkt); receive_packet(n, inpkt);
}
} }
void receive_tcppacket(connection_t *c, const char *buffer, int len) { void receive_tcppacket(connection_t *c, const char *buffer, length_t len) {
vpn_packet_t outpkt; vpn_packet_t outpkt;
if(len > sizeof outpkt.data) if(len > sizeof(outpkt.data)) {
return; return;
}
outpkt.len = len; outpkt.len = len;
if(c->options & OPTION_TCPONLY)
if(c->options & OPTION_TCPONLY) {
outpkt.priority = 0; outpkt.priority = 0;
else } else {
outpkt.priority = -1; outpkt.priority = -1;
}
memcpy(outpkt.data, buffer, len); memcpy(outpkt.data, buffer, len);
receive_packet(c->node, &outpkt); receive_packet(c->node, &outpkt);
@ -426,8 +452,8 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(!n->status.validkey) { if(!n->status.validkey) {
ifdebug(TRAFFIC) logger(LOG_INFO, ifdebug(TRAFFIC) logger(LOG_INFO,
"No valid key known yet for %s (%s), forwarding via TCP", "No valid key known yet for %s (%s), forwarding via TCP",
n->name, n->hostname); n->name, n->hostname);
if(n->last_req_key + 10 <= now) { if(n->last_req_key + 10 <= now) {
send_req_key(n); send_req_key(n);
@ -441,13 +467,14 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) { if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
ifdebug(TRAFFIC) logger(LOG_INFO, ifdebug(TRAFFIC) logger(LOG_INFO,
"Packet for %s (%s) larger than minimum MTU, forwarding via %s", "Packet for %s (%s) larger than minimum MTU, forwarding via %s",
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP"); n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
if(n != n->nexthop) if(n != n->nexthop) {
send_packet(n->nexthop, origpkt); send_packet(n->nexthop, origpkt);
else } else {
send_tcppacket(n->nexthop->connection, origpkt); send_tcppacket(n->nexthop->connection, origpkt);
}
return; return;
} }
@ -460,9 +487,9 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(n->outcompression) { if(n->outcompression) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) { if(!(outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression))) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)", ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)",
n->name, n->hostname); n->name, n->hostname);
return; return;
} }
@ -480,11 +507,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
outpkt = pkt[nextpkt++]; outpkt = pkt[nextpkt++];
if(!EVP_EncryptInit_ex(n->outctx, NULL, NULL, NULL, NULL) if(!EVP_EncryptInit_ex(n->outctx, NULL, NULL, NULL, NULL)
|| !EVP_EncryptUpdate(n->outctx, (unsigned char *) &outpkt->seqno, &outlen, || !EVP_EncryptUpdate(n->outctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len) (unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_EncryptFinal_ex(n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) { || !EVP_EncryptFinal_ex(n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s): %s", ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s): %s",
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL)); n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
goto end; goto end;
} }
@ -496,7 +523,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(n->outdigest && n->outmaclength) { if(n->outdigest && n->outmaclength) {
HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno, HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno,
inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL); inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
inpkt->len += n->outmaclength; inpkt->len += n->outmaclength;
} }
@ -522,7 +549,8 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(origpriority == -1 && n->prevedge) { if(origpriority == -1 && n->prevedge) {
sock = rand() % listen_sockets; sock = rand() % listen_sockets;
memset(&broadcast, 0, sizeof broadcast); memset(&broadcast, 0, sizeof(broadcast));
if(listen_socket[sock].sa.sa.sa_family == AF_INET6) { if(listen_socket[sock].sa.sa.sa_family == AF_INET6) {
broadcast.in6.sin6_family = AF_INET6; broadcast.in6.sin6_family = AF_INET6;
broadcast.in6.sin6_addr.s6_addr[0x0] = 0xff; broadcast.in6.sin6_addr.s6_addr[0x0] = 0xff;
@ -535,11 +563,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
broadcast.in.sin_addr.s_addr = -1; broadcast.in.sin_addr.s_addr = -1;
broadcast.in.sin_port = n->prevedge->address.in.sin_port; broadcast.in.sin_port = n->prevedge->address.in.sin_port;
} }
sa = &broadcast.sa; sa = &broadcast.sa;
sl = SALEN(broadcast.sa); sl = SALEN(broadcast.sa);
} else { } else {
if(origpriority == -1) if(origpriority == -1) {
origpriority = 0; origpriority = 0;
}
sa = &(n->address.sa); sa = &(n->address.sa);
sl = SALEN(n->address.sa); sl = SALEN(n->address.sa);
@ -548,21 +578,31 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(priorityinheritance && origpriority != listen_socket[n->sock].priority) { if(priorityinheritance && origpriority != listen_socket[n->sock].priority) {
listen_socket[n->sock].priority = origpriority; listen_socket[n->sock].priority = origpriority;
switch(listen_socket[n->sock].sa.sa.sa_family) { switch(listen_socket[n->sock].sa.sa.sa_family) {
#if defined(SOL_IP) && defined(IP_TOS) #if defined(SOL_IP) && defined(IP_TOS)
case AF_INET: case AF_INET:
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority); ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority);
if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, (void *)&origpriority, sizeof(origpriority))) /* SO_PRIORITY doesn't seem to work */
if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, (void *)&origpriority, sizeof(origpriority))) { /* SO_PRIORITY doesn't seem to work */
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno)); logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
break; break;
#endif #endif
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
case AF_INET6: case AF_INET6:
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority); ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority);
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof(origpriority)))
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof(origpriority))) {
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno)); logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
break; break;
#endif #endif
default: default:
break; break;
} }
@ -570,12 +610,16 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) { if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) { if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen) if(n->maxmtu >= origlen) {
n->maxmtu = origlen - 1; n->maxmtu = origlen - 1;
if(n->mtu >= origlen) }
if(n->mtu >= origlen) {
n->mtu = origlen - 1; n->mtu = origlen - 1;
} else }
} else {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno)); ifdebug(TRAFFIC) logger(LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
}
} }
end: end:
@ -589,18 +633,20 @@ void send_packet(const node_t *n, vpn_packet_t *packet) {
node_t *via; node_t *via;
if(n == myself) { if(n == myself) {
if(overwrite_mac) if(overwrite_mac) {
memcpy(packet->data, mymac.x, ETH_ALEN); memcpy(packet->data, mymac.x, ETH_ALEN);
}
devops.write(packet); devops.write(packet);
return; return;
} }
ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)", ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)",
packet->len, n->name, n->hostname); packet->len, n->name, n->hostname);
if(!n->status.reachable) { if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable", ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable",
n->name, n->hostname); n->name, n->hostname);
return; return;
} }
@ -608,13 +654,15 @@ void send_packet(const node_t *n, vpn_packet_t *packet) {
if(via != n) if(via != n)
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)", ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)",
n->name, via->name, n->via->hostname); n->name, via->name, n->via->hostname);
if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) { if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
if(!send_tcppacket(via->connection, packet)) if(!send_tcppacket(via->connection, packet)) {
terminate_connection(via->connection, true); terminate_connection(via->connection, true);
} else }
} else {
send_udppacket(via, packet); send_udppacket(via, packet);
}
} }
/* Broadcast a packet using the minimum spanning tree */ /* Broadcast a packet using the minimum spanning tree */
@ -625,47 +673,54 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
node_t *n; node_t *n;
// Always give ourself a copy of the packet. // Always give ourself a copy of the packet.
if(from != myself) if(from != myself) {
send_packet(myself, packet); send_packet(myself, packet);
}
// In TunnelServer mode, do not forward broadcast packets. // In TunnelServer mode, do not forward broadcast packets.
// The MST might not be valid and create loops. // The MST might not be valid and create loops.
if(tunnelserver || broadcast_mode == BMODE_NONE) if(tunnelserver || broadcast_mode == BMODE_NONE) {
return; return;
}
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)", ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
packet->len, from->name, from->hostname); packet->len, from->name, from->hostname);
switch(broadcast_mode) { switch(broadcast_mode) {
// In MST mode, broadcast packets travel via the Minimum Spanning Tree. // In MST mode, broadcast packets travel via the Minimum Spanning Tree.
// This guarantees all nodes receive the broadcast packet, and // This guarantees all nodes receive the broadcast packet, and
// usually distributes the sending of broadcast packets over all nodes. // usually distributes the sending of broadcast packets over all nodes.
case BMODE_MST: case BMODE_MST:
for(node = connection_tree->head; node; node = node->next) { for(node = connection_tree->head; node; node = node->next) {
c = node->data; c = node->data;
if(c->status.active && c->status.mst && c != from->nexthop->connection) if(c->status.active && c->status.mst && c != from->nexthop->connection) {
send_packet(c->node, packet); send_packet(c->node, packet);
} }
}
break;
// In direct mode, we send copies to each node we know of.
// However, this only reaches nodes that can be reached in a single hop.
// We don't have enough information to forward broadcast packets in this case.
case BMODE_DIRECT:
if(from != myself) {
break; break;
}
// In direct mode, we send copies to each node we know of. for(node = node_udp_tree->head; node; node = node->next) {
// However, this only reaches nodes that can be reached in a single hop. n = node->data;
// We don't have enough information to forward broadcast packets in this case.
case BMODE_DIRECT:
if(from != myself)
break;
for(node = node_udp_tree->head; node; node = node->next) { if(n->status.reachable && n != myself && ((n->via == myself && n->nexthop == n) || n->via == n)) {
n = node->data; send_packet(n, packet);
if(n->status.reachable && n != myself && ((n->via == myself && n->nexthop == n) || n->via == n))
send_packet(n, packet);
} }
break; }
default: break;
break;
default:
break;
} }
} }
@ -678,14 +733,17 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
for(node = edge_weight_tree->head; node; node = node->next) { for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data; e = node->data;
if(e->to == myself) if(e->to == myself) {
continue; continue;
}
if(last_hard_try == now && sockaddrcmp_noport(from, &e->address)) if(last_hard_try == now && sockaddrcmp_noport(from, &e->address)) {
continue; continue;
}
if(!try_mac(e->to, pkt)) if(!try_mac(e->to, pkt)) {
continue; continue;
}
n = e->to; n = e->to;
break; break;
@ -702,30 +760,36 @@ void handle_incoming_vpn_data(int sock) {
socklen_t fromlen = sizeof(from); socklen_t fromlen = sizeof(from);
node_t *n; node_t *n;
pkt.len = recvfrom(listen_socket[sock].udp, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); ssize_t len = recvfrom(listen_socket[sock].udp, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
if(pkt.len < 0) { if(len <= 0 || len > UINT16_MAX) {
if(!sockwouldblock(sockerrno)) if(len >= 0) {
logger(LOG_ERR, "Receiving packet with invalid size");
} else if(!sockwouldblock(sockerrno)) {
logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
}
return; return;
} }
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */ pkt.len = len;
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
n = lookup_node_udp(&from); n = lookup_node_udp(&from);
if(!n) { if(!n) {
n = try_harder(&from, &pkt); n = try_harder(&from, &pkt);
if(n)
if(n) {
update_node_udp(n, &from); update_node_udp(n, &from);
else ifdebug(PROTOCOL) { } else ifdebug(PROTOCOL) {
hostname = sockaddr2hostname(&from); hostname = sockaddr2hostname(&from);
logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname); logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname); free(hostname);
return; return;
} } else {
else
return; return;
}
} }
n->sock = sock; n->sock = sock;

View file

@ -50,9 +50,12 @@ devops_t devops;
#ifndef HAVE_RSA_SET0_KEY #ifndef HAVE_RSA_SET0_KEY
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) {
BN_free(r->n); r->n = n; BN_free(r->n);
BN_free(r->e); r->e = e; r->n = n;
BN_free(r->d); r->d = d; BN_free(r->e);
r->e = e;
BN_free(r->d);
r->d = d;
return 1; return 1;
} }
#endif #endif
@ -73,19 +76,22 @@ bool read_rsa_public_key(connection_t *c) {
/* First, check for simple PublicKey statement */ /* First, check for simple PublicKey statement */
if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) { if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) {
if(BN_hex2bn(&n, key) != strlen(key)) { if((size_t)BN_hex2bn(&n, key) != strlen(key)) {
free(key); free(key);
logger(LOG_ERR, "Invalid PublicKey for %s!", c->name); logger(LOG_ERR, "Invalid PublicKey for %s!", c->name);
return false; return false;
} }
free(key); free(key);
BN_hex2bn(&e, "FFFF"); BN_hex2bn(&e, "FFFF");
if(!n || !e || RSA_set0_key(c->rsa_key, n, e, NULL) != 1) { if(!n || !e || RSA_set0_key(c->rsa_key, n, e, NULL) != 1) {
BN_free(e); BN_free(e);
BN_free(n); BN_free(n);
logger(LOG_ERR, "RSA_set0_key() failed with PublicKey for %s!", c->name); logger(LOG_ERR, "RSA_set0_key() failed with PublicKey for %s!", c->name);
return false; return false;
} }
return true; return true;
} }
@ -105,7 +111,7 @@ bool read_rsa_public_key(connection_t *c) {
if(c->rsa_key) { if(c->rsa_key) {
free(pubname); free(pubname);
return true; /* Woohoo. */ return true; /* Woohoo. */
} }
/* If it fails, try PEM_read_RSA_PUBKEY. */ /* If it fails, try PEM_read_RSA_PUBKEY. */
@ -165,8 +171,9 @@ bool read_rsa_public_key(connection_t *c) {
// RSA_blinding_on(c->rsa_key, NULL); // RSA_blinding_on(c->rsa_key, NULL);
fclose(fp); fclose(fp);
if(c->rsa_key) if(c->rsa_key) {
return true; return true;
}
logger(LOG_ERR, "No public key for %s specified!", c->name); logger(LOG_ERR, "No public key for %s specified!", c->name);
@ -182,26 +189,32 @@ static bool read_rsa_private_key(void) {
if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) {
myself->connection->rsa_key = RSA_new(); myself->connection->rsa_key = RSA_new();
// RSA_blinding_on(myself->connection->rsa_key, NULL); // RSA_blinding_on(myself->connection->rsa_key, NULL);
if(BN_hex2bn(&d, key) != strlen(key)) { if((size_t)BN_hex2bn(&d, key) != strlen(key)) {
logger(LOG_ERR, "Invalid PrivateKey for myself!"); logger(LOG_ERR, "Invalid PrivateKey for myself!");
free(key); free(key);
return false; return false;
} }
free(key); free(key);
if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) { if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) {
BN_free(d); BN_free(d);
logger(LOG_ERR, "PrivateKey used but no PublicKey found!"); logger(LOG_ERR, "PrivateKey used but no PublicKey found!");
return false; return false;
} }
if(BN_hex2bn(&n, pubkey) != strlen(pubkey)) {
if((size_t)BN_hex2bn(&n, pubkey) != strlen(pubkey)) {
free(pubkey); free(pubkey);
BN_free(d); BN_free(d);
logger(LOG_ERR, "Invalid PublicKey for myself!"); logger(LOG_ERR, "Invalid PublicKey for myself!");
return false; return false;
} }
free(pubkey); free(pubkey);
BN_hex2bn(&e, "FFFF"); BN_hex2bn(&e, "FFFF");
if(!n || !e || !d || RSA_set0_key(myself->connection->rsa_key, n, e, d) != 1) { if(!n || !e || !d || RSA_set0_key(myself->connection->rsa_key, n, e, d) != 1) {
BN_free(d); BN_free(d);
BN_free(e); BN_free(e);
@ -209,17 +222,19 @@ static bool read_rsa_private_key(void) {
logger(LOG_ERR, "RSA_set0_key() failed with PrivateKey for myself!"); logger(LOG_ERR, "RSA_set0_key() failed with PrivateKey for myself!");
return false; return false;
} }
return true; return true;
} }
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) {
xasprintf(&fname, "%s/rsa_key.priv", confbase); xasprintf(&fname, "%s/rsa_key.priv", confbase);
}
fp = fopen(fname, "r"); fp = fopen(fname, "r");
if(!fp) { if(!fp) {
logger(LOG_ERR, "Error reading RSA private key file `%s': %s", logger(LOG_ERR, "Error reading RSA private key file `%s': %s",
fname, strerror(errno)); fname, strerror(errno));
free(fname); free(fname);
return false; return false;
} }
@ -228,11 +243,13 @@ static bool read_rsa_private_key(void) {
struct stat s; struct stat s;
if(!fstat(fileno(fp), &s)) { if(!fstat(fileno(fp), &s)) {
if(s.st_mode & ~0100700) if(s.st_mode & ~0100700) {
logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname); logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
}
} else { } else {
logger(LOG_WARNING, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno)); logger(LOG_WARNING, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
} }
#endif #endif
myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
@ -240,7 +257,7 @@ static bool read_rsa_private_key(void) {
if(!myself->connection->rsa_key) { if(!myself->connection->rsa_key) {
logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s",
fname, strerror(errno)); fname, strerror(errno));
free(fname); free(fname);
return false; return false;
} }
@ -264,6 +281,7 @@ void load_all_subnets(void) {
xasprintf(&dname, "%s/hosts", confbase); xasprintf(&dname, "%s/hosts", confbase);
dir = opendir(dname); dir = opendir(dname);
if(!dir) { if(!dir) {
logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno)); logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
free(dname); free(dname);
@ -271,14 +289,15 @@ void load_all_subnets(void) {
} }
while((ent = readdir(dir))) { while((ent = readdir(dir))) {
if(!check_id(ent->d_name)) if(!check_id(ent->d_name)) {
continue; continue;
}
n = lookup_node(ent->d_name); n = lookup_node(ent->d_name);
#ifdef _DIRENT_HAVE_D_TYPE #ifdef _DIRENT_HAVE_D_TYPE
//if(ent->d_type != DT_REG) //if(ent->d_type != DT_REG)
// continue; // continue;
#endif #endif
xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name); xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name);
init_configuration(&config_tree); init_configuration(&config_tree);
@ -293,8 +312,9 @@ void load_all_subnets(void) {
} }
for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) { for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
if(!get_config_subnet(cfg, &s)) if(!get_config_subnet(cfg, &s)) {
continue; continue;
}
if((s2 = lookup_subnet(n, s))) { if((s2 = lookup_subnet(n, s))) {
s2->expires = -1; s2->expires = -1;
@ -314,31 +334,38 @@ char *get_name(void) {
get_config_string(lookup_config(config_tree, "Name"), &name); get_config_string(lookup_config(config_tree, "Name"), &name);
if(!name) if(!name) {
return NULL; return NULL;
}
if(*name == '$') { if(*name == '$') {
char *envname = getenv(name + 1); char *envname = getenv(name + 1);
char hostname[32] = ""; char hostname[32] = "";
if(!envname) { if(!envname) {
if(strcmp(name + 1, "HOST")) { if(strcmp(name + 1, "HOST")) {
fprintf(stderr, "Invalid Name: environment variable %s does not exist\n", name + 1); fprintf(stderr, "Invalid Name: environment variable %s does not exist\n", name + 1);
free(name); free(name);
return false; return false;
} }
if(gethostname(hostname, sizeof hostname) || !*hostname) {
if(gethostname(hostname, sizeof(hostname)) || !*hostname) {
fprintf(stderr, "Could not get hostname: %s\n", strerror(errno)); fprintf(stderr, "Could not get hostname: %s\n", strerror(errno));
free(name); free(name);
return false; return false;
} }
hostname[31] = 0; hostname[31] = 0;
envname = hostname; envname = hostname;
} }
free(name); free(name);
name = xstrdup(envname); name = xstrdup(envname);
for(char *c = name; *c; c++) for(char *c = name; *c; c++)
if(!isalnum(*c)) if(!isalnum(*c)) {
*c = '_'; *c = '_';
}
} }
if(!check_id(name)) { if(!check_id(name)) {
@ -361,8 +388,8 @@ static bool setup_myself(void) {
char *address = NULL; char *address = NULL;
char *proxy = NULL; char *proxy = NULL;
char *space; char *space;
char *envp[5] = {NULL}; char *envp[5] = {};
struct addrinfo *ai, *aip, hint = {0}; struct addrinfo *ai, *aip, hint = {};
bool choice; bool choice;
int i, err; int i, err;
int replaywin_int; int replaywin_int;
@ -391,29 +418,35 @@ static bool setup_myself(void) {
read_config_file(config_tree, fname); read_config_file(config_tree, fname);
free(fname); free(fname);
if(!read_rsa_private_key()) if(!read_rsa_private_key()) {
return false; return false;
}
if(!get_config_string(lookup_config(config_tree, "Port"), &myport)) if(!get_config_string(lookup_config(config_tree, "Port"), &myport)) {
myport = xstrdup("655"); myport = xstrdup("655");
else } else {
port_specified = true; port_specified = true;
}
/* Ensure myport is numeric */ /* Ensure myport is numeric */
if(!atoi(myport)) { if(!atoi(myport)) {
struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM); struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM);
sockaddr_t sa; sockaddr_t sa;
if(!ai || !ai->ai_addr)
if(!ai || !ai->ai_addr) {
return false; return false;
}
free(myport); free(myport);
memcpy(&sa, ai->ai_addr, ai->ai_addrlen); memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
sockaddr2str(&sa, NULL, &myport); sockaddr2str(&sa, NULL, &myport);
} }
if(get_config_string(lookup_config(config_tree, "Proxy"), &proxy)) { if(get_config_string(lookup_config(config_tree, "Proxy"), &proxy)) {
if((space = strchr(proxy, ' '))) if((space = strchr(proxy, ' '))) {
*space++ = 0; *space++ = 0;
}
if(!strcasecmp(proxy, "none")) { if(!strcasecmp(proxy, "none")) {
proxytype = PROXY_NONE; proxytype = PROXY_NONE;
@ -434,42 +467,56 @@ static bool setup_myself(void) {
} }
switch(proxytype) { switch(proxytype) {
case PROXY_NONE: case PROXY_NONE:
default: default:
break; break;
case PROXY_EXEC: case PROXY_EXEC:
if(!space || !*space) { if(!space || !*space) {
logger(LOG_ERR, "Argument expected for proxy type exec!"); logger(LOG_ERR, "Argument expected for proxy type exec!");
free(proxy); free(proxy);
return false; return false;
} }
proxyhost = xstrdup(space);
break;
case PROXY_SOCKS4: proxyhost = xstrdup(space);
case PROXY_SOCKS4A: break;
case PROXY_SOCKS5:
case PROXY_HTTP: case PROXY_SOCKS4:
proxyhost = space; case PROXY_SOCKS4A:
if(space && (space = strchr(space, ' '))) case PROXY_SOCKS5:
*space++ = 0, proxyport = space; case PROXY_HTTP:
if(space && (space = strchr(space, ' '))) proxyhost = space;
*space++ = 0, proxyuser = space;
if(space && (space = strchr(space, ' '))) if(space && (space = strchr(space, ' '))) {
*space++ = 0, proxypass = space; *space++ = 0, proxyport = space;
if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) { }
logger(LOG_ERR, "Host and port argument expected for proxy!");
free(proxy); if(space && (space = strchr(space, ' '))) {
return false; *space++ = 0, proxyuser = space;
} }
proxyhost = xstrdup(proxyhost);
proxyport = xstrdup(proxyport); if(space && (space = strchr(space, ' '))) {
if(proxyuser && *proxyuser) *space++ = 0, proxypass = space;
proxyuser = xstrdup(proxyuser); }
if(proxypass && *proxypass)
proxypass = xstrdup(proxypass); if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) {
break; logger(LOG_ERR, "Host and port argument expected for proxy!");
free(proxy);
return false;
}
proxyhost = xstrdup(proxyhost);
proxyport = xstrdup(proxyport);
if(proxyuser && *proxyuser) {
proxyuser = xstrdup(proxyuser);
}
if(proxypass && *proxypass) {
proxypass = xstrdup(proxypass);
}
break;
} }
free(proxy); free(proxy);
@ -480,8 +527,9 @@ static bool setup_myself(void) {
cfg = lookup_config(config_tree, "Subnet"); cfg = lookup_config(config_tree, "Subnet");
while(cfg) { while(cfg) {
if(!get_config_subnet(cfg, &subnet)) if(!get_config_subnet(cfg, &subnet)) {
return false; return false;
}
subnet_add(myself, subnet); subnet_add(myself, subnet);
@ -490,14 +538,17 @@ static bool setup_myself(void) {
/* Check some options */ /* Check some options */
if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice) if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice) {
myself->options |= OPTION_INDIRECT; myself->options |= OPTION_INDIRECT;
}
if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice) if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice) {
myself->options |= OPTION_TCPONLY; myself->options |= OPTION_TCPONLY;
}
if(myself->options & OPTION_TCPONLY) if(myself->options & OPTION_TCPONLY) {
myself->options |= OPTION_INDIRECT; myself->options |= OPTION_INDIRECT;
}
get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly); get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets); get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
@ -506,94 +557,112 @@ static bool setup_myself(void) {
strictsubnets |= tunnelserver; strictsubnets |= tunnelserver;
if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) { if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
if(!strcasecmp(mode, "router")) if(!strcasecmp(mode, "router")) {
routing_mode = RMODE_ROUTER; routing_mode = RMODE_ROUTER;
else if(!strcasecmp(mode, "switch")) } else if(!strcasecmp(mode, "switch")) {
routing_mode = RMODE_SWITCH; routing_mode = RMODE_SWITCH;
else if(!strcasecmp(mode, "hub")) } else if(!strcasecmp(mode, "hub")) {
routing_mode = RMODE_HUB; routing_mode = RMODE_HUB;
else { } else {
logger(LOG_ERR, "Invalid routing mode!"); logger(LOG_ERR, "Invalid routing mode!");
free(mode); free(mode);
return false; return false;
} }
free(mode); free(mode);
} }
if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) { if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
if(!strcasecmp(mode, "off")) if(!strcasecmp(mode, "off")) {
forwarding_mode = FMODE_OFF; forwarding_mode = FMODE_OFF;
else if(!strcasecmp(mode, "internal")) } else if(!strcasecmp(mode, "internal")) {
forwarding_mode = FMODE_INTERNAL; forwarding_mode = FMODE_INTERNAL;
else if(!strcasecmp(mode, "kernel")) } else if(!strcasecmp(mode, "kernel")) {
forwarding_mode = FMODE_KERNEL; forwarding_mode = FMODE_KERNEL;
else { } else {
logger(LOG_ERR, "Invalid forwarding mode!"); logger(LOG_ERR, "Invalid forwarding mode!");
free(mode); free(mode);
return false; return false;
} }
free(mode); free(mode);
} }
choice = true; choice = !(myself->options & OPTION_TCPONLY);
get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice); get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice);
if(choice)
if(choice) {
myself->options |= OPTION_PMTU_DISCOVERY; myself->options |= OPTION_PMTU_DISCOVERY;
}
choice = true; choice = true;
get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice); get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice);
if(choice)
if(choice) {
myself->options |= OPTION_CLAMP_MSS; myself->options |= OPTION_CLAMP_MSS;
}
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance); get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl); get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) { if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) {
if(!strcasecmp(mode, "no")) if(!strcasecmp(mode, "no")) {
broadcast_mode = BMODE_NONE; broadcast_mode = BMODE_NONE;
else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst")) } else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst")) {
broadcast_mode = BMODE_MST; broadcast_mode = BMODE_MST;
else if(!strcasecmp(mode, "direct")) } else if(!strcasecmp(mode, "direct")) {
broadcast_mode = BMODE_DIRECT; broadcast_mode = BMODE_DIRECT;
else { } else {
logger(LOG_ERR, "Invalid broadcast mode!"); logger(LOG_ERR, "Invalid broadcast mode!");
free(mode); free(mode);
return false; return false;
} }
free(mode); free(mode);
} }
#if !defined(SOL_IP) || !defined(IP_TOS) #if !defined(SOL_IP) || !defined(IP_TOS)
if(priorityinheritance)
if(priorityinheritance) {
logger(LOG_WARNING, "%s not supported on this platform for IPv4 connection", "PriorityInheritance"); logger(LOG_WARNING, "%s not supported on this platform for IPv4 connection", "PriorityInheritance");
}
#endif #endif
#if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS) #if !defined(IPPROTO_IPV6) || !defined(IPV6_TCLASS)
if(priorityinheritance)
if(priorityinheritance) {
logger(LOG_WARNING, "%s not supported on this platform for IPv6 connection", "PriorityInheritance"); logger(LOG_WARNING, "%s not supported on this platform for IPv6 connection", "PriorityInheritance");
}
#endif #endif
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) {
macexpire = 600; macexpire = 600;
}
if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) { if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
if(maxtimeout <= 0) { if(maxtimeout <= 0) {
logger(LOG_ERR, "Bogus maximum timeout!"); logger(LOG_ERR, "Bogus maximum timeout!");
return false; return false;
} }
} else } else {
maxtimeout = 900; maxtimeout = 900;
}
if(get_config_int(lookup_config(config_tree, "MinTimeout"), &mintimeout)) { if(get_config_int(lookup_config(config_tree, "MinTimeout"), &mintimeout)) {
if(mintimeout < 0) { if(mintimeout < 0) {
logger(LOG_ERR, "Bogus minimum timeout!"); logger(LOG_ERR, "Bogus minimum timeout!");
return false; return false;
} }
if(mintimeout > maxtimeout) {
logger(LOG_WARNING, "Minimum timeout (%d s) cannot be larger than maximum timeout (%d s). Correcting !", mintimeout, maxtimeout ); if(mintimeout > maxtimeout) {
mintimeout=maxtimeout; logger(LOG_WARNING, "Minimum timeout (%d s) cannot be larger than maximum timeout (%d s). Correcting !", mintimeout, maxtimeout);
} mintimeout = maxtimeout;
} else }
mintimeout = 0; } else {
mintimeout = 0;
}
if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) { if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
if(udp_rcvbuf <= 0) { if(udp_rcvbuf <= 0) {
@ -614,21 +683,23 @@ static bool setup_myself(void) {
logger(LOG_ERR, "ReplayWindow cannot be negative!"); logger(LOG_ERR, "ReplayWindow cannot be negative!");
return false; return false;
} }
replaywin = (unsigned)replaywin_int; replaywin = (unsigned)replaywin_int;
} }
if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) { if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) {
if(!strcasecmp(afname, "IPv4")) if(!strcasecmp(afname, "IPv4")) {
addressfamily = AF_INET; addressfamily = AF_INET;
else if(!strcasecmp(afname, "IPv6")) } else if(!strcasecmp(afname, "IPv6")) {
addressfamily = AF_INET6; addressfamily = AF_INET6;
else if(!strcasecmp(afname, "any")) } else if(!strcasecmp(afname, "any")) {
addressfamily = AF_UNSPEC; addressfamily = AF_UNSPEC;
else { } else {
logger(LOG_ERR, "Invalid address family!"); logger(LOG_ERR, "Invalid address family!");
free(afname); free(afname);
return false; return false;
} }
free(afname); free(afname);
} }
@ -648,14 +719,17 @@ static bool setup_myself(void) {
return false; return false;
} }
} }
free(cipher);
} else
myself->incipher = EVP_aes_256_cbc();
if(myself->incipher) free(cipher);
} else {
myself->incipher = EVP_aes_256_cbc();
}
if(myself->incipher) {
myself->inkeylength = EVP_CIPHER_key_length(myself->incipher) + EVP_CIPHER_iv_length(myself->incipher); myself->inkeylength = EVP_CIPHER_key_length(myself->incipher) + EVP_CIPHER_iv_length(myself->incipher);
else } else {
myself->inkeylength = 1; myself->inkeylength = 1;
}
/* We need to use a stream mode for the meta protocol. Use AES for this, /* We need to use a stream mode for the meta protocol. Use AES for this,
but try to match the key size with the one from the cipher selected but try to match the key size with the one from the cipher selected
@ -666,15 +740,18 @@ static bool setup_myself(void) {
*/ */
int keylen = myself->incipher ? EVP_CIPHER_key_length(myself->incipher) : 0; int keylen = myself->incipher ? EVP_CIPHER_key_length(myself->incipher) : 0;
if(keylen <= 16)
myself->connection->outcipher = EVP_aes_128_cfb();
else if(keylen <= 24)
myself->connection->outcipher = EVP_aes_192_cfb();
else
myself->connection->outcipher = EVP_aes_256_cfb();
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) if(keylen <= 16) {
myself->connection->outcipher = EVP_aes_128_cfb();
} else if(keylen <= 24) {
myself->connection->outcipher = EVP_aes_192_cfb();
} else {
myself->connection->outcipher = EVP_aes_256_cfb();
}
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) {
keylifetime = 3600; keylifetime = 3600;
}
keyexpires = now + keylifetime; keyexpires = now + keylifetime;
@ -694,8 +771,9 @@ static bool setup_myself(void) {
} }
free(digest); free(digest);
} else } else {
myself->indigest = EVP_sha256(); myself->indigest = EVP_sha256();
}
myself->connection->outdigest = EVP_sha256(); myself->connection->outdigest = EVP_sha256();
@ -709,8 +787,9 @@ static bool setup_myself(void) {
return false; return false;
} }
} }
} else } else {
myself->inmaclength = 4; myself->inmaclength = 4;
}
myself->connection->outmaclength = 0; myself->connection->outmaclength = 0;
@ -721,8 +800,9 @@ static bool setup_myself(void) {
logger(LOG_ERR, "Bogus compression level!"); logger(LOG_ERR, "Bogus compression level!");
return false; return false;
} }
} else } else {
myself->incompression = 0; myself->incompression = 0;
}
myself->connection->outcompression = 0; myself->connection->outcompression = 0;
@ -735,33 +815,41 @@ static bool setup_myself(void) {
graph(); graph();
if(strictsubnets) if(strictsubnets) {
load_all_subnets(); load_all_subnets();
}
/* Open device */ /* Open device */
devops = os_devops; devops = os_devops;
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "dummy")) if(!strcasecmp(type, "dummy")) {
devops = dummy_devops; devops = dummy_devops;
else if(!strcasecmp(type, "raw_socket")) } else if(!strcasecmp(type, "raw_socket")) {
devops = raw_socket_devops; devops = raw_socket_devops;
else if(!strcasecmp(type, "multicast")) } else if(!strcasecmp(type, "multicast")) {
devops = multicast_devops; devops = multicast_devops;
}
#ifdef ENABLE_UML #ifdef ENABLE_UML
else if(!strcasecmp(type, "uml")) else if(!strcasecmp(type, "uml")) {
devops = uml_devops; devops = uml_devops;
}
#endif #endif
#ifdef ENABLE_VDE #ifdef ENABLE_VDE
else if(!strcasecmp(type, "vde")) else if(!strcasecmp(type, "vde")) {
devops = vde_devops; devops = vde_devops;
}
#endif #endif
free(type); free(type);
} }
if(!devops.setup()) if(!devops.setup()) {
return false; return false;
}
/* Run tinc-up script to further initialize the tap interface */ /* Run tinc-up script to further initialize the tap interface */
xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
@ -777,8 +865,9 @@ static bool setup_myself(void) {
#endif #endif
execute_script("tinc-up", envp); execute_script("tinc-up", envp);
for(i = 0; i < 4; i++) for(i = 0; i < 4; i++) {
free(envp[i]); free(envp[i]);
}
/* Run subnet-up scripts for our own subnets */ /* Run subnet-up scripts for our own subnets */
@ -801,7 +890,8 @@ static bool setup_myself(void) {
} }
for(i = 0; i < listen_sockets; i++) { for(i = 0; i < listen_sockets; i++) {
salen = sizeof sa; salen = sizeof(sa);
if(getsockname(i + 3, &sa.sa, &salen) < 0) { if(getsockname(i + 3, &sa.sa, &salen) < 0) {
logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno)); logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
return false; return false;
@ -810,12 +900,14 @@ static bool setup_myself(void) {
listen_socket[i].tcp = i + 3; listen_socket[i].tcp = i + 3;
#ifdef FD_CLOEXEC #ifdef FD_CLOEXEC
fcntl(i + 3, F_SETFD, FD_CLOEXEC); fcntl(i + 3, F_SETFD, FD_CLOEXEC);
#endif #endif
listen_socket[i].udp = setup_vpn_in_socket(&sa); listen_socket[i].udp = setup_vpn_in_socket(&sa);
if(listen_socket[i].udp < 0)
if(listen_socket[i].udp < 0) {
return false; return false;
}
ifdebug(CONNECTIONS) { ifdebug(CONNECTIONS) {
hostname = sockaddr2hostname(&sa); hostname = sockaddr2hostname(&sa);
@ -831,20 +923,24 @@ static bool setup_myself(void) {
do { do {
get_config_string(cfg, &address); get_config_string(cfg, &address);
if(cfg)
if(cfg) {
cfg = lookup_config_next(config_tree, cfg); cfg = lookup_config_next(config_tree, cfg);
}
char *port = myport; char *port = myport;
if(address) { if(address) {
char *space = strchr(address, ' '); char *space = strchr(address, ' ');
if(space) { if(space) {
*space++ = 0; *space++ = 0;
port = space; port = space;
} }
if(!strcmp(address, "*")) if(!strcmp(address, "*")) {
*address = 0; *address = 0;
}
} }
hint.ai_family = addressfamily; hint.ai_family = addressfamily;
@ -861,7 +957,7 @@ static bool setup_myself(void) {
if(err || !ai) { if(err || !ai) {
logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo", logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
gai_strerror(err)); gai_strerror(err));
return false; return false;
} }
@ -872,16 +968,18 @@ static bool setup_myself(void) {
} }
listen_socket[listen_sockets].tcp = listen_socket[listen_sockets].tcp =
setup_listen_socket((sockaddr_t *) aip->ai_addr); setup_listen_socket((sockaddr_t *) aip->ai_addr);
if(listen_socket[listen_sockets].tcp < 0) if(listen_socket[listen_sockets].tcp < 0) {
continue; continue;
}
listen_socket[listen_sockets].udp = listen_socket[listen_sockets].udp =
setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
if(listen_socket[listen_sockets].udp < 0) if(listen_socket[listen_sockets].udp < 0) {
continue; continue;
}
ifdebug(CONNECTIONS) { ifdebug(CONNECTIONS) {
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
@ -906,12 +1004,15 @@ static bool setup_myself(void) {
if(!port_specified) { if(!port_specified) {
sockaddr_t sa; sockaddr_t sa;
socklen_t salen = sizeof sa; socklen_t salen = sizeof(sa);
if(!getsockname(listen_socket[0].udp, &sa.sa, &salen)) { if(!getsockname(listen_socket[0].udp, &sa.sa, &salen)) {
free(myport); free(myport);
sockaddr2str(&sa, NULL, &myport); sockaddr2str(&sa, NULL, &myport);
if(!myport)
if(!myport) {
myport = xstrdup("655"); myport = xstrdup("655");
}
} }
} }
@ -938,19 +1039,25 @@ bool setup_network(void) {
if(pinginterval < 1) { if(pinginterval < 1) {
pinginterval = 86400; pinginterval = 86400;
} }
} else } else {
pinginterval = 60; pinginterval = 60;
}
if(!get_config_int(lookup_config(config_tree, "PingTimeout"), &pingtimeout)) if(!get_config_int(lookup_config(config_tree, "PingTimeout"), &pingtimeout)) {
pingtimeout = 5; pingtimeout = 5;
if(pingtimeout < 1 || pingtimeout > pinginterval) }
if(pingtimeout < 1 || pingtimeout > pinginterval) {
pingtimeout = pinginterval; pingtimeout = pinginterval;
}
if(!get_config_int(lookup_config(config_tree, "MaxOutputBufferSize"), &maxoutbufsize)) if(!get_config_int(lookup_config(config_tree, "MaxOutputBufferSize"), &maxoutbufsize)) {
maxoutbufsize = 10 * MTU; maxoutbufsize = 10 * MTU;
}
if(!setup_myself()) if(!setup_myself()) {
return false; return false;
}
return true; return true;
} }
@ -961,7 +1068,7 @@ bool setup_network(void) {
void close_network_connections(void) { void close_network_connections(void) {
avl_node_t *node, *next; avl_node_t *node, *next;
connection_t *c; connection_t *c;
char *envp[5] = {NULL}; char *envp[5] = {};
int i; int i;
for(node = connection_tree->head; node; node = next) { for(node = connection_tree->head; node; node = next) {
@ -974,8 +1081,9 @@ void close_network_connections(void) {
for(list_node_t *node = outgoing_list->head; node; node = node->next) { for(list_node_t *node = outgoing_list->head; node; node = node->next) {
outgoing_t *outgoing = node->data; outgoing_t *outgoing = node->data;
if(outgoing->event) if(outgoing->event) {
event_del(outgoing->event); event_del(outgoing->event);
}
} }
list_delete_list(outgoing_list); list_delete_list(outgoing_list);
@ -1005,10 +1113,13 @@ void close_network_connections(void) {
execute_script("tinc-down", envp); execute_script("tinc-down", envp);
if(myport) free(myport); if(myport) {
free(myport);
}
for(i = 0; i < 4; i++) for(i = 0; i < 4; i++) {
free(envp[i]); free(envp[i]);
}
devops.close(); devops.close();

View file

@ -62,12 +62,14 @@ static void configure_tcp(connection_t *c) {
if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) { if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno)); logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
} }
#elif defined(WIN32) #elif defined(WIN32)
unsigned long arg = 1; unsigned long arg = 1;
if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) { if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
logger(LOG_ERR, "ioctlsocket for %s: %s", c->hostname, sockstrerror(sockerrno)); logger(LOG_ERR, "ioctlsocket for %s: %s", c->hostname, sockstrerror(sockerrno));
} }
#endif #endif
#if defined(SOL_TCP) && defined(TCP_NODELAY) #if defined(SOL_TCP) && defined(TCP_NODELAY)
@ -94,8 +96,9 @@ static bool bind_to_interface(int sd) {
int status; int status;
#endif /* defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) */ #endif /* defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) */
if(!get_config_string(lookup_config (config_tree, "BindToInterface"), &iface)) if(!get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
return true; return true;
}
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
@ -104,6 +107,7 @@ static bool bind_to_interface(int sd) {
free(iface); free(iface);
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)); status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
if(status) { if(status) {
logger(LOG_ERR, "Can't bind to interface %s: %s", ifr.ifr_ifrn.ifrn_name, strerror(errno)); logger(LOG_ERR, "Can't bind to interface %s: %s", ifr.ifr_ifrn.ifrn_name, strerror(errno));
return false; return false;
@ -139,8 +143,11 @@ int setup_listen_socket(const sockaddr_t *sa) {
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) #if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6)
setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); if(sa->sa.sa_family == AF_INET6) {
setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
}
#endif #endif
if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) { if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
@ -203,13 +210,14 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd); closesocket(nfd);
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", logger(LOG_ERR, "System call `%s' failed: %s", "fcntl",
strerror(errno)); strerror(errno));
return -1; return -1;
} }
} }
#elif defined(WIN32) #elif defined(WIN32)
{ {
unsigned long arg = 1; unsigned long arg = 1;
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) { if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
closesocket(nfd); closesocket(nfd);
logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno)); logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
@ -222,15 +230,20 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option)); setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option));
if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf))) if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf))) {
logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno)); logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
}
if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf))) if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf))) {
logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno)); logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
}
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if(sa->sa.sa_family == AF_INET6)
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); if(sa->sa.sa_family == AF_INET6) {
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
}
#endif #endif
#if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT) #if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT)
@ -238,30 +251,38 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
#endif #endif
#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) { if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IP_PMTUDISC_DO; option = IP_PMTUDISC_DO;
setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option)); setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
} }
#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT) #elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT)
if(myself->options & OPTION_PMTU_DISCOVERY) { if(myself->options & OPTION_PMTU_DISCOVERY) {
option = 1; option = 1;
setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option)); setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option));
} }
#endif #endif
#if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) #if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
if(myself->options & OPTION_PMTU_DISCOVERY) { if(myself->options & OPTION_PMTU_DISCOVERY) {
option = IPV6_PMTUDISC_DO; option = IPV6_PMTUDISC_DO;
setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option)); setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
} }
#elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG) #elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
if(myself->options & OPTION_PMTU_DISCOVERY) { if(myself->options & OPTION_PMTU_DISCOVERY) {
option = 1; option = 1;
setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option)); setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option));
} }
#endif #endif
if (!bind_to_interface(nfd)) { if(!bind_to_interface(nfd)) {
closesocket(nfd); closesocket(nfd);
return -1; return -1;
} }
@ -280,14 +301,18 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
void retry_outgoing(outgoing_t *outgoing) { void retry_outgoing(outgoing_t *outgoing) {
outgoing->timeout += 5; outgoing->timeout += 5;
if(outgoing->timeout < mintimeout) if(outgoing->timeout < mintimeout) {
outgoing->timeout = mintimeout; outgoing->timeout = mintimeout;
}
if(outgoing->timeout > maxtimeout) if(outgoing->timeout > maxtimeout) {
outgoing->timeout = maxtimeout; outgoing->timeout = maxtimeout;
}
if(outgoing->event) if(outgoing->event) {
event_del(outgoing->event); event_del(outgoing->event);
}
outgoing->event = new_event(); outgoing->event = new_event();
outgoing->event->handler = (event_handler_t) setup_outgoing_connection; outgoing->event->handler = (event_handler_t) setup_outgoing_connection;
outgoing->event->time = now + outgoing->timeout; outgoing->event->time = now + outgoing->timeout;
@ -295,8 +320,8 @@ void retry_outgoing(outgoing_t *outgoing) {
event_add(outgoing->event); event_add(outgoing->event);
ifdebug(CONNECTIONS) logger(LOG_NOTICE, ifdebug(CONNECTIONS) logger(LOG_NOTICE,
"Trying to re-establish outgoing connection in %d seconds", "Trying to re-establish outgoing connection in %d seconds",
outgoing->timeout); outgoing->timeout);
} }
void finish_connecting(connection_t *c) { void finish_connecting(connection_t *c) {
@ -340,14 +365,19 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
setenv("REMOTEPORT", port, true); setenv("REMOTEPORT", port, true);
setenv("NODE", c->name, true); setenv("NODE", c->name, true);
setenv("NAME", myself->name, true); setenv("NAME", myself->name, true);
if(netname)
if(netname) {
setenv("NETNAME", netname, true); setenv("NETNAME", netname, true);
}
int result = system(command); int result = system(command);
if(result < 0)
if(result < 0) {
logger(LOG_ERR, "Could not execute %s: %s\n", command, strerror(errno)); logger(LOG_ERR, "Could not execute %s: %s\n", command, strerror(errno));
else if(result) } else if(result) {
logger(LOG_ERR, "%s exited with non-zero status %d", command, result); logger(LOG_ERR, "%s exited with non-zero status %d", command, result);
}
exit(result); exit(result);
#else #else
logger(LOG_ERR, "Proxy type exec not supported on this platform!"); logger(LOG_ERR, "Proxy type exec not supported on this platform!");
@ -357,12 +387,14 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
static bool is_valid_host_port(const char *host, const char *port) { static bool is_valid_host_port(const char *host, const char *port) {
for(const char *p = host; *p; p++) for(const char *p = host; *p; p++)
if(!isalnum(*p) && *p != '-' && *p != '.') if(!isalnum(*p) && *p != '-' && *p != '.') {
return false; return false;
}
for(const char *p = port; *p; p++) for(const char *p = port; *p; p++)
if(!isalnum(*p)) if(!isalnum(*p)) {
return false; return false;
}
return true; return true;
} }
@ -377,10 +409,11 @@ void do_outgoing_connection(connection_t *c) {
} }
begin: begin:
if(!c->outgoing->ai) { if(!c->outgoing->ai) {
if(!c->outgoing->cfg) { if(!c->outgoing->cfg) {
ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s", ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s",
c->name); c->name);
c->status.remove = true; c->status.remove = true;
retry_outgoing(c->outgoing); retry_outgoing(c->outgoing);
c->outgoing = NULL; c->outgoing = NULL;
@ -392,19 +425,21 @@ begin:
get_config_string(c->outgoing->cfg, &address); get_config_string(c->outgoing->cfg, &address);
space = strchr(address, ' '); space = strchr(address, ' ');
if(space) { if(space) {
port = xstrdup(space + 1); port = xstrdup(space + 1);
*space = 0; *space = 0;
} else { } else {
if(!get_config_string(lookup_config(c->config_tree, "Port"), &port)) if(!get_config_string(lookup_config(c->config_tree, "Port"), &port)) {
port = xstrdup("655"); port = xstrdup("655");
}
} }
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM); c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
// If we cannot resolve the address, maybe we are using a proxy that can? // If we cannot resolve the address, maybe we are using a proxy that can?
if(!c->outgoing->ai && proxytype != PROXY_NONE && is_valid_host_port(address, port)) { if(!c->outgoing->ai && proxytype != PROXY_NONE && is_valid_host_port(address, port)) {
memset(&c->address, 0, sizeof c->address); memset(&c->address, 0, sizeof(c->address));
c->address.sa.sa_family = AF_UNKNOWN; c->address.sa.sa_family = AF_UNKNOWN;
c->address.unknown.address = address; c->address.unknown.address = address;
c->address.unknown.port = port; c->address.unknown.port = port;
@ -416,13 +451,16 @@ begin:
c->outgoing->aip = c->outgoing->ai; c->outgoing->aip = c->outgoing->ai;
c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg); c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
if(!c->outgoing->ai && proxytype != PROXY_NONE) if(!c->outgoing->ai && proxytype != PROXY_NONE) {
goto connect; goto connect;
}
} }
if(!c->outgoing->aip) { if(!c->outgoing->aip) {
if(c->outgoing->ai) if(c->outgoing->ai) {
freeaddrinfo(c->outgoing->ai); freeaddrinfo(c->outgoing->ai);
}
c->outgoing->ai = NULL; c->outgoing->ai = NULL;
goto begin; goto begin;
} }
@ -431,13 +469,15 @@ begin:
c->outgoing->aip = c->outgoing->aip->ai_next; c->outgoing->aip = c->outgoing->aip->ai_next;
connect: connect:
if(c->hostname)
if(c->hostname) {
free(c->hostname); free(c->hostname);
}
c->hostname = sockaddr2hostname(&c->address); c->hostname = sockaddr2hostname(&c->address);
ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name, ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name,
c->hostname); c->hostname);
if(!proxytype) { if(!proxytype) {
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
@ -446,8 +486,11 @@ connect:
do_outgoing_pipe(c, proxyhost); do_outgoing_pipe(c, proxyhost);
} else { } else {
proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM); proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM);
if(!proxyai)
if(!proxyai) {
goto begin; goto begin;
}
ifdebug(CONNECTIONS) logger(LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport); ifdebug(CONNECTIONS) logger(LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport);
c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP); c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP);
} }
@ -457,8 +500,9 @@ connect:
goto begin; goto begin;
} }
if(proxytype != PROXY_EXEC) if(proxytype != PROXY_EXEC) {
configure_tcp(c); configure_tcp(c);
}
#ifdef FD_CLOEXEC #ifdef FD_CLOEXEC
fcntl(c->socket, F_SETFD, FD_CLOEXEC); fcntl(c->socket, F_SETFD, FD_CLOEXEC);
@ -467,8 +511,11 @@ connect:
if(proxytype != PROXY_EXEC) { if(proxytype != PROXY_EXEC) {
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY) #if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
int option = 1; int option = 1;
if(c->address.sa.sa_family == AF_INET6)
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); if(c->address.sa.sa_family == AF_INET6) {
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
}
#endif #endif
bind_to_interface(c->socket); bind_to_interface(c->socket);
@ -488,10 +535,12 @@ connect:
if(b != -1) { if(b != -1) {
sockaddr_t sa = listen_socket[b].sa; sockaddr_t sa = listen_socket[b].sa;
if(sa.sa.sa_family == AF_INET)
if(sa.sa.sa_family == AF_INET) {
sa.in.sin_port = 0; sa.in.sin_port = 0;
else if(sa.sa.sa_family == AF_INET6) } else if(sa.sa.sa_family == AF_INET6) {
sa.in6.sin6_port = 0; sa.in6.sin6_port = 0;
}
if(bind(c->socket, &sa.sa, SALEN(sa.sa))) { if(bind(c->socket, &sa.sa, SALEN(sa.sa))) {
char *addrstr = sockaddr2hostname(&sa); char *addrstr = sockaddr2hostname(&sa);
@ -557,6 +606,7 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
c->outcompression = myself->connection->outcompression; c->outcompression = myself->connection->outcompression;
init_configuration(&c->config_tree); init_configuration(&c->config_tree);
if(!read_connection_config(c)) { if(!read_connection_config(c)) {
free_connection(c); free_connection(c);
outgoing->timeout = maxtimeout; outgoing->timeout = maxtimeout;
@ -626,11 +676,13 @@ bool handle_new_meta_connection(int sock) {
} }
static void free_outgoing(outgoing_t *outgoing) { static void free_outgoing(outgoing_t *outgoing) {
if(outgoing->ai) if(outgoing->ai) {
freeaddrinfo(outgoing->ai); freeaddrinfo(outgoing->ai);
}
if(outgoing->name) if(outgoing->name) {
free(outgoing->name); free(outgoing->name);
}
free(outgoing); free(outgoing);
} }
@ -647,8 +699,8 @@ void try_outgoing_connections(void) {
if(!check_id(name)) { if(!check_id(name)) {
logger(LOG_ERR, logger(LOG_ERR,
"Invalid name for outgoing connection in %s line %d", "Invalid name for outgoing connection in %s line %d",
cfg->file, cfg->line); cfg->file, cfg->line);
free(name); free(name);
continue; continue;
} }

View file

@ -33,7 +33,7 @@ bool hostnames = false;
Return NULL on failure. Return NULL on failure.
*/ */
struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) { struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) {
struct addrinfo *ai = NULL, hint = {0}; struct addrinfo *ai = NULL, hint = {};
int err; int err;
hint.ai_family = addressfamily; hint.ai_family = addressfamily;
@ -47,7 +47,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
if(err) { if(err) {
logger(LOG_WARNING, "Error looking up %s port %s: %s", address, logger(LOG_WARNING, "Error looking up %s port %s: %s", address,
service, gai_strerror(err)); service, gai_strerror(err));
return NULL; return NULL;
} }
@ -55,7 +55,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
} }
sockaddr_t str2sockaddr(const char *address, const char *port) { sockaddr_t str2sockaddr(const char *address, const char *port) {
struct addrinfo *ai = NULL, hint = {0}; struct addrinfo *ai = NULL, hint = {};
sockaddr_t result; sockaddr_t result;
int err; int err;
@ -67,7 +67,7 @@ sockaddr_t str2sockaddr(const char *address, const char *port) {
if(err || !ai) { if(err || !ai) {
ifdebug(SCARY_THINGS) ifdebug(SCARY_THINGS)
logger(LOG_DEBUG, "Unknown type address %s port %s", address, port); logger(LOG_DEBUG, "Unknown type address %s port %s", address, port);
result.sa.sa_family = AF_UNKNOWN; result.sa.sa_family = AF_UNKNOWN;
result.unknown.address = xstrdup(address); result.unknown.address = xstrdup(address);
result.unknown.port = xstrdup(port); result.unknown.port = xstrdup(port);
@ -87,10 +87,14 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
int err; int err;
if(sa->sa.sa_family == AF_UNKNOWN) { if(sa->sa.sa_family == AF_UNKNOWN) {
if(addrstr) if(addrstr) {
*addrstr = xstrdup(sa->unknown.address); *addrstr = xstrdup(sa->unknown.address);
if(portstr) }
if(portstr) {
*portstr = xstrdup(sa->unknown.port); *portstr = xstrdup(sa->unknown.port);
}
return; return;
} }
@ -98,19 +102,23 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
if(err) { if(err) {
logger(LOG_ERR, "Error while translating addresses: %s", logger(LOG_ERR, "Error while translating addresses: %s",
gai_strerror(err)); gai_strerror(err));
abort(); abort();
} }
scopeid = strchr(address, '%'); scopeid = strchr(address, '%');
if(scopeid) if(scopeid) {
*scopeid = '\0'; /* Descope. */ *scopeid = '\0'; /* Descope. */
}
if(addrstr) if(addrstr) {
*addrstr = xstrdup(address); *addrstr = xstrdup(address);
if(portstr) }
if(portstr) {
*portstr = xstrdup(port); *portstr = xstrdup(port);
}
} }
char *sockaddr2hostname(const sockaddr_t *sa) { char *sockaddr2hostname(const sockaddr_t *sa) {
@ -125,10 +133,11 @@ char *sockaddr2hostname(const sockaddr_t *sa) {
} }
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV)); hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
if(err) { if(err) {
logger(LOG_ERR, "Error while looking up hostname: %s", logger(LOG_ERR, "Error while looking up hostname: %s",
gai_strerror(err)); gai_strerror(err));
} }
xasprintf(&str, "%s port %s", address, port); xasprintf(&str, "%s port %s", address, port);
@ -141,26 +150,27 @@ int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b) {
result = a->sa.sa_family - b->sa.sa_family; result = a->sa.sa_family - b->sa.sa_family;
if(result) if(result) {
return result; return result;
}
switch (a->sa.sa_family) { switch(a->sa.sa_family) {
case AF_UNSPEC: case AF_UNSPEC:
return 0; return 0;
case AF_UNKNOWN: case AF_UNKNOWN:
return strcmp(a->unknown.address, b->unknown.address); return strcmp(a->unknown.address, b->unknown.address);
case AF_INET: case AF_INET:
return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr)); return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
case AF_INET6: case AF_INET6:
return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)); return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
default: default:
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!", logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
a->sa.sa_family); a->sa.sa_family);
abort(); abort();
} }
} }
@ -169,41 +179,45 @@ int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) {
result = a->sa.sa_family - b->sa.sa_family; result = a->sa.sa_family - b->sa.sa_family;
if(result) if(result) {
return result; return result;
}
switch (a->sa.sa_family) { switch(a->sa.sa_family) {
case AF_UNSPEC: case AF_UNSPEC:
return 0; return 0;
case AF_UNKNOWN: case AF_UNKNOWN:
result = strcmp(a->unknown.address, b->unknown.address); result = strcmp(a->unknown.address, b->unknown.address);
if(result) if(result) {
return result; return result;
}
return strcmp(a->unknown.port, b->unknown.port); return strcmp(a->unknown.port, b->unknown.port);
case AF_INET: case AF_INET:
result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr)); result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
if(result) if(result) {
return result; return result;
}
return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port)); return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port));
case AF_INET6: case AF_INET6:
result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)); result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
if(result) if(result) {
return result; return result;
}
return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port)); return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
default: default:
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!", logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
a->sa.sa_family); a->sa.sa_family);
abort(); abort();
} }
} }
@ -233,20 +247,26 @@ void sockaddrunmap(sockaddr_t *sa) {
void sockaddr_setport(sockaddr_t *sa, const char *port) { void sockaddr_setport(sockaddr_t *sa, const char *port) {
uint16_t portnum = htons(atoi(port)); uint16_t portnum = htons(atoi(port));
if(!portnum)
if(!portnum) {
return; return;
}
switch(sa->sa.sa_family) { switch(sa->sa.sa_family) {
case AF_INET: case AF_INET:
sa->in.sin_port = portnum; sa->in.sin_port = portnum;
break; break;
case AF_INET6:
sa->in6.sin6_port = portnum; case AF_INET6:
break; sa->in6.sin6_port = portnum;
case AF_UNKNOWN: break;
free(sa->unknown.port);
sa->unknown.port = xstrdup(port); case AF_UNKNOWN:
default: free(sa->unknown.port);
return; sa->unknown.port = xstrdup(port);
default:
return;
} }
} }
@ -259,13 +279,15 @@ int maskcmp(const void *va, const void *vb, int masklen) {
for(m = masklen, i = 0; m >= 8; m -= 8, i++) { for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
result = a[i] - b[i]; result = a[i] - b[i];
if(result)
if(result) {
return result; return result;
}
} }
if(m) if(m)
return (a[i] & (0x100 - (1 << (8 - m)))) - return (a[i] & (0x100 - (1 << (8 - m)))) -
(b[i] & (0x100 - (1 << (8 - m)))); (b[i] & (0x100 - (1 << (8 - m))));
return 0; return 0;
} }
@ -277,11 +299,13 @@ void mask(void *va, int masklen, int len) {
i = masklen / 8; i = masklen / 8;
masklen %= 8; masklen %= 8;
if(masklen) if(masklen) {
a[i++] &= (0x100 - (1 << (8 - masklen))); a[i++] &= (0x100 - (1 << (8 - masklen)));
}
for(; i < len; i++) for(; i < len; i++) {
a[i] = 0; a[i] = 0;
}
} }
void maskcpy(void *va, const void *vb, int masklen, int len) { void maskcpy(void *va, const void *vb, int masklen, int len) {
@ -289,16 +313,18 @@ void maskcpy(void *va, const void *vb, int masklen, int len) {
char *a = va; char *a = va;
const char *b = vb; const char *b = vb;
for(m = masklen, i = 0; m >= 8; m -= 8, i++) for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
a[i] = b[i]; a[i] = b[i];
}
if(m) { if(m) {
a[i] = b[i] & (0x100 - (1 << (8 - m))); a[i] = b[i] & (0x100 - (1 << (8 - m)));
i++; i++;
} }
for(; i < len; i++) for(; i < len; i++) {
a[i] = 0; a[i] = 0;
}
} }
bool maskcheck(const void *va, int masklen, int len) { bool maskcheck(const void *va, int masklen, int len) {
@ -308,12 +334,14 @@ bool maskcheck(const void *va, int masklen, int len) {
i = masklen / 8; i = masklen / 8;
masklen %= 8; masklen %= 8;
if(masklen && a[i++] & (0xff >> masklen)) if(masklen && a[i++] & (0xff >> masklen)) {
return false; return false;
}
for(; i < len; i++) for(; i < len; i++)
if(a[i] != 0) if(a[i] != 0) {
return false; return false;
}
return true; return true;
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_NETUTL_H
#define TINC_NETUTL_H
/* /*
netutl.h -- header file for netutl.c netutl.h -- header file for netutl.c
Copyright (C) 1998-2005 Ivo Timmermans Copyright (C) 1998-2005 Ivo Timmermans
@ -18,26 +21,23 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_NETUTL_H__
#define __TINC_NETUTL_H__
#include "net.h" #include "net.h"
extern bool hostnames; extern bool hostnames;
extern struct addrinfo *str2addrinfo(const char *, const char *, int); extern struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype);
extern sockaddr_t str2sockaddr(const char *, const char *); extern sockaddr_t str2sockaddr(const char *address, const char *port);
extern void sockaddr2str(const sockaddr_t *, char **, char **); extern void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr);
extern char *sockaddr2hostname(const sockaddr_t *); extern char *sockaddr2hostname(const sockaddr_t *sa);
extern int sockaddrcmp(const sockaddr_t *, const sockaddr_t *); extern int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b);
extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *); extern int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b);
extern void sockaddrunmap(sockaddr_t *); extern void sockaddrunmap(sockaddr_t *sa);
extern void sockaddrfree(sockaddr_t *); extern void sockaddrfree(sockaddr_t *sa);
extern void sockaddrcpy(sockaddr_t *, const sockaddr_t *); extern void sockaddrcpy(sockaddr_t *dest, const sockaddr_t *src);
extern void sockaddr_setport(sockaddr_t *, const char *); extern void sockaddr_setport(sockaddr_t *sa, const char *port);
extern int maskcmp(const void *, const void *, int); extern int maskcmp(const void *a, const void *b, int masklen);
extern void maskcpy(void *, const void *, int, int); extern void maskcpy(void *dest, const void *src, int masklen, int len);
extern void mask(void *, int, int); extern void mask(void *mask, int masklen, int len);
extern bool maskcheck(const void *, int, int); extern bool maskcheck(const void *mask, int masklen, int len);
#endif /* __TINC_NETUTL_H__ */ #endif

View file

@ -28,8 +28,8 @@
#include "utils.h" #include "utils.h"
#include "xalloc.h" #include "xalloc.h"
avl_tree_t *node_tree; /* Known nodes, sorted by name */ avl_tree_t *node_tree; /* Known nodes, sorted by name */
avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */ avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */
node_t *myself; node_t *myself;
@ -38,7 +38,7 @@ static int node_compare(const node_t *a, const node_t *b) {
} }
static int node_udp_compare(const node_t *a, const node_t *b) { static int node_udp_compare(const node_t *a, const node_t *b) {
return sockaddrcmp(&a->address, &b->address); return sockaddrcmp(&a->address, &b->address);
} }
void init_nodes(void) { void init_nodes(void) {
@ -54,13 +54,19 @@ void exit_nodes(void) {
node_t *new_node(void) { node_t *new_node(void) {
node_t *n = xmalloc_and_zero(sizeof(*n)); node_t *n = xmalloc_and_zero(sizeof(*n));
if(replaywin) n->late = xmalloc_and_zero(replaywin); if(replaywin) {
n->late = xmalloc_and_zero(replaywin);
}
n->subnet_tree = new_subnet_tree(); n->subnet_tree = new_subnet_tree();
n->edge_tree = new_edge_tree(); n->edge_tree = new_edge_tree();
n->inctx = EVP_CIPHER_CTX_new(); n->inctx = EVP_CIPHER_CTX_new();
n->outctx = EVP_CIPHER_CTX_new(); n->outctx = EVP_CIPHER_CTX_new();
if(!n->inctx || !n->outctx)
if(!n->inctx || !n->outctx) {
abort(); abort();
}
n->mtu = MTU; n->mtu = MTU;
n->maxmtu = MTU; n->maxmtu = MTU;
@ -68,34 +74,42 @@ node_t *new_node(void) {
} }
void free_node(node_t *n) { void free_node(node_t *n) {
if(n->inkey) if(n->inkey) {
free(n->inkey); free(n->inkey);
}
if(n->outkey) if(n->outkey) {
free(n->outkey); free(n->outkey);
}
if(n->subnet_tree) if(n->subnet_tree) {
free_subnet_tree(n->subnet_tree); free_subnet_tree(n->subnet_tree);
}
if(n->edge_tree) if(n->edge_tree) {
free_edge_tree(n->edge_tree); free_edge_tree(n->edge_tree);
}
sockaddrfree(&n->address); sockaddrfree(&n->address);
EVP_CIPHER_CTX_free(n->outctx); EVP_CIPHER_CTX_free(n->outctx);
EVP_CIPHER_CTX_free(n->inctx); EVP_CIPHER_CTX_free(n->inctx);
if(n->mtuevent) if(n->mtuevent) {
event_del(n->mtuevent); event_del(n->mtuevent);
}
if(n->hostname) if(n->hostname) {
free(n->hostname); free(n->hostname);
}
if(n->name) if(n->name) {
free(n->name); free(n->name);
}
if(n->late) if(n->late) {
free(n->late); free(n->late);
}
free(n); free(n);
} }
@ -126,7 +140,7 @@ void node_del(node_t *n) {
} }
node_t *lookup_node(char *name) { node_t *lookup_node(char *name) {
node_t n = {NULL}; node_t n = {};
n.name = name; n.name = name;
@ -134,7 +148,7 @@ node_t *lookup_node(char *name) {
} }
node_t *lookup_node_udp(const sockaddr_t *sa) { node_t *lookup_node_udp(const sockaddr_t *sa) {
node_t n = {NULL}; node_t n = {};
n.address = *sa; n.address = *sa;
n.name = NULL; n.name = NULL;
@ -150,8 +164,9 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
avl_delete(node_udp_tree, n); avl_delete(node_udp_tree, n);
if(n->hostname) if(n->hostname) {
free(n->hostname); free(n->hostname);
}
if(sa) { if(sa) {
n->address = *sa; n->address = *sa;
@ -159,7 +174,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
avl_insert(node_udp_tree, n); avl_insert(node_udp_tree, n);
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname); ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
} else { } else {
memset(&n->address, 0, sizeof n->address); memset(&n->address, 0, sizeof(n->address));
n->hostname = NULL; n->hostname = NULL;
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s cleared", n->name); ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s cleared", n->name);
} }
@ -174,10 +189,10 @@ void dump_nodes(void) {
for(node = node_tree->head; node; node = node->next) { for(node = node_tree->head; node; node = node->next) {
n = node->data; n = node->data;
logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s pmtu %d (min %d max %d)", logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s pmtu %d (min %d max %d)",
n->name, n->hostname, n->outcipher ? EVP_CIPHER_nid(n->outcipher) : 0, n->name, n->hostname, n->outcipher ? EVP_CIPHER_nid(n->outcipher) : 0,
n->outdigest ? EVP_MD_type(n->outdigest) : 0, n->outmaclength, n->outcompression, n->outdigest ? EVP_MD_type(n->outdigest) : 0, n->outmaclength, n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-", n->options, bitfield_to_int(&n->status, sizeof(n->status)), n->nexthop ? n->nexthop->name : "-",
n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu); n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
} }
logger(LOG_DEBUG, "End of nodes."); logger(LOG_DEBUG, "End of nodes.");

View file

@ -1,3 +1,6 @@
#ifndef TINC_NODE_H
#define TINC_NODE_H
/* /*
node.h -- header for node.c node.h -- header for node.c
Copyright (C) 2001-2016 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2001-2016 Guus Sliepen <guus@tinc-vpn.org>,
@ -18,74 +21,71 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_NODE_H__
#define __TINC_NODE_H__
#include "avl_tree.h" #include "avl_tree.h"
#include "connection.h" #include "connection.h"
#include "event.h" #include "event.h"
#include "subnet.h" #include "subnet.h"
typedef struct node_status_t { typedef struct node_status_t {
unsigned int unused_active:1; /* 1 if active (not used for nodes) */ unsigned int unused_active: 1; /* 1 if active (not used for nodes) */
unsigned int validkey:1; /* 1 if we currently have a valid key for him */ unsigned int validkey: 1; /* 1 if we currently have a valid key for him */
unsigned int unused_waitingforkey:1; /* 1 if we already sent out a request */ unsigned int unused_waitingforkey: 1; /* 1 if we already sent out a request */
unsigned int visited:1; /* 1 if this node has been visited by one of the graph algorithms */ unsigned int visited: 1; /* 1 if this node has been visited by one of the graph algorithms */
unsigned int reachable:1; /* 1 if this node is reachable in the graph */ unsigned int reachable: 1; /* 1 if this node is reachable in the graph */
unsigned int indirect:1; /* 1 if this node is not directly reachable by us */ unsigned int indirect: 1; /* 1 if this node is not directly reachable by us */
unsigned int unused:26; unsigned int unused: 26;
} node_status_t; } node_status_t;
typedef struct node_t { typedef struct node_t {
char *name; /* name of this node */ char *name; /* name of this node */
uint32_t options; /* options turned on for this node */ uint32_t options; /* options turned on for this node */
int sock; /* Socket to use for outgoing UDP packets */ int sock; /* Socket to use for outgoing UDP packets */
sockaddr_t address; /* his real (internet) ip to send UDP packets to */ sockaddr_t address; /* his real (internet) ip to send UDP packets to */
char *hostname; /* the hostname of its real ip */ char *hostname; /* the hostname of its real ip */
node_status_t status; node_status_t status;
time_t last_req_key; time_t last_req_key;
const EVP_CIPHER *incipher; /* Cipher type for UDP packets received from him */ const EVP_CIPHER *incipher; /* Cipher type for UDP packets received from him */
char *inkey; /* Cipher key and iv */ char *inkey; /* Cipher key and iv */
int inkeylength; /* Cipher key and iv length */ int inkeylength; /* Cipher key and iv length */
EVP_CIPHER_CTX *inctx; /* Cipher context */ EVP_CIPHER_CTX *inctx; /* Cipher context */
const EVP_CIPHER *outcipher; /* Cipher type for UDP packets sent to him*/ const EVP_CIPHER *outcipher; /* Cipher type for UDP packets sent to him*/
char *outkey; /* Cipher key and iv */ char *outkey; /* Cipher key and iv */
int outkeylength; /* Cipher key and iv length */ int outkeylength; /* Cipher key and iv length */
EVP_CIPHER_CTX *outctx; /* Cipher context */ EVP_CIPHER_CTX *outctx; /* Cipher context */
const EVP_MD *indigest; /* Digest type for MAC of packets received from him */ const EVP_MD *indigest; /* Digest type for MAC of packets received from him */
int inmaclength; /* Length of MAC */ int inmaclength; /* Length of MAC */
const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/ const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/
int outmaclength; /* Length of MAC */ int outmaclength; /* Length of MAC */
int incompression; /* Compressionlevel, 0 = no compression */ int incompression; /* Compressionlevel, 0 = no compression */
int outcompression; /* Compressionlevel, 0 = no compression */ int outcompression; /* Compressionlevel, 0 = no compression */
struct node_t *nexthop; /* nearest node from us to him */ struct node_t *nexthop; /* nearest node from us to him */
struct edge_t *prevedge; /* nearest node from him to us */ struct edge_t *prevedge; /* nearest node from him to us */
struct node_t *via; /* next hop for UDP packets */ struct node_t *via; /* next hop for UDP packets */
avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */
avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */
struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */ struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */
uint32_t sent_seqno; /* Sequence number last sent to this node */ uint32_t sent_seqno; /* Sequence number last sent to this node */
uint32_t received_seqno; /* Sequence number last received from this node */ uint32_t received_seqno; /* Sequence number last received from this node */
uint32_t farfuture; /* Packets in a row that have arrived from the far future */ uint32_t farfuture; /* Packets in a row that have arrived from the far future */
unsigned char* late; /* Bitfield marking late packets */ unsigned char *late; /* Bitfield marking late packets */
length_t mtu; /* Maximum size of packets to send to this node */ length_t mtu; /* Maximum size of packets to send to this node */
length_t minmtu; /* Probed minimum MTU */ length_t minmtu; /* Probed minimum MTU */
length_t maxmtu; /* Probed maximum MTU */ length_t maxmtu; /* Probed maximum MTU */
int mtuprobes; /* Number of probes */ int mtuprobes; /* Number of probes */
event_t *mtuevent; /* Probe event */ event_t *mtuevent; /* Probe event */
} node_t; } node_t;
extern struct node_t *myself; extern struct node_t *myself;
@ -94,13 +94,13 @@ extern avl_tree_t *node_udp_tree;
extern void init_nodes(void); extern void init_nodes(void);
extern void exit_nodes(void); extern void exit_nodes(void);
extern node_t *new_node(void) __attribute__ ((__malloc__)); extern node_t *new_node(void) __attribute__((__malloc__));
extern void free_node(node_t *); extern void free_node(node_t *n);
extern void node_add(node_t *); extern void node_add(node_t *n);
extern void node_del(node_t *); extern void node_del(node_t *n);
extern node_t *lookup_node(char *); extern node_t *lookup_node(char *name);
extern node_t *lookup_node_udp(const sockaddr_t *); extern node_t *lookup_node_udp(const sockaddr_t *sa);
extern void update_node_udp(node_t *, const sockaddr_t *); extern void update_node_udp(node_t *n, const sockaddr_t *sa);
extern void dump_nodes(void); extern void dump_nodes(void);
#endif /* __TINC_NODE_H__ */ #endif

View file

@ -22,7 +22,7 @@
/* left unaltered for tinc -- Ivo Timmermans */ /* left unaltered for tinc -- Ivo Timmermans */
/* /*
* Sat Aug 19 13:24:33 MET DST 1995: Martin Schulze * Sat Aug 19 13:24:33 MET DST 1995: Martin Schulze
* First version (v0.2) released * First version (v0.2) released
*/ */
#include "system.h" #include "system.h"
@ -36,17 +36,20 @@
* 0 is returned if either there's no pidfile, it's empty * 0 is returned if either there's no pidfile, it's empty
* or no pid can be read. * or no pid can be read.
*/ */
pid_t read_pid (const char *pidfile) pid_t read_pid(const char *pidfile) {
{ FILE *f;
FILE *f; long pid;
long pid;
if (!(f=fopen(pidfile,"r"))) if(!(f = fopen(pidfile, "r"))) {
return 0; return 0;
if(fscanf(f,"%20ld", &pid) != 1) }
pid = 0;
fclose(f); if(fscanf(f, "%20ld", &pid) != 1) {
return (pid_t)pid; pid = 0;
}
fclose(f);
return (pid_t)pid;
} }
/* check_pid /* check_pid
@ -55,25 +58,27 @@ pid_t read_pid (const char *pidfile)
* table (using /proc) to determine if the process already exists. If * table (using /proc) to determine if the process already exists. If
* so the pid is returned, otherwise 0. * so the pid is returned, otherwise 0.
*/ */
pid_t check_pid (const char *pidfile) pid_t check_pid(const char *pidfile) {
{ pid_t pid = read_pid(pidfile);
pid_t pid = read_pid(pidfile);
/* Amazing ! _I_ am already holding the pid file... */ /* Amazing ! _I_ am already holding the pid file... */
if ((!pid) || (pid == getpid ())) if((!pid) || (pid == getpid())) {
return 0; return 0;
}
/* /*
* The 'standard' method of doing this is to try and do a 'fake' kill * The 'standard' method of doing this is to try and do a 'fake' kill
* of the process. If an ESRCH error is returned the process cannot * of the process. If an ESRCH error is returned the process cannot
* be found -- GW * be found -- GW
*/ */
/* But... errno is usually changed only on error.. */ /* But... errno is usually changed only on error.. */
errno = 0; errno = 0;
if (kill(pid, 0) && errno == ESRCH)
return 0;
return pid; if(kill(pid, 0) && errno == ESRCH) {
return 0;
}
return pid;
} }
/* write_pid /* write_pid
@ -81,44 +86,49 @@ pid_t check_pid (const char *pidfile)
* Writes the pid to the specified file. If that fails 0 is * Writes the pid to the specified file. If that fails 0 is
* returned, otherwise the pid. * returned, otherwise the pid.
*/ */
pid_t write_pid (const char *pidfile) pid_t write_pid(const char *pidfile) {
{ FILE *f;
FILE *f; int fd;
int fd; pid_t pid;
pid_t pid;
if ((fd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1) { if((fd = open(pidfile, O_RDWR | O_CREAT, 0644)) == -1) {
return 0; return 0;
} }
if ((f = fdopen(fd, "r+")) == NULL) { if((f = fdopen(fd, "r+")) == NULL) {
close(fd); close(fd);
return 0; return 0;
} }
#ifdef HAVE_FLOCK #ifdef HAVE_FLOCK
if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
fclose(f); if(flock(fd, LOCK_EX | LOCK_NB) == -1) {
return 0; fclose(f);
} return 0;
}
#endif #endif
pid = getpid(); pid = getpid();
if (!fprintf(f,"%ld\n", (long)pid)) {
fclose(f); if(!fprintf(f, "%ld\n", (long)pid)) {
return 0; fclose(f);
} return 0;
fflush(f); }
fflush(f);
#ifdef HAVE_FLOCK #ifdef HAVE_FLOCK
if (flock(fd, LOCK_UN) == -1) {
fclose(f);
return 0;
}
#endif
fclose(f);
return pid; if(flock(fd, LOCK_UN) == -1) {
fclose(f);
return 0;
}
#endif
fclose(f);
return pid;
} }
/* remove_pid /* remove_pid
@ -126,8 +136,7 @@ pid_t write_pid (const char *pidfile)
* Remove the the specified file. The result from unlink(2) * Remove the the specified file. The result from unlink(2)
* is returned * is returned
*/ */
int remove_pid (const char *pidfile) int remove_pid(const char *pidfile) {
{ return unlink(pidfile);
return unlink (pidfile);
} }
#endif #endif

View file

@ -1,3 +1,6 @@
#ifndef TINC_PIDFILE_H
#define TINC_PIDFILE_H
/* /*
pidfile.h - interact with pidfiles pidfile.h - interact with pidfiles
Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE> Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE>
@ -26,7 +29,7 @@
* 0 is returned if either there's no pidfile, it's empty * 0 is returned if either there's no pidfile, it's empty
* or no pid can be read. * or no pid can be read.
*/ */
extern pid_t read_pid (const char *pidfile); extern pid_t read_pid(const char *pidfile);
/* check_pid /* check_pid
* *
@ -34,19 +37,21 @@ extern pid_t read_pid (const char *pidfile);
* table (using /proc) to determine if the process already exists. If * table (using /proc) to determine if the process already exists. If
* so 1 is returned, otherwise 0. * so 1 is returned, otherwise 0.
*/ */
extern pid_t check_pid (const char *pidfile); extern pid_t check_pid(const char *pidfile);
/* write_pid /* write_pid
* *
* Writes the pid to the specified file. If that fails 0 is * Writes the pid to the specified file. If that fails 0 is
* returned, otherwise the pid. * returned, otherwise the pid.
*/ */
extern pid_t write_pid (const char *pidfile); extern pid_t write_pid(const char *pidfile);
/* remove_pid /* remove_pid
* *
* Remove the the specified file. The result from unlink(2) * Remove the the specified file. The result from unlink(2)
* is returned * is returned
*/ */
extern int remove_pid (const char *pidfile); extern int remove_pid(const char *pidfile);
#endif
#endif #endif

View file

@ -47,11 +47,6 @@ extern bool use_logfile;
static sigset_t emptysigset; static sigset_t emptysigset;
#endif #endif
static void memory_full(int size) {
logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size);
exit(1);
}
/* Some functions the less gifted operating systems might lack... */ /* Some functions the less gifted operating systems might lack... */
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
@ -71,42 +66,47 @@ bool install_service(void) {
SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"}; SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!manager) { if(!manager) {
logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError())); logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
return false; return false;
} }
if(!strchr(program_name, '\\')) { if(!strchr(program_name, '\\')) {
GetCurrentDirectory(sizeof command - 1, command + 1); GetCurrentDirectory(sizeof(command) - 1, command + 1);
strncat(command, "\\", sizeof command - strlen(command)); strncat(command, "\\", sizeof(command) - strlen(command));
} }
strncat(command, program_name, sizeof command - strlen(command)); strncat(command, program_name, sizeof(command) - strlen(command));
strncat(command, "\"", sizeof command - strlen(command)); strncat(command, "\"", sizeof(command) - strlen(command));
for(argp = g_argv + 1; *argp; argp++) { for(argp = g_argv + 1; *argp; argp++) {
space = strchr(*argp, ' '); space = strchr(*argp, ' ');
strncat(command, " ", sizeof command - strlen(command)); strncat(command, " ", sizeof(command) - strlen(command));
if(space) if(space) {
strncat(command, "\"", sizeof command - strlen(command)); strncat(command, "\"", sizeof(command) - strlen(command));
}
strncat(command, *argp, sizeof command - strlen(command)); strncat(command, *argp, sizeof(command) - strlen(command));
if(space) if(space) {
strncat(command, "\"", sizeof command - strlen(command)); strncat(command, "\"", sizeof(command) - strlen(command));
}
} }
service = CreateService(manager, identname, identname, service = CreateService(manager, identname, identname,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
command, NULL, NULL, NULL, NULL, NULL); command, NULL, NULL, NULL, NULL, NULL);
if(!service) { if(!service) {
DWORD lasterror = GetLastError(); DWORD lasterror = GetLastError();
logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror)); logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror));
if(lasterror != ERROR_SERVICE_EXISTS)
if(lasterror != ERROR_SERVICE_EXISTS) {
return false; return false;
}
} }
if(service) { if(service) {
@ -116,16 +116,18 @@ bool install_service(void) {
service = OpenService(manager, identname, SERVICE_ALL_ACCESS); service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
} }
if(!StartService(service, 0, NULL)) if(!StartService(service, 0, NULL)) {
logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError())); logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
else } else {
logger(LOG_INFO, "%s service started", identname); logger(LOG_INFO, "%s service started", identname);
}
return true; return true;
} }
bool remove_service(void) { bool remove_service(void) {
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!manager) { if(!manager) {
logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError())); logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
return false; return false;
@ -138,10 +140,11 @@ bool remove_service(void) {
return false; return false;
} }
if(!ControlService(service, SERVICE_CONTROL_STOP, &status)) if(!ControlService(service, SERVICE_CONTROL_STOP, &status)) {
logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError())); logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError()));
else } else {
logger(LOG_INFO, "%s service stopped", identname); logger(LOG_INFO, "%s service stopped", identname);
}
if(!DeleteService(service)) { if(!DeleteService(service)) {
logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError())); logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError()));
@ -155,18 +158,21 @@ bool remove_service(void) {
DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) { DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
switch(request) { switch(request) {
case SERVICE_CONTROL_INTERROGATE: case SERVICE_CONTROL_INTERROGATE:
SetServiceStatus(statushandle, &status); SetServiceStatus(statushandle, &status);
return NO_ERROR; return NO_ERROR;
case SERVICE_CONTROL_STOP:
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP"); case SERVICE_CONTROL_STOP:
break; logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
case SERVICE_CONTROL_SHUTDOWN: break;
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
break; case SERVICE_CONTROL_SHUTDOWN:
default: logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
logger(LOG_WARNING, "Got unexpected request %d", (int)request); break;
return ERROR_CALL_NOT_IMPLEMENTED;
default:
logger(LOG_WARNING, "Got unexpected request %d", (int)request);
return ERROR_CALL_NOT_IMPLEMENTED;
} }
if(running) { if(running) {
@ -184,7 +190,7 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
} }
VOID WINAPI run_service(DWORD argc, LPTSTR* argv) { VOID WINAPI run_service(DWORD argc, LPTSTR *argv) {
extern int main2(int argc, char **argv); extern int main2(int argc, char **argv);
status.dwServiceType = SERVICE_WIN32; status.dwServiceType = SERVICE_WIN32;
@ -195,7 +201,7 @@ VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL); statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL);
if (!statushandle) { if(!statushandle) {
logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError())); logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
} else { } else {
status.dwWaitHint = 30000; status.dwWaitHint = 30000;
@ -225,9 +231,9 @@ bool init_service(void) {
if(!StartServiceCtrlDispatcher(services)) { if(!StartServiceCtrlDispatcher(services)) {
if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
return false; return false;
} } else {
else
logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError())); logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
}
} }
return true; return true;
@ -246,9 +252,11 @@ static bool write_pidfile(void) {
if(pid) { if(pid) {
if(netname) if(netname)
fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n", fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n",
netname, (long)pid); netname, (long)pid);
else else {
fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid); fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid);
}
return false; return false;
} }
@ -274,21 +282,24 @@ bool kill_other(int signal) {
if(!pid) { if(!pid) {
if(netname) if(netname)
fprintf(stderr, "No other tincd is running for net `%s'.\n", fprintf(stderr, "No other tincd is running for net `%s'.\n",
netname); netname);
else else {
fprintf(stderr, "No other tincd is running.\n"); fprintf(stderr, "No other tincd is running.\n");
}
return false; return false;
} }
errno = 0; /* No error, sometimes errno is only changed on error */ errno = 0; /* No error, sometimes errno is only changed on error */
/* ESRCH is returned when no process with that pid is found */ /* ESRCH is returned when no process with that pid is found */
if(kill(pid, signal) && errno == ESRCH) { if(kill(pid, signal) && errno == ESRCH) {
if(netname) if(netname)
fprintf(stderr, "The tincd for net `%s' is no longer running. ", fprintf(stderr, "The tincd for net `%s' is no longer running. ",
netname); netname);
else else {
fprintf(stderr, "The tincd is no longer running. "); fprintf(stderr, "The tincd is no longer running. ");
}
fprintf(stderr, "Removing stale lock file.\n"); fprintf(stderr, "Removing stale lock file.\n");
remove_pid(pidfilename); remove_pid(pidfilename);
@ -309,8 +320,10 @@ bool detach(void) {
/* First check if we can open a fresh new pidfile */ /* First check if we can open a fresh new pidfile */
#ifndef HAVE_MINGW #ifndef HAVE_MINGW
if(!write_pidfile())
if(!write_pidfile()) {
return false; return false;
}
/* If we succeeded in doing that, detach */ /* If we succeeded in doing that, detach */
@ -319,9 +332,10 @@ bool detach(void) {
if(do_detach) { if(do_detach) {
#ifndef HAVE_MINGW #ifndef HAVE_MINGW
if(daemon(0, 0)) { if(daemon(0, 0)) {
fprintf(stderr, "Couldn't detach from terminal: %s", fprintf(stderr, "Couldn't detach from terminal: %s",
strerror(errno)); strerror(errno));
return false; return false;
} }
@ -331,18 +345,20 @@ bool detach(void) {
fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno)); fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno));
return false; return false;
} }
#else #else
if(!statushandle)
if(!statushandle) {
exit(install_service()); exit(install_service());
}
#endif #endif
} }
openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR)); openlogger(identname, use_logfile ? LOGMODE_FILE : (do_detach ? LOGMODE_SYSLOG : LOGMODE_STDERR));
logger(LOG_NOTICE, "tincd %s starting, debug level %d", logger(LOG_NOTICE, "tincd %s starting, debug level %d",
VERSION, debug_level); VERSION, debug_level);
xalloc_fail_func = memory_full;
return true; return true;
} }
@ -350,8 +366,11 @@ bool detach(void) {
#ifdef HAVE_PUTENV #ifdef HAVE_PUTENV
void unputenv(char *p) { void unputenv(char *p) {
char *e = strchr(p, '='); char *e = strchr(p, '=');
if(!e)
if(!e) {
return; return;
}
int len = e - p; int len = e - p;
#ifndef HAVE_UNSETENV #ifndef HAVE_UNSETENV
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
@ -368,13 +387,16 @@ void unputenv(char *p) {
// We must keep what we putenv() around in memory. // We must keep what we putenv() around in memory.
// To do this without memory leaks, keep things in a list and reuse if possible. // To do this without memory leaks, keep things in a list and reuse if possible.
static list_t list = {}; static list_t list = {};
for(list_node_t *node = list.head; node; node = node->next) { for(list_node_t *node = list.head; node; node = node->next) {
char *data = node->data; char *data = node->data;
if(!strcmp(data, var)) { if(!strcmp(data, var)) {
putenv(data); putenv(data);
return; return;
} }
} }
char *data = xstrdup(var); char *data = xstrdup(var);
list_insert_tail(&list, data); list_insert_tail(&list, data);
putenv(data); putenv(data);
@ -396,13 +418,18 @@ bool execute_script(const char *name, char **envp) {
#ifndef HAVE_MINGW #ifndef HAVE_MINGW
len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name); len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
#else #else
if(cfg_interpreter)
if(cfg_interpreter) {
len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name); len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
else } else {
len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name); len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name);
}
#endif #endif
if(len < 0)
if(len < 0) {
return false; return false;
}
scriptname[len - 1] = '\0'; scriptname[len - 1] = '\0';
@ -418,16 +445,19 @@ bool execute_script(const char *name, char **envp) {
free(scriptname); free(scriptname);
len = xasprintf(&scriptname, "%s \"%s/%s\"", interpreter, confbase, name); len = xasprintf(&scriptname, "%s \"%s/%s\"", interpreter, confbase, name);
free(interpreter); free(interpreter);
if(len < 0)
if(len < 0) {
return false; return false;
}
} }
ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name); ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name);
/* Set environment */ /* Set environment */
for(i = 0; envp[i]; i++) for(i = 0; envp[i]; i++) {
putenv(envp[i]); putenv(envp[i]);
}
scriptname[len - 1] = '\"'; scriptname[len - 1] = '\"';
status = system(scriptname); status = system(scriptname);
@ -436,30 +466,34 @@ bool execute_script(const char *name, char **envp) {
/* Unset environment */ /* Unset environment */
for(i = 0; envp[i]; i++) for(i = 0; envp[i]; i++) {
unputenv(envp[i]); unputenv(envp[i]);
}
if(status != -1) { if(status != -1) {
#ifdef WEXITSTATUS #ifdef WEXITSTATUS
if(WIFEXITED(status)) { /* Child exited by itself */
if(WIFEXITED(status)) { /* Child exited by itself */
if(WEXITSTATUS(status)) { if(WEXITSTATUS(status)) {
logger(LOG_ERR, "Script %s exited with non-zero status %d", logger(LOG_ERR, "Script %s exited with non-zero status %d",
name, WEXITSTATUS(status)); name, WEXITSTATUS(status));
return false; return false;
} }
} else if(WIFSIGNALED(status)) { /* Child was killed by a signal */ } else if(WIFSIGNALED(status)) { /* Child was killed by a signal */
logger(LOG_ERR, "Script %s was killed by signal %d (%s)", logger(LOG_ERR, "Script %s was killed by signal %d (%s)",
name, WTERMSIG(status), strsignal(WTERMSIG(status))); name, WTERMSIG(status), strsignal(WTERMSIG(status)));
return false; return false;
} else { /* Something strange happened */ } else { /* Something strange happened */
logger(LOG_ERR, "Script %s terminated abnormally", name); logger(LOG_ERR, "Script %s terminated abnormally", name);
return false; return false;
} }
#endif #endif
} else { } else {
logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno)); logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
return false; return false;
} }
#endif #endif
return true; return true;
} }
@ -471,24 +505,30 @@ bool execute_script(const char *name, char **envp) {
#ifndef HAVE_MINGW #ifndef HAVE_MINGW
static RETSIGTYPE sigterm_handler(int a) { static RETSIGTYPE sigterm_handler(int a) {
(void)a;
logger(LOG_NOTICE, "Got %s signal", "TERM"); logger(LOG_NOTICE, "Got %s signal", "TERM");
if(running)
if(running) {
running = false; running = false;
else } else {
exit(1); exit(1);
}
} }
static RETSIGTYPE sigquit_handler(int a) { static RETSIGTYPE sigquit_handler(int a) {
(void)a;
logger(LOG_NOTICE, "Got %s signal", "QUIT"); logger(LOG_NOTICE, "Got %s signal", "QUIT");
if(running)
if(running) {
running = false; running = false;
else } else {
exit(1); exit(1);
}
} }
static RETSIGTYPE fatal_signal_square(int a) { static RETSIGTYPE fatal_signal_square(int a) {
logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a, logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a,
strsignal(a)); strsignal(a));
exit(1); exit(1);
} }
@ -515,39 +555,44 @@ static RETSIGTYPE fatal_signal_handler(int a) {
} }
static RETSIGTYPE sighup_handler(int a) { static RETSIGTYPE sighup_handler(int a) {
(void)a;
logger(LOG_NOTICE, "Got %s signal", "HUP"); logger(LOG_NOTICE, "Got %s signal", "HUP");
sighup = true; sighup = true;
} }
static RETSIGTYPE sigint_handler(int a) { static RETSIGTYPE sigint_handler(int a) {
(void)a;
static int saved_debug_level = -1; static int saved_debug_level = -1;
logger(LOG_NOTICE, "Got %s signal", "INT"); logger(LOG_NOTICE, "Got %s signal", "INT");
if(saved_debug_level != -1) { if(saved_debug_level != -1) {
logger(LOG_NOTICE, "Reverting to old debug level (%d)", logger(LOG_NOTICE, "Reverting to old debug level (%d)",
saved_debug_level); saved_debug_level);
debug_level = saved_debug_level; debug_level = saved_debug_level;
saved_debug_level = -1; saved_debug_level = -1;
} else { } else {
logger(LOG_NOTICE, logger(LOG_NOTICE,
"Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.", "Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.",
debug_level); debug_level);
saved_debug_level = debug_level; saved_debug_level = debug_level;
debug_level = 5; debug_level = 5;
} }
} }
static RETSIGTYPE sigalrm_handler(int a) { static RETSIGTYPE sigalrm_handler(int a) {
(void)a;
logger(LOG_NOTICE, "Got %s signal", "ALRM"); logger(LOG_NOTICE, "Got %s signal", "ALRM");
sigalrm = true; sigalrm = true;
} }
static RETSIGTYPE sigusr1_handler(int a) { static RETSIGTYPE sigusr1_handler(int a) {
(void)a;
dump_connections(); dump_connections();
} }
static RETSIGTYPE sigusr2_handler(int a) { static RETSIGTYPE sigusr2_handler(int a) {
(void)a;
devops.dump_stats(); devops.dump_stats();
dump_nodes(); dump_nodes();
dump_edges(); dump_edges();
@ -555,14 +600,17 @@ static RETSIGTYPE sigusr2_handler(int a) {
} }
static RETSIGTYPE sigwinch_handler(int a) { static RETSIGTYPE sigwinch_handler(int a) {
(void)a;
do_purge = true; do_purge = true;
} }
static RETSIGTYPE unexpected_signal_handler(int a) { static RETSIGTYPE unexpected_signal_handler(int a) {
(void)a;
logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a)); logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a));
} }
static RETSIGTYPE ignore_signal_handler(int a) { static RETSIGTYPE ignore_signal_handler(int a) {
(void)a;
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignored signal %d (%s)", a, strsignal(a)); ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignored signal %d (%s)", a, strsignal(a));
} }
@ -601,25 +649,30 @@ void setup_signals(void) {
/* Set a default signal handler for every signal, errors will be /* Set a default signal handler for every signal, errors will be
ignored. */ ignored. */
for(i = 1; i < NSIG; i++) { for(i = 1; i < NSIG; i++) {
if(!do_detach) if(!do_detach) {
act.sa_handler = SIG_DFL; act.sa_handler = SIG_DFL;
else } else {
act.sa_handler = unexpected_signal_handler; act.sa_handler = unexpected_signal_handler;
}
sigaction(i, &act, NULL); sigaction(i, &act, NULL);
} }
/* If we didn't detach, allow coredumps */ /* If we didn't detach, allow coredumps */
if(!do_detach) if(!do_detach) {
sighandlers[3].handler = SIG_DFL; sighandlers[3].handler = SIG_DFL;
}
/* Then, for each known signal that we want to catch, assign a /* Then, for each known signal that we want to catch, assign a
handler to the signal, with error checking this time. */ handler to the signal, with error checking this time. */
for(i = 0; sighandlers[i].signal; i++) { for(i = 0; sighandlers[i].signal; i++) {
act.sa_handler = sighandlers[i].handler; act.sa_handler = sighandlers[i].handler;
if(sigaction(sighandlers[i].signal, &act, NULL) < 0) if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n", fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n",
sighandlers[i].signal, strsignal(sighandlers[i].signal), sighandlers[i].signal, strsignal(sighandlers[i].signal),
strerror(errno)); strerror(errno));
} }
#endif #endif
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_PROCESS_H
#define TINC_PROCESS_H
/* /*
process.h -- header file for process.c process.h -- header file for process.c
Copyright (C) 1999-2005 Ivo Timmermans, Copyright (C) 1999-2005 Ivo Timmermans,
@ -18,20 +21,17 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_PROCESS_H__
#define __TINC_PROCESS_H__
extern bool do_detach; extern bool do_detach;
extern bool sighup; extern bool sighup;
extern bool sigalrm; extern bool sigalrm;
extern void setup_signals(void); extern void setup_signals(void);
extern bool execute_script(const char *, char **); extern bool execute_script(const char *name, char **envp);
extern bool detach(void); extern bool detach(void);
extern bool kill_other(int); extern bool kill_other(int signal);
#ifdef HAVE_MINGW #ifdef HAVE_MINGW
extern bool init_service(void); extern bool init_service(void);
#endif #endif
#endif /* __TINC_PROCESS_H__ */ #endif

View file

@ -34,30 +34,31 @@ bool strictsubnets = false;
/* Jumptable for the request handlers */ /* Jumptable for the request handlers */
static bool (*request_handlers[])(connection_t *) = { static bool (*request_handlers[])(connection_t *) = {
id_h, metakey_h, challenge_h, chal_reply_h, ack_h, id_h, metakey_h, challenge_h, chal_reply_h, ack_h,
status_h, error_h, termreq_h, NULL, NULL, NULL,
ping_h, pong_h, ping_h, pong_h,
add_subnet_h, del_subnet_h, add_subnet_h, del_subnet_h,
add_edge_h, del_edge_h, add_edge_h, del_edge_h,
key_changed_h, req_key_h, ans_key_h, tcppacket_h, key_changed_h, req_key_h, ans_key_h, tcppacket_h,
}; };
/* Request names */ /* Request names */
static char (*request_name[]) = { static char (*request_name[]) = {
"ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK", "ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
"STATUS", "ERROR", "TERMREQ", "STATUS", "ERROR", "TERMREQ",
"PING", "PONG", "PING", "PONG",
"ADD_SUBNET", "DEL_SUBNET", "ADD_SUBNET", "DEL_SUBNET",
"ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET",
}; };
static avl_tree_t *past_request_tree; static avl_tree_t *past_request_tree;
bool check_id(const char *id) { bool check_id(const char *id) {
for(; *id; id++) for(; *id; id++)
if(!isalnum(*id) && *id != '_') if(!isalnum(*id) && *id != '_') {
return false; return false;
}
return true; return true;
} }
@ -75,24 +76,24 @@ bool send_request(connection_t *c, const char *format, ...) {
input buffer anyway */ input buffer anyway */
va_start(args, format); va_start(args, format);
len = vsnprintf(buffer, sizeof buffer, format, args); len = vsnprintf(buffer, sizeof(buffer), format, args);
buffer[sizeof buffer - 1] = 0; buffer[sizeof(buffer) - 1] = 0;
va_end(args); va_end(args);
if(len < 0 || len > sizeof buffer - 1) { if(len < 0 || (size_t)len > sizeof(buffer) - 1) {
logger(LOG_ERR, "Output buffer overflow while sending request to %s (%s)", logger(LOG_ERR, "Output buffer overflow while sending request to %s (%s)",
c->name, c->hostname); c->name, c->hostname);
return false; return false;
} }
ifdebug(PROTOCOL) { ifdebug(PROTOCOL) {
sscanf(buffer, "%d", &request); sscanf(buffer, "%d", &request);
ifdebug(META) ifdebug(META)
logger(LOG_DEBUG, "Sending %s to %s (%s): %s", logger(LOG_DEBUG, "Sending %s to %s (%s): %s",
request_name[request], c->name, c->hostname, buffer); request_name[request], c->name, c->hostname, buffer);
else else
logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[request], logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[request],
c->name, c->hostname); c->name, c->hostname);
} }
buffer[len++] = '\n'; buffer[len++] = '\n';
@ -100,8 +101,9 @@ bool send_request(connection_t *c, const char *format, ...) {
if(c == everyone) { if(c == everyone) {
broadcast_meta(NULL, buffer, len); broadcast_meta(NULL, buffer, len);
return true; return true;
} else } else {
return send_meta(c, buffer, len); return send_meta(c, buffer, len);
}
} }
void forward_request(connection_t *from) { void forward_request(connection_t *from) {
@ -110,12 +112,12 @@ void forward_request(connection_t *from) {
ifdebug(PROTOCOL) { ifdebug(PROTOCOL) {
sscanf(from->buffer, "%d", &request); sscanf(from->buffer, "%d", &request);
ifdebug(META) ifdebug(META)
logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s", logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s",
request_name[request], from->name, from->hostname, request_name[request], from->name, from->hostname,
from->buffer); from->buffer);
else else
logger(LOG_DEBUG, "Forwarding %s from %s (%s)", logger(LOG_DEBUG, "Forwarding %s from %s (%s)",
request_name[request], from->name, from->hostname); request_name[request], from->name, from->hostname);
} }
from->buffer[from->reqlen - 1] = '\n'; from->buffer[from->reqlen - 1] = '\n';
@ -129,28 +131,28 @@ bool receive_request(connection_t *c) {
if(sscanf(c->buffer, "%d", &request) == 1) { if(sscanf(c->buffer, "%d", &request) == 1) {
if((request < 0) || (request >= LAST) || !request_handlers[request]) { if((request < 0) || (request >= LAST) || !request_handlers[request]) {
ifdebug(META) ifdebug(META)
logger(LOG_DEBUG, "Unknown request from %s (%s): %s", logger(LOG_DEBUG, "Unknown request from %s (%s): %s",
c->name, c->hostname, c->buffer); c->name, c->hostname, c->buffer);
else else
logger(LOG_ERR, "Unknown request from %s (%s)", logger(LOG_ERR, "Unknown request from %s (%s)",
c->name, c->hostname); c->name, c->hostname);
return false; return false;
} else { } else {
ifdebug(PROTOCOL) { ifdebug(PROTOCOL) {
ifdebug(META) ifdebug(META)
logger(LOG_DEBUG, "Got %s from %s (%s): %s", logger(LOG_DEBUG, "Got %s from %s (%s): %s",
request_name[request], c->name, c->hostname, request_name[request], c->name, c->hostname,
c->buffer); c->buffer);
else else
logger(LOG_DEBUG, "Got %s from %s (%s)", logger(LOG_DEBUG, "Got %s from %s (%s)",
request_name[request], c->name, c->hostname); request_name[request], c->name, c->hostname);
} }
} }
if((c->allow_request != ALL) && (c->allow_request != request)) { if((c->allow_request != ALL) && (c->allow_request != request)) {
logger(LOG_ERR, "Unauthorized request from %s (%s)", c->name, logger(LOG_ERR, "Unauthorized request from %s (%s)", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -158,12 +160,12 @@ bool receive_request(connection_t *c) {
/* Something went wrong. Probably scriptkiddies. Terminate. */ /* Something went wrong. Probably scriptkiddies. Terminate. */
logger(LOG_ERR, "Error while processing %s from %s (%s)", logger(LOG_ERR, "Error while processing %s from %s (%s)",
request_name[request], c->name, c->hostname); request_name[request], c->name, c->hostname);
return false; return false;
} }
} else { } else {
logger(LOG_ERR, "Bogus data received from %s (%s)", logger(LOG_ERR, "Bogus data received from %s (%s)",
c->name, c->hostname); c->name, c->hostname);
return false; return false;
} }
@ -175,8 +177,9 @@ static int past_request_compare(const past_request_t *a, const past_request_t *b
} }
static void free_past_request(past_request_t *r) { static void free_past_request(past_request_t *r) {
if(r->request) if(r->request) {
free(r->request); free(r->request);
}
free(r); free(r);
} }
@ -190,7 +193,7 @@ void exit_requests(void) {
} }
bool seen_request(char *request) { bool seen_request(char *request) {
past_request_t *new, p = {NULL}; past_request_t *new, p = {};
p.request = request; p.request = request;
@ -215,13 +218,14 @@ void age_past_requests(void) {
next = node->next; next = node->next;
p = node->data; p = node->data;
if(p->firstseen + pinginterval <= now) if(p->firstseen + pinginterval <= now) {
avl_delete_node(past_request_tree, node), deleted++; avl_delete_node(past_request_tree, node), deleted++;
else } else {
left++; left++;
}
} }
if(left || deleted) if(left || deleted)
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Aging past requests: deleted %d, left %d", ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Aging past requests: deleted %d, left %d",
deleted, left); deleted, left);
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_PROTOCOL_H
#define TINC_PROTOCOL_H
/* /*
protocol.h -- header for protocol.c protocol.h -- header for protocol.c
Copyright (C) 1999-2005 Ivo Timmermans, Copyright (C) 1999-2005 Ivo Timmermans,
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_PROTOCOL_H__
#define __TINC_PROTOCOL_H__
/* Protocol version. Different versions are incompatible, /* Protocol version. Different versions are incompatible,
incompatible version have different protocols. incompatible version have different protocols.
*/ */
@ -37,7 +37,7 @@
typedef enum request_t { typedef enum request_t {
PROXY = -2, PROXY = -2,
ALL = -1, /* Guardian for allow_request */ ALL = -1, /* Guardian for allow_request */
ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK, ID = 0, METAKEY, CHALLENGE, CHAL_REPLY, ACK,
STATUS, ERROR, TERMREQ, STATUS, ERROR, TERMREQ,
PING, PONG, PING, PONG,
@ -45,7 +45,7 @@ typedef enum request_t {
ADD_EDGE, DEL_EDGE, ADD_EDGE, DEL_EDGE,
KEY_CHANGED, REQ_KEY, ANS_KEY, KEY_CHANGED, REQ_KEY, ANS_KEY,
PACKET, PACKET,
LAST /* Guardian for the highest request number */ LAST /* Guardian for the highest request number */
} request_t; } request_t;
typedef struct past_request_t { typedef struct past_request_t {
@ -71,56 +71,50 @@ extern bool strictsubnets;
/* Basic functions */ /* Basic functions */
extern bool send_request(struct connection_t *, const char *, ...) __attribute__ ((__format__(printf, 2, 3))); extern bool send_request(struct connection_t *c, const char *format, ...) __attribute__((__format__(printf, 2, 3)));
extern void forward_request(struct connection_t *); extern void forward_request(struct connection_t *c);
extern bool receive_request(struct connection_t *); extern bool receive_request(struct connection_t *c);
extern bool check_id(const char *); extern bool check_id(const char *name);
extern void init_requests(void); extern void init_requests(void);
extern void exit_requests(void); extern void exit_requests(void);
extern bool seen_request(char *); extern bool seen_request(char *request);
extern void age_past_requests(void); extern void age_past_requests(void);
/* Requests */ /* Requests */
extern bool send_id(struct connection_t *); extern bool send_id(struct connection_t *c);
extern bool send_metakey(struct connection_t *); extern bool send_metakey(struct connection_t *c);
extern bool send_challenge(struct connection_t *); extern bool send_challenge(struct connection_t *c);
extern bool send_chal_reply(struct connection_t *); extern bool send_chal_reply(struct connection_t *c);
extern bool send_ack(struct connection_t *); extern bool send_ack(struct connection_t *c);
extern bool send_status(struct connection_t *, int, const char *); extern bool send_ping(struct connection_t *c);
extern bool send_error(struct connection_t *, int,const char *); extern bool send_pong(struct connection_t *c);
extern bool send_termreq(struct connection_t *); extern bool send_add_subnet(struct connection_t *c, const struct subnet_t *subnet);
extern bool send_ping(struct connection_t *); extern bool send_del_subnet(struct connection_t *c, const struct subnet_t *subnet);
extern bool send_pong(struct connection_t *); extern bool send_add_edge(struct connection_t *c, const struct edge_t *e);
extern bool send_add_subnet(struct connection_t *, const struct subnet_t *); extern bool send_del_edge(struct connection_t *c, const struct edge_t *e);
extern bool send_del_subnet(struct connection_t *, const struct subnet_t *);
extern bool send_add_edge(struct connection_t *, const struct edge_t *);
extern bool send_del_edge(struct connection_t *, const struct edge_t *);
extern void send_key_changed(void); extern void send_key_changed(void);
extern bool send_req_key(struct node_t *); extern bool send_req_key(struct node_t *n);
extern bool send_ans_key(struct node_t *); extern bool send_ans_key(struct node_t *n);
extern bool send_tcppacket(struct connection_t *, const struct vpn_packet_t *); extern bool send_tcppacket(struct connection_t *c, const struct vpn_packet_t *packet);
/* Request handlers */ /* Request handlers */
extern bool id_h(struct connection_t *); extern bool id_h(struct connection_t *c);
extern bool metakey_h(struct connection_t *); extern bool metakey_h(struct connection_t *c);
extern bool challenge_h(struct connection_t *); extern bool challenge_h(struct connection_t *c);
extern bool chal_reply_h(struct connection_t *); extern bool chal_reply_h(struct connection_t *c);
extern bool ack_h(struct connection_t *); extern bool ack_h(struct connection_t *c);
extern bool status_h(struct connection_t *); extern bool ping_h(struct connection_t *c);
extern bool error_h(struct connection_t *); extern bool pong_h(struct connection_t *c);
extern bool termreq_h(struct connection_t *); extern bool add_subnet_h(struct connection_t *c);
extern bool ping_h(struct connection_t *); extern bool del_subnet_h(struct connection_t *c);
extern bool pong_h(struct connection_t *); extern bool add_edge_h(struct connection_t *c);
extern bool add_subnet_h(struct connection_t *); extern bool del_edge_h(struct connection_t *c);
extern bool del_subnet_h(struct connection_t *); extern bool key_changed_h(struct connection_t *c);
extern bool add_edge_h(struct connection_t *); extern bool req_key_h(struct connection_t *c);
extern bool del_edge_h(struct connection_t *); extern bool ans_key_h(struct connection_t *c);
extern bool key_changed_h(struct connection_t *); extern bool tcppacket_h(struct connection_t *c);
extern bool req_key_h(struct connection_t *);
extern bool ans_key_h(struct connection_t *);
extern bool tcppacket_h(struct connection_t *);
#endif /* __TINC_PROTOCOL_H__ */ #endif

View file

@ -41,11 +41,12 @@
#include "xalloc.h" #include "xalloc.h"
bool send_id(connection_t *c) { bool send_id(connection_t *c) {
if(proxytype && c->outgoing && !c->status.proxy_passed) if(proxytype && c->outgoing && !c->status.proxy_passed) {
return send_proxyrequest(c); return send_proxyrequest(c);
}
return send_request(c, "%d %s %d", ID, myself->connection->name, return send_request(c, "%d %s %d", ID, myself->connection->name,
myself->connection->protocol_version); myself->connection->protocol_version);
} }
bool id_h(connection_t *c) { bool id_h(connection_t *c) {
@ -53,7 +54,7 @@ bool id_h(connection_t *c) {
if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) { if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "ID", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "ID", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -61,7 +62,7 @@ bool id_h(connection_t *c) {
if(!check_id(name)) { if(!check_id(name)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name, logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name,
c->hostname, "invalid name"); c->hostname, "invalid name");
return false; return false;
} }
@ -70,12 +71,14 @@ bool id_h(connection_t *c) {
if(c->outgoing) { if(c->outgoing) {
if(strcmp(c->name, name)) { if(strcmp(c->name, name)) {
logger(LOG_ERR, "Peer %s is %s instead of %s", c->hostname, name, logger(LOG_ERR, "Peer %s is %s instead of %s", c->hostname, name,
c->name); c->name);
return false; return false;
} }
} else { } else {
if(c->name) if(c->name) {
free(c->name); free(c->name);
}
c->name = xstrdup(name); c->name = xstrdup(name);
} }
@ -83,13 +86,15 @@ bool id_h(connection_t *c) {
if(c->protocol_version != myself->connection->protocol_version) { if(c->protocol_version != myself->connection->protocol_version) {
logger(LOG_ERR, "Peer %s (%s) uses incompatible version %d", logger(LOG_ERR, "Peer %s (%s) uses incompatible version %d",
c->name, c->hostname, c->protocol_version); c->name, c->hostname, c->protocol_version);
return false; return false;
} }
if(bypass_security) { if(bypass_security) {
if(!c->config_tree) if(!c->config_tree) {
init_configuration(&c->config_tree); init_configuration(&c->config_tree);
}
c->allow_request = ACK; c->allow_request = ACK;
return send_ack(c); return send_ack(c);
} }
@ -99,7 +104,7 @@ bool id_h(connection_t *c) {
if(!read_connection_config(c)) { if(!read_connection_config(c)) {
logger(LOG_ERR, "Peer %s had unknown identity (%s)", c->hostname, logger(LOG_ERR, "Peer %s had unknown identity (%s)", c->hostname,
c->name); c->name);
return false; return false;
} }
} }
@ -141,13 +146,15 @@ bool send_metakey(connection_t *c) {
if(!c->outctx) { if(!c->outctx) {
c->outctx = EVP_CIPHER_CTX_new(); c->outctx = EVP_CIPHER_CTX_new();
if(!c->outctx)
if(!c->outctx) {
abort(); abort();
}
} }
/* Copy random data to the buffer */ /* Copy random data to the buffer */
if (1 != RAND_bytes((unsigned char *)c->outkey, len)) { if(1 != RAND_bytes((unsigned char *)c->outkey, len)) {
int err = ERR_get_error(); int err = ERR_get_error();
logger(LOG_ERR, "Failed to generate meta key (%s)", ERR_error_string(err, NULL)); logger(LOG_ERR, "Failed to generate meta key (%s)", ERR_error_string(err, NULL));
return false; return false;
@ -170,7 +177,7 @@ bool send_metakey(connection_t *c) {
bin2hex(c->outkey, buffer, len); bin2hex(c->outkey, buffer, len);
buffer[len * 2] = '\0'; buffer[len * 2] = '\0';
logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s", logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s",
buffer); buffer);
} }
/* Encrypt the random data /* Encrypt the random data
@ -182,7 +189,7 @@ bool send_metakey(connection_t *c) {
if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) { if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) {
logger(LOG_ERR, "Error during encryption of meta key for %s (%s): %s", logger(LOG_ERR, "Error during encryption of meta key for %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -194,19 +201,19 @@ bool send_metakey(connection_t *c) {
/* Send the meta key */ /* Send the meta key */
x = send_request(c, "%d %d %d %d %d %s", METAKEY, x = send_request(c, "%d %d %d %d %d %s", METAKEY,
c->outcipher ? EVP_CIPHER_nid(c->outcipher) : 0, c->outcipher ? EVP_CIPHER_nid(c->outcipher) : 0,
c->outdigest ? EVP_MD_type(c->outdigest) : 0, c->outmaclength, c->outdigest ? EVP_MD_type(c->outdigest) : 0, c->outmaclength,
c->outcompression, buffer); c->outcompression, buffer);
/* Further outgoing requests are encrypted with the key we just generated */ /* Further outgoing requests are encrypted with the key we just generated */
if(c->outcipher) { if(c->outcipher) {
if(!EVP_EncryptInit(c->outctx, c->outcipher, if(!EVP_EncryptInit(c->outctx, c->outcipher,
(unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher), (unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher),
(unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher) - (unsigned char *)c->outkey + len - EVP_CIPHER_key_length(c->outcipher) -
EVP_CIPHER_iv_length(c->outcipher))) { EVP_CIPHER_iv_length(c->outcipher))) {
logger(LOG_ERR, "Error during initialisation of cipher for %s (%s): %s", logger(LOG_ERR, "Error during initialisation of cipher for %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -224,7 +231,7 @@ bool metakey_h(connection_t *c) {
if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) { if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -232,7 +239,7 @@ bool metakey_h(connection_t *c) {
/* Check if the length of the meta key is all right */ /* Check if the length of the meta key is all right */
if(strlen(buffer) != len * 2) { if(strlen(buffer) != (size_t)len * 2) {
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength"); logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength");
return false; return false;
} }
@ -243,8 +250,10 @@ bool metakey_h(connection_t *c) {
if(!c->inctx) { if(!c->inctx) {
c->inctx = EVP_CIPHER_CTX_new(); c->inctx = EVP_CIPHER_CTX_new();
if(!c->inctx)
if(!c->inctx) {
abort(); abort();
}
} }
/* Convert the challenge from hexadecimal back to binary */ /* Convert the challenge from hexadecimal back to binary */
@ -256,9 +265,9 @@ bool metakey_h(connection_t *c) {
/* Decrypt the meta key */ /* Decrypt the meta key */
if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */ if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */
logger(LOG_ERR, "Error during decryption of meta key for %s (%s): %s", logger(LOG_ERR, "Error during decryption of meta key for %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -281,11 +290,11 @@ bool metakey_h(connection_t *c) {
} }
if(!EVP_DecryptInit(c->inctx, c->incipher, if(!EVP_DecryptInit(c->inctx, c->incipher,
(unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher), (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher),
(unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher) - (unsigned char *)c->inkey + len - EVP_CIPHER_key_length(c->incipher) -
EVP_CIPHER_iv_length(c->incipher))) { EVP_CIPHER_iv_length(c->incipher))) {
logger(LOG_ERR, "Error during initialisation of cipher from %s (%s): %s", logger(LOG_ERR, "Error during initialisation of cipher from %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -333,7 +342,7 @@ bool send_challenge(connection_t *c) {
/* Copy random data to the buffer */ /* Copy random data to the buffer */
if (1 != RAND_bytes((unsigned char *)c->hischallenge, len)) { if(1 != RAND_bytes((unsigned char *)c->hischallenge, len)) {
int err = ERR_get_error(); int err = ERR_get_error();
logger(LOG_ERR, "Failed to generate challenge (%s)", ERR_error_string(err, NULL)); logger(LOG_ERR, "Failed to generate challenge (%s)", ERR_error_string(err, NULL));
return false; // Do not send predictable challenges, let connection attempt fail. return false; // Do not send predictable challenges, let connection attempt fail.
@ -355,7 +364,7 @@ bool challenge_h(connection_t *c) {
if(sscanf(c->buffer, "%*d " MAX_STRING, buffer) != 1) { if(sscanf(c->buffer, "%*d " MAX_STRING, buffer) != 1) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -363,9 +372,9 @@ bool challenge_h(connection_t *c) {
/* Check if the length of the challenge is all right */ /* Check if the length of the challenge is all right */
if(strlen(buffer) != len * 2) { if(strlen(buffer) != (size_t)len * 2) {
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
c->hostname, "wrong challenge length"); c->hostname, "wrong challenge length");
return false; return false;
} }
@ -394,15 +403,17 @@ bool send_chal_reply(connection_t *c) {
/* Calculate the hash from the challenge we received */ /* Calculate the hash from the challenge we received */
ctx = EVP_MD_CTX_create(); ctx = EVP_MD_CTX_create();
if(!ctx)
if(!ctx) {
abort(); abort();
}
if(!EVP_DigestInit(ctx, c->indigest) if(!EVP_DigestInit(ctx, c->indigest)
|| !EVP_DigestUpdate(ctx, c->mychallenge, RSA_size(myself->connection->rsa_key)) || !EVP_DigestUpdate(ctx, c->mychallenge, RSA_size(myself->connection->rsa_key))
|| !EVP_DigestFinal(ctx, (unsigned char *)hash, NULL)) { || !EVP_DigestFinal(ctx, (unsigned char *)hash, NULL)) {
EVP_MD_CTX_destroy(ctx); EVP_MD_CTX_destroy(ctx);
logger(LOG_ERR, "Error during calculation of response for %s (%s): %s", logger(LOG_ERR, "Error during calculation of response for %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -425,15 +436,15 @@ bool chal_reply_h(connection_t *c) {
if(sscanf(c->buffer, "%*d " MAX_STRING, hishash) != 1) { if(sscanf(c->buffer, "%*d " MAX_STRING, hishash) != 1) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "CHAL_REPLY", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "CHAL_REPLY", c->name,
c->hostname); c->hostname);
return false; return false;
} }
/* Check if the length of the hash is all right */ /* Check if the length of the hash is all right */
if(strlen(hishash) != EVP_MD_size(c->outdigest) * 2) { if(strlen(hishash) != (size_t)EVP_MD_size(c->outdigest) * 2) {
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
c->hostname, "wrong challenge reply length"); c->hostname, "wrong challenge reply length");
return false; return false;
} }
@ -447,15 +458,17 @@ bool chal_reply_h(connection_t *c) {
/* Calculate the hash from the challenge we sent */ /* Calculate the hash from the challenge we sent */
ctx = EVP_MD_CTX_create(); ctx = EVP_MD_CTX_create();
if(!ctx)
if(!ctx) {
abort(); abort();
}
if(!EVP_DigestInit(ctx, c->outdigest) if(!EVP_DigestInit(ctx, c->outdigest)
|| !EVP_DigestUpdate(ctx, c->hischallenge, RSA_size(c->rsa_key)) || !EVP_DigestUpdate(ctx, c->hischallenge, RSA_size(c->rsa_key))
|| !EVP_DigestFinal(ctx, (unsigned char *)myhash, NULL)) { || !EVP_DigestFinal(ctx, (unsigned char *)myhash, NULL)) {
EVP_MD_CTX_destroy(ctx); EVP_MD_CTX_destroy(ctx);
logger(LOG_ERR, "Error during calculation of response from %s (%s): %s", logger(LOG_ERR, "Error during calculation of response from %s (%s): %s",
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
return false; return false;
} }
@ -465,7 +478,7 @@ bool chal_reply_h(connection_t *c) {
if(memcmp(hishash, myhash, EVP_MD_size(c->outdigest))) { if(memcmp(hishash, myhash, EVP_MD_size(c->outdigest))) {
logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
c->hostname, "wrong challenge reply"); c->hostname, "wrong challenge reply");
ifdebug(SCARY_THINGS) { ifdebug(SCARY_THINGS) {
bin2hex(myhash, hishash, SHA_DIGEST_LENGTH); bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
@ -499,19 +512,24 @@ bool send_ack(connection_t *c) {
/* Check some options */ /* Check some options */
if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &choice) && choice) || myself->options & OPTION_INDIRECT) if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &choice) && choice) || myself->options & OPTION_INDIRECT) {
c->options |= OPTION_INDIRECT; c->options |= OPTION_INDIRECT;
}
if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY) if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY) {
c->options |= OPTION_TCPONLY | OPTION_INDIRECT; c->options |= OPTION_TCPONLY | OPTION_INDIRECT;
}
if(myself->options & OPTION_PMTU_DISCOVERY) if(myself->options & OPTION_PMTU_DISCOVERY && !(c->options & OPTION_TCPONLY)) {
c->options |= OPTION_PMTU_DISCOVERY; c->options |= OPTION_PMTU_DISCOVERY;
}
choice = myself->options & OPTION_CLAMP_MSS; choice = myself->options & OPTION_CLAMP_MSS;
get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice); get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice);
if(choice)
if(choice) {
c->options |= OPTION_CLAMP_MSS; c->options |= OPTION_CLAMP_MSS;
}
get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight); get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight);
@ -559,7 +577,7 @@ bool ack_h(connection_t *c) {
if(sscanf(c->buffer, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) { if(sscanf(c->buffer, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -575,7 +593,7 @@ bool ack_h(connection_t *c) {
if(n->connection) { if(n->connection) {
/* Oh dear, we already have a connection to this node. */ /* Oh dear, we already have a connection to this node. */
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection", ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection",
n->name, n->hostname); n->name, n->hostname);
terminate_connection(n->connection, false); terminate_connection(n->connection, false);
/* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */ /* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
graph(); graph();
@ -584,23 +602,28 @@ bool ack_h(connection_t *c) {
n->connection = c; n->connection = c;
c->node = n; c->node = n;
if(!(c->options & options & OPTION_PMTU_DISCOVERY)) { if(!(c->options & options & OPTION_PMTU_DISCOVERY)) {
c->options &= ~OPTION_PMTU_DISCOVERY; c->options &= ~OPTION_PMTU_DISCOVERY;
options &= ~OPTION_PMTU_DISCOVERY; options &= ~OPTION_PMTU_DISCOVERY;
} }
c->options |= options; c->options |= options;
if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu) if(get_config_int(lookup_config(c->config_tree, "PMTU"), &mtu) && mtu < n->mtu) {
n->mtu = mtu; n->mtu = mtu;
}
if(get_config_int(lookup_config(config_tree, "PMTU"), &mtu) && mtu < n->mtu) if(get_config_int(lookup_config(config_tree, "PMTU"), &mtu) && mtu < n->mtu) {
n->mtu = mtu; n->mtu = mtu;
}
if(get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice)) { if(get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice)) {
if(choice) if(choice) {
c->options |= OPTION_CLAMP_MSS; c->options |= OPTION_CLAMP_MSS;
else } else {
c->options &= ~OPTION_CLAMP_MSS; c->options &= ~OPTION_CLAMP_MSS;
}
} }
/* Activate this connection */ /* Activate this connection */
@ -609,7 +632,7 @@ bool ack_h(connection_t *c) {
c->status.active = true; c->status.active = true;
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection with %s (%s) activated", c->name, ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection with %s (%s) activated", c->name,
c->hostname); c->hostname);
/* Send him everything we know */ /* Send him everything we know */
@ -630,10 +653,11 @@ bool ack_h(connection_t *c) {
/* Notify everyone of the new edge */ /* Notify everyone of the new edge */
if(tunnelserver) if(tunnelserver) {
send_add_edge(c, c->edge); send_add_edge(c, c->edge);
else } else {
send_add_edge(everyone, c->edge); send_add_edge(everyone, c->edge);
}
/* Run MST and SSSP algorithms */ /* Run MST and SSSP algorithms */

View file

@ -42,8 +42,8 @@ bool send_add_edge(connection_t *c, const edge_t *e) {
sockaddr2str(&e->address, &address, &port); sockaddr2str(&e->address, &address, &port);
x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(), x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(),
e->from->name, e->to->name, address, port, e->from->name, e->to->name, address, port,
e->options, e->weight); e->options, e->weight);
free(address); free(address);
free(port); free(port);
@ -62,9 +62,9 @@ bool add_edge_h(connection_t *c) {
int weight; int weight;
if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d", if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d",
from_name, to_name, to_address, to_port, &options, &weight) != 6) { from_name, to_name, to_address, to_port, &options, &weight) != 6) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -72,12 +72,13 @@ bool add_edge_h(connection_t *c) {
if(!check_id(from_name) || !check_id(to_name)) { if(!check_id(from_name) || !check_id(to_name)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
c->hostname, "invalid name"); c->hostname, "invalid name");
return false; return false;
} }
if(seen_request(c->buffer)) if(seen_request(c->buffer)) {
return true; return true;
}
/* Lookup nodes */ /* Lookup nodes */
@ -85,12 +86,12 @@ bool add_edge_h(connection_t *c) {
to = lookup_node(to_name); to = lookup_node(to_name);
if(tunnelserver && if(tunnelserver &&
from != myself && from != c->node && from != myself && from != c->node &&
to != myself && to != c->node) { to != myself && to != c->node) {
/* ignore indirect edge registrations for tunnelserver */ /* ignore indirect edge registrations for tunnelserver */
ifdebug(PROTOCOL) logger(LOG_WARNING, ifdebug(PROTOCOL) logger(LOG_WARNING,
"Ignoring indirect %s from %s (%s)", "Ignoring indirect %s from %s (%s)",
"ADD_EDGE", c->name, c->hostname); "ADD_EDGE", c->name, c->hostname);
return true; return true;
} }
@ -119,17 +120,19 @@ bool add_edge_h(connection_t *c) {
if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) { if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
if(from == myself) { if(from == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
"ADD_EDGE", c->name, c->hostname); "ADD_EDGE", c->name, c->hostname);
send_add_edge(c, e); send_add_edge(c, e);
return true; return true;
} else { } else {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not match existing entry", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not match existing entry",
"ADD_EDGE", c->name, c->hostname); "ADD_EDGE", c->name, c->hostname);
e->options = options; e->options = options;
if(sockaddrcmp(&e->address, &address)) { if(sockaddrcmp(&e->address, &address)) {
sockaddrfree(&e->address); sockaddrfree(&e->address);
e->address = address; e->address = address;
} }
if(e->weight != weight) { if(e->weight != weight) {
avl_node_t *node = avl_unlink(edge_weight_tree, e); avl_node_t *node = avl_unlink(edge_weight_tree, e);
e->weight = weight; e->weight = weight;
@ -138,11 +141,12 @@ bool add_edge_h(connection_t *c) {
goto done; goto done;
} }
} else } else {
return true; return true;
}
} else if(from == myself) { } else if(from == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist",
"ADD_EDGE", c->name, c->hostname); "ADD_EDGE", c->name, c->hostname);
contradicting_add_edge++; contradicting_add_edge++;
e = new_edge(); e = new_edge();
e->from = from; e->from = from;
@ -163,8 +167,9 @@ bool add_edge_h(connection_t *c) {
done: done:
/* Tell the rest about the new edge */ /* Tell the rest about the new edge */
if(!tunnelserver) if(!tunnelserver) {
forward_request(c); forward_request(c);
}
/* Run MST before or after we tell the rest? */ /* Run MST before or after we tell the rest? */
@ -175,7 +180,7 @@ done:
bool send_del_edge(connection_t *c, const edge_t *e) { bool send_del_edge(connection_t *c, const edge_t *e) {
return send_request(c, "%d %x %s %s", DEL_EDGE, rand(), return send_request(c, "%d %x %s %s", DEL_EDGE, rand(),
e->from->name, e->to->name); e->from->name, e->to->name);
} }
bool del_edge_h(connection_t *c) { bool del_edge_h(connection_t *c) {
@ -186,7 +191,7 @@ bool del_edge_h(connection_t *c) {
if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) { if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -194,12 +199,13 @@ bool del_edge_h(connection_t *c) {
if(!check_id(from_name) || !check_id(to_name)) { if(!check_id(from_name) || !check_id(to_name)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name,
c->hostname, "invalid name"); c->hostname, "invalid name");
return false; return false;
} }
if(seen_request(c->buffer)) if(seen_request(c->buffer)) {
return true; return true;
}
/* Lookup nodes */ /* Lookup nodes */
@ -207,24 +213,24 @@ bool del_edge_h(connection_t *c) {
to = lookup_node(to_name); to = lookup_node(to_name);
if(tunnelserver && if(tunnelserver &&
from != myself && from != c->node && from != myself && from != c->node &&
to != myself && to != c->node) { to != myself && to != c->node) {
/* ignore indirect edge registrations for tunnelserver */ /* ignore indirect edge registrations for tunnelserver */
ifdebug(PROTOCOL) logger(LOG_WARNING, ifdebug(PROTOCOL) logger(LOG_WARNING,
"Ignoring indirect %s from %s (%s)", "Ignoring indirect %s from %s (%s)",
"DEL_EDGE", c->name, c->hostname); "DEL_EDGE", c->name, c->hostname);
return true; return true;
} }
if(!from) { if(!from) {
ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree", ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree",
"DEL_EDGE", c->name, c->hostname); "DEL_EDGE", c->name, c->hostname);
return true; return true;
} }
if(!to) { if(!to) {
ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree", ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree",
"DEL_EDGE", c->name, c->hostname); "DEL_EDGE", c->name, c->hostname);
return true; return true;
} }
@ -234,22 +240,23 @@ bool del_edge_h(connection_t *c) {
if(!e) { if(!e) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not appear in the edge tree", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not appear in the edge tree",
"DEL_EDGE", c->name, c->hostname); "DEL_EDGE", c->name, c->hostname);
return true; return true;
} }
if(e->from == myself) { if(e->from == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
"DEL_EDGE", c->name, c->hostname); "DEL_EDGE", c->name, c->hostname);
contradicting_del_edge++; contradicting_del_edge++;
send_add_edge(c, e); /* Send back a correction */ send_add_edge(c, e); /* Send back a correction */
return true; return true;
} }
/* Tell the rest about the deleted edge */ /* Tell the rest about the deleted edge */
if(!tunnelserver) if(!tunnelserver) {
forward_request(c); forward_request(c);
}
/* Delete the edge */ /* Delete the edge */
@ -263,9 +270,12 @@ bool del_edge_h(connection_t *c) {
if(!to->status.reachable) { if(!to->status.reachable) {
e = lookup_edge(to, myself); e = lookup_edge(to, myself);
if(e) { if(e) {
if(!tunnelserver) if(!tunnelserver) {
send_del_edge(everyone, e); send_del_edge(everyone, e);
}
edge_del(e); edge_del(e);
} }
} }

View file

@ -46,8 +46,10 @@ void send_key_changed(void) {
for(node = connection_tree->head; node; node = node->next) { for(node = connection_tree->head; node; node = node->next) {
c = node->data; c = node->data;
if(c->status.active && c->node && c->node->status.reachable)
if(c->status.active && c->node && c->node->status.reachable) {
send_ans_key(c->node); send_ans_key(c->node);
}
} }
} }
@ -57,7 +59,7 @@ bool key_changed_h(connection_t *c) {
if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) { if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED", logger(LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED",
c->name, c->hostname); c->name, c->hostname);
return false; return false;
} }
@ -66,14 +68,15 @@ bool key_changed_h(connection_t *c) {
return false; return false;
} }
if(seen_request(c->buffer)) if(seen_request(c->buffer)) {
return true; return true;
}
n = lookup_node(name); n = lookup_node(name);
if(!n) { if(!n) {
logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist", logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist",
"KEY_CHANGED", c->name, c->hostname, name); "KEY_CHANGED", c->name, c->hostname, name);
return true; return true;
} }
@ -82,8 +85,9 @@ bool key_changed_h(connection_t *c) {
/* Tell the others */ /* Tell the others */
if(!tunnelserver) if(!tunnelserver) {
forward_request(c); forward_request(c);
}
return true; return true;
} }
@ -99,7 +103,7 @@ bool req_key_h(connection_t *c) {
if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) { if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -112,7 +116,7 @@ bool req_key_h(connection_t *c) {
if(!from) { if(!from) {
logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
"REQ_KEY", c->name, c->hostname, from_name); "REQ_KEY", c->name, c->hostname, from_name);
return true; return true;
} }
@ -120,22 +124,24 @@ bool req_key_h(connection_t *c) {
if(!to) { if(!to) {
logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
"REQ_KEY", c->name, c->hostname, to_name); "REQ_KEY", c->name, c->hostname, to_name);
return true; return true;
} }
/* Check if this key request is for us */ /* Check if this key request is for us */
if(to == myself) { /* Yes, send our own key back */ if(to == myself) { /* Yes, send our own key back */
if (!send_ans_key(from)) if(!send_ans_key(from)) {
return false; return false;
}
} else { } else {
if(tunnelserver) if(tunnelserver) {
return true; return true;
}
if(!to->status.reachable) { if(!to->status.reachable) {
logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable", logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
"REQ_KEY", c->name, c->hostname, to_name); "REQ_KEY", c->name, c->hostname, to_name);
return true; return true;
} }
@ -157,19 +163,23 @@ bool send_ans_key(node_t *to) {
to->inkey = xrealloc(to->inkey, to->inkeylength); to->inkey = xrealloc(to->inkey, to->inkeylength);
// Create a new key // Create a new key
if (1 != RAND_bytes((unsigned char *)to->inkey, to->inkeylength)) { if(1 != RAND_bytes((unsigned char *)to->inkey, to->inkeylength)) {
int err = ERR_get_error(); int err = ERR_get_error();
logger(LOG_ERR, "Failed to generate random for key (%s)", ERR_error_string(err, NULL)); logger(LOG_ERR, "Failed to generate random for key (%s)", ERR_error_string(err, NULL));
return false; // Do not send insecure keys, let connection attempt fail. return false; // Do not send insecure keys, let connection attempt fail.
} }
if(to->incipher) if(to->incipher) {
EVP_DecryptInit_ex(to->inctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + EVP_CIPHER_key_length(to->incipher)); EVP_DecryptInit_ex(to->inctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + EVP_CIPHER_key_length(to->incipher));
}
// Reset sequence number and late packet window // Reset sequence number and late packet window
mykeyused = true; mykeyused = true;
to->received_seqno = 0; to->received_seqno = 0;
if(replaywin) memset(to->late, 0, replaywin);
if(replaywin) {
memset(to->late, 0, replaywin);
}
// Convert to hexadecimal and send // Convert to hexadecimal and send
char key[2 * to->inkeylength + 1]; char key[2 * to->inkeylength + 1];
@ -177,10 +187,10 @@ bool send_ans_key(node_t *to) {
key[to->inkeylength * 2] = '\0'; key[to->inkeylength * 2] = '\0';
return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY, return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
myself->name, to->name, key, myself->name, to->name, key,
to->incipher ? EVP_CIPHER_nid(to->incipher) : 0, to->incipher ? EVP_CIPHER_nid(to->incipher) : 0,
to->indigest ? EVP_MD_type(to->indigest) : 0, to->inmaclength, to->indigest ? EVP_MD_type(to->indigest) : 0, to->inmaclength,
to->incompression); to->incompression);
} }
bool ans_key_h(connection_t *c) { bool ans_key_h(connection_t *c) {
@ -193,10 +203,10 @@ bool ans_key_h(connection_t *c) {
node_t *from, *to; node_t *from, *to;
if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING, if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
from_name, to_name, key, &cipher, &digest, &maclength, from_name, to_name, key, &cipher, &digest, &maclength,
&compression, address, port) < 7) { &compression, address, port) < 7) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -209,7 +219,7 @@ bool ans_key_h(connection_t *c) {
if(!from) { if(!from) {
logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
"ANS_KEY", c->name, c->hostname, from_name); "ANS_KEY", c->name, c->hostname, from_name);
return true; return true;
} }
@ -217,19 +227,20 @@ bool ans_key_h(connection_t *c) {
if(!to) { if(!to) {
logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
"ANS_KEY", c->name, c->hostname, to_name); "ANS_KEY", c->name, c->hostname, to_name);
return true; return true;
} }
/* Forward it if necessary */ /* Forward it if necessary */
if(to != myself) { if(to != myself) {
if(tunnelserver) if(tunnelserver) {
return true; return true;
}
if(!to->status.reachable) { if(!to->status.reachable) {
logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable", logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
"ANS_KEY", c->name, c->hostname, to_name); "ANS_KEY", c->name, c->hostname, to_name);
return true; return true;
} }
@ -252,6 +263,7 @@ bool ans_key_h(connection_t *c) {
/* Update our copy of the origin's packet key */ /* Update our copy of the origin's packet key */
from->outkey = xrealloc(from->outkey, strlen(key) / 2); from->outkey = xrealloc(from->outkey, strlen(key) / 2);
from->outkeylength = strlen(key) / 2; from->outkeylength = strlen(key) / 2;
if(!hex2bin(key, from->outkey, from->outkeylength)) { if(!hex2bin(key, from->outkey, from->outkeylength)) {
logger(LOG_ERR, "Got bad %s from %s(%s): %s", "ANS_KEY", from->name, from->hostname, "invalid key"); logger(LOG_ERR, "Got bad %s from %s(%s): %s", "ANS_KEY", from->name, from->hostname, "invalid key");
return true; return true;
@ -264,13 +276,13 @@ bool ans_key_h(connection_t *c) {
if(!from->outcipher) { if(!from->outcipher) {
logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name,
from->hostname); from->hostname);
return true; return true;
} }
if(from->outkeylength != EVP_CIPHER_key_length(from->outcipher) + EVP_CIPHER_iv_length(from->outcipher)) { if(from->outkeylength != EVP_CIPHER_key_length(from->outcipher) + EVP_CIPHER_iv_length(from->outcipher)) {
logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name,
from->hostname); from->hostname);
return true; return true;
} }
} else { } else {
@ -284,13 +296,13 @@ bool ans_key_h(connection_t *c) {
if(!from->outdigest) { if(!from->outdigest) {
logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name,
from->hostname); from->hostname);
return true; return true;
} }
if(from->outmaclength > EVP_MD_size(from->outdigest) || from->outmaclength < 0) { if(from->outmaclength > EVP_MD_size(from->outdigest) || from->outmaclength < 0) {
logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!", logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!",
from->name, from->hostname); from->name, from->hostname);
return true; return true;
} }
} else { } else {
@ -307,7 +319,7 @@ bool ans_key_h(connection_t *c) {
if(from->outcipher) if(from->outcipher)
if(!EVP_EncryptInit_ex(from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + EVP_CIPHER_key_length(from->outcipher))) { if(!EVP_EncryptInit_ex(from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + EVP_CIPHER_key_length(from->outcipher))) {
logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s", logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s",
from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL)); from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL));
return true; return true;
} }
@ -320,8 +332,9 @@ bool ans_key_h(connection_t *c) {
update_node_udp(from, &sa); update_node_udp(from, &sa);
} }
if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuevent) if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuevent) {
send_mtu_probe(from); send_mtu_probe(from);
}
return true; return true;
} }

View file

@ -31,66 +31,6 @@
int maxoutbufsize = 0; int maxoutbufsize = 0;
/* Status and error notification routines */
bool send_status(connection_t *c, int statusno, const char *statusstring) {
if(!statusstring)
statusstring = "Status";
return send_request(c, "%d %d %s", STATUS, statusno, statusstring);
}
bool status_h(connection_t *c) {
int statusno;
char statusstring[MAX_STRING_SIZE];
if(sscanf(c->buffer, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "STATUS",
c->name, c->hostname);
return false;
}
ifdebug(STATUS) logger(LOG_NOTICE, "Status message from %s (%s): %d: %s",
c->name, c->hostname, statusno, statusstring);
return true;
}
bool send_error(connection_t *c, int err, const char *errstring) {
if(!errstring)
errstring = "Error";
return send_request(c, "%d %d %s", ERROR, err, errstring);
}
bool error_h(connection_t *c) {
int err;
char errorstring[MAX_STRING_SIZE];
if(sscanf(c->buffer, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "ERROR",
c->name, c->hostname);
return false;
}
ifdebug(ERROR) logger(LOG_NOTICE, "Error message from %s (%s): %d: %s",
c->name, c->hostname, err, errorstring);
terminate_connection(c, c->status.active);
return true;
}
bool send_termreq(connection_t *c) {
return send_request(c, "%d", TERMREQ);
}
bool termreq_h(connection_t *c) {
terminate_connection(c, c->status.active);
return true;
}
bool send_ping(connection_t *c) { bool send_ping(connection_t *c) {
c->status.pinged = true; c->status.pinged = true;
c->last_ping_time = now; c->last_ping_time = now;
@ -114,8 +54,11 @@ bool pong_h(connection_t *c) {
if(c->outgoing) { if(c->outgoing) {
c->outgoing->timeout = 0; c->outgoing->timeout = 0;
c->outgoing->cfg = NULL; c->outgoing->cfg = NULL;
if(c->outgoing->ai)
if(c->outgoing->ai) {
freeaddrinfo(c->outgoing->ai); freeaddrinfo(c->outgoing->ai);
}
c->outgoing->ai = NULL; c->outgoing->ai = NULL;
c->outgoing->aip = NULL; c->outgoing->aip = NULL;
} }
@ -127,23 +70,25 @@ bool pong_h(connection_t *c) {
bool send_tcppacket(connection_t *c, const vpn_packet_t *packet) { bool send_tcppacket(connection_t *c, const vpn_packet_t *packet) {
/* If there already is a lot of data in the outbuf buffer, discard this packet. /* If there already is a lot of data in the outbuf buffer, discard this packet.
We use a very simple Random Early Drop algorithm. */ We use a very simple Random Early Drop algorithm. */
if(2.0 * c->outbuflen / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX) if(2.0 * c->outbuflen / (float)maxoutbufsize - 1 > (float)rand() / (float)RAND_MAX) {
return true; return true;
}
if(!send_request(c, "%d %hd", PACKET, packet->len)) if(!send_request(c, "%d %hd", PACKET, packet->len)) {
return false; return false;
}
return send_meta(c, (char *)packet->data, packet->len) && flush_meta(c); return send_meta(c, (char *)packet->data, packet->len) && flush_meta(c);
} }
bool tcppacket_h(connection_t *c) { bool tcppacket_h(connection_t *c) {
short int len; length_t len;
if(sscanf(c->buffer, "%*d %hd", &len) != 1) { if(sscanf(c->buffer, "%*d %hu", &len) != 1) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name,
c->hostname); c->hostname);
return false; return false;
} }

View file

@ -35,8 +35,9 @@
bool send_add_subnet(connection_t *c, const subnet_t *subnet) { bool send_add_subnet(connection_t *c, const subnet_t *subnet) {
char netstr[MAXNETSTR]; char netstr[MAXNETSTR];
if(!net2str(netstr, sizeof netstr, subnet)) if(!net2str(netstr, sizeof(netstr), subnet)) {
return false; return false;
}
return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr); return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr);
} }
@ -45,11 +46,11 @@ bool add_subnet_h(connection_t *c) {
char subnetstr[MAX_STRING_SIZE]; char subnetstr[MAX_STRING_SIZE];
char name[MAX_STRING_SIZE]; char name[MAX_STRING_SIZE];
node_t *owner; node_t *owner;
subnet_t s = {NULL}, *new, *old; subnet_t s = {}, *new, *old;
if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -57,7 +58,7 @@ bool add_subnet_h(connection_t *c) {
if(!check_id(name)) { if(!check_id(name)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name, logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name,
c->hostname, "invalid name"); c->hostname, "invalid name");
return false; return false;
} }
@ -65,12 +66,13 @@ bool add_subnet_h(connection_t *c) {
if(!str2net(&s, subnetstr)) { if(!str2net(&s, subnetstr)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name, logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name,
c->hostname, "invalid subnet string"); c->hostname, "invalid subnet string");
return false; return false;
} }
if(seen_request(c->buffer)) if(seen_request(c->buffer)) {
return true; return true;
}
/* Check if the owner of the new subnet is in the connection list */ /* Check if the owner of the new subnet is in the connection list */
@ -79,7 +81,7 @@ bool add_subnet_h(connection_t *c) {
if(tunnelserver && owner != myself && owner != c->node) { if(tunnelserver && owner != myself && owner != c->node) {
/* in case of tunnelserver, ignore indirect subnet registrations */ /* in case of tunnelserver, ignore indirect subnet registrations */
ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s", ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s",
"ADD_SUBNET", c->name, c->hostname, subnetstr); "ADD_SUBNET", c->name, c->hostname, subnetstr);
return true; return true;
} }
@ -91,14 +93,15 @@ bool add_subnet_h(connection_t *c) {
/* Check if we already know this subnet */ /* Check if we already know this subnet */
if(lookup_subnet(owner, &s)) if(lookup_subnet(owner, &s)) {
return true; return true;
}
/* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */ /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */
if(owner == myself) { if(owner == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
"ADD_SUBNET", c->name, c->hostname); "ADD_SUBNET", c->name, c->hostname);
s.owner = myself; s.owner = myself;
send_del_subnet(c, &s); send_del_subnet(c, &s);
return true; return true;
@ -108,7 +111,7 @@ bool add_subnet_h(connection_t *c) {
if(tunnelserver) { if(tunnelserver) {
logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s", logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s",
"ADD_SUBNET", c->name, c->hostname, subnetstr); "ADD_SUBNET", c->name, c->hostname, subnetstr);
return true; return true;
} }
@ -116,7 +119,7 @@ bool add_subnet_h(connection_t *c) {
if(strictsubnets) { if(strictsubnets) {
logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s", logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s",
"ADD_SUBNET", c->name, c->hostname, subnetstr); "ADD_SUBNET", c->name, c->hostname, subnetstr);
forward_request(c); forward_request(c);
return true; return true;
} }
@ -126,8 +129,9 @@ bool add_subnet_h(connection_t *c) {
*(new = new_subnet()) = s; *(new = new_subnet()) = s;
subnet_add(owner, new); subnet_add(owner, new);
if(owner->status.reachable) if(owner->status.reachable) {
subnet_update(owner, new, true); subnet_update(owner, new, true);
}
/* Tell the rest */ /* Tell the rest */
@ -135,8 +139,9 @@ bool add_subnet_h(connection_t *c) {
/* Fast handoff of roaming MAC addresses */ /* Fast handoff of roaming MAC addresses */
if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires) if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires) {
old->expires = now; old->expires = now;
}
return true; return true;
} }
@ -144,8 +149,9 @@ bool add_subnet_h(connection_t *c) {
bool send_del_subnet(connection_t *c, const subnet_t *s) { bool send_del_subnet(connection_t *c, const subnet_t *s) {
char netstr[MAXNETSTR]; char netstr[MAXNETSTR];
if(!net2str(netstr, sizeof netstr, s)) if(!net2str(netstr, sizeof(netstr), s)) {
return false; return false;
}
return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr); return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr);
} }
@ -154,11 +160,11 @@ bool del_subnet_h(connection_t *c) {
char subnetstr[MAX_STRING_SIZE]; char subnetstr[MAX_STRING_SIZE];
char name[MAX_STRING_SIZE]; char name[MAX_STRING_SIZE];
node_t *owner; node_t *owner;
subnet_t s = {NULL}, *find; subnet_t s = {}, *find;
if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_SUBNET", c->name, logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_SUBNET", c->name,
c->hostname); c->hostname);
return false; return false;
} }
@ -166,7 +172,7 @@ bool del_subnet_h(connection_t *c) {
if(!check_id(name)) { if(!check_id(name)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name, logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name,
c->hostname, "invalid name"); c->hostname, "invalid name");
return false; return false;
} }
@ -174,12 +180,13 @@ bool del_subnet_h(connection_t *c) {
if(!str2net(&s, subnetstr)) { if(!str2net(&s, subnetstr)) {
logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name, logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name,
c->hostname, "invalid subnet string"); c->hostname, "invalid subnet string");
return false; return false;
} }
if(seen_request(c->buffer)) if(seen_request(c->buffer)) {
return true; return true;
}
/* Check if the owner of the subnet being deleted is in the connection list */ /* Check if the owner of the subnet being deleted is in the connection list */
@ -188,13 +195,13 @@ bool del_subnet_h(connection_t *c) {
if(tunnelserver && owner != myself && owner != c->node) { if(tunnelserver && owner != myself && owner != c->node) {
/* in case of tunnelserver, ignore indirect subnet deletion */ /* in case of tunnelserver, ignore indirect subnet deletion */
ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s", ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s",
"DEL_SUBNET", c->name, c->hostname, subnetstr); "DEL_SUBNET", c->name, c->hostname, subnetstr);
return true; return true;
} }
if(!owner) { if(!owner) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which is not in our node tree", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which is not in our node tree",
"DEL_SUBNET", c->name, c->hostname, name); "DEL_SUBNET", c->name, c->hostname, name);
return true; return true;
} }
@ -206,9 +213,12 @@ bool del_subnet_h(connection_t *c) {
if(!find) { if(!find) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which does not appear in his subnet tree", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which does not appear in his subnet tree",
"DEL_SUBNET", c->name, c->hostname, name); "DEL_SUBNET", c->name, c->hostname, name);
if(strictsubnets)
if(strictsubnets) {
forward_request(c); forward_request(c);
}
return true; return true;
} }
@ -216,24 +226,28 @@ bool del_subnet_h(connection_t *c) {
if(owner == myself) { if(owner == myself) {
ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself", ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
"DEL_SUBNET", c->name, c->hostname); "DEL_SUBNET", c->name, c->hostname);
send_add_subnet(c, find); send_add_subnet(c, find);
return true; return true;
} }
if(tunnelserver) if(tunnelserver) {
return true; return true;
}
/* Tell the rest */ /* Tell the rest */
forward_request(c); forward_request(c);
if(strictsubnets)
if(strictsubnets) {
return true; return true;
}
/* Finally, delete it. */ /* Finally, delete it. */
if(owner->status.reachable) if(owner->status.reachable) {
subnet_update(owner, find, false); subnet_update(owner, find, false);
}
subnet_del(owner, find); subnet_del(owner, find);

View file

@ -35,28 +35,40 @@ char *proxypass;
static void update_address_ipv4(connection_t *c, void *address, void *port) { static void update_address_ipv4(connection_t *c, void *address, void *port) {
sockaddrfree(&c->address); sockaddrfree(&c->address);
memset(&c->address, 0, sizeof c->address); memset(&c->address, 0, sizeof(c->address));
c->address.sa.sa_family = AF_INET; c->address.sa.sa_family = AF_INET;
if(address)
if(address) {
memcpy(&c->address.in.sin_addr, address, sizeof(ipv4_t)); memcpy(&c->address.in.sin_addr, address, sizeof(ipv4_t));
if(port) }
if(port) {
memcpy(&c->address.in.sin_port, port, sizeof(uint16_t)); memcpy(&c->address.in.sin_port, port, sizeof(uint16_t));
}
// OpenSSH -D returns all zero address, set it to 0.0.0.1 to prevent spamming ourselves. // OpenSSH -D returns all zero address, set it to 0.0.0.1 to prevent spamming ourselves.
if(!memcmp(&c->address.in.sin_addr, "\0\0\0\0", 4)) if(!memcmp(&c->address.in.sin_addr, "\0\0\0\0", 4)) {
memcpy(&c->address.in.sin_addr, "\0\0\0\01", 4); memcpy(&c->address.in.sin_addr, "\0\0\0\01", 4);
}
} }
static void update_address_ipv6(connection_t *c, void *address, void *port) { static void update_address_ipv6(connection_t *c, void *address, void *port) {
sockaddrfree(&c->address); sockaddrfree(&c->address);
memset(&c->address, 0, sizeof c->address); memset(&c->address, 0, sizeof(c->address));
c->address.sa.sa_family = AF_INET6; c->address.sa.sa_family = AF_INET6;
if(address)
if(address) {
memcpy(&c->address.in6.sin6_addr, address, sizeof(ipv6_t)); memcpy(&c->address.in6.sin6_addr, address, sizeof(ipv6_t));
if(port) }
if(port) {
memcpy(&c->address.in6.sin6_port, port, sizeof(uint16_t)); memcpy(&c->address.in6.sin6_port, port, sizeof(uint16_t));
}
// OpenSSH -D returns all zero address, set it to 0100:: to prevent spamming ourselves. // OpenSSH -D returns all zero address, set it to 0100:: to prevent spamming ourselves.
if(!memcmp(&c->address.in6.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) if(!memcmp(&c->address.in6.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) {
memcpy(&c->address.in6.sin6_addr, "\01\0\0\0\0\0\0\0", 8); memcpy(&c->address.in6.sin6_addr, "\01\0\0\0\0\0\0\0", 8);
}
} }
bool send_proxyrequest(connection_t *c) { bool send_proxyrequest(connection_t *c) {
@ -66,19 +78,28 @@ bool send_proxyrequest(connection_t *c) {
logger(LOG_ERR, "Can only connect to numeric IPv4 addresses through a SOCKS 4 proxy!"); logger(LOG_ERR, "Can only connect to numeric IPv4 addresses through a SOCKS 4 proxy!");
return false; return false;
} }
// fallthrough
case PROXY_SOCKS4A: { case PROXY_SOCKS4A: {
if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) { if(c->address.sa.sa_family != AF_INET && c->address.sa.sa_family != AF_UNKNOWN) {
logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!"); logger(LOG_ERR, "Can only connect to IPv4 addresses or hostnames through a SOCKS 4a proxy!");
return false; return false;
} }
int len = 9; int len = 9;
if(proxyuser)
if(proxyuser) {
len += strlen(proxyuser); len += strlen(proxyuser);
if(c->address.sa.sa_family == AF_UNKNOWN) }
if(c->address.sa.sa_family == AF_UNKNOWN) {
len += 1 + strlen(c->address.unknown.address); len += 1 + strlen(c->address.unknown.address);
}
char s4req[len]; char s4req[len];
s4req[0] = 4; s4req[0] = 4;
s4req[1] = 1; s4req[1] = 1;
if(c->address.sa.sa_family == AF_INET) { if(c->address.sa.sa_family == AF_INET) {
memcpy(s4req + 2, &c->address.in.sin_port, 2); memcpy(s4req + 2, &c->address.in.sin_port, 2);
memcpy(s4req + 4, &c->address.in.sin_addr, 4); memcpy(s4req + 4, &c->address.in.sin_addr, 4);
@ -88,17 +109,21 @@ bool send_proxyrequest(connection_t *c) {
memcpy(s4req + 4, "\0\0\0\1", 4); memcpy(s4req + 4, "\0\0\0\1", 4);
strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address); strcpy(s4req + (9 + (proxyuser ? strlen(proxyuser) : 0)), c->address.unknown.address);
} }
if(proxyuser)
if(proxyuser) {
strcpy(s4req + 8, proxyuser); strcpy(s4req + 8, proxyuser);
else } else {
s4req[8] = 0; s4req[8] = 0;
s4req[sizeof s4req - 1] = 0; }
s4req[sizeof(s4req) - 1] = 0;
c->allow_request = PROXY; c->allow_request = PROXY;
return send_meta(c, s4req, sizeof s4req); return send_meta(c, s4req, sizeof(s4req));
} }
case PROXY_SOCKS5: { case PROXY_SOCKS5: {
int len = 3 + 6; int len = 3 + 6;
if(c->address.sa.sa_family == AF_INET) { if(c->address.sa.sa_family == AF_INET) {
len += 4; len += 4;
} else if(c->address.sa.sa_family == AF_INET6) { } else if(c->address.sa.sa_family == AF_INET6) {
@ -109,12 +134,16 @@ bool send_proxyrequest(connection_t *c) {
logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family); logger(LOG_ERR, "Address family %x not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
return false; return false;
} }
if(proxypass)
if(proxypass) {
len += 3 + strlen(proxyuser) + strlen(proxypass); len += 3 + strlen(proxyuser) + strlen(proxypass);
}
char s5req[len]; char s5req[len];
int i = 0; int i = 0;
s5req[i++] = 5; s5req[i++] = 5;
s5req[i++] = 1; s5req[i++] = 1;
if(proxypass) { if(proxypass) {
s5req[i++] = 2; s5req[i++] = 2;
s5req[i++] = 1; s5req[i++] = 1;
@ -127,9 +156,11 @@ bool send_proxyrequest(connection_t *c) {
} else { } else {
s5req[i++] = 0; s5req[i++] = 0;
} }
s5req[i++] = 5; s5req[i++] = 5;
s5req[i++] = 1; s5req[i++] = 1;
s5req[i++] = 0; s5req[i++] = 0;
if(c->address.sa.sa_family == AF_INET) { if(c->address.sa.sa_family == AF_INET) {
s5req[i++] = 1; s5req[i++] = 1;
memcpy(s5req + i, &c->address.in.sin_addr, 4); memcpy(s5req + i, &c->address.in.sin_addr, 4);
@ -155,10 +186,13 @@ bool send_proxyrequest(connection_t *c) {
logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy"); logger(LOG_ERR, "Unknown address family while trying to connect to SOCKS5 proxy");
return false; return false;
} }
if(i > len)
if(i > len) {
abort(); abort();
}
c->allow_request = PROXY; c->allow_request = PROXY;
return send_meta(c, s5req, sizeof s5req); return send_meta(c, s5req, sizeof(s5req));
} }
case PROXY_HTTP: { case PROXY_HTTP: {
@ -182,15 +216,18 @@ bool send_proxyrequest(connection_t *c) {
} }
} }
int receive_proxy_meta(connection_t *c, int start, int lenin) { int receive_proxy_meta(connection_t *c) {
switch(proxytype) { switch(proxytype) {
case PROXY_SOCKS4: case PROXY_SOCKS4:
case PROXY_SOCKS4A: case PROXY_SOCKS4A:
if(c->buflen < 8) if(c->buflen < 8) {
return 0; return 0;
}
if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) { if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
if(c->address.sa.sa_family == AF_UNKNOWN) if(c->address.sa.sa_family == AF_UNKNOWN) {
update_address_ipv4(c, c->buffer + 4, c->buffer + 2); update_address_ipv4(c, c->buffer + 4, c->buffer + 2);
}
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted"); ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Proxy request granted");
c->allow_request = ID; c->allow_request = ID;
@ -203,49 +240,71 @@ int receive_proxy_meta(connection_t *c, int start, int lenin) {
} }
case PROXY_SOCKS5: case PROXY_SOCKS5:
if(c->buflen < 2) if(c->buflen < 2) {
return 0; return 0;
}
if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) { if(c->buffer[0] != 0x05 || c->buffer[1] == (char)0xff) {
logger(LOG_ERR, "Proxy authentication method rejected"); logger(LOG_ERR, "Proxy authentication method rejected");
return -1; return -1;
} }
int offset = 2; int offset = 2;
if(c->buffer[1] == 0x02) { if(c->buffer[1] == 0x02) {
if(c->buflen < 4) if(c->buflen < 4) {
return 0; return 0;
}
if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) { if(c->buffer[2] != 0x05 || c->buffer[3] != 0x00) {
logger(LOG_ERR, "Proxy username/password rejected"); logger(LOG_ERR, "Proxy username/password rejected");
return -1; return -1;
} }
offset += 2; offset += 2;
} }
if(c->buflen - offset < 7)
if(c->buflen - offset < 7) {
return 0; return 0;
}
if(c->buffer[offset] != 0x05 || c->buffer[offset + 1] != 0x00) { if(c->buffer[offset] != 0x05 || c->buffer[offset + 1] != 0x00) {
logger(LOG_ERR, "Proxy request rejected"); logger(LOG_ERR, "Proxy request rejected");
return -1; return -1;
} }
int replen = offset + 6; int replen = offset + 6;
switch(c->buffer[offset + 3]) { switch(c->buffer[offset + 3]) {
case 0x01: // IPv4 case 0x01: // IPv4
if(c->address.sa.sa_family == AF_UNKNOWN) if(c->address.sa.sa_family == AF_UNKNOWN) {
update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8); update_address_ipv4(c, c->buffer + offset + 4, c->buffer + offset + 8);
replen += 4; }
break;
case 0x03: // Hostname replen += 4;
if(c->address.sa.sa_family == AF_UNKNOWN) break;
update_address_ipv4(c, "\0\0\0\1", "\0\0");
replen += ((uint8_t *)c->buffer)[offset + 4]; case 0x03: // Hostname
break; if(c->address.sa.sa_family == AF_UNKNOWN) {
case 0x04: // IPv6 update_address_ipv4(c, "\0\0\0\1", "\0\0");
if(c->address.sa.sa_family == AF_UNKNOWN) }
update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
replen += 16; replen += ((uint8_t *)c->buffer)[offset + 4];
break; break;
default:
logger(LOG_ERR, "Proxy reply malformed"); case 0x04: // IPv6
return -1; if(c->address.sa.sa_family == AF_UNKNOWN) {
update_address_ipv6(c, c->buffer + offset + 4, c->buffer + offset + 20);
}
replen += 16;
break;
default:
logger(LOG_ERR, "Proxy reply malformed");
return -1;
} }
if(c->buflen < replen) { if(c->buflen < replen) {
return 0; return 0;
} else { } else {
@ -258,24 +317,31 @@ int receive_proxy_meta(connection_t *c, int start, int lenin) {
case PROXY_HTTP: { case PROXY_HTTP: {
char *p = memchr(c->buffer, '\n', c->buflen); char *p = memchr(c->buffer, '\n', c->buflen);
if(!p || p - c->buffer >= c->buflen)
return 0;
while((p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer)))) { if(!p || p - c->buffer >= c->buflen) {
if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4)) return 0;
break;
} }
if(!p) while((p = memchr(p + 1, '\n', c->buflen - (p + 1 - c->buffer)))) {
return 0; if(p > c->buffer + 3 && !memcmp(p - 3, "\r\n\r\n", 4)) {
break;
}
}
if(c->buflen < 9) if(!p) {
return 0; return 0;
}
if(c->buflen < 9) {
return 0;
}
if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) { if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
if(!strncmp(c->buffer + 9, "200", 3)) { if(!strncmp(c->buffer + 9, "200", 3)) {
if(c->address.sa.sa_family == AF_UNKNOWN) if(c->address.sa.sa_family == AF_UNKNOWN) {
update_address_ipv4(c, "\0\0\0\1", "\0\0"); update_address_ipv4(c, "\0\0\0\1", "\0\0");
}
logger(LOG_DEBUG, "Proxy request granted"); logger(LOG_DEBUG, "Proxy request granted");
replen = p + 1 - c->buffer; replen = p + 1 - c->buffer;
c->allow_request = ID; c->allow_request = ID;

View file

@ -1,3 +1,6 @@
#ifndef TINC_PROXY_H
#define TINC_PROXY_H
/* /*
proxy.h -- header for proxy.c proxy.h -- header for proxy.c
Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org> Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org>
@ -17,9 +20,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_PROXY_H__
#define __TINC_PROXY_H__
#include "connection.h" #include "connection.h"
typedef enum proxytype_t { typedef enum proxytype_t {
@ -38,6 +38,6 @@ extern char *proxyuser;
extern char *proxypass; extern char *proxypass;
extern bool send_proxyrequest(struct connection_t *c); extern bool send_proxyrequest(struct connection_t *c);
extern int receive_proxy_meta(struct connection_t *c, int start, int lenin); extern int receive_proxy_meta(struct connection_t *c);
#endif #endif

View file

@ -33,7 +33,7 @@
#include "xalloc.h" #include "xalloc.h"
#if defined(PF_PACKET) && defined(ETH_P_ALL) && defined(AF_PACKET) && defined(SIOCGIFINDEX) #if defined(PF_PACKET) && defined(ETH_P_ALL) && defined(AF_PACKET) && defined(SIOCGIFINDEX)
static char *device_info; static const char *device_info = "raw_socket";
static uint64_t device_total_in = 0; static uint64_t device_total_in = 0;
static uint64_t device_total_out = 0; static uint64_t device_total_out = 0;
@ -42,17 +42,17 @@ static bool setup_device(void) {
struct ifreq ifr; struct ifreq ifr;
struct sockaddr_ll sa; struct sockaddr_ll sa;
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) {
iface = xstrdup("eth0"); iface = xstrdup("eth0");
}
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
device = xstrdup(iface); device = xstrdup(iface);
}
device_info = "raw socket";
if((device_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { if((device_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
logger(LOG_ERR, "Could not open %s: %s", device_info, logger(LOG_ERR, "Could not open %s: %s", device_info,
strerror(errno)); strerror(errno));
return false; return false;
} }
@ -97,7 +97,7 @@ static bool read_packet(vpn_packet_t *packet) {
if((lenin = read(device_fd, packet->data, MTU)) <= 0) { if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
device, strerror(errno)); device, strerror(errno));
return false; return false;
} }
@ -106,18 +106,18 @@ static bool read_packet(vpn_packet_t *packet) {
device_total_in += packet->len; device_total_in += packet->len;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
device_info); device_info);
return true; return true;
} }
static bool write_packet(vpn_packet_t *packet) { static bool write_packet(vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
packet->len, device_info); packet->len, device_info);
if(write(device_fd, packet->data, packet->len) < 0) { if(write(device_fd, packet->data, packet->len) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
strerror(errno)); strerror(errno));
return false; return false;
} }

View file

@ -2,7 +2,7 @@
route.c -- routing route.c -- routing
Copyright (C) 2000-2005 Ivo Timmermans, Copyright (C) 2000-2005 Ivo Timmermans,
2000-2017 Guus Sliepen <guus@tinc-vpn.org> 2000-2017 Guus Sliepen <guus@tinc-vpn.org>
2015-2016 Vittorio Gambaletta 2015-2016 Vittorio Gambaletta
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -69,11 +69,13 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
len -= 2; len -= 2;
} }
if(len) if(len) {
checksum += *(uint8_t *)p; checksum += *(uint8_t *)p;
}
while(checksum >> 16) while(checksum >> 16) {
checksum = (checksum & 0xFFFF) + (checksum >> 16); checksum = (checksum & 0xFFFF) + (checksum >> 16);
}
return ~checksum; return ~checksum;
} }
@ -83,8 +85,9 @@ static bool ratelimit(int frequency) {
static int count = 0; static int count = 0;
if(lasttime == now) { if(lasttime == now) {
if(count >= frequency) if(count >= frequency) {
return true; return true;
}
} else { } else {
lasttime = now; lasttime = now;
count = 0; count = 0;
@ -98,29 +101,31 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
if(packet->len < length) { if(packet->len < length) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got too short packet from %s (%s)", source->name, source->hostname); ifdebug(TRAFFIC) logger(LOG_WARNING, "Got too short packet from %s (%s)", source->name, source->hostname);
return false; return false;
} else } else {
return true; return true;
}
} }
static void swap_mac_addresses(vpn_packet_t *packet) { static void swap_mac_addresses(vpn_packet_t *packet) {
mac_t tmp; mac_t tmp;
memcpy(&tmp, &packet->data[0], sizeof tmp); memcpy(&tmp, &packet->data[0], sizeof(tmp));
memcpy(&packet->data[0], &packet->data[6], sizeof tmp); memcpy(&packet->data[0], &packet->data[6], sizeof(tmp));
memcpy(&packet->data[6], &tmp, sizeof tmp); memcpy(&packet->data[6], &tmp, sizeof(tmp));
} }
/* RFC 792 */ /* RFC 792 */
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip ip = {0}; struct ip ip = {};
struct icmp icmp = {0}; struct icmp icmp = {};
struct in_addr ip_src; struct in_addr ip_src;
struct in_addr ip_dst; struct in_addr ip_dst;
uint32_t oldlen; uint32_t oldlen;
if(ratelimit(3)) if(ratelimit(3)) {
return; return;
}
/* Swap Ethernet source and destination addresses */ /* Swap Ethernet source and destination addresses */
@ -137,32 +142,38 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
/* Try to reply with an IP address assigned to the local machine */ /* Try to reply with an IP address assigned to the local machine */
if (type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) { if(type == ICMP_TIME_EXCEEDED && code == ICMP_EXC_TTL) {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd != -1) {
if(sockfd != -1) {
struct sockaddr_in addr; struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr = ip.ip_src; addr.sin_addr = ip.ip_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
if(!connect(sockfd, (const struct sockaddr *) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
socklen_t addrlen = sizeof(addr); socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && addrlen <= sizeof(addr)) {
ip_dst = addr.sin_addr; ip_dst = addr.sin_addr;
} }
} }
close(sockfd); close(sockfd);
} }
} }
oldlen = packet->len - ether_size; oldlen = packet->len - ether_size;
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
icmp.icmp_nextmtu = htons(packet->len - ether_size); icmp.icmp_nextmtu = htons(packet->len - ether_size);
}
if(oldlen >= IP_MSS - ip_size - icmp_size) if(oldlen >= IP_MSS - ip_size - icmp_size) {
oldlen = IP_MSS - ip_size - icmp_size; oldlen = IP_MSS - ip_size - icmp_size;
}
/* Copy first part of original contents to ICMP message */ /* Copy first part of original contents to ICMP message */
@ -207,18 +218,19 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, length_
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) { static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_t ether_size, uint8_t type, uint8_t code) {
struct ip6_hdr ip6; struct ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0}; struct icmp6_hdr icmp6 = {};
uint16_t checksum; uint16_t checksum;
struct { struct {
struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */ struct in6_addr ip6_dst; /* destination address */
uint32_t length; uint32_t length;
uint32_t next; uint32_t next;
} pseudo; } pseudo;
if(ratelimit(3)) if(ratelimit(3)) {
return; return;
}
/* Swap Ethernet source and destination addresses */ /* Swap Ethernet source and destination addresses */
@ -235,32 +247,38 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, length_
/* Try to reply with an IP address assigned to the local machine */ /* Try to reply with an IP address assigned to the local machine */
if (type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) { if(type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) {
int sockfd = socket(AF_INET6, SOCK_DGRAM, 0); int sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockfd != -1) {
if(sockfd != -1) {
struct sockaddr_in6 addr; struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6; addr.sin6_family = AF_INET6;
addr.sin6_addr = ip6.ip6_src; addr.sin6_addr = ip6.ip6_src;
if (!connect(sockfd, (const struct sockaddr*) &addr, sizeof(addr))) {
if(!connect(sockfd, (const struct sockaddr *) &addr, sizeof(addr))) {
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6; addr.sin6_family = AF_INET6;
socklen_t addrlen = sizeof(addr); socklen_t addrlen = sizeof(addr);
if (!getsockname(sockfd, (struct sockaddr*) &addr, &addrlen) && addrlen <= sizeof(addr)) {
if(!getsockname(sockfd, (struct sockaddr *) &addr, &addrlen) && addrlen <= sizeof(addr)) {
pseudo.ip6_src = addr.sin6_addr; pseudo.ip6_src = addr.sin6_addr;
} }
} }
close(sockfd); close(sockfd);
} }
} }
pseudo.length = packet->len - ether_size; pseudo.length = packet->len - ether_size;
if(type == ICMP6_PACKET_TOO_BIG) if(type == ICMP6_PACKET_TOO_BIG) {
icmp6.icmp6_mtu = htonl(pseudo.length); icmp6.icmp6_mtu = htonl(pseudo.length);
}
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) if(pseudo.length >= IP_MSS - ip6_size - icmp6_size) {
pseudo.length = IP_MSS - ip6_size - icmp6_size; pseudo.length = IP_MSS - ip6_size - icmp6_size;
}
/* Copy first part of original contents to ICMP message */ /* Copy first part of original contents to ICMP message */
@ -313,56 +331,68 @@ static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) {
ethlen += 4; ethlen += 4;
} }
switch (type) { switch(type) {
case ETH_P_IP: case ETH_P_IP:
if(!checklength(source, packet, ethlen + ip_size)) if(!checklength(source, packet, ethlen + ip_size)) {
return false; return false;
}
if(packet->data[ethlen + 8] <= 1) { if(packet->data[ethlen + 8] <= 1) {
if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED) if(packet->data[ethlen + 11] != IPPROTO_ICMP || packet->data[ethlen + 32] != ICMP_TIME_EXCEEDED) {
route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); route_ipv4_unreachable(source, packet, ethlen, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL);
return false;
} }
uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; return false;
packet->data[ethlen + 8]--; }
uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11]; uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
checksum += old + (~new & 0xFFFF); packet->data[ethlen + 8]--;
while(checksum >> 16) uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9];
checksum = (checksum & 0xFFFF) + (checksum >> 16);
packet->data[ethlen + 10] = checksum >> 8;
packet->data[ethlen + 11] = checksum & 0xff;
return true; uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11];
checksum += old + (~new & 0xFFFF);
case ETH_P_IPV6: while(checksum >> 16) {
if(!checklength(source, packet, ethlen + ip6_size)) checksum = (checksum & 0xFFFF) + (checksum >> 16);
return false; }
if(packet->data[ethlen + 7] <= 1) { packet->data[ethlen + 10] = checksum >> 8;
if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED) packet->data[ethlen + 11] = checksum & 0xff;
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
return false; return true;
case ETH_P_IPV6:
if(!checklength(source, packet, ethlen + ip6_size)) {
return false;
}
if(packet->data[ethlen + 7] <= 1) {
if(packet->data[ethlen + 6] != IPPROTO_ICMPV6 || packet->data[ethlen + 40] != ICMP6_TIME_EXCEEDED) {
route_ipv6_unreachable(source, packet, ethlen, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT);
} }
packet->data[ethlen + 7]--; return false;
}
return true; packet->data[ethlen + 7]--;
default: return true;
return true;
default:
return true;
} }
} }
static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) { static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
if(!source || !via || !(via->options & OPTION_CLAMP_MSS)) if(!source || !via || !(via->options & OPTION_CLAMP_MSS)) {
return; return;
}
uint16_t mtu = source->mtu; uint16_t mtu = source->mtu;
if(via != myself && via->mtu < mtu)
if(via != myself && via->mtu < mtu) {
mtu = via->mtu; mtu = via->mtu;
}
/* Find TCP header */ /* Find TCP header */
int start = ether_size; int start = ether_size;
@ -373,52 +403,61 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac
type = packet->data[16] << 8 | packet->data[17]; type = packet->data[16] << 8 | packet->data[17];
} }
if(type == ETH_P_IP && packet->data[start + 9] == 6) if(type == ETH_P_IP && packet->data[start + 9] == 6) {
start += (packet->data[start] & 0xf) * 4; start += (packet->data[start] & 0xf) * 4;
else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6) } else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6) {
start += 40; start += 40;
else } else {
return; return;
}
if(packet->len <= start + 20) if(packet->len <= start + 20) {
return; return;
}
/* Use data offset field to calculate length of options field */ /* Use data offset field to calculate length of options field */
int len = ((packet->data[start + 12] >> 4) - 5) * 4; int len = ((packet->data[start + 12] >> 4) - 5) * 4;
if(packet->len < start + 20 + len) if(packet->len < start + 20 + len) {
return; return;
}
/* Search for MSS option header */ /* Search for MSS option header */
for(int i = 0; i < len;) { for(int i = 0; i < len;) {
if(packet->data[start + 20 + i] == 0) if(packet->data[start + 20 + i] == 0) {
break; break;
}
if(packet->data[start + 20 + i] == 1) { if(packet->data[start + 20 + i] == 1) {
i++; i++;
continue; continue;
} }
if(i > len - 2 || i > len - packet->data[start + 21 + i]) if(i > len - 2 || i > len - packet->data[start + 21 + i]) {
break; break;
}
if(packet->data[start + 20 + i] != 2) { if(packet->data[start + 20 + i] != 2) {
if(packet->data[start + 21 + i] < 2) if(packet->data[start + 21 + i] < 2) {
break; break;
}
i += packet->data[start + 21 + i]; i += packet->data[start + 21 + i];
continue; continue;
} }
if(packet->data[start + 21] != 4) if(packet->data[start + 21] != 4) {
break; break;
}
/* Found it */ /* Found it */
uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i]; uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i];
uint16_t newmss = mtu - start - 20; uint16_t newmss = mtu - start - 20;
uint32_t csum = packet->data[start + 16] << 8 | packet->data[start + 17]; uint32_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
if(oldmss <= newmss) if(oldmss <= newmss) {
break; break;
}
ifdebug(TRAFFIC) logger(LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss); ifdebug(TRAFFIC) logger(LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss);
@ -448,8 +487,8 @@ static void learn_mac(mac_t *address) {
if(!subnet) { if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Learned new MAC address %x:%x:%x:%x:%x:%x", ifdebug(TRAFFIC) logger(LOG_INFO, "Learned new MAC address %x:%x:%x:%x:%x:%x",
address->x[0], address->x[1], address->x[2], address->x[3], address->x[0], address->x[1], address->x[2], address->x[3],
address->x[4], address->x[5]); address->x[4], address->x[5]);
subnet = new_subnet(); subnet = new_subnet();
subnet->type = SUBNET_MAC; subnet->type = SUBNET_MAC;
@ -463,13 +502,16 @@ static void learn_mac(mac_t *address) {
for(node = connection_tree->head; node; node = node->next) { for(node = connection_tree->head; node; node = node->next) {
c = node->data; c = node->data;
if(c->status.active)
if(c->status.active) {
send_add_subnet(c, subnet); send_add_subnet(c, subnet);
}
} }
} }
if(subnet->expires) if(subnet->expires) {
subnet->expires = now + macexpire; subnet->expires = now + macexpire;
}
} }
void age_subnets(void) { void age_subnets(void) {
@ -480,17 +522,22 @@ void age_subnets(void) {
for(node = myself->subnet_tree->head; node; node = next) { for(node = myself->subnet_tree->head; node; node = next) {
next = node->next; next = node->next;
s = node->data; s = node->data;
if(s->expires && s->expires <= now) { if(s->expires && s->expires <= now) {
ifdebug(TRAFFIC) { ifdebug(TRAFFIC) {
char netstr[MAXNETSTR]; char netstr[MAXNETSTR];
if(net2str(netstr, sizeof netstr, s))
if(net2str(netstr, sizeof(netstr), s)) {
logger(LOG_INFO, "Subnet %s expired", netstr); logger(LOG_INFO, "Subnet %s expired", netstr);
}
} }
for(node2 = connection_tree->head; node2; node2 = node2->next) { for(node2 = connection_tree->head; node2; node2 = node2->next) {
c = node2->data; c = node2->data;
if(c->status.active)
if(c->status.active) {
send_del_subnet(c, s); send_del_subnet(c, s);
}
} }
subnet_update(myself, s, false); subnet_update(myself, s, false);
@ -501,8 +548,9 @@ void age_subnets(void) {
static void route_broadcast(node_t *source, vpn_packet_t *packet) { static void route_broadcast(node_t *source, vpn_packet_t *packet) {
if(decrement_ttl && source != myself) if(decrement_ttl && source != myself)
if(!do_decrement_ttl(source, packet)) if(!do_decrement_ttl(source, packet)) {
return; return;
}
broadcast_packet(source, packet); broadcast_packet(source, packet);
} }
@ -519,8 +567,9 @@ static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t et
memcpy(&ip, packet->data + ether_size, ip_size); memcpy(&ip, packet->data + ether_size, ip_size);
fragment.priority = packet->priority; fragment.priority = packet->priority;
if(ip.ip_hl != ip_size / 4) if(ip.ip_hl != ip_size / 4) {
return; return;
}
todo = ntohs(ip.ip_len) - ip_size; todo = ntohs(ip.ip_len) - ip_size;
@ -562,16 +611,16 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
node_t *via; node_t *via;
ipv4_t dest; ipv4_t dest;
memcpy(&dest, &packet->data[30], sizeof dest); memcpy(&dest, &packet->data[30], sizeof(dest));
subnet = lookup_subnet_ipv4(&dest); subnet = lookup_subnet_ipv4(&dest);
if(!subnet) { if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d", ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d",
source->name, source->hostname, source->name, source->hostname,
dest.x[0], dest.x[0],
dest.x[1], dest.x[1],
dest.x[2], dest.x[2],
dest.x[3]); dest.x[3]);
route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN); route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN);
return; return;
@ -582,18 +631,22 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
return; return;
} }
if(!subnet->owner->status.reachable) if(!subnet->owner->status.reachable) {
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNREACH); return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
}
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) {
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
}
if(decrement_ttl && source != myself && subnet->owner != myself) if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet)) if(!do_decrement_ttl(source, packet)) {
return; return;
}
if(priorityinheritance) if(priorityinheritance) {
packet->priority = packet->data[15]; packet->priority = packet->data[15];
}
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
@ -602,11 +655,13 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
return; return;
} }
if(directonly && subnet->owner != via) if(directonly && subnet->owner != via) {
return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO);
}
if(via && packet->len > MAX(via->mtu, 590) && via != myself) { if(via && packet->len > MAX(via->mtu, 590) && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
if(packet->data[20] & 0x40) { if(packet->data[20] & 0x40) {
packet->len = MAX(via->mtu, 590); packet->len = MAX(via->mtu, 590);
route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
@ -623,17 +678,19 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
} }
static void route_ipv4(node_t *source, vpn_packet_t *packet) { static void route_ipv4(node_t *source, vpn_packet_t *packet) {
if(!checklength(source, packet, ether_size + ip_size)) if(!checklength(source, packet, ether_size + ip_size)) {
return; return;
}
if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || ( if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || (
packet->data[30] == 255 && packet->data[30] == 255 &&
packet->data[31] == 255 && packet->data[31] == 255 &&
packet->data[32] == 255 && packet->data[32] == 255 &&
packet->data[33] == 255))) packet->data[33] == 255))) {
route_broadcast(source, packet); route_broadcast(source, packet);
else } else {
route_ipv4_unicast(source, packet); route_ipv4_unicast(source, packet);
}
} }
static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
@ -641,20 +698,20 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
node_t *via; node_t *via;
ipv6_t dest; ipv6_t dest;
memcpy(&dest, &packet->data[38], sizeof dest); memcpy(&dest, &packet->data[38], sizeof(dest));
subnet = lookup_subnet_ipv6(&dest); subnet = lookup_subnet_ipv6(&dest);
if(!subnet) { if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
source->name, source->hostname, source->name, source->hostname,
ntohs(dest.x[0]), ntohs(dest.x[0]),
ntohs(dest.x[1]), ntohs(dest.x[1]),
ntohs(dest.x[2]), ntohs(dest.x[2]),
ntohs(dest.x[3]), ntohs(dest.x[3]),
ntohs(dest.x[4]), ntohs(dest.x[4]),
ntohs(dest.x[5]), ntohs(dest.x[5]),
ntohs(dest.x[6]), ntohs(dest.x[6]),
ntohs(dest.x[7])); ntohs(dest.x[7]));
route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR); route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR);
return; return;
@ -665,18 +722,22 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
return; return;
} }
if(!subnet->owner->status.reachable) if(!subnet->owner->status.reachable) {
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE); return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
}
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) {
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
}
if(decrement_ttl && source != myself && subnet->owner != myself) if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet)) if(!do_decrement_ttl(source, packet)) {
return; return;
}
if(priorityinheritance) if(priorityinheritance) {
packet->priority = ((packet->data[14] & 0x0f) << 4) | (packet->data[15] >> 4); packet->priority = ((packet->data[14] & 0x0f) << 4) | (packet->data[15] >> 4);
}
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
@ -685,8 +746,9 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
return; return;
} }
if(directonly && subnet->owner != via) if(directonly && subnet->owner != via) {
return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
}
if(via && packet->len > MAX(via->mtu, 1294) && via != myself) { if(via && packet->len > MAX(via->mtu, 1294) && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
@ -711,14 +773,15 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
bool has_opt; bool has_opt;
struct { struct {
struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */ struct in6_addr ip6_dst; /* destination address */
uint32_t length; uint32_t length;
uint32_t next; uint32_t next;
} pseudo; } pseudo;
if(!checklength(source, packet, ether_size + ip6_size + ns_size)) if(!checklength(source, packet, ether_size + ip6_size + ns_size)) {
return; return;
}
has_opt = packet->len >= ether_size + ip6_size + ns_size + opt_size + ETH_ALEN; has_opt = packet->len >= ether_size + ip6_size + ns_size + opt_size + ETH_ALEN;
@ -731,18 +794,21 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
memcpy(&ip6, packet->data + ether_size, ip6_size); memcpy(&ip6, packet->data + ether_size, ip6_size);
memcpy(&ns, packet->data + ether_size + ip6_size, ns_size); memcpy(&ns, packet->data + ether_size + ip6_size, ns_size);
if(has_opt)
if(has_opt) {
memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size); memcpy(&opt, packet->data + ether_size + ip6_size + ns_size, opt_size);
}
/* First, snatch the source address from the neighbor solicitation packet */ /* First, snatch the source address from the neighbor solicitation packet */
if(overwrite_mac) if(overwrite_mac) {
memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN); memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN);
}
/* Check if this is a valid neighbor solicitation request */ /* Check if this is a valid neighbor solicitation request */
if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT || if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
(has_opt && opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR)) { (has_opt && opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR)) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type neighbor solicitation request"); ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type neighbor solicitation request");
return; return;
} }
@ -751,16 +817,20 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
pseudo.ip6_src = ip6.ip6_src; pseudo.ip6_src = ip6.ip6_src;
pseudo.ip6_dst = ip6.ip6_dst; pseudo.ip6_dst = ip6.ip6_dst;
if(has_opt)
if(has_opt) {
pseudo.length = htonl(ns_size + opt_size + ETH_ALEN); pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
else } else {
pseudo.length = htonl(ns_size); pseudo.length = htonl(ns_size);
}
pseudo.next = htonl(IPPROTO_ICMPV6); pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */ /* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
checksum = inet_checksum(&ns, ns_size, checksum); checksum = inet_checksum(&ns, ns_size, checksum);
if(has_opt) { if(has_opt) {
checksum = inet_checksum(&opt, opt_size, checksum); checksum = inet_checksum(&opt, opt_size, checksum);
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum); checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
@ -777,57 +847,64 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
if(!subnet) { if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
ntohs(((uint16_t *) &ns.nd_ns_target)[0]), ntohs(((uint16_t *) &ns.nd_ns_target)[0]),
ntohs(((uint16_t *) &ns.nd_ns_target)[1]), ntohs(((uint16_t *) &ns.nd_ns_target)[1]),
ntohs(((uint16_t *) &ns.nd_ns_target)[2]), ntohs(((uint16_t *) &ns.nd_ns_target)[2]),
ntohs(((uint16_t *) &ns.nd_ns_target)[3]), ntohs(((uint16_t *) &ns.nd_ns_target)[3]),
ntohs(((uint16_t *) &ns.nd_ns_target)[4]), ntohs(((uint16_t *) &ns.nd_ns_target)[4]),
ntohs(((uint16_t *) &ns.nd_ns_target)[5]), ntohs(((uint16_t *) &ns.nd_ns_target)[5]),
ntohs(((uint16_t *) &ns.nd_ns_target)[6]), ntohs(((uint16_t *) &ns.nd_ns_target)[6]),
ntohs(((uint16_t *) &ns.nd_ns_target)[7])); ntohs(((uint16_t *) &ns.nd_ns_target)[7]));
return; return;
} }
/* Check if it is for our own subnet */ /* Check if it is for our own subnet */
if(subnet->owner == myself) if(subnet->owner == myself) {
return; /* silently ignore */ return; /* silently ignore */
}
if(decrement_ttl) if(decrement_ttl)
if(!do_decrement_ttl(source, packet)) if(!do_decrement_ttl(source, packet)) {
return; return;
}
/* Create neighbor advertation reply */ /* Create neighbor advertation reply */
memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */ ip6.ip6_dst = ip6.ip6_src; /* swap destination and source protocoll address */
ip6.ip6_src = ns.nd_ns_target; ip6.ip6_src = ns.nd_ns_target;
if(has_opt) if(has_opt) {
memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ memcpy(packet->data + ether_size + ip6_size + ns_size + opt_size, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
}
ns.nd_ns_cksum = 0; ns.nd_ns_cksum = 0;
ns.nd_ns_type = ND_NEIGHBOR_ADVERT; ns.nd_ns_type = ND_NEIGHBOR_ADVERT;
ns.nd_ns_reserved = htonl(0x40000000UL); /* Set solicited flag */ ns.nd_ns_reserved = htonl(0x40000000UL); /* Set solicited flag */
opt.nd_opt_type = ND_OPT_TARGET_LINKADDR; opt.nd_opt_type = ND_OPT_TARGET_LINKADDR;
/* Create pseudo header */ /* Create pseudo header */
pseudo.ip6_src = ip6.ip6_src; pseudo.ip6_src = ip6.ip6_src;
pseudo.ip6_dst = ip6.ip6_dst; pseudo.ip6_dst = ip6.ip6_dst;
if(has_opt)
if(has_opt) {
pseudo.length = htonl(ns_size + opt_size + ETH_ALEN); pseudo.length = htonl(ns_size + opt_size + ETH_ALEN);
else } else {
pseudo.length = htonl(ns_size); pseudo.length = htonl(ns_size);
}
pseudo.next = htonl(IPPROTO_ICMPV6); pseudo.next = htonl(IPPROTO_ICMPV6);
/* Generate checksum */ /* Generate checksum */
checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0); checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
checksum = inet_checksum(&ns, ns_size, checksum); checksum = inet_checksum(&ns, ns_size, checksum);
if(has_opt) { if(has_opt) {
checksum = inet_checksum(&opt, opt_size, checksum); checksum = inet_checksum(&opt, opt_size, checksum);
checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum); checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
@ -839,25 +916,29 @@ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
memcpy(packet->data + ether_size, &ip6, ip6_size); memcpy(packet->data + ether_size, &ip6, ip6_size);
memcpy(packet->data + ether_size + ip6_size, &ns, ns_size); memcpy(packet->data + ether_size + ip6_size, &ns, ns_size);
if(has_opt)
if(has_opt) {
memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size); memcpy(packet->data + ether_size + ip6_size + ns_size, &opt, opt_size);
}
send_packet(source, packet); send_packet(source, packet);
} }
static void route_ipv6(node_t *source, vpn_packet_t *packet) { static void route_ipv6(node_t *source, vpn_packet_t *packet) {
if(!checklength(source, packet, ether_size + ip6_size)) if(!checklength(source, packet, ether_size + ip6_size)) {
return; return;
}
if(packet->data[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && packet->data[54] == ND_NEIGHBOR_SOLICIT) { if(packet->data[20] == IPPROTO_ICMPV6 && checklength(source, packet, ether_size + ip6_size + icmp6_size) && packet->data[54] == ND_NEIGHBOR_SOLICIT) {
route_neighborsol(source, packet); route_neighborsol(source, packet);
return; return;
} }
if(broadcast_mode && packet->data[38] == 255) if(broadcast_mode && packet->data[38] == 255) {
route_broadcast(source, packet); route_broadcast(source, packet);
else } else {
route_ipv6_unicast(source, packet); route_ipv6_unicast(source, packet);
}
} }
/* RFC 826 */ /* RFC 826 */
@ -867,8 +948,9 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
subnet_t *subnet; subnet_t *subnet;
struct in_addr addr; struct in_addr addr;
if(!checklength(source, packet, ether_size + arp_size)) if(!checklength(source, packet, ether_size + arp_size)) {
return; return;
}
if(source != myself) { if(source != myself) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got ARP request from %s (%s) while in router mode!", source->name, source->hostname); ifdebug(TRAFFIC) logger(LOG_WARNING, "Got ARP request from %s (%s) while in router mode!", source->name, source->hostname);
@ -877,8 +959,9 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
/* First, snatch the source address from the ARP packet */ /* First, snatch the source address from the ARP packet */
if(overwrite_mac) if(overwrite_mac) {
memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN); memcpy(mymac.x, packet->data + ETH_ALEN, ETH_ALEN);
}
/* Copy headers from packet to structs on the stack */ /* Copy headers from packet to structs on the stack */
@ -887,7 +970,7 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
/* Check if this is a valid ARP request */ /* Check if this is a valid ARP request */
if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP || if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) { arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request"); ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request");
return; return;
} }
@ -898,29 +981,31 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
if(!subnet) { if(!subnet) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: ARP request for unknown address %d.%d.%d.%d", ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: ARP request for unknown address %d.%d.%d.%d",
arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2], arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2],
arp.arp_tpa[3]); arp.arp_tpa[3]);
return; return;
} }
/* Check if it is for our own subnet */ /* Check if it is for our own subnet */
if(subnet->owner == myself) if(subnet->owner == myself) {
return; /* silently ignore */ return; /* silently ignore */
}
if(decrement_ttl) if(decrement_ttl)
if(!do_decrement_ttl(source, packet)) if(!do_decrement_ttl(source, packet)) {
return; return;
}
memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */ memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN); /* copy destination address */
packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */ packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
memcpy(&addr, arp.arp_tpa, sizeof(addr)); /* save protocol addr */ memcpy(&addr, arp.arp_tpa, sizeof(addr)); /* save protocol addr */
memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */ memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */
memcpy(arp.arp_spa, &addr, sizeof(addr)); /* ... */ memcpy(arp.arp_spa, &addr, sizeof(addr)); /* ... */
memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */ memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN); /* set target hard/proto addr */
memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */ memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
arp.arp_op = htons(ARPOP_REPLY); arp.arp_op = htons(ARPOP_REPLY);
/* Copy structs on stack back to packet */ /* Copy structs on stack back to packet */
@ -938,13 +1023,13 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
if(source == myself) { if(source == myself) {
mac_t src; mac_t src;
memcpy(&src, &packet->data[6], sizeof src); memcpy(&src, &packet->data[6], sizeof(src));
learn_mac(&src); learn_mac(&src);
} }
/* Lookup destination address */ /* Lookup destination address */
memcpy(&dest, &packet->data[0], sizeof dest); memcpy(&dest, &packet->data[0], sizeof(dest));
subnet = lookup_subnet_mac(NULL, &dest); subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet) { if(!subnet) {
@ -957,28 +1042,32 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
return; return;
} }
if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself) {
return; return;
}
if(decrement_ttl && source != myself && subnet->owner != myself) if(decrement_ttl && source != myself && subnet->owner != myself)
if(!do_decrement_ttl(source, packet)) if(!do_decrement_ttl(source, packet)) {
return; return;
}
uint16_t type = packet->data[12] << 8 | packet->data[13]; uint16_t type = packet->data[12] << 8 | packet->data[13];
if(priorityinheritance) { if(priorityinheritance) {
if(type == ETH_P_IP && packet->len >= ether_size + ip_size) if(type == ETH_P_IP && packet->len >= ether_size + ip_size) {
packet->priority = packet->data[15]; packet->priority = packet->data[15];
else if(type == ETH_P_IPV6 && packet->len >= ether_size + ip6_size) } else if(type == ETH_P_IPV6 && packet->len >= ether_size + ip6_size) {
packet->priority = ((packet->data[14] & 0x0f) << 4) | (packet->data[15] >> 4); packet->priority = ((packet->data[14] & 0x0f) << 4) | (packet->data[15] >> 4);
}
} }
// Handle packets larger than PMTU // Handle packets larger than PMTU
node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
if(directonly && subnet->owner != via) if(directonly && subnet->owner != via) {
return; return;
}
if(via && packet->len > via->mtu && via != myself) { if(via && packet->len > via->mtu && via != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
@ -996,6 +1085,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
} else { } else {
fragment_ipv4_packet(via, packet, ethlen); fragment_ipv4_packet(via, packet, ethlen);
} }
return; return;
} else if(type == ETH_P_IPV6 && packet->len > 1280 + ethlen) { } else if(type == ETH_P_IPV6 && packet->len > 1280 + ethlen) {
packet->len = via->mtu; packet->len = via->mtu;
@ -1015,40 +1105,40 @@ void route(node_t *source, vpn_packet_t *packet) {
return; return;
} }
if(!checklength(source, packet, ether_size)) if(!checklength(source, packet, ether_size)) {
return; return;
}
switch (routing_mode) { switch(routing_mode) {
case RMODE_ROUTER: case RMODE_ROUTER: {
{ uint16_t type = packet->data[12] << 8 | packet->data[13];
uint16_t type = packet->data[12] << 8 | packet->data[13];
switch (type) { switch(type) {
case ETH_P_ARP: case ETH_P_ARP:
route_arp(source, packet); route_arp(source, packet);
break;
case ETH_P_IP:
route_ipv4(source, packet);
break;
case ETH_P_IPV6:
route_ipv6(source, packet);
break;
default:
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type);
break;
}
}
break; break;
case RMODE_SWITCH: case ETH_P_IP:
route_mac(source, packet); route_ipv4(source, packet);
break; break;
case RMODE_HUB: case ETH_P_IPV6:
route_broadcast(source, packet); route_ipv6(source, packet);
break; break;
default:
ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type);
break;
}
}
break;
case RMODE_SWITCH:
route_mac(source, packet);
break;
case RMODE_HUB:
route_broadcast(source, packet);
break;
} }
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_ROUTE_H
#define TINC_ROUTE_H
/* /*
route.h -- header file for route.c route.h -- header file for route.c
Copyright (C) 2000-2005 Ivo Timmermans Copyright (C) 2000-2005 Ivo Timmermans
@ -18,9 +21,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_ROUTE_H__
#define __TINC_ROUTE_H__
#include "net.h" #include "net.h"
#include "node.h" #include "node.h"
@ -54,6 +54,6 @@ extern int macexpire;
extern mac_t mymac; extern mac_t mymac;
extern void age_subnets(void); extern void age_subnets(void);
extern void route(struct node_t *, struct vpn_packet_t *); extern void route(struct node_t *source, struct vpn_packet_t *packet);
#endif /* __TINC_ROUTE_H__ */ #endif

View file

@ -53,7 +53,7 @@ static int if_fd = -1;
static int ip_fd = -1; static int ip_fd = -1;
char *device = NULL; char *device = NULL;
char *iface = NULL; char *iface = NULL;
static char *device_info = NULL; static const char *device_info = NULL;
uint64_t device_total_in = 0; uint64_t device_total_in = 0;
uint64_t device_total_out = 0; uint64_t device_total_out = 0;
@ -62,33 +62,37 @@ static bool setup_device(void) {
char *type; char *type;
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
if(routing_mode == RMODE_ROUTER) if(routing_mode == RMODE_ROUTER) {
device = xstrdup(DEFAULT_TUN_DEVICE); device = xstrdup(DEFAULT_TUN_DEVICE);
else } else {
device = xstrdup(DEFAULT_TAP_DEVICE); device = xstrdup(DEFAULT_TAP_DEVICE);
}
} }
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
if(!strcasecmp(type, "tun")) if(!strcasecmp(type, "tun"))
/* use default */; /* use default */;
else if(!strcasecmp(type, "tap")) else if(!strcasecmp(type, "tap")) {
device_type = DEVICE_TYPE_TAP; device_type = DEVICE_TYPE_TAP;
else { } else {
logger(LOG_ERR, "Unknown device type %s!", type); logger(LOG_ERR, "Unknown device type %s!", type);
return false; return false;
} }
} else { } else {
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) {
device_type = DEVICE_TYPE_TAP; device_type = DEVICE_TYPE_TAP;
}
} }
if(device_type == DEVICE_TYPE_TUN) if(device_type == DEVICE_TYPE_TUN) {
device_info = "Solaris tun device"; device_info = "Solaris tun device";
else } else {
device_info = "Solaris tap device"; device_info = "Solaris tap device";
}
if(device_type == DEVICE_TYPE_TAP && routing_mode == RMODE_ROUTER) if(device_type == DEVICE_TYPE_TAP && routing_mode == RMODE_ROUTER) {
overwrite_mac = true; overwrite_mac = true;
}
/* The following is black magic copied from OpenVPN. */ /* The following is black magic copied from OpenVPN. */
@ -107,29 +111,35 @@ static bool setup_device(void) {
char *ptr = device; char *ptr = device;
get_config_string(lookup_config(config_tree, "Interface"), &ptr); get_config_string(lookup_config(config_tree, "Interface"), &ptr);
while(*ptr && !isdigit(*ptr)) while(*ptr && !isdigit(*ptr)) {
ptr++; ptr++;
}
int ppa = atoi(ptr); int ppa = atoi(ptr);
/* Assign a new PPA and get its unit number. */ /* Assign a new PPA and get its unit number. */
struct strioctl strioc_ppa = { struct strioctl strioc_ppa = {
.ic_cmd = TUNNEWPPA, .ic_cmd = TUNNEWPPA,
.ic_len = sizeof ppa, .ic_len = sizeof(ppa),
.ic_dp = (char *)&ppa, .ic_dp = (char *) &ppa,
}; };
if(!*ptr) { /* no number given, try dynamic */ if(!*ptr) { /* no number given, try dynamic */
bool found = false; bool found = false;
while(!found && ppa < 64) { while(!found && ppa < 64) {
int new_ppa = ioctl(device_fd, I_STR, &strioc_ppa); int new_ppa = ioctl(device_fd, I_STR, &strioc_ppa);
if(new_ppa >= 0) { if(new_ppa >= 0) {
ppa = new_ppa; ppa = new_ppa;
found = true; found = true;
break; break;
} }
ppa++; ppa++;
} }
if(!found) { if(!found) {
logger(LOG_ERR, "Could not find free PPA for %s %s!", device_info, device); logger(LOG_ERR, "Could not find free PPA for %s %s!", device_info, device);
return false; return false;
@ -156,7 +166,8 @@ static bool setup_device(void) {
{ {
/* Remove muxes just in case they are left over from a crashed tincd */ /* Remove muxes just in case they are left over from a crashed tincd */
struct lifreq ifr = {}; struct lifreq ifr = {};
strncpy(ifr.lifr_name, iface, sizeof ifr.lifr_name); strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) { if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
int muxid = ifr.lifr_arp_muxid; int muxid = ifr.lifr_arp_muxid;
ioctl(ip_fd, I_PUNLINK, muxid); ioctl(ip_fd, I_PUNLINK, muxid);
@ -191,6 +202,7 @@ static bool setup_device(void) {
logger(LOG_ERR, "Could not set PPA %d on %s %s!", ppa, device_info, device); logger(LOG_ERR, "Could not set PPA %d on %s %s!", ppa, device_info, device);
return false; return false;
} }
if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) { if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
logger(LOG_ERR, "Could not set flags on %s %s!", device_info, device); logger(LOG_ERR, "Could not set flags on %s %s!", device_info, device);
return false; return false;
@ -204,8 +216,9 @@ static bool setup_device(void) {
/* Pop any modules on the stream */ /* Pop any modules on the stream */
while(true) { while(true) {
if(ioctl(ip_fd, I_POP, NULL) < 0) if(ioctl(ip_fd, I_POP, NULL) < 0) {
break; break;
}
} }
/* Push arp module to ip_fd */ /* Push arp module to ip_fd */
@ -229,8 +242,8 @@ static bool setup_device(void) {
/* Set ifname to arp */ /* Set ifname to arp */
struct strioctl strioc_if = { struct strioctl strioc_if = {
.ic_cmd = SIOCSLIFNAME, .ic_cmd = SIOCSLIFNAME,
.ic_len = sizeof ifr, .ic_len = sizeof(ifr),
.ic_dp = (char *)&ifr, .ic_dp = (char *) &ifr,
}; };
if(ioctl(arp_fd, I_STR, &strioc_if) < 0) { if(ioctl(arp_fd, I_STR, &strioc_if) < 0) {
@ -251,12 +264,16 @@ static bool setup_device(void) {
logger(LOG_ERR, "Could not link %s %s to ARP", device_info, device); logger(LOG_ERR, "Could not link %s %s to ARP", device_info, device);
return false; return false;
} }
close(arp_fd); close(arp_fd);
} }
struct lifreq ifr = {}; struct lifreq ifr = {};
strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name)); strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
ifr.lifr_ip_muxid = ip_muxid; ifr.lifr_ip_muxid = ip_muxid;
if(device_type == DEVICE_TYPE_TAP) { if(device_type == DEVICE_TYPE_TAP) {
ifr.lifr_arp_muxid = arp_muxid; ifr.lifr_arp_muxid = arp_muxid;
} }
@ -265,6 +282,7 @@ static bool setup_device(void) {
if(device_type == DEVICE_TYPE_TAP) { if(device_type == DEVICE_TYPE_TAP) {
ioctl(ip_fd, I_PUNLINK, arp_muxid); ioctl(ip_fd, I_PUNLINK, arp_muxid);
} }
ioctl(ip_fd, I_PUNLINK, ip_muxid); ioctl(ip_fd, I_PUNLINK, ip_muxid);
logger(LOG_ERR, "Could not set multiplexor id for %s %s", device_info, device); logger(LOG_ERR, "Could not set multiplexor id for %s %s", device_info, device);
return false; return false;
@ -285,7 +303,8 @@ static bool setup_device(void) {
static void close_device(void) { static void close_device(void) {
if(iface) { if(iface) {
struct lifreq ifr = {}; struct lifreq ifr = {};
strncpy(ifr.lifr_name, iface, sizeof ifr.lifr_name); strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) { if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
int muxid = ifr.lifr_arp_muxid; int muxid = ifr.lifr_arp_muxid;
ioctl(ip_fd, I_PUNLINK, muxid); ioctl(ip_fd, I_PUNLINK, muxid);
@ -307,47 +326,49 @@ static bool read_packet(vpn_packet_t *packet) {
int f = 0; int f = 0;
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
sbuf.maxlen = MTU - 14; sbuf.maxlen = MTU - 14;
sbuf.buf = (char *)packet->data + 14; sbuf.buf = (char *)packet->data + 14;
if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) { if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
return false; return false;
} }
switch(packet->data[14] >> 4) { switch(packet->data[14] >> 4) {
case 4: case 4:
packet->data[12] = 0x08; packet->data[12] = 0x08;
packet->data[13] = 0x00; packet->data[13] = 0x00;
break;
case 6:
packet->data[12] = 0x86;
packet->data[13] = 0xDD;
break;
default:
ifdebug(TRAFFIC) logger(LOG_ERR, "Unknown IP version %d while reading packet from %s %s", packet->data[14] >> 4, device_info, device);
return false;
}
memset(packet->data, 0, 12);
packet->len = sbuf.len + 14;
break; break;
case DEVICE_TYPE_TAP: case 6:
sbuf.maxlen = MTU; packet->data[12] = 0x86;
sbuf.buf = (char *)packet->data; packet->data[13] = 0xDD;
if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
return false;
}
packet->len = sbuf.len;
break; break;
default: default:
abort(); ifdebug(TRAFFIC) logger(LOG_ERR, "Unknown IP version %d while reading packet from %s %s", packet->data[14] >> 4, device_info, device);
return false;
}
memset(packet->data, 0, 12);
packet->len = sbuf.len + 14;
break;
case DEVICE_TYPE_TAP:
sbuf.maxlen = MTU;
sbuf.buf = (char *)packet->data;
if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) {
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
return false;
}
packet->len = sbuf.len;
break;
default:
abort();
} }
device_total_in += packet->len; device_total_in += packet->len;
@ -363,28 +384,30 @@ static bool write_packet(vpn_packet_t *packet) {
struct strbuf sbuf; struct strbuf sbuf;
switch(device_type) { switch(device_type) {
case DEVICE_TYPE_TUN: case DEVICE_TYPE_TUN:
sbuf.len = packet->len - 14; sbuf.len = packet->len - 14;
sbuf.buf = (char *)packet->data + 14; sbuf.buf = (char *)packet->data + 14;
if(putmsg(device_fd, NULL, &sbuf, 0) < 0) { if(putmsg(device_fd, NULL, &sbuf, 0) < 0) {
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
return false; return false;
} }
break;
case DEVICE_TYPE_TAP: break;
sbuf.len = packet->len;
sbuf.buf = (char *)packet->data;
if(putmsg(device_fd, NULL, &sbuf, 0) < 0) { case DEVICE_TYPE_TAP:
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); sbuf.len = packet->len;
return false; sbuf.buf = (char *)packet->data;
}
break;
default: if(putmsg(device_fd, NULL, &sbuf, 0) < 0) {
abort(); logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
return false;
}
break;
default:
abort();
} }
device_total_out += packet->len; device_total_out += packet->len;

View file

@ -65,13 +65,15 @@ static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t)); result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
if(result) if(result) {
return result; return result;
}
result = a->weight - b->weight; result = a->weight - b->weight;
if(result || !a->owner || !b->owner) if(result || !a->owner || !b->owner) {
return result; return result;
}
return strcmp(a->owner->name, b->owner->name); return strcmp(a->owner->name, b->owner->name);
} }
@ -81,18 +83,21 @@ static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) {
result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength; result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength;
if(result) if(result) {
return result; return result;
}
result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t)); result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t));
if(result) if(result) {
return result; return result;
}
result = a->weight - b->weight; result = a->weight - b->weight;
if(result || !a->owner || !b->owner) if(result || !a->owner || !b->owner) {
return result; return result;
}
return strcmp(a->owner->name, b->owner->name); return strcmp(a->owner->name, b->owner->name);
} }
@ -102,18 +107,21 @@ static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) {
result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength; result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength;
if(result) if(result) {
return result; return result;
}
result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t)); result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
if(result) if(result) {
return result; return result;
}
result = a->weight - b->weight; result = a->weight - b->weight;
if(result || !a->owner || !b->owner) if(result || !a->owner || !b->owner) {
return result; return result;
}
return strcmp(a->owner->name, b->owner->name); return strcmp(a->owner->name, b->owner->name);
} }
@ -123,19 +131,23 @@ int subnet_compare(const subnet_t *a, const subnet_t *b) {
result = a->type - b->type; result = a->type - b->type;
if(result) if(result) {
return result; return result;
}
switch (a->type) { switch(a->type) {
case SUBNET_MAC: case SUBNET_MAC:
return subnet_compare_mac(a, b); return subnet_compare_mac(a, b);
case SUBNET_IPV4: case SUBNET_IPV4:
return subnet_compare_ipv4(a, b); return subnet_compare_ipv4(a, b);
case SUBNET_IPV6: case SUBNET_IPV6:
return subnet_compare_ipv6(a, b); return subnet_compare_ipv6(a, b);
default: default:
logger(LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!", logger(LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!",
a->type); a->type);
exit(0); exit(0);
} }
@ -198,17 +210,20 @@ bool str2net(subnet_t *subnet, const char *subnetstr) {
int weight = 10; int weight = 10;
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d", if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d",
&x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) { &x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) {
if(l < 0 || l > 32) if(l < 0 || l > 32) {
return false; return false;
}
subnet->type = SUBNET_IPV4; subnet->type = SUBNET_IPV4;
subnet->net.ipv4.prefixlength = l; subnet->net.ipv4.prefixlength = l;
subnet->weight = weight; subnet->weight = weight;
for(i = 0; i < 4; i++) { for(i = 0; i < 4; i++) {
if(x[i] > 255) if(x[i] > 255) {
return false; return false;
}
subnet->net.ipv4.address.x[i] = x[i]; subnet->net.ipv4.address.x[i] = x[i];
} }
@ -216,17 +231,19 @@ bool str2net(subnet_t *subnet, const char *subnetstr) {
} }
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d", if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
&l, &weight) >= 9) { &l, &weight) >= 9) {
if(l < 0 || l > 128) if(l < 0 || l > 128) {
return false; return false;
}
subnet->type = SUBNET_IPV6; subnet->type = SUBNET_IPV6;
subnet->net.ipv6.prefixlength = l; subnet->net.ipv6.prefixlength = l;
subnet->weight = weight; subnet->weight = weight;
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++) {
subnet->net.ipv6.address.x[i] = htons(x[i]); subnet->net.ipv6.address.x[i] = htons(x[i]);
}
return true; return true;
} }
@ -237,8 +254,10 @@ bool str2net(subnet_t *subnet, const char *subnetstr) {
subnet->weight = weight; subnet->weight = weight;
for(i = 0; i < 4; i++) { for(i = 0; i < 4; i++) {
if(x[i] > 255) if(x[i] > 255) {
return false; return false;
}
subnet->net.ipv4.address.x[i] = x[i]; subnet->net.ipv4.address.x[i] = x[i];
} }
@ -246,24 +265,26 @@ bool str2net(subnet_t *subnet, const char *subnetstr) {
} }
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d", if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) { &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) {
subnet->type = SUBNET_IPV6; subnet->type = SUBNET_IPV6;
subnet->net.ipv6.prefixlength = 128; subnet->net.ipv6.prefixlength = 128;
subnet->weight = weight; subnet->weight = weight;
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++) {
subnet->net.ipv6.address.x[i] = htons(x[i]); subnet->net.ipv6.address.x[i] = htons(x[i]);
}
return true; return true;
} }
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d", if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) { &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) {
subnet->type = SUBNET_MAC; subnet->type = SUBNET_MAC;
subnet->weight = weight; subnet->weight = weight;
for(i = 0; i < 6; i++) for(i = 0; i < 6; i++) {
subnet->net.mac.address.x[i] = x[i]; subnet->net.mac.address.x[i] = x[i];
}
return true; return true;
} }
@ -276,66 +297,87 @@ bool str2net(subnet_t *subnet, const char *subnetstr) {
// Count number of colons // Count number of colons
for(p = subnetstr; *p; p++) for(p = subnetstr; *p; p++)
if(*p == ':') if(*p == ':') {
colons++; colons++;
}
if(colons > 7) if(colons > 7) {
return false; return false;
}
// Scan numbers before the double colon // Scan numbers before the double colon
p = subnetstr; p = subnetstr;
for(i = 0; i < colons; i++) { for(i = 0; i < colons; i++) {
if(*p == ':') if(*p == ':') {
break; break;
}
x[i] = strtoul(p, &q, 0x10); x[i] = strtoul(p, &q, 0x10);
if(!q || p == q || *q != ':')
if(!q || p == q || *q != ':') {
return false; return false;
}
p = ++q; p = ++q;
} }
p++; p++;
colons -= i; colons -= i;
if(!i) { if(!i) {
p++; p++;
colons--; colons--;
} }
if(!*p || *p == '/' || *p == '#') if(!*p || *p == '/' || *p == '#') {
colons--; colons--;
}
// Fill in the blanks // Fill in the blanks
for(; i < 8 - colons; i++) for(; i < 8 - colons; i++) {
x[i] = 0; x[i] = 0;
}
// Scan the remaining numbers // Scan the remaining numbers
for(; i < 8; i++) { for(; i < 8; i++) {
x[i] = strtoul(p, &q, 0x10); x[i] = strtoul(p, &q, 0x10);
if(!q || p == q)
if(!q || p == q) {
return false; return false;
}
if(i == 7) { if(i == 7) {
p = q; p = q;
break; break;
} }
if(*q != ':')
if(*q != ':') {
return false; return false;
}
p = ++q; p = ++q;
} }
l = 128; l = 128;
if(*p == '/')
sscanf(p, "/%d#%d", &l, &weight);
else if(*p == '#')
sscanf(p, "#%d", &weight);
if(l < 0 || l > 128) if(*p == '/') {
sscanf(p, "/%d#%d", &l, &weight);
} else if(*p == '#') {
sscanf(p, "#%d", &weight);
}
if(l < 0 || l > 128) {
return false; return false;
}
subnet->type = SUBNET_IPV6; subnet->type = SUBNET_IPV6;
subnet->net.ipv6.prefixlength = l; subnet->net.ipv6.prefixlength = l;
subnet->weight = weight; subnet->weight = weight;
for(i = 0; i < 8; i++) for(i = 0; i < 8; i++) {
subnet->net.ipv6.address.x[i] = htons(x[i]); subnet->net.ipv6.address.x[i] = htons(x[i]);
}
return true; return true;
} }
@ -349,47 +391,47 @@ bool net2str(char *netstr, int len, const subnet_t *subnet) {
return false; return false;
} }
switch (subnet->type) { switch(subnet->type) {
case SUBNET_MAC: case SUBNET_MAC:
snprintf(netstr, len, "%x:%x:%x:%x:%x:%x#%d", snprintf(netstr, len, "%x:%x:%x:%x:%x:%x#%d",
subnet->net.mac.address.x[0], subnet->net.mac.address.x[0],
subnet->net.mac.address.x[1], subnet->net.mac.address.x[1],
subnet->net.mac.address.x[2], subnet->net.mac.address.x[2],
subnet->net.mac.address.x[3], subnet->net.mac.address.x[3],
subnet->net.mac.address.x[4], subnet->net.mac.address.x[4],
subnet->net.mac.address.x[5], subnet->net.mac.address.x[5],
subnet->weight); subnet->weight);
break; break;
case SUBNET_IPV4: case SUBNET_IPV4:
snprintf(netstr, len, "%u.%u.%u.%u/%d#%d", snprintf(netstr, len, "%u.%u.%u.%u/%d#%d",
subnet->net.ipv4.address.x[0], subnet->net.ipv4.address.x[0],
subnet->net.ipv4.address.x[1], subnet->net.ipv4.address.x[1],
subnet->net.ipv4.address.x[2], subnet->net.ipv4.address.x[2],
subnet->net.ipv4.address.x[3], subnet->net.ipv4.address.x[3],
subnet->net.ipv4.prefixlength, subnet->net.ipv4.prefixlength,
subnet->weight); subnet->weight);
break; break;
case SUBNET_IPV6: case SUBNET_IPV6:
snprintf(netstr, len, "%x:%x:%x:%x:%x:%x:%x:%x/%d#%d", snprintf(netstr, len, "%x:%x:%x:%x:%x:%x:%x:%x/%d#%d",
ntohs(subnet->net.ipv6.address.x[0]), ntohs(subnet->net.ipv6.address.x[0]),
ntohs(subnet->net.ipv6.address.x[1]), ntohs(subnet->net.ipv6.address.x[1]),
ntohs(subnet->net.ipv6.address.x[2]), ntohs(subnet->net.ipv6.address.x[2]),
ntohs(subnet->net.ipv6.address.x[3]), ntohs(subnet->net.ipv6.address.x[3]),
ntohs(subnet->net.ipv6.address.x[4]), ntohs(subnet->net.ipv6.address.x[4]),
ntohs(subnet->net.ipv6.address.x[5]), ntohs(subnet->net.ipv6.address.x[5]),
ntohs(subnet->net.ipv6.address.x[6]), ntohs(subnet->net.ipv6.address.x[6]),
ntohs(subnet->net.ipv6.address.x[7]), ntohs(subnet->net.ipv6.address.x[7]),
subnet->net.ipv6.prefixlength, subnet->net.ipv6.prefixlength,
subnet->weight); subnet->weight);
break; break;
default: default:
logger(LOG_ERR, logger(LOG_ERR,
"net2str() was called with unknown subnet type %d, exiting!", "net2str() was called with unknown subnet type %d, exiting!",
subnet->type); subnet->type);
exit(0); exit(0);
} }
return true; return true;
@ -409,12 +451,17 @@ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
// Check if this address is cached // Check if this address is cached
for(i = 0; i < 2; i++) { for(i = 0; i < 2; i++) {
if(!cache_mac_valid[i]) if(!cache_mac_valid[i]) {
continue; continue;
if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner) }
if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner) {
continue; continue;
if(!memcmp(address, &cache_mac_address[i], sizeof *address)) }
if(!memcmp(address, &cache_mac_address[i], sizeof(*address))) {
return cache_mac_subnet[i]; return cache_mac_subnet[i];
}
} }
// Search all subnets for a matching one // Search all subnets for a matching one
@ -422,20 +469,23 @@ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) { for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) {
p = n->data; p = n->data;
if(!p || p->type != SUBNET_MAC) if(!p || p->type != SUBNET_MAC) {
continue; continue;
}
if(!memcmp(address, &p->net.mac.address, sizeof *address)) { if(!memcmp(address, &p->net.mac.address, sizeof(*address))) {
r = p; r = p;
if(p->owner->status.reachable)
if(p->owner->status.reachable) {
break; break;
}
} }
} }
// Cache the result // Cache the result
cache_mac_slot = !cache_mac_slot; cache_mac_slot = !cache_mac_slot;
memcpy(&cache_mac_address[cache_mac_slot], address, sizeof *address); memcpy(&cache_mac_address[cache_mac_slot], address, sizeof(*address));
cache_mac_subnet[cache_mac_slot] = r; cache_mac_subnet[cache_mac_slot] = r;
cache_mac_valid[cache_mac_slot] = true; cache_mac_valid[cache_mac_slot] = true;
@ -450,10 +500,13 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
// Check if this address is cached // Check if this address is cached
for(i = 0; i < 2; i++) { for(i = 0; i < 2; i++) {
if(!cache_ipv4_valid[i]) if(!cache_ipv4_valid[i]) {
continue; continue;
if(!memcmp(address, &cache_ipv4_address[i], sizeof *address)) }
if(!memcmp(address, &cache_ipv4_address[i], sizeof(*address))) {
return cache_ipv4_subnet[i]; return cache_ipv4_subnet[i];
}
} }
// Search all subnets for a matching one // Search all subnets for a matching one
@ -461,20 +514,23 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
for(n = subnet_tree->head; n; n = n->next) { for(n = subnet_tree->head; n; n = n->next) {
p = n->data; p = n->data;
if(!p || p->type != SUBNET_IPV4) if(!p || p->type != SUBNET_IPV4) {
continue; continue;
}
if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) { if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) {
r = p; r = p;
if(p->owner->status.reachable)
if(p->owner->status.reachable) {
break; break;
}
} }
} }
// Cache the result // Cache the result
cache_ipv4_slot = !cache_ipv4_slot; cache_ipv4_slot = !cache_ipv4_slot;
memcpy(&cache_ipv4_address[cache_ipv4_slot], address, sizeof *address); memcpy(&cache_ipv4_address[cache_ipv4_slot], address, sizeof(*address));
cache_ipv4_subnet[cache_ipv4_slot] = r; cache_ipv4_subnet[cache_ipv4_slot] = r;
cache_ipv4_valid[cache_ipv4_slot] = true; cache_ipv4_valid[cache_ipv4_slot] = true;
@ -489,10 +545,13 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
// Check if this address is cached // Check if this address is cached
for(i = 0; i < 2; i++) { for(i = 0; i < 2; i++) {
if(!cache_ipv6_valid[i]) if(!cache_ipv6_valid[i]) {
continue; continue;
if(!memcmp(address, &cache_ipv6_address[i], sizeof *address)) }
if(!memcmp(address, &cache_ipv6_address[i], sizeof(*address))) {
return cache_ipv6_subnet[i]; return cache_ipv6_subnet[i];
}
} }
// Search all subnets for a matching one // Search all subnets for a matching one
@ -500,20 +559,23 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
for(n = subnet_tree->head; n; n = n->next) { for(n = subnet_tree->head; n; n = n->next) {
p = n->data; p = n->data;
if(!p || p->type != SUBNET_IPV6) if(!p || p->type != SUBNET_IPV6) {
continue; continue;
}
if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) { if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) {
r = p; r = p;
if(p->owner->status.reachable)
if(p->owner->status.reachable) {
break; break;
}
} }
} }
// Cache the result // Cache the result
cache_ipv6_slot = !cache_ipv6_slot; cache_ipv6_slot = !cache_ipv6_slot;
memcpy(&cache_ipv6_address[cache_ipv6_slot], address, sizeof *address); memcpy(&cache_ipv6_address[cache_ipv6_slot], address, sizeof(*address));
cache_ipv6_subnet[cache_ipv6_slot] = r; cache_ipv6_subnet[cache_ipv6_slot] = r;
cache_ipv6_valid[cache_ipv6_slot] = true; cache_ipv6_valid[cache_ipv6_slot] = true;
@ -550,33 +612,44 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
if(!subnet) { if(!subnet) {
for(node = owner->subnet_tree->head; node; node = node->next) { for(node = owner->subnet_tree->head; node; node = node->next) {
subnet = node->data; subnet = node->data;
if(!net2str(netstr, sizeof netstr, subnet))
if(!net2str(netstr, sizeof(netstr), subnet)) {
continue; continue;
}
// Strip the weight from the subnet, and put it in its own environment variable // Strip the weight from the subnet, and put it in its own environment variable
char *weight = strchr(netstr, '#'); char *weight = strchr(netstr, '#');
if(weight)
if(weight) {
*weight++ = 0; *weight++ = 0;
else } else {
weight = empty; weight = empty;
}
// Prepare the SUBNET and WEIGHT variables // Prepare the SUBNET and WEIGHT variables
if(envp[5]) if(envp[5]) {
free(envp[5]); free(envp[5]);
if(envp[6]) }
if(envp[6]) {
free(envp[6]); free(envp[6]);
}
xasprintf(&envp[5], "SUBNET=%s", netstr); xasprintf(&envp[5], "SUBNET=%s", netstr);
xasprintf(&envp[6], "WEIGHT=%s", weight); xasprintf(&envp[6], "WEIGHT=%s", weight);
execute_script(name, envp); execute_script(name, envp);
} }
} else { } else {
if(net2str(netstr, sizeof netstr, subnet)) { if(net2str(netstr, sizeof(netstr), subnet)) {
// Strip the weight from the subnet, and put it in its own environment variable // Strip the weight from the subnet, and put it in its own environment variable
char *weight = strchr(netstr, '#'); char *weight = strchr(netstr, '#');
if(weight)
if(weight) {
*weight++ = 0; *weight++ = 0;
else } else {
weight = empty; weight = empty;
}
// Prepare the SUBNET and WEIGHT variables // Prepare the SUBNET and WEIGHT variables
xasprintf(&envp[5], "SUBNET=%s", netstr); xasprintf(&envp[5], "SUBNET=%s", netstr);
@ -586,8 +659,9 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
} }
} }
for(i = 0; envp[i] && i < 9; i++) for(i = 0; envp[i] && i < 9; i++) {
free(envp[i]); free(envp[i]);
}
} }
void dump_subnets(void) { void dump_subnets(void) {
@ -599,8 +673,11 @@ void dump_subnets(void) {
for(node = subnet_tree->head; node; node = node->next) { for(node = subnet_tree->head; node; node = node->next) {
subnet = node->data; subnet = node->data;
if(!net2str(netstr, sizeof netstr, subnet))
if(!net2str(netstr, sizeof(netstr), subnet)) {
continue; continue;
}
logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name); logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name);
} }

View file

@ -1,3 +1,6 @@
#ifndef TINC_SUBNET_H
#define TINC_SUBNET_H
/* /*
subnet.h -- header for subnet.c subnet.h -- header for subnet.c
Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>, Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
@ -18,16 +21,13 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef __TINC_SUBNET_H__
#define __TINC_SUBNET_H__
#include "net.h" #include "net.h"
typedef enum subnet_type_t { typedef enum subnet_type_t {
SUBNET_MAC = 0, SUBNET_MAC = 0,
SUBNET_IPV4, SUBNET_IPV4,
SUBNET_IPV6, SUBNET_IPV6,
SUBNET_TYPES /* Guardian */ SUBNET_TYPES, /* Guardian */
} subnet_type_t; } subnet_type_t;
typedef struct subnet_mac_t { typedef struct subnet_mac_t {
@ -47,11 +47,11 @@ typedef struct subnet_ipv6_t {
#include "node.h" #include "node.h"
typedef struct subnet_t { typedef struct subnet_t {
struct node_t *owner; /* the owner of this subnet */ struct node_t *owner; /* the owner of this subnet */
subnet_type_t type; /* subnet type (IPv4? IPv6? MAC? something even weirder?) */ subnet_type_t type; /* subnet type (IPv4? IPv6? MAC? something even weirder?) */
time_t expires; /* expiry time */ time_t expires; /* expiry time */
int weight; /* weight (higher value is higher priority) */ int weight; /* weight (higher value is higher priority) */
/* And now for the actual subnet: */ /* And now for the actual subnet: */
@ -66,23 +66,22 @@ typedef struct subnet_t {
extern avl_tree_t *subnet_tree; extern avl_tree_t *subnet_tree;
extern int subnet_compare(const struct subnet_t *, const struct subnet_t *); extern subnet_t *new_subnet(void) __attribute__((__malloc__));
extern subnet_t *new_subnet(void) __attribute__ ((__malloc__)); extern void free_subnet(subnet_t *subnet);
extern void free_subnet(subnet_t *);
extern void init_subnets(void); extern void init_subnets(void);
extern void exit_subnets(void); extern void exit_subnets(void);
extern avl_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__)); extern avl_tree_t *new_subnet_tree(void) __attribute__((__malloc__));
extern void free_subnet_tree(avl_tree_t *); extern void free_subnet_tree(avl_tree_t *subnet_tree);
extern void subnet_add(struct node_t *, subnet_t *); extern void subnet_add(struct node_t *owner, subnet_t *subnet);
extern void subnet_del(struct node_t *, subnet_t *); extern void subnet_del(struct node_t *owner, subnet_t *subnet);
extern void subnet_update(struct node_t *, subnet_t *, bool); extern void subnet_update(struct node_t *owner, subnet_t *subnet, bool up);
extern bool net2str(char *, int, const subnet_t *); extern bool net2str(char *netstr, int len, const subnet_t *subnet);
extern bool str2net(subnet_t *, const char *); extern bool str2net(subnet_t *subnet, const char *netstr);
extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *); extern subnet_t *lookup_subnet(const struct node_t *owner, const subnet_t *subnet);
extern subnet_t *lookup_subnet_mac(const struct node_t *, const mac_t *); extern subnet_t *lookup_subnet_mac(const struct node_t *owner, const mac_t *address);
extern subnet_t *lookup_subnet_ipv4(const ipv4_t *); extern subnet_t *lookup_subnet_ipv4(const ipv4_t *address);
extern subnet_t *lookup_subnet_ipv6(const ipv6_t *); extern subnet_t *lookup_subnet_ipv6(const ipv6_t *address);
extern void dump_subnets(void); extern void dump_subnets(void);
extern void subnet_cache_flush(void); extern void subnet_cache_flush(void);
#endif /* __TINC_SUBNET_H__ */ #endif

Some files were not shown because too many files have changed in this diff Show more