Merge branch 'master' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Mon, 2 Nov 2009 13:24:27 +0000 (14:24 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Mon, 2 Nov 2009 13:24:27 +0000 (14:24 +0100)
Conflicts:
NEWS
README
configure.in
doc/tinc.texi
doc/tincd.8.in
src/Makefile.am
src/connection.c
src/edge.c
src/meta.c
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/node.c
src/openssl/rsagen.h
src/protocol_auth.c
src/protocol_edge.c
src/subnet.c

26 files changed:
Makefile.am
NEWS
README
THANKS
doc/tinc.conf.5.in
lib/getopt.c
lib/utils.h
lib/xmalloc.c
src/Makefile.am
src/bsd/device.c
src/connection.h
src/dummy/device.c [new file with mode: 0644]
src/edge.h
src/meta.c
src/net.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/node.h
src/process.c
src/protocol_auth.c
src/protocol_edge.c
src/protocol_subnet.c
src/route.c
src/solaris/device.c
src/subnet.c

index 3a8e51f..b13689a 100644 (file)
@@ -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
diff --git a/NEWS b/NEWS
index 09b02b8..51f11be 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,20 +4,39 @@ Version 1.1-cvs              Work in progress
 
  * Use splay trees instead of AVL trees.
 
-Version 1.0.10               not yet released
+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
    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 c324e2b..01ea950 100644 (file)
--- a/README
+++ b/README
@@ -118,8 +118,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 ed57da5..e0d33d3 100644 (file)
--- 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
index 223005f..1cb2f0c 100644 (file)
@@ -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
@@ -515,6 +519,9 @@ 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.
+
+.It Ev WEIGHT
+When a subnet becomes (un)reachable, this is set to the subnet weight.
 .El
 
 .Sh FILES
index fce2f0c..b2f88b4 100644 (file)
@@ -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.
index c6fb180..4456616 100644 (file)
@@ -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);
index 9563391..4e79aff 100644 (file)
@@ -34,6 +34,7 @@ void *realloc ();
 void free ();
 #endif
 
+#include "dropin.h"
 #include "xalloc.h"
 
 #ifndef EXIT_FAILURE
index 3af74ca..bb78d4d 100644 (file)
@@ -35,9 +35,7 @@ tincd_LDADD = \
 tincctl_LDADD = \
        $(top_builddir)/lib/libvpn.a
 
-localedir = $(datadir)/locale
-
-AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
+AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
 
 dist-hook:
        rm -f `find . -type l`
index 1ffc960..a9e39d4 100644 (file)
@@ -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:
@@ -209,7 +220,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 +251,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;
                        }
@@ -268,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;
 }
 
index 93191df..9476996 100644 (file)
@@ -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/dummy/device.c b/src/dummy/device.c
new file mode 100644 (file)
index 0000000..a9600b2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    device.c -- Dummy device
+    Copyright (C) 2009 Guus Sliepen <guus@tinc-vpn.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#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);
+}
index 442ec41..cf62b71 100644 (file)
@@ -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 */
index 787ccbd..1bb634f 100644 (file)
@@ -92,7 +92,14 @@ bool receive_meta(connection_t *c) {
        inlen = recv(c->socket, inbuf, sizeof inbuf, 0);
 
        if(inlen <= 0) {
-               logger(LOG_ERR, "Receive callback called for %s (%s) but no data to receive: %s", c->name, c->hostname, strerror(errno));
+               if(!inlen || !errno) {
+                       ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
+                                          c->name, c->hostname);
+               } else if(sockwouldblock(sockerrno))
+                       return true;
+               else
+                       logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
+                                  c->name, c->hostname, sockstrerror(sockerrno));
                return false;
        }
 
@@ -152,7 +159,5 @@ bool receive_meta(connection_t *c) {
                }
        } while(inlen);
 
-       c->last_ping_time = time(NULL);
-
        return true;
 }
index 1c267f6..9445b68 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -208,7 +208,7 @@ void handle_meta_connection_data(int fd, short events, void *data) {
                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);
                        return;
index e430b6c..aaa0c72 100644 (file)
 #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];
@@ -54,31 +50,61 @@ 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
+
 static void send_mtu_probe_handler(int fd, short events, void *data) {
        node_t *n = data;
        vpn_packet_t packet;
        int len, i;
+       int timeout = 1;
        
        n->mtuprobes++;
 
-       if(!n->status.reachable) {
-               logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname);
+       if(!n->status.reachable || !n->status.validkey) {
+               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;
        }
 
+       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;
        }
 
+       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;
+       }
+
+       if(n->mtuprobes == 31) {
+               timeout = pinginterval;
+               goto end;
+       } else if(n->mtuprobes == 32) {
+               timeout = pingtimeout;
+       }
+
        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->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;
                
@@ -92,7 +118,8 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
                send_udppacket(n, &packet);
        }
 
