From 3282375f4d64d9402141ac4bf142629ec2e1cd53 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 29 Sep 2009 16:25:20 +0200 Subject: [PATCH 01/30] Remove autogenerated files from EXTRA_DIST. Apparently they were once necessary, but autoconf now includes them automatically. Some of them are not used anymore, and this caused make dist to fail. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 3a8e51fe..b13689aa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,7 +6,7 @@ SUBDIRS = m4 lib src doc ACLOCAL_AMFLAGS = -I m4 -EXTRA_DIST = config.rpath mkinstalldirs have.h system.h COPYING.README depcomp +EXTRA_DIST = have.h system.h COPYING.README ChangeLog: git log > ChangeLog From 430c90412c521c534113b3c4e5fc883e9b7ecff0 Mon Sep 17 00:00:00 2001 From: Borg Date: Sat, 3 Oct 2009 13:06:00 +0200 Subject: [PATCH 02/30] Removed last gettext function. --- lib/getopt.c | 2 -- src/bsd/device.c | 4 ++-- src/solaris/device.c | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/getopt.c b/lib/getopt.c index fce2f0c7..b2f88b42 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -85,8 +85,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #define getpid() GetCurrentProcessId() #endif -#include "gettext.h" - /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. diff --git a/src/bsd/device.c b/src/bsd/device.c index ee9b0e53..fd1f35dd 100644 --- a/src/bsd/device.c +++ b/src/bsd/device.c @@ -209,7 +209,7 @@ bool read_packet(vpn_packet_t *packet) { break; default: ifdebug(TRAFFIC) logger(LOG_ERR, - _ ("Unknown IP version %d while reading packet from %s %s"), + "Unknown IP version %d while reading packet from %s %s", packet->data[14] >> 4, device_info, device); return false; } @@ -240,7 +240,7 @@ bool read_packet(vpn_packet_t *packet) { default: ifdebug(TRAFFIC) logger(LOG_ERR, - _ ("Unknown address family %x while reading packet from %s %s"), + "Unknown address family %x while reading packet from %s %s", ntohl(type), device_info, device); return false; } diff --git a/src/solaris/device.c b/src/solaris/device.c index 43938006..e26dc06c 100644 --- a/src/solaris/device.c +++ b/src/solaris/device.c @@ -131,7 +131,7 @@ bool read_packet(vpn_packet_t *packet) { break; default: ifdebug(TRAFFIC) logger(LOG_ERR, - _ ("Unknown IP version %d while reading packet from %s %s"), + "Unknown IP version %d while reading packet from %s %s", packet->data[14] >> 4, device_info, device); return false; } From 5cddf5e52aeb20e50c887356ad23aec354e04151 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 11 Oct 2009 13:51:10 +0200 Subject: [PATCH 03/30] Don't disconnect clients in TunnelServer mode who send unauthorised ADD_SUBNETs. So that we are liberal in what we accept. --- src/protocol_subnet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocol_subnet.c b/src/protocol_subnet.c index e7ab8b24..f7ce53b9 100644 --- a/src/protocol_subnet.c +++ b/src/protocol_subnet.c @@ -112,7 +112,7 @@ bool add_subnet_h(connection_t *c) { for(cfg = lookup_config(c->config_tree, "Subnet"); cfg; cfg = lookup_config_next(c->config_tree, cfg)) { if(!get_config_subnet(cfg, &allowed)) - return false; + continue; if(!subnet_compare(&s, allowed)) break; @@ -121,9 +121,9 @@ bool add_subnet_h(connection_t *c) { } if(!cfg) { - logger(LOG_WARNING, "Unauthorized %s from %s (%s) for %s", - "ADD_SUBNET", c->name, c->hostname, subnetstr); - return false; + logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s", + "ADD_SUBNET", c->name, c->hostname, subnetstr); + return true; } free_subnet(allowed); From 2762509be179dcb21d855f3d6f90d3ee686e3910 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 11 Oct 2009 13:54:05 +0200 Subject: [PATCH 04/30] Remove code duplication when checking ADD_EDGE/DEL_EDGE messages. --- src/protocol_edge.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/protocol_edge.c b/src/protocol_edge.c index 57e202f6..9d439225 100644 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -70,13 +70,7 @@ bool add_edge_h(connection_t *c) { /* Check if names are valid */ - if(!check_id(from_name)) { - logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, - c->hostname, "invalid name"); - return false; - } - - if(!check_id(to_name)) { + if(!check_id(from_name) || !check_id(to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, c->hostname, "invalid name"); return false; @@ -186,13 +180,7 @@ bool del_edge_h(connection_t *c) { /* Check if names are valid */ - if(!check_id(from_name)) { - logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, - c->hostname, "invalid name"); - return false; - } - - if(!check_id(to_name)) { + if(!check_id(from_name) || !check_id(to_name)) { logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name, c->hostname, "invalid name"); return false; From a4f132770dc136d456c67b01d209e73f5f4d7a65 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 11 Oct 2009 13:56:04 +0200 Subject: [PATCH 05/30] Revert "Raise default crypto algorithms to AES256 and SHA256." Although it would be better to have the new defaults, only the most recent releases of most of the platforms supported by tinc come with a version of OpenSSL that supports SHA256. To ensure people can compile tinc and that nodes can interact with each other, we revert the default back to Blowfish and SHA1. This reverts commit 4bb3793e38b7c7f24dd308801e7f6dbb02cf02d2. --- src/net_setup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/net_setup.c b/src/net_setup.c index f7302db7..a08981f9 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -352,14 +352,14 @@ bool setup_myself(void) { } } } else - myself->incipher = EVP_aes_256_cbc(); + myself->incipher = EVP_bf_cbc(); if(myself->incipher) myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len; else myself->inkeylength = 1; - myself->connection->outcipher = EVP_aes_256_ofb(); + myself->connection->outcipher = EVP_bf_ofb(); if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; @@ -380,9 +380,9 @@ bool setup_myself(void) { } } } else - myself->indigest = EVP_sha256(); + myself->indigest = EVP_sha1(); - myself->connection->outdigest = EVP_sha256(); + myself->connection->outdigest = EVP_sha1(); if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->inmaclength)) { if(myself->indigest) { From 2c30af6c90926340a89748c63cc453b1c0b5a589 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 11 Oct 2009 14:20:14 +0200 Subject: [PATCH 06/30] Ensure that the texinfo manual can be converted to HTML. The top node was made conditional with the @iftex command, since it should not appear in PostScript and PDF output. However, it is still necessary for texi2html, so we have to use @ifnottex instead. Texi2html also complains about the use of @cindex in the copyright statement, so we remove that. --- doc/tinc.texi | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/tinc.texi b/doc/tinc.texi index d07958c7..3b92916a 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -37,7 +37,6 @@ permission notice identical to this one. @page @vskip 0pt plus 1filll -@cindex copyright This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon. Copyright @copyright{} 1998-2009 Ivo Timmermans, @@ -55,7 +54,7 @@ permission notice identical to this one. @end titlepage -@ifinfo +@ifnottex @c ================================================================== @node Top @top Top @@ -71,7 +70,7 @@ permission notice identical to this one. * About us:: * Concept Index:: All used terms explained @end menu -@end ifinfo +@end ifnottex @c ================================================================== @node Introduction From 927064e5fd0ebf29a7ea768a7f9c4226da626a72 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 11 Oct 2009 15:46:52 +0200 Subject: [PATCH 07/30] Small updates to the documentation. Mention that TCPOnly is not necessary anymore since tinc will autodetect whether it can send via UDP or not. Also mention the WEIGHT environment variable and the new default value (2048 bits) of RSA keys. --- doc/tinc.conf.5.in | 10 +++++++++- doc/tinc.texi | 16 +++++++++++----- doc/tincd.8.in | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 223005fb..9c279a23 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -427,13 +427,17 @@ 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 +.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. 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 @@ -517,6 +521,10 @@ When a host becomes (un)reachable, this is set to the port number it uses for co When a subnet becomes (un)reachable, this is set to the subnet. .El +.It Ev WEIGHT +When a subnet becomes (un)reachable, this is set to the subnet weight. +.El + .Sh FILES The most important files are: .Bl -tag -width indent diff --git a/doc/tinc.texi b/doc/tinc.texi index 3b92916a..0dfc902d 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -1038,6 +1038,7 @@ example: netmask 255.255.255.0 would become /24, 255.255.252.0 becomes /22. This conforms to standard CIDR notation as described in @uref{ftp://ftp.isi.edu/in-notes/rfc1519.txt, RFC1519} +@cindex Subnet weight 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, @@ -1045,12 +1046,15 @@ unless that node is not reachable, in which case the node with the next highest priority will be tried, and so on. @cindex TCPonly -@item TCPonly = (no) +@item TCPonly = (no) [deprecated] If this variable is set to yes, then the packets are tunnelled over a TCP connection instead of a UDP connection. 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. + +Since version 1.0.10, tinc will automatically detect whether communication via +UDP is possible or not. @end table @@ -1139,6 +1143,10 @@ this is set to the port number it uses for communication with other tinc daemons @item SUBNET When a subnet becomes (un)reachable, this is set to the subnet. +@cindex WEIGHT +@item SUBNET +When a subnet becomes (un)reachable, this is set to the subnet weight. + @end table @@ -1491,7 +1499,7 @@ Use configuration for net @var{netname}. @xref{Multiple networks}. @item -K, --generate-keys[=@var{bits}] Generate public/private keypair of @var{bits} length. If @var{bits} is not specified, -1024 is the default. tinc will ask where you want to store the files, +2048 is the default. tinc will ask where you want to store the files, but will default to the configuration directory (you can use the -c or -n option in combination with -K). After that, tinc will quit. @@ -1633,7 +1641,7 @@ Do you have a firewall or a NAT device (a masquerading firewall or perhaps an AD If so, check that it allows TCP and UDP traffic on port 655. If it masquerades and the host running tinc is behind it, make sure that it forwards TCP and UDP traffic to port 655 to the host running tinc. You can add @samp{TCPOnly = yes} to your host config file to force tinc to only use a single TCP connection, -this works through most firewalls and NATs. +this works through most firewalls and NATs. Since version 1.0.10, tinc will automatically fall back to TCP if direct communication via UDP is not possible. @end itemize @@ -1732,8 +1740,6 @@ or if that is not the case, try changing the prefix length into /32. @itemize @item If you see this only sporadically, it is harmless and caused by a node sending packets using an old key. -@item If you see this often and another node is not reachable anymore, then a NAT (masquerading firewall) is changing the source address of UDP packets. -You can add @samp{TCPOnly = yes} to host configuration files to force all VPN traffic to go over a TCP connection. @end itemize @item Got bad/bogus/unauthorized REQUEST from foo (1.2.3.4 port 12345) diff --git a/doc/tincd.8.in b/doc/tincd.8.in index 358e9701..b8520521 100644 --- a/doc/tincd.8.in +++ b/doc/tincd.8.in @@ -68,7 +68,7 @@ Connect to net Generate public/private RSA keypair and exit. If .Ar BITS -is omitted, the default length will be 1024 bits. +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 Fl L, -mlock From 92b8abc921dd15b710f67335562210eb713fbb39 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 11 Oct 2009 18:57:58 +0200 Subject: [PATCH 08/30] Use MTU probes to regularly ping other nodes over UDP. This keeps NAT mappings for UDP alive, and will also detect when a node is not reachable via UDP anymore or if the path MTU is decreasing. Tinc will fall back to TCP if the node has become unreachable. If UDP communication is impossible, we stop sending probes, but we retry if it changes its keys. We also decouple the UDP and TCP ping mechanisms completely, to ensure tinc properly detects failure of either method. --- src/meta.c | 2 -- src/net_packet.c | 52 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/meta.c b/src/meta.c index 765baeca..21400f29 100644 --- a/src/meta.c +++ b/src/meta.c @@ -225,7 +225,5 @@ bool receive_meta(connection_t *c) { return false; } - c->last_ping_time = now; - return true; } diff --git a/src/net_packet.c b/src/net_packet.c index 63e3592e..7a73ef58 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -58,31 +58,57 @@ static void send_udppacket(node_t *, vpn_packet_t *); #define MAX_SEQNO 1073741824 +// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval +// mtuprobes == 31: sleep pinginterval seconds +// mtuprobes == 32: send 1 burst, sleep pingtimeout second +// mtuprobes == 33: no response from other side, restart PMTU discovery process + void send_mtu_probe(node_t *n) { vpn_packet_t packet; int len, i; + int timeout = 1; n->mtuprobes++; n->mtuevent = NULL; - if(!n->status.reachable) { + if(!n->status.reachable || !n->status.validkey) { logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname); + n->mtuprobes = 0; return; } + if(n->mtuprobes > 32) { + ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname); + n->mtuprobes = 1; + n->minmtu = 0; + n->maxmtu = MTU; + } + if(n->mtuprobes >= 10 && !n->minmtu) { ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname); + n->mtuprobes = 0; return; } - for(i = 0; i < 3; i++) { - if(n->mtuprobes >= 30 || n->minmtu >= n->maxmtu) { - n->mtu = n->minmtu; - ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes); - return; - } + if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) { + n->mtu = n->minmtu; + ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes); + n->mtuprobes = 31; + } + + if(n->mtuprobes == 31) { + timeout = pinginterval; + goto end; + } else if(n->mtuprobes == 32) { + timeout = pingtimeout; + } + + for(i = 0; i < 3; i++) { + if(n->maxmtu <= n->minmtu) + len = n->maxmtu; + else + len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu); - len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu); if(len < 64) len = 64; @@ -96,10 +122,11 @@ void send_mtu_probe(node_t *n) { send_udppacket(n, &packet); } +end: n->mtuevent = new_event(); n->mtuevent->handler = (event_handler_t)send_mtu_probe; n->mtuevent->data = n; - n->mtuevent->time = now + 1; + n->mtuevent->time = now + timeout; event_add(n->mtuevent); } @@ -110,8 +137,12 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { packet->data[0] = 1; send_packet(n, packet); } else { + if(len > n->maxmtu) + len = n->maxmtu; if(n->minmtu < len) n->minmtu = len; + if(n->mtuprobes > 30) + n->mtuprobes = 30; } } @@ -279,9 +310,6 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { inpkt->priority = 0; - if(n->connection) - n->connection->last_ping_time = now; - if(!inpkt->data[12] && !inpkt->data[13]) mtu_probe_h(n, inpkt, origlen); else From ec4c8bcb18c1f463cf4544126e027fc8ec9b3a39 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Mon, 12 Oct 2009 22:14:47 +0200 Subject: [PATCH 09/30] Allow the cloning /dev/tap interface to be used on FreeBSD and NetBSD. This device works like /dev/tun on Linux, automatically creating a new tap interface when a program opens it. We now pass the actual name of the newly created interface in $INTERFACE. --- src/bsd/device.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/bsd/device.c b/src/bsd/device.c index fd1f35dd..06889e3c 100644 --- a/src/bsd/device.c +++ b/src/bsd/device.c @@ -150,6 +150,17 @@ bool setup_device(void) { if(routing_mode == RMODE_ROUTER) overwrite_mac = true; device_info = "Generic BSD tap device"; +#ifdef TAPGIFNAME + { + struct ifreq ifr; + if(ioctl(device_fd, TAPGIFNAME, (void*)&ifr) == 0) { + if(iface) + free(iface); + iface = xstrdup(ifr.ifr_name); + } + } + +#endif break; #ifdef HAVE_TUNEMU case DEVICE_TYPE_TUNEMU: From c7fdc7d5b8d728c744b13a823e7eef9d2432c61e Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Mon, 12 Oct 2009 23:51:57 +0200 Subject: [PATCH 10/30] Remove debugging message when reading packets from a BSD device. This was inadvertently introduced by commit 4a5d42178cc0954efba8b24058da9c70cc77c35a. --- src/bsd/device.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bsd/device.c b/src/bsd/device.c index 06889e3c..c2cd34cb 100644 --- a/src/bsd/device.c +++ b/src/bsd/device.c @@ -279,7 +279,6 @@ bool read_packet(vpn_packet_t *packet) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, device_info); - logger(LOG_INFO, "E:fd_read"); return true; } From 87364c16564c897b1a2d306615804d68ea5a9ba1 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 18 Oct 2009 14:22:20 +0200 Subject: [PATCH 11/30] Include missing header. --- lib/xmalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/xmalloc.c b/lib/xmalloc.c index 9563391e..4e79aff9 100644 --- a/lib/xmalloc.c +++ b/lib/xmalloc.c @@ -34,6 +34,7 @@ void *realloc (); void free (); #endif +#include "dropin.h" #include "xalloc.h" #ifndef EXIT_FAILURE From 3849de9a331ad132ed9d01c9f0cac47196624b3e Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 18 Oct 2009 16:44:32 +0200 Subject: [PATCH 12/30] Fix description of the WEIGHT environment variable. --- doc/tinc.conf.5.in | 1 - doc/tinc.texi | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 9c279a23..1cb2f0c8 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -519,7 +519,6 @@ When a host becomes (un)reachable, this is set to the port number it uses for co .It Ev SUBNET When a subnet becomes (un)reachable, this is set to the subnet. -.El .It Ev WEIGHT When a subnet becomes (un)reachable, this is set to the subnet weight. diff --git a/doc/tinc.texi b/doc/tinc.texi index 0dfc902d..e6e6a42e 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -1144,7 +1144,7 @@ this is set to the port number it uses for communication with other tinc daemons When a subnet becomes (un)reachable, this is set to the subnet. @cindex WEIGHT -@item SUBNET +@item WEIGHT When a subnet becomes (un)reachable, this is set to the subnet weight. @end table From 8c267d3d558ac97a4ce7381a37abb6cc4b46b133 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 18 Oct 2009 16:45:13 +0200 Subject: [PATCH 13/30] Releasing 1.0.10. --- NEWS | 10 ++++++---- README | 9 ++++----- THANKS | 3 ++- configure.in | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index da10928c..b0a5533d 100644 --- a/NEWS +++ b/NEWS @@ -1,17 +1,19 @@ -Version 1.0.10 not yet released +Version 1.0.10 Oct 18 2009 * Fixed potential crashes during shutdown and (in rare conditions) when other nodes disconnected from the VPN. * Improved NAT handling: tinc now copes with mangled port numbers, and will automatically fall back to TCP if direct UDP connection between nodes is not - possible. + possible. The TCPOnly option should not have to be used anymore. * Allow configuration files with CRLF line endings to be read on UNIX. - * Disable old RSA keys when generating new ones. + * Disable old RSA keys when generating new ones, and raise the default size of + new RSA keys to 2048 bits. - * Many fixes in the path MTU discovery code. + * Many fixes in the path MTU discovery code, especially when Compression is + being used. * Tinc can now drop privileges and/or chroot itself. diff --git a/README b/README index 23b24581..a8fff176 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ -This is the README file for tinc version 1.0.9. Installation +This is the README file for tinc version 1.0.10. Installation instructions may be found in the INSTALL file. -tinc is Copyright (C) 1998-2008 by: +tinc is Copyright (C) 1998-2009 by: Ivo Timmermans, Guus Sliepen , @@ -55,7 +55,7 @@ should be changed into "Device", and "Device" should be changed into Compatibility ------------- -Version 1.0.9 is compatible with 1.0pre8, 1.0 and later, but not with older +Version 1.0.10 is compatible with 1.0pre8, 1.0 and later, but not with older versions of tinc. @@ -115,8 +115,7 @@ Support for routing IPv6 packets has been added. Just add Subnet lines with IPv6 addresses (without using :: abbreviations) and use ifconfig or ip (from the iproute package) to give the virtual network interface corresponding IPv6 addresses. tinc does not provide autoconfiguration for IPv6 hosts, if you need -it use radvd or zebra. Tunneling IPv6 packets only works on Linux, FreeBSD, -Windows and possibly OpenBSD. +it use radvd or zebra. It is also possible to make tunnels to other tinc daemons over IPv6 networks, if the operating system supports IPv6. tinc will automatically use both IPv6 diff --git a/THANKS b/THANKS index ed57da59..e0d33d3f 100644 --- a/THANKS +++ b/THANKS @@ -4,8 +4,9 @@ We would like to thank the following people for their contributions to tinc: * Allesandro Gatti * Andreas van Cranenburgh * Armijn Hemel -* dnk * Cris van Pelt +* Delf Eldkraft +* dnk * Enrique Zanardi * Flynn Marquardt * Grzegorz Dymarek diff --git a/configure.in b/configure.in index 01f56ebf..efe9a8ae 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT AC_CONFIG_SRCDIR([src/tincd.c]) -AM_INIT_AUTOMAKE(tinc, 1.0-cvs) +AM_INIT_AUTOMAKE(tinc, 1.0.10) AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE From 35af4051c3749cd2c2137a7eb57171a1fbb12af7 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 20 Oct 2009 22:14:47 +0200 Subject: [PATCH 14/30] Fix a possible crash when sending the HUP signal. When the HUP signal is sent while some outgoing connections have not been made yet, or are being retried, a NULL pointer could be dereferenced resulting in tinc crashing. We fix this by more careful handling of outgoing_ts, and by deleting all connections that have not been fully activated yet at the HUP signal is received. --- src/event.h | 2 +- src/net.c | 27 ++++++++++++++++++++++++++- src/net.h | 1 + src/net_setup.c | 9 ++++++++- src/net_socket.c | 33 +++++++++++++++------------------ 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/event.h b/src/event.h index 345a5f91..da2e741a 100644 --- a/src/event.h +++ b/src/event.h @@ -27,7 +27,7 @@ extern avl_tree_t *event_tree; typedef void (*event_handler_t)(void *); -typedef struct { +typedef struct event { time_t time; int id; event_handler_t handler; diff --git a/src/net.c b/src/net.c index 31970366..59dd39b3 100644 --- a/src/net.c +++ b/src/net.c @@ -431,7 +431,7 @@ int main_loop(void) { if(sighup) { connection_t *c; - avl_node_t *node; + avl_node_t *node, *next; char *fname; struct stat s; @@ -447,6 +447,31 @@ int main_loop(void) { return 1; } + /* Cancel non-active outgoing connections */ + + for(node = connection_tree->head; node; node = next) { + next = node->next; + c = node->data; + + c->outgoing = NULL; + + if(c->status.connecting) { + terminate_connection(c, false); + connection_del(c); + } + } + + /* Wipe list of outgoing connections */ + + for(list_node_t *node = outgoing_list->head; node; node = node->next) { + outgoing_t *outgoing = node->data; + + if(outgoing->event) + event_del(outgoing->event); + } + + list_delete_list(outgoing_list); + /* Close connections to hosts that have a changed or deleted host config file */ for(node = connection_tree->head; node; node = node->next) { diff --git a/src/net.h b/src/net.h index 31438e52..fe4b54b7 100644 --- a/src/net.h +++ b/src/net.h @@ -98,6 +98,7 @@ typedef struct outgoing_t { struct config_t *cfg; struct addrinfo *ai; struct addrinfo *aip; + struct event *event; } outgoing_t; extern list_t *outgoing_list; diff --git a/src/net_setup.c b/src/net_setup.c index a08981f9..cbf631f5 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -541,10 +541,17 @@ void close_network_connections(void) { for(node = connection_tree->head; node; node = next) { next = node->next; c = node->data; - c->outgoing = false; + c->outgoing = NULL; terminate_connection(c, false); } + for(list_node_t *node = outgoing_list->head; node; node = node->next) { + outgoing_t *outgoing = node->data; + + if(outgoing->event) + event_del(outgoing->event); + } + list_delete_list(outgoing_list); if(myself && myself->connection) { diff --git a/src/net_socket.c b/src/net_socket.c index 7189025c..baf0227a 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -306,18 +306,18 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { } /* int setup_vpn_in_socket */ void retry_outgoing(outgoing_t *outgoing) { - event_t *event; - outgoing->timeout += 5; if(outgoing->timeout > maxtimeout) outgoing->timeout = maxtimeout; - event = new_event(); - event->handler = (event_handler_t) setup_outgoing_connection; - event->time = now + outgoing->timeout; - event->data = outgoing; - event_add(event); + if(outgoing->event) + event_del(outgoing->event); + outgoing->event = new_event(); + outgoing->event->handler = (event_handler_t) setup_outgoing_connection; + outgoing->event->time = now + outgoing->timeout; + outgoing->event->data = outgoing; + event_add(outgoing->event); ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Trying to re-establish outgoing connection in %d seconds", @@ -338,6 +338,11 @@ void do_outgoing_connection(connection_t *c) { char *address, *port; int result; + if(!c->outgoing) { + logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name); + abort(); + } + begin: if(!c->outgoing->ai) { if(!c->outgoing->cfg) { @@ -345,6 +350,7 @@ begin: c->name); c->status.remove = true; retry_outgoing(c->outgoing); + c->outgoing = NULL; return; } @@ -431,6 +437,8 @@ void setup_outgoing_connection(outgoing_t *outgoing) { connection_t *c; node_t *n; + outgoing->event = NULL; + n = lookup_node(outgoing->name); if(n) @@ -525,18 +533,7 @@ void try_outgoing_connections(void) { static config_t *cfg = NULL; char *name; outgoing_t *outgoing; - connection_t *c; - avl_node_t *node; - if(outgoing_list) { - for(node = connection_tree->head; node; node = node->next) { - c = node->data; - c->outgoing = NULL; - } - - list_delete_list(outgoing_list); - } - outgoing_list = list_alloc((list_action_t)free_outgoing); for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) { From 3a925479c2883a6a9711f7b6931863d7f2a2c09b Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 20 Oct 2009 22:22:59 +0200 Subject: [PATCH 15/30] Starting to work towards 1.0.11. --- NEWS | 4 ++++ configure.in | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index b0a5533d..0d5d2ade 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Version 1.0.11 Not released yet. + + * Fixed potential crash when the HUP signal is sent. + Version 1.0.10 Oct 18 2009 * Fixed potential crashes during shutdown and (in rare conditions) when other diff --git a/configure.in b/configure.in index efe9a8ae..89ef5b28 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT AC_CONFIG_SRCDIR([src/tincd.c]) -AM_INIT_AUTOMAKE(tinc, 1.0.10) +AM_INIT_AUTOMAKE(tinc, 1.0.11~git) AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE From 43a6e786648fb666a9b7be8f05c8a173031c9110 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 20 Oct 2009 22:33:16 +0200 Subject: [PATCH 16/30] Handle weighted Subnets in switch and hub modes. We now handle MAC Subnets in exactly the same way as IPv4 and IPv6 Subnets. This also fixes a problem that causes unncessary broadcasting of unicast packets in VPNs where some daemons run 1.0.10 and some run other versions. --- src/route.c | 1 + src/subnet.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/route.c b/src/route.c index 2da781e5..5c69671a 100644 --- a/src/route.c +++ b/src/route.c @@ -117,6 +117,7 @@ static void learn_mac(mac_t *address) { subnet->type = SUBNET_MAC; subnet->expires = now + macexpire; subnet->net.mac.address = *address; + subnet->weight = 10; subnet_add(myself, subnet); /* And tell all other tinc daemons it's our MAC */ diff --git a/src/subnet.c b/src/subnet.c index ef4e59e9..3d1168de 100644 --- a/src/subnet.c +++ b/src/subnet.c @@ -47,9 +47,15 @@ static subnet_t *cache_ipv6_subnet[2]; static bool cache_ipv6_valid[2]; static int cache_ipv6_slot; +static mac_t cache_mac_address[2]; +static subnet_t *cache_mac_subnet[2]; +static bool cache_mac_valid[2]; +static int cache_mac_slot; + void subnet_cache_flush() { cache_ipv4_valid[0] = cache_ipv4_valid[1] = false; cache_ipv6_valid[0] = cache_ipv6_valid[1] = false; + cache_mac_valid[0] = cache_mac_valid[1] = false; } /* Subnet comparison */ @@ -324,15 +330,46 @@ subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) { } subnet_t *lookup_subnet_mac(const mac_t *address) { - subnet_t *p, subnet = {0}; + subnet_t *p, *r = NULL, subnet = {0}; + avl_node_t *n; + int i; + + // Check if this address is cached + + for(i = 0; i < 2; i++) { + if(!cache_mac_valid[i]) + continue; + if(!memcmp(address, &cache_mac_address[i], sizeof *address)) + return cache_mac_subnet[i]; + } + + // Search all subnets for a matching one subnet.type = SUBNET_MAC; subnet.net.mac.address = *address; subnet.owner = NULL; - p = avl_search(subnet_tree, &subnet); + for(n = subnet_tree->head; n; n = n->next) { + p = n->data; + + if(!p || p->type != subnet.type) + continue; - return p; + if(!memcmp(address, &p->net.mac.address, sizeof *address)) { + r = p; + if(p->owner->status.reachable) + break; + } + } + + // Cache the result + + cache_mac_slot = !cache_mac_slot; + memcpy(&cache_mac_address[cache_mac_slot], address, sizeof *address); + cache_mac_subnet[cache_mac_slot] = r; + cache_mac_valid[cache_mac_slot] = true; + + return r; } subnet_t *lookup_subnet_ipv4(const ipv4_t *address) { From b6543af7626403516b5fc54c24b11d3a242a2992 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 20 Oct 2009 22:39:07 +0200 Subject: [PATCH 17/30] Clarify and increase level of log message about MTU probes to unreachable nodes. --- src/net_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net_packet.c b/src/net_packet.c index 7a73ef58..9b0e4685 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -72,7 +72,7 @@ void send_mtu_probe(node_t *n) { n->mtuevent = NULL; if(!n->status.reachable || !n->status.validkey) { - logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname); + ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname); n->mtuprobes = 0; return; } From 468f393c4fabf9223a1bd15adfb3906cde90d547 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 24 Oct 2009 16:05:12 +0200 Subject: [PATCH 18/30] Add dummy device. --- src/dummy/device.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/dummy/device.c diff --git a/src/dummy/device.c b/src/dummy/device.c new file mode 100644 index 00000000..a9600b28 --- /dev/null +++ b/src/dummy/device.c @@ -0,0 +1,54 @@ +/* + device.c -- Dummy device + Copyright (C) 2009 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 "logger.h" +#include "net.h" + +int device_fd = -1; +char *device = "dummy"; +char *iface = "dummy"; +static char *device_info = "dummy device"; + +static int device_total_in = 0; +static int device_total_out = 0; + +bool setup_device(void) { + logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info); + return true; +} + +void close_device(void) { +} + +bool read_packet(vpn_packet_t *packet) { + return false; +} + +bool write_packet(vpn_packet_t *packet) { + device_total_out += packet->len; + return true; +} + +void dump_device_stats(void) { + logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device); + logger(LOG_DEBUG, " total bytes in: %10d", device_total_in); + logger(LOG_DEBUG, " total bytes out: %10d", device_total_out); +} From 5cbddc68bade0d1f8ded1b784bb27bb44c5dc5dc Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 24 Oct 2009 16:15:24 +0200 Subject: [PATCH 19/30] Use uint32_t instead of long int for connection options. Options should have a fixed width anyway, but this also fixes a possible MinGW compiler bug where %lx tries to print a 64 bit value, even though a long int is only 32 bits. --- src/connection.c | 2 +- src/connection.h | 2 +- src/edge.c | 2 +- src/edge.h | 2 +- src/node.c | 2 +- src/node.h | 2 +- src/protocol_auth.c | 6 +++--- src/protocol_edge.c | 6 +++--- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/connection.c b/src/connection.c index 6e942f8e..9a26ec9d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -120,7 +120,7 @@ void dump_connections(void) { for(node = connection_tree->head; node; node = node->next) { c = node->data; - logger(LOG_DEBUG, " %s at %s options %lx socket %d status %04x outbuf %d/%d/%d", + logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d", c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof c->status), c->outbufsize, c->outbufstart, c->outbuflen); } diff --git a/src/connection.h b/src/connection.h index 24c95f4c..b3a7e33f 100644 --- a/src/connection.h +++ b/src/connection.h @@ -56,7 +56,7 @@ typedef struct connection_t { int protocol_version; /* used protocol */ int socket; /* socket used for this connection */ - long int options; /* options for this connection */ + uint32_t options; /* options for this connection */ connection_status_t status; /* status info */ int estimated_weight; /* estimation for the weight of the edge for this connection */ struct timeval start; /* time this connection was started, used for above estimation */ diff --git a/src/edge.c b/src/edge.c index 9e1b31eb..e42dbd17 100644 --- a/src/edge.c +++ b/src/edge.c @@ -118,7 +118,7 @@ void dump_edges(void) { for(node2 = n->edge_tree->head; node2; node2 = node2->next) { e = node2->data; address = sockaddr2hostname(&e->address); - logger(LOG_DEBUG, " %s to %s at %s options %lx weight %d", + logger(LOG_DEBUG, " %s to %s at %s options %x weight %d", e->from->name, e->to->name, address, e->options, e->weight); free(address); } diff --git a/src/edge.h b/src/edge.h index dc5cf461..4c65213b 100644 --- a/src/edge.h +++ b/src/edge.h @@ -31,7 +31,7 @@ typedef struct edge_t { struct node_t *to; sockaddr_t address; - long int options; /* options turned on for this edge */ + uint32_t options; /* options turned on for this edge */ int weight; /* weight of this edge */ struct connection_t *connection; /* connection associated with this edge, if available */ diff --git a/src/node.c b/src/node.c index c1f12194..b323dca3 100644 --- a/src/node.c +++ b/src/node.c @@ -162,7 +162,7 @@ void dump_nodes(void) { for(node = node_tree->head; node; node = node->next) { n = node->data; - logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)", + logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s pmtu %d (min %d max %d)", n->name, n->hostname, n->outcipher ? n->outcipher->nid : 0, n->outdigest ? n->outdigest->type : 0, n->outmaclength, n->outcompression, n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-", diff --git a/src/node.h b/src/node.h index 619baa94..a621a0a2 100644 --- a/src/node.h +++ b/src/node.h @@ -39,7 +39,7 @@ typedef struct node_status_t { typedef struct node_t { char *name; /* name of this node */ - long int options; /* options turned on for this node */ + uint32_t options; /* options turned on for this node */ sockaddr_t address; /* his real (internet) ip to send UDP packets to */ char *hostname; /* the hostname of its real ip */ diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 24f591a7..c2df4cd8 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -455,7 +455,7 @@ bool send_ack(connection_t *c) { get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight); - return send_request(c, "%d %s %d %lx", ACK, myport, c->estimated_weight, c->options); + return send_request(c, "%d %s %d %x", ACK, myport, c->estimated_weight, c->options); } static void send_everything(connection_t *c) { @@ -494,10 +494,10 @@ bool ack_h(connection_t *c) { char hisport[MAX_STRING_SIZE]; char *hisaddress, *dummy; int weight, mtu; - long int options; + uint32_t options; node_t *n; - if(sscanf(c->buffer, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) { + if(sscanf(c->buffer, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name, c->hostname); return false; diff --git a/src/protocol_edge.c b/src/protocol_edge.c index 9d439225..300333b6 100644 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -41,7 +41,7 @@ bool send_add_edge(connection_t *c, const edge_t *e) { sockaddr2str(&e->address, &address, &port); - x = send_request(c, "%d %x %s %s %s %s %lx %d", ADD_EDGE, rand(), + x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(), e->from->name, e->to->name, address, port, e->options, e->weight); free(address); @@ -58,10 +58,10 @@ bool add_edge_h(connection_t *c) { char to_address[MAX_STRING_SIZE]; char to_port[MAX_STRING_SIZE]; sockaddr_t address; - long int options; + uint32_t options; int weight; - if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d", + if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d", from_name, to_name, to_address, to_port, &options, &weight) != 6) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, c->hostname); From cddcdc9af34afb388a8e4bdfff6882f568b98313 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 24 Oct 2009 20:54:44 +0200 Subject: [PATCH 20/30] Allow UDP packets with an address different from the corresponding TCP connection. --- src/net_packet.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/net_packet.c b/src/net_packet.c index 9b0e4685..7bf12497 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -521,12 +521,16 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { avl_node_t *node; edge_t *e; node_t *n = NULL; + static time_t last_hard_try = 0; for(node = edge_weight_tree->head; node; node = node->next) { e = node->data; - if(sockaddrcmp_noport(from, &e->address)) - continue; + if(sockaddrcmp_noport(from, &e->address)) { + if(last_hard_try == now) + continue; + last_hard_try = now; + } if(!n) n = e->to; From a8f7fccbc2b5f1c4c39fc2804abaa358b31a5080 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 24 Oct 2009 21:32:06 +0200 Subject: [PATCH 21/30] Always reply to MTU probes via UDP. It could sometime happen that a node would return MTU probes via TCP, which does not make a lot of sense. --- src/net_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net_packet.c b/src/net_packet.c index 7bf12497..626f8b1c 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -135,7 +135,7 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { if(!packet->data[0]) { packet->data[0] = 1; - send_packet(n, packet); + send_udppacket(n, packet); } else { if(len > n->maxmtu) len = n->maxmtu; From d922db253cd098bc038449e5c591cc94c1019952 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 24 Oct 2009 21:35:40 +0200 Subject: [PATCH 22/30] Make maxmtu equal to minmtu when fixing the path MTU to a node. This ensures MTU probes used to ping nodes are not too large, and prevents restarting MTU probing unnecessarily. --- src/net_packet.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/net_packet.c b/src/net_packet.c index 626f8b1c..3466f87e 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -91,6 +91,10 @@ void send_mtu_probe(node_t *n) { } if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) { + if(n->minmtu > n->maxmtu) + n->minmtu = n->maxmtu; + else + n->maxmtu = n->minmtu; n->mtu = n->minmtu; ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes); n->mtuprobes = 31; From 242c4e2ca67d0b5c78dfe6e68a5ddcd27be1de99 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 24 Oct 2009 21:53:01 +0200 Subject: [PATCH 23/30] Forward packets to not directly reachable hosts via UDP if possible. If MTU probing discovered a node was not reachable via UDP, packets for it were forwarded to the next hop, but always via TCP, even if the next hop was reachable via UDP. This is now fixed by retrying to send the packet using send_packet() if the destination is not the same as the nexthop. --- src/net_packet.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/net_packet.c b/src/net_packet.c index 3466f87e..054a66fe 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -369,10 +369,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) { ifdebug(TRAFFIC) logger(LOG_INFO, - "Packet for %s (%s) larger than minimum MTU, forwarding via TCP", - n->name, n->hostname); + "Packet for %s (%s) larger than minimum MTU, forwarding via %s", + n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP"); - send_tcppacket(n->nexthop->connection, origpkt); + if(n != n->nexthop) + send_packet(n->nexthop, origpkt); + else + send_tcppacket(n->nexthop->connection, origpkt); return; } From c3acae034c4da2d1c70f31b852b14ca098c0eeb9 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 24 Oct 2009 22:32:35 +0200 Subject: [PATCH 24/30] Use IP_DONTFRAGMENT instead of IP_MTU_DISCOVER on Windows. This ensures the DF bit on outgoing UDP packets gets set on Windows when path MTU discovery is enabled, reducing fragmentation. --- src/net_socket.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/net_socket.c b/src/net_socket.c index baf0227a..f5a569b2 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -279,6 +279,11 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { option = IP_PMTUDISC_DO; setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, &option, sizeof(option)); } +#elif defined(IPPROTO_IP) && defined(IP_DONTFRAGMENT) + if(myself->options & OPTION_PMTU_DISCOVERY) { + option = 1; + setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, &option, sizeof(option)); + } #endif #if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) From 1bca167b7e24a9cb00ad6130c24f0bb60e208f1f Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sun, 18 Oct 2009 21:27:24 +0400 Subject: [PATCH 25/30] Remove localedir leftovers. --- src/Makefile.am | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index bdd1a3f8..491f0115 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,9 +30,7 @@ endif tincd_LDADD = \ $(top_builddir)/lib/libvpn.a -localedir = $(datadir)/locale - -AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" +AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" dist-hook: rm -f `find . -type l` From c11dc8079b60d9f8c5b1c7e8fecd90d0fac5a20c Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 25 Oct 2009 00:50:09 +0200 Subject: [PATCH 26/30] Use WSAGetLastError() to determine cause of network errors on Windows. This reduces log spam and lets path MTU discovery work faster. --- src/net_packet.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/net_packet.c b/src/net_packet.c index 054a66fe..32436702 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -46,8 +46,16 @@ #include "utils.h" #include "xalloc.h" -#ifdef WSAEMSGSIZE +#ifdef HAVE_MINGW +#include #define EMSGSIZE WSAEMSGSIZE +#define EAGAIN WSATRY_AGAIN +#define EINTR WSAEINTR +#define sockstrerror(x) winerror(x) +#define sockerrno WSAGetLastError() +#else +#define sockstrerror(x) strerror(x) +#define sockerrno errno #endif int keylifetime = 0; @@ -450,13 +458,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { #endif if((sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa))) < 0) { - if(errno == EMSGSIZE) { + if(sockerrno == EMSGSIZE) { if(n->maxmtu >= origlen) n->maxmtu = origlen - 1; if(n->mtu >= origlen) n->mtu = origlen - 1; } else - logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, strerror(errno)); + logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno)); } end: @@ -562,8 +570,8 @@ void handle_incoming_vpn_data(int sock) { pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); if(pkt.len < 0) { - if(errno != EAGAIN && errno != EINTR) - logger(LOG_ERR, "Receiving packet failed: %s", strerror(errno)); + if(sockerrno != EAGAIN && sockerrno != EINTR) + logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); return; } From e00b44cb98e4d50a0d426048ba01dbd80bcb5941 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 25 Oct 2009 01:40:07 +0200 Subject: [PATCH 27/30] Move socket error interpretation to utils.h. --- lib/utils.h | 11 +++++++++++ src/meta.c | 10 ++++------ src/net.c | 7 +++---- src/net_packet.c | 18 +++--------------- src/net_socket.c | 42 +++++++++++++----------------------------- 5 files changed, 34 insertions(+), 54 deletions(-) diff --git a/lib/utils.h b/lib/utils.h index c6fb1807..4456616d 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -27,6 +27,17 @@ extern void bin2hex(char *src, char *dst, int length); #ifdef HAVE_MINGW extern const char *winerror(int); #define strerror(x) ((x)>0?strerror(x):winerror(GetLastError())) +#define sockerrno WSAGetLastError() +#define sockstrerror(x) winerror(x) +#define sockwouldblock(x) ((x) == WSAEWOULDBLOCK || (x) == WSAEINTR) +#define sockmsgsize(x) ((x) == WSAEMSGSIZE) +#define sockinprogress(x) ((x) == WSAEINPROGRESS || (x) == WSAEWOULDBLOCK) +#else +#define sockerrno errno +#define sockstrerror(x) strerror(x) +#define sockwouldblock(x) ((x) == EWOULDBLOCK || (x) == EINTR) +#define sockmsgsize(x) ((x) == EMSGSIZE) +#define sockinprogress(x) ((x) == EINPROGRESS) #endif extern unsigned int bitfield_to_int(void *bitfield, size_t size); diff --git a/src/meta.c b/src/meta.c index 21400f29..4c52464c 100644 --- a/src/meta.c +++ b/src/meta.c @@ -94,15 +94,13 @@ bool flush_meta(connection_t *c) { c->name, c->hostname); } else if(errno == EINTR) { continue; -#ifdef EWOULDBLOCK - } else if(errno == EWOULDBLOCK) { + } else if(sockwouldblock(sockerrno)) { ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block", c->outbuflen, c->name, c->hostname); return true; -#endif } else { logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name, - c->hostname, strerror(errno)); + c->hostname, sockstrerror(sockerrno)); } return false; @@ -149,11 +147,11 @@ bool receive_meta(connection_t *c) { if(!lenin || !errno) { ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", c->name, c->hostname); - } else if(errno == EINTR) + } else if(sockwouldblock(sockerrno)) return true; else logger(LOG_ERR, "Metadata socket read error for %s (%s): %s", - c->name, c->hostname, strerror(errno)); + c->name, c->hostname, sockstrerror(sockerrno)); return false; } diff --git a/src/net.c b/src/net.c index 59dd39b3..3f17083c 100644 --- a/src/net.c +++ b/src/net.c @@ -303,7 +303,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) { else { ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Error while connecting to %s (%s): %s", - c->name, c->hostname, strerror(result)); + c->name, c->hostname, sockstrerror(result)); closesocket(c->socket); do_outgoing_connection(c); continue; @@ -369,9 +369,8 @@ int main_loop(void) { #endif if(r < 0) { - if(errno != EINTR && errno != EAGAIN) { - logger(LOG_ERR, "Error while waiting for input: %s", - strerror(errno)); + if(!sockwouldblock(sockerrno)) { + logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno)); dump_connections(); return 1; } diff --git a/src/net_packet.c b/src/net_packet.c index 32436702..e5011532 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -46,18 +46,6 @@ #include "utils.h" #include "xalloc.h" -#ifdef HAVE_MINGW -#include -#define EMSGSIZE WSAEMSGSIZE -#define EAGAIN WSATRY_AGAIN -#define EINTR WSAEINTR -#define sockstrerror(x) winerror(x) -#define sockerrno WSAGetLastError() -#else -#define sockstrerror(x) strerror(x) -#define sockerrno errno -#endif - int keylifetime = 0; int keyexpires = 0; static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS]; @@ -457,8 +445,8 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { } #endif - if((sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa))) < 0) { - if(sockerrno == EMSGSIZE) { + if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) { + if(sockmsgsize(sockerrno)) { if(n->maxmtu >= origlen) n->maxmtu = origlen - 1; if(n->mtu >= origlen) @@ -570,7 +558,7 @@ void handle_incoming_vpn_data(int sock) { pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); if(pkt.len < 0) { - if(sockerrno != EAGAIN && sockerrno != EINTR) + if(!sockwouldblock(sockerrno)) logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); return; } diff --git a/src/net_socket.c b/src/net_socket.c index f5a569b2..46e0532e 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -36,10 +36,6 @@ #include -#ifdef WSAEINPROGRESS -#define EINPROGRESS WSAEINPROGRESS -#endif - /* Needed on Mac OS/X */ #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP @@ -68,7 +64,7 @@ static void configure_tcp(connection_t *c) { unsigned long arg = 1; if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) { - logger(LOG_ERR, "ioctlsocket for %s: WSA error %d", c->hostname, WSAGetLastError()); + logger(LOG_ERR, "ioctlsocket for %s: %d", c->hostname, sockstrerror(sockerrno)); } #endif @@ -157,8 +153,7 @@ static bool bind_to_address(connection_t *c) { if(status) { - logger(LOG_ERR, "Can't bind to %s/tcp: %s", node, - strerror(errno)); + logger(LOG_ERR, "Can't bind to %s/tcp: %s", node, sockstrerror(sockerrno)); } else ifdebug(CONNECTIONS) { logger(LOG_DEBUG, "Successfully bound outgoing " "TCP socket to %s", node); @@ -179,7 +174,7 @@ int setup_listen_socket(const sockaddr_t *sa) { nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP); if(nfd < 0) { - ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", strerror(errno)); + ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno)); return -1; } @@ -204,7 +199,7 @@ int setup_listen_socket(const sockaddr_t *sa) { if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) { closesocket(nfd); logger(LOG_ERR, "Can't bind to interface %s: %s", iface, - strerror(errno)); + strerror(sockerrno)); return -1; } #else @@ -215,16 +210,14 @@ int setup_listen_socket(const sockaddr_t *sa) { if(bind(nfd, &sa->sa, SALEN(sa->sa))) { closesocket(nfd); addrstr = sockaddr2hostname(sa); - logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, - strerror(errno)); + logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno)); free(addrstr); return -1; } if(listen(nfd, 3)) { closesocket(nfd); - logger(LOG_ERR, "System call `%s' failed: %s", "listen", - strerror(errno)); + logger(LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno)); return -1; } @@ -239,7 +232,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP); if(nfd < 0) { - logger(LOG_ERR, "Creating UDP socket failed: %s", strerror(errno)); + logger(LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno)); return -1; } @@ -259,8 +252,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { unsigned long arg = 1; if(ioctlsocket(nfd, FIONBIO, &arg) != 0) { closesocket(nfd); - logger(LOG_ERR, "Call to `%s' failed: WSA error %d", "ioctlsocket", - WSAGetLastError()); + logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno)); return -1; } } @@ -301,8 +293,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { if(bind(nfd, &sa->sa, SALEN(sa->sa))) { closesocket(nfd); addrstr = sockaddr2hostname(sa); - logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr, - strerror(errno)); + logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno)); free(addrstr); return -1; } @@ -393,9 +384,7 @@ begin: c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); if(c->socket == -1) { - ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, - strerror(errno)); - + ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno)); goto begin; } @@ -417,18 +406,14 @@ begin: result = connect(c->socket, &c->address.sa, SALEN(c->address.sa)); if(result == -1) { - if(errno == EINPROGRESS -#if defined(WIN32) && !defined(O_NONBLOCK) - || WSAGetLastError() == WSAEWOULDBLOCK -#endif - ) { + if(sockinprogress(sockerrno)) { c->status.connecting = true; return; } closesocket(c->socket); - ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, strerror(errno)); + ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, sockstrerror(sockerrno)); goto begin; } @@ -493,8 +478,7 @@ bool handle_new_meta_connection(int sock) { fd = accept(sock, &sa.sa, &len); if(fd < 0) { - logger(LOG_ERR, "Accepting a new connection failed: %s", - strerror(errno)); + logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno)); return false; } From 6f6f426b353596edca77829c0477268fc2fc1925 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 27 Oct 2009 23:53:49 +0100 Subject: [PATCH 28/30] Fast handoff of roaming MAC addresses. In switch mode, if a known MAC address is claimed by a second node before it expired at the first node, it is likely that this is because a computer has roamed from the LAN of the first node to that of the second node. To ensure packets for that computer are routed to the second node, the first node should delete its corresponding Subnet as soon as possible, without waiting for the normal expiry timeout. --- src/protocol_subnet.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/protocol_subnet.c b/src/protocol_subnet.c index f7ce53b9..ba75c899 100644 --- a/src/protocol_subnet.c +++ b/src/protocol_subnet.c @@ -45,7 +45,7 @@ bool add_subnet_h(connection_t *c) { char subnetstr[MAX_STRING_SIZE]; char name[MAX_STRING_SIZE]; node_t *owner; - subnet_t s = {0}, *new; + subnet_t s = {0}, *new, *old; if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name, @@ -142,6 +142,11 @@ bool add_subnet_h(connection_t *c) { if(!tunnelserver) forward_request(c); + /* Fast handoff of roaming MAC addresses */ + + if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires) + old->expires = now; + return true; } From d331f04e4598824afc7de33ac1228cf441ae9872 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 1 Nov 2009 15:57:28 +0100 Subject: [PATCH 29/30] Start a tinc service if it already exists. --- src/process.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/process.c b/src/process.c index 01ebe494..6d0e499a 100644 --- a/src/process.c +++ b/src/process.c @@ -103,13 +103,18 @@ bool install_service(void) { command, NULL, NULL, NULL, NULL, NULL); if(!service) { - logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(GetLastError())); - return false; + DWORD lasterror = GetLastError(); + logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror)); + if(lasterror != ERROR_SERVICE_EXISTS) + return false; } - ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description); - - logger(LOG_INFO, "%s service installed", identname); + if(service) { + ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description); + logger(LOG_INFO, "%s service installed", identname); + } else { + service = OpenService(manager, identname, SERVICE_ALL_ACCESS); + } if(!StartService(service, 0, NULL)) logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError())); From 44834d030464bbe1f7733caba8d96c678f1d6cf2 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 1 Nov 2009 16:24:39 +0100 Subject: [PATCH 30/30] Releasing 1.0.11. --- NEWS | 15 ++++++++++++++- README | 4 ++-- configure.in | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 0d5d2ade..330efbc1 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,20 @@ -Version 1.0.11 Not released yet. +Version 1.0.11 Nov 1 2009 * Fixed potential crash when the HUP signal is sent. + * Fixes handling of weighted Subnets in switch and hub modes, preventing + unnecessary broadcasts. + + * Works around a MinGW bug that caused packets to Windows nodes to always be + sent via TCP. + + * Improvements to the PMTU discovery code, especially on Windows. + + * Use UDP again in certain cases where 1.0.10 was too conservative and fell + back to TCP unnecessarily. + + * Allow fast roaming of hosts to other nodes in a switched VPN. + Version 1.0.10 Oct 18 2009 * Fixed potential crashes during shutdown and (in rare conditions) when other diff --git a/README b/README index a8fff176..8f76b150 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is the README file for tinc version 1.0.10. Installation +This is the README file for tinc version 1.0.11. Installation instructions may be found in the INSTALL file. tinc is Copyright (C) 1998-2009 by: @@ -55,7 +55,7 @@ should be changed into "Device", and "Device" should be changed into Compatibility ------------- -Version 1.0.10 is compatible with 1.0pre8, 1.0 and later, but not with older +Version 1.0.11 is compatible with 1.0pre8, 1.0 and later, but not with older versions of tinc. diff --git a/configure.in b/configure.in index 89ef5b28..21a5818f 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) AC_INIT AC_CONFIG_SRCDIR([src/tincd.c]) -AM_INIT_AUTOMAKE(tinc, 1.0.11~git) +AM_INIT_AUTOMAKE(tinc, 1.0.11) AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE