From 23bd9e9d5316bec02b327a60565bbbc0fc825169 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Mon, 26 Aug 2019 13:44:38 +0200 Subject: [PATCH] Import Upstream version 1.0.11 --- ChangeLog | 139 ++++++++++++++++++++++++++++++++++++++++++ NEWS | 17 ++++++ README | 4 +- configure | 2 +- configure.in | 2 +- doc/tinc.info | 2 +- lib/utils.h | 11 ++++ src/Makefile.am | 4 +- src/Makefile.in | 4 +- src/connection.c | 2 +- src/connection.h | 2 +- src/edge.c | 2 +- src/edge.h | 2 +- src/event.h | 2 +- src/meta.c | 10 ++- src/net.c | 34 +++++++++-- src/net.h | 1 + src/net_packet.c | 39 +++++++----- src/net_setup.c | 9 ++- src/net_socket.c | 80 ++++++++++-------------- src/node.c | 2 +- src/node.h | 2 +- src/process.c | 15 +++-- src/protocol_auth.c | 6 +- src/protocol_edge.c | 6 +- src/protocol_subnet.c | 7 ++- src/route.c | 1 + src/subnet.c | 43 ++++++++++++- 28 files changed, 343 insertions(+), 107 deletions(-) diff --git a/ChangeLog b/ChangeLog index d906b29..0f3aeef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,142 @@ +commit 44834d030464bbe1f7733caba8d96c678f1d6cf2 +Author: Guus Sliepen +Date: Sun Nov 1 16:24:39 2009 +0100 + + Releasing 1.0.11. + +commit d331f04e4598824afc7de33ac1228cf441ae9872 +Author: Guus Sliepen +Date: Sun Nov 1 15:57:28 2009 +0100 + + Start a tinc service if it already exists. + +commit 6f6f426b353596edca77829c0477268fc2fc1925 +Author: Guus Sliepen +Date: Tue Oct 27 23:53:49 2009 +0100 + + 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. + +commit e00b44cb98e4d50a0d426048ba01dbd80bcb5941 +Author: Guus Sliepen +Date: Sun Oct 25 01:40:07 2009 +0200 + + Move socket error interpretation to utils.h. + +commit c11dc8079b60d9f8c5b1c7e8fecd90d0fac5a20c +Author: Guus Sliepen +Date: Sun Oct 25 00:50:09 2009 +0200 + + Use WSAGetLastError() to determine cause of network errors on Windows. + + This reduces log spam and lets path MTU discovery work faster. + +commit 1bca167b7e24a9cb00ad6130c24f0bb60e208f1f +Author: Michael Tokarev +Date: Sun Oct 18 21:27:24 2009 +0400 + + Remove localedir leftovers. + +commit c3acae034c4da2d1c70f31b852b14ca098c0eeb9 +Author: Guus Sliepen +Date: Sat Oct 24 22:32:35 2009 +0200 + + 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. + +commit 242c4e2ca67d0b5c78dfe6e68a5ddcd27be1de99 +Author: Guus Sliepen +Date: Sat Oct 24 21:53:01 2009 +0200 + + 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. + +commit d922db253cd098bc038449e5c591cc94c1019952 +Author: Guus Sliepen +Date: Sat Oct 24 21:35:40 2009 +0200 + + 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. + +commit a8f7fccbc2b5f1c4c39fc2804abaa358b31a5080 +Author: Guus Sliepen +Date: Sat Oct 24 21:32:06 2009 +0200 + + 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. + +commit cddcdc9af34afb388a8e4bdfff6882f568b98313 +Author: Guus Sliepen +Date: Sat Oct 24 20:54:44 2009 +0200 + + Allow UDP packets with an address different from the corresponding TCP connection. + +commit 5cbddc68bade0d1f8ded1b784bb27bb44c5dc5dc +Author: Guus Sliepen +Date: Sat Oct 24 16:15:24 2009 +0200 + + 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. + +commit 468f393c4fabf9223a1bd15adfb3906cde90d547 +Author: Guus Sliepen +Date: Sat Oct 24 16:05:12 2009 +0200 + + Add dummy device. + +commit b6543af7626403516b5fc54c24b11d3a242a2992 +Author: Guus Sliepen +Date: Tue Oct 20 22:39:07 2009 +0200 + + Clarify and increase level of log message about MTU probes to unreachable nodes. + +commit 43a6e786648fb666a9b7be8f05c8a173031c9110 +Author: Guus Sliepen +Date: Tue Oct 20 22:33:16 2009 +0200 + + 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. + +commit 3a925479c2883a6a9711f7b6931863d7f2a2c09b +Author: Guus Sliepen +Date: Tue Oct 20 22:22:59 2009 +0200 + + Starting to work towards 1.0.11. + +commit 35af4051c3749cd2c2137a7eb57171a1fbb12af7 +Author: Guus Sliepen +Date: Tue Oct 20 22:14:47 2009 +0200 + + 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. + commit 8c267d3d558ac97a4ce7381a37abb6cc4b46b133 Author: Guus Sliepen Date: Sun Oct 18 16:45:13 2009 +0200 diff --git a/NEWS b/NEWS index b0a5533..330efbc 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,20 @@ +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 a8fff17..8f76b15 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 b/configure index 331668f..21baffb 100755 --- a/configure +++ b/configure @@ -2701,7 +2701,7 @@ fi # Define the identity of the package. PACKAGE=tinc - VERSION=1.0.10 + VERSION=1.0.11 cat >>confdefs.h <<_ACEOF diff --git a/configure.in b/configure.in index efe9a8a..21a5818 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) AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE diff --git a/doc/tinc.info b/doc/tinc.info index fe5c670..8af5678 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.0.10, a Virtual Private + This is the info manual for tinc version 1.0.11, a Virtual Private Network daemon. Copyright (C) 1998-2009 Ivo Timmermans, Guus Sliepen diff --git a/lib/utils.h b/lib/utils.h index c6fb180..4456616 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/Makefile.am b/src/Makefile.am index bdd1a3f..491f011 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` diff --git a/src/Makefile.in b/src/Makefile.in index 6bae860..1f9e7f5 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -166,7 +166,7 @@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ -localedir = $(datadir)/locale +localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ @@ -197,7 +197,7 @@ noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h logger.h me tincd_LDADD = \ $(top_builddir)/lib/libvpn.a -AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" +AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" all: all-am .SUFFIXES: diff --git a/src/connection.c b/src/connection.c index 6e942f8..9a26ec9 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 24c95f4..b3a7e33 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 9e1b31e..e42dbd1 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 dc5cf46..4c65213 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/event.h b/src/event.h index 345a5f9..da2e741 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/meta.c b/src/meta.c index 21400f2..4c52464 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 3197036..3f17083 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; } @@ -431,7 +430,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 +446,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 31438e5..fe4b54b 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_packet.c b/src/net_packet.c index 7a73ef5..e501153 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -46,10 +46,6 @@ #include "utils.h" #include "xalloc.h" -#ifdef WSAEMSGSIZE -#define EMSGSIZE WSAEMSGSIZE -#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]; @@ -72,7 +68,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; } @@ -91,6 +87,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; @@ -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; @@ -365,10 +365,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; } @@ -442,14 +445,14 @@ 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(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) 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: @@ -521,12 +524,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; @@ -551,8 +558,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(!sockwouldblock(sockerrno)) + logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); return; } diff --git a/src/net_setup.c b/src/net_setup.c index a08981f..cbf631f 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 7189025..46e0532 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; } } @@ -279,6 +271,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) @@ -296,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; } @@ -306,18 +302,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 +334,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 +346,7 @@ begin: c->name); c->status.remove = true; retry_outgoing(c->outgoing); + c->outgoing = NULL; return; } @@ -382,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; } @@ -406,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; } @@ -431,6 +427,8 @@ void setup_outgoing_connection(outgoing_t *outgoing) { connection_t *c; node_t *n; + outgoing->event = NULL; + n = lookup_node(outgoing->name); if(n) @@ -480,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; } @@ -525,18 +522,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)) { diff --git a/src/node.c b/src/node.c index c1f1219..b323dca 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 619baa9..a621a0a 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/process.c b/src/process.c index 01ebe49..6d0e499 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())); diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 24f591a..c2df4cd 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 9d43922..300333b 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); diff --git a/src/protocol_subnet.c b/src/protocol_subnet.c index f7ce53b..ba75c89 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; } diff --git a/src/route.c b/src/route.c index 2da781e..5c69671 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 ef4e59e..3d1168d 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) {