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

22 files changed:
1  2 
NEWS
README
doc/tinc.texi
have.h
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 --cc NEWS
index 51f11be3534d40718d05ab51996fa9ea2c0d58cd,942398efe1565f89aba4af53ed6813e934dd0fe7..3b06596968f0a43638801fb2968de4e40f8b6b10
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,9 -1,18 +1,24 @@@
 +Version 1.1-cvs              Work in progress
 +
 + * Use libevent to handle I/O events and timeouts.
 +
 + * 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 --cc README
index 01ea9507b475736b240e01fbf2d2e0a3fdbbba9f,9cc1042f08e40058523e5789130403e3d9f62cbd..3f21f25d51fbb25957dd87ee200be5144f122e82
--- 1/README
--- 2/README
+++ b/README
@@@ -1,7 -1,7 +1,7 @@@
 -This is the README file for tinc version 1.0.12. Installation
 +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>,
diff --cc doc/tinc.texi
index 094c54dbc28efc75e73b84ba80ad2c4307216e50,a938c2720143304287d1663e65234157f50226b8..f4b98dd76b3532cd13c05a072a9e042d1d9c57cc
@@@ -37,10 -37,9 +37,10 @@@ permission notice identical to this one
  
  @page
  @vskip 0pt plus 1filll
 +@cindex copyright
  This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon.
  
- Copyright @copyright{} 1998-2009 Ivo Timmermans,
+ Copyright @copyright{} 1998-2010 Ivo Timmermans,
  Guus Sliepen <guus@@tinc-vpn.org> and
  Wessel Dankers <wsl@@tinc-vpn.org>.
  
diff --cc have.h
index 92914ea010e11e0dfcac60c715e58b267b5eaab0,cf5c173a107af5ad6588107fd310e9c9f875516e..89454feba1e92cf46db611f3d3271b42ebb45002
--- 1/have.h
--- 2/have.h
+++ b/have.h
  #include <sys/uio.h>
  #endif
  
 +#ifdef HAVE_SYS_UN_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. */
  
