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
--- 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
--- 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
@@@ -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
--- 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
@@@ -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
  #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
  
  #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
@@@ -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)
  */
@@@ -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
@@@ -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
@@@ -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;
  #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);
  
@@@ -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
@@@ -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
@@@ -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