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

19 files changed:
1  2 
NEWS
README
src/Makefile.am
src/bsd/device.c
src/connection.h
src/edge.h
src/meta.c
src/net.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/node.h
src/process.c
src/protocol_auth.c
src/protocol_edge.c
src/protocol_subnet.c
src/route.c
src/solaris/device.c
src/subnet.c

diff --cc NEWS
index 09b02b8efaad5b2d0ade9c7aa233d096eb3e9b30,330efbc1913e39936a850606ce0d4ad32ff2aed8..51f11be3534d40718d05ab51996fa9ea2c0d58cd
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,10 -1,21 +1,27 @@@
- Version 1.0.10               not yet released
 +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.11               Nov  1 2009
+  * Fixed potential crash when the HUP signal is sent.
+  * Fixes handling of weighted Subnets in switch and hub modes, preventing
+    unnecessary broadcasts.
+  * Works around a MinGW bug that caused packets to Windows nodes to always be
+    sent via TCP.
+  * Improvements to the PMTU discovery code, especially on Windows.
+  * Use UDP again in certain cases where 1.0.10 was too conservative and fell
+    back to TCP unnecessarily.
+  * Allow fast roaming of hosts to other nodes in a switched VPN.
+ Version 1.0.10               Oct 18 2009
  
   * Fixed potential crashes during shutdown and (in rare conditions) when other
     nodes disconnected from the VPN.
diff --cc README
Simple merge
diff --cc src/Makefile.am
index 3af74ca170517eb005934df54b95d396436565e7,491f0115ba0a137a4edb7ba2e0400624b1a266db..bb78d4dd9d55692cf0ec13521012ebf467c14d6a
@@@ -32,12 -30,7 +32,10 @@@ endi
  tincd_LDADD = \
        $(top_builddir)/lib/libvpn.a
  
 -AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\"
 +tincctl_LDADD = \
 +      $(top_builddir)/lib/libvpn.a
 +
- localedir = $(datadir)/locale
- AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
++AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
  
  dist-hook:
        rm -f `find . -type l`
Simple merge
Simple merge
diff --cc src/edge.h
Simple merge
diff --cc src/meta.c
index 787ccbd0ff17426b709dc8683e08e3a358d6cf12,4c52464c33d2a62f663f54c2b920832b8a20e910..1bb634fdf2832f2271ff15f348f528d97c615af3
@@@ -89,10 -141,18 +89,17 @@@ bool receive_meta(connection_t *c) 
           - If not, keep stuff in buffer and exit.
         */
  
 -      lenin = recv(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen, 0);
 +      inlen = recv(c->socket, inbuf, sizeof inbuf, 0);
  
 -      if(lenin <= 0) {
 -              if(!lenin || !errno) {
 +      if(inlen <= 0) {
-               logger(LOG_ERR, "Receive callback called for %s (%s) but no data to receive: %s", c->name, c->hostname, strerror(errno));
++              if(!inlen || !errno) {
+                       ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
+                                          c->name, c->hostname);
+               } else if(sockwouldblock(sockerrno))
+                       return true;
+               else
+                       logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
+                                  c->name, c->hostname, sockstrerror(sockerrno));
 -
                return false;
        }
  
                                break;
                        }
                }
 -
 -              /* Otherwise we are waiting for a request */
 -
 -              reqlen = 0;
 -
 -              for(i = oldlen; i < c->buflen; i++) {
 -                      if(c->buffer[i] == '\n') {
 -                              c->buffer[i] = '\0';    /* replace end-of-line by end-of-string so we can use sscanf */
 -                              reqlen = i + 1;
 -                              break;
 -                      }
 -              }
 -
 -              if(reqlen) {
 -                      c->reqlen = reqlen;
 -                      if(!receive_request(c))
 -                              return false;
 -
 -                      c->buflen -= reqlen;
 -                      lenin -= reqlen - oldlen;
 -                      memmove(c->buffer, c->buffer + reqlen, c->buflen);
 -                      oldlen = 0;
 -                      continue;
 -              } else {
 -                      break;
 -              }
 -      }
 -
 -      if(c->buflen >= MAXBUFSIZE) {
 -              logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)",
 -                         c->name, c->hostname);
 -              return false;
 -      }
 +      } while(inlen);
  
-       c->last_ping_time = time(NULL);
        return true;
  }
diff --cc src/net.c
index 1c267f64801a5dc161021b674cfb93d3833834ed,3f17083c192dec33ceb2fb5481513294263d6b8f..9445b68a046d6f0489eba826c9c0647cbc003514
+++ b/src/net.c
@@@ -188,30 -254,73 +188,30 @@@ static void timeout_handler(int fd, sho
                                }
                        }
                }
 -
 -              if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout < now) {
 -                      if(c->status.active) {
 -                              ifdebug(CONNECTIONS) logger(LOG_INFO,
 -                                              "%s (%s) could not flush for %ld seconds (%d bytes remaining)",
 -                                              c->name, c->hostname, now - c->last_flushed_time, c->outbuflen);
 -                              c->status.timeout = true;
 -                              terminate_connection(c, true);
 -                      }
 -              }
        }
 -}
 -
 -/*
 -  check all connections to see if anything
 -  happened on their sockets
 -*/
 -static void check_network_activity(fd_set * readset, fd_set * writeset) {
 -      connection_t *c;
 -      avl_node_t *node;
 -      int result, i;
 -      socklen_t len = sizeof(result);
 -      vpn_packet_t packet;
 -
 -      /* check input from kernel */
 -      if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
 -              if(read_packet(&packet)) {
 -                      packet.priority = 0;
 -                      route(myself, &packet);
 -              }
 -      }
 -
 -      /* check meta connections */
 -      for(node = connection_tree->head; node; node = node->next) {
 -              c = node->data;
 -
 -              if(c->status.remove)
 -                      continue;
 -
 -              if(FD_ISSET(c->socket, readset)) {
 -                      if(c->status.connecting) {
 -                              c->status.connecting = false;
 -                              getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
 -
 -                              if(!result)
 -                                      finish_connecting(c);
 -                              else {
 -                                      ifdebug(CONNECTIONS) logger(LOG_DEBUG,
 -                                                         "Error while connecting to %s (%s): %s",
 -                                                         c->name, c->hostname, sockstrerror(result));
 -                                      closesocket(c->socket);
 -                                      do_outgoing_connection(c);
 -                                      continue;
 -                              }
 -                      }
  
 -                      if(!receive_meta(c)) {
 -                              terminate_connection(c, c->status.active);
 -                              continue;
 -                      }
 -              }
 +      event_add(event, &(struct timeval){pingtimeout, 0});
 +}
  
 -              if(FD_ISSET(c->socket, writeset)) {
 -                      if(!flush_meta(c)) {
 -                              terminate_connection(c, c->status.active);
 -                              continue;
 -                      }
 +void handle_meta_connection_data(int fd, short events, void *data) {
 +      connection_t *c = data;
 +      int result;
 +      socklen_t len = sizeof result;
 +
 +      if(c->status.connecting) {
 +              c->status.connecting = false;
 +
 +              getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
 +
 +              if(!result)
 +                      finish_connecting(c);
 +              else {
 +                      ifdebug(CONNECTIONS) logger(LOG_DEBUG,
 +                                         "Error while connecting to %s (%s): %s",
-                                          c->name, c->hostname, strerror(result));
++                                         c->name, c->hostname, sockstrerror(result));
 +                      closesocket(c->socket);
 +                      do_outgoing_connection(c);
 +                      return;
                }
        }
  
index e430b6c96a5efcd948f53bb019d71fff1f9b82c2,e5011532629d818062464a244f43de84785f6f91..aaa0c7206df76877207b3e916cdaa8e7fe97f4e4
@@@ -54,15 -54,22 +50,22 @@@ static void send_udppacket(node_t *, vp
  
  #define MAX_SEQNO 1073741824
  
 -void send_mtu_probe(node_t *n) {
+ // mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
+ // mtuprobes ==    31: sleep pinginterval seconds
+ // mtuprobes ==    32: send 1 burst, sleep pingtimeout second
+ // mtuprobes ==    33: no response from other side, restart PMTU discovery process
 +static void send_mtu_probe_handler(int fd, short events, void *data) {
 +      node_t *n = data;
        vpn_packet_t packet;
        int len, i;
+       int timeout = 1;
        
        n->mtuprobes++;
 -      n->mtuevent = NULL;
  
-       if(!n->status.reachable) {
-               logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname);
+       if(!n->status.reachable || !n->status.validkey) {
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
+               n->mtuprobes = 0;
                return;
        }
  
                send_udppacket(n, &packet);
        }
  
-       event_add(&n->mtuevent, &(struct timeval){1, 0});
+ end:
 -      n->mtuevent = new_event();
 -      n->mtuevent->handler = (event_handler_t)send_mtu_probe;
 -      n->mtuevent->data = n;
 -      n->mtuevent->time = now + timeout;
 -      event_add(n->mtuevent);
++      event_add(&n->mtuevent, &(struct timeval){timeout, 0});
 +}
 +
 +void send_mtu_probe(node_t *n) {
 +      if(!timeout_initialized(&n->mtuevent))
 +              timeout_set(&n->mtuevent, send_mtu_probe_handler, n);
 +      send_mtu_probe_handler(0, 0, n);
  }
  
  void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
@@@ -466,9 -521,10 +500,11 @@@ void broadcast_packet(const node_t *fro
  }
  
  static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
 -      avl_node_t *node;
 +      splay_node_t *node;
        edge_t *e;
        node_t *n = NULL;
+       static time_t last_hard_try = 0;
++      time_t now = time(NULL);
  
        for(node = edge_weight_tree->head; node; node = node->next) {
                e = node->data;
diff --cc src/net_setup.c
index 44c8d8dca3e3e2dbba197d9457caa409f412ca9e,cbf631f5f211b61ccc545e3676c097a0484689be..de2d0feaadf7fd84dc81cac8e69164c421c412a3
@@@ -292,36 -339,65 +292,36 @@@ bool setup_myself(void) 
  
        /* Generate packet encryption key */
  
 -      if(get_config_string
 -         (lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) {
 -              if(!strcasecmp(cipher, "none")) {
 -                      myself->incipher = NULL;
 -              } else {
 -                      myself->incipher = EVP_get_cipherbyname(cipher);
 -
 -                      if(!myself->incipher) {
 -                              logger(LOG_ERR, "Unrecognized cipher type!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->incipher = EVP_bf_cbc();
 +      if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
-               cipher = xstrdup("aes256");
++              cipher = xstrdup("blowfish");
  
 -      if(myself->incipher)
 -              myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
 -      else
 -              myself->inkeylength = 1;
 -
 -      myself->connection->outcipher = EVP_bf_ofb();
 +      if(!cipher_open_by_name(&myself->incipher, cipher)) {
 +              logger(LOG_ERR, "Unrecognized cipher type!");
 +              return false;
 +      }
  
        if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
                keylifetime = 3600;
  
 -      keyexpires = now + keylifetime;
 -      
 +      regenerate_key();
 +
        /* Check if we want to use message authentication codes... */
  
 -      if(get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
 -              if(!strcasecmp(digest, "none")) {
 -                      myself->indigest = NULL;
 -              } else {
 -                      myself->indigest = EVP_get_digestbyname(digest);
 +      if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
-               digest = xstrdup("sha256");
++              digest = xstrdup("sha1");
  
 -                      if(!myself->indigest) {
 -                              logger(LOG_ERR, "Unrecognized digest type!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->indigest = EVP_sha1();
 -
 -      myself->connection->outdigest = EVP_sha1();
 -
 -      if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->inmaclength)) {
 -              if(myself->indigest) {
 -                      if(myself->inmaclength > myself->indigest->md_size) {
 -                              logger(LOG_ERR, "MAC length exceeds size of digest!");
 -                              return false;
 -                      } else if(myself->inmaclength < 0) {
 -                              logger(LOG_ERR, "Bogus MAC length!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->inmaclength = 4;
 +      int maclength = 4;
 +      get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &maclength);
 +
 +      if(maclength < 0) {
 +              logger(LOG_ERR, "Bogus MAC length!");
 +              return false;
 +      }
  
 -      myself->connection->outmaclength = 0;
 +      if(!digest_open_by_name(&myself->indigest, digest, maclength)) {
 +              logger(LOG_ERR, "Unrecognized digest type!");
 +              return false;
 +      }
  
        /* Compression */
  
index be44a1ce605dc9552ead36133b06727f2827f249,46e0532eaf59d5f8e5f0f36887fe5a0f9d560ffe..d05dfd5c05ec896c677a0bdd8a513b3f24944c36
@@@ -197,13 -193,13 +192,13 @@@ int setup_listen_socket(const sockaddr_
  #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
                struct ifreq ifr;
  
 -              memset(&ifr, 0, sizeof(ifr));
 +              memset(&ifr, 0, sizeof ifr);
                strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
  
 -              if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
 +              if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr)) {
                        closesocket(nfd);
                        logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
-                                  strerror(errno));
+                                  strerror(sockerrno));
                        return -1;
                }
  #else
@@@ -446,6 -427,8 +441,8 @@@ void setup_outgoing_connection(outgoing
        connection_t *c;
        node_t *n;
  
 -      outgoing->event = NULL;
++      event_del(&outgoing->ev);
        n = lookup_node(outgoing->name);
  
        if(n)
@@@ -504,8 -478,8 +501,8 @@@ void handle_new_meta_connection(int soc
        fd = accept(sock, &sa.sa, &len);
  
        if(fd < 0) {
-               logger(LOG_ERR, "Accepting a new connection failed: %s", strerror(errno));
+               logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
 -              return false;
 +              return;
        }
  
        sockaddrunmap(&sa);
diff --cc src/node.h
Simple merge
diff --cc src/process.c
Simple merge
index c783189b94db2126ddc11ae8122e7834027ab9b6,c2df4cd83badc6e478af94f36167ceaac809e357..a38b9adffe6c876e0dad6a4e484353cd2426d2ec
@@@ -387,10 -494,10 +387,10 @@@ bool ack_h(connection_t *c, char *reque
        char hisport[MAX_STRING_SIZE];
        char *hisaddress, *dummy;
        int weight, mtu;
-       long int options;
+       uint32_t options;
        node_t *n;
  
-       if(sscanf(request, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
 -      if(sscanf(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 df7e9c25efc9960b79fc4b87eafc0404785f4518,300333b6b42b9567bbc21f4d21c903267982616d..4aad53f012da36bd16852d945612c4ce6e1fa2f0
@@@ -58,10 -58,10 +58,10 @@@ bool add_edge_h(connection_t *c, char *
        char to_address[MAX_STRING_SIZE];
        char to_port[MAX_STRING_SIZE];
        sockaddr_t address;
-       long int options;
+       uint32_t options;
        int weight;
  
-       if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
 -      if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d",
++      if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d",
                          from_name, to_name, to_address, to_port, &options, &weight) != 6) {
                logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name,
                           c->hostname);
index 6ec505487a46847939dce5207e3230a9743e3444,ba75c89988493db3ae835c397f79f970bb25f676..ea112b9dc99d8623dc6c399727643dd403e5a793
@@@ -45,9 -45,9 +45,9 @@@ bool add_subnet_h(connection_t *c, cha
        char subnetstr[MAX_STRING_SIZE];
        char name[MAX_STRING_SIZE];
        node_t *owner;
-       subnet_t s = {0}, *new;
+       subnet_t s = {0}, *new, *old;
  
 -      if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
 +      if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
                logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name,
                           c->hostname);
                return false;
        /* Tell the rest */
  
        if(!tunnelserver)
 -              forward_request(c);
 +              forward_request(c, request);
  
 -              old->expires = now;
+       /* Fast handoff of roaming MAC addresses */
+       if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires)
++              old->expires = 1;
        return true;
  }
  
diff --cc src/route.c
index 600c53dd4e1812809b8e7119d0ed77289931c7f4,5c69671ad30a7d55602569defe55db43eb970f9d..758801be80bbd38582b08d5a39724b453652a6db
@@@ -152,8 -115,9 +152,9 @@@ static void learn_mac(mac_t *address) 
  
                subnet = new_subnet();
                subnet->type = SUBNET_MAC;
 -              subnet->expires = now + macexpire;
 +              subnet->expires = time(NULL) + macexpire;
                subnet->net.mac.address = *address;
+               subnet->weight = 10;
                subnet_add(myself, subnet);
  
                /* And tell all other tinc daemons it's our MAC */
Simple merge
diff --cc src/subnet.c
index 1cb816390465fda49cc0bf762ee645f05d50167a,3d1168dee2600c69416bf91c7ad4ca623195a3ce..29ea96d9755276e2140a84cf9f13f53154fa1422
@@@ -324,7 -330,20 +330,20 @@@ subnet_t *lookup_subnet(const node_t *o
  }
  
  subnet_t *lookup_subnet_mac(const mac_t *address) {
-       subnet_t *p, subnet = {0};
+       subnet_t *p, *r = NULL, subnet = {0};
 -      avl_node_t *n;
++      splay_node_t *n;
+       int i;
+       // Check if this address is cached
+       for(i = 0; i < 2; i++) {
+               if(!cache_mac_valid[i])
+                       continue;
+               if(!memcmp(address, &cache_mac_address[i], sizeof *address))
+                       return cache_mac_subnet[i];
+       }
+       // Search all subnets for a matching one
  
        subnet.type = SUBNET_MAC;
        subnet.net.mac.address = *address;