diff --cc src/conf.c
index b1a6f0b179c26bf2a56b117107cf3537c4358f86,f64fb22127ac018c5a54459b5b64bd8a70599238..42866b83cb21ddb1b17550ce55dee6193e984a86
@@@ -279,10 -237,10 +237,11 @@@ static char *readline(FILE * fp, char *
    Parse a configuration file and put the results in the configuration tree
    starting at *base.
  */
 -bool read_config_file(avl_tree_t *config_tree, const char *fname) {
 +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;
Simple merge
index 6d2953124403c9092ce4602cdbbe00fea00efdc8,5aac4a661cc83f01a7e24ce053d5b63c9ba6a4b0..0f2b1d6a44d86ac0b72f453245203e1a399d98f6
  #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 */
 -      int active:1;                           /* 1 if active.. */
 -      int connecting:1;                       /* 1 if we are waiting for a non-blocking connect() to finish */
 -      int termreq:1;                          /* the termination of this connection was requested */
 -      int remove:1;                           /* Set to 1 if you want this connection removed */
 -      int timeout:1;                          /* 1 if gotten timeout */
 -      int encryptout:1;                       /* 1 if we can encrypt outgoing traffic */
 -      int decryptin:1;                        /* 1 if we have to decrypt incoming traffic */
 -      int mst:1;                              /* 1 if this connection is part of a minimum spanning tree */
 -      int unused:23;
 +              int pinged:1;                           /* sent ping */
 +              int active:1;                           /* 1 if active.. */
 +              int connecting:1;                       /* 1 if we are waiting for a non-blocking connect() to finish */
 +              int termreq:1;                          /* the termination of this connection was requested */
 +              int remove_unused:1;                            /* Set to 1 if you want this connection removed */
 +              int timeout_unused:1;                           /* 1 if gotten timeout */
 +              int encryptout:1;                       /* 1 if we can encrypt outgoing traffic */
 +              int decryptin:1;                        /* 1 if we have to decrypt incoming traffic */
 +              int mst:1;                              /* 1 if this connection is part of a minimum spanning tree */
 +              int control:1;
 +              int unused:22;
  } connection_status_t;
  
  #include "edge.h"
diff --cc src/graph.c
Simple merge
diff --cc src/net.c
Simple merge
index b50ddc4f27f48114061674dadf2416dc4d90d888,a438d3e9577e45aefd5ffeabc49d5da1955fe6ce..fc09957d0ec386c7eb6668586ef74b4f9c5e2ec5
  
  #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 "avl_tree.h"
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "conf.h"
  #include "connection.h"
 +#include "crypto.h"
 +#include "digest.h"
  #include "device.h"
  #include "ethernet.h"
 -#include "event.h"
  #include "graph.h"
  #include "list.h"
  #include "logger.h"
diff --cc src/net_setup.c
index c643449b88b161ef36e54d5f9d26722c046f947b,70291bffe97111f5f4a30691e63c56172a669351..9a0c78bdcf8c3ab6e201c7e381828a2c38447e54
@@@ -127,33 -187,79 +127,92 @@@ bool read_rsa_private_key() 
                logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
  #endif
  
 -      myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
 +      result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
        fclose(fp);
  
 -      if(!myself->connection->rsa_key) {
 -              logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s",
 -                         fname, strerror(errno));
 -              free(fname);
 -              return false;
 +      if(!result) 
 +              logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
 +      free(fname);
 +      return result;
 +}
 +
 +static struct event keyexpire_event;
 +
 +static void keyexpire_handler(int fd, short events, void *data) {
 +      regenerate_key();
 +}
 +
 +void regenerate_key() {
 +      if(timeout_initialized(&keyexpire_event)) {
 +              ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
 +              event_del(&keyexpire_event);
 +              send_key_changed(broadcast, myself);
 +      } else {
 +              timeout_set(&keyexpire_event, keyexpire_handler, NULL);
        }
  
 -      free(fname);
 -      return true;
 +      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)
  */
index d05dfd5c05ec896c677a0bdd8a513b3f24944c36,96e268fa98c8ffb3430632e613cd46f2228b2519..5eef3875c524b222679e7d95f1ade95bf503135d
@@@ -258,11 -259,15 +258,15 @@@ int setup_vpn_in_socket(const sockaddr_
  #endif
  
        option = 1;
 -      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
 +      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)
diff --cc src/node.h
index f5ebde3b3f45be4d4591f75d8151d28f14b2c5de,83e89c7d183c05c6a625a6c524832f014f2d6a13..a9322aa54256ca9698e582379bb133a6d66a6caa
@@@ -46,12 -45,23 +46,13 @@@ typedef struct node_t 
        char *hostname;                         /* the hostname of its real ip */
  
        node_status_t status;
+       time_t last_req_key;
  
 -      const EVP_CIPHER *incipher;             /* Cipher type for UDP packets received from him */
 -      char *inkey;                            /* Cipher key and iv */
 -      int inkeylength;                        /* Cipher key and iv length */
 -      EVP_CIPHER_CTX inctx;                   /* Cipher context */
 -      
 -      const EVP_CIPHER *outcipher;            /* Cipher type for UDP packets sent to him*/
 -      char *outkey;                           /* Cipher key and iv */
 -      int outkeylength;                       /* Cipher key and iv length */
 -      EVP_CIPHER_CTX outctx;                  /* Cipher context */
 -      
 -      const EVP_MD *indigest;                 /* Digest type for MAC of packets received from him */
 -      int inmaclength;                        /* Length of MAC */
 -
 -      const EVP_MD *outdigest;                /* Digest type for MAC of packets sent to him*/
 -      int outmaclength;                       /* Length of MAC */
 +      cipher_t incipher;                        /* Cipher for UDP packets */
 +      digest_t indigest;                        /* Digest for UDP packets */  
 +
 +      cipher_t outcipher;                        /* Cipher for UDP packets */
 +      digest_t outdigest;                        /* Digest for UDP packets */ 
  
        int incompression;                      /* Compressionlevel, 0 = no compression */
        int outcompression;                     /* Compressionlevel, 0 = no compression */
diff --cc src/protocol.c
Simple merge
diff --cc src/protocol.h
Simple merge
index 85272301c4e3a1cfadf5e1e8862a9f75b2a0357b,06735dcf87c27e4db30a096dd1a27d5eb3586ffc..cf6b26f2d4ad3f915c6532c93cf421769309281e
@@@ -400,8 -501,9 +405,9 @@@ bool ack_h(connection_t *c, char *reque
        int weight, mtu;
        uint32_t options;
        node_t *n;
+       bool choice;
  
 -      if(sscanf(c->buffer, "%*d " MAX_STRING " %d %x", 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 3b022679dbadb6fae80a6001ed2c3726bc0f8afe,67f40af45caa660c93b8a207f2c568920878a6ec..069cfd5f8ff8dd26abb1b3fd1bbcc93faa9fdfff
  #include "utils.h"
  #include "xalloc.h"
  
 -bool mykeyused = false;
 +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) {
 +bool key_changed_h(connection_t *c, char *request) {
        char name[MAX_STRING_SIZE];
        node_t *n;
  
@@@ -161,12 -183,14 +170,14 @@@ bool ans_key_h(connection_t *c, char *r
        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;
++        char address[MAX_STRING_SIZE] = "";
++        char port[MAX_STRING_SIZE] = "";
 +      int cipher, digest, maclength, compression, keylen;
        node_t *from, *to;
  
 -      if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
 +      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;
        
        from->outcompression = compression;
  
 -      if(from->outcipher)
 -              if(!EVP_EncryptInit_ex(&from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + from->outcipher->key_len)) {
 -                      logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s",
 -                                      from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL));
 -                      return true;
 -              }
 +      /* Update our copy of the origin's packet key */
 +
 +      hex2bin(key, key, keylen);
 +      cipher_set_key(&from->outcipher, key, false);
 +      digest_set_key(&from->outdigest, key, keylen);
  
        from->status.validkey = true;
 +      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,9ae491d0533b276ac409b87fc4be0559439d268b..65ab6e13948cc922f3d8230da495d0f74741f5a0
@@@ -228,10 -221,14 +222,15 @@@ bool del_subnet_h(connection_t *c, cha
                return true;
        }
  
+       if(tunnelserver)
+               return true;
        /* Tell the rest */
  
 -      forward_request(c);
 +      if(!tunnelserver)
 +              forward_request(c, request);
+       if(strictsubnets)
+               return true;
  
        /* Finally, delete it. */
  
diff --cc src/route.c
index 3c0cf5b5b3a0d7aedc02807da006d46f26dbcc1a,853b7f5b1acb5a916ec1657131c598e26768b4ec..f18bd268305a520cc3ba7c1d22e6aacf7fa2c15b
@@@ -48,9 -50,8 +50,10 @@@ static const size_t ip6_size = sizeof(s
  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;
 +
  /* RFC 1071 */
  
  static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
diff --cc src/route.h
Simple merge
diff --cc src/subnet.c
Simple merge
diff --cc src/tincd.c
index 9c6009e1a9f87ad208fbaf6b431dc6bb50b8271c,3debb3e48c2992204e6169d9df02da35c06123ff..21623647fb1eb0be7876a74c49fa16d19263494b
@@@ -377,8 -547,14 +386,9 @@@ int main(int argc, char **argv) 
                logger(LOG_ERR, "Error initializing LZO compressor!");
                return 1;
        }
+ #endif
  
  #ifdef HAVE_MINGW
 -      if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
 -              logger(LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
 -              return 1;
 -      }
 -
        if(!do_detach || !init_service())
                return main2(argc, argv);
        else