]> git.meshlink.io Git - meshlink/commitdiff
Merge branch 'master' into 1.1
authorSven-Haegar Koch <haegar@sdinet.de>
Fri, 26 Mar 2010 15:51:03 +0000 (16:51 +0100)
committerSven-Haegar Koch <haegar@sdinet.de>
Fri, 26 Mar 2010 15:51:03 +0000 (16:51 +0100)
Conflicts:
NEWS
README
configure.in
have.h
src/conf.c
src/conf.h
src/net.c
src/net_packet.c
src/protocol_key.c
src/protocol_subnet.c
src/route.c
src/tincd.c

27 files changed:
COPYING
COPYING.README
NEWS
README
doc/tinc.conf.5.in
doc/tinc.texi
have.h
m4/lzo.m4
m4/zlib.m4
src/conf.c
src/connection.c
src/connection.h
src/graph.c
src/net.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/node.h
src/protocol.c
src/protocol.h
src/protocol_auth.c
src/protocol_key.c
src/protocol_subnet.c
src/route.c
src/route.h
src/subnet.c
src/tincd.c

diff --git a/COPYING b/COPYING
index 2ecad8df327ce1040d21185170e43fb9b5207a04..74fe22a07f10902dc399c25913ccd809b46e8e2b 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 1998-2009 Ivo Timmermans, Guus Sliepen and others.
+Copyright (C) 1998-2010 Ivo Timmermans, Guus Sliepen and others.
 See the AUTHORS file for a complete list.
 
 This program is free software; you can redistribute it and/or modify it under
index efeb98c0662e9b62f16864598b00b4f313ce7de9..2eb9c1facc212244a4103f9f9b81149c6f6a9d44 100644 (file)
@@ -15,3 +15,5 @@ The following applies to the LZO library:
 
 When tinc is compiled with the --enable-tunemu option, the resulting binary
 falls under the GPL version 3 or later.
+
+
diff --git a/NEWS b/NEWS
index 51f11be3534d40718d05ab51996fa9ea2c0d58cd..3b06596968f0a43638801fb2968de4e40f8b6b10 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,21 @@ Version 1.1-cvs              Work in progress
 
  * Use splay trees instead of AVL trees.
 
+Version 1.0.12               Feb  3 2010
+
+ * Really allow fast roaming of hosts to other nodes in a switched VPN.
+
+ * Fixes missing or incorrect environment variables when calling host-up/down
+   and subnet-up/down scripts in some cases.
+
+ * Allow port to be specified in Address statements.
+
+ * Clamp MSS of TCP packets to the discovered path MTU.
+
+ * Let two nodes behind NAT learn each others current UDP address and port via
+   a third node, potentially allowing direct communications in a similar way to
+   STUN.
+
 Version 1.0.11               Nov  1 2009
 
  * Fixed potential crash when the HUP signal is sent.
diff --git a/README b/README
index 01ea9507b475736b240e01fbf2d2e0a3fdbbba9f..3f21f25d51fbb25957dd87ee200be5144f122e82 100644 (file)
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 This is the README file for tinc version 1.1-cvs. Installation
 instructions may be found in the INSTALL file.
 
-tinc is Copyright (C) 1998-2009 by:
+tinc is Copyright (C) 1998-2010 by:
 
 Ivo Timmermans,
 Guus Sliepen <guus@tinc-vpn.org>,
index 1cb2f0c87dd31ddccae71633bc1e0779c2762dd4..8f5237f7d19a4dd1c9c8b750d87a134831cc6f57 100644 (file)
@@ -1,4 +1,4 @@
-.Dd 2009-03-05
+.Dd 2010-01-16
 .Dt TINC.CONF 5
 .\" Manual page created by:
 .\" Ivo Timmermans
@@ -199,6 +199,32 @@ Tinc will expect packets read from the virtual network device
 to start with an Ethernet header.
 .El
 
+.It Va DirectOnly Li = yes | no Pq no
+When this option is enabled, packets that cannot be sent directly to the destination node,
+but which would have to be forwarded by an intermediate node, are dropped instead.
+When combined with the IndirectData option,
+packets for nodes for which we do not have a meta connection with are also dropped.
+
+.It Va Forwarding Li = off | internal | kernel Pq internal
+This option selects the way indirect packets are forwarded.
+.Bl -tag -width indent
+
+.It off
+Incoming packets that are not meant for the local node,
+but which should be forwarded to another node, are dropped.
+
+.It internal
+Incoming packets that are meant for another node are forwarded by tinc internally.
+
+.Pp
+This is the default mode, and unless you really know you need another forwarding mode, don't change it.
+
+.It kernel
+Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node.
+This is less efficient, but allows the kernel to apply its routing and firewall rules on them,
+and can also help debugging.
+.El
+
 .It Va GraphDumpFile Li = Ar filename Bq experimental
 If this option is present,
 .Nm tinc
@@ -308,11 +334,18 @@ specified in the configuration file.
 When this option is used the priority of the tincd process will be adjusted.
 Increasing the priority may help to reduce latency and packet loss on the VPN.
 
+.It Va StrictSubnets Li = yes | no Po no Pc Bq experimental
+When this option is enabled tinc will only use Subnet statements which are
+present in the host config files in the local
+.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
+directory.
+
 .It Va TunnelServer Li = yes | no Po no Pc Bq experimental
 When this option is enabled tinc will no longer forward information between other tinc daemons,
-and will only allow nodes and subnets on the VPN which are present in the
+and will only allow connections with nodes for which host config files are present in the local
 .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
 directory.
+Setting this options also implicitly sets StrictSubnets.
 .El
 
 .Sh HOST CONFIGURATION FILES
@@ -330,9 +363,10 @@ Since host configuration files only contain public keys,
 no secrets are revealed by sending out this information.
 .Bl -tag -width indent
 
-.It Va Address Li = Ar address Bq recommended
+.It Va Address Li = Ar address Oo port Oc Bq recommended
 The IP address or hostname of this tinc daemon on the real network.
 This will only be used when trying to make an outgoing connection to this tinc daemon.
+Optionally, a port can be specified to use for this address.
 Multiple
 .Va Address
 variables can be specified, in which case each address will be tried until a working
@@ -346,6 +380,11 @@ Furthermore, specifying
 will turn off packet encryption.
 It is best to use only those ciphers which support CBC mode.
 
+.It Va ClampMSS Li = yes | no Pq yes
+This option specifies whether tinc should clamp the maximum segment size (MSS)
+of TCP packets to the path MTU. This helps in situations where ICMP
+Fragmentation Needed or Packet too Big messages are dropped by firewalls.
+
 .It Va Compression Li = Ar level Pq 0
 This option sets the level of compression used for UDP packets.
 Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib),
@@ -380,7 +419,10 @@ When this option is enabled, tinc will try to discover the path MTU to this node
 After the path MTU has been discovered, it will be enforced on the VPN.
 
 .It Va Port Li = Ar port Pq 655
-The port number on which this tinc daemon is listening for incoming connections.
+The port number on which this tinc daemon is listening for incoming connections,
+which is used if no port number is specified in an
+.Va Address
+statement.
 
 .It Va PublicKey Li = Ar key Bq obsolete
 The public RSA key of this tinc daemon.
index 094c54dbc28efc75e73b84ba80ad2c4307216e50..f4b98dd76b3532cd13c05a072a9e042d1d9c57cc 100644 (file)
@@ -15,7 +15,7 @@
 
 This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
 
-Copyright @copyright{} 1998-2009 Ivo Timmermans,
+Copyright @copyright{} 1998-2010 Ivo Timmermans,
 Guus Sliepen <guus@@tinc-vpn.org> and
 Wessel Dankers <wsl@@tinc-vpn.org>.
 
@@ -40,7 +40,7 @@ permission notice identical to this one.
 @cindex copyright
 This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
 
-Copyright @copyright{} 1998-2009 Ivo Timmermans,
+Copyright @copyright{} 1998-2010 Ivo Timmermans,
 Guus Sliepen <guus@@tinc-vpn.org> and
 Wessel Dankers <wsl@@tinc-vpn.org>.
 
@@ -842,6 +842,33 @@ Tinc will expect packets read from the virtual network device
 to start with an Ethernet header.
 @end table
 
+@cindex DirectOnly
+@item DirectOnly = <yes|no> (no)
+When this option is enabled, packets that cannot be sent directly to the destination node,
+but which would have to be forwarded by an intermediate node, are dropped instead.
+When combined with the IndirectData option,
+packets for nodes for which we do not have a meta connection with are also dropped.
+
+@cindex Forwarding
+@item Forwarding = <off|internal|kernel> (internal)
+This option selects the way indirect packets are forwarded.
+
+@table @asis
+@item off
+Incoming packets that are not meant for the local node,
+but which should be forwarded to another node, are dropped.
+
+@item internal
+Incoming packets that are meant for another node are forwarded by tinc internally.
+
+This is the default mode, and unless you really know you need another forwarding mode, don't change it.
+
+@item kernel
+Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node.
+This is less efficient, but allows the kernel to apply its routing and firewall rules on them,
+and can also help debugging.
+@end table
+
 @cindex GraphDumpFile
 @item GraphDumpFile = <@var{filename}> [experimental]
 If this option is present,
@@ -952,11 +979,18 @@ specified in the configuration file.
 When this option is used the priority of the tincd process will be adjusted.
 Increasing the priority may help to reduce latency and packet loss on the VPN.
 
+@cindex StrictSubnets
+@item StrictSubnets <yes|no> (no) [experimental]
+When this option is enabled tinc will only use Subnet statements which are
+present in the host config files in the local
+@file{@value{sysconfdir}/tinc/@var{netname}/hosts/} directory.
+
 @cindex TunnelServer
 @item TunnelServer = <yes|no> (no) [experimental]
 When this option is enabled tinc will no longer forward information between other tinc daemons,
-and will only allow nodes and subnets on the VPN which are present in the
+and will only allow connections with nodes for which host config files are present in the local
 @file{@value{sysconfdir}/tinc/@var{netname}/hosts/} directory.
+Setting this options also implicitly sets StrictSubnets.
 
 @end table
 
@@ -967,10 +1001,11 @@ and will only allow nodes and subnets on the VPN which are present in the
 
 @table @asis
 @cindex Address
-@item Address = <@var{IP address}|@var{hostname}> [recommended]
+@item Address = <@var{IP address}|@var{hostname}> [<port>] [recommended]
 This variable is only required if you want to connect to this host.  It
 must resolve to the external IP address where the host can be reached,
 not the one that is internal to the VPN.
+If no port is specified, the default Port is used.
 
 @cindex Cipher
 @item Cipher = <@var{cipher}> (blowfish)
@@ -979,6 +1014,12 @@ Any cipher supported by OpenSSL is recognized.
 Furthermore, specifying "none" will turn off packet encryption.
 It is best to use only those ciphers which support CBC mode.
 
+@cindex ClampMSS
+@item ClampMSS = <yes|no> (yes)
+This option specifies whether tinc should clamp the maximum segment size (MSS)
+of TCP packets to the path MTU. This helps in situations where ICMP
+Fragmentation Needed or Packet too Big messages are dropped by firewalls.
+
 @cindex Compression
 @item Compression = <@var{level}> (0)
 This option sets the level of compression used for UDP packets.
@@ -1323,7 +1364,7 @@ Address = 1.2.3.4
 
 Note that the IP addresses of eth0 and tap0 are the same.
 This is quite possible, if you make sure that the netmasks of the interfaces are different.
-It is in fact recommended to give give both real internal network interfaces and tap interfaces the same IP address,
+It is in fact recommended to give both real internal network interfaces and tap interfaces the same IP address,
 since that will make things a lot easier to remember and set up.
 
 
@@ -1346,8 +1387,8 @@ ConnectTo = BranchA
 @end example
 
 Note here that the internal address (on eth0) doesn't have to be the
-same as on the tap0 device.  Also, ConnectTo is given so that no-one can
-connect to this node.
+same as on the tap0 device.  Also, ConnectTo is given so that this node will
+always try to connect to BranchA.
 
 On all hosts, in @file{@value{sysconfdir}/tinc/company/hosts/BranchB}:
 
diff --git a/have.h b/have.h
index 92914ea010e11e0dfcac60c715e58b267b5eaab0..89454feba1e92cf46db611f3d3271b42ebb45002 100644 (file)
--- a/have.h
+++ b/have.h
 #include <sys/un.h>
 #endif
 
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
 /* SunOS really wants sys/socket.h BEFORE net/if.h,
    and FreeBSD wants these lines below the rest. */
 
