Merge branch 'master' of git://tinc-vpn.org/tinc into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 25 Mar 2012 22:35:31 +0000 (23:35 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 25 Mar 2012 22:35:31 +0000 (23:35 +0100)
Conflicts:
NEWS
README
configure.in
src/Makefile.am
src/conf.c
src/conf.h
src/connection.c
src/net.c
src/tincd.c

29 files changed:
1  2 
NEWS
README
doc/tinc.conf.5.in
doc/tinc.texi
src/Makefile.am
src/conf.c
src/conf.h
src/connection.c
src/connection.h
src/device.h
src/graph.c
src/ipv4.h
src/ipv6.h
src/multicast_device.c
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/node.h
src/protocol.c
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/protocol_misc.c
src/route.c
src/route.h
src/subnet.c
src/tincd.c
src/vde_device.c

diff --cc NEWS
index 36f50606cd4bddad0c8cf063143dadd8b734560d,e2215fce0dde1ed47cfdbfa16d751a193cc0d28f..a3850477a70ce6b8df7a2d00c1273bbf6e98e09c
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,33 -1,29 +1,59 @@@
 +Version 1.1pre2              Juli 17 2011
 +
 + * .cookie files are renamed to .pid files, which are compatible with 1.0.x.
 +
 + * Experimental protocol enhancements that can be enabled with the option
 +   ExperimentalProtocol = yes:
 +
 +   * Ephemeral ECDH key exchange will be used for both the meta protocol and
 +     UDP session keys.
 +   * Key exchanges are signed with ECDSA.
 +   * ECDSA public keys are automatically exchanged after RSA authentication if
 +     nodes do not know each other's ECDSA public key yet.
 +
 +Version 1.1pre1              June 25 2011
 +
 + * Control interface allows control of a running tinc daemon. Used by:
 +   * tincctl, a commandline utility
 +   * tinc-gui, a preliminary GUI implemented in Python/wxWidgets
 +
 + * Code cleanups and reorganization. 
 +
 + * Repleacable cryptography backend, currently supports OpenSSL and libgcrypt.
 +
 + * Use libevent to handle I/O events and timeouts.
 +
 + * Use splay trees instead of AVL trees to manage internal datastructures.
 +
 + Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this
 + version of tinc.
 +
+ Version 1.0.18               March 25 2012
+  * Fixed IPv6 in switch mode by turning off DecrementTTL by default.
+  * Allow a port number to be specified in BindToAddress, which also allows tinc
+    to listen on multiple ports.
+  * Add support for multicast communication with UML/QEMU/KVM.
+ Version 1.0.17               March 10 2012
+  * The DeviceType option can now be used to select dummy, raw socket, UML and
+    VDE devices without needing to recompile tinc.
+  * Allow multiple BindToAddress statements.
+  * Decrement TTL value of IPv4 and IPv6 packets.
+  * Add LocalDiscovery option allowing tinc to detect peers that are behind the
+    same NAT.
+  * Accept Subnets passed with the -o option when StrictSubnets = yes.
+  * Disabling old RSA keys when generating new ones now also works properly on
+    Windows.
  Version 1.0.16               July 23 2011
  
   * Fixed a performance issue with TCP communication under Windows.
diff --cc README
index 09f6e6e9e60cbaee09d7ed5b7cefb58f226e6a74,ed1d2b42c84a4768de4ab0d5de8a3096a8b005ce..f978028b806d5644a1ba3a20df06cc3ab31fa326
--- 1/README
--- 2/README
+++ b/README
@@@ -1,7 -1,7 +1,7 @@@
 -This is the README file for tinc version 1.0.18. Installation
 +This is the README file for tinc version 1.1pre2. Installation
  instructions may be found in the INSTALL file.
  
- tinc is Copyright (C) 1998-2011 by:
+ tinc is Copyright (C) 1998-2012 by:
  
  Ivo Timmermans,
  Guus Sliepen <guus@tinc-vpn.org>,
