Merge branch 'master' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Sat, 17 Apr 2010 10:21:53 +0000 (12:21 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 17 Apr 2010 10:21:53 +0000 (12:21 +0200)
Conflicts:
NEWS
README
configure.in
src/net.c
src/net.h

12 files changed:
1  2 
NEWS
doc/tinc.texi
src/conf.c
src/ipv4.h
src/ipv6.h
src/net.c
src/net.h
src/net_setup.c
src/netutl.c
src/protocol_auth.c
src/route.c
src/subnet.h

diff --cc NEWS
index 3b06596968f0a43638801fb2968de4e40f8b6b10,b5ce49600d12c92ec1d529f5717fa91a44abf30d..cee37ea824ca32fb6835e76a00f8a2f1d38ef4c3
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,9 -1,19 +1,25 @@@
 +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.14               not released yet
+  * Fixed reading configuration files that do not end with a newline. Again.
+ Version 1.0.13               Apr 11 2010
+  * Allow building tinc without LZO and/or Zlib.
+  * Clamp MSS of TCP packets in both directions.
+  * Experimental StrictSubnets, Forwarding and DirectOnly options,
+    giving more control over information and packets received from/sent to other
+    nodes.
+  * Ensure tinc never sends symbolic names for ports over the wire.
  Version 1.0.12               Feb  3 2010
  
   * Really allow fast roaming of hosts to other nodes in a switched VPN.
diff --cc doc/tinc.texi
Simple merge
diff --cc src/conf.c
index c734a0bbff68f6b4fc023c35ef061d53e6b677a5,ea33e9c38a4c91588aed75a9a7b91587e01d986d..d5bc9165804209608d30ced5bf589128e3b946ce
@@@ -237,8 -237,7 +237,7 @@@ 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[MAX_STRING_SIZE];
        char *line;
diff --cc src/ipv4.h
index 80ab17c506aaa096da22d3af72657490589b10fb,0000000000000000000000000000000000000000..940c239c985737669802aca300d80c34f78369af
mode 100644,000000..100644
--- /dev/null
@@@ -1,137 -1,0 +1,141 @@@
 +/*
 +    ipv4.h -- missing IPv4 related definitions
 +    Copyright (C) 2005 Ivo Timmermans
 +                  2006 Guus Sliepen <guus@tinc-vpn.org>
 +
 +    This program is free software; you can redistribute it and/or modify
 +    it under the terms of the GNU General Public License as published by
 +    the Free Software Foundation; either version 2 of the License, or
 +    (at your option) any later version.
 +
 +    This program is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License along
 +    with this program; if not, write to the Free Software Foundation, Inc.,
 +    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 +*/
 +
 +#ifndef __TINC_IPV4_H__
 +#define __TINC_IPV4_H__
 +
 +#ifndef AF_INET
 +#define AF_INET 2
 +#endif
 +
 +#ifndef IPPROTO_ICMP
 +#define IPPROTO_ICMP 1
 +#endif
 +
 +#ifndef ICMP_DEST_UNREACH
 +#define ICMP_DEST_UNREACH 3
 +#endif
 +
 +#ifndef ICMP_FRAG_NEEDED
 +#define ICMP_FRAG_NEEDED 4
 +#endif
 +
 +#ifndef ICMP_NET_UNKNOWN
 +#define ICMP_NET_UNKNOWN 6
 +#endif
 +
 +#ifndef ICMP_NET_UNREACH
 +#define ICMP_NET_UNREACH 0
 +#endif
 +
++#ifndef ICMP_NET_ANO
++#define ICMP_NET_ANO 9
++#endif
++
 +#ifndef IP_MSS
 +#define       IP_MSS          576
 +#endif
 +
 +#ifndef HAVE_STRUCT_IP
 +struct ip {
 +#if __BYTE_ORDER == __LITTLE_ENDIAN
 +      unsigned int ip_hl:4;
 +      unsigned int ip_v:4;
 +#else
 +      unsigned int ip_v:4;
 +      unsigned int ip_hl:4;
 +#endif
 +      uint8_t ip_tos;
 +      uint16_t ip_len;
 +      uint16_t ip_id; 
 +      uint16_t ip_off;
 +#define IP_RF 0x8000
 +#define IP_DF 0x4000
 +#define IP_MF 0x2000
 +      uint8_t ip_ttl;
 +      uint8_t ip_p;
 +      uint16_t ip_sum;
 +      struct in_addr ip_src, ip_dst;
 +} __attribute__ ((__packed__));
 +#endif
 +
 +#ifndef IP_OFFMASK
 +#define IP_OFFMASK 0x1fff
 +#endif
 +
 +#ifndef HAVE_STRUCT_ICMP
 +struct icmp {
 +      uint8_t icmp_type;
 +      uint8_t icmp_code;
 +      uint16_t icmp_cksum;
 +      union {
 +              uint8_t ih_pptr;
 +              struct in_addr ih_gwaddr;
 +              struct ih_idseq {
 +                      uint16_t icd_id;
 +                      uint16_t icd_seq;
 +              } ih_idseq;
 +              uint32_t ih_void;
 +
 +
 +              struct ih_pmtu {
 +                      uint16_t ipm_void;
 +                      uint16_t ipm_nextmtu;
 +              } ih_pmtu;
 +
 +              struct ih_rtradv {
 +                      uint8_t irt_num_addrs;
 +                      uint8_t irt_wpa;
 +                      uint16_t irt_lifetime;
 +              } ih_rtradv;
 +      } icmp_hun;
 +#define icmp_pptr icmp_hun.ih_pptr
 +#define icmp_gwaddr icmp_hun.ih_gwaddr
 +#define icmp_id icmp_hun.ih_idseq.icd_id
 +#define icmp_seq icmp_hun.ih_idseq.icd_seq
 +#define icmp_void icmp_hun.ih_void
 +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
 +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
 +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
 +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
 +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
 +      union {
 +              struct {
 +                      uint32_t its_otime;
 +                      uint32_t its_rtime;
 +                      uint32_t its_ttime;
 +              } id_ts;
 +              struct {
 +                      struct ip idi_ip;
 +              } id_ip;
 +              uint32_t id_mask;
 +              uint8_t id_data[1];
 +      } icmp_dun;
 +#define icmp_otime icmp_dun.id_ts.its_otime
 +#define icmp_rtime icmp_dun.id_ts.its_rtime
 +#define icmp_ttime icmp_dun.id_ts.its_ttime
 +#define icmp_ip icmp_dun.id_ip.idi_ip
 +#define icmp_radv icmp_dun.id_radv
 +#define icmp_mask icmp_dun.id_mask
 +#define icmp_data icmp_dun.id_data
 +} __attribute__ ((__packed__));
 +#endif
 +
 +#endif /* __TINC_IPV4_H__ */
diff --cc src/ipv6.h
index fee74f5ebc219b9399e6c141afac5eccfd2067c8,0000000000000000000000000000000000000000..d98001d6a0c2569ad26358a0d43fd5f0f561eec2
mode 100644,000000..100644
--- /dev/null
@@@ -1,127 -1,0 +1,128 @@@
 +/*
 +    ipv6.h -- missing IPv6 related definitions
 +    Copyright (C) 2005 Ivo Timmermans
 +                  2006 Guus Sliepen <guus@tinc-vpn.org>
 +
 +    This program is free software; you can redistribute it and/or modify
 +    it under the terms of the GNU General Public License as published by
 +    the Free Software Foundation; either version 2 of the License, or
 +    (at your option) any later version.
 +
 +    This program is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License along
 +    with this program; if not, write to the Free Software Foundation, Inc.,
 +    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 +*/
 +
 +#ifndef __TINC_IPV6_H__
 +#define __TINC_IPV6_H__
 +
 +#ifndef AF_INET6
 +#define AF_INET6 10
 +#endif
 +
 +#ifndef IPPROTO_ICMPV6
 +#define IPPROTO_ICMPV6 58
 +#endif
 +
 +#ifndef HAVE_STRUCT_IN6_ADDR
 +struct in6_addr {
 +      union {
 +              uint8_t u6_addr8[16];
 +              uint16_t u6_addr16[8];
 +              uint32_t u6_addr32[4];
 +      } in6_u;
 +} __attribute__ ((__packed__));
 +#define s6_addr in6_u.u6_addr8
 +#define s6_addr16 in6_u.u6_addr16
 +#define s6_addr32 in6_u.u6_addr32
 +#endif
 +
 +#ifndef HAVE_STRUCT_SOCKADDR_IN6
 +struct sockaddr_in6 {
 +      uint16_t sin6_family;
 +      uint16_t sin6_port;
 +      uint32_t sin6_flowinfo;
 +      struct in6_addr sin6_addr;
 +      uint32_t sin6_scope_id;
 +} __attribute__ ((__packed__));
 +#endif
 +
 +#ifndef IN6_IS_ADDR_V4MAPPED
 +#define IN6_IS_ADDR_V4MAPPED(a) \
 +        ((((__const uint32_t *) (a))[0] == 0) \
 +        && (((__const uint32_t *) (a))[1] == 0) \
 +        && (((__const uint32_t *) (a))[2] == htonl (0xffff)))
 +#endif
 +
 +#ifndef HAVE_STRUCT_IP6_HDR
 +struct ip6_hdr {
 +      union {
 +              struct ip6_hdrctl {
 +                      uint32_t ip6_un1_flow;
 +                      uint16_t ip6_un1_plen;
 +                      uint8_t ip6_un1_nxt;
 +                      uint8_t ip6_un1_hlim;
 +              } ip6_un1;
 +              uint8_t ip6_un2_vfc;
 +      } ip6_ctlun;
 +      struct in6_addr ip6_src;
 +      struct in6_addr ip6_dst;
 +} __attribute__ ((__packed__));
 +#define ip6_vfc ip6_ctlun.ip6_un2_vfc
 +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
 +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
 +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
 +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
 +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
 +#endif
 +
 +#ifndef HAVE_STRUCT_ICMP6_HDR
 +struct icmp6_hdr {
 +      uint8_t icmp6_type;
 +      uint8_t icmp6_code;
 +      uint16_t icmp6_cksum;
 +      union {
 +              uint32_t icmp6_un_data32[1];
 +              uint16_t icmp6_un_data16[2];
 +              uint8_t icmp6_un_data8[4];
 +      } icmp6_dataun;
 +} __attribute__ ((__packed__));
 +#define ICMP6_DST_UNREACH_NOROUTE 0
 +#define ICMP6_DST_UNREACH 1
 +#define ICMP6_PACKET_TOO_BIG 2
++#define ICMP6_DST_UNREACH_ADMIN 1
 +#define ICMP6_DST_UNREACH_ADDR 3
 +#define ND_NEIGHBOR_SOLICIT 135
 +#define ND_NEIGHBOR_ADVERT 136
 +#define icmp6_data32 icmp6_dataun.icmp6_un_data32
 +#define icmp6_data16 icmp6_dataun.icmp6_un_data16
 +#define icmp6_data8 icmp6_dataun.icmp6_un_data8
 +#define icmp6_mtu icmp6_data32[0]
 +#endif
 +
 +#ifndef HAVE_STRUCT_ND_NEIGHBOR_SOLICIT
 +struct nd_neighbor_solicit {
 +      struct icmp6_hdr nd_ns_hdr;
 +      struct in6_addr nd_ns_target;
 +} __attribute__ ((__packed__));
 +#define ND_OPT_SOURCE_LINKADDR 1
 +#define ND_OPT_TARGET_LINKADDR 2
 +#define nd_ns_type nd_ns_hdr.icmp6_type
 +#define nd_ns_code nd_ns_hdr.icmp6_code
 +#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
 +#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
 +#endif
 +
 +#ifndef HAVE_STRUCT_ND_OPT_HDR
 +struct nd_opt_hdr {
 +      uint8_t nd_opt_type;
 +      uint8_t nd_opt_len;
 +} __attribute__ ((__packed__));
 +#endif
 +
 +#endif /* __TINC_IPV6_H__ */
diff --cc src/net.c
index 23b3e7ca1316446689008184e5fdeaa4b5fdaf5f,a04ba005b67fc616e8291a4f80dddb9ff9c50af8..0e5823641de349b1bb2321623be9820e0a37891c
+++ b/src/net.c
@@@ -220,115 -334,203 +220,145 @@@ void handle_meta_connection_data(int fd
        }
  }
  
 -/*
 -  this is where it all happens...
 -*/
 -int main_loop(void) {
 -      fd_set readset, writeset;
 -      struct timeval tv;
 -      int r, maxfd;
 -      time_t last_ping_check, last_config_check, last_graph_dump;
 -      event_t *event;
 -
 -      last_ping_check = now;
 -      last_config_check = now;
 -      last_graph_dump = now;
 -      
 -      srand(now);
 -
 -      running = true;
 -
 -      while(running) {
 -              now = time(NULL);
 +static void sigterm_handler(int signal, short events, void *data) {
 +      logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
 +      event_loopexit(NULL);
 +}
  
 -      //      tv.tv_sec = 1 + (rand() & 7);   /* Approx. 5 seconds, randomized to prevent global synchronisation effects */
 -              tv.tv_sec = 1;
 -              tv.tv_usec = 0;
 +static void sighup_handler(int signal, short events, void *data) {
 +      logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
 +      reload_configuration();
 +}
  
 -              maxfd = build_fdset(&readset, &writeset);
 +int reload_configuration(void) {
 +      connection_t *c;
 +      splay_node_t *node, *next;
 +      char *fname;
 +      struct stat s;
 +      static time_t last_config_check = 0;
  
 -#ifdef HAVE_MINGW
 -              LeaveCriticalSection(&mutex);
 -#endif
 -              r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
 -#ifdef HAVE_MINGW
 -              EnterCriticalSection(&mutex);
 -#endif
 +      /* Reread our own configuration file */
  
 -              if(r < 0) {
 -                      if(!sockwouldblock(sockerrno)) {
 -                              logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno));
 -                              dump_connections();
 -                              return 1;
 -                      }
 -              }
 +      exit_configuration(&config_tree);
 +      init_configuration(&config_tree);
  
 -              if(r > 0)
 -                      check_network_activity(&readset, &writeset);
 +      if(!read_server_config()) {
 +              logger(LOG_ERR, "Unable to reread configuration file, exitting.");
 +              event_loopexit(NULL);
 +              return EINVAL;
 +      }
  
 -              if(do_purge) {
 -                      purge();
 -                      do_purge = false;
 +      /* Close connections to hosts that have a changed or deleted host config file */
 +      
 +      for(node = connection_tree->head; node; node = next) {
 +              c = node->data;
 +              next = node->next;
 +              
 +              if(c->outgoing) {
 +                      free(c->outgoing->name);
 +                      if(c->outgoing->ai)
 +                              freeaddrinfo(c->outgoing->ai);
 +                      free(c->outgoing);
 +                      c->outgoing = NULL;
                }
 +              
 +              xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
 +              if(stat(fname, &s) || s.st_mtime > last_config_check)
 +                      terminate_connection(c, c->status.active);
 +              free(fname);
 +      }
  
 -              /* Let's check if everybody is still alive */
 -
 -              if(last_ping_check + pingtimeout < now) {
 -                      check_dead_connections();
 -                      last_ping_check = now;
 -
 -                      if(routing_mode == RMODE_SWITCH)
 -                              age_subnets();
 -
 -                      age_past_requests();
 -
 -                      /* Should we regenerate our key? */
 -
 -                      if(keyexpires < now) {
 -                              avl_node_t *node;
 -                              node_t *n;
 +      last_config_check = time(NULL);
  
 -                              ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
++      /* If StrictSubnet is set, expire deleted Subnets and read new ones in */
 -                              for(node = node_tree->head; node; node = node->next) {
 -                                      n = node->data;
 -                                      if(n->inkey) {
 -                                              free(n->inkey);
 -                                              n->inkey = NULL;
 -                                      }
 -                              }
++      if(strictsubnets) {
++              subnet_t *subnet;
 -                              send_key_changed(broadcast, myself);
 -                              keyexpires = now + keylifetime;
 -                      }
++              for(node = subnet_tree->head; node; node = node->next) {
++                      subnet = node->data;
++                      subnet->expires = 1;
+               }
 -              if(sigalrm) {
 -                      avl_node_t *node;
 -                      logger(LOG_INFO, "Flushing event queue");
 -                      expire_events();
 -                      for(node = connection_tree->head; node; node = node->next) {
 -                              connection_t *c = node->data;
 -                              send_ping(c);
++              load_all_subnets();
++
++              for(node = subnet_tree->head; node; node = next) {
++                      next = node->next;
++                      subnet = node->data;
++                      if(subnet->expires == 1) {
++                              send_del_subnet(broadcast, subnet);
++                              if(subnet->owner->status.reachable)
++                                      subnet_update(subnet->owner, subnet, false);
++                              subnet_del(subnet->owner, subnet);
++                      } else if(subnet->expires == -1) {
++                              subnet->expires = 0;
++                      } else {
++                              send_add_subnet(broadcast, subnet);
++                              if(subnet->owner->status.reachable)
++                                      subnet_update(subnet->owner, subnet, true);
+                       }
 -                      sigalrm = false;
 -              }
 -
 -              while((event = get_expired_event())) {
 -                      event->handler(event->data);
 -                      free_event(event);
+               }
++      }
 -              if(sighup) {
 -                      connection_t *c;
 -                      avl_node_t *node, *next;
 -                      char *fname;
 -                      struct stat s;
 -                      
 -                      sighup = false;
 -                      
 -                      /* Reread our own configuration file */
 -
 -                      exit_configuration(&config_tree);
 -                      init_configuration(&config_tree);
 -
 -                      if(!read_server_config()) {
 -                              logger(LOG_ERR, "Unable to reread configuration file, exitting.");
 -                              return 1;
 -                      }
 -
 -                      /* Cancel non-active outgoing connections */
 -
 -                      for(node = connection_tree->head; node; node = next) {
 -                              next = node->next;
 -                              c = node->data;
 -
 -                              c->outgoing = NULL;
 -
 -                              if(c->status.connecting) {
 -                                      terminate_connection(c, false);
 -                                      connection_del(c);
 -                              }
 -                      }
 -
 -                      /* Wipe list of outgoing connections */
 -
 -                      for(list_node_t *node = outgoing_list->head; node; node = node->next) {
 -                              outgoing_t *outgoing = node->data;
 -
 -                              if(outgoing->event)
 -                                      event_del(outgoing->event);
 -                      }
 -
 -                      list_delete_list(outgoing_list);
 -
 -                      /* Close connections to hosts that have a changed or deleted host config file */
 -                      
 -                      for(node = connection_tree->head; node; node = node->next) {
 -                              c = node->data;
 -                              
 -                              xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
 -                              if(stat(fname, &s) || s.st_mtime > last_config_check)
 -                                      terminate_connection(c, c->status.active);
 -                              free(fname);
 -                      }
 +      /* Try to make outgoing connections */
 +      
 +      try_outgoing_connections();
  
 -                      last_config_check = now;
 +      return 0;
 +}
  
 -                      /* If StrictSubnet is set, expire deleted Subnets and read new ones in */
 +void retry(void) {
 +      connection_t *c;
 +      splay_node_t *node;
  
 -                      if(strictsubnets) {
 -                              subnet_t *subnet;
 +      for(node = connection_tree->head; node; node = node->next) {
 +              c = node->data;
 +              
 +              if(c->outgoing && !c->node) {
 +                      if(timeout_initialized(&c->outgoing->ev))
 +                              event_del(&c->outgoing->ev);
 +                      if(c->status.connecting)
 +                              close(c->socket);
 +                      c->outgoing->timeout = 0;
 +                      do_outgoing_connection(c);
 +              }
 +      }
 +}
  
 -                              for(node = subnet_tree->head; node; node = node->next) {
 -                                      subnet = node->data;
 -                                      subnet->expires = 1;
 -                              }
 +/*
 +  this is where it all happens...
 +*/
 +int main_loop(void) {
 +      struct event timeout_event;
 +      struct event sighup_event;
 +      struct event sigterm_event;
 +      struct event sigquit_event;
  
 -                              load_all_subnets();
 -
 -                              for(node = subnet_tree->head; node; node = next) {
 -                                      next = node->next;
 -                                      subnet = node->data;
 -                                      if(subnet->expires == 1) {
 -                                              send_del_subnet(broadcast, subnet);
 -                                              if(subnet->owner->status.reachable)
 -                                                      subnet_update(subnet->owner, subnet, false);
 -                                              subnet_del(subnet->owner, subnet);
 -                                      } else if(subnet->expires == -1) {
 -                                              subnet->expires = 0;
 -                                      } else {
 -                                              send_add_subnet(broadcast, subnet);
 -                                              if(subnet->owner->status.reachable)
 -                                                      subnet_update(subnet->owner, subnet, true);
 -                                      }
 -                              }
 -                      }
 +      timeout_set(&timeout_event, timeout_handler, &timeout_event);
 +      event_add(&timeout_event, &(struct timeval){pingtimeout, 0});
  
 -                      /* Try to make outgoing connections */
 -                      
 -                      try_outgoing_connections();
 -              }
 -              
 -              /* Dump graph if wanted every 60 seconds*/
 +#ifdef SIGHUP
 +      signal_set(&sighup_event, SIGHUP, sighup_handler, NULL);
 +      signal_add(&sighup_event, NULL);
 +#endif
 +#ifdef SIGTERM
 +      signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL);
 +      signal_add(&sigterm_event, NULL);
 +#endif
 +#ifdef SIGQUIT
 +      signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
 +      signal_add(&sigquit_event, NULL);
 +#endif
  
 -              if(last_graph_dump + 60 < now) {
 -                      dump_graph();
 -                      last_graph_dump = now;
 -              }
 +      if(event_loop(0) < 0) {
 +              logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno));
 +              return 1;
        }
  
 +      signal_del(&sighup_event);
 +      signal_del(&sigterm_event);
 +      signal_del(&sigquit_event);
 +      event_del(&timeout_event);
 +
        return 0;
  }
diff --cc src/net.h
index 634e9e75d3447eca5a0bcd158b8f0984954f9f5b,a97759fc80dfcf755e4b74bf24c327a63cec5c90..cd97e301e3e8f85c30d21c0df5f2e69a3de960cb
+++ b/src/net.h
@@@ -138,12 -139,7 +138,13 @@@ extern void terminate_connection(struc
  extern void flush_queue(struct node_t *);
  extern bool read_rsa_public_key(struct connection_t *);
  extern void send_mtu_probe(struct node_t *);
 +extern void handle_device_data(int, short, void *);
 +extern void handle_meta_connection_data(int, short, void *);
 +extern void regenerate_key();
 +extern void purge(void);
 +extern void retry(void);
 +extern int reload_configuration(void);
+ extern void load_all_subnets();
  
  #ifndef HAVE_MINGW
  #define closesocket(s) close(s)
diff --cc src/net_setup.c
index c2ae6491407b28a4f3e413db77ecb79866fa78a9,cb70926ad0c3dbaa13bac715514098a536f533a8..593d8625b410a2ca87c0444ad86fd614adf336d6
@@@ -162,9 -209,9 +162,9 @@@ void load_all_subnets(void) 
        struct dirent *ent;
        char *dname;
        char *fname;
 -      avl_tree_t *config_tree;
 +      splay_tree_t *config_tree;
        config_t *cfg;
-       subnet_t *s;
+       subnet_t *s, *s2;
        node_t *n;
        bool result;
  
diff --cc src/netutl.c
Simple merge
index cf6b26f2d4ad3f915c6532c93cf421769309281e,98d5b61dde4415db74e3c12a853489a99d8c5eea..8d4dfb939eb881824e3cdd96e739f4c5190a4aca
@@@ -399,9 -495,9 +399,9 @@@ static void send_everything(connection_
        }
  }
  
 -bool ack_h(connection_t *c) {
 +bool ack_h(connection_t *c, char *request) {
        char hisport[MAX_STRING_SIZE];
-       char *hisaddress, *dummy;
+       char *hisaddress;
        int weight, mtu;
        uint32_t options;
        node_t *n;
diff --cc src/route.c
index f18bd268305a520cc3ba7c1d22e6aacf7fa2c15b,1caf738ff99493c02ad1782b0547ba178d0ef5cc..9897d0d7e260f602ad809ff595d48226ffe60c6b
@@@ -50,10 -50,11 +50,13 @@@ 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))
+ #ifndef MAX
+ #define MAX(a, b) ((a) > (b) ? (a) : (b))
+ #endif
  
 +static struct event age_subnets_event;
 +
  /* RFC 1071 */
  
  static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
diff --cc src/subnet.h
index df48f60eda8268cc989cb9591bf47b4c72076c8f,e129a9592d3f98975db56aa0e7bf41dfff63bbd6..f22e6d58abfc0d36ee601519a999922cedf2612c
@@@ -64,6 -64,8 +64,8 @@@ typedef struct subnet_t 
  
  #define MAXNETSTR 64
  
 -extern avl_tree_t *subnet_tree;
++extern splay_tree_t *subnet_tree;
  extern int subnet_compare(const struct subnet_t *, const struct subnet_t *);
  extern subnet_t *new_subnet(void) __attribute__ ((__malloc__));
  extern void free_subnet(subnet_t *);