index a996b1d09bccac82542af92751c27fc5b26273f0..36aa9b7f3d69275243dd068b681489cca52c4338 100644 (file)
--- a/m4/lzo.m4
+++ b/m4/lzo.m4
@@ -2,41 +2,46 @@ dnl Check to find the lzo headers/libraries
 
 AC_DEFUN([tinc_LZO],
 [
-  AC_ARG_WITH(lzo,
-    AS_HELP_STRING([--with-lzo=DIR], [lzo base directory, or:]),
-    [lzo="$withval"
-     CPPFLAGS="$CPPFLAGS -I$withval/include"
-     LDFLAGS="$LDFLAGS -L$withval/lib"]
-  )
+  AC_ARG_ENABLE([lzo],
+    AS_HELP_STRING([--disable-lzo], [disable lzo compression support]))
+  AS_IF([test "x$enable_lzo" != "xno"], [
+    AC_DEFINE(HAVE_LZO, 1, [enable lzo compression support])
+    AC_ARG_WITH(lzo,
+      AS_HELP_STRING([--with-lzo=DIR], [lzo base directory, or:]),
+      [lzo="$withval"
+       CPPFLAGS="$CPPFLAGS -I$withval/include"
+       LDFLAGS="$LDFLAGS -L$withval/lib"]
+    )
 
-  AC_ARG_WITH(lzo-include,
-    AS_HELP_STRING([--with-lzo-include=DIR], [lzo headers directory]),
-    [lzo_include="$withval"
-     CPPFLAGS="$CPPFLAGS -I$withval"]
-  )
+    AC_ARG_WITH(lzo-include,
+      AS_HELP_STRING([--with-lzo-include=DIR], [lzo headers directory]),
+      [lzo_include="$withval"
+       CPPFLAGS="$CPPFLAGS -I$withval"]
+    )
 
-  AC_ARG_WITH(lzo-lib,
-    AS_HELP_STRING([--with-lzo-lib=DIR], [lzo library directory]),
-    [lzo_lib="$withval"
-     LDFLAGS="$LDFLAGS -L$withval"]
-  )
+    AC_ARG_WITH(lzo-lib,
+      AS_HELP_STRING([--with-lzo-lib=DIR], [lzo library directory]),
+      [lzo_lib="$withval"
+       LDFLAGS="$LDFLAGS -L$withval"]
+    )
 
-  AC_CHECK_LIB(lzo2, lzo1x_1_compress,
-    [LIBS="$LIBS -llzo2"],
-    [AC_CHECK_LIB(lzo, lzo1x_1_compress,
-      [LIBS="$LIBS -llzo"],
-      [AC_MSG_ERROR("lzo libraries not found."); break]
-    )]
-  )
+    AC_CHECK_LIB(lzo2, lzo1x_1_compress,
+      [LIBS="$LIBS -llzo2"],
+      [AC_CHECK_LIB(lzo, lzo1x_1_compress,
+        [LIBS="$LIBS -llzo"],
+        [AC_MSG_ERROR("lzo libraries not found."); break]
+      )]
+    )
 
-  AC_CHECK_HEADERS(lzo/lzo1x.h,
-    [AC_DEFINE(LZO1X_H, [<lzo/lzo1x.h>], [Location of lzo1x.h])],
-    [AC_CHECK_HEADERS(lzo2/lzo1x.h,
-      [AC_DEFINE(LZO1X_H, [<lzo2/lzo1x.h>], [Location of lzo1x.h])],
-      [AC_CHECK_HEADERS(lzo1x.h,
-        [AC_DEFINE(LZO1X_H, [<lzo1x.h>], [Location of lzo1x.h])],
-        [AC_MSG_ERROR("lzo header files not found."); break]
+    AC_CHECK_HEADERS(lzo/lzo1x.h,
+      [AC_DEFINE(LZO1X_H, [<lzo/lzo1x.h>], [Location of lzo1x.h])],
+      [AC_CHECK_HEADERS(lzo2/lzo1x.h,
+        [AC_DEFINE(LZO1X_H, [<lzo2/lzo1x.h>], [Location of lzo1x.h])],
+        [AC_CHECK_HEADERS(lzo1x.h,
+          [AC_DEFINE(LZO1X_H, [<lzo1x.h>], [Location of lzo1x.h])],
+          [AC_MSG_ERROR("lzo header files not found."); break]
+        )]
       )]
-    )]
-  )
+    )
+  ])
 ])
index 71f39f717ce895038c68edf0b87f7247f4643788..64245a505825f865260f5d061ff9983bece0eb49 100644 (file)
@@ -2,32 +2,37 @@ dnl Check to find the zlib headers/libraries
 
 AC_DEFUN([tinc_ZLIB],
 [
-  AC_ARG_WITH(zlib,
-    AS_HELP_STRING([--with-zlib=DIR], [zlib base directory, or:]),
-    [zlib="$withval"
-     CPPFLAGS="$CPPFLAGS -I$withval/include"
-     LDFLAGS="$LDFLAGS -L$withval/lib"]
-  )
+  AC_ARG_ENABLE([zlib],
+    AS_HELP_STRING([--disable-zlib], [disable zlib compression support]))
+  AS_IF([test "x$enable_zlib" != "xno"], [
+  AC_DEFINE(HAVE_ZLIB, 1, [have zlib compression support])
+    AC_ARG_WITH(zlib,
+      AS_HELP_STRING([--with-zlib=DIR], [zlib base directory, or:]),
+      [zlib="$withval"
+       CPPFLAGS="$CPPFLAGS -I$withval/include"
+       LDFLAGS="$LDFLAGS -L$withval/lib"]
+    )
 
-  AC_ARG_WITH(zlib-include,
-    AS_HELP_STRING([--with-zlib-include=DIR], [zlib headers directory]),
-    [zlib_include="$withval"
-     CPPFLAGS="$CPPFLAGS -I$withval"]
-  )
+    AC_ARG_WITH(zlib-include,
+      AS_HELP_STRING([--with-zlib-include=DIR], [zlib headers directory]),
+      [zlib_include="$withval"
+       CPPFLAGS="$CPPFLAGS -I$withval"]
+    )
 
-  AC_ARG_WITH(zlib-lib,
-    AS_HELP_STRING([--with-zlib-lib=DIR], [zlib library directory]),
-    [zlib_lib="$withval"
-     LDFLAGS="$LDFLAGS -L$withval"]
-  )
+    AC_ARG_WITH(zlib-lib,
+      AS_HELP_STRING([--with-zlib-lib=DIR], [zlib library directory]),
+      [zlib_lib="$withval"
+       LDFLAGS="$LDFLAGS -L$withval"]
+    )
 
-  AC_CHECK_HEADERS(zlib.h,
-    [],
-    [AC_MSG_ERROR("zlib header files not found."); break]
-  )
+    AC_CHECK_HEADERS(zlib.h,
+      [],
+      [AC_MSG_ERROR("zlib header files not found."); break]
+    )
 
-  AC_CHECK_LIB(z, compress2,
-    [LIBS="$LIBS -lz"],
-    [AC_MSG_ERROR("zlib libraries not found.")]
-  )
+    AC_CHECK_LIB(z, compress2,
+      [LIBS="$LIBS -lz"],
+      [AC_MSG_ERROR("zlib libraries not found.")]
+    )
+  ])
 ])
index b1a6f0b179c26bf2a56b117107cf3537c4358f86..42866b83cb21ddb1b17550ce55dee6193e984a86 100644 (file)
@@ -26,6 +26,7 @@
 #include "conf.h"
 #include "logger.h"
 #include "netutl.h"                            /* for str2address */
+#include "protocol.h"
 #include "utils.h"                             /* for cp */
 #include "xalloc.h"
 
@@ -206,73 +207,30 @@ bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
 }
 
 /*
-  Read exactly one line and strip the trailing newline if any.  If the
-  file was on EOF, return NULL. Otherwise, return all the data in a
-  dynamically allocated buffer.
-
-  If line is non-NULL, it will be used as an initial buffer, to avoid
-  unnecessary mallocing each time this function is called.  If buf is
-  given, and buf needs to be expanded, the var pointed to by buflen
-  will be increased.
+  Read exactly one line and strip the trailing newline if any.
 */
-static char *readline(FILE * fp, char **buf, size_t *buflen) {
+static char *readline(FILE * fp, char *buf, size_t buflen) {
        char *newline = NULL;
        char *p;
-       char *line;                                     /* The array that contains everything that has been read so far */
-       char *idx;                                      /* Read into this pointer, which points to an offset within line */
-       size_t size, newsize;           /* The size of the current array pointed to by line */
-       size_t maxlen;                          /* Maximum number of characters that may be read with fgets.  This is newsize - oldsize. */
 
        if(feof(fp))
                return NULL;
 
-       if(buf && buflen) {
-               size = *buflen;
-               line = *buf;
-       } else {
-               size = 100;
-               line = xmalloc(size);
-       }
-
-       maxlen = size;
-       idx = line;
-       *idx = 0;
+       p = fgets(buf, buflen, fp);
 
-       for(;;) {
-               errno = 0;
-               p = fgets(idx, maxlen, fp);
-
-               if(!p) {                                /* EOF or error */
-                       if(feof(fp))
-                               break;
+       if(!p)
+               return NULL;
 
-                       /* otherwise: error; let the calling function print an error message if applicable */
-                       free(line);
-                       return NULL;
-               }
+       newline = strchr(p, '\n');
 
-               newline = strchr(p, '\n');
-
-               if(!newline) {                  /* We haven't yet read everything to the end of the line */
-                       newsize = size << 1;
-                       line = xrealloc(line, newsize);
-                       idx = &line[size - 1];
-                       maxlen = newsize - size + 1;
-                       size = newsize;
-               } else {
-                       *newline = '\0';        /* kill newline */
-                       if(newline > p && newline[-1] == '\r')  /* and carriage return if necessary */
-                               newline[-1] = '\0';
-                       break;                          /* yay */
-               }
-       }
+       if(!newline)
+               return NULL;
 
-       if(buf && buflen) {
-               *buflen = size;
-               *buf = line;
-       }
+       *newline = '\0';        /* kill newline */
+       if(newline > p && newline[-1] == '\r')  /* and carriage return if necessary */
+               newline[-1] = '\0';
 
-       return line;
+       return buf;
 }
 
 /*
@@ -282,35 +240,28 @@ static char *readline(FILE * fp, char **buf, size_t *buflen) {
 int read_config_file(splay_tree_t *config_tree, const char *fname) {
        int err = -2;                           /* Parse error */
        FILE *fp;
-       char *buffer, *line;
+       char buffer[MAX_STRING_SIZE];
+       char *line;
        char *variable, *value, *eol;
        int lineno = 0;
        int len;
        bool ignore = false;
        config_t *cfg;
-       size_t bufsize;
+       bool result = false;
 
        fp = fopen(fname, "r");
 
        if(!fp) {
-               logger(LOG_ERR, "Cannot open config file %s: %s", fname,
-                          strerror(errno));
-               return -3;
+               logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
+               return false;
        }
 
-       bufsize = 100;
-       buffer = xmalloc(bufsize);
-
        for(;;) {
-               if(feof(fp)) {
-                       err = 0;
-                       break;
-               }
-
-               line = readline(fp, &buffer, &bufsize);
+               line = readline(fp, buffer, sizeof buffer);
 
                if(!line) {
-                       err = -1;
+                       if(feof(fp))
+                               result = true;
                        break;
                }
 
@@ -361,24 +312,114 @@ int read_config_file(splay_tree_t *config_tree, const char *fname) {
                config_add(config_tree, cfg);
        }
 
-       free(buffer);
        fclose(fp);
 
-       return err;
+       return result;
 }
 
 bool read_server_config() {
        char *fname;
-       int x;
+       bool x;
 
        xasprintf(&fname, "%s/tinc.conf", confbase);
        x = read_config_file(config_tree, fname);
 
-       if(x == -1) {                           /* System error: complain */
+       if(!x) {                                /* System error: complain */
                logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
        }
 
        free(fname);
 
-       return x == 0;
+       return x;
+}
+
+FILE *ask_and_open(const char *filename, const char *what) {
+       FILE *r;
+       char *directory;
+       char line[PATH_MAX];
+       const char *fn;
+
+       /* Check stdin and stdout */
+       if(!isatty(0) || !isatty(1)) {
+               /* Argh, they are running us from a script or something.  Write
+                  the files to the current directory and let them burn in hell
+                  for ever. */
+               fn = filename;
+       } else {
+               /* Ask for a file and/or directory name. */
+               fprintf(stdout, "Please enter a file to save %s to [%s]: ",
+                               what, filename);
+               fflush(stdout);
+
+               fn = readline(stdin, line, sizeof line);
+
+               if(!fn) {
+                       fprintf(stderr, "Error while reading stdin: %s\n",
+                                       strerror(errno));
+                       return NULL;
+               }
+
+               if(!strlen(fn))
+                       /* User just pressed enter. */
+                       fn = filename;
+       }
+
+#ifdef HAVE_MINGW
+       if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
+#else
+       if(fn[0] != '/') {
+#endif
+               /* The directory is a relative path or a filename. */
+               char *p;
+
+               directory = get_current_dir_name();
+               xasprintf(&p, "%s/%s", directory, fn);
+               free(directory);
+               fn = p;
+       }
+
+       umask(0077);                            /* Disallow everything for group and other */
+
+       /* Open it first to keep the inode busy */
+
+       r = fopen(fn, "r+") ?: fopen(fn, "w+");
+
+       if(!r) {
+               fprintf(stderr, "Error opening file `%s': %s\n",
+                               fn, strerror(errno));
+               return NULL;
+       }
+
+       return r;
+}
+
+bool disable_old_keys(FILE *f) {
+       char buf[100];
+       long pos;
+       bool disabled = false;
+
+       rewind(f);
+       pos = ftell(f);
+
+       while(fgets(buf, sizeof buf, f)) {
+               if(!strncmp(buf, "-----BEGIN RSA", 14)) {       
+                       buf[11] = 'O';
+                       buf[12] = 'L';
+                       buf[13] = 'D';
+                       fseek(f, pos, SEEK_SET);
+                       fputs(buf, f);
+                       disabled = true;
+               }
+               else if(!strncmp(buf, "-----END RSA", 12)) {    
+                       buf[ 9] = 'O';
+                       buf[10] = 'L';
+                       buf[11] = 'D';
+                       fseek(f, pos, SEEK_SET);
+                       fputs(buf, f);
+                       disabled = true;
+               }
+               pos = ftell(f);
+       }
+
+       return disabled;
 }
index 519cf5b39bb507f0b1b997d149aa7608b6e08b6b..18c03c7e8c808377e843f10e77b836296b876f36 100644 (file)
@@ -109,11 +109,11 @@ bool dump_connections(connection_t *cdump) {
 
 bool read_connection_config(connection_t *c) {
        char *fname;
-       int x;
+       bool x;
 
        xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
        x = read_config_file(c->config_tree, fname);
        free(fname);
 
-       return x == 0;
+       return x;
 }
index 6d2953124403c9092ce4602cdbbe00fea00efdc8..0f2b1d6a44d86ac0b72f453245203e1a399d98f6 100644 (file)
@@ -1,6 +1,6 @@
 /*
     connection.h -- header for connection.c
-    Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2000-2010 Guus Sliepen <guus@tinc-vpn.org>,
                   2000-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@
 #define OPTION_INDIRECT                0x0001
 #define OPTION_TCPONLY         0x0002
 #define OPTION_PMTU_DISCOVERY  0x0004
+#define OPTION_CLAMP_MSS       0x0008
 
 typedef struct connection_status_t {
                int pinged:1;                           /* sent ping */
index d54e5cd6a99de011bb64030ed648b9190deeb8b1..216f9de2754d054213bc08ee25892fba171bc6d9 100644 (file)
@@ -1,6 +1,6 @@
 /*
     graph.c -- graph algorithms
-    Copyright (C) 2001-2009 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2001-2010 Guus Sliepen <guus@tinc-vpn.org>,
                   2001-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -53,6 +53,7 @@
 #include "netutl.h"
 #include "node.h"
 #include "process.h"
+#include "protocol.h"
 #include "subnet.h"
 #include "utils.h"
 #include "xalloc.h"
@@ -346,7 +347,7 @@ void check_reachability() {
                        /* TODO: only clear status.validkey if node is unreachable? */
 
                        n->status.validkey = false;
-                       n->status.waitingforkey = false;
+                       n->last_req_key = 0;
 
                        n->maxmtu = MTU;
                        n->minmtu = 0;
@@ -381,6 +382,8 @@ void check_reachability() {
 
                        if(!n->status.reachable)
                                update_node_udp(n, NULL);
+                       else if(n->connection)
+                               send_ans_key(n);
                }
        }
 }
index 99fcb0ded1a924b55fd5e0ba195d0d26481e5c4a..23b3e7ca1316446689008184e5fdeaa4b5fdaf5f 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -1,7 +1,7 @@
 /*
     net.c -- most of the network code
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -59,9 +59,9 @@ void purge(void) {
                        for(snode = n->subnet_tree->head; snode; snode = snext) {
                                snext = snode->next;
                                s = snode->data;
-                               if(!tunnelserver)
-                                       send_del_subnet(broadcast, s);
-                               subnet_del(n, s);
+                               send_del_subnet(broadcast, s);
+                               if(!strictsubnets)
+                                       subnet_del(n, s);
                        }
 
                        for(enode = n->edge_tree->head; enode; enode = enext) {
@@ -89,7 +89,8 @@ void purge(void) {
                                        break;
                        }
 
-                       if(!enode)
+                       if(!enode && (!strictsubnets || !n->subnet_tree->head))
+                               /* in strictsubnets mode do not delete nodes with subnets */
                                node_del(n);
                }
        }