Simple merge
diff --cc doc/tinc.texi
Simple merge
diff --cc src/Makefile.am
index 255ce3407f154f38e9021c0e4e6f4e63e3152081,cd44eb64adce99dc2a493613ff1670450c237962..e383e1f48eea7ed9e5ac3e8149e37398d046a206
@@@ -1,15 -1,13 +1,15 @@@
  ## Produce this file with automake to get Makefile.in
  
 -sbin_PROGRAMS = tincd
 +sbin_PROGRAMS = tincd tincctl sptps_test
  
 -EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h
 +EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt
  
 -tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c net_packet.c net_setup.c     \
 -      net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c       \
 -      protocol_key.c protocol_subnet.c route.c subnet.c tincd.c \
 +tincd_SOURCES = \
 +      utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \
 +      buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
 +      net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
 +      protocol_key.c protocol_subnet.c route.c sptps.c subnet.c tincd.c \
-       dummy_device.c raw_socket_device.c
+       dummy_device.c raw_socket_device.c multicast_device.c
        
  if UML
  tincd_SOURCES += uml_device.c
diff --cc src/conf.c
index d7df4e96893e240a9ae4616dfa53177be5989dd0,0fc9d8f46cc559a16fdca1075ffd3db6db987627..f580a203d9275ce99e057deca263f4d1ea25ff29
@@@ -400,60 -400,130 +400,21 @@@ bool read_connection_config(connection_
        return x;
  }
  
 -static void disable_old_keys(const char *filename) {
 -      char tmpfile[PATH_MAX] = "";
 -      char buf[1024];
 -      bool disabled = false;
 -      FILE *r, *w;
 -
 -      r = fopen(filename, "r");
 -      if(!r)
 -              return;
 -
 -      snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename);
 -
 -      w = fopen(tmpfile, "w");
 -
 -      while(fgets(buf, sizeof buf, r)) {
 -              if(!strncmp(buf, "-----BEGIN RSA", 14)) {       
 -                      buf[11] = 'O';
 -                      buf[12] = 'L';
 -                      buf[13] = 'D';
 -                      disabled = true;
 -              }
 -              else if(!strncmp(buf, "-----END RSA", 12)) {    
 -                      buf[ 9] = 'O';
 -                      buf[10] = 'L';
 -                      buf[11] = 'D';
 -                      disabled = true;
 -              }
 -              if(w && fputs(buf, w) < 0) {
 -                      disabled = false;
 -                      break;
 -              }
 -      }
 -
 -      if(w)
 -              fclose(w);
 -      fclose(r);
 -
 -      if(!w && disabled) {
 -              fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
 -              return;
 -      }
 -
 -      if(disabled) {
 -#ifdef HAVE_MINGW
 -              // We cannot atomically replace files on Windows.
 -              char bakfile[PATH_MAX] = "";
 -              snprintf(bakfile, sizeof bakfile, "%s.bak", filename);
 -              if(rename(filename, bakfile) || rename(tmpfile, filename)) {
 -                      rename(bakfile, filename);
 -#else
 -              if(rename(tmpfile, filename)) {
 -#endif
 -                      fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
 -              } else  {
 -#ifdef HAVE_MINGW
 -                      unlink(bakfile);
 -#endif
 -                      fprintf(stderr, "Warning: old key(s) found and disabled.\n");
 -              }
 -      }
 +bool append_config_file(const char *name, const char *key, const char *value) {
 +      char *fname;
 +      xasprintf(&fname, "%s/hosts/%s", confbase, name);
  
 -      unlink(tmpfile);
 -}
 +      FILE *fp = fopen(fname, "a");
  
 -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;
 +      if(!fp) {
 +              logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
        } 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;
 +              fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
 +              fclose(fp);
        }
  
 -      umask(0077);                            /* Disallow everything for group and other */
 -      disable_old_keys(fn);
 -
 -      /* Open it first to keep the inode busy */
 -
 -      r = fopen(fn, "a");
 -
 -      if(!r) {
 -              fprintf(stderr, "Error opening file `%s': %s\n",
 -                              fn, strerror(errno));
 -              return NULL;
 -      }
 +      free(fname);
  
 -      return r;
 +      return fp;
  }
