diff --git a/ChangeLog b/ChangeLog index 831cb4e..67cebbe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,267 @@ +commit 5b7f42bca4dbfee7a5fa2bc119f4739baaeb2f55 +Author: Guus Sliepen +Date: Wed Dec 5 22:32:10 2012 +0100 + + Releasing 1.1pre4. + +commit 4c16094e949e1f17461ac744118076a3cec437e8 +Author: Guus Sliepen +Date: Wed Dec 5 21:42:43 2012 +0100 + + Fix whitespace. + +commit 4f8abf1b29b117c5d593bfa7703966fd88e9eace +Author: Guus Sliepen +Date: Wed Dec 5 21:40:49 2012 +0100 + + Scale packet counters similar to byte counters. + +commit d5f0ff5df86d06825110527ddc252b1268e31479 +Author: Guus Sliepen +Date: Wed Dec 5 21:33:01 2012 +0100 + + Don't use nested functions. + + This allows tinc to be compiled with Clang. + +commit eb80105ea855f2c7ee0ea467574acf86cf455a77 +Author: Guus Sliepen +Date: Wed Dec 5 14:42:21 2012 +0100 + + Fix compiler warnings on OpenBSD. + +commit 5e3607b616538eac7bb70d78d4f20d847a1c3064 +Author: Guus Sliepen +Date: Mon Dec 3 13:09:40 2012 +0100 + + Remove GraphDumpFile from the manual and manpages. + + This option is not supported in tinc 1.1, "tincctl dump graph" can be used + instead. + +commit a717b9bcfbe811787fd6718fb3f8fb3f272bcfb9 +Author: Guus Sliepen +Date: Mon Dec 3 13:08:03 2012 +0100 + + Add option to dump only a list of reachable nodes. + +commit 75c619e372f02f8225d158fd514f01bd04857d3b +Author: Guus Sliepen +Date: Mon Dec 3 10:41:28 2012 +0100 + + More fixes for Windows. + + In particular, Windows does support many of the timer* macros, except timeradd + and timersub. + +commit d53384c2de6d2824b9adcec111301d86e6b25f8e +Author: Guus Sliepen +Date: Mon Dec 3 09:08:21 2012 +0100 + + Fix compiler error on Windows. + +commit 76816e119b7d38a14823d430aafeff362dfbfd41 +Author: Guus Sliepen +Date: Mon Dec 3 09:07:23 2012 +0100 + + Fix crash in timeout handling. + +commit d19b00606576d19ef206e363ac709daf3bd00f25 +Author: Guus Sliepen +Date: Mon Dec 3 09:02:08 2012 +0100 + + Set a node's pointers to zero before trying to insert it into a tree. + +commit d2b19be1a0dd3c4987aa926117f5bf281892c78b +Author: Guus Sliepen +Date: Thu Nov 29 14:35:08 2012 +0100 + + Fix use of unitialised values in hash tables. + + Not only was Valgrind unhappy about it, it could also result in cache misses. + +commit d9c70767aa6da8b62b4a1034d5f07892603beddd +Author: Guus Sliepen +Date: Thu Nov 29 14:32:12 2012 +0100 + + Fix check for expired events. + + This would trigger a infinite loop if a timeout expired and the next timeout + was not expired yet, but less than 1 second from being expired. + +commit 8825cddd0d8ed6dad00924ef382139da51ca3fc4 +Author: Guus Sliepen +Date: Thu Nov 29 12:37:04 2012 +0100 + + Allow multiple timeouts to expire at the exact same time. + +commit 6bc5d626a8726fc23365ee705761a3c666a08ad4 +Author: Guus Sliepen +Date: Thu Nov 29 12:28:23 2012 +0100 + + Drop libevent and use our own event handling again. + + There are several reasons for this: + + - MacOS/X doesn't support polling the tap device using kqueue, requiring a + workaround to fall back to select(). + - On Windows only sockets are properly handled, therefore tinc uses a second + thread that does a blocking ReadFile() on the TAP-Win32/64 device. However, + this does not mix well with libevent. + - Libevent, event just the core, is quite large, and although it is easy to get + and install on many platforms, it can be a burden. + - Libev is more lightweight and seems technically superior, but it doesn't + abstract away all the platform differences (for example, async events are not + supported on Windows). + +commit d30b9e1272fef18070d37d10b2b3e4bb2fc07f59 +Author: Guus Sliepen +Date: Mon Nov 19 14:20:50 2012 +0100 + + Ensure MTU probe replies are sent back the same way they came in. + + Also sprinkle some comments over mtu_probe_h(). + +commit 3c1b7047332f4b5e9d5ae7109e696b33712a5fb2 +Author: Guus Sliepen +Date: Mon Nov 19 13:50:17 2012 +0100 + + Improve UDP address selection. + + We don't need to search the whole edge tree, we can use the node's own edge + tree since each edge has a pointer to its reverse. Also, we do need to make + sure we try the reflexive address often. + +commit f57129ce3439f3826c12f15feb5df05e5ad8cab9 +Author: Guus Sliepen +Date: Sat Nov 17 22:48:06 2012 +0100 + + Try all known addresses of node during PMTU discovery, now also for SPTPS. + +commit 30404650b28bf72d0b05b55393f2dd492434f9f3 +Author: Guus Sliepen +Date: Sat Nov 17 22:14:52 2012 +0100 + + Choose a suitable socket when updating a node's UDP address. + +commit 8f9ee895224b39347783f3119343efc3bdaa3511 +Author: Guus Sliepen +Date: Thu Nov 15 11:24:18 2012 +0100 + + Also don't use poll() on MacOS/X. + +commit 8a77df9e28114cbfd83351070fdb266cf31fc310 +Author: Guus Sliepen +Date: Thu Nov 15 11:13:40 2012 +0100 + + Disable support for kqueue on MacOS/X. + + Apparently MacOS/X doesn't support kqueue events on character devices. + +commit 818c92e6583006bf2e38f1027044925df6cf0ca0 +Author: Guus Sliepen +Date: Wed Nov 14 10:44:35 2012 +0100 + + Remove text saying you must have one of PrivateKey or PrivateKeyFile in tinc.conf. + +commit e8bf81794f412b27261be0f2aa4eb287352041af +Author: Guus Sliepen +Date: Tue Nov 13 15:05:41 2012 +0100 + + Send broadcast packets using a random socket, and properly support IPv6. + + Before it would always use the first socket, and always send an IPv4 broadcast packet. That + works fine in a lot of situations, but it is better to try all sockets, and to send IPv6 packets + on IPv6 sockets. This is especially important for users that are on IPv6-only networks or that + have multiple physical network interfaces, although in the latter case it probably requires + them to use the ListenAddress variable to create a separate socket for each interface. + +commit 0870c7c32cf8a24f234fc066df867747ddb1ddc7 +Author: Guus Sliepen +Date: Tue Nov 13 15:01:43 2012 +0100 + + Don't take the address of a variable whose scope is about to disappear. + +commit bb3d7f3b31d4a429d1c31c6621d82f34dd552482 +Author: Guus Sliepen +Date: Sun Nov 11 19:01:28 2012 +0100 + + Fix configure script help text for --enable options. + +commit 5bfbb8f6c58307a8109f556caa30be122cc4d39f +Author: Guus Sliepen +Date: Sun Nov 11 19:01:02 2012 +0100 + + Fix index entry for section about readline library. + +commit 5766518589a5e6cc43ba77a4049059ead05fb300 +Author: Guus Sliepen +Date: Sun Nov 11 18:53:23 2012 +0100 + + Mention in the manual that support for LZO and zlib can be disabled. + +commit 6ec4596557d658f6c15c2cb9a96152c8c476118a +Author: Guus Sliepen +Date: Sun Nov 11 18:45:40 2012 +0100 + + Mention libcurses and libreadline in the manual. + +commit 0ee139e91431527015b7132e4c36f8d4ec09f66b +Author: Guus Sliepen +Date: Sat Nov 10 23:45:22 2012 +0100 + + Make sure PMTU discovery works in switch mode with VLAN tags. + + Before, when tinc saw a packet larger than the PMTU with a VLAN tag, it would + not know what to do with it, and would just forward it via TCP. Now, tinc + handles 802.1q packets correctly, as long as there is only one tag. + +commit ade4fccad6857f3d6d548e52bc94ab23751e4fef +Author: Guus Sliepen +Date: Sat Nov 10 23:13:05 2012 +0100 + + Using alloca() for a constant sized buffer is very silly. + + Cppcheck said using alloca() in the 21st century is silly anyway. + +commit b355476e917f377abb6434657933fcf4ffe6870a +Author: Guus Sliepen +Date: Sat Nov 10 23:09:31 2012 +0100 + + Fix potential buffer overflow reading the PID file. + + Found by cppcheck. + +commit edc08b73a9e353bde6db4c73866a6a730a1a7cb4 +Author: Guus Sliepen +Date: Sun Oct 21 17:45:16 2012 +0200 + + Slightly randomize all timeouts. + +commit 717ea66d7ba0c23f27d86b3d5c6992b751135455 +Author: Guus Sliepen +Date: Sun Oct 21 17:35:13 2012 +0200 + + Add the AutoConnect option. + + When set to a non-zero value, tinc will try to maintain exactly that number of + meta connections to other nodes. If there are not enough connections, it will + periodically try to set up an outgoing connection to a random node. If there + are too many connections, it will periodically try to remove an outgoing + connection. + +commit 1f8b70efa0dedbd3642e0ee82a640d125664af34 +Author: Guus Sliepen +Date: Sun Oct 21 17:34:53 2012 +0200 + + Keep track of the number of nodes in a tree. + +commit 0006c754f2e61e108aa2dd5a6ddd2e9b50d51bd6 +Author: Guus Sliepen +Date: Wed Oct 17 13:51:02 2012 +0200 + + Fix warnings from groff. + commit 0db9e471ea53b48687ea247c855cd95ec453530c Author: Guus Sliepen Date: Sun Oct 14 19:22:30 2012 +0200 diff --git a/Makefile.in b/Makefile.in index 3fe02c7..657ca58 100644 --- a/Makefile.in +++ b/Makefile.in @@ -57,10 +57,9 @@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ THANKS config.guess config.sub depcomp install-sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ - $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.in + $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/lzo.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ diff --git a/NEWS b/NEWS index 806f2b7..3dea2b5 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,17 @@ +Version 1.1pre4 December 5 2012 + + * Added the "AutoConnect" option which will let tinc automatically select + which nodes to connect to. + + * Improved performance of VLAN-tagged IP traffic inside the VPN. + + * Ensured LocalDiscovery works with multiple BindToAddress statements and/or + IPv6-only LANs. + + * Dropped dependency on libevent. + + * Fixed Windows version not reading packets from the TAP adapter. + Version 1.1pre3 October 14 2012 * New experimental protocol: @@ -41,7 +55,7 @@ Version 1.1pre1 June 25 2011 * tincctl, a commandline utility * tinc-gui, a preliminary GUI implemented in Python/wxWidgets - * Code cleanups and reorganization. + * Code cleanups and reorganization. * Repleacable cryptography backend, currently supports OpenSSL and libgcrypt. @@ -247,13 +261,13 @@ Version 1.0.6 Dec 18 2006 * Fixed a bug where broadcasts in switch and hub modes sometimes would not work anymore when part of the VPN had become disconnected from the rest. -version 1.0.5 Nov 14 2006 +Version 1.0.5 Nov 14 2006 * Lots of small fixes. * Broadcast packets no longer grow in size with each hop. This should fix switch mode (again). - + * Generic host-up and host-down scripts. * Optionally dump graph in graphviz format to a file or a script. @@ -262,347 +276,354 @@ version 1.0.5 Nov 14 2006 Thanks to Scott Lamb for his contributions to this version of tinc. -version 1.0.4 May 4 2005 +Version 1.0.4 May 4 2005 * Fix switch and hub modes. * Optionally start scripts when a Subnet becomes (un)reachable. -version 1.0.3 Nov 11 2004 +Version 1.0.3 Nov 11 2004 -* Show error message when failing to write a PID file. + * Show error message when failing to write a PID file. -* Ignore spaces at end of lines in config files. + * Ignore spaces at end of lines in config files. -* Fix handling of late packets. + * Fix handling of late packets. -* Unify BSD tun/tap device handling. This allows IPv6 on tun devices and - anything on tap devices as long as the underlying OS supports it. + * Unify BSD tun/tap device handling. This allows IPv6 on tun devices and + anything on tap devices as long as the underlying OS supports it. -* Handle IPv6 on Solaris tun devices. + * Handle IPv6 on Solaris tun devices. -* Allow tinc to work properly under Windows XP SP2. + * Allow tinc to work properly under Windows XP SP2. -* Allow VLAN tagged Ethernet frames in switch and hub mode. + * Allow VLAN tagged Ethernet frames in switch and hub mode. -* Experimental PMTUDiscovery, TunnelServer and BlockingTCP options. + * Experimental PMTUDiscovery, TunnelServer and BlockingTCP options. -version 1.0.2 Nov 8 2003 +Version 1.0.2 Nov 8 2003 -* Fix address and hostname resolving under Windows. + * Fix address and hostname resolving under Windows. -* Remove warnings about non-existing scripts and unsupported address families. + * Remove warnings about non-existing scripts and unsupported address families. -* Use the event logger under Windows. + * Use the event logger under Windows. -* Fix quoting of filenames and command line arguments under Windows. + * Fix quoting of filenames and command line arguments under Windows. -* Strict checks for length incoming network packets and return values of - cryptographic functions, + * Strict checks for length incoming network packets and return values of + cryptographic functions, -* Fix a bug in metadata handling that made the tinc daemon abort. + * Fix a bug in metadata handling that made the tinc daemon abort. -version 1.0.1 Aug 14 2003 +Version 1.0.1 Aug 14 2003 -* Allow empty lines in config files. + * Allow empty lines in config files. -* Fix handling of spaces and backslashes in filenames under native Windows. + * Fix handling of spaces and backslashes in filenames under native Windows. -* Allow scripts to be executed under native Windows. + * Allow scripts to be executed under native Windows. -* Update documentation, make it less Linux specific. + * Update documentation, make it less Linux specific. -version 1.0 Aug 4 2003 +Version 1.0 Aug 4 2003 -* Lots of small bugfixes and code cleanups. + * Lots of small bugfixes and code cleanups. -* Throughput doubled and latency reduced. + * Throughput doubled and latency reduced. -* Added support for LZO compression. + * Added support for LZO compression. -* No need to set MAC address or disable ARP anymore. + * No need to set MAC address or disable ARP anymore. -* Added support for Windows 2000 and XP, both natively and in a Cygwin - environment. + * Added support for Windows 2000 and XP, both natively and in a Cygwin + environment. -version 1.0pre8 Sep 16 2002 +Version 1.0pre8 Sep 16 2002 -* More fixes for subnets with prefixlength undivisible by 8. + * More fixes for subnets with prefixlength undivisible by 8. -* Added support for NetBSD and MacOS/X. + * Added support for NetBSD and MacOS/X. -* Switched from undirected graphs to directed graphs to avoid certain race - conditions and improve scalability. + * Switched from undirected graphs to directed graphs to avoid certain race + conditions and improve scalability. -* Generalized broadcasting and forwarding of protocol messages. + * Generalized broadcasting and forwarding of protocol messages. -* Cleanup of source code. + * Cleanup of source code. +Version 1.0pre7 Apr 7 2002 -version 1.0pre7 Apr 7 2002 + * Don't do blocking read()s when getting a signal. -* Don't do blocking read()s when getting a signal. + * Remove RSA key checking code, since it sometimes thinks perfectly good RSA + keys are bad. -* Remove RSA key checking code, since it sometimes thinks perfectly good RSA - keys are bad. + * Fix handling of subnets when prefixlength isn't divisible by 8. -* Fix handling of subnets when prefixlength isn't divisible by 8. +Version 1.0pre6 Mar 27 2002 + * Improvement of redundant links: + * Non-blocking connects. + * Protocol broadcast messages can no longer go into an infinite loop. + * Graph algorithm updated to look harder for direct connections. -version 1.0pre6 Mar 27 2002 + * Good support for routing IPv6 packets over the VPN. Works on Linux, + FreeBSD, possibly OpenBSD but not on Solaris. -* Improvement of redundant links: + * Support for tunnels over IPv6 networks. Works on all supported + operating systems. - * Non-blocking connects. - - * Protocol broadcast messages can no longer go into an infinite loop. - - * Graph algorithm updated to look harder for direct connections. + * Optional compression of UDP connections using zlib. -* Good support for routing IPv6 packets over the VPN. Works on Linux, - FreeBSD, possibly OpenBSD but not on Solaris. + * Optionally let UDP connections inherit TOS field of tunneled packets. -* Support for tunnels over IPv6 networks. Works on all supported - operating systems. + * Optionally start scripts when certain hosts become (un)reachable. -* Optional compression of UDP connections using zlib. +Version 1.0pre5 Feb 9 2002 -* Optionally let UDP connections inherit TOS field of tunneled packets. + * Security enhancements: + * Added sequence number and optional message authentication code to + the packets. + * Configurable encryption cipher and digest algorithms. -* Optionally start scripts when certain hosts become (un)reachable. + * More robust handling of dis- and reconnects. + * Added a "switch" and a "hub" mode to allow bridging setups. -version 1.0pre5 Feb 9 2002 + * Preliminary support for routing of IPv6 packets. -* Security enhancements: + * Supports Linux, FreeBSD, OpenBSD and Solaris. - * Added sequence number and optional message authentication code to - the packets. +Version 1.0pre4 Jan 17 2001 - * Configurable encryption cipher and digest algorithms. + * Updated documentation; the documentation now reflects the + configuration as it is. -* More robust handling of dis- and reconnects. + * Some internal changes to make tinc scale better for large + networks, such as using AVL trees instead of linked lists for the + connection list. -* Added a "switch" and a "hub" mode to allow bridging setups. + * RSA keys can be stored in separate files if needed. See the + documentation for more information. -* Preliminary support for routing of IPv6 packets. + * Tinc has now been reported to run on Linux PowerPC and FreeBSD x86. -* Supports Linux, FreeBSD, OpenBSD and Solaris. +Version 1.0pre3 Oct 31 2000 + * The protocol has been redesigned, and although some details are + still under discussion, this is secure. Care has been taken to + resist most, if not all, attacks. -It looks like this might be the last release before 1.0. + * Unfortunately this protocol is not compatible with earlier versions, + nor are earlier versions compatible with this version. Because the + older protocol has huge security flaws, we feel that not + implementing backwards compatibility is justified. + * Some data about the protocol: + * It uses public/private RSA keys for authentication (this is the + actual fix for the security hole). + * All cryptographic functions have been taken out of tinc, instead + it uses the OpenSSL library functions. + * Offers support for multiple subnets per tinc daemon. -version 1.0pre4 Jan 17 2001 + * New is also the support for the universal tun/tap device. This + means better portability to FreeBSD and Solaris. -* Updated documentation; the documentation now reflects the - configuration as it is. + * Tinc is tested to compile on Solaris, Linux x86, Linux alpha. -* Some internal changes to make tinc scale better for large - networks, such as using AVL trees instead of linked lists for the - connection list. + * Tinc now uses the OpenSSL library for cryptographic operations. + More information on getting and installing OpenSSL is in the manual. + This also means that the GMP library is no longer required. -* RSA keys can be stored in separate files if needed. See the - documentation for more information. + * Further, thanks to Enrique Zanardi, we have Spanish messages; Matias + Carrasco provided us with a Spanish translation of the manual. -* tinc has now been reported to run on Linux PowerPC and FreeBSD x86. +Version 1.0pre2 May 31 2000 + * This version has been internationalized; and a Dutch translation has + been included. + * Two configuration variables have been added: + * VpnMask - the IP network mask for the entire VPN, not just our + subnet (as given by MyVirtualIP). The Redhat and Debian packages + use this variable in their system startup scripts, but it is + ignored by tinc. + * Hostnames - if set to `yes', look up the names of IP addresses + trying to connect to us. Default set to `no', to prevent lockups + during lookups. -version 1.0pre3 Oct 31 2000 + * The system startup scripts for Debian and Redhat use + /etc/tinc/nets.boot to find out which networks need to be started + during system boot. -* The protocol has been redesigned, and although some details are - still under discussion, this is secure. Care has been taken to - resist most, if not all, attacks. - -* Unfortunately this protocol is not compatible with earlier versions, - nor are earlier versions compatible with this version. Because the - older protocol has huge security flaws, we feel that not - implementing backwards compatibility is justified. + * Fixes to prevent denial of service attacks by sending random data + after connecting (and even when the connection has been established), + either random garbage or just nonsensical protocol fields. -* Some data about the protocol: + * Tinc will retry to connect upon startup, does not quit if it doesn't + work the first time. - * It uses public/private RSA keys for authentication (this is the - actual fix for the security hole). + * Hosts that are disconnected implicitly if we lose a connection get + deleted from the internal list, to prevent hogging eachother with + add and delete requests when the connection is restored. - * All cryptographic functions have been taken out of tinc, instead - it uses the OpenSSL library functions. +Version 1.0pre1 May 12 2000 - * Offers support for multiple subnets per tinc daemon. - -* New is also the support for the universal tun/tap device. This - means better portability to FreeBSD and Solaris. - -* tinc is tested to compile on Solaris, Linux x86, Linux alpha. - -* tinc now uses the OpenSSL library for cryptographic operations. - More information on getting and installing OpenSSL is in the manual. - This also means that the GMP library is no longer required. - -* Further, thanks to Enrique Zanardi, we have Spanish messages; Matias - Carrasco provided us with a Spanish translation of the manual. - - -What still needs to be done before 1.0: - -* Documentation. Especially since the protocol has changed, and a lot - of configuration directives have been added. - - - - -version 1.0pre2 May 31 2000 - -* This version has been internationalized; and a Dutch translation has - been included. - -* Two configuration variables have been added: - * VpnMask - the IP network mask for the entire VPN, not just our - subnet (as given by MyVirtualIP). The Redhat and Debian packages - use this variable in their system startup scripts, but it is - ignored by tinc. - * Hostnames - if set to `yes', look up the names of IP addresses - trying to connect to us. Default set to `no', to prevent lockups - during lookups. - -* The system startup scripts for Debian and Redhat use - /etc/tinc/nets.boot to find out which networks need to be started - during system boot. - -* Fixes to prevent denial of service attacks by sending random data - after connecting (and even when the connection has been established), - either random garbage or just nonsensical protocol fields. - -* tinc will retry to connect upon startup, does not quit if it doesn't - work the first time. - -* Hosts that are disconnected implicitly if we lose a connection get - deleted from the internal list, to prevent hogging eachother with - add and delete requests when the connection is restored. - - -What still needs to be done before 1.0: - -* Documentation. -* Failover ConnectTo lines, try another one if the first doesn't work. - - - - -version 1.0pre1 May 12 2000 * New meta-protocol + * Various other bugfixes + * Documentation updates -version 0.3.3 Feb 9 2000 - * Fixed bug that made tinc stop working with latest kernels (Guus - Sliepen) +Version 0.3.3 Feb 9 2000 + + * Fixed bug that made tinc stop working with latest kernels + * Updated the manual -version 0.3.2 Nov 12 1999 - * no more `Invalid filedescriptor' when working with multiple - connections - * forward unknown packets to uplink +Version 0.3.2 Nov 12 1999 -version 0.3.1 Oct 20 1999 - * fixed a bug where tinc would exit without a trace + * No more `Invalid filedescriptor' when working with multiple + connections. -version 0.3 Aug 20 1999 - * pings now work immediately - * all packet sizes get transmitted correctly + * Forward unknown packets to uplink. -version 0.2.26 Aug 15 1999 - * fixed some remaining bugs - * --sysconfdir works with configure - * last version before 0.3 +Version 0.3.1 Oct 20 1999 -version 0.2.25 Aug 8 1999 - * improved stability, going towards 0.3 now. + * Fixed a bug where tinc would exit without a trace. -version 0.2.24 Aug 7 1999 - * added key aging, there's a new config variable, KeyExpire. - * updated man and info pages +Version 0.3 Aug 20 1999 -version 0.2.23 Aug 5 1999 - * all known bugs fixed, this is a candidate for 0.3 + * Pings now work immediately. -version 0.2.22 Apr 11 1999 - * multiconnection thing is now working nearly perfect :) + * All packet sizes get transmitted correctly. + +Version 0.2.26 Aug 15 1999 + + * Fixed some remaining bugs. + + * --sysconfdir works with configure. + + * Last version before 0.3. + +Version 0.2.25 Aug 8 1999 + + * Improved stability, going towards 0.3 now. + +Version 0.2.24 Aug 7 1999 + + * Added key aging, there's a new config variable, KeyExpire. + + * Updated man and info pages. + +Version 0.2.23 Aug 5 1999 + + * All known bugs fixed, this is a candidate for 0.3. + +Version 0.2.22 Apr 11 1999 + + * Multiconnection thing is now working nearly perfect :) + +Version 0.2.21 Apr 10 1999 -version 0.2.21 Apr 10 1999 * You shouldn't notice a thing, but a lot has changed wrt key management - except that it refuses to talk to versions < 0.2.20 -version 0.2.20 +Version 0.2.19 Apr 3 1999 -version 0.2.19 Apr 3 1999 - * don't install a libcipher.so + * Don't install a libcipher.so. -version 0.2.18 Apr 3 1999 - * blowfish library dynamically loaded upon execution - * included Eric Young's IDEA library +Version 0.2.18 Apr 3 1999 -version 0.2.17 Apr 1 1999 - * tincd now re-executes itself in case of a segmentation fault. + * Blowfish library dynamically loaded upon execution. -version 0.2.16 Apr 1 1999 - * wrote tincd.conf(5) man page, which still needs a lot of work. - * config file now accepts and tolerates spaces, and any integer base -for integer variables, and better error reporting. See -doc/tincd.conf.sample for an example. + * Included Eric Young's IDEA library. -version 0.2.15 Mar 29 1999 - * fixed bugs +Version 0.2.17 Apr 1 1999 -version 0.2.14 Feb 10 1999 - * added --timeout flag and PingTimeout configuration - * did some first syslog cleanup work + * Tincd now re-executes itself in case of a segmentation fault. -version 0.2.13 Jan 23 1999 - * bugfixes +Version 0.2.16 Apr 1 1999 -version 0.2.12 Jan 23 1999 - * fixed nauseating bug so that it would crash whenever a connection -got lost + * Wrote tincd.conf(5) man page, which still needs a lot of work. -version 0.2.11 Jan 22 1999 - * framework for multiple connections has been done - * simple manpage for tincd + * Config file now accepts and tolerates spaces, and any integer base + for integer variables, and better error reporting. See + doc/tincd.conf.sample for an example. -version 0.2.10 Jan 18 1999 - * passphrase support added +Version 0.2.15 Mar 29 1999 -version 0.2.9 Jan 13 1999 - * bugs fixed. + * Fixed bugs. -version 0.2.8 Jan 11 1999 - * a reworked protocol version - * a ping/pong system - * more reliable networking code - * automatic reconnection - * still does not work with more than one connection :) - * strips MAC addresses before sending, so there's less overhead, and -less redundancy +Version 0.2.14 Feb 10 1999 -version 0.2.7 Jan 3 1999 - * several updates to make extending more easy. + * Added --timeout flag and PingTimeout configuration. + * Did some first syslog cleanup work. + +Version 0.2.13 Jan 23 1999 + + * Bugfixes. + +Version 0.2.12 Jan 23 1999 + + * Fixed nauseating bug so that it would crash whenever a connection + got lost. + +Version 0.2.11 Jan 22 1999 + + * Framework for multiple connections has been done. + + * Simple manpage for tincd. + +Version 0.2.10 Jan 18 1999 + + * Passphrase support added. + +Version 0.2.9 Jan 13 1999 + + * Bugs fixed. + +Version 0.2.8 Jan 11 1999 + + * A reworked protocol version. + + * A ping/pong system. + + * More reliable networking code. + + * Automatic reconnection. + + * Still does not work with more than one connection :) + + * Strips MAC addresses before sending, so there's less overhead, and + less redundancy. + +Version 0.2.7 Jan 3 1999 + + * Several updates to make extending more easy. + +Version 0.2.6 Dec 20 1998 -version 0.2.6 Dec 20 1998 * Point-to-Point connections have been established, including -blowfish encryption and a secret key-exchange. + Blowfish encryption and a secret key-exchange. + +Version 0.2.5 Dec 16 1998 -version 0.2.5 Dec 16 1998 * Project renamed to tinc, in honour of TINC. -version 0.2.4 Dec 16 1998 - * now it really does ;) +Version 0.2.4 Dec 16 1998 -version 0.2.3 Nov 24 1998 - * it sort of works now + * Now it really does ;) -version 0.2.2 Nov 20 1998 - * uses GNU gmp. +Version 0.2.3 Nov 24 1998 -version 0.2.1 Nov 14 1998 + * It sort of works now. + +Version 0.2.2 Nov 20 1998 + + * Uses GNU gmp. + +Version 0.2.1 Nov 14 1998 * Bare version. diff --git a/README b/README index 10cb0b5..639829c 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is the README file for tinc version 1.1pre3. Installation +This is the README file for tinc version 1.1pre4. Installation instructions may be found in the INSTALL file. tinc is Copyright (C) 1998-2012 by: @@ -36,11 +36,11 @@ at your own risk. Compatibility ------------- -Version 1.1pre3 is compatible with 1.0pre8, 1.0 and later, but not with older +Version 1.1pre4 is compatible with 1.0pre8, 1.0 and later, but not with older versions of tinc. When the ExperimentalProtocol option is used, tinc is still compatible with -1.0.X and 1.1pre3 itself, but not with any other 1.1preX version. +1.0.X and 1.1pre4 itself, but not with any other 1.1preX version. Requirements @@ -50,7 +50,6 @@ In order to compile tinc, you will need a GNU C compiler environment. Please ensure you have the latest stable versions of all the required libraries: - OpenSSL (http://www.openssl.org/) version 1.0.0 or later. -- Libevent (http://monkey.org/~provos/libevent/) The following libraries are used by default, but can be disabled if necessary: diff --git a/aclocal.m4 b/aclocal.m4 index 4171fdd..181bd2f 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1135,7 +1135,6 @@ AC_SUBST([am__untar]) m4_include([m4/attribute.m4]) m4_include([m4/curses.m4]) -m4_include([m4/libevent.m4]) m4_include([m4/lzo.m4]) m4_include([m4/openssl.m4]) m4_include([m4/readline.m4]) diff --git a/config.h.in b/config.h.in index ce11d29..7d902fe 100644 --- a/config.h.in +++ b/config.h.in @@ -64,9 +64,6 @@ /* Define to 1 if you have the `ECDSA_verify' function. */ #undef HAVE_ECDSA_VERIFY -/* Define to 1 if you have the header file. */ -#undef HAVE_EVENT_H - /* Define to 1 if you have the `EVP_EncryptInit_ex' function. */ #undef HAVE_EVP_ENCRYPTINIT_EX diff --git a/configure b/configure index ecbfc43..01cfacd 100755 --- a/configure +++ b/configure @@ -738,7 +738,6 @@ enable_uml enable_vde enable_tunemu with_windows2000 -with_libgcrypt enable_curses with_curses with_curses_include @@ -747,9 +746,6 @@ enable_readline with_readline with_readline_include with_readline_lib -with_libevent -with_libevent_include -with_libevent_lib enable_zlib with_zlib with_zlib_include @@ -1393,9 +1389,9 @@ Optional Features: --enable-dependency-tracking do not reject slow dependency extractors --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer - --disable-uml enable support for User Mode Linux - --disable-vde enable support for Virtual Distributed Ethernet - --disable-tunemu enable support for the tunemu driver + --enable-uml enable support for User Mode Linux + --enable-vde enable support for Virtual Distributed Ethernet + --enable-tunemu enable support for the tunemu driver --disable-curses disable curses support --disable-readline disable readline support --disable-zlib disable zlib compression support @@ -1408,7 +1404,6 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-windows2000 compile with support for Windows 2000. This disables support for tunneling over existing IPv6 networks. - --with-libgcrypt enable use of libgcrypt instead of OpenSSL] --with-curses=DIR curses base directory, or: --with-curses-include=DIR curses headers directory @@ -1417,10 +1412,6 @@ Optional Packages: --with-readline-include=DIR readline headers directory --with-readline-lib=DIR readline library directory - --with-libevent=DIR libevent base directory, or: - --with-libevent-include=DIR - libevent headers directory - --with-libevent-lib=DIR libevent library directory --with-zlib=DIR zlib base directory, or: --with-zlib-include=DIR zlib headers directory --with-zlib-lib=DIR zlib library directory @@ -4104,7 +4095,7 @@ fi # Define the identity of the package. PACKAGE=tinc - VERSION=1.1pre3 + VERSION=1.1pre4 cat >>confdefs.h <<_ACEOF @@ -5929,12 +5920,6 @@ rm -f confcache -# Check whether --with-libgcrypt was given. -if test "${with_libgcrypt+set}" = set; then : - withval=$with_libgcrypt; -fi - - # Check whether --enable-curses was given. if test "${enable_curses+set}" = set; then : @@ -6145,95 +6130,6 @@ fi - -# Check whether --with-libevent was given. -if test "${with_libevent+set}" = set; then : - withval=$with_libevent; libevent="$withval" - CPPFLAGS="$CPPFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib" - -fi - - - -# Check whether --with-libevent-include was given. -if test "${with_libevent_include+set}" = set; then : - withval=$with_libevent_include; libevent_include="$withval" - CPPFLAGS="$CPPFLAGS -I$withval" - -fi - - - -# Check whether --with-libevent-lib was given. -if test "${with_libevent_lib+set}" = set; then : - withval=$with_libevent_lib; libevent_lib="$withval" - LDFLAGS="$LDFLAGS -L$withval" - -fi - - - for ac_header in event.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "event.h" "ac_cv_header_event_h" "$ac_includes_default" -if test "x$ac_cv_header_event_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_EVENT_H 1 -_ACEOF - -else - as_fn_error $? "\"libevent header files not found.\"" "$LINENO" 5; break - -fi - -done - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for event_init in -levent" >&5 -$as_echo_n "checking for event_init in -levent... " >&6; } -if ${ac_cv_lib_event_event_init+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-levent $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char event_init (); -int -main () -{ -return event_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_event_event_init=yes -else - ac_cv_lib_event_event_init=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_event_event_init" >&5 -$as_echo "$ac_cv_lib_event_event_init" >&6; } -if test "x$ac_cv_lib_event_event_init" = xyes; then : - LIBS="-levent $LIBS" -else - as_fn_error $? "\"libevent libraries not found.\"" "$LINENO" 5 - -fi - - - # Check whether --enable-zlib was given. if test "${enable_zlib+set}" = set; then : enableval=$enable_zlib; diff --git a/configure.in b/configure.in index 5781537..e513248 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ AC_PREREQ(2.61) AC_INIT AC_CONFIG_SRCDIR([src/tincd.c]) AC_GNU_SOURCE -AM_INIT_AUTOMAKE(tinc, 1.1pre3) +AM_INIT_AUTOMAKE(tinc, 1.1pre4) AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE @@ -74,7 +74,7 @@ case $host_os in esac AC_ARG_ENABLE(uml, - AS_HELP_STRING([--disable-uml], [enable support for User Mode Linux]), + AS_HELP_STRING([--enable-uml], [enable support for User Mode Linux]), [ AS_IF([test "x$enable_uml" = "xyes"], [ AC_DEFINE(ENABLE_UML, 1, [Support for UML]) uml=true @@ -85,7 +85,7 @@ AC_ARG_ENABLE(uml, ) AC_ARG_ENABLE(vde, - AS_HELP_STRING([--disable-vde], [enable support for Virtual Distributed Ethernet]), + AS_HELP_STRING([--enable-vde], [enable support for Virtual Distributed Ethernet]), [ AS_IF([test "x$enable_vde" = "xyes"], [ AC_CHECK_HEADERS(libvdeplug_dyn.h, [], [AC_MSG_ERROR([VDE plug header files not found.]); break]) AC_DEFINE(ENABLE_VDE, 1, [Support for VDE]) @@ -97,7 +97,7 @@ AC_ARG_ENABLE(vde, ) AC_ARG_ENABLE(tunemu, - AS_HELP_STRING([--disable-tunemu], [enable support for the tunemu driver]), + AS_HELP_STRING([--enable-tunemu], [enable support for the tunemu driver]), [ AS_IF([test "x$enable_tunemu" = "xyes"], [ AC_DEFINE(ENABLE_TUNEMU, 1, [Support for tunemu]) tunemu=true @@ -179,11 +179,10 @@ AC_CACHE_SAVE dnl These are defined in files in m4/ -AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], []) +dnl AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], []) tinc_CURSES tinc_READLINE -tinc_LIBEVENT tinc_ZLIB tinc_LZO diff --git a/doc/Makefile.in b/doc/Makefile.in index 4610da9..3212126 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -53,10 +53,9 @@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in texinfo.tex ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ - $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.in + $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/lzo.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/doc/sample-config.tar.gz b/doc/sample-config.tar.gz index d7edc13..aa515c9 100644 Binary files a/doc/sample-config.tar.gz and b/doc/sample-config.tar.gz differ diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index f868c15..350a410 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -3,16 +3,13 @@ .\" Manual page created by: .\" Ivo Timmermans .\" Guus Sliepen - .Sh NAME .Nm tinc.conf .Nd tinc daemon configuration - .Sh DESCRIPTION The files in the .Pa @sysconfdir@/tinc/ directory contain runtime and security information for the tinc daemon. - .Sh NETWORKS To distinguish multiple instances of tinc running on one computer, you can use the @@ -44,31 +41,26 @@ the configuration file should be .Pa @sysconfdir@/tinc/tinc.conf , and the host configuration files are now expected to be in .Pa @sysconfdir@/tinc/hosts/ . - .Sh NAMES Each tinc daemon should have a name that is unique in the network which it will be part of. The name will be used by other tinc daemons for identification. The name has to be declared in the .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf file. - .Pp To make things easy, choose something that will give unique and easy to remember names to your tinc daemon(s). You could try things like hostnames, owner surnames or location names. However, you are only allowed to use alphanumerical characters (a-z, A-Z, and 0-9) and underscores (_) in the name. - .Sh INITIAL CONFIGURATION If you have not configured tinc yet, you can easily create a basic configuration using the following command: .Bd -literal -offset indent .Nm tincctl Fl n Ar NETNAME Li init Ar NAME .Ed - .Pp You can further change the configuration as needed either by manually editing the configuration files, or by using .Xr tincctl 8 . - .Sh PUBLIC/PRIVATE KEYS The .Nm tincctl Li init @@ -81,24 +73,20 @@ in the directory .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / The public keys should be stored in the host configuration file .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME . - The RSA keys are used for backwards compatibility with tinc version 1.0. If you are upgrading from version 1.0 to 1.1, you can keep the old configuration files, but you will need to create ECDSA keys using the following command: .Bd -literal -offset indent .Nm tincctl Fl n Ar NETNAME Li generate-ecdsa-keys .Ed - .Sh SERVER CONFIGURATION The server configuration of the daemon is done in the file .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf . This file consists of comments (lines started with a .Li # ) or assignments in the form of: - .Pp .Va Variable Li = Ar Value . - .Pp The variable names are case insensitive, and any spaces, tabs, newlines and carriage returns are ignored. @@ -106,31 +94,35 @@ Note: it is not required that you put in the .Li = sign, but doing so improves readability. If you leave it out, remember to replace it with at least one space character. - .Pp The server configuration is complemented with host specific configuration (see the next section). Although all configuration options for the local host listed in this document can also be put in .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf , it is recommended to put host specific configuration options in the host configuration file, as this makes it easy to exchange with other nodes. - .Pp You can edit the config file manually, but it is recommended that you use .Xr tincctl 8 to change configuration variables for you. - .Pp Here are all valid variables, listed in alphabetical order. The default value is given between parentheses. .Bl -tag -width indent - .It Va AddressFamily Li = ipv4 | ipv6 | any Pq any This option affects the address family of listening and outgoing sockets. If .Qq any is selected, then depending on the operating system both IPv4 and IPv6 or just IPv6 listening sockets will be created. - +.It Va AutoConnect Li = Ar count Po 0 Pc Bq experimental +If set to a non-zero value, +.Nm +will try to only have +.Ar count +meta connections to other nodes, +by automatically making or breaking connections to known nodes. +Higher values increase redundancy but also increase meta data overhead. +When using this option, a good value is 3. .It Va BindToAddress Li = Ar address Op Ar port If your computer has more than one IPv4 or IPv6 address, .Nm tinc @@ -149,38 +141,31 @@ To only bind to a specific port but not to a specific address, use .Li * for the .Ar address . - .It Va BindToInterface Li = Ar interface Bq experimental If your computer has more than one network interface, .Nm tinc will by default listen on all of them for incoming connections. It is possible to bind only to a single interface with this variable. - .Pp This option may not work on all platforms. Also, on some platforms it will not actually bind to an interface, but rather to the address that the interface has at the moment a socket is created. - .It Va Broadcast Li = no | mst | direct Po mst Pc Bq experimental This option selects the way broadcast packets are sent to other daemons. NOTE: all nodes in a VPN must use the same .Va Broadcast mode, otherwise routing loops can form. - .Bl -tag -width indent .It no Broadcast packets are never sent to other nodes. - .It mst Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree. This ensures broadcast packets reach all nodes. - .It direct Broadcast packets are sent directly to all nodes that can be reached directly. Broadcast packets received from other nodes are never forwarded. If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to. .El - .It Va ConnectTo Li = Ar name Specifies which other tinc daemon to connect to on startup. Multiple @@ -191,14 +176,12 @@ The names should be known to this tinc daemon (i.e., there should be a host configuration file for the name on the .Va ConnectTo line). - .Pp If you don't specify a host with .Va ConnectTo , .Nm tinc won't try to connect to other daemons at all, and will instead just listen for incoming connections. - .It Va DecrementTTL Li = yes | no Po no Pc Bq experimental When enabled, .Nm tinc @@ -208,7 +191,6 @@ and will drop packets that have a TTL value of zero, in which case it will send an ICMP Time Exceeded packet back. .Pp Do not use this option if you use switch mode and want to use IPv6. - .It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc The virtual network device to use. .Nm tinc @@ -220,18 +202,15 @@ instead of .Va Device . The info pages of the tinc package contain more information about configuring the virtual network device. - .It Va DeviceType Li = Ar type Pq platform dependent The type of the virtual network device. Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used. However, this option can be used to select one of the special interface types, if support for them is compiled in. .Bl -tag -width indent - .It dummy Use a dummy interface. No packets are ever read or written to a virtual network device. Useful for testing, or when setting up a node that only forwards packets for other nodes. - .It raw_socket Open a raw socket, and bind it to a pre-existing .Va Interface @@ -239,7 +218,6 @@ Open a raw socket, and bind it to a pre-existing All packets are read from this interface. Packets received for the local node are written to the raw socket. However, at least on Linux, the operating system does not process IP packets destined for the local host. - .It multicast Open a multicast UDP socket and bind it to the address and port (separated by spaces) and optionally a TTL value specified using .Va Device . @@ -249,7 +227,6 @@ Do NOT connect multiple .Nm tinc daemons to the same multicast address, this will very likely cause routing loops. Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured. - .It uml Pq not compiled in by default Create a UNIX socket with the filename specified by .Va Device , @@ -258,7 +235,6 @@ or if not specified. .Nm tinc will wait for a User Mode Linux instance to connect to this socket. - .It vde Pq not compiled in by default Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch, using the UNIX socket specified by @@ -267,46 +243,37 @@ or .Pa @localstatedir@/run/vde.ctl if not specified. .El - Also, in case tinc does not seem to correctly interpret packets received from the virtual network device, it can be used to change the way packets are interpreted: - .Bl -tag -width indent - .It tun Pq BSD and Linux Set type to tun. Depending on the platform, this can either be with or without an address family header (see below). - .It tunnohead Pq BSD Set type to tun without an address family header. Tinc will expect packets read from the virtual network device to start with an IP header. On some platforms IPv6 packets cannot be read from or written to the device in this mode. - .It tunifhead Pq BSD Set type to tun with an address family header. Tinc will expect packets read from the virtual network device to start with a four byte header containing the address family, followed by an IP header. This mode should support both IPv4 and IPv6 packets. - .It tap Pq BSD and Linux Set type to tap. Tinc will expect packets read from the virtual network device to start with an Ethernet header. .El - .It Va DirectOnly Li = yes | no Po no Pc Bq experimental When this option is enabled, packets that cannot be sent directly to the destination node, but which would have to be forwarded by an intermediate node, are dropped instead. When combined with the IndirectData option, packets for nodes for which we do not have a meta connection with are also dropped. - .It Va ECDSAPrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /ecdsa_key.priv Pc The file in which the private ECDSA key of this tinc daemon resides. This is only used if .Va ExperimentalProtocol is enabled. - .It Va ExperimentalProtocol Li = yes | no Po no Pc Bq experimental When this option is enabled, experimental protocol enhancements will be used. Ephemeral ECDH will be used for key exchanges, @@ -315,53 +282,31 @@ When enabled, an ECDSA key must have been generated before with .Nm tincctl generate-ecdsa-keys . The experimental protocol may change at any time, and there is no guarantee that tinc will run stable when it is used. - .It Va Forwarding Li = off | internal | kernel Po internal Pc Bq experimental This option selects the way indirect packets are forwarded. .Bl -tag -width indent - .It off Incoming packets that are not meant for the local node, but which should be forwarded to another node, are dropped. - .It internal Incoming packets that are meant for another node are forwarded by tinc internally. - .Pp This is the default mode, and unless you really know you need another forwarding mode, don't change it. - .It kernel Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node. This is less efficient, but allows the kernel to apply its routing and firewall rules on them, and can also help debugging. .El - -.It Va GraphDumpFile Li = Ar filename -If this option is present, -.Nm tinc -will dump the current network graph to the file -.Ar filename -every minute, unless there were no changes to the graph. -The file is in a format that can be read by graphviz tools. -If -.Ar filename -starts with a pipe symbol |, -then the rest of the filename is interpreted as a shell command -that is executed, the graph is then sent to stdin. - .It Va Hostnames Li = yes | no Pq no This option selects whether IP addresses (both real and on the VPN) should be resolved. Since DNS lookups are blocking, it might affect tinc's efficiency, even stopping the daemon for a few seconds every time it does a lookup if your DNS server is not responding. - .Pp This does not affect resolving hostnames to IP addresses from the host configuration files, but whether hostnames should be resolved while logging. - .It Va IffOneQueue Li = yes | no Po no Pc Bq experimental (Linux only) Set IFF_ONE_QUEUE flag on TUN/TAP devices. - .It Va Interface Li = Ar interface Defines the name of the interface corresponding to the virtual network device. Depending on the operating system and the type of device this may or may not actually set the name of the interface. @@ -369,12 +314,10 @@ Under Windows, this variable is used to select which network interface will be u If you specified a .Va Device , this variable is almost always already correctly set. - .It Va KeyExpire Li = Ar seconds Pq 3600 This option controls the period the encryption keys used to encrypt the data are valid. It is common practice to change keys at regular intervals to make it even harder for crackers, even though it is thought to be nearly impossible to crack a single key. - .It Va LocalDiscovery Li = yes | no Pq no When enabled, .Nm tinc @@ -382,54 +325,43 @@ will try to detect peers that are on the same local network. This will allow direct communication using LAN addresses, even if both peers are behind a NAT and they only ConnectTo a third node outside the NAT, which normally would prevent the peers from learning each other's LAN address. - .Pp Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery. This feature may not work in all possible situations. - .It Va MACExpire Li = Ar seconds Pq 600 This option controls the amount of time MAC addresses are kept before they are removed. This only has effect when .Va Mode is set to .Qq switch . - .It Va MaxTimeout Li = Ar seconds Pq 900 This is the maximum delay before trying to reconnect to other tinc daemons. - .It Va Mode Li = router | switch | hub Pq router This option selects the way packets are routed to other daemons. .Bl -tag -width indent - .It router In this mode .Va Subnet variables in the host configuration files will be used to form a routing table. Only unicast packets of routable protocols (IPv4 and IPv6) are supported in this mode. - .Pp This is the default mode, and unless you really know you need another mode, don't change it. - .It switch In this mode the MAC addresses of the packets on the VPN will be used to dynamically create a routing table just like an Ethernet switch does. Unicast, multicast and broadcast packets of every protocol that runs over Ethernet are supported in this mode at the cost of frequent broadcast ARP requests and routing table updates. - .Pp This mode is primarily useful if you want to bridge Ethernet segments. - .It hub This mode is almost the same as the switch mode, but instead every packet will be broadcast to the other daemons while no routing table is managed. .El - .It Va Name Li = Ar name Bq required This is the name which identifies this tinc daemon. It must be unique for the virtual private network this daemon will connect to. The Name may only consist of alphanumeric and underscore characters. - If .Va Name starts with a @@ -441,40 +373,28 @@ If is .Li $HOST , but no such environment variable exist, the hostname will be read using the gethostnname() system call. - .It Va PingInterval Li = Ar seconds Pq 60 The number of seconds of inactivity that .Nm tinc will wait before sending a probe to the other end. - .It Va PingTimeout Li = Ar seconds Pq 5 The number of seconds to wait for a response to pings or to allow meta connections to block. If the other end doesn't respond within this time, the connection is terminated, and the others will be notified of this. - .It Va PriorityInheritance Li = yes | no Po no Pc Bq experimental When this option is enabled the value of the TOS field of tunneled IPv4 packets will be inherited by the UDP packets that are sent out. - .It Va PrivateKey Li = Ar key Bq obsolete The private RSA key of this tinc daemon. It will allow this tinc daemon to authenticate itself to other daemons. - .It Va PrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv Pc The file in which the private RSA key of this tinc daemon resides. -Note that there must be exactly one of -.Va PrivateKey -or -.Va PrivateKeyFile -specified in the configuration file. - .It Va ProcessPriority Li = low | normal | high When this option is used the priority of the .Nm tincd process will be adjusted. Increasing the priority may help to reduce latency and packet loss on the VPN. - .It Va Proxy Li = socks4 | socks5 | http | exec Ar ... Bq experimental Use a proxy when making outgoing connections. The following proxy types are currently supported: @@ -507,7 +427,6 @@ and .Ev REMOTEPORT are available. .El - .It Va ReplayWindow Li = Ar bytes Pq 16 vhis is the size of the replay tracking window for each remote node, in bytes. The window is a bitfield which tracks 1 packet per bit, so for example @@ -517,35 +436,29 @@ the interaction of replay tracking with underlying real packet loss and/or reordering. Setting this to zero will disable replay tracking completely and pass all traffic, but leaves tinc vulnerable to replay-based attacks on your traffic. - .It Va StrictSubnets Li = yes | no Po no Pc Bq experimental When this option is enabled tinc will only use Subnet statements which are present in the host config files in the local .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ directory. - .It Va TunnelServer Li = yes | no Po no Pc Bq experimental When this option is enabled tinc will no longer forward information between other tinc daemons, and will only allow connections with nodes for which host config files are present in the local .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ directory. Setting this options also implicitly sets StrictSubnets. - .It Va UDPRcvBuf Li = Ar bytes Pq OS default Sets the socket receive buffer size for the UDP socket, in bytes. If unset, the default buffer size will be used by the operating system. - .It Va UDPSndBuf Li = Ar bytes Pq OS default Sets the socket send buffer size for the UDP socket, in bytes. If unset, the default buffer size will be used by the operating system. .El - .Sh HOST CONFIGURATION FILES The host configuration files contain all information needed to establish a connection to those hosts. A host configuration file is also required for the local tinc daemon, it will use it to read in it's listen port, public key and subnets. - .Pp The idea is that these files are portable. You can safely mail your own host configuration file to someone else. @@ -554,7 +467,6 @@ and now his tinc daemon will be able to connect to your tinc daemon. Since host configuration files only contain public keys, no secrets are revealed by sending out this information. .Bl -tag -width indent - .It Va Address Li = Ar address Oo Ar port Oc Bq recommended The IP address or hostname of this tinc daemon on the real network. This will only be used when trying to make an outgoing connection to this tinc daemon. @@ -563,7 +475,6 @@ Multiple .Va Address variables can be specified, in which case each address will be tried until a working connection has been established. - .It Va Cipher Li = Ar cipher Pq blowfish The symmetric cipher algorithm used to encrypt UDP packets. Any cipher supported by OpenSSL is recognised. @@ -571,24 +482,20 @@ Furthermore, specifying .Qq none will turn off packet encryption. It is best to use only those ciphers which support CBC mode. - .It Va ClampMSS Li = yes | no Pq yes This option specifies whether tinc should clamp the maximum segment size (MSS) of TCP packets to the path MTU. This helps in situations where ICMP Fragmentation Needed or Packet too Big messages are dropped by firewalls. - .It Va Compression Li = Ar level Pq 0 This option sets the level of compression used for UDP packets. Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib), 10 (fast lzo) and 11 (best lzo). - .It Va Digest Li = Ar digest Pq sha1 The digest algorithm used to authenticate UDP packets. Any digest supported by OpenSSL is recognised. Furthermore, specifying .Qq none will turn off packet authentication. - .It Va IndirectData Li = yes | no Pq no This option specifies whether other tinc daemons besides the one you specified with .Va ConnectTo @@ -596,33 +503,26 @@ can make a direct connection to you. This is especially useful if you are behind a firewall and it is impossible to make a connection from the outside to your tinc daemon. Otherwise, it is best to leave this option out or set it to no. - .It Va MACLength Li = Ar length Pq 4 The length of the message authentication code used to authenticate UDP packets. Can be anything from .Qq 0 up to the length of the digest produced by the digest algorithm. - .It Va PMTU Li = Ar mtu Po 1514 Pc This option controls the initial path MTU to this node. - .It Va PMTUDiscovery Li = yes | no Po yes Pc When this option is enabled, tinc will try to discover the path MTU to this node. After the path MTU has been discovered, it will be enforced on the VPN. - .It Va Port Li = Ar port Pq 655 The port number on which this tinc daemon is listening for incoming connections, which is used if no port number is specified in an .Va Address statement. - .It Va PublicKey Li = Ar key Bq obsolete The public RSA key of this tinc daemon. It will be used to cryptographically verify it's identity and to set up a secure connection. - .It Va PublicKeyFile Li = Ar filename Bq obsolete The file in which the public RSA key of this tinc daemon resides. - .Pp From version 1.0pre4 on .Nm tinc @@ -631,7 +531,6 @@ the above two options then are not necessary. Either the PEM format is used, or exactly one of the above two options must be specified in each host configuration file, if you want to be able to establish a connection with that host. - .It Va Subnet Li = Ar address Ns Op Li / Ns Ar prefixlength Ns Op Li # Ns Ar weight The subnet which this tinc daemon will serve. .Nm tinc @@ -641,7 +540,6 @@ it will be sent to the daemon who has this subnet in his host configuration file Multiple .Va Subnet variables can be specified. - .Pp Subnets can either be single MAC, IPv4 or IPv6 addresses, in which case a subnet consisting of only that single address is assumed, @@ -652,14 +550,12 @@ Note that subnets like 192.168.1.1/24 are invalid! Read a networking HOWTO/FAQ/guide if you don't understand this. IPv6 subnets are notated like fec0:0:0:1::/64. MAC addresses are notated like 0:1a:2b:3c:4d:5e. - .Pp A Subnet can be given a weight to indicate its priority over identical Subnets owned by different nodes. The default weight is 10. Lower values indicate higher priority. Packets will be sent to the node with the highest priority, unless that node is not reachable, in which case the node with the next highest priority will be tried, and so on. - .It Va TCPOnly Li = yes | no Pq no Bq obsolete If this variable is set to yes, then the packets are tunnelled over the TCP connection instead of a UDP connection. @@ -667,53 +563,42 @@ This is especially useful for those who want to run a tinc daemon from behind a masquerading firewall, or if UDP packet routing is disabled somehow. Setting this options also implicitly sets IndirectData. - .Pp Since version 1.0.10, tinc will automatically detect whether communication via UDP is possible or not. .El - .Sh SCRIPTS Apart from reading the server and host configuration files, tinc can also run scripts at certain moments. Under Windows (not Cygwin), the scripts should have the extension .Pa .bat . .Bl -tag -width indent - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up This is the most important script. If it is present it will be executed right after the tinc daemon has been started and has connected to the virtual network device. It should be used to set up the corresponding network interface, but can also be used to start other things. Under Windows you can use the Network Connections control panel instead of creating this script. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-down This script is started right before the tinc daemon quits. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Ar HOST Ns Pa -up This script is started when the tinc daemon with name .Ar HOST becomes reachable. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Ar HOST Ns Pa -down This script is started when the tinc daemon with name .Ar HOST becomes unreachable. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /host-up This script is started when any host becomes reachable. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /host-down This script is started when any host becomes unreachable. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /subnet-up This script is started when a Subnet becomes reachable. The Subnet and the node it belongs to are passed in environment variables. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /subnet-down This script is started when a Subnet becomes unreachable. .El - .Pp The scripts are started without command line arguments, but can make use of certain environment variables. Under UNIX like operating systems the names of environment variables must be preceded by a @@ -725,73 +610,55 @@ files, they have to be put between .Li % signs. .Bl -tag -width indent - .It Ev NETNAME If a netname was specified, this environment variable contains it. - .It Ev NAME Contains the name of this tinc daemon. - .It Ev DEVICE Contains the name of the virtual network device that tinc uses. - .It Ev INTERFACE Contains the name of the virtual network interface that tinc uses. This should be used for commands like .Pa ifconfig . - .It Ev NODE When a host becomes (un)reachable, this is set to its name. If a subnet becomes (un)reachable, this is set to the owner of that subnet. - .It Ev REMOTEADDRESS When a host becomes (un)reachable, this is set to its real address. - .It Ev REMOTEPORT When a host becomes (un)reachable, this is set to the port number it uses for communication with other tinc daemons. - .It Ev SUBNET When a subnet becomes (un)reachable, this is set to the subnet. - .It Ev WEIGHT When a subnet becomes (un)reachable, this is set to the subnet weight. .El - .Pp Do not forget that under UNIX operating systems, you have to make the scripts executable, using the command .Nm chmod Li a+x Pa script . - .Sh FILES The most important files are: .Bl -tag -width indent - .It Pa @sysconfdir@/tinc/ The top directory for configuration files. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf The default name of the server configuration file for net .Ar NETNAME . - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Host configuration files are kept in this directory. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up If an executable file with this name exists, it will be executed right after the tinc daemon has connected to the virtual network device. It can be used to set up the corresponding network interface. - .It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-down If an executable file with this name exists, it will be executed right before the tinc daemon is going to close its connection to the virtual network device. .El - .Sh SEE ALSO .Xr tincd 8 , .Xr tincctl 8 , .Pa http://www.tinc-vpn.org/ , .Pa http://www.tldp.org/LDP/nag2/ . - .Pp The full documentation for .Nm tinc @@ -799,7 +666,6 @@ is maintained as a Texinfo manual. If the info and tinc programs are properly installed at your site, the command .Ic info tinc should give you access to the complete manual. - .Pp .Nm tinc comes with ABSOLUTELY NO WARRANTY. diff --git a/doc/tinc.info b/doc/tinc.info index 8a95302..73343b8 100644 --- a/doc/tinc.info +++ b/doc/tinc.info @@ -5,7 +5,7 @@ START-INFO-DIR-ENTRY * tinc: (tinc). The tinc Manual. END-INFO-DIR-ENTRY - This is the info manual for tinc version 1.1pre2, a Virtual Private + This is the info manual for tinc version 1.1pre4, a Virtual Private Network daemon. Copyright (C) 1998-2012 Ivo Timmermans, Guus Sliepen @@ -295,7 +295,8 @@ an error message, and stop. * OpenSSL:: * zlib:: * lzo:: -* libevent:: +* libcurses:: +* libreadline::  File: tinc.info, Node: OpenSSL, Next: zlib, Up: Libraries @@ -307,8 +308,8 @@ For all cryptography-related functions, tinc uses the functions provided by the OpenSSL library. If this library is not installed, you wil get an error when -configuring tinc for build. Support for running tinc without having -OpenSSL installed _may_ be added in the future. +configuring tinc for build. Support for running tinc with other +cryptographic libraries installed _may_ be added in the future. You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime @@ -363,9 +364,12 @@ File: tinc.info, Node: zlib, Next: lzo, Prev: OpenSSL, Up: Libraries For the optional compression of UDP packets, tinc uses the functions provided by the zlib library. - If this library is not installed, you wil get an error when -configuring tinc for build. Support for running tinc without having -zlib installed _may_ be added in the future. + If this library is not installed, you wil get an error when running +the configure script. You can either install the zlib library, or +disable support for zlib compression by using the "-disable-zlib" +option when running the configure script. Note that if you disable +support for zlib, the resulting binary will not work correctly on VPNs +where zlib compression is used. You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime @@ -378,16 +382,19 @@ make sure you build development and runtime libraries (which is the default).  -File: tinc.info, Node: lzo, Next: libevent, Prev: zlib, Up: Libraries +File: tinc.info, Node: lzo, Next: libcurses, Prev: zlib, Up: Libraries 2.2.3 lzo --------- -Another form of compression is offered using the lzo library. +Another form of compression is offered using the LZO library. - If this library is not installed, you wil get an error when -configuring tinc for build. Support for running tinc without having lzo -installed _may_ be added in the future. + If this library is not installed, you wil get an error when running +the configure script. You can either install the LZO library, or +disable support for LZO compression by using the "-disable-lzo" option +when running the configure script. Note that if you disable support for +LZO, the resulting binary will not work correctly on VPNs where LZO +compression is used. You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime @@ -400,24 +407,52 @@ package. Please make sure you build development and runtime libraries (which is the default).  -File: tinc.info, Node: libevent, Prev: lzo, Up: Libraries +File: tinc.info, Node: libcurses, Next: libreadline, Prev: lzo, Up: Libraries -2.2.4 libevent --------------- +2.2.4 libcurses +--------------- -For the main event loop, tinc uses the libevent library. +For the "tincctl top" command, tinc requires a curses library. - If this library is not installed, you wil get an error when -configuring tinc for build. + If this library is not installed, you wil get an error when running +the configure script. You can either install a suitable curses +library, or disable all functionality that depends on a curses library +by using the "-disable-curses" option when running the configure script. + + There are several curses libraries. It is recommended that you +install "ncurses" (`http://invisible-island.net/ncurses/'), however +other curses libraries should also work. In particular, "PDCurses" +(`http://pdcurses.sourceforge.net/') is recommended if you want to +compile tinc for Windows. + + You can use your operating system's package manager to install this +if available. Make sure you install the development AND runtime versions +of this package. + + +File: tinc.info, Node: libreadline, Prev: libcurses, Up: Libraries + +2.2.5 libreadline +----------------- + +For the "tincctl" command's shell functionality, tinc uses the readline +library. + + If this library is not installed, you wil get an error when running +the configure script. You can either install a suitable readline +library, or disable all functionality that depends on a readline +library by using the "-disable-readline" option when running the +configure script. You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime versions of this package. - If you have to install libevent manually, you can get the source code -from `http://libevent.org/'. Instructions on how to configure, build -and install this package are included within the package. Please make -sure you build development and runtime libraries (which is the default). + If you have to install libreadline manually, you can get the source +code from `http://www.gnu.org/software/readline/'. Instructions on how +to configure, build and install this package are included within the +package. Please make sure you build development and runtime libraries +(which is the default).  File: tinc.info, Node: Installation, Next: Configuration, Prev: Preparations, Up: Top @@ -738,6 +773,13 @@ AddressFamily = (any) system both IPv4 and IPv6 or just IPv6 listening sockets will be created. +AutoConnect = (0) [experimental] + If set to a non-zero value, tinc will try to only have count meta + connections to other nodes, by automatically making or breaking + connections to known nodes. Higher values increase redundancy but + also increase meta data overhead. When using this option, a good + value is 3. + BindToAddress =
[] If your computer has more than one IPv4 or IPv6 address, tinc will by default listen on all of them for incoming connections. @@ -912,14 +954,6 @@ Forwarding = (internal) [experimental] efficient, but allows the kernel to apply its routing and firewall rules on them, and can also help debugging. -GraphDumpFile = - If this option is present, tinc will dump the current network - graph to the file FILENAME every minute, unless there were no - changes to the graph. The file is in a format that can be read by - graphviz tools. If FILENAME starts with a pipe symbol |, then the - rest of the filename is interpreted as a shell command that is - executed, the graph is then sent to stdin. - Hostnames = (no) This option selects whether IP addresses (both real and on the VPN) should be resolved. Since DNS lookups are blocking, it might @@ -1026,9 +1060,6 @@ PrivateKeyFile = (`/etc/tinc/NETNAME/rsa_key.priv') generated by `tincctl generate-keys'. It must be a full path, not a relative directory. - Note that there must be exactly one of PrivateKey or PrivateKeyFile - specified in the configuration file. - ProcessPriority = When this option is used the priority of the tincd process will be adjusted. Increasing the priority may help to reduce latency and @@ -2073,8 +2104,9 @@ File: tinc.info, Node: tincctl commands, Next: tincctl examples, Prev: tincct store the files, but will default to the configuration directory (you can use the -c or -n option). -`dump nodes' - Dump a list of all known nodes in the VPN. +`dump [reachable] nodes' + Dump a list of all known nodes in the VPN. If the reachable + keyword is used, only lists reachable nodes. `dump edges' Dump a list of all known connections in the VPN. @@ -2792,14 +2824,16 @@ Concept Index * ANS_KEY: The meta-protocol. (line 64) * authentication: Authentication protocol. (line 6) +* AutoConnect: Main configuration variables. + (line 12) * binary package: Building and installing tinc. (line 9) * BindToAddress: Main configuration variables. - (line 12) + (line 19) * BindToInterface: Main configuration variables. - (line 23) + (line 30) * Broadcast: Main configuration variables. - (line 34) + (line 41) * Cabal: Security. (line 6) * CHAL_REPLY: Authentication protocol. (line 10) @@ -2818,29 +2852,29 @@ Concept Index (line 24) * connection: The connection. (line 6) * ConnectTo: Main configuration variables. - (line 54) + (line 61) * daemon: Running tinc. (line 11) * data-protocol: The meta-connection. (line 18) * debug level: Runtime options. (line 17) * debug levels: Debug levels. (line 6) * DecrementTTL: Main configuration variables. - (line 65) + (line 72) * DEL_EDGE: The meta-protocol. (line 47) * DEL_SUBNET: The meta-protocol. (line 47) * DEVICE: Scripts. (line 55) * Device: Main configuration variables. - (line 74) + (line 81) * device files: Device files. (line 6) * DeviceType: Main configuration variables. - (line 81) + (line 88) * Digest: Host configuration variables. (line 29) * DirectOnly: Main configuration variables. - (line 146) -* dummy: Main configuration variables. - (line 88) -* ECDSAPrivateKeyFile: Main configuration variables. (line 153) +* dummy: Main configuration variables. + (line 95) +* ECDSAPrivateKeyFile: Main configuration variables. + (line 160) * encapsulating: The UDP tunnel. (line 30) * encryption: Encryption of network packets. (line 6) @@ -2848,52 +2882,51 @@ Concept Index * example: Example configuration. (line 6) * exec: Main configuration variables. - (line 326) + (line 322) * ExperimentalProtocol: Main configuration variables. - (line 157) + (line 164) * Forwarding: Main configuration variables. - (line 166) + (line 173) * frame type: The UDP tunnel. (line 6) -* GraphDumpFile: Main configuration variables. - (line 186) * Hostnames: Main configuration variables. - (line 194) + (line 193) * http: Main configuration variables. - (line 323) + (line 319) * hub: Main configuration variables. - (line 247) + (line 246) * ID: Authentication protocol. (line 10) * IndirectData: Host configuration variables. (line 34) * INTERFACE: Scripts. (line 58) * Interface: Main configuration variables. - (line 205) + (line 204) * IRC: Contact information. (line 9) * KEY_CHANGED: The meta-protocol. (line 64) * KeyExpire: Main configuration variables. - (line 252) -* libevent: libevent. (line 6) + (line 251) +* libcurses: libcurses. (line 6) * libraries: Libraries. (line 6) +* libreadline: libreadline. (line 6) * license: OpenSSL. (line 36) * LocalDiscovery: Main configuration variables. - (line 213) + (line 212) * lzo: lzo. (line 6) * MACExpire: Main configuration variables. - (line 258) + (line 257) * MACLength: Host configuration variables. (line 42) * meta-protocol: The meta-connection. (line 18) * META_KEY: Authentication protocol. (line 10) * Mode: Main configuration variables. - (line 224) + (line 223) * multicast: Main configuration variables. - (line 100) + (line 107) * multiple networks: Multiple networks. (line 6) * NAME: Scripts. (line 52) * Name: Main configuration variables. - (line 263) + (line 262) * netmask: Network interfaces. (line 39) * NETNAME <1>: tincctl environment variables. (line 6) @@ -2908,9 +2941,9 @@ Concept Index (line 67) * PING: The meta-protocol. (line 89) * PingInterval: Main configuration variables. - (line 274) + (line 273) * PingTimeout: Main configuration variables. - (line 278) + (line 277) * platforms: Supported platforms. (line 6) * PMTU: Host configuration variables. (line 47) @@ -2921,32 +2954,32 @@ Concept Index (line 55) * port numbers: Other files. (line 17) * PriorityInheritance: Main configuration variables. - (line 284) + (line 283) * private: Virtual Private Networks. (line 10) * PrivateKey: Main configuration variables. - (line 289) + (line 288) * PrivateKeyFile: Main configuration variables. - (line 295) + (line 294) * ProcessPriority: Main configuration variables. - (line 303) + (line 299) * Proxy: Main configuration variables. - (line 308) + (line 304) * PublicKey: Host configuration variables. (line 59) * PublicKeyFile: Host configuration variables. (line 62) * raw_socket: Main configuration variables. - (line 93) + (line 100) * release: Supported platforms. (line 14) * REMOTEADDRESS: Scripts. (line 67) * REMOTEPORT: Scripts. (line 70) * ReplayWindow: Main configuration variables. - (line 331) + (line 327) * REQ_KEY: The meta-protocol. (line 64) * requirements: Libraries. (line 6) * router: Main configuration variables. - (line 227) + (line 226) * runtime options: Runtime options. (line 9) * scalability: tinc. (line 19) * scripts: Scripts. (line 6) @@ -2954,17 +2987,17 @@ Concept Index (line 18) * signals: Signals. (line 6) * socks4: Main configuration variables. - (line 312) + (line 308) * socks5: Main configuration variables. - (line 317) + (line 313) * StrictSubnets: Main configuration variables. - (line 342) + (line 338) * SUBNET: Scripts. (line 74) * Subnet: Host configuration variables. (line 74) * SVPN: Security. (line 11) * switch: Main configuration variables. - (line 236) + (line 235) * TCP: The meta-connection. (line 10) * TCPonly: Host configuration variables. (line 103) @@ -2976,24 +3009,24 @@ Concept Index * tincd: tinc. (line 14) * traditional VPNs: tinc. (line 19) * tunifhead: Main configuration variables. - (line 135) + (line 142) * TunnelServer: Main configuration variables. - (line 347) + (line 343) * tunnohead: Main configuration variables. - (line 129) + (line 136) * UDP <1>: Encryption of network packets. (line 12) * UDP: The UDP tunnel. (line 30) * UDPRcvBuf: Main configuration variables. - (line 354) + (line 350) * UDPSndBuf: Main configuration variables. - (line 359) + (line 355) * UML: Main configuration variables. - (line 111) + (line 118) * Universal tun/tap: Configuration of Linux kernels. (line 6) * VDE: Main configuration variables. - (line 116) + (line 123) * virtual: Virtual Private Networks. (line 18) * virtual network device: The UDP tunnel. (line 6) @@ -3021,57 +3054,58 @@ Node: Configuration of Solaris kernels8891 Node: Configuration of Darwin (MacOS/X) kernels9552 Node: Configuration of Windows10241 Node: Libraries10755 -Node: OpenSSL11156 -Node: zlib13432 -Node: lzo14261 -Node: libevent15065 -Node: Installation15760 -Node: Building and installing tinc16776 -Node: Darwin (MacOS/X) build environment17435 -Node: Cygwin (Windows) build environment18002 -Node: MinGW (Windows) build environment18590 -Node: System files19114 -Node: Device files19379 -Node: Other files19795 -Node: Configuration20408 -Node: Configuration introduction20695 -Node: Multiple networks22242 -Node: How connections work23622 -Node: Configuration files26195 -Node: Main configuration variables27728 -Node: Host configuration variables44334 -Node: Scripts49564 -Node: How to configure52243 -Node: Network interfaces56861 -Node: Example configuration59262 -Node: Running tinc64414 -Node: Runtime options65007 -Node: Signals67711 -Node: Debug levels68561 -Node: Solving problems69497 -Node: Error messages70927 -Node: Sending bug reports75249 -Node: Controlling tinc76201 -Node: tincctl runtime options76598 -Node: tincctl environment variables77297 -Node: tincctl commands77641 -Node: tincctl examples81866 -Node: tincctl top82471 -Node: Technical information84069 -Node: The connection84304 -Node: The UDP tunnel84616 -Node: The meta-connection87677 -Node: The meta-protocol89146 -Node: Security94155 -Node: Authentication protocol95285 -Node: Encryption of network packets100289 -Node: Security issues101662 -Node: Platform specific information103279 -Node: Interface configuration103507 -Node: Routes105960 -Node: About us107876 -Node: Contact information108051 -Node: Authors108455 -Node: Concept Index108860 +Node: OpenSSL11173 +Node: zlib13461 +Node: lzo14487 +Node: libcurses15485 +Node: libreadline16405 +Node: Installation17353 +Node: Building and installing tinc18369 +Node: Darwin (MacOS/X) build environment19028 +Node: Cygwin (Windows) build environment19595 +Node: MinGW (Windows) build environment20183 +Node: System files20707 +Node: Device files20972 +Node: Other files21388 +Node: Configuration22001 +Node: Configuration introduction22288 +Node: Multiple networks23835 +Node: How connections work25215 +Node: Configuration files27788 +Node: Main configuration variables29321 +Node: Host configuration variables45731 +Node: Scripts50961 +Node: How to configure53640 +Node: Network interfaces58258 +Node: Example configuration60659 +Node: Running tinc65811 +Node: Runtime options66404 +Node: Signals69108 +Node: Debug levels69958 +Node: Solving problems70894 +Node: Error messages72324 +Node: Sending bug reports76646 +Node: Controlling tinc77598 +Node: tincctl runtime options77995 +Node: tincctl environment variables78694 +Node: tincctl commands79038 +Node: tincctl examples83343 +Node: tincctl top83948 +Node: Technical information85546 +Node: The connection85781 +Node: The UDP tunnel86093 +Node: The meta-connection89154 +Node: The meta-protocol90623 +Node: Security95632 +Node: Authentication protocol96762 +Node: Encryption of network packets101766 +Node: Security issues103139 +Node: Platform specific information104756 +Node: Interface configuration104984 +Node: Routes107437 +Node: About us109353 +Node: Contact information109528 +Node: Authors109932 +Node: Concept Index110337  End Tag Table diff --git a/doc/tinc.texi b/doc/tinc.texi index ac3a630..0e2b1eb 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -339,7 +339,8 @@ having them installed, configure will give you an error message, and stop. * OpenSSL:: * zlib:: * lzo:: -* libevent:: +* libcurses:: +* libreadline:: @end menu @@ -352,7 +353,7 @@ For all cryptography-related functions, tinc uses the functions provided by the OpenSSL library. If this library is not installed, you wil get an error when configuring -tinc for build. Support for running tinc without having OpenSSL +tinc for build. Support for running tinc with other cryptographic libraries installed @emph{may} be added in the future. You can use your operating system's package manager to install this if @@ -415,9 +416,11 @@ Markus F.X.J. Oberhumer For the optional compression of UDP packets, tinc uses the functions provided by the zlib library. -If this library is not installed, you wil get an error when configuring -tinc for build. Support for running tinc without having zlib -installed @emph{may} be added in the future. +If this library is not installed, you wil get an error when running the +configure script. You can either install the zlib library, or disable support +for zlib compression by using the "--disable-zlib" option when running the +configure script. Note that if you disable support for zlib, the resulting +binary will not work correctly on VPNs where zlib compression is used. You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime versions @@ -435,11 +438,13 @@ default). @subsection lzo @cindex lzo -Another form of compression is offered using the lzo library. +Another form of compression is offered using the LZO library. -If this library is not installed, you wil get an error when configuring -tinc for build. Support for running tinc without having lzo -installed @emph{may} be added in the future. +If this library is not installed, you wil get an error when running the +configure script. You can either install the LZO library, or disable support +for LZO compression by using the "--disable-lzo" option when running the +configure script. Note that if you disable support for LZO, the resulting +binary will not work correctly on VPNs where LZO compression is used. You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime versions @@ -453,24 +458,48 @@ default). @c ================================================================== -@node libevent -@subsection libevent +@node libcurses +@subsection libcurses -@cindex libevent -For the main event loop, tinc uses the libevent library. +@cindex libcurses +For the "tincctl top" command, tinc requires a curses library. -If this library is not installed, you wil get an error when configuring -tinc for build. +If this library is not installed, you wil get an error when running the +configure script. You can either install a suitable curses library, or disable +all functionality that depends on a curses library by using the +"--disable-curses" option when running the configure script. + +There are several curses libraries. It is recommended that you install +"ncurses" (@url{http://invisible-island.net/ncurses/}), +however other curses libraries should also work. +In particular, "PDCurses" (@url{http://pdcurses.sourceforge.net/}) +is recommended if you want to compile tinc for Windows. + +You can use your operating system's package manager to install this if +available. Make sure you install the development AND runtime versions +of this package. + + +@c ================================================================== +@node libreadline +@subsection libreadline + +@cindex libreadline +For the "tincctl" command's shell functionality, tinc uses the readline library. + +If this library is not installed, you wil get an error when running the +configure script. You can either install a suitable readline library, or +disable all functionality that depends on a readline library by using the +"--disable-readline" option when running the configure script. You can use your operating system's package manager to install this if available. Make sure you install the development AND runtime versions of this package. -If you have to install libevent manually, you can get the source code -from @url{http://libevent.org/}. Instructions on how to configure, -build and install this package are included within the package. Please -make sure you build development and runtime libraries (which is the -default). +If you have to install libreadline manually, you can get the source code from +@url{http://www.gnu.org/software/readline/}. Instructions on how to configure, +build and install this package are included within the package. Please make +sure you build development and runtime libraries (which is the default). @c @@ -805,6 +834,14 @@ This option affects the address family of listening and outgoing sockets. If any is selected, then depending on the operating system both IPv4 and IPv6 or just IPv6 listening sockets will be created. +@cindex AutoConnect +@item AutoConnect = (0) [experimental] +If set to a non-zero value, +tinc will try to only have count meta connections to other nodes, +by automatically making or breaking connections to known nodes. +Higher values increase redundancy but also increase meta data overhead. +When using this option, a good value is 3. + @cindex BindToAddress @item BindToAddress = <@var{address}> [<@var{port}>] If your computer has more than one IPv4 or IPv6 address, tinc @@ -990,16 +1027,6 @@ This is less efficient, but allows the kernel to apply its routing and firewall and can also help debugging. @end table -@cindex GraphDumpFile -@item GraphDumpFile = <@var{filename}> -If this option is present, -tinc will dump the current network graph to the file @var{filename} -every minute, unless there were no changes to the graph. -The file is in a format that can be read by graphviz tools. -If @var{filename} starts with a pipe symbol |, -then the rest of the filename is interpreted as a shell command -that is executed, the graph is then sent to stdin. - @cindex Hostnames @item Hostnames = (no) This option selects whether IP addresses (both real and on the VPN) @@ -1106,10 +1133,6 @@ This is the full path name of the RSA private key file that was generated by @samp{tincctl generate-keys}. It must be a full path, not a relative directory. -Note that there must be exactly one of PrivateKey -or PrivateKeyFile -specified in the configuration file. - @cindex ProcessPriority @item ProcessPriority = When this option is used the priority of the tincd process will be adjusted. @@ -2199,8 +2222,9 @@ Generate public/private keypair of @var{bits} length. If @var{bits} is not speci but will default to the configuration directory (you can use the -c or -n option). -@item dump nodes +@item dump [reachable] nodes Dump a list of all known nodes in the VPN. +If the reachable keyword is used, only lists reachable nodes. @item dump edges Dump a list of all known connections in the VPN. diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in index 3834323..8fdd272 100644 --- a/doc/tincctl.8.in +++ b/doc/tincctl.8.in @@ -45,7 +45,6 @@ If no netname is specified on the command line with the option, the value of this environment variable is used. .El .Sh COMMANDS -.zZ .Bl -tag -width indent .It init Op Ar name Create initial configuration files and RSA and ECDSA keypairs with default length. @@ -115,9 +114,9 @@ If is omitted, the default length will be 2048 bits. When saving keys to existing files, tinc will not delete the old keys; you have to remove them manually. - -.It dump nodes +.It dump [reachable] nodes Dump a list of all known nodes in the VPN. +If the keyword reachable is used, only lists reachable nodes. .It dump edges Dump a list of all known connections in the VPN. .It dump subnets @@ -190,6 +189,7 @@ tincctl -n vpn config Subnet 192.168.1.0/24 tincctl -n vpn config bar.Address bar.example.com tincctl -n vpn config ConnectTo bar tincctl -n vpn export | gpg --clearsign | mail -s "My config" vpnmaster@example.com +.Ed .Sh TOP The top command connects to a running tinc daemon and repeatedly queries its per-node traffic counters. It displays a list of all the known nodes in the left-most column, diff --git a/gui/Makefile.in b/gui/Makefile.in index 2d08ef7..2e52de5 100644 --- a/gui/Makefile.in +++ b/gui/Makefile.in @@ -56,10 +56,9 @@ DIST_COMMON = $(dist_bin_SCRIPTS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ - $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.in + $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/lzo.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/have.h b/have.h index d040717..6d65bcd 100644 --- a/have.h +++ b/have.h @@ -196,10 +196,6 @@ #include #endif -#ifdef HAVE_EVENT_H -#include -#endif - #ifdef HAVE_MINGW #define SLASH "\\" #else diff --git a/m4/Makefile.in b/m4/Makefile.in index 8f1372a..557ba46 100644 --- a/m4/Makefile.in +++ b/m4/Makefile.in @@ -54,10 +54,9 @@ subdir = m4 DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ - $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.in + $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/lzo.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/m4/libevent.m4 b/m4/libevent.m4 deleted file mode 100644 index 34bdef7..0000000 --- a/m4/libevent.m4 +++ /dev/null @@ -1,33 +0,0 @@ -dnl Check to find the libevent headers/libraries - -AC_DEFUN([tinc_LIBEVENT], -[ - AC_ARG_WITH(libevent, - AS_HELP_STRING([--with-libevent=DIR], [libevent base directory, or:]), - [libevent="$withval" - CPPFLAGS="$CPPFLAGS -I$withval/include" - LDFLAGS="$LDFLAGS -L$withval/lib"] - ) - - AC_ARG_WITH(libevent-include, - AS_HELP_STRING([--with-libevent-include=DIR], [libevent headers directory]), - [libevent_include="$withval" - CPPFLAGS="$CPPFLAGS -I$withval"] - ) - - AC_ARG_WITH(libevent-lib, - AS_HELP_STRING([--with-libevent-lib=DIR], [libevent library directory]), - [libevent_lib="$withval" - LDFLAGS="$LDFLAGS -L$withval"] - ) - - AC_CHECK_HEADERS(event.h, - [], - [AC_MSG_ERROR("libevent header files not found."); break] - ) - - AC_CHECK_LIB(event, event_init, - [LIBS="-levent $LIBS"], - [AC_MSG_ERROR("libevent libraries not found.")] - ) -]) diff --git a/src/Makefile.am b/src/Makefile.am index 3bd8646..6a8737b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,7 @@ tincd_SOURCES = \ utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c \ buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \ net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \ - protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c tincd.c \ + protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c event.c tincd.c \ dummy_device.c raw_socket_device.c multicast_device.c if UML @@ -46,7 +46,7 @@ INCLUDES = @INCLUDES@ -I$(top_builddir) noinst_HEADERS = \ xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \ buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \ - protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h + protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h event.h nodist_noinst_HEADERS = \ cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h diff --git a/src/Makefile.in b/src/Makefile.in index d2a972b..37eaa7c 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -62,10 +62,9 @@ DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \ - $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libevent.m4 \ - $(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/openssl.m4 \ - $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/zlib.m4 \ - $(top_srcdir)/configure.in + $(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/lzo.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \ + $(top_srcdir)/m4/zlib.m4 $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -95,8 +94,8 @@ am__tincd_SOURCES_DIST = utils.c getopt.c getopt1.c list.c \ netutl.c node.c process.c protocol.c protocol_auth.c \ protocol_edge.c protocol_misc.c protocol_key.c \ protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c \ - tincd.c dummy_device.c raw_socket_device.c multicast_device.c \ - uml_device.c vde_device.c bsd/tunemu.c + event.c tincd.c dummy_device.c raw_socket_device.c \ + multicast_device.c uml_device.c vde_device.c bsd/tunemu.c @UML_TRUE@am__objects_1 = uml_device.$(OBJEXT) @VDE_TRUE@am__objects_2 = vde_device.$(OBJEXT) @TUNEMU_TRUE@am__objects_3 = tunemu.$(OBJEXT) @@ -112,9 +111,10 @@ am_tincd_OBJECTS = utils.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \ protocol_edge.$(OBJEXT) protocol_misc.$(OBJEXT) \ protocol_key.$(OBJEXT) protocol_subnet.$(OBJEXT) \ route.$(OBJEXT) sptps.$(OBJEXT) subnet.$(OBJEXT) \ - subnet_parse.$(OBJEXT) tincd.$(OBJEXT) dummy_device.$(OBJEXT) \ - raw_socket_device.$(OBJEXT) multicast_device.$(OBJEXT) \ - $(am__objects_1) $(am__objects_2) $(am__objects_3) + subnet_parse.$(OBJEXT) event.$(OBJEXT) tincd.$(OBJEXT) \ + dummy_device.$(OBJEXT) raw_socket_device.$(OBJEXT) \ + multicast_device.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) nodist_tincd_OBJECTS = device.$(OBJEXT) cipher.$(OBJEXT) \ crypto.$(OBJEXT) ecdh.$(OBJEXT) ecdsa.$(OBJEXT) \ digest.$(OBJEXT) prf.$(OBJEXT) rsa.$(OBJEXT) @@ -251,7 +251,7 @@ tincd_SOURCES = utils.c getopt.c getopt1.c list.c splay_tree.c \ net.c net_packet.c net_setup.c net_socket.c netutl.c node.c \ process.c protocol.c protocol_auth.c protocol_edge.c \ protocol_misc.c protocol_key.c protocol_subnet.c route.c \ - sptps.c subnet.c subnet_parse.c tincd.c dummy_device.c \ + sptps.c subnet.c subnet_parse.c event.c tincd.c dummy_device.c \ raw_socket_device.c multicast_device.c $(am__append_1) \ $(am__append_2) $(am__append_3) nodist_tincd_SOURCES = \ @@ -273,7 +273,7 @@ DEFAULT_INCLUDES = noinst_HEADERS = \ xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \ buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \ - protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h + protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h event.h nodist_noinst_HEADERS = \ cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h @@ -383,6 +383,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecdsagen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edge.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getaddrinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getnameinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ diff --git a/src/connection.c b/src/connection.c index d39f43f..4798c5a 100644 --- a/src/connection.c +++ b/src/connection.c @@ -68,11 +68,7 @@ void free_connection(connection_t *c) { buffer_clear(&c->inbuf); buffer_clear(&c->outbuf); - if(event_initialized(&c->inevent)) - event_del(&c->inevent); - - if(event_initialized(&c->outevent)) - event_del(&c->outevent); + io_del(&c->io); if(c->socket > 0) closesocket(c->socket); diff --git a/src/connection.h b/src/connection.h index 01c2bf4..10f4a76 100644 --- a/src/connection.h +++ b/src/connection.h @@ -90,8 +90,7 @@ typedef struct connection_t { struct buffer_t inbuf; struct buffer_t outbuf; - struct event inevent; /* input event on this metadata connection */ - struct event outevent; /* output event on this metadata connection */ + io_t io; /* input/output event on this metadata connection */ int tcplen; /* length of incoming TCPpacket */ int allow_request; /* defined if there's only one request possible */ diff --git a/src/control.c b/src/control.c index c166943..83a9d79 100644 --- a/src/control.c +++ b/src/control.c @@ -58,7 +58,7 @@ bool control_h(connection_t *c, const char *request) { switch (type) { case REQ_STOP: - event_loopexit(NULL); + event_exit(); return control_ok(c, REQ_STOP); case REQ_DUMP_NODES: @@ -156,7 +156,7 @@ bool init_control(void) { // Make sure we have a valid address, and map 0.0.0.0 and :: to 127.0.0.1 and ::1. - if(getsockname(listen_socket[0].tcp, (struct sockaddr *)&sa, &len)) { + if(getsockname(listen_socket[0].tcp.fd, (struct sockaddr *)&sa, &len)) { xasprintf(&localhost, "127.0.0.1 port %d", myport); } else { if(sa.sa.sa_family == AF_INET) { diff --git a/src/dropin.h b/src/dropin.h index c6cabba..61143eb 100644 --- a/src/dropin.h +++ b/src/dropin.h @@ -45,4 +45,22 @@ extern int gettimeofday(struct timeval *, void *); extern int usleep(long long usec); #endif +#ifndef timeradd +#define timeradd(a, b, r) do {\ + (r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\ + (r)->tv_usec = (a)->tv_usec + (b)->tv_usec;\ + if((r)->tv_usec >= 1000000)\ + (r)->tv_sec++, (r)->tv_usec -= 1000000;\ +} while (0) +#endif + +#ifndef timersub +#define timersub(a, b, r) do {\ + (r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\ + (r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\ + if((r)->tv_usec < 1000000)\ + (r)->tv_sec--, (r)->tv_usec += 1000000;\ +} while (0) +#endif + #endif /* __DROPIN_H__ */ diff --git a/src/ethernet.h b/src/ethernet.h index b759ab3..a8b6420 100644 --- a/src/ethernet.h +++ b/src/ethernet.h @@ -41,6 +41,10 @@ #define ETH_P_IPV6 0x86DD #endif +#ifndef ETH_P_8021Q +#define ETH_P_8021Q 0x8100 +#endif + #ifndef HAVE_STRUCT_ETHER_HEADER struct ether_header { uint8_t ether_dhost[ETH_ALEN]; diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..0dde994 --- /dev/null +++ b/src/event.c @@ -0,0 +1,250 @@ +/* + event.c -- I/O, timeout and signal event handling + Copyright (C) 2012 Guus Sliepen + + 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. +*/ + +#include "system.h" + +#include "dropin.h" +#include "event.h" +#include "net.h" +#include "utils.h" + +struct timeval now; + +static fd_set readfds; +static fd_set writefds; +static volatile bool running; + +static int io_compare(const io_t *a, const io_t *b) { + return a->fd - b->fd; +} + +static int timeout_compare(const timeout_t *a, const timeout_t *b) { + struct timeval diff; + timersub(&a->tv, &b->tv, &diff); + if(diff.tv_sec < 0) + return -1; + if(diff.tv_sec > 0) + return 1; + if(diff.tv_usec < 0) + return -1; + if(diff.tv_usec > 0) + return 1; + if(a < b) + return -1; + if(a > b) + return 1; + return 0; +} + +static int signal_compare(const signal_t *a, const signal_t *b) { + return a->signum - b->signum; +} + +static splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare}; +static splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare}; +static splay_tree_t signal_tree = {.compare = (splay_compare_t)signal_compare}; + +void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) { + if(io->cb) + return; + + io->fd = fd; + io->cb = cb; + io->data = data; + io->node.data = io; + + io_set(io, flags); + + if(!splay_insert_node(&io_tree, &io->node)) + abort(); +} + +void io_set(io_t *io, int flags) { + io->flags = flags; + + if(flags & IO_READ) + FD_SET(io->fd, &readfds); + else + FD_CLR(io->fd, &readfds); + + if(flags & IO_WRITE) + FD_SET(io->fd, &writefds); + else + FD_CLR(io->fd, &writefds); +} + +void io_del(io_t *io) { + if(!io->cb) + return; + + io_set(io, 0); + + splay_unlink_node(&io_tree, &io->node); + io->cb = NULL; +} + +void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) { + timeout->cb = cb; + timeout->data = data; + timeout->node.data = timeout; + + timeout_set(timeout, tv); +} + +void timeout_set(timeout_t *timeout, struct timeval *tv) { + if(timerisset(&timeout->tv)) + splay_unlink_node(&timeout_tree, &timeout->node); + + if(!now.tv_sec) + gettimeofday(&now, NULL); + + timeradd(&now, tv, &timeout->tv); + + if(!splay_insert_node(&timeout_tree, &timeout->node)) + abort(); +} + +void timeout_del(timeout_t *timeout) { + if(!timeout->cb) + return; + + splay_unlink_node(&timeout_tree, &timeout->node); + timeout->cb = 0; + timeout->tv = (struct timeval){0, 0}; +} + +#ifndef HAVE_MINGW +static io_t signalio; +static int pipefd[2] = {-1, -1}; + +static void signal_handler(int signum) { + unsigned char num = signum; + write(pipefd[1], &num, 1); +} + +static void signalio_handler(void *data, int flags) { + unsigned char signum; + if(read(pipefd[0], &signum, 1) != 1) + return; + + signal_t *sig = splay_search(&signal_tree, &((signal_t){.signum = signum})); + if(sig) + sig->cb(sig->data); +} + +static void pipe_init(void) { + if(!pipe(pipefd)) + io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ); +} + +void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) { + if(sig->cb) + return; + + sig->cb = cb; + sig->data = data; + sig->signum = signum; + sig->node.data = sig; + + if(pipefd[0] == -1) + pipe_init(); + + signal(sig->signum, signal_handler); + + if(!splay_insert_node(&signal_tree, &sig->node)) + abort(); +} + +void signal_del(signal_t *sig) { + if(!sig->cb) + return; + + signal(sig->signum, SIG_DFL); + + splay_unlink_node(&signal_tree, &sig->node); + sig->cb = NULL; +} +#endif + +bool event_loop(void) { + running = true; + + fd_set readable; + fd_set writable; + + while(running) { + gettimeofday(&now, NULL); + struct timeval diff, *tv = NULL; + + while(timeout_tree.head) { + timeout_t *timeout = timeout_tree.head->data; + timersub(&timeout->tv, &now, &diff); + + if(diff.tv_sec < 0) { + timeout->cb(timeout->data); + if(timercmp(&timeout->tv, &now, <)) + timeout_del(timeout); + } else { + tv = &diff; + break; + } + } + + memcpy(&readable, &readfds, sizeof readable); + memcpy(&writable, &writefds, sizeof writable); + + int fds = 0; + + if(io_tree.tail) { + io_t *last = io_tree.tail->data; + fds = last->fd + 1; + } + +#ifdef HAVE_MINGW + LeaveCriticalSection(&mutex); +#endif + int n = select(fds, &readable, &writable, NULL, tv); +#ifdef HAVE_MINGW + EnterCriticalSection(&mutex); +#endif + + if(n < 0) { + if(sockwouldblock(errno)) + continue; + else + return false; + } + + if(!n) + continue; + + for splay_each(io_t, io, &io_tree) { + if(FD_ISSET(io->fd, &writable)) + io->cb(io->data, IO_WRITE); + else if(FD_ISSET(io->fd, &readable)) + io->cb(io->data, IO_READ); + } + } + + return true; +} + +void event_exit(void) { + running = false; +} diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..d0129d0 --- /dev/null +++ b/src/event.h @@ -0,0 +1,70 @@ +/* + event.h -- I/O, timeout and signal event handling + Copyright (C) 2012 Guus Sliepen + + 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. +*/ + +#ifndef __TINC_EVENT_H__ +#define __TINC_EVENT_H__ + +#include "splay_tree.h" + +#define IO_READ 1 +#define IO_WRITE 2 + +typedef void (*io_cb_t)(void *data, int flags); +typedef void (*timeout_cb_t)(void *data); +typedef void (*signal_cb_t)(void *data); + +typedef struct io_t { + int fd; + int flags; + io_cb_t cb; + void *data; + splay_node_t node; +} io_t; + +typedef struct timeout_t { + struct timeval tv; + timeout_cb_t cb; + void *data; + splay_node_t node; +} timeout_t; + +typedef struct signal_t { + int signum; + signal_cb_t cb; + void *data; + splay_node_t node; +} signal_t; + +extern struct timeval now; + +extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags); +extern void io_del(io_t *io); +extern void io_set(io_t *io, int flags); + +extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv); +extern void timeout_del(timeout_t *timeout); +extern void timeout_set(timeout_t *timeout, struct timeval *tv); + +extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum); +extern void signal_del(signal_t *sig); + +extern bool event_loop(void); +extern void event_exit(void); + +#endif diff --git a/src/graph.c b/src/graph.c index 9036c52..73db3b2 100644 --- a/src/graph.c +++ b/src/graph.c @@ -213,8 +213,7 @@ static void check_reachability(void) { n->minmtu = 0; n->mtuprobes = 0; - if(timeout_initialized(&n->mtuevent)) - event_del(&n->mtuevent); + timeout_del(&n->mtutimeout); char *name; char *address; diff --git a/src/hash.c b/src/hash.c index cf5ba90..1d203c5 100644 --- a/src/hash.c +++ b/src/hash.c @@ -55,7 +55,7 @@ hash_t *hash_alloc(size_t n, size_t size) { hash_t *hash = xmalloc_and_zero(sizeof *hash); hash->n = n; hash->size = size; - hash->keys = xmalloc(hash->n * hash->size); + hash->keys = xmalloc_and_zero(hash->n * hash->size); hash->values = xmalloc_and_zero(hash->n * sizeof *hash->values); return hash; } @@ -100,6 +100,8 @@ void hash_clear(hash_t *hash) { void hash_resize(hash_t *hash, size_t n) { hash->keys = xrealloc(hash->keys, n * hash->size); hash->values = xrealloc(hash->values, n * sizeof *hash->values); - if(n > hash->n) + if(n > hash->n) { + memset(hash->keys + hash->n * hash->size, 0, (n - hash->n) * hash->size); memset(hash->values + hash->n, 0, (n - hash->n) * sizeof *hash->values); + } } diff --git a/src/logger.c b/src/logger.c index 4527a37..e01980e 100644 --- a/src/logger.c +++ b/src/logger.c @@ -41,7 +41,6 @@ bool logcontrol = false; static void real_logger(int level, int priority, const char *message) { char timestr[32] = ""; - time_t now; static bool suppress = false; // Bail out early if there is nothing to do. @@ -58,8 +57,10 @@ static void real_logger(int level, int priority, const char *message) { fflush(stderr); break; case LOGMODE_FILE: - now = time(NULL); - strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now)); + if(!now.tv_sec) + gettimeofday(&now, NULL); + time_t now_sec = now.tv_sec; + strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now_sec)); fprintf(logfile, "%s %s[%ld]: %s\n", timestr, logident, (long)logpid, message); fflush(logfile); break; diff --git a/src/meta.c b/src/meta.c index 84fb196..1244bfd 100644 --- a/src/meta.c +++ b/src/meta.c @@ -39,7 +39,7 @@ bool send_meta_sptps(void *handle, uint8_t type, const char *buffer, size_t leng } buffer_add(&c->outbuf, buffer, length); - event_add(&c->outevent, NULL); + io_set(&c->io, IO_READ | IO_WRITE); return true; } @@ -65,12 +65,11 @@ bool send_meta(connection_t *c, const char *buffer, int length) { c->name, c->hostname); return false; } - } else { buffer_add(&c->outbuf, buffer, length); } - event_add(&c->outevent, NULL); + io_set(&c->io, IO_READ | IO_WRITE); return true; } diff --git a/src/net.c b/src/net.c index f8ffbe3..fe272db 100644 --- a/src/net.c +++ b/src/net.c @@ -74,7 +74,7 @@ void purge(void) { if(e->to == n) return; - if(!strictsubnets || !n->subnet_tree->head) + if(!autoconnect && (!strictsubnets || !n->subnet_tree->head)) /* in strictsubnets mode do not delete nodes with subnets */ node_del(n); } @@ -137,18 +137,16 @@ void terminate_connection(connection_t *c, bool report) { end does not reply in time, we consider them dead and close the connection. */ -static void timeout_handler(int fd, short events, void *event) { - time_t now = time(NULL); - +static void timeout_handler(void *data) { for list_each(connection_t, c, connection_list) { if(c->status.control) continue; - if(c->last_ping_time + pingtimeout <= now) { + if(c->last_ping_time + pingtimeout <= now.tv_sec) { if(c->status.active) { if(c->status.pinged) { - logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now - c->last_ping_time); - } else if(c->last_ping_time + pinginterval <= now) { + logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time); + } else if(c->last_ping_time + pinginterval <= now.tv_sec) { send_ping(c); continue; } else { @@ -164,6 +162,15 @@ static void timeout_handler(int fd, short events, void *event) { } } + timeout_set(data, &(struct timeval){pingtimeout, rand() % 100000}); +} + +static void periodic_handler(void *data) { + /* Check if there are too many contradicting ADD_EDGE and DEL_EDGE messages. + This usually only happens when another node has the same Name as this node. + If so, sleep for a short while to prevent a storm of contradicting messages. + */ + if(contradicting_del_edge > 100 && contradicting_add_edge > 100) { logger(DEBUG_ALWAYS, LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime); usleep(sleeptime * 1000000LL); @@ -179,11 +186,100 @@ static void timeout_handler(int fd, short events, void *event) { contradicting_add_edge = 0; contradicting_del_edge = 0; - event_add(event, &(struct timeval){pingtimeout, 0}); + /* If AutoConnect is set, check if we need to make or break connections. */ + + if(autoconnect && node_tree->count > 1) { + /* Count number of active connections */ + int nc = 0; + for list_each(connection_t, c, connection_list) { + if(c->status.active && !c->status.control) + nc++; + } + + if(nc < autoconnect) { + /* Not enough active connections, try to add one. + Choose a random node, if we don't have a connection to it, + and we are not already trying to make one, create an + outgoing connection to this node. + */ + int r = rand() % node_tree->count; + int i = 0; + + for splay_each(node_t, n, node_tree) { + if(i++ != r) + continue; + + if(n->connection) + break; + + bool found = false; + + for list_each(outgoing_t, outgoing, outgoing_list) { + if(!strcmp(outgoing->name, n->name)) { + found = true; + break; + } + } + + if(!found) { + logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name); + outgoing_t *outgoing = xmalloc_and_zero(sizeof *outgoing); + outgoing->name = xstrdup(n->name); + list_insert_tail(outgoing_list, outgoing); + setup_outgoing_connection(outgoing); + } + break; + } + } else if(nc > autoconnect) { + /* Too many active connections, try to remove one. + Choose a random outgoing connection to a node + that has at least one other connection. + */ + int r = rand() % nc; + int i = 0; + + for list_each(connection_t, c, connection_list) { + if(!c->status.active || c->status.control) + continue; + + if(i++ != r) + continue; + + if(!c->outgoing || !c->node || c->node->edge_tree->count < 2) + break; + + logger(DEBUG_CONNECTIONS, LOG_INFO, "Autodisconnecting from %s", c->name); + list_delete(outgoing_list, c->outgoing); + c->outgoing = NULL; + terminate_connection(c, c->status.active); + break; + } + } + + if(nc >= autoconnect) { + /* If we have enough active connections, + remove any pending outgoing connections. + */ + for list_each(outgoing_t, o, outgoing_list) { + bool found = false; + for list_each(connection_t, c, connection_list) { + if(c->outgoing == o) { + found = true; + break; + } + } + if(!found) { + logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->name); + list_delete_node(outgoing_list, node); + } + } + } + } + + timeout_set(data, &(struct timeval){5, rand() % 100000}); } -void handle_meta_connection_data(int fd, short events, void *data) { - connection_t *c = data; +void handle_meta_connection_data(connection_t *c) { int result; socklen_t len = sizeof result; @@ -207,19 +303,19 @@ void handle_meta_connection_data(int fd, short events, void *data) { } } -static void sigterm_handler(int signal, short events, void *data) { - logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal)); - event_loopexit(NULL); +static void sigterm_handler(void *data) { + logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum)); + event_exit(); } -static void sighup_handler(int signal, short events, void *data) { - logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal)); +static void sighup_handler(void *data) { + logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum)); reopenlogger(); reload_configuration(); } -static void sigalrm_handler(int signal, short events, void *data) { - logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal)); +static void sigalrm_handler(void *data) { + logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum)); retry(); } @@ -233,7 +329,7 @@ int reload_configuration(void) { if(!read_server_config()) { logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file, exitting."); - event_loopexit(NULL); + event_exit(); return EINVAL; } @@ -332,8 +428,7 @@ int reload_configuration(void) { void retry(void) { for list_each(connection_t, c, connection_list) { if(c->outgoing && !c->node) { - if(timeout_initialized(&c->outgoing->ev)) - event_del(&c->outgoing->ev); + timeout_del(&c->outgoing->ev); if(c->status.connecting) close(c->socket); c->outgoing->timeout = 0; @@ -346,40 +441,38 @@ void retry(void) { this is where it all happens... */ int main_loop(void) { - struct event timeout_event; + timeout_t pingtimer = {{0}}; + timeout_t periodictimer = {{0}}; - timeout_set(&timeout_event, timeout_handler, &timeout_event); - event_add(&timeout_event, &(struct timeval){pingtimeout, 0}); + timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000}); + timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){pingtimeout, rand() % 100000}); #ifndef HAVE_MINGW - struct event sighup_event; - struct event sigterm_event; - struct event sigquit_event; - struct event sigalrm_event; + signal_t sighup = {0}; + signal_t sigterm = {0}; + signal_t sigquit = {0}; + signal_t sigalrm = {0}; - signal_set(&sighup_event, SIGHUP, sighup_handler, NULL); - signal_add(&sighup_event, NULL); - signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL); - signal_add(&sigterm_event, NULL); - signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL); - signal_add(&sigquit_event, NULL); - signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL); - signal_add(&sigalrm_event, NULL); + signal_add(&sighup, sighup_handler, &sighup, SIGHUP); + signal_add(&sigterm, sigterm_handler, &sigterm, SIGTERM); + signal_add(&sigquit, sigterm_handler, &sigquit, SIGQUIT); + signal_add(&sigalrm, sigalrm_handler, &sigalrm, SIGALRM); #endif - if(event_loop(0) < 0) { + if(!event_loop()) { logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", strerror(errno)); return 1; } #ifndef HAVE_MINGW - signal_del(&sighup_event); - signal_del(&sigterm_event); - signal_del(&sigquit_event); - signal_del(&sigalrm_event); + signal_del(&sighup); + signal_del(&sigalrm); + signal_del(&sigquit); + signal_del(&sigterm); #endif - event_del(&timeout_event); + timeout_del(&periodictimer); + timeout_del(&pingtimer); return 0; } diff --git a/src/net.h b/src/net.h index 23b8cae..4277279 100644 --- a/src/net.h +++ b/src/net.h @@ -24,6 +24,7 @@ #include "ipv6.h" #include "cipher.h" #include "digest.h" +#include "event.h" #ifdef ENABLE_JUMBOGRAMS #define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ @@ -99,10 +100,8 @@ typedef enum packet_type_t { } packet_type_t; typedef struct listen_socket_t { - struct event ev_tcp; - struct event ev_udp; - int tcp; - int udp; + io_t tcp; + io_t udp; sockaddr_t sa; } listen_socket_t; @@ -116,7 +115,7 @@ typedef struct outgoing_t { struct config_t *cfg; struct addrinfo *ai; struct addrinfo *aip; - struct event ev; + timeout_t ev; } outgoing_t; extern list_t *outgoing_list; @@ -134,6 +133,7 @@ extern int udp_rcvbuf; extern int udp_sndbuf; extern bool do_prune; extern char *myport; +extern int autoconnect; extern int contradicting_add_edge; extern int contradicting_del_edge; extern time_t last_config_check; @@ -160,10 +160,10 @@ extern char *scriptextension; #include "node.h" extern void retry_outgoing(outgoing_t *); -extern void handle_incoming_vpn_data(int, short, void *); +extern void handle_incoming_vpn_data(void *, int); extern void finish_connecting(struct connection_t *); extern bool do_outgoing_connection(struct outgoing_t *); -extern void handle_new_meta_connection(int, short, void *); +extern void handle_new_meta_connection(void *, int); extern int setup_listen_socket(const sockaddr_t *); extern int setup_vpn_in_socket(const sockaddr_t *); extern bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len); @@ -183,13 +183,14 @@ extern bool node_read_ecdsa_public_key(struct node_t *); extern bool read_ecdsa_public_key(struct connection_t *); extern bool read_rsa_public_key(struct connection_t *); extern void send_mtu_probe(struct node_t *); -extern void handle_device_data(int, short, void *); -extern void handle_meta_connection_data(int, short, void *); +extern void handle_device_data(void *, int); +extern void handle_meta_connection_data(struct connection_t *); extern void regenerate_key(void); extern void purge(void); extern void retry(void); extern int reload_configuration(void); extern void load_all_subnets(void); +extern void load_all_nodes(void); #ifndef HAVE_MINGW #define closesocket(s) close(s) diff --git a/src/net_packet.c b/src/net_packet.c index 67ebc22..3c3397c 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -77,7 +77,7 @@ bool localdiscovery = false; which will be broadcast to the local network. */ -static void send_mtu_probe_handler(int fd, short events, void *data) { +static void send_mtu_probe_handler(void *data) { node_t *n = data; int timeout = 1; @@ -151,23 +151,37 @@ static void send_mtu_probe_handler(int fd, short events, void *data) { } end: - event_add(&n->mtuevent, &(struct timeval){timeout, 0}); + timeout_set(&n->mtutimeout, &(struct timeval){timeout, rand() % 100000}); } void send_mtu_probe(node_t *n) { - if(!timeout_initialized(&n->mtuevent)) - timeout_set(&n->mtuevent, send_mtu_probe_handler, n); - send_mtu_probe_handler(0, 0, n); + timeout_add(&n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval){1, 0}); + send_mtu_probe_handler(n); } static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname); if(!packet->data[0]) { + /* It's a probe request, send back a reply */ + packet->data[0] = 1; - send_udppacket(n, packet); - } else { + + /* Temporarily set udp_confirmed, so that the reply is sent + back exactly the way it came in. */ + + bool udp_confirmed = n->status.udp_confirmed; n->status.udp_confirmed = true; + send_udppacket(n, packet); + n->status.udp_confirmed = udp_confirmed; + } else { + /* It's a valid reply: now we know bidirectional communication + is possible using the address and socket that the reply + packet used. */ + + n->status.udp_confirmed = true; + + /* If we haven't established the PMTU yet, restart the discovery process. */ if(n->mtuprobes > 30) { if(n->minmtu) @@ -176,6 +190,8 @@ static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { n->mtuprobes = 1; } + /* If applicable, raise the minimum supported MTU */ + if(len > n->maxmtu) len = n->maxmtu; if(n->minmtu < len) @@ -438,6 +454,84 @@ static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) { return; } +static void choose_udp_address(const node_t *n, const sockaddr_t **sa, int *sock) { + /* Latest guess */ + *sa = &n->address; + *sock = n->sock; + + /* If the UDP address is confirmed, use it. */ + if(n->status.udp_confirmed) + return; + + /* Send every third packet to n->address; that could be set + to the node's reflexive UDP address discovered during key + exchange. */ + + static int x = 0; + if(++x >= 3) { + x = 0; + return; + } + + /* Otherwise, address are found in edges to this node. + So we pick a random edge and a random socket. */ + + int i = 0; + int j = rand() % n->edge_tree->count; + edge_t *candidate = NULL; + + for splay_each(edge_t, e, n->edge_tree) { + if(i++ == j) { + candidate = e->reverse; + break; + } + } + + if(candidate) { + *sa = &candidate->address; + *sock = rand() % listen_sockets; + } + + /* Make sure we have a suitable socket for the chosen address */ + if(listen_socket[*sock].sa.sa.sa_family != (*sa)->sa.sa_family) { + for(int i = 0; i < listen_sockets; i++) { + if(listen_socket[i].sa.sa.sa_family == (*sa)->sa.sa_family) { + *sock = i; + break; + } + } + } +} + +static void choose_broadcast_address(const node_t *n, const sockaddr_t **sa, int *sock) { + static sockaddr_t broadcast_ipv4 = { + .in = { + .sin_family = AF_INET, + .sin_addr.s_addr = -1, + } + }; + + static sockaddr_t broadcast_ipv6 = { + .in6 = { + .sin6_family = AF_INET6, + .sin6_addr.s6_addr[0x0] = 0xff, + .sin6_addr.s6_addr[0x1] = 0x02, + .sin6_addr.s6_addr[0xf] = 0x01, + } + }; + + *sock = rand() % listen_sockets; + + if(listen_socket[*sock].sa.sa.sa_family == AF_INET6) { + broadcast_ipv6.in6.sin6_port = n->prevedge->address.in.sin_port; + broadcast_ipv6.in6.sin6_scope_id = listen_socket[*sock].sa.in6.sin6_scope_id; + *sa = &broadcast_ipv6; + } else { + broadcast_ipv4.in.sin_port = n->prevedge->address.in.sin_port; + *sa = &broadcast_ipv4; + } +} + static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { vpn_packet_t pkt1, pkt2; vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 }; @@ -462,15 +556,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { /* Make sure we have a valid key */ if(!n->status.validkey) { - time_t now = time(NULL); - logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s), forwarding via TCP", n->name, n->hostname); - if(n->last_req_key + 10 <= now) { + if(n->last_req_key + 10 <= now.tv_sec) { send_req_key(n); - n->last_req_key = now; + n->last_req_key = now.tv_sec; } send_tcppacket(n->nexthop->connection, origpkt); @@ -534,88 +626,27 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { /* Send the packet */ - sockaddr_t *sa; + const sockaddr_t *sa; int sock; /* Overloaded use of priority field: -1 means local broadcast */ - if(origpriority == -1 && n->prevedge) { - sockaddr_t broadcast; - broadcast.in.sin_family = AF_INET; - broadcast.in.sin_addr.s_addr = -1; - broadcast.in.sin_port = n->prevedge->address.in.sin_port; - sa = &broadcast; - sock = 0; - } else { - if(origpriority == -1) - origpriority = 0; - - if(n->status.udp_confirmed) { - /* Address of this node is confirmed, so use it. */ - sa = &n->address; - sock = n->sock; - } else { - /* Otherwise, go through the list of known addresses of - this node. The first address we try is always the - one in n->address; that could be set to the node's - reflexive UDP address discovered during key - exchange. The other known addresses are those found - in edges to this node. */ - - static unsigned int i; - int j = 0; - edge_t *candidate = NULL; - - if(i) { - for splay_each(edge_t, e, edge_weight_tree) { - if(e->to != n) - continue; - j++; - if(!candidate || j == i) - candidate = e; - } - } - - if(!candidate) { - sa = &n->address; - sock = n->sock; - } else { - sa = &candidate->address; - sock = rand() % listen_sockets; - } - - if(i++) - if(i > j) - i = 0; - } - } - - /* Determine which socket we have to use */ - - if(sa->sa.sa_family != listen_socket[sock].sa.sa.sa_family) - for(sock = 0; sock < listen_sockets; sock++) - if(sa->sa.sa_family == listen_socket[sock].sa.sa.sa_family) - break; - - if(sock >= listen_sockets) - sock = 0; - - if(!n->status.udp_confirmed) - n->sock = sock; + if(origpriority == -1 && n->prevedge) + choose_broadcast_address(n, &sa, &sock); + else + choose_udp_address(n, &sa, &sock); #if defined(SOL_IP) && defined(IP_TOS) if(priorityinheritance && origpriority != priority && listen_socket[n->sock].sa.sa.sa_family == AF_INET) { priority = origpriority; logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority); - if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */ + if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */ logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno)); } #endif - socklen_t sl = SALEN(n->address.sa); - - if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, sl) < 0 && !sockwouldblock(sockerrno)) { + if(sendto(listen_socket[sock].udp.fd, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) { if(sockmsgsize(sockerrno)) { if(n->maxmtu >= origlen) n->maxmtu = origlen - 1; @@ -647,15 +678,12 @@ bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) { /* Otherwise, send the packet via UDP */ - struct sockaddr *sa; - socklen_t sl; + const sockaddr_t *sa; int sock; - sa = &(to->address.sa); - sl = SALEN(to->address.sa); - sock = to->sock; + choose_udp_address(to, &sa, &sock); - if(sendto(listen_socket[sock].udp, data, len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) { + if(sendto(listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) { if(sockmsgsize(sockerrno)) { if(to->maxmtu >= len) to->maxmtu = len - 1; @@ -711,11 +739,11 @@ bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t int offset = (type & PKT_MAC) ? 0 : 14; if(type & PKT_COMPRESSED) { - len = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression); - if(len < 0) { + length_t ulen = uncompress_packet(inpkt.data + offset, (const uint8_t *)data, len, from->incompression); + if(ulen < 0) { return false; } else { - inpkt.len = len + offset; + inpkt.len = ulen + offset; } if(inpkt.len > MAXSIZE) abort(); @@ -838,14 +866,13 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { node_t *n = NULL; bool hard = false; static time_t last_hard_try = 0; - time_t now = time(NULL); for splay_each(edge_t, e, edge_weight_tree) { if(!e->to->status.reachable || e->to == myself) continue; if(sockaddrcmp_noport(from, &e->address)) { - if(last_hard_try == now) + if(last_hard_try == now.tv_sec) continue; hard = true; } @@ -858,13 +885,14 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { } if(hard) - last_hard_try = now; + last_hard_try = now.tv_sec; - last_hard_try = now; + last_hard_try = now.tv_sec; return n; } -void handle_incoming_vpn_data(int sock, short events, void *data) { +void handle_incoming_vpn_data(void *data, int flags) { + listen_socket_t *ls = data; vpn_packet_t pkt; char *hostname; sockaddr_t from = {{0}}; @@ -872,7 +900,7 @@ void handle_incoming_vpn_data(int sock, short events, void *data) { node_t *n; int len; - len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); + len = recvfrom(ls->udp.fd, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); if(len <= 0 || len > MAXSIZE) { if(!sockwouldblock(sockerrno)) @@ -900,12 +928,12 @@ void handle_incoming_vpn_data(int sock, short events, void *data) { return; } - n->sock = (intptr_t)data; + n->sock = ls - listen_socket; receive_udppacket(n, &pkt); } -void handle_device_data(int sock, short events, void *data) { +void handle_device_data(void *data, int flags) { vpn_packet_t packet; packet.priority = 0; diff --git a/src/net_setup.c b/src/net_setup.c index 95ff5c3..c5c83e7 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -42,7 +42,7 @@ #include "xalloc.h" char *myport; -static struct event device_ev; +static io_t device_io; devops_t devops; char *proxyhost; @@ -50,6 +50,7 @@ char *proxyport; char *proxyuser; char *proxypass; proxytype_t proxytype; +int autoconnect; char *scriptinterpreter; char *scriptextension; @@ -269,22 +270,16 @@ static bool read_rsa_private_key(void) { return result; } -static struct event keyexpire_event; +static timeout_t keyexpire_timeout; -static void keyexpire_handler(int fd, short events, void *data) { +static void keyexpire_handler(void *data) { regenerate_key(); + timeout_set(data, &(struct timeval){keylifetime, rand() % 100000}); } void regenerate_key(void) { - if(timeout_initialized(&keyexpire_event)) { - logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys"); - event_del(&keyexpire_event); - send_key_changed(); - } else { - timeout_set(&keyexpire_event, keyexpire_handler, NULL); - } - - event_add(&keyexpire_event, &(struct timeval){keylifetime, 0}); + logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys"); + send_key_changed(); } /* @@ -347,6 +342,36 @@ void load_all_subnets(void) { closedir(dir); } +void load_all_nodes(void) { + DIR *dir; + struct dirent *ent; + char *dname; + + xasprintf(&dname, "%s" SLASH "hosts", confbase); + dir = opendir(dname); + if(!dir) { + logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno)); + free(dname); + return; + } + + while((ent = readdir(dir))) { + if(!check_id(ent->d_name)) + continue; + + node_t *n = lookup_node(ent->d_name); + if(n) + continue; + + n = new_node(); + n->name = xstrdup(ent->d_name); + node_add(n); + } + + closedir(dir); +} + + char *get_name(void) { char *name = NULL; @@ -362,7 +387,7 @@ char *get_name(void) { logger(DEBUG_ALWAYS, LOG_ERR, "Invalid Name: environment variable %s does not exist\n", name + 1); return false; } - envname = alloca(32); + char envname[32]; if(gethostname(envname, 32)) { logger(DEBUG_ALWAYS, LOG_ERR, "Could not get hostname: %s\n", strerror(errno)); return false; @@ -570,6 +595,8 @@ bool setup_myself_reloadable(void) { if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; + get_config_int(lookup_config(config_tree, "AutoConnect"), &autoconnect); + return true; } @@ -683,7 +710,8 @@ static bool setup_myself(void) { free(cipher); - regenerate_key(); + send_key_changed(); + timeout_add(&keyexpire_timeout, keyexpire_handler, &keyexpire_timeout, &(struct timeval){keylifetime, rand() % 100000}); /* Check if we want to use message authentication codes... */ @@ -730,6 +758,8 @@ static bool setup_myself(void) { if(strictsubnets) load_all_subnets(); + else if(autoconnect) + load_all_nodes(); /* Open device */ @@ -755,15 +785,8 @@ static bool setup_myself(void) { if(!devops.setup()) return false; - if(device_fd >= 0) { - event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL); - - if (event_add(&device_ev, NULL) < 0) { - logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno)); - devops.close(); - return false; - } - } + if(device_fd >= 0) + io_add(&device_io, handle_device_data, NULL, device_fd, IO_READ); /* Run tinc-up script to further initialize the tap interface */ char *envp[5]; @@ -805,27 +828,16 @@ static bool setup_myself(void) { return false; } - listen_socket[i].tcp = i + 3; - #ifdef FD_CLOEXEC fcntl(i + 3, F_SETFD, FD_CLOEXEC); #endif - listen_socket[i].udp = setup_vpn_in_socket(&sa); - if(listen_socket[i].udp < 0) + int udp_fd = setup_vpn_in_socket(&sa); + if(udp_fd < 0) return false; - event_set(&listen_socket[i].ev_tcp, listen_socket[i].tcp, EV_READ|EV_PERSIST, handle_new_meta_connection, NULL); - if(event_add(&listen_socket[i].ev_tcp, NULL) < 0) { - logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno)); - abort(); - } - - event_set(&listen_socket[i].ev_udp, listen_socket[i].udp, EV_READ|EV_PERSIST, handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets); - if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) { - logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno)); - abort(); - } + io_add(&listen_socket[i].tcp, (io_cb_t)handle_new_meta_connection, &listen_socket[i], i + 3, IO_READ); + io_add(&listen_socket[i].udp, (io_cb_t)handle_incoming_vpn_data, &listen_socket[i], udp_fd, IO_READ); if(debug_level >= DEBUG_CONNECTIONS) { hostname = sockaddr2hostname(&sa); @@ -878,37 +890,20 @@ static bool setup_myself(void) { return false; } - listen_socket[listen_sockets].tcp = - setup_listen_socket((sockaddr_t *) aip->ai_addr); + int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr); - if(listen_socket[listen_sockets].tcp < 0) + if(tcp_fd < 0) continue; - listen_socket[listen_sockets].udp = - setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); + int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); - if(listen_socket[listen_sockets].udp < 0) { - close(listen_socket[listen_sockets].tcp); + if(tcp_fd < 0) { + close(tcp_fd); continue; } - event_set(&listen_socket[listen_sockets].ev_tcp, - listen_socket[listen_sockets].tcp, - EV_READ|EV_PERSIST, - handle_new_meta_connection, NULL); - if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) { - logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno)); - abort(); - } - - event_set(&listen_socket[listen_sockets].ev_udp, - listen_socket[listen_sockets].udp, - EV_READ|EV_PERSIST, - handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets); - if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) { - logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno)); - abort(); - } + io_add(&listen_socket[listen_sockets].tcp, handle_new_meta_connection, &listen_socket[listen_sockets], tcp_fd, IO_READ); + io_add(&listen_socket[listen_sockets].udp, handle_incoming_vpn_data, &listen_socket[listen_sockets], udp_fd, IO_READ); if(debug_level >= DEBUG_CONNECTIONS) { hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); @@ -990,10 +985,10 @@ void close_network_connections(void) { } for(int i = 0; i < listen_sockets; i++) { - event_del(&listen_socket[i].ev_tcp); - event_del(&listen_socket[i].ev_udp); - close(listen_socket[i].tcp); - close(listen_socket[i].udp); + io_del(&listen_socket[i].tcp); + io_del(&listen_socket[i].udp); + close(listen_socket[i].tcp.fd); + close(listen_socket[i].udp.fd); } char *envp[5]; diff --git a/src/net_socket.c b/src/net_socket.c index 09c5207..212649b 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -271,7 +271,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { return nfd; } /* int setup_vpn_in_socket */ -static void retry_outgoing_handler(int fd, short events, void *data) { +static void retry_outgoing_handler(void *data) { setup_outgoing_connection(data); } @@ -281,12 +281,9 @@ void retry_outgoing(outgoing_t *outgoing) { if(outgoing->timeout > maxtimeout) outgoing->timeout = maxtimeout; - timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing); - event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0}); + timeout_add(&outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval){outgoing->timeout, rand() % 100000}); - logger(DEBUG_CONNECTIONS, LOG_NOTICE, - "Trying to re-establish outgoing connection in %d seconds", - outgoing->timeout); + logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout); } void finish_connecting(connection_t *c) { @@ -349,9 +346,7 @@ static void do_outgoing_pipe(connection_t *c, char *command) { #endif } -static void handle_meta_write(int sock, short events, void *data) { - connection_t *c = data; - +static void handle_meta_write(connection_t *c) { ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0); if(outlen <= 0) { if(!errno || errno == EPIPE) { @@ -368,10 +363,16 @@ static void handle_meta_write(int sock, short events, void *data) { } buffer_read(&c->outbuf, outlen); - if(!c->outbuf.len && event_initialized(&c->outevent)) - event_del(&c->outevent); + if(!c->outbuf.len) + io_set(&c->io, IO_READ); } +static void handle_meta_io(void *data, int flags) { + if(flags & IO_WRITE) + handle_meta_write(data); + else + handle_meta_connection_data(data); +} bool do_outgoing_connection(outgoing_t *outgoing) { char *address, *port, *space; @@ -487,16 +488,13 @@ begin: connection_add(c); - event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c); - event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c); - event_add(&c->inevent, NULL); + io_add(&c->io, handle_meta_io, c, c->socket, IO_READ); return true; } void setup_outgoing_connection(outgoing_t *outgoing) { - if(event_initialized(&outgoing->ev)) - event_del(&outgoing->ev); + timeout_del(&outgoing->ev); node_t *n = lookup_node(outgoing->name); @@ -523,13 +521,14 @@ void setup_outgoing_connection(outgoing_t *outgoing) { accept a new tcp connect and create a new connection */ -void handle_new_meta_connection(int sock, short events, void *data) { +void handle_new_meta_connection(void *data, int flags) { + listen_socket_t *l = data; connection_t *c; sockaddr_t sa; int fd; socklen_t len = sizeof sa; - fd = accept(sock, &sa.sa, &len); + fd = accept(l->tcp.fd, &sa.sa, &len); if(fd < 0) { logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno)); @@ -552,9 +551,7 @@ void handle_new_meta_connection(int sock, short events, void *data) { logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname); - event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c); - event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c); - event_add(&c->inevent, NULL); + io_add(&c->io, handle_meta_io, c, c->socket, IO_READ); configure_tcp(c); @@ -565,8 +562,7 @@ void handle_new_meta_connection(int sock, short events, void *data) { } static void free_outgoing(outgoing_t *outgoing) { - if(event_initialized(&outgoing->ev)) - event_del(&outgoing->ev); + timeout_del(&outgoing->ev); if(outgoing->ai) freeaddrinfo(outgoing->ai); diff --git a/src/netutl.c b/src/netutl.c index a71b370..a55eaea 100644 --- a/src/netutl.c +++ b/src/netutl.c @@ -52,7 +52,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock sockaddr_t str2sockaddr(const char *address, const char *port) { struct addrinfo *ai, hint = {0}; - sockaddr_t result; + sockaddr_t result = {{0}}; int err; hint.ai_family = AF_UNSPEC; diff --git a/src/node.c b/src/node.c index e67b9b9..465a48a 100644 --- a/src/node.c +++ b/src/node.c @@ -78,8 +78,7 @@ void free_node(node_t *n) { ecdsa_free(&n->ecdsa); sptps_stop(&n->sptps); - if(timeout_initialized(&n->mtuevent)) - event_del(&n->mtuevent); + timeout_del(&n->mtutimeout); if(n->hostname) free(n->hostname); @@ -129,6 +128,13 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) { if(sa) { n->address = *sa; + n->sock = 0; + for(int i = 0; i < listen_sockets; i++) { + if(listen_socket[i].sa.sa.sa_family == sa->sa.sa_family) { + n->sock = i; + break; + } + } hash_insert(node_udp_cache, sa, n); free(n->hostname); n->hostname = sockaddr2hostname(&n->address); diff --git a/src/node.h b/src/node.h index 3327fca..c567ad9 100644 --- a/src/node.h +++ b/src/node.h @@ -25,6 +25,7 @@ #include "cipher.h" #include "connection.h" #include "digest.h" +#include "event.h" #include "subnet.h" typedef struct node_status_t { @@ -83,7 +84,7 @@ typedef struct node_t { length_t minmtu; /* Probed minimum MTU */ length_t maxmtu; /* Probed maximum MTU */ int mtuprobes; /* Number of probes */ - struct event mtuevent; /* Probe event */ + timeout_t mtutimeout; /* Probe event */ uint64_t in_packets; uint64_t in_bytes; diff --git a/src/process.c b/src/process.c index 37ba84b..2fd3d93 100644 --- a/src/process.c +++ b/src/process.c @@ -25,6 +25,7 @@ #include "control.h" #include "device.h" #include "edge.h" +#include "event.h" #include "logger.h" #include "net.h" #include "node.h" @@ -127,7 +128,7 @@ DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) { return ERROR_CALL_NOT_IMPLEMENTED; } - event_loopexit(NULL); + event_exit(); status.dwWaitHint = 30000; status.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(statushandle, &status); diff --git a/src/protocol.c b/src/protocol.c index 3c08d72..bdc0378 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -165,7 +165,24 @@ static void free_past_request(past_request_t *r) { free(r); } -static struct event past_request_event; +static timeout_t past_request_timeout; + +static void age_past_requests(void *data) { + int left = 0, deleted = 0; + + for splay_each(past_request_t, p, past_request_tree) { + if(p->firstseen + pinginterval <= now.tv_sec) + splay_delete_node(past_request_tree, node), deleted++; + else + left++; + } + + if(left || deleted) + logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Aging past requests: deleted %d, left %d", deleted, left); + + if(left) + timeout_set(&past_request_timeout, &(struct timeval){10, rand() % 100000}); +} bool seen_request(const char *request) { past_request_t *new, p = {NULL}; @@ -180,39 +197,17 @@ bool seen_request(const char *request) { new->request = xstrdup(request); new->firstseen = time(NULL); splay_insert(past_request_tree, new); - event_add(&past_request_event, &(struct timeval){10, 0}); + timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000}); return false; } } -static void age_past_requests(int fd, short events, void *data) { - int left = 0, deleted = 0; - time_t now = time(NULL); - - for splay_each(past_request_t, p, past_request_tree) { - if(p->firstseen + pinginterval <= now) - splay_delete_node(past_request_tree, node), deleted++; - else - left++; - } - - if(left || deleted) - logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Aging past requests: deleted %d, left %d", - deleted, left); - - if(left) - event_add(&past_request_event, &(struct timeval){10, 0}); -} - void init_requests(void) { past_request_tree = splay_alloc_tree((splay_compare_t) past_request_compare, (splay_action_t) free_past_request); - - timeout_set(&past_request_event, age_past_requests, NULL); } void exit_requests(void) { splay_delete_tree(past_request_tree); - if(timeout_initialized(&past_request_event)) - event_del(&past_request_event); + timeout_del(&past_request_timeout); } diff --git a/src/route.c b/src/route.c index e874d89..7bb9996 100644 --- a/src/route.c +++ b/src/route.c @@ -59,7 +59,7 @@ static const size_t opt_size = sizeof(struct nd_opt_hdr); #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif -static struct event age_subnets_event; +static timeout_t age_subnets_timeout; /* RFC 1071 */ @@ -84,13 +84,12 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { static bool ratelimit(int frequency) { static time_t lasttime = 0; static int count = 0; - time_t now = time(NULL); - if(lasttime == now) { + if(lasttime == now.tv_sec) { if(count >= frequency) return true; } else { - lasttime = now; + lasttime = now.tv_sec; count = 0; } @@ -115,15 +114,22 @@ static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *pac mtu = via->mtu; /* Find TCP header */ - int start = 0; + int start = ether_size; uint16_t type = packet->data[12] << 8 | packet->data[13]; - if(type == ETH_P_IP && packet->data[23] == 6) - start = 14 + (packet->data[14] & 0xf) * 4; - else if(type == ETH_P_IPV6 && packet->data[20] == 6) - start = 14 + 40; + if(type == ETH_P_8021Q) { + start += 4; + type = packet->data[16] << 8 | packet->data[17]; + } - if(!start || packet->len <= start + 20) + if(type == ETH_P_IP && packet->data[start + 9] == 6) + start += (packet->data[start] & 0xf) * 4; + else if(type == ETH_P_IPV6 && packet->data[start + 6] == 6) + start += 40; + else + return; + + if(packet->len <= start + 20) return; /* Use data offset field to calculate length of options field */ @@ -185,12 +191,11 @@ static void swap_mac_addresses(vpn_packet_t *packet) { memcpy(&packet->data[6], &tmp, sizeof tmp); } -static void age_subnets(int fd, short events, void *data) { +static void age_subnets(void *data) { bool left = false; - time_t now = time(NULL); for splay_each(subnet_t, s, myself->subnet_tree) { - if(s->expires && s->expires < now) { + if(s->expires && s->expires < now.tv_sec) { if(debug_level >= DEBUG_TRAFFIC) { char netstr[MAXNETSTR]; if(net2str(netstr, sizeof netstr, s)) @@ -209,7 +214,7 @@ static void age_subnets(int fd, short events, void *data) { } if(left) - event_add(&age_subnets_event, &(struct timeval){10, 0}); + timeout_set(&age_subnets_timeout, &(struct timeval){10, rand() % 100000}); } static void learn_mac(mac_t *address) { @@ -236,9 +241,7 @@ static void learn_mac(mac_t *address) { if(c->status.active) send_add_subnet(c, subnet); - if(!timeout_initialized(&age_subnets_event)) - timeout_set(&age_subnets_event, age_subnets, NULL); - event_add(&age_subnets_event, &(struct timeval){10, 0}); + timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000}); } else { if(subnet->expires) subnet->expires = time(NULL) + macexpire; @@ -247,7 +250,7 @@ static void learn_mac(mac_t *address) { /* RFC 792 */ -static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, 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 icmp icmp = {0}; @@ -320,7 +323,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t /* RFC 791 */ -static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet) { +static void fragment_ipv4_packet(node_t *dest, vpn_packet_t *packet, length_t ether_size) { struct ip ip; vpn_packet_t fragment; int len, maxlen, todo; @@ -384,7 +387,7 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { dest.x[2], dest.x[3]); - route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN); + route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN); return; } @@ -394,10 +397,10 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { } if(!subnet->owner->status.reachable) - return route_ipv4_unreachable(source, packet, 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) - return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO); + return route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_NET_ANO); if(priorityinheritance) packet->priority = packet->data[15]; @@ -410,15 +413,15 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) { } if(directonly && subnet->owner != via) - return route_ipv4_unreachable(source, packet, 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) { logger(DEBUG_TRAFFIC, 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) { packet->len = MAX(via->mtu, 590); - route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); + route_ipv4_unreachable(source, packet, ether_size, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); } else { - fragment_ipv4_packet(via, packet); + fragment_ipv4_packet(via, packet, ether_size); } return; @@ -445,7 +448,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) { /* RFC 2463 */ -static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, 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 icmp6_hdr icmp6 = {0}; uint16_t checksum; @@ -543,7 +546,7 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { ntohs(dest.x[6]), ntohs(dest.x[7])); - route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR); + route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR); return; } @@ -553,10 +556,10 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { } if(!subnet->owner->status.reachable) - return route_ipv6_unreachable(source, packet, 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) - return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); + return route_ipv6_unreachable(source, packet, ether_size, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN); via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via; @@ -566,12 +569,12 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) { } if(directonly && subnet->owner != via) - return route_ipv6_unreachable(source, packet, 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) { logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); packet->len = MAX(via->mtu, 1294); - route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0); + route_ipv6_unreachable(source, packet, ether_size, ICMP6_PACKET_TOO_BIG, 0); return; } @@ -842,17 +845,24 @@ static void route_mac(node_t *source, vpn_packet_t *packet) { if(via && packet->len > via->mtu && via != myself) { logger(DEBUG_TRAFFIC, LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu); uint16_t type = packet->data[12] << 8 | packet->data[13]; - if(type == ETH_P_IP && packet->len > 590) { - if(packet->data[20] & 0x40) { + length_t ethlen = 14; + + if(type == ETH_P_8021Q) { + type = packet->data[16] << 8 | packet->data[17]; + ethlen += 4; + } + + if(type == ETH_P_IP && packet->len > 576 + ethlen) { + if(packet->data[6 + ethlen] & 0x40) { packet->len = via->mtu; - route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); + route_ipv4_unreachable(source, packet, ethlen, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED); } else { - fragment_ipv4_packet(via, packet); + fragment_ipv4_packet(via, packet, ethlen); } return; - } else if(type == ETH_P_IPV6 && packet->len > 1294) { + } else if(type == ETH_P_IPV6 && packet->len > 1280 + ethlen) { packet->len = via->mtu; - route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0); + route_ipv6_unreachable(source, packet, ethlen, ICMP6_PACKET_TOO_BIG, 0); return; } } @@ -881,42 +891,48 @@ static void send_pcap(vpn_packet_t *packet) { static bool do_decrement_ttl(node_t *source, vpn_packet_t *packet) { uint16_t type = packet->data[12] << 8 | packet->data[13]; + length_t ethlen = ether_size; + + if(type == ETH_P_8021Q) { + type = packet->data[16] << 8 | packet->data[17]; + ethlen += 4; + } switch (type) { case ETH_P_IP: - if(!checklength(source, packet, 14 + 32)) + if(!checklength(source, packet, ethlen + ip_size)) return false; - if(packet->data[22] < 1) { - if(packet->data[25] != IPPROTO_ICMP || packet->data[46] != ICMP_TIME_EXCEEDED) - route_ipv4_unreachable(source, packet, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL); + if(packet->data[ethlen + 8] < 1) { + 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); return false; } - uint16_t old = packet->data[22] << 8 | packet->data[23]; - packet->data[22]--; - uint16_t new = packet->data[22] << 8 | packet->data[23]; + uint16_t old = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; + packet->data[ethlen + 8]--; + uint16_t new = packet->data[ethlen + 8] << 8 | packet->data[ethlen + 9]; - uint32_t checksum = packet->data[24] << 8 | packet->data[25]; + uint32_t checksum = packet->data[ethlen + 10] << 8 | packet->data[ethlen + 11]; checksum += old + (~new & 0xFFFF); while(checksum >> 16) checksum = (checksum & 0xFFFF) + (checksum >> 16); - packet->data[24] = checksum >> 8; - packet->data[25] = checksum & 0xff; + packet->data[ethlen + 10] = checksum >> 8; + packet->data[ethlen + 11] = checksum & 0xff; return true; case ETH_P_IPV6: - if(!checklength(source, packet, 14 + 40)) + if(!checklength(source, packet, ethlen + ip6_size)) return false; - if(packet->data[21] < 1) { - if(packet->data[20] != IPPROTO_ICMPV6 || packet->data[54] != ICMP6_TIME_EXCEEDED) - route_ipv6_unreachable(source, packet, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT); + 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); return false; } - packet->data[21]--; + packet->data[ethlen + 7]--; return true; diff --git a/src/splay_tree.c b/src/splay_tree.c index e7d6dbb..54a46f2 100644 --- a/src/splay_tree.c +++ b/src/splay_tree.c @@ -398,6 +398,8 @@ splay_node_t *splay_insert_node(splay_tree_t *tree, splay_node_t *node) { splay_node_t *closest; int result; + node->left = node->right = node->parent = node->next = node->prev = NULL; + if(!tree->root) splay_insert_top(tree, node); else { @@ -418,6 +420,7 @@ splay_node_t *splay_insert_node(splay_tree_t *tree, splay_node_t *node) { void splay_insert_top(splay_tree_t *tree, splay_node_t *node) { node->prev = node->next = node->left = node->right = node->parent = NULL; tree->head = tree->tail = tree->root = node; + tree->count++; } void splay_insert_before(splay_tree_t *tree, splay_node_t *before, splay_node_t *node) { @@ -446,6 +449,7 @@ void splay_insert_before(splay_tree_t *tree, splay_node_t *before, splay_node_t node->parent = NULL; tree->root = node; + tree->count++; } void splay_insert_after(splay_tree_t *tree, splay_node_t *after, splay_node_t *node) { @@ -474,6 +478,7 @@ void splay_insert_after(splay_tree_t *tree, splay_node_t *after, splay_node_t *n node->parent = NULL; tree->root = node; + tree->count++; } splay_node_t *splay_unlink(splay_tree_t *tree, void *data) { @@ -511,6 +516,8 @@ void splay_unlink_node(splay_tree_t *tree, splay_node_t *node) { } else { tree->root = NULL; } + + tree->count--; } void splay_delete_node(splay_tree_t *tree, splay_node_t *node) { diff --git a/src/splay_tree.h b/src/splay_tree.h index 88d7516..8367ce7 100644 --- a/src/splay_tree.h +++ b/src/splay_tree.h @@ -58,6 +58,8 @@ typedef struct splay_tree_t { splay_compare_t compare; splay_action_t delete; + int count; + } splay_tree_t; /* (De)constructors */ diff --git a/src/sptps_test.c b/src/sptps_test.c index 7aafbbe..9db63ff 100644 --- a/src/sptps_test.c +++ b/src/sptps_test.c @@ -29,6 +29,7 @@ bool send_request(void *c, const char *msg, ...) { return false; } struct list_t *connection_list = NULL; bool send_meta(void *c, const char *msg , int len) { return false; } char *logfilename = NULL; +struct timeval now; ecdsa_t mykey, hiskey; diff --git a/src/tincctl.c b/src/tincctl.c index c1cabdb..dd0bbcc 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -57,11 +57,12 @@ static char *name = NULL; static char *identname = NULL; /* program name for syslog */ static char *pidfilename = NULL; /* pid file location */ static char *confdir = NULL; -static char controlcookie[1024]; +static char controlcookie[1025]; char *netname = NULL; char *confbase = NULL; static char *tinc_conf = NULL; static char *hosts_dir = NULL; +struct timeval now; // Horrible global variables... static int pid = 0; @@ -134,7 +135,7 @@ static void usage(bool status) { " generate-rsa-keys [bits] Generate a new RSA public/private keypair.\n" " generate-ecdsa-keys Generate a new ECDSA public/private keypair.\n" " dump Dump a list of one of the following things:\n" - " nodes - all known nodes in the VPN\n" + " [reachable] nodes - all known nodes in the VPN\n" " edges - all known connections in the VPN\n" " subnets - all known subnets in the VPN\n" " connections - all meta connections with ourself\n" @@ -708,8 +709,8 @@ static bool connect_tincd(bool verbose) { return false; } - char host[128]; - char port[128]; + char host[129]; + char port[129]; if(fscanf(f, "%20d %1024s %128s port %128s", &pid, controlcookie, host, port) != 4) { if(verbose) @@ -911,6 +912,19 @@ static int cmd_reload(int argc, char *argv[]) { } static int cmd_dump(int argc, char *argv[]) { + bool only_reachable = false; + + if(argc > 2 && !strcasecmp(argv[1], "reachable")) { + if(strcasecmp(argv[2], "nodes")) { + fprintf(stderr, "`reachable' only supported for nodes.\n"); + usage(true); + return 1; + } + only_reachable = true; + argv++; + argc--; + } + if(argc != 2) { fprintf(stderr, "Invalid number of arguments.\n"); usage(true); @@ -985,8 +999,10 @@ static int cmd_dump(int argc, char *argv[]) { fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line); return 1; } + + memcpy(&status, &status_int, sizeof status); + if(do_graph) { - memcpy(&status, &status_int, sizeof status); const char *color = "black"; if(!strcmp(host, "MYSELF")) color = "green"; @@ -1000,6 +1016,8 @@ static int cmd_dump(int argc, char *argv[]) { color = "green"; printf(" %s [label = \"%s\", color = \"%s\"%s];\n", node, node, color, strcmp(host, "MYSELF") ? "" : ", style = \"filled\""); } else { + if(only_reachable && !status.reachable) + continue; printf("%s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n", node, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu); } @@ -1233,6 +1251,7 @@ static struct { } const variables[] = { /* Server configuration */ {"AddressFamily", VAR_SERVER}, + {"AutoConnect", VAR_SERVER}, {"BindToAddress", VAR_SERVER | VAR_MULTIPLE}, {"BindToInterface", VAR_SERVER}, {"Broadcast", VAR_SERVER}, @@ -1945,7 +1964,7 @@ static char *complete_command(const char *text, int state) { } static char *complete_dump(const char *text, int state) { - const char *matches[] = {"nodes", "edges", "subnets", "connections", "graph", NULL}; + const char *matches[] = {"reachable", "nodes", "edges", "subnets", "connections", "graph", NULL}; static int i; if(!state) diff --git a/src/tincd.c b/src/tincd.c index 9f94d89..3883ec2 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -450,11 +450,6 @@ int main2(int argc, char **argv) { } #endif - if(!event_init()) { - logger(DEBUG_ALWAYS, LOG_ERR, "Error initializing libevent!"); - return 1; - } - /* Setup sockets and open device. */ if(!setup_network()) diff --git a/src/top.c b/src/top.c index 8232c7a..8cd82be 100644 --- a/src/top.c +++ b/src/top.c @@ -57,11 +57,13 @@ static int sortmode = 0; static bool cumulative = false; static list_t node_list; -static struct timeval now, prev, diff; +static struct timeval cur, prev, diff; static int delay = 1000; static bool changed = true; -static const char *unit = "bytes"; -static float scale = 1; +static const char *bunit = "bytes"; +static float bscale = 1; +static const char *punit = "pkts"; +static float pscale = 1; #ifndef timersub #define timersub(a, b, c) do {(c)->tv_sec = (a)->tv_sec - (b)->tv_sec; (c)->tv_usec = (a)->tv_usec = (b)->tv_usec;} while(0) @@ -69,10 +71,10 @@ static float scale = 1; static void update(int fd) { sendline(fd, "%d %d", CONTROL, REQ_DUMP_TRAFFIC); - gettimeofday(&now, NULL); + gettimeofday(&cur, NULL); - timersub(&now, &prev, &diff); - prev = now; + timersub(&cur, &prev, &diff); + prev = cur; float interval = diff.tv_sec + diff.tv_usec * 1e-6; char line[4096]; @@ -136,12 +138,69 @@ static void update(int fd) { } } +static int cmpfloat(float a, float b) { + if(a < b) + return -1; + else if(a > b) + return 1; + else + return 0; +} + +static int cmpu64(uint64_t a, uint64_t b) { + if(a < b) + return -1; + else if(a > b) + return 1; + else + return 0; +} + +static int sortfunc(const void *a, const void *b) { + const nodestats_t *na = *(const nodestats_t **)a; + const nodestats_t *nb = *(const nodestats_t **)b; + switch(sortmode) { + case 1: + if(cumulative) + return -cmpu64(na->in_packets, nb->in_packets) ?: na->i - nb->i; + else + return -cmpfloat(na->in_packets_rate, nb->in_packets_rate) ?: na->i - nb->i; + case 2: + if(cumulative) + return -cmpu64(na->in_bytes, nb->in_bytes) ?: na->i - nb->i; + else + return -cmpfloat(na->in_bytes_rate, nb->in_bytes_rate) ?: na->i - nb->i; + case 3: + if(cumulative) + return -cmpu64(na->out_packets, nb->out_packets) ?: na->i - nb->i; + else + return -cmpfloat(na->out_packets_rate, nb->out_packets_rate) ?: na->i - nb->i; + case 4: + if(cumulative) + return -cmpu64(na->out_bytes, nb->out_bytes) ?: na->i - nb->i; + else + return -cmpfloat(na->out_bytes_rate, nb->out_bytes_rate) ?: na->i - nb->i; + case 5: + if(cumulative) + return -cmpu64(na->in_packets + na->out_packets, nb->in_packets + nb->out_packets) ?: na->i - nb->i; + else + return -cmpfloat(na->in_packets_rate + na->out_packets_rate, nb->in_packets_rate + nb->out_packets_rate) ?: na->i - nb->i; + case 6: + if(cumulative) + return -cmpu64(na->in_bytes + na->out_bytes, nb->in_bytes + nb->out_bytes) ?: na->i - nb->i; + else + return -cmpfloat(na->in_bytes_rate + na->out_bytes_rate, nb->in_bytes_rate + nb->out_bytes_rate) ?: na->i - nb->i; + default: + return strcmp(na->name, nb->name) ?: na->i - nb->i; + } +} + static void redraw(void) { erase(); mvprintw(0, 0, "Tinc %-16s Nodes: %4d Sort: %-10s %s", netname ?: "", node_list.count, sortname[sortmode], cumulative ? "Cumulative" : "Current"); attrset(A_REVERSE); - mvprintw(2, 0, "Node IN pkts IN %s OUT pkts OUT %s", unit, unit); + mvprintw(2, 0, "Node IN %s IN %s OUT %s OUT %s", punit, bunit, punit, bunit); chgat(-1, A_REVERSE, 0, NULL); static nodestats_t **sorted = 0; @@ -157,63 +216,6 @@ static void redraw(void) { for(int i = 0; i < n; i++) sorted[i]->i = i; - int cmpfloat(float a, float b) { - if(a < b) - return -1; - else if(a > b) - return 1; - else - return 0; - } - - int cmpu64(uint64_t a, uint64_t b) { - if(a < b) - return -1; - else if(a > b) - return 1; - else - return 0; - } - - int sortfunc(const void *a, const void *b) { - const nodestats_t *na = *(const nodestats_t **)a; - const nodestats_t *nb = *(const nodestats_t **)b; - switch(sortmode) { - case 1: - if(cumulative) - return -cmpu64(na->in_packets, nb->in_packets) ?: na->i - nb->i; - else - return -cmpfloat(na->in_packets_rate, nb->in_packets_rate) ?: na->i - nb->i; - case 2: - if(cumulative) - return -cmpu64(na->in_bytes, nb->in_bytes) ?: na->i - nb->i; - else - return -cmpfloat(na->in_bytes_rate, nb->in_bytes_rate) ?: na->i - nb->i; - case 3: - if(cumulative) - return -cmpu64(na->out_packets, nb->out_packets) ?: na->i - nb->i; - else - return -cmpfloat(na->out_packets_rate, nb->out_packets_rate) ?: na->i - nb->i; - case 4: - if(cumulative) - return -cmpu64(na->out_bytes, nb->out_bytes) ?: na->i - nb->i; - else - return -cmpfloat(na->out_bytes_rate, nb->out_bytes_rate) ?: na->i - nb->i; - case 5: - if(cumulative) - return -cmpu64(na->in_packets + na->out_packets, nb->in_packets + nb->out_packets) ?: na->i - nb->i; - else - return -cmpfloat(na->in_packets_rate + na->out_packets_rate, nb->in_packets_rate + nb->out_packets_rate) ?: na->i - nb->i; - case 6: - if(cumulative) - return -cmpu64(na->in_bytes + na->out_bytes, nb->in_bytes + nb->out_bytes) ?: na->i - nb->i; - else - return -cmpfloat(na->in_bytes_rate + na->out_bytes_rate, nb->in_bytes_rate + nb->out_bytes_rate) ?: na->i - nb->i; - default: - return strcmp(na->name, nb->name) ?: na->i - nb->i; - } - } - qsort(sorted, n, sizeof *sorted, sortfunc); for(int i = 0, row = 3; i < n; i++, row++) { @@ -228,10 +230,10 @@ static void redraw(void) { if(cumulative) mvprintw(row, 0, "%-16s %10"PRIu64" %10.0f %10"PRIu64" %10.0f", - node->name, node->in_packets, node->in_bytes * scale, node->out_packets, node->out_bytes * scale); + node->name, node->in_packets * pscale, node->in_bytes * bscale, node->out_packets * pscale, node->out_bytes * bscale); else mvprintw(row, 0, "%-16s %10.0f %10.0f %10.0f %10.0f", - node->name, node->in_packets_rate, node->in_bytes_rate * scale, node->out_packets_rate, node->out_bytes_rate * scale); + node->name, node->in_packets_rate * pscale, node->in_bytes_rate * bscale, node->out_packets_rate * pscale, node->out_bytes_rate * bscale); } attrset(A_NORMAL); @@ -262,45 +264,53 @@ void top(int fd) { break; } case 'c': - cumulative = !cumulative; - break; + cumulative = !cumulative; + break; case 'n': - sortmode = 0; - break; + sortmode = 0; + break; case 'i': - sortmode = 2; - break; + sortmode = 2; + break; case 'I': - sortmode = 1; - break; + sortmode = 1; + break; case 'o': - sortmode = 4; - break; + sortmode = 4; + break; case 'O': - sortmode = 3; - break; + sortmode = 3; + break; case 't': - sortmode = 6; - break; + sortmode = 6; + break; case 'T': - sortmode = 5; - break; + sortmode = 5; + break; case 'b': - unit = "bytes"; - scale = 1; - break; + bunit = "bytes"; + bscale = 1; + punit = "pkts"; + pscale = 1; + break; case 'k': - unit = "kbyte"; - scale = 1e-3; - break; + bunit = "kbyte"; + bscale = 1e-3; + punit = "pkts"; + pscale = 1; + break; case 'M': - unit = "Mbyte"; - scale = 1e-6; - break; + bunit = "Mbyte"; + bscale = 1e-6; + punit = "kpkt"; + pscale = 1e-3; + break; case 'G': - unit = "Gbyte"; - scale = 1e-9; - break; + bunit = "Gbyte"; + bscale = 1e-9; + punit = "Mpkt"; + pscale = 1e-6; + break; case 'q': case KEY_BREAK: running = false;