index b50ddc4f27f48114061674dadf2416dc4d90d888..fc09957d0ec386c7eb6668586ef74b4f9c5e2ec5 100644 (file)
@@ -1,7 +1,7 @@
 /*
     net_packet.c -- Handles in- and outgoing VPN packets
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 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
 
 #include "system.h"
 
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/hmac.h>
+
+#ifdef HAVE_ZLIB
 #include <zlib.h>
+#endif
+
+#ifdef HAVE_LZO
 #include LZO1X_H
+#endif
 
 #include "splay_tree.h"
 #include "cipher.h"
@@ -44,7 +55,9 @@
 
 int keylifetime = 0;
 int keyexpires = 0;
+#ifdef HAVE_LZO
 static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
+#endif
 
 static void send_udppacket(node_t *, vpn_packet_t *);
 
@@ -145,40 +158,61 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
 }
 
 static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
-       if(level == 10) {
+       if(level == 0) {
+               memcpy(dest, source, len);
+               return len;
+       } else if(level == 10) {
+#ifdef HAVE_LZO
                lzo_uint lzolen = MAXSIZE;
                lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem);
                return lzolen;
+#else
+               return -1;
+#endif
        } else if(level < 10) {
+#ifdef HAVE_ZLIB
                unsigned long destlen = MAXSIZE;
                if(compress2(dest, &destlen, source, len, level) == Z_OK)
                        return destlen;
                else
+#endif
                        return -1;
        } else {
+#ifdef HAVE_LZO
                lzo_uint lzolen = MAXSIZE;
                lzo1x_999_compress(source, len, dest, &lzolen, lzo_wrkmem);
                return lzolen;
+#else
+               return -1;
+#endif
        }
        
        return -1;
 }
 
 static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
-       if(level > 9) {
+       if(level == 0) {
+               memcpy(dest, source, len);
+               return len;
+       } else if(level > 9) {
+#ifdef HAVE_LZO
                lzo_uint lzolen = MAXSIZE;
                if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK)
                        return lzolen;
                else
+#endif
                        return -1;
-       } else {
+       }
+#ifdef HAVE_ZLIB
+       else {
                unsigned long destlen = MAXSIZE;
                if(uncompress(dest, &destlen, source, len) == Z_OK)
                        return destlen;
                else
                        return -1;
        }
-       
+#endif
+
        return -1;
 }
 
@@ -338,10 +372,10 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
                                   "No valid key known yet for %s (%s), forwarding via TCP",
                                   n->name, n->hostname);
 
-               if(!n->status.waitingforkey)
+               if(n->last_req_key + 10 < now) {
                        send_req_key(n);
-
-               n->status.waitingforkey = true;
+                       n->last_req_key = now;
+               }
 
                send_tcppacket(n->nexthop->connection, origpkt);
 
index c643449b88b161ef36e54d5f9d26722c046f947b..9a0c78bdcf8c3ab6e201c7e381828a2c38447e54 100644 (file)
@@ -1,7 +1,7 @@
 /*
     net_setup.c -- Setup.
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -154,6 +154,65 @@ void regenerate_key() {
        event_add(&keyexpire_event, &(struct timeval){keylifetime, 0});
 }
 
+/*
+  Read Subnets from all host config files
+*/
+static void load_all_subnets(void) {
+       DIR *dir;
+       struct dirent *ent;
+       char *dname;
+       char *fname;
+       avl_tree_t *config_tree;
+       config_t *cfg;
+       subnet_t *s;
+       node_t *n;
+       bool result;
+
+       xasprintf(&dname, "%s/hosts", confbase);
+       dir = opendir(dname);
+       if(!dir) {
+               logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
+               free(dname);
+               return;
+       }
+
+       while((ent = readdir(dir))) {
+               if(!check_id(ent->d_name))
+                       continue;
+
+               n = lookup_node(ent->d_name);
+               if(n)
+                       continue;
+
+               #ifdef _DIRENT_HAVE_D_TYPE
+               //if(ent->d_type != DT_REG)
+               //      continue;
+               #endif
+
+               xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name);
+               init_configuration(&config_tree);
+               result = read_config_file(config_tree, fname);
+               free(fname);
+               if(!result)
+                       continue;
+
+               n = new_node();
+               n->name = xstrdup(ent->d_name);
+               node_add(n);
+
+               for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
+                       if(!get_config_subnet(cfg, &s))
+                               continue;
+
+                       subnet_add(n, s);
+               }
+
+               exit_configuration(&config_tree);
+       }
+
+       closedir(dir);
+}
+
 /*
   Configure node_t myself and set up the local sockets (listen only)
 */
@@ -171,8 +230,8 @@ bool setup_myself(void) {
        myself->connection = new_connection();
        init_configuration(&myself->connection->config_tree);
 
-       xasprintf(&myself->hostname, "MYSELF");
-       xasprintf(&myself->connection->hostname, "MYSELF");
+       myself->hostname = xstrdup("MYSELF");
+       myself->connection->hostname = xstrdup("MYSELF");
 
        myself->connection->options = 0;
        myself->connection->protocol_version = PROT_CURRENT;
@@ -199,8 +258,9 @@ bool setup_myself(void) {
        if(!read_rsa_private_key())
                return false;
 
-       if(!get_config_string(lookup_config(myself->connection->config_tree, "Port"), &myport))
-               xasprintf(&myport, "655");
+       if(!get_config_string(lookup_config(config_tree, "Port"), &myport)
+                       && !get_config_string(lookup_config(myself->connection->config_tree, "Port"), &myport))
+               myport = xstrdup("655");
 
        /* Read in all the subnets specified in the host configuration file */
 
@@ -232,7 +292,10 @@ bool setup_myself(void) {
        if(myself->options & OPTION_TCPONLY)
                myself->options |= OPTION_INDIRECT;
 
+       get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
+       get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets);
        get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver);
+       strictsubnets |= tunnelserver;
 
        if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) {
                if(!strcasecmp(mode, "router"))
@@ -246,16 +309,34 @@ bool setup_myself(void) {
                        return false;
                }
                free(mode);
-       } else
-               routing_mode = RMODE_ROUTER;
+       }
 
-       // Enable PMTUDiscovery by default if we are in router mode.
+       if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) {
+               if(!strcasecmp(mode, "off"))
+                       forwarding_mode = FMODE_OFF;
+               else if(!strcasecmp(mode, "internal"))
+                       forwarding_mode = FMODE_INTERNAL;
+               else if(!strcasecmp(mode, "kernel"))
+                       forwarding_mode = FMODE_KERNEL;
+               else {
+                       logger(LOG_ERR, "Invalid forwarding mode!");
+                       return false;
+               }
+               free(mode);
+       }
 
-       choice = routing_mode == RMODE_ROUTER;
+       choice = true;
        get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice);
-       if(choice)      
+       get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice);
+       if(choice)
                myself->options |= OPTION_PMTU_DISCOVERY;
 
+       choice = true;
+       get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice);
+       get_config_bool(lookup_config(myself->connection->config_tree, "ClampMSS"), &choice);
+       if(choice)
+               myself->options |= OPTION_CLAMP_MSS;
+
        get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
 
 #if !defined(SOL_IP) || !defined(IP_TOS)
@@ -344,6 +425,9 @@ bool setup_myself(void) {
 
        graph();
 
+       if(strictsubnets)
+               load_all_subnets();
+
        /* Open device */
 
        if(!setup_device())
index d05dfd5c05ec896c677a0bdd8a513b3f24944c36..5eef3875c524b222679e7d95f1ade95bf503135d 100644 (file)
@@ -1,7 +1,7 @@
 /*
     net_socket.c -- Handle various kinds of sockets.
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
                   2009      Florian Forster <octo@verplant.org>
 
@@ -260,9 +260,13 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
        option = 1;
        setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option);
 
-#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
        if(sa->sa.sa_family == AF_INET6)
-               setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, &option, sizeof option);
+               setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, &option, sizeof option);
+#endif
+
+#if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT)
+#define IP_DONTFRAGMENT IP_DONTFRAG
 #endif
 
 #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
@@ -275,6 +279,8 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
                option = 1;
                setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, &option, sizeof(option));
        }
+#else
+#warning No way to disable IPv4 fragmentation
 #endif
 
 #if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
@@ -282,6 +288,13 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
                option = IPV6_PMTUDISC_DO;
                setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, &option, sizeof(option));
        }
+#elif defined(IPPROTO_IPV6) && defined(IPV6_DONTFRAG)
+       if(myself->options & OPTION_PMTU_DISCOVERY) {
+               option = 1;
+               setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, &option, sizeof(option));
+       }
+#else
+#warning No way to disable IPv6 fragmentation
 #endif
 
        if (!bind_to_interface(nfd)) {
@@ -330,7 +343,7 @@ void finish_connecting(connection_t *c) {
 }
 
 void do_outgoing_connection(connection_t *c) {
-       char *address, *port;
+       char *address, *port, *space;
        int result;
 
        if(!c->outgoing) {
@@ -351,8 +364,14 @@ begin:
 
                get_config_string(c->outgoing->cfg, &address);
 
-               if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
-                       xasprintf(&port, "655");
+               space = strchr(address, ' ');
+               if(space) {
+                       port = xstrdup(space + 1);
+                       *space = 0;
+               } else {
+                       if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
+                               port = xstrdup("655");
+               }
 
                c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
                free(address);
index f5ebde3b3f45be4d4591f75d8151d28f14b2c5de..a9322aa54256ca9698e582379bb133a6d66a6caa 100644 (file)
@@ -1,6 +1,6 @@
 /*
     node.h -- header for node.c
-    Copyright (C) 2001-2009 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2001-2010 Guus Sliepen <guus@tinc-vpn.org>,
                   2001-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
 typedef struct node_status_t {
        int unused_active:1;                    /* 1 if active (not used for nodes) */
        int validkey:1;                         /* 1 if we currently have a valid key for him */
-       int waitingforkey:1;                    /* 1 if we already sent out a request */
+       int unused_waitingforkey:1;             /* 1 if we already sent out a request */
        int visited:1;                          /* 1 if this node has been visited by one of the graph algorithms */
        int reachable:1;                        /* 1 if this node is reachable in the graph */
        int indirect:1;                         /* 1 if this node is not directly reachable by us */
@@ -46,6 +46,7 @@ typedef struct node_t {
        char *hostname;                         /* the hostname of its real ip */
 
        node_status_t status;
+       time_t last_req_key;
 
        cipher_t incipher;                        /* Cipher for UDP packets */
        digest_t indigest;                        /* Digest for UDP packets */  
index 02f2841fb08859ab24cdf0a5c49e74e349a4c9ab..90eca015ea5d5a009749afa27fa1e0e69161a71c 100644 (file)
@@ -29,6 +29,7 @@
 #include "xalloc.h"
 
 bool tunnelserver = false;
+bool strictsubnets = false;
 
 /* Jumptable for the request handlers */
 
index f290148f90f500d71404e3b58f3eee5b72ba20ed..29c4ab1cdd052ad4f85d51fa036421b242e43a46 100644 (file)
@@ -54,6 +54,7 @@ typedef struct past_request_t {
 } past_request_t;
 
 extern bool tunnelserver;
+extern bool strictsubnets;
 
 /* Maximum size of strings in a request.
  * scanf terminates %2048s with a NUL character,
@@ -95,7 +96,7 @@ extern bool send_add_subnet(struct connection_t *, const struct subnet_t *);
 extern bool send_del_subnet(struct connection_t *, const struct subnet_t *);
 extern bool send_add_edge(struct connection_t *, const struct edge_t *);
 extern bool send_del_edge(struct connection_t *, const struct edge_t *);
-extern bool send_key_changed();
+extern void send_key_changed();
 extern bool send_req_key(struct node_t *);
 extern bool send_ans_key(struct node_t *);
 extern bool send_tcppacket(struct connection_t *, struct vpn_packet_t *);
index 85272301c4e3a1cfadf5e1e8862a9f75b2a0357b..cf6b26f2d4ad3f915c6532c93cf421769309281e 100644 (file)
@@ -1,7 +1,7 @@
 /*
     protocol_auth.c -- handle the meta-protocol, authentication
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 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
@@ -357,6 +357,11 @@ bool send_ack(connection_t *c) {
        if(myself->options & OPTION_PMTU_DISCOVERY)
                c->options |= OPTION_PMTU_DISCOVERY;
 
+       choice = myself->options & OPTION_CLAMP_MSS;
+       get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice);
+       if(choice)
+               c->options |= OPTION_CLAMP_MSS;
+
        get_config_int(lookup_config(c->config_tree, "Weight"), &c->estimated_weight);
 
        return send_request(c, "%d %s %d %x", ACK, myport, c->estimated_weight, c->options);
@@ -400,6 +405,7 @@ bool ack_h(connection_t *c, char *request) {
        int weight, mtu;
        uint32_t options;
        node_t *n;
+       bool choice;
 
        if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) {
                logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name,
@@ -449,6 +455,13 @@ bool ack_h(connection_t *c, char *request) {
        if(get_config_int(lookup_config(myself->connection->config_tree, "PMTU"), &mtu) && mtu < n->mtu)
                n->mtu = mtu;
 
+       if(get_config_bool(lookup_config(c->config_tree, "ClampMSS"), &choice)) {
+               if(choice)
+                       c->options |= OPTION_CLAMP_MSS;
+               else
+                       c->options &= ~OPTION_CLAMP_MSS;
+       }
+
        /* Activate this connection */
 
        c->allow_request = ALL;
index 3b022679dbadb6fae80a6001ed2c3726bc0f8afe..069cfd5f8ff8dd26abb1b3fd1bbcc93faa9fdfff 100644 (file)
@@ -1,7 +1,7 @@
 /*
     protocol_key.c -- handle the meta-protocol, key exchange
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 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
 
 static bool mykeyused = false;
 
-bool send_key_changed() {
-       /* Only send this message if some other daemon requested our key previously.
-          This reduces unnecessary key_changed broadcasts.
-        */
+void send_key_changed() {
+       avl_node_t *node;
+       connection_t *c;
 
-       if(!mykeyused)
-               return true;
+       send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name);
+
+       /* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
 
-       return send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name);
+       for(node = connection_tree->head; node; node = node->next) {
+               c = node->data;
+               if(c->status.active && c->node && c->node->status.reachable)
+                       send_ans_key(c->node);
+       }
 }
 
 bool key_changed_h(connection_t *c, char *request) {
@@ -63,11 +67,11 @@ bool key_changed_h(connection_t *c, char *request) {
        if(!n) {
                logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist",
                           "KEY_CHANGED", c->name, c->hostname, name);
-               return false;
+               return true;
        }
 
        n->status.validkey = false;
-       n->status.waitingforkey = false;
+       n->last_req_key = 0;
 
        /* Tell the others */
 
@@ -92,12 +96,17 @@ bool req_key_h(connection_t *c, char *request) {
                return false;
        }
 
+       if(!check_id(from_name) || !check_id(to_name)) {
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_KEY", c->name, c->hostname, "invalid name");
+               return false;
+       }
+
        from = lookup_node(from_name);
 
        if(!from) {
                logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
                           "REQ_KEY", c->name, c->hostname, from_name);
-               return false;
+               return true;
        }
 
        to = lookup_node(to_name);
@@ -105,7 +114,7 @@ bool req_key_h(connection_t *c, char *request) {
        if(!to) {
                logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
                           "REQ_KEY", c->name, c->hostname, to_name);
-               return false;
+               return true;
        }
 
        /* Check if this key request is for us */
@@ -115,7 +124,7 @@ bool req_key_h(connection_t *c, char *request) {
                send_ans_key(from);
        } else {
                if(tunnelserver)
-                       return false;
+                       return true;
 
                if(!to->status.reachable) {
                        logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
@@ -161,23 +170,30 @@ bool ans_key_h(connection_t *c, char *request) {
        char from_name[MAX_STRING_SIZE];
        char to_name[MAX_STRING_SIZE];
        char key[MAX_STRING_SIZE];
+        char address[MAX_STRING_SIZE] = "";
+        char port[MAX_STRING_SIZE] = "";
        int cipher, digest, maclength, compression, keylen;
        node_t *from, *to;
 
        if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d",
                from_name, to_name, key, &cipher, &digest, &maclength,
-               &compression) != 7) {
+               &compression, address, port) < 7) {
                logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
                           c->hostname);
                return false;
        }
 
+       if(!check_id(from_name) || !check_id(to_name)) {
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_KEY", c->name, c->hostname, "invalid name");
+               return false;
+       }
+
        from = lookup_node(from_name);
 
        if(!from) {
                logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
                           "ANS_KEY", c->name, c->hostname, from_name);
-               return false;
+               return true;
        }
 
        to = lookup_node(to_name);
@@ -185,14 +201,14 @@ bool ans_key_h(connection_t *c, char *request) {
        if(!to) {
                logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
                           "ANS_KEY", c->name, c->hostname, to_name);
-               return false;
+               return true;
        }
 
        /* Forward it if necessary */
 
        if(to != myself) {
                if(tunnelserver)
-                       return false;
+                       return true;
 
                if(!to->status.reachable) {
                        logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
@@ -229,7 +245,7 @@ bool ans_key_h(connection_t *c, char *request) {
 
        if(compression < 0 || compression > 11) {
                logger(LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
-               return false;
+               return true;
        }
        
        from->outcompression = compression;
@@ -244,6 +260,12 @@ bool ans_key_h(connection_t *c, char *request) {
        from->status.waitingforkey = false;
        from->sent_seqno = 0;
 
+       if(*address && *port) {
+               ifdebug(PROTOCOL) logger(LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
+               sockaddr_t sa = str2sockaddr(address, port);
+               update_node_udp(from, &sa);
+       }
+
        if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes)
                send_mtu_probe(from);
 
index ea112b9dc99d8623dc6c399727643dd403e5a793..65ab6e13948cc922f3d8230da495d0f74741f5a0 100644 (file)
@@ -104,29 +104,21 @@ bool add_subnet_h(connection_t *c, char *request) {
                return true;
        }
 
-       /* In tunnel server mode, check if the subnet matches one in the config file of this node */
+       /* In tunnel server mode, we should already know all allowed subnets */
 
        if(tunnelserver) {
-               config_t *cfg;
-               subnet_t *allowed;
-
-               for(cfg = lookup_config(c->config_tree, "Subnet"); cfg; cfg = lookup_config_next(c->config_tree, cfg)) {
-                       if(!get_config_subnet(cfg, &allowed))
-                               continue;
-
-                       if(!subnet_compare(&s, allowed))
-                               break;
-
-                       free_subnet(allowed);
-               }
+               logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s",
+                               "ADD_SUBNET", c->name, c->hostname, subnetstr);
+               return true;
+       }
 
-               if(!cfg) {
-                       logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s",
-                                       "ADD_SUBNET", c->name, c->hostname, subnetstr);
-                       return true;
-               }
+       /* Ignore if strictsubnets is true, but forward it to others */
 
-               free_subnet(allowed);
+       if(strictsubnets) {
+               logger(LOG_WARNING, "Ignoring unauthorized %s from %s (%s): %s",
+                               "ADD_SUBNET", c->name, c->hostname, subnetstr);
+               forward_request(c);
+               return true;
        }
 
        /* If everything is correct, add the subnet to the list of the owner */
@@ -216,6 +208,8 @@ bool del_subnet_h(connection_t *c, char *request) {
        if(!find) {
                ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which does not appear in his subnet tree",
                                   "DEL_SUBNET", c->name, c->hostname, name);
+               if(strictsubnets)
+                       forward_request(c);
                return true;
        }
 
@@ -228,10 +222,15 @@ bool del_subnet_h(connection_t *c, char *request) {
                return true;
        }
 
+       if(tunnelserver)
+               return true;
+
        /* Tell the rest */
 
        if(!tunnelserver)
                forward_request(c, request);
+       if(strictsubnets)
+               return true;
 
        /* Finally, delete it. */
 
index 3c0cf5b5b3a0d7aedc02807da006d46f26dbcc1a..f18bd268305a520cc3ba7c1d22e6aacf7fa2c15b 100644 (file)
@@ -1,7 +1,7 @@
 /*
     route.c -- routing
     Copyright (C) 2000-2005 Ivo Timmermans,
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 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
@@ -33,6 +33,8 @@
 #include "utils.h"
 
 rmode_t routing_mode = RMODE_ROUTER;
+fmode_t forwarding_mode = FMODE_INTERNAL;
+bool directonly = false;
 bool priorityinheritance = false;
 int macexpire = 600;
 bool overwrite_mac = false;
@@ -48,6 +50,7 @@ static const size_t ip6_size = sizeof(struct ip6_hdr);
 static const size_t icmp6_size = sizeof(struct icmp6_hdr);
 static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
 static const size_t opt_size = sizeof(struct nd_opt_hdr);
+#define max(a, b) ((a) > (b) ? (a) : (b))
 
 static struct event age_subnets_event;
 
@@ -95,6 +98,78 @@ static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
                return true;
 }
 
+static void clamp_mss(const node_t *source, const node_t *via, vpn_packet_t *packet) {
+       if(!source || !via || !(via->options & OPTION_CLAMP_MSS))
+               return;
+
+       uint16_t mtu = source->mtu;
+       if(via != myself && via->mtu < mtu)
+               mtu = via->mtu;
+
+       /* Find TCP header */
+       int start = 0;
+       uint16_t type = packet->data[12] << 8 | packet->data[13];
+
+       if(type == ETH_P_IP && packet->data[23] == 6)
+               start = 14 + (packet->data[14] & 0xf) * 4;
+       else if(type == ETH_P_IPV6 && packet->data[20] == 6)
+               start = 14 + 40;
+
+       if(!start || packet->len <= start + 20)
+               return;
+
+       /* Use data offset field to calculate length of options field */
+       int len = ((packet->data[start + 12] >> 4) - 5) * 4;
+
+       if(packet->len < start + 20 + len)
+               return;
+
+       /* Search for MSS option header */
+       for(int i = 0; i < len;) {
+               if(packet->data[start + 20 + i] == 0)
+                       break;
+
+               if(packet->data[start + 20 + i] == 1) {
+                       i++;
+                       continue;
+               }
+
+               if(i > len - 2 || i > len - packet->data[start + 21 + i])
+                       break;
+
+               if(packet->data[start + 20 + i] != 2) {
+                       if(packet->data[start + 21 + i] < 2)
+                               break;
+                       i += packet->data[start + 21 + i];
+                       continue;
+               }
+
+               if(packet->data[start + 21] != 4)
+                       break;
+
+               /* Found it */
+               uint16_t oldmss = packet->data[start + 22 + i] << 8 | packet->data[start + 23 + i];
+               uint16_t newmss = mtu - start - 20;
+               uint16_t csum = packet->data[start + 16] << 8 | packet->data[start + 17];
+
+               if(oldmss <= newmss)
+                       break;
+               
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss);
+
+               /* Update the MSS value and the checksum */
+               packet->data[start + 22 + i] = newmss >> 8;
+               packet->data[start + 23 + i] = newmss & 0xff;
+               csum ^= 0xffff;
+               csum -= oldmss;
+               csum += newmss;
+               csum ^= 0xffff;
+               packet->data[start + 16] = csum >> 8;
+               packet->data[start + 17] = csum & 0xff;
+               break;
+       }
+}
+
 static void swap_mac_addresses(vpn_packet_t *packet) {
        mac_t tmp;
        memcpy(&tmp, &packet->data[0], sizeof tmp);
@@ -156,6 +231,7 @@ static void learn_mac(mac_t *address) {
                subnet->net.mac.address = *address;
                subnet->weight = 10;
                subnet_add(myself, subnet);
+               subnet_update(myself, subnet, true);
 
                /* And tell all other tinc daemons it's our MAC */
 
@@ -323,17 +399,23 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
        }
 
        if(!subnet->owner->status.reachable)
-               route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
+               return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
+
+       if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
+               return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO);
 
        if(priorityinheritance)
                packet->priority = packet->data[15];
 
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
-       if(via && packet->len > via->mtu && via != myself) {
+       if(directonly && subnet->owner != via)
+               return route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_ANO);
+
+       if(via && packet->len > max(via->mtu, 590) && via != myself) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
                if(packet->data[20] & 0x40) {
-                       packet->len = via->mtu;
+                       packet->len = max(via->mtu, 590);
                        route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
                } else {
                        fragment_ipv4_packet(via, packet);
@@ -342,6 +424,8 @@ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
+       clamp_mss(source, via, packet);
        send_packet(subnet->owner, packet);
 }
 
@@ -469,17 +553,25 @@ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
        }
 
        if(!subnet->owner->status.reachable)
-               route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
+               return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
+
+       if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
+               return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
 
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
-       if(via && packet->len > via->mtu && via != myself) {
+       if(directonly && subnet->owner != via)
+               return route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN);
+
+       if(via && packet->len > max(via->mtu, 1294) && via != myself) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
-               packet->len = via->mtu;
+               packet->len = max(via->mtu, 1294);
                route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
                return;
        }
 
+       clamp_mss(source, via, packet);
        send_packet(subnet->owner, packet);
 }
 
@@ -732,14 +824,20 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
                return;
        }
 
+       if(forwarding_mode == FMODE_OFF && source != myself && subnet->owner != myself)
+               return;
+
        // Handle packets larger than PMTU
 
        node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
+
+       if(directonly && subnet->owner != via)
+               return;
        
        if(via && packet->len > via->mtu && via != myself) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
                uint16_t type = packet->data[12] << 8 | packet->data[13];
-               if(type == ETH_P_IP) {
+               if(type == ETH_P_IP && packet->len > 590) {
                        if(packet->data[20] & 0x40) {
                                packet->len = via->mtu;
                                route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
@@ -747,17 +845,24 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
                                fragment_ipv4_packet(via, packet);
                        }
                        return;
-               } else if(type == ETH_P_IPV6) {
+               } else if(type == ETH_P_IPV6 && packet->len > 1294) {
                        packet->len = via->mtu;
                        route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
                        return;
                }
        }
 
+       clamp_mss(source, via, packet);
        send_packet(subnet->owner, packet);
 }
 
 void route(node_t *source, vpn_packet_t *packet) {
+       if(forwarding_mode == FMODE_KERNEL && source != myself) {
+               send_packet(myself, packet);
+               return;
+       }
+
        if(!checklength(source, packet, ether_size))
                return;
 
index 18189d42b9f1e7a632db652d386db4ac7c7e6d94..cfe39e4b45f147933ced3aea76f783c7fa5b3359 100644 (file)
@@ -30,7 +30,15 @@ typedef enum rmode_t {
        RMODE_ROUTER,
 } rmode_t;
 
+typedef enum fmode_t {
+       FMODE_OFF = 0,
+       FMODE_INTERNAL,
+       FMODE_KERNEL,
+} fmode_t;
+
 extern rmode_t routing_mode;
+extern fmode_t forwarding_mode;
+extern bool directonly;
 extern bool overwrite_mac;
 extern bool priorityinheritance;
 extern int macexpire;
index 8bc8fce89efdc5040f6ba1c04c27b6d157d7c917..dce57477091a00259f0414784a1a60646f160dc8 100644 (file)
@@ -1,6 +1,6 @@
 /*
     subnet.c -- handle subnet lookups and lists
-    Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
+    Copyright (C) 2000-2010 Guus Sliepen <guus@tinc-vpn.org>,
                   2000-2005 Ivo Timmermans
 
     This program is free software; you can redistribute it and/or modify
@@ -479,7 +479,7 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
                        if(!net2str(netstr, sizeof netstr, subnet))
                                continue;
                        // Strip the weight from the subnet, and put it in its own environment variable
-                       char *weight = strchr(netstr + 7, '#');
+                       char *weight = strchr(netstr, '#');
                        if(weight)
                                *weight++ = 0;
                        else
@@ -496,9 +496,9 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
                        execute_script(name, envp);
                }
        } else {
-               if(net2str(netstr + 7, sizeof netstr - 7, subnet)) {
+               if(net2str(netstr, sizeof netstr, subnet)) {
                        // Strip the weight from the subnet, and put it in its own environment variable
-                       char *weight = strchr(netstr + 7, '#');
+                       char *weight = strchr(netstr, '#');
                        if(weight)
                                *weight++ = 0;
                        else
index 9c6009e1a9f87ad208fbaf6b431dc6bb50b8271c..21623647fb1eb0be7876a74c49fa16d19263494b 100644 (file)
@@ -1,7 +1,7 @@
 /*
     tincd.c -- the main file for tincd
     Copyright (C) 1998-2005 Ivo Timmermans
-                  2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
                   2008      Max Rijevski <maksuf@gmail.com>
                   2009      Michael Tokarev <mjt@tls.msk.ru>
 
 #include <sys/mman.h>
 #endif
 
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+
+#ifdef HAVE_LZO
 #include LZO1X_H
+#endif
 
 #ifndef HAVE_MINGW
 #include <pwd.h>
@@ -333,7 +341,7 @@ int main(int argc, char **argv) {
        if(show_version) {
                printf("%s version %s (built %s %s, protocol %d)\n", PACKAGE,
                           VERSION, __DATE__, __TIME__, PROT_CURRENT);
-               printf("Copyright (C) 1998-2009 Ivo Timmermans, Guus Sliepen and others.\n"
+               printf("Copyright (C) 1998-2010 Ivo Timmermans, Guus Sliepen and others.\n"
                                "See the AUTHORS file for a complete list.\n\n"
                                "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
                                "and you are welcome to redistribute it under certain conditions;\n"
@@ -373,10 +381,12 @@ int main(int argc, char **argv) {
        if(!read_server_config())
                return 1;
 
+#ifdef HAVE_LZO
        if(lzo_init() != LZO_E_OK) {
                logger(LOG_ERR, "Error initializing LZO compressor!");
                return 1;
        }
+#endif
 
 #ifdef HAVE_MINGW
        if(!do_detach || !init_service())