-       event_add(&n->mtuevent, &(struct timeval){1, 0});
+end:
+       event_add(&n->mtuevent, &(struct timeval){timeout, 0});
 }
 
 void send_mtu_probe(node_t *n) {
@@ -106,10 +133,14 @@ 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;
                if(n->minmtu < len)
                        n->minmtu = len;
+               if(n->mtuprobes > 30)
+                       n->mtuprobes = 30;
        }
 }
 
@@ -317,10 +348,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;
        }
@@ -390,14 +424,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:
@@ -469,12 +503,17 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
        splay_node_t *node;
        edge_t *e;
        node_t *n = NULL;
+       static time_t last_hard_try = 0;
+       time_t now = time(NULL);
 
        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;
@@ -499,8 +538,8 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
        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;
        }
 
index 44c8d8d..de2d0fe 100644 (file)
@@ -293,7 +293,7 @@ bool setup_myself(void) {
        /* Generate packet encryption key */
 
        if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
-               cipher = xstrdup("aes256");
+               cipher = xstrdup("blowfish");
 
        if(!cipher_open_by_name(&myself->incipher, cipher)) {
                logger(LOG_ERR, "Unrecognized cipher type!");
@@ -308,7 +308,7 @@ bool setup_myself(void) {
        /* Check if we want to use message authentication codes... */
 
        if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
-               digest = xstrdup("sha256");
+               digest = xstrdup("sha1");
 
        int maclength = 4;
        get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &maclength);
index be44a1c..d05dfd5 100644 (file)
 
 #include <assert.h>
 
-#ifdef WSAEINPROGRESS
-#define EINPROGRESS WSAEINPROGRESS
-#endif
-
 /* Needed on Mac OS/X */
 #ifndef SOL_TCP
 #define SOL_TCP IPPROTO_TCP
@@ -67,7 +63,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
 
@@ -156,8 +152,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);
@@ -178,7 +173,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;
        }
 
@@ -203,7 +198,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
@@ -214,16 +209,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;
        }
 
@@ -238,7 +231,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;
        }
 
@@ -258,8 +251,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;
                }
        }
@@ -278,6 +270,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)
@@ -295,8 +292,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;
        }
@@ -337,6 +333,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) {
@@ -382,9 +383,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 +405,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;
        }
@@ -446,6 +441,8 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
        connection_t *c;
        node_t *n;
 
+       event_del(&outgoing->ev);
+
        n = lookup_node(outgoing->name);
 
        if(n)
@@ -504,7 +501,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
        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;
        }
 
@@ -555,18 +552,7 @@ void try_outgoing_connections(void) {
        static config_t *cfg = NULL;
        char *name;
        outgoing_t *outgoing;
-       connection_t *c;
-       splay_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)) {
index 830dcac..1e08c7e 100644 (file)
@@ -42,7 +42,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 */
index f0e5dd8..09fd63e 100644 (file)
@@ -98,13 +98,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()));
index c783189..a38b9ad 100644 (file)
@@ -348,7 +348,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) {
@@ -387,10 +387,10 @@ bool ack_h(connection_t *c, char *request) {
        char hisport[MAX_STRING_SIZE];
        char *hisaddress, *dummy;
        int weight, mtu;
-       long int options;
+       uint32_t options;
        node_t *n;
 
-       if(sscanf(request, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
+       if(sscanf(request, "%*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;
index df7e9c2..4aad53f 100644 (file)
@@ -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 *request) {
        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(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
+       if(sscanf(request, "%*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);
@@ -70,13 +70,7 @@ bool add_edge_h(connection_t *c, char *request) {
 
        /* 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, char *request) {
 
        /* 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;
index 6ec5054..ea112b9 100644 (file)
@@ -45,7 +45,7 @@ bool add_subnet_h(connection_t *c, char *request) {
        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(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
                logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name,
@@ -112,7 +112,7 @@ bool add_subnet_h(connection_t *c, char *request) {
 
                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, char *request) {
                }
 
                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);
@@ -142,6 +142,11 @@ bool add_subnet_h(connection_t *c, char *request) {
        if(!tunnelserver)
                forward_request(c, request);
 
+       /* Fast handoff of roaming MAC addresses */
+
+       if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires)
+               old->expires = 1;
+
        return true;
 }
 
index 600c53d..758801b 100644 (file)
@@ -154,6 +154,7 @@ static void learn_mac(mac_t *address) {
                subnet->type = SUBNET_MAC;
                subnet->expires = time(NULL) + macexpire;
                subnet->net.mac.address = *address;
+               subnet->weight = 10;
                subnet_add(myself, subnet);
 
                /* And tell all other tinc daemons it's our MAC */
index 6fbd053..8221b9f 100644 (file)
@@ -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;
        }
index 1cb8163..29ea96d 100644 (file)
@@ -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};
+       splay_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 = splay_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) {