- bool disable_old_keys(FILE *f) {
-       char buf[100];
-       long pos;
-       bool disabled = false;
-       rewind(f);
-       pos = ftell(f);
-       if(pos < 0)
-               return false;
--
-       while(fgets(buf, sizeof buf, f)) {
-               if(!strncmp(buf, "-----BEGIN RSA", 14)) {       
-                       buf[11] = 'O';
-                       buf[12] = 'L';
-                       buf[13] = 'D';
-                       if(fseek(f, pos, SEEK_SET))
-                               break;
-                       if(fputs(buf, f) <= 0)
-                               break;
-                       disabled = true;
-               }
-               else if(!strncmp(buf, "-----END RSA", 12)) {    
-                       buf[ 9] = 'O';
-                       buf[10] = 'L';
-                       buf[11] = 'D';
-                       if(fseek(f, pos, SEEK_SET))
-                               break;
-                       if(fputs(buf, f) <= 0)
-                               break;
-                       disabled = true;
-               }
-               pos = ftell(f);
-               if(pos < 0)
-                       break;
-       }
--
-       return disabled;
- }
diff --cc src/conf.h
index 1ae5b73541c4b1a4ff9ffb8b9c2e480355ed2850,3a040c7b74cdb9b5502210e764b59d6e13ecc059..743851a70b9b7cade29f0802c23393c08c4b4af3
@@@ -57,11 -57,11 +57,10 @@@ extern bool get_config_address(const co
  extern bool get_config_subnet(const config_t *, struct subnet_t **);
  
  extern config_t *parse_config_line(char *, const char *, int);
 -extern bool read_config_file(avl_tree_t *, const char *);
 -extern void read_config_options(avl_tree_t *, const char *);
 +extern bool read_config_file(splay_tree_t *, const char *);
 +extern void read_config_options(splay_tree_t *, const char *);
  extern bool read_server_config(void);
  extern bool read_connection_config(struct connection_t *);
 -extern FILE *ask_and_open(const char *, const char *);
 -extern bool is_safe_path(const char *);
 +extern bool append_config_file(const char *, const char *, const char *);
- extern bool disable_old_keys(FILE *);
  
  #endif                                                        /* __TINC_CONF_H__ */
index ee44e539acabadccf7a5818519a593eaec0b5495,9b752fadaa3d1b292e36702c933ffbcf08897bf5..dd5244860bfea4df1ff31d0f8cb9711b8409f027
@@@ -51,46 -48,66 +51,49 @@@ void exit_connections(void) 
  }
  
  connection_t *new_connection(void) {
 -      connection_t *c;
 +      return xmalloc_and_zero(sizeof(connection_t));
 +}
  
- void free_connection(connection_t *c) {
-       if(!c)
-               return;
-       if(c->name)
-               free(c->name);
-       if(c->hostname)
-               free(c->hostname);
 -      c = xmalloc_and_zero(sizeof(connection_t));
++void free_connection_partially(connection_t *c) {
 +      cipher_close(&c->incipher);
 +      digest_close(&c->indigest);
 +      cipher_close(&c->outcipher);
 +      digest_close(&c->outdigest);
  
 -      if(!c)
 -              return NULL;
 +      sptps_stop(&c->sptps);
 +      ecdsa_free(&c->ecdsa);
 +      rsa_free(&c->rsa);
  
 -      gettimeofday(&c->start, NULL);
 +      if(c->hischallenge)
 +              free(c->hischallenge);
  
-       if(c->config_tree)
-               exit_configuration(&c->config_tree);
 -      return c;
 -}
 +      buffer_clear(&c->inbuf);
 +      buffer_clear(&c->outbuf);
 +      
 +      if(event_initialized(&c->inevent))
 +              event_del(&c->inevent);
  
 -void free_connection_partially(connection_t *c) {
 -      free(c->inkey);
 -      free(c->outkey);
 -      free(c->mychallenge);
 -      free(c->hischallenge);
 -      free(c->outbuf);
 -
 -      c->inkey = NULL;
 -      c->outkey = NULL;
 -      c->mychallenge = NULL;
 -      c->hischallenge = NULL;
 -      c->outbuf = NULL;
 -
 -      c->buflen = 0;
 -      c->reqlen = 0;
 -      c->tcplen = 0;
 -      c->allow_request = 0;
 -      c->outbuflen = 0;
 -      c->outbufsize = 0;
 -      c->outbufstart = 0;
 -
 -      if(c->inctx) {
 -              EVP_CIPHER_CTX_cleanup(c->inctx);
 -              free(c->inctx);
 -              c->inctx = NULL;
 -      }
 +      if(event_initialized(&c->outevent))
 +              event_del(&c->outevent);
  
 -      if(c->outctx) {
 -              EVP_CIPHER_CTX_cleanup(c->outctx);
 -              free(c->outctx);
 -              c->outctx = NULL;
 -      }
 +      if(c->socket > 0)
 +              closesocket(c->socket);
  
 -      if(c->rsa_key) {
 -              RSA_free(c->rsa_key);
 -              c->rsa_key = NULL;
 -      }
++      c->socket = -1;
+ }
+ void free_connection(connection_t *c) {
++      if(!c)
++              return;
++
+       free_connection_partially(c);
+       free(c->name);
+       free(c->hostname);
+       if(c->config_tree)
+               exit_configuration(&c->config_tree);
        free(c);
  }
  
index 58eea4e694742ab26d0af94b39177493bbb41bbb,fbe4e02ca68a551728e57169c641d48e8eedd0b2..2b6870e41c60d90260c0f2e561f237268c9fdd89
@@@ -107,8 -107,9 +107,9 @@@ extern void init_connections(void)
  extern void exit_connections(void);
  extern connection_t *new_connection(void) __attribute__ ((__malloc__));
  extern void free_connection(connection_t *);
+ extern void free_connection_partially(connection_t *);
  extern void connection_add(connection_t *);
  extern void connection_del(connection_t *);
 -extern void dump_connections(void);
 +extern bool dump_connections(struct connection_t *);
  
  #endif                                                        /* __TINC_CONNECTION_H__ */
diff --cc src/device.h
Simple merge
diff --cc src/graph.c
Simple merge
diff --cc src/ipv4.h
index 57d236d33115f901ce2087834917b4214bf42826,0000000000000000000000000000000000000000..bd63ad04785e559c93eb18b53ed6fc0482ff3643
mode 100644,000000..100644
--- /dev/null
@@@ -1,149 -1,0 +1,149 @@@
-                   2006 Guus Sliepen <guus@tinc-vpn.org>
 +/*
 +    ipv4.h -- missing IPv4 related definitions
 +    Copyright (C) 2005 Ivo Timmermans
++                  2006-2012 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_TIME_EXCEEDED
 +#define ICMP_TIME_EXCEEDED 11
 +#endif
 +
 +#ifndef ICMP_EXC_TTL
 +#define ICMP_EXC_TTL 0
 +#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 d98001d6a0c2569ad26358a0d43fd5f0f561eec2,0000000000000000000000000000000000000000..6a4466f11d37e652121a11037e11eab4b09d1c77
mode 100644,000000..100644
--- /dev/null
@@@ -1,128 -1,0 +1,130 @@@
-                   2006 Guus Sliepen <guus@tinc-vpn.org>
 +/*
 +    ipv6.h -- missing IPv6 related definitions
 +    Copyright (C) 2005 Ivo Timmermans
++                  2006-2012 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_TIME_EXCEEDED 3
 +#define ICMP6_DST_UNREACH_ADMIN 1
 +#define ICMP6_DST_UNREACH_ADDR 3
++#define ICMP6_TIME_EXCEED_TRANSIT 0
 +#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__ */
index 0000000000000000000000000000000000000000,0b232dbb6f0238d260a8f658f6c7a69d19374b9b..e5e9a3fbd4fa7a009ec0b4cd7f11bc9d09341671
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,228 +1,228 @@@
 -              logger(LOG_ERR, "Device variable required for %s", device_info);
+ /*
+     device.c -- multicast socket
+     Copyright (C) 2002-2005 Ivo Timmermans,
+                   2002-2012 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.
+ */
+ #include "system.h"
+ #include "conf.h"
+ #include "device.h"
+ #include "net.h"
+ #include "logger.h"
+ #include "netutl.h"
+ #include "utils.h"
+ #include "route.h"
+ #include "xalloc.h"
+ static char *device_info;
+ static uint64_t device_total_in = 0;
+ static uint64_t device_total_out = 0;
+ static struct addrinfo *ai = NULL;
+ static mac_t ignore_src = {{0}};
+ static bool setup_device(void) {
+       char *host;
+       char *port;
+       char *space;
+       int ttl = 1;
+       device_info = "multicast socket";
+       get_config_string(lookup_config(config_tree, "Interface"), &iface);
+       if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
 -              logger(LOG_ERR, "Port number required for %s", device_info);
++              logger(DEBUG_ALWAYS, LOG_ERR, "Device variable required for %s", device_info);
+               return false;
+       }
+       host = xstrdup(device);
+       space = strchr(host, ' ');
+       if(!space) {
 -              logger(LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
++              logger(DEBUG_ALWAYS, LOG_ERR, "Port number required for %s", device_info);
+               return false;
+       }
+       *space++ = 0;
+       port = space;
+       space = strchr(port, ' ');
+       if(space) {
+               *space++ = 0;
+               ttl = atoi(space);
+       }
+       ai = str2addrinfo(host, port, SOCK_DGRAM);
+       if(!ai)
+               return false;
+       device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
+       if(device_fd < 0) {
 -              logger(LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno));
++              logger(DEBUG_ALWAYS, LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
+               return false;
+       }
+ #ifdef FD_CLOEXEC
+       fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+ #endif
+       static const int one = 1;
+       setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof one);
+       if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) {
+               closesocket(device_fd);
 -                              logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
++              logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno));
+               return false;
+       }
+       switch(ai->ai_family) {
+ #ifdef IP_ADD_MEMBERSHIP
+               case AF_INET: {
+                       struct ip_mreq mreq;
+                       struct sockaddr_in in;
+                       memcpy(&in, ai->ai_addr, sizeof in);
+                       mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr;
+                       mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+                       if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof mreq)) {
 -                              logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
++                              logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
+                               closesocket(device_fd);
+                               return false;
+                       }
+ #ifdef IP_MULTICAST_LOOP
+                       setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof one);
+ #endif
+ #ifdef IP_MULTICAST_TTL
+                       setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof ttl);
+ #endif
+               } break;
+ #endif
+ #ifdef IPV6_JOIN_GROUP
+               case AF_INET6: {
+                       struct ipv6_mreq mreq;
+                       struct sockaddr_in6 in6;
+                       memcpy(&in6, ai->ai_addr, sizeof in6);
+                       memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof mreq.ipv6mr_multiaddr);
+                       mreq.ipv6mr_interface = in6.sin6_scope_id;
+                       if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof mreq)) {
 -                      logger(LOG_ERR, "Multicast for address family %hx unsupported", ai->ai_family);
++                              logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
+                               closesocket(device_fd);
+                               return false;
+                       }
+ #ifdef IPV6_MULTICAST_LOOP
+                       setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof one);
+ #endif
+ #ifdef IPV6_MULTICAST_HOPS
+                       setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof ttl);
+ #endif
+               } break;
+ #endif
+       
+               default:
 -      logger(LOG_INFO, "%s is a %s", device, device_info);
