Merge branch 'master' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 5 Jun 2009 21:03:28 +0000 (23:03 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Fri, 5 Jun 2009 21:14:13 +0000 (23:14 +0200)
Conflicts:
doc/tincd.8.in
lib/pidfile.c
src/graph.c
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/netutl.c
src/node.c
src/node.h
src/protocol_auth.c
src/protocol_key.c
src/tincd.c

20 files changed:
1  2 
doc/tinc.texi
doc/tincd.8.in
lib/utils.c
src/graph.c
src/linux/device.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/netutl.c
src/node.c
src/node.h
src/openssl/digest.c
src/openssl/digest.h
src/protocol.h
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/protocol_subnet.c
src/tincd.c

diff --cc doc/tinc.texi
Simple merge
diff --cc doc/tincd.8.in
@@@ -8,14 -8,19 +8,16 @@@
  .Nd tinc VPN daemon
  .Sh SYNOPSIS
  .Nm
- .Op Fl cdDKnL
 -.Op Fl cdDkKnLRU
++.Op Fl cdDKnLRU
  .Op Fl -config Ns = Ns Ar DIR
  .Op Fl -no-detach
  .Op Fl -debug Ns Op = Ns Ar LEVEL
 -.Op Fl -kill Ns Op = Ns Ar SIGNAL
  .Op Fl -net Ns = Ns Ar NETNAME
 -.Op Fl -generate-keys Ns Op = Ns Ar BITS
  .Op Fl -mlock
  .Op Fl -logfile Ns Op = Ns Ar FILE
 -.Op Fl -pidfile Ns = Ns Ar FILE
  .Op Fl -bypass-security
+ .Op Fl -chroot
+ .Op Fl -user Ns = Ns Ar USER
  .Op Fl -help
  .Op Fl -version
  .Sh DESCRIPTION
diff --cc lib/utils.c
@@@ -29,9 -29,10 +29,9 @@@ volatile char (*cp_file[]) = {"?", "?"
  volatile int cp_index = 0;
  #endif
  
- char *hexadecimals = "0123456789ABCDEF";
+ const char hexadecimals[] = "0123456789ABCDEF";
  
 -int charhex2bin(char c)
 -{
 +int charhex2bin(char c) {
        if(isdigit(c))
                return c - '0';
        else
diff --cc src/graph.c
Simple merge
Simple merge
diff --cc src/net.h
Simple merge
@@@ -90,16 -96,14 +91,16 @@@ static void send_mtu_probe_handler(int 
                send_udppacket(n, &packet);
        }
  
 -      n->mtuevent = new_event();
 -      n->mtuevent->handler = (event_handler_t)send_mtu_probe;
 -      n->mtuevent->data = n;
 -      n->mtuevent->time = now + 1;
 -      event_add(n->mtuevent);
 +      event_add(&n->mtuevent, &(struct timeval){1, 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) {
+ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
        ifdebug(TRAFFIC) logger(LOG_INFO, _("Got MTU probe length %d from %s (%s)"), packet->len, n->name, n->hostname);
  
        if(!packet->data[0]) {
@@@ -160,7 -167,20 +161,16 @@@ static void receive_packet(node_t *n, v
        route(n, packet);
  }
  
- static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
 -static bool try_mac(const node_t *n, const vpn_packet_t *inpkt)
++static bool try_mac(node_t *n, const vpn_packet_t *inpkt)
+ {
 -      unsigned char hmac[EVP_MAX_MD_SIZE];
 -
 -      if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof inpkt->seqno + n->inmaclength)
++      if(!digest_active(&n->indigest) || !n->inmaclength || inpkt->len < sizeof inpkt->seqno + n->inmaclength)
+               return false;
 -      HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL);
 -
 -      return !memcmp(hmac, (char *) &inpkt->seqno + inpkt->len - n->inmaclength, n->inmaclength);
++      return digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len);
+ }
+ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
+ {
        vpn_packet_t pkt1, pkt2;
        vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
        int nextpkt = 0;
  
        cp();
  
 -      if(!n->inkey) {
++      if(!cipher_active(&n->incipher)) {
+               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got packet from %s (%s) but he hasn't got our key yet"),
+                                       n->name, n->hostname);
+               return;
+       }
        /* Check packet length */
  
-       if(inpkt->len < sizeof inpkt->seqno + digest_length(&myself->digest)) {
 -      if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
++      if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
                ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
                                        n->name, n->hostname);
                return;
  
        /* Check the message authentication code */
  
-       if(digest_active(&myself->digest) && !digest_verify(&myself->digest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len)) {
 -      if(n->indigest && n->inmaclength) {
 -              inpkt->len -= n->inmaclength;
 -              HMAC(n->indigest, n->inkey, n->inkeylength,
 -                       (unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
 -
 -              if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) {
 -                      ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"),
 -                                         n->name, n->hostname);
 -                      return;
 -              }
++      if(digest_active(&n->indigest) && !digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len)) {
 +              ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname);
 +              return;
        }
  
        /* Decrypt the packet */
  
-       if(cipher_active(&myself->cipher)) {
 -      if(n->incipher) {
++      if(cipher_active(&n->incipher)) {
                outpkt = pkt[nextpkt++];
 +              outlen = MAXSIZE;
  
-               if(!cipher_decrypt(&myself->cipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
 -              if(!EVP_DecryptInit_ex(&n->inctx, NULL, NULL, NULL, NULL)
 -                              || !EVP_DecryptUpdate(&n->inctx, (unsigned char *) &outpkt->seqno, &outlen,
 -                                      (unsigned char *) &inpkt->seqno, inpkt->len)
 -                              || !EVP_DecryptFinal_ex(&n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
 -                      ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s): %s"),
 -                                              n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
++              if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
 +                      ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s)"), n->name, n->hostname);
                        return;
                }
                
  
        inpkt->priority = 0;
  
 -      if(n->connection)
 -              n->connection->last_ping_time = now;
 -
        if(!inpkt->data[12] && !inpkt->data[13])
-               mtu_probe_h(n, inpkt);
+               mtu_probe_h(n, inpkt, origlen);
        else
                receive_packet(n, inpkt);
  }
@@@ -331,12 -379,15 +353,12 @@@ static void send_udppacket(node_t *n, v
  
        /* Encrypt the packet */
  
-       if(cipher_active(&n->cipher)) {
 -      if(n->outcipher) {
++      if(cipher_active(&n->outcipher)) {
                outpkt = pkt[nextpkt++];
 +              outlen = MAXSIZE;
  
-               if(!cipher_encrypt(&n->cipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
 -              if(!EVP_EncryptInit_ex(&n->outctx, NULL, NULL, NULL, NULL)
 -                              || !EVP_EncryptUpdate(&n->outctx, (unsigned char *) &outpkt->seqno, &outlen,
 -                                      (unsigned char *) &inpkt->seqno, inpkt->len)
 -                              || !EVP_EncryptFinal_ex(&n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
 -                      ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s): %s"),
 -                                              n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
++              if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
 +                      ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s)"), n->name, n->hostname);
                        goto end;
                }
  
  
        /* Add the message authentication code */
  
-       if(digest_active(&n->digest)) {
-               digest_create(&n->digest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len);
-               inpkt->len += digest_length(&n->digest);
 -      if(n->outdigest && n->outmaclength) {
 -              HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno,
 -                       inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
 -              inpkt->len += n->outmaclength;
++      if(digest_active(&n->outdigest)) {
++              digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len);
++              inpkt->len += digest_length(&n->outdigest);
        }
  
        /* Determine which socket we have to use */
@@@ -445,7 -505,31 +473,31 @@@ void broadcast_packet(const node_t *fro
        }
  }
  
 -      avl_node_t *node;
+ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
 -void handle_incoming_vpn_data(int sock)
++      splay_node_t *node;
+       edge_t *e;
+       node_t *n = NULL;
+       for(node = edge_weight_tree->head; node; node = node->next) {
+               e = node->data;
+               if(sockaddrcmp_noport(from, &e->address))
+                       continue;
+               if(!n)
+                       n = e->to;
+               if(!try_mac(e->to, pkt))
+                       continue;
+               n = e->to;
+               break;
+       }
+       return n;
+ }
 +void handle_incoming_vpn_data(int sock, short events, void *data)
  {
        vpn_packet_t pkt;
        char *hostname;
diff --cc src/net_setup.c
@@@ -132,37 -194,18 +132,31 @@@ 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() {
-       ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key"));
-       if(!cipher_regenerate_key(&myself->cipher, true)) {
-               logger(LOG_ERR, _("Error regenerating key!"));
-               abort();
-       }
 +      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});
  }
  
  /*
@@@ -302,40 -346,65 +296,40 @@@ 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(myself->incipher)
 -              myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
 -      else
 -              myself->inkeylength = 1;
 +      if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
 +              cipher = xstrdup("blowfish");
  
-       if(!cipher_open_by_name(&myself->cipher, cipher)) {
 -      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("sha1");
  
-       if(!digest_open_by_name(&myself->digest, digest)) {
 -                      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;
++      if(!digest_open_by_name(&myself->indigest, digest)) {
 +              logger(LOG_ERR, _("Unrecognized digest type!"));
 +              return false;
 +      }
  
-       if(!get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->maclength))
 -      myself->connection->outmaclength = 0;
++      if(!get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->inmaclength))
 +
-       if(digest_active(&myself->digest)) {
-               if(myself->maclength > digest_length(&myself->digest)) {
++      if(digest_active(&myself->indigest)) {
++              if(myself->inmaclength > digest_length(&myself->indigest)) {
 +                      logger(LOG_ERR, _("MAC length exceeds size of digest!"));
 +                      return false;
-               } else if(myself->maclength < 0) {
++              } else if(myself->inmaclength < 0) {
 +                      logger(LOG_ERR, _("Bogus MAC length!"));
 +                      return false;
 +              }
 +      }
  
        /* Compression */
  
  }
  
  /*
-   setup all initial network connections
+   initialize network
  */
- bool setup_network_connections(void) {
+ bool setup_network(void)
+ {
        cp();
  
 -      now = time(NULL);
 -
 -      init_events();
        init_connections();
        init_subnets();
        init_nodes();
@@@ -231,13 -310,12 +307,13 @@@ int setup_vpn_in_socket(const sockaddr_
        }
  
        return nfd;
- }
+ } /* int setup_vpn_in_socket */
  
 -void retry_outgoing(outgoing_t *outgoing)
 -{
 -      event_t *event;
 +static void retry_outgoing_handler(int fd, short events, void *data) {
 +      setup_outgoing_connection(data);
 +}
  
 +void retry_outgoing(outgoing_t *outgoing) {
        cp();
  
        outgoing->timeout += 5;
diff --cc src/netutl.c
Simple merge
diff --cc src/node.c
@@@ -90,10 -95,11 +90,12 @@@ void free_node(node_t *n) 
  
        sockaddrfree(&n->address);
  
-       cipher_close(&n->cipher);
-       digest_close(&n->digest);
 -      EVP_CIPHER_CTX_cleanup(&n->inctx);
 -      EVP_CIPHER_CTX_cleanup(&n->outctx);
++      cipher_close(&n->incipher);
++      digest_close(&n->indigest);
++      cipher_close(&n->outcipher);
++      digest_close(&n->outdigest);
  
 -      if(n->mtuevent)
 -              event_del(n->mtuevent);
 +      event_del(&n->mtuevent);
        
        if(n->hostname)
                free(n->hostname);
@@@ -129,10 -137,12 +131,11 @@@ void node_del(node_t *n) 
                edge_del(e);
        }
  
 -      avl_delete(node_tree, n);
 -      avl_delete(node_udp_tree, n);
 +      splay_delete(node_tree, n);
++      splay_delete(node_udp_tree, n);
  }
  
 -node_t *lookup_node(char *name)
 -{
 +node_t *lookup_node(char *name) {
        node_t n = {0};
  
        cp();
@@@ -150,24 -161,45 +153,43 @@@ node_t *lookup_node_udp(const sockaddr_
        n.address = *sa;
        n.name = NULL;
  
 -      return avl_search(node_udp_tree, &n);
 +      return splay_search(node_udp_tree, &n);
  }
  
 -      avl_delete(node_udp_tree, n);
+ void update_node_udp(node_t *n, const sockaddr_t *sa)
+ {
 -              avl_delete(node_udp_tree, n);
 -              avl_insert(node_udp_tree, n);
++      splay_delete(node_udp_tree, n);
+       if(n->hostname)
+               free(n->hostname);
+       if(sa) {
+               n->address = *sa;
+               n->hostname = sockaddr2hostname(&n->address);
 -void dump_nodes(void)
 -{
 -      avl_node_t *node;
++              splay_delete(node_udp_tree, n);
++              splay_insert(node_udp_tree, n);
+               logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
+       } else {
+               memset(&n->address, 0, sizeof n->address);
+               logger(LOG_DEBUG, "UDP address of %s cleared", n->name);
+       }
+ }
 +int dump_nodes(struct evbuffer *out) {
 +      splay_node_t *node;
        node_t *n;
  
        cp();
  
 -      logger(LOG_DEBUG, _("Nodes:"));
 -
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
 -              logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)"),
 -                         n->name, n->hostname, n->outcipher ? n->outcipher->nid : 0,
 -                         n->outdigest ? n->outdigest->type : 0, n->outmaclength, n->outcompression,
 +              if(evbuffer_add_printf(out, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d)\n"),
-                          n->name, n->hostname, cipher_get_nid(&n->cipher),
-                          digest_get_nid(&n->digest), n->maclength, n->compression,
++                         n->name, n->hostname, cipher_get_nid(&n->outcipher),
++                         digest_get_nid(&n->outdigest), n->outmaclength, n->outcompression,
                           n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-",
 -                         n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
 +                         n->via ? n->via->name : "-", n->distance, n->mtu, n->minmtu, n->maxmtu) == -1)
 +                      return errno;
        }
  
 -      logger(LOG_DEBUG, _("End of nodes."));
 +      return 0;
  }
diff --cc src/node.h
@@@ -54,13 -51,25 +54,18 @@@ typedef struct node_t 
  
        node_status_t status;
  
-       cipher_t cipher;                        /* Cipher for UDP packets */
-       digest_t digest;                        /* Digest for UDP packets */    
-       int maclength;                          /* Portion of digest to use */
 -      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 */  
++      int inmaclength;                                /* Portion of digest to use */
 +
-       int compression;                        /* Compressionlevel, 0 = no compression */
++      cipher_t outcipher;                        /* Cipher for UDP packets */
++      digest_t outdigest;                        /* Digest for UDP packets */ 
++      int outmaclength;                               /* Portion of digest to use */
+       int incompression;                      /* Compressionlevel, 0 = no compression */
+       int outcompression;                     /* Compressionlevel, 0 = no compression */
  
 +      int distance;
        struct node_t *nexthop;                 /* nearest node from us to him */
        struct node_t *via;                     /* next hop for UDP packets */
  
@@@ -93,6 -102,7 +98,7 @@@ extern void node_add(node_t *)
  extern void node_del(node_t *);
  extern node_t *lookup_node(char *);
  extern node_t *lookup_node_udp(const sockaddr_t *);
 -extern void dump_nodes(void);
 +extern int dump_nodes(struct evbuffer *);
+ extern void update_node_udp(node_t *, const sockaddr_t *);
  
  #endif                                                        /* __TINC_NODE_H__ */
index 7c4dfc2,0000000..1e2557d
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,84 @@@
- bool digest_create(digest_t *digest, void *indata, size_t inlen, void *outdata) {
 +/*
 +    digest.c -- Digest handling
 +    Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 +
 +    $Id$
 +*/
 +
 +#include "system.h"
 +
 +#include <openssl/err.h>
 +
 +#include "digest.h"
 +#include "logger.h"
 +
 +bool digest_open_by_name(digest_t *digest, const char *name) {
 +      digest->digest = EVP_get_digestbyname(name);
 +      if(digest->digest)
 +              return true;
 +
 +      logger(LOG_DEBUG, _("Unknown digest name '%s'!"), name);
 +      return false;
 +}
 +
 +bool digest_open_by_nid(digest_t *digest, int nid) {
 +      digest->digest = EVP_get_digestbynid(nid);
 +      if(digest->digest)
 +              return true;
 +
 +      logger(LOG_DEBUG, _("Unknown digest nid %d!"), nid);
 +      return false;
 +}
 +
 +bool digest_open_sha1(digest_t *digest) {
 +      digest->digest = EVP_sha1();
 +      return true;
 +}
 +
 +void digest_close(digest_t *digest) {
 +}
 +
- bool digest_verify(digest_t *digest, void *indata, size_t inlen, void *cmpdata) {
++bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
 +      EVP_MD_CTX ctx;
 +
 +      if(EVP_DigestInit(&ctx, digest->digest)
 +                      && EVP_DigestUpdate(&ctx, indata, inlen)
 +                      && EVP_DigestFinal(&ctx, outdata, NULL))
 +              return true;
 +      
 +      logger(LOG_DEBUG, _("Error creating digest: %s"), ERR_error_string(ERR_get_error(), NULL));
 +      return false;
 +}
 +
++bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
 +      size_t len = EVP_MD_size(digest->digest);
 +      char outdata[len];
 +
 +      return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, len);
 +}
 +
 +int digest_get_nid(const digest_t *digest) {
 +      return digest->digest ? digest->digest->type : 0;
 +}
 +
 +size_t digest_length(const digest_t *digest) {
 +      return EVP_MD_size(digest->digest);
 +}
 +
 +bool digest_active(const digest_t *digest) {
 +      return digest->digest && digest->digest->type != 0;
 +}
index f10e67f,0000000..deba7d3
mode 100644,000000..100644
--- /dev/null
@@@ -1,43 -1,0 +1,43 @@@
- extern bool digest_create(struct digest *, void *indata, size_t inlen, void *outdata);
- extern bool digest_verify(struct digest *, void *indata, size_t inlen, void *digestdata);
 +/*
 +    digest.h -- header file digest.c
 +    Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 +
 +    $Id$
 +*/
 +
 +#ifndef __TINC_DIGEST_H__
 +#define __TINC_DIGEST_H__
 +
 +#include <openssl/evp.h>
 +
 +#define DIGEST_MAX_SIZE EVP_MAX_MD_SIZE
 +
 +typedef struct digest {
 +      const EVP_MD *digest;
 +} digest_t;
 +
 +extern bool digest_open_by_name(struct digest *, const char *);
 +extern bool digest_open_by_nid(struct digest *, int);
 +extern bool digest_open_sha1(struct digest *);
 +extern void digest_close(struct digest *);
++extern bool digest_create(struct digest *, const void *indata, size_t inlen, void *outdata);
++extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
 +extern int digest_get_nid(const struct digest *);
 +extern size_t digest_length(const struct digest *);
 +extern bool digest_active(const struct digest *);
 +
 +#endif
diff --cc src/protocol.h
Simple merge
@@@ -242,8 -307,15 +242,8 @@@ bool send_challenge(connection_t *c) 
  
        cp();
  
 -      /* CHECKME: what is most reasonable value for len? */
 -
 -      len = RSA_size(c->rsa_key);
 -
 -      /* Allocate buffers for the challenge */
 -
 -      buffer = alloca(2 * len + 1);
 -
 -      c->hischallenge = xrealloc(c->hischallenge, len);
 +      if(!c->hischallenge)
-               c->hischallenge = xmalloc(len);
++              c->hischallenge = xrealloc(c->hischallenge, len);
  
        /* Copy random data to the buffer */
  
Simple merge
  
  #include "system.h"
  
 -#include <openssl/evp.h>
 -#include <openssl/err.h>
 -#include <openssl/rand.h>
 -
 -#include "avl_tree.h"
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "connection.h"
++#include "crypto.h"
  #include "logger.h"
  #include "net.h"
  #include "netutl.h"
  #include "utils.h"
  #include "xalloc.h"
  
 -bool mykeyused = false;
 +static bool mykeyused = false;
  
- bool send_key_changed(connection_t *c, const node_t *n) {
 -bool send_key_changed()
 -{
++bool send_key_changed() {
        cp();
  
        /* Only send this message if some other daemon requested our key previously.
           This reduces unnecessary key_changed broadcasts.
         */
  
-       if(n == myself && !mykeyused)
+       if(!mykeyused)
                return true;
  
-       return send_request(c, "%d %lx %s", KEY_CHANGED, random(), n->name);
+       return send_request(broadcast, "%d %lx %s", KEY_CHANGED, random(), myself->name);
  }
  
 -bool key_changed_h(connection_t *c)
 -{
 +bool key_changed_h(connection_t *c, char *request) {
        char name[MAX_STRING_SIZE];
        node_t *n;
  
        return true;
  }
  
- bool send_req_key(connection_t *c, const node_t *from, const node_t *to) {
 -bool send_req_key(node_t *to)
 -{
++bool send_req_key(node_t *to) {
        cp();
  
-       return send_request(c, "%d %s %s", REQ_KEY, from->name, to->name);
+       return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
  }
  
 -bool req_key_h(connection_t *c)
 -{
 +bool req_key_h(connection_t *c, char *request) {
        char from_name[MAX_STRING_SIZE];
        char to_name[MAX_STRING_SIZE];
        node_t *from, *to;
        /* Check if this key request is for us */
  
        if(to == myself) {                      /* Yes, send our own key back */
-               mykeyused = true;
-               from->received_seqno = 0;
-               memset(from->late, 0, sizeof from->late);
-               send_ans_key(c, myself, from);
++
+               send_ans_key(from);
        } else {
                if(tunnelserver)
                        return false;
                        return true;
                }
  
-               send_req_key(to->nexthop->connection, from, to);
 -              send_request(to->nexthop->connection, "%s", c->buffer);
++              send_request(to->nexthop->connection, "%s", request);
        }
  
        return true;
  }
  
- bool send_ans_key(connection_t *c, const node_t *from, const node_t *to) {
-       size_t keylen = cipher_keylength(&from->cipher);
 -bool send_ans_key(node_t *to)
 -{
 -      char *key;
++bool send_ans_key(node_t *to) {
++      size_t keylen = cipher_keylength(&myself->incipher);
 +      char key[keylen * 2 + 1];
  
        cp();
  
-       cipher_get_key(&from->cipher, key);
 -      // Set key parameters
 -      to->incipher = myself->incipher;
 -      to->inkeylength = myself->inkeylength;
 -      to->indigest = myself->indigest;
++      cipher_open_by_nid(&to->incipher, cipher_get_nid(&myself->incipher));
++      digest_open_by_nid(&to->indigest, digest_get_nid(&myself->indigest));
++      to->inmaclength = myself->inmaclength;
+       to->incompression = myself->incompression;
 -      // Allocate memory for key
 -      to->inkey = xrealloc(to->inkey, to->inkeylength);
++      randomize(key, keylen);
++      cipher_set_key(&to->incipher, key, true);
 -      // Create a new key
 -      RAND_pseudo_bytes((unsigned char *)to->inkey, to->inkeylength);
 -      if(to->incipher)
 -              EVP_DecryptInit_ex(&to->inctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + to->incipher->key_len);
 +      bin2hex(key, key, keylen);
 +      key[keylen * 2] = '\0';
  
-       return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY,
-                                               from->name, to->name, key,
-                                               cipher_get_nid(&from->cipher),
-                                               digest_get_nid(&from->digest), from->maclength,
-                                               from->compression);
+       // Reset sequence number and late packet window
+       mykeyused = true;
+       to->received_seqno = 0;
+       memset(to->late, 0, sizeof(to->late));
 -      // Convert to hexadecimal and send
 -      key = alloca(2 * to->inkeylength + 1);
 -      bin2hex(to->inkey, key, to->inkeylength);
 -      key[to->inkeylength * 2] = '\0';
 -
+       return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
 -                      myself->name, to->name, key,
 -                      to->incipher ? to->incipher->nid : 0,
 -                      to->indigest ? to->indigest->type : 0, to->inmaclength,
 -                      to->incompression);
++                                              myself->name, to->name, key,
++                                              cipher_get_nid(&to->incipher),
++                                              digest_get_nid(&to->indigest), to->inmaclength,
++                                              to->incompression);
  }
  
 -bool ans_key_h(connection_t *c)
 -{
 +bool ans_key_h(connection_t *c, char *request) {
        char from_name[MAX_STRING_SIZE];
        char to_name[MAX_STRING_SIZE];
        char key[MAX_STRING_SIZE];
                        return true;
                }
  
 -              return send_request(to->nexthop->connection, "%s", c->buffer);
 +              return send_request(to->nexthop->connection, "%s", request);
        }
  
 -      /* Update our copy of the origin's packet key */
 -      from->outkey = xrealloc(from->outkey, strlen(key) / 2);
 -
 -      from->outkey = xstrdup(key);
 -      from->outkeylength = strlen(key) / 2;
 -      hex2bin(key, from->outkey, from->outkeylength);
 -
 -      from->status.waitingforkey = false;
        /* Check and lookup cipher and digest algorithms */
  
-       if(!cipher_open_by_nid(&from->cipher, cipher)) {
 -      if(cipher) {
 -              from->outcipher = EVP_get_cipherbynid(cipher);
 -
 -              if(!from->outcipher) {
 -                      logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name,
 -                                 from->hostname);
 -                      return false;
 -              }
++      if(!cipher_open_by_nid(&from->outcipher, cipher)) {
 +              logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname);
 +              return false;
 +      }
  
-       if(strlen(key) / 2 != cipher_keylength(&from->cipher)) {
 -              if(from->outkeylength != from->outcipher->key_len + from->outcipher->iv_len) {
 -                      logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name,
 -                                 from->hostname);
 -                      return false;
 -              }
 -      } else {
 -              from->outcipher = NULL;
++      if(strlen(key) / 2 != cipher_keylength(&from->outcipher)) {
 +              logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname);
 +              return false;
        }
  
-       from->maclength = maclength;
+       from->outmaclength = maclength;
  
-       if(!digest_open_by_nid(&from->digest, digest)) {
 -      if(digest) {
 -              from->outdigest = EVP_get_digestbynid(digest);
 -
 -              if(!from->outdigest) {
 -                      logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name,
 -                                 from->hostname);
 -                      return false;
 -              }
++      if(!digest_open_by_nid(&from->outdigest, digest)) {
 +              logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname);
 +              return false;
 +      }
  
-       if(from->maclength > digest_length(&from->digest) || from->maclength < 0) {
 -              if(from->outmaclength > from->outdigest->md_size || from->outmaclength < 0) {
 -                      logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"),
 -                                 from->name, from->hostname);
 -                      return false;
 -              }
 -      } else {
 -              from->outdigest = NULL;
++      if(from->outmaclength > digest_length(&from->outdigest) || from->outmaclength < 0) {
 +              logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname);
 +              return false;
        }
  
        if(compression < 0 || compression > 11) {
                return false;
        }
        
-       from->compression = compression;
+       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 false;
 -              }
 +      /* Update our copy of the origin's packet key */
 +
-       hex2bin(key, key, cipher_keylength(&from->cipher));
-       cipher_set_key(&from->cipher, key, false);
++      hex2bin(key, key, cipher_keylength(&from->outcipher));
++      cipher_set_key(&from->outcipher, key, false);
  
        from->status.validkey = true;
 +      from->status.waitingforkey = false;
        from->sent_seqno = 0;
  
        if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes)
@@@ -205,9 -195,26 +195,26 @@@ bool del_subnet_h(connection_t *c, cha
                return false;
        }
  
 -      if(seen_request(c->buffer))
 +      if(seen_request(request))
                return true;
  
+       /* Check if the owner of the subnet being deleted is in the connection list */
+       owner = lookup_node(name);
+       if(tunnelserver && owner != myself && owner != c->node) {
+               /* in case of tunnelserver, ignore indirect subnet deletion */
+               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Ignoring indirect %s from %s (%s) for %s"),
+                                   "DEL_SUBNET", c->name, c->hostname, subnetstr);
+               return true;
+       }
+       if(!owner) {
+               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
+                                  "DEL_SUBNET", c->name, c->hostname, name);
+               return true;
+       }
        /* If everything is correct, delete the subnet from the list of the owner */
  
        s.owner = owner;
diff --cc src/tincd.c
  #include <sys/mman.h>
  #endif
  
 -#include <openssl/rand.h>
 -#include <openssl/rsa.h>
 -#include <openssl/pem.h>
 -#include <openssl/evp.h>
 -#include <openssl/engine.h>
 -
  #include LZO1X_H
  
+ #ifndef HAVE_MINGW
+ #include <pwd.h>
+ #include <grp.h>
+ #include <time.h>
+ #endif
  #include <getopt.h>
 -#include "pidfile.h"
  
  #include "conf.h"
 +#include "control.h"
 +#include "crypto.h"
  #include "device.h"
  #include "logger.h"
  #include "net.h"
@@@ -81,8 -105,11 +93,10 @@@ static struct option const long_options
        {"debug", optional_argument, NULL, 'd'},
        {"bypass-security", no_argument, NULL, 3},
        {"mlock", no_argument, NULL, 'L'},
+       {"chroot", no_argument, NULL, 'R'},
+       {"user", required_argument, NULL, 'U'},
        {"logfile", optional_argument, NULL, 4},
 -      {"pidfile", required_argument, NULL, 5},
 +      {"controlsocket", required_argument, NULL, 5},
        {NULL, 0, NULL, 0}
  };
  
@@@ -97,16 -124,19 +111,17 @@@ static void usage(bool status
                                program_name);
        else {
                printf(_("Usage: %s [option]...\n\n"), program_name);
 -              printf(_("  -c, --config=DIR           Read configuration options from DIR.\n"
 -                              "  -D, --no-detach            Don't fork and detach.\n"
 -                              "  -d, --debug[=LEVEL]        Increase debug level or set it to LEVEL.\n"
 -                              "  -k, --kill[=SIGNAL]        Attempt to kill a running tincd and exit.\n"
 -                              "  -n, --net=NETNAME          Connect to net NETNAME.\n"
 -                              "  -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n"
 -                              "  -L, --mlock                Lock tinc into main memory.\n"
 -                              "      --logfile[=FILENAME]   Write log entries to a logfile.\n"
 -                              "      --pidfile=FILENAME     Write PID to FILENAME.\n"
 -                              "  -R, --chroot               chroot to NET dir at startup.\n"
 -                              "  -U, --user=USER            setuid to given USER at startup.\n"
 -                              "      --help                 Display this help and exit.\n"
 -                              "      --version              Output version information and exit.\n\n"));
 +              printf(_(       "  -c, --config=DIR              Read configuration options from DIR.\n"
 +                              "  -D, --no-detach               Don't fork and detach.\n"
 +                              "  -d, --debug[=LEVEL]           Increase debug level or set it to LEVEL.\n"
 +                              "  -n, --net=NETNAME             Connect to net NETNAME.\n"
 +                              "  -L, --mlock                   Lock tinc into main memory.\n"
 +                              "      --logfile[=FILENAME]      Write log entries to a logfile.\n"
 +                              "      --controlsocket=FILENAME  Open control socket at FILENAME.\n"
 +                              "      --bypass-security         Disables meta protocol security, for debugging.\n"
-                               "      --help                    Display this help and exit.\n"
++                              "  -R, --chroot                  chroot to NET dir at startup.\n"
++                              "  -U, --user=USER               setuid to given USER at startup.\n"                            "      --help                    Display this help and exit.\n"
 +                              "      --version                 Output version information and exit.\n\n"));
                printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
        }
  }
@@@ -116,7 -146,7 +131,7 @@@ static bool parse_options(int argc, cha
        int r;
        int option_index = 0;
  
-       while((r = getopt_long(argc, argv, "c:DLd::n:", long_options, &option_index)) != EOF) {
 -      while((r = getopt_long(argc, argv, "c:DLd::k::n:K::RU:", long_options, &option_index)) != EOF) {
++      while((r = getopt_long(argc, argv, "c:DLd::n:RU:", long_options, &option_index)) != EOF) {
                switch (r) {
                        case 0:                         /* long option */
                                break;
                                netname = xstrdup(optarg);
                                break;
  
 -                      case 'K':                               /* generate public/private keypair */
 -                              if(optarg) {
 -                                      generate_keys = atoi(optarg);
 -
 -                                      if(generate_keys < 512) {
 -                                              fprintf(stderr, _("Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n"),
 -                                                              optarg);
 -                                              usage(true);
 -                                              return false;
 -                                      }
 -
 -                                      generate_keys &= ~7;    /* Round it to bytes */
 -                              } else
 -                                      generate_keys = 1024;
 -                              break;
 -
+                       case 'R':                               /* chroot to NETNAME dir */
+                               do_chroot = true;
+                               break;
+                       case 'U':                               /* setuid to USER */
+                               switchuser = optarg;
+                               break;
                        case 1:                                 /* show help */
                                show_help = true;
                                break;
@@@ -267,30 -523,11 +352,16 @@@ int main(int argc, char **argv
                return 0;
        }
  
 -      if(kill_tincd)
 -              return !kill_other(kill_tincd);
 -
        openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR);
  
-       /* Lock all pages into memory if requested */
-       if(do_mlock)
- #ifdef HAVE_MLOCKALL
-               if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
-                       logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
-                                  strerror(errno));
- #else
-       {
-               logger(LOG_ERR, _("mlockall() not supported on this platform!"));
- #endif
-               return -1;
-       }
 +      if(!event_init()) {
 +              logger(LOG_ERR, _("Error initializing libevent!"));
 +              return 1;
 +      }
 +
 +      if(!init_control())
 +              return 1;
 +
        g_argv = argv;
  
        init_configuration(&config_tree);
@@@ -348,10 -629,17 +454,13 @@@ end
        logger(LOG_NOTICE, _("Terminating"));
  
  #ifndef HAVE_MINGW
 -      remove_pid(pidfilename);
 +      exit_control();
  #endif
  
 -      EVP_cleanup();
 -      ENGINE_cleanup();
 -      CRYPTO_cleanup_all_ex_data();
 -      ERR_remove_state(0);
 -      ERR_free_strings();
 +      crypto_exit();
  
+       exit_configuration(&config_tree);
+       free_names();
        return status;
  }