++                      logger(DEBUG_ALWAYS, LOG_ERR, "Multicast for address family %hx unsupported", ai->ai_family);
+                       closesocket(device_fd);
+                       return false;
+       }
 -              logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
++      logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
+       return true;
+ }
+ static void close_device(void) {
+       close(device_fd);
+       free(device);
+       free(iface);
+       if(ai)
+               freeaddrinfo(ai);
+ }
+ static bool read_packet(vpn_packet_t *packet) {
+       int lenin;
+       if((lenin = recv(device_fd, packet->data, MTU, 0)) <= 0) {
 -              ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
++              logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
+                          device, strerror(errno));
+               return false;
+       }
+       if(!memcmp(&ignore_src, packet->data + 6, sizeof ignore_src)) {
 -      ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
++              logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
+               packet->len = 0;
+               return true;
+       }
+       packet->len = lenin;
+       device_total_in += packet->len;
 -      ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
++      logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
+                          device_info);
+       return true;
+ }
+ static bool write_packet(vpn_packet_t *packet) {
 -              logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
++      logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
+                          packet->len, device_info);
+       if(sendto(device_fd, packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
 -      logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
 -      logger(LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
 -      logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
++              logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
+                          strerror(errno));
+               return false;
+       }
+       device_total_out += packet->len;
+       memcpy(&ignore_src, packet->data + 6, sizeof ignore_src);
+       return true;
+ }
+ static void dump_device_stats(void) {
 -      logger(LOG_ERR, "Raw socket device not supported on this platform");
++      logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device);
++      logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in:  %10"PRIu64, device_total_in);
++      logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
+ }
+ const devops_t multicast_devops = {
+       .setup = setup_device,
+       .close = close_device,
+       .read = read_packet,
+       .write = write_packet,
+       .dump_stats = dump_device_stats,
+ };
+ #if 0
+ static bool not_supported(void) {
++      logger(DEBUG_ALWAYS, LOG_ERR, "Raw socket device not supported on this platform");
+       return false;
+ }
+ const devops_t multicast_devops = {
+       .setup = not_supported,
+       .close = NULL,
+       .read = NULL,
+       .write = NULL,
+       .dump_stats = NULL,
+ };
+ #endif
diff --cc src/net.c
index 10a2d20645951081fef4c68e70fdf4e97f8df111,9799feabdf73952f3dc709434210f6014dee31d4..db5743af2e9179915aca7686ac5c7fa497050746
+++ b/src/net.c
@@@ -139,12 -204,14 +139,13 @@@ void terminate_connection(connection_t 
                }
        }
  
-       /* Check if this was our outgoing connection */
+       free_connection_partially(c);
  
-       if(c->outgoing)
-               retry_outgoing(c->outgoing);
+       /* Check if this was our outgoing connection */
  
-       connection_del(c);
+       if(c->outgoing) {
 -              c->status.remove = false;
+               do_outgoing_connection(c);      
+       }
  }
  
  /*
@@@ -170,10 -233,10 +171,10 @@@ static void timeout_handler(int fd, sho
                if(c->last_ping_time + pingtimeout <= now) {
                        if(c->status.active) {
                                if(c->status.pinged) {
 -                                      ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
 +                                      logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
-                                                          c->name, c->hostname, now - c->last_ping_time);
+                                                          c->name, c->hostname, (long)now - c->last_ping_time);
 -                                      c->status.timeout = true;
                                        terminate_connection(c, true);
 +                                      continue;
                                } else if(c->last_ping_time + pinginterval <= now) {
                                        send_ping(c);
                                }
diff --cc src/net.h
Simple merge
Simple merge
diff --cc src/net_setup.c
Simple merge
diff --cc src/node.h
Simple merge
diff --cc src/protocol.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc src/route.c
Simple merge
diff --cc src/route.h
Simple merge
diff --cc src/subnet.c
Simple merge
diff --cc src/tincd.c
index a78ca0c4a7e1bdc5bae92c7353a397efcf8085ee,443301e083f178a501926dd0d383315463c2409b..1008f88aaec0865a5c604594f586f277a83f9f60
@@@ -357,9 -516,9 +357,9 @@@ int main(int argc, char **argv) 
        make_names();
  
        if(show_version) {
 -              printf("%s version %s (built %s %s, protocol %d)\n", PACKAGE,
 -                         VERSION, __DATE__, __TIME__, PROT_CURRENT);
 +              printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
 +                         VERSION, __DATE__, __TIME__, PROT_MAJOR, PROT_MINOR);
-               printf("Copyright (C) 1998-2011 Ivo Timmermans, Guus Sliepen and others.\n"
+               printf("Copyright (C) 1998-2012 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"
index ab2ffdcd70617bc174dddb490f1982cd1f13eb3d,e69ae80236457cf973bf9fb5c0efe1e3e8c32ae4..815b956fbeae12f417fde3633f3f870196a484be
@@@ -99,9 -99,9 +99,9 @@@ static void close_device(void) 
  }
  
  static bool read_packet(vpn_packet_t *packet) {
-       int lenin = plug.vde_recv(conn, packet->data, MTU, 0);
+       int lenin = (ssize_t)plug.vde_recv(conn, packet->data, MTU, 0);
        if(lenin <= 0) {
 -              logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
 +              logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
                running = false;
                return false;
        }
  }
  
  static bool write_packet(vpn_packet_t *packet) {
-       if(plug.vde_send(conn, packet->data, packet->len, 0) < 0) {
+       if((ssize_t)plug.vde_send(conn, packet->data, packet->len, 0) < 0) {
                if(errno != EINTR && errno != EAGAIN) {
 -                      logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
 +                      logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
                        running = false;
                }