Handle UDP packets from different and ports than advertised.
authorGuus Sliepen <guus@sliepen.eu.org>
Thu, 2 Apr 2009 23:05:23 +0000 (01:05 +0200)
committerGuus Sliepen <guus@sliepen.eu.org>
Thu, 2 Apr 2009 23:05:23 +0000 (01:05 +0200)
Previously, tinc used a fixed address and port for each node for UDP packet
exchange.  The port was the one advertised by that node as its listening port.
However, due to NAT the port might be different.  Now, tinc sends a different
session key to each node. This way, the sending node can be determined from
incoming packets by checking the MAC against all session keys. If a match is
found, the address and port for that node are updated.

src/graph.c
src/net.c
src/net_packet.c
src/net_setup.c
src/netutl.c
src/node.c
src/node.h
src/protocol.h
src/protocol_key.c

index e0c48d42890425e337ab62cee1b9ec2c09a8fb17..87bb220402dbd864e029782df1594eb55cdb9356 100644 (file)
@@ -226,27 +226,8 @@ void sssp_bfs(void)
                        e->to->via = indirect ? n->via : e->to;
                        e->to->options = e->options;
 
-                       if(sockaddrcmp(&e->to->address, &e->address)) {
-                               node = avl_unlink(node_udp_tree, e->to);
-                               sockaddrfree(&e->to->address);
-                               sockaddrcpy(&e->to->address, &e->address);
-
-                               if(e->to->hostname)
-                                       free(e->to->hostname);
-
-                               e->to->hostname = sockaddr2hostname(&e->to->address);
-
-                               if(node)
-                                       avl_insert_node(node_udp_tree, node);
-
-                               if(e->to->options & OPTION_PMTU_DISCOVERY) {
-                                       e->to->mtuprobes = 0;
-                                       e->to->minmtu = 0;
-                                       e->to->maxmtu = MTU;
-                                       if(e->to->status.validkey)
-                                               send_mtu_probe(e->to);
-                               }
-                       }
+                       if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
+                               update_node_udp(e->to, &e->address);
 
                        list_insert_tail(todo_list, e->to);
                }
@@ -269,13 +250,13 @@ void sssp_bfs(void)
                        if(n->status.reachable) {
                                ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became reachable"),
                                           n->name, n->hostname);
-                               avl_insert(node_udp_tree, n);
                        } else {
                                ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became unreachable"),
                                           n->name, n->hostname);
-                               avl_delete(node_udp_tree, n);
                        }
 
+                       /* TODO: only clear status.validkey if node is unreachable? */
+
                        n->status.validkey = false;
                        n->status.waitingforkey = false;
 
index 0cdc72cc5ad8f150ad6520f20ef06d1847850098..7f17252d3d52ea432f4ed4fe77fce8b12d9d1c48 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -414,11 +414,19 @@ int main_loop(void)
                        /* Should we regenerate our key? */
 
                        if(keyexpires < now) {
-                               ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key"));
+                               avl_node_t *node;
+                               node_t *n;
+
+                               ifdebug(STATUS) logger(LOG_INFO, _("Expiring symmetric keys"));
+
+                               for(node = node_tree->head; node; node = node->next) {
+                                       n = node->data;
+                                       if(n->inkey) {
+                                               free(n->inkey);
+                                               n->inkey = NULL;
+                                       }
+                               }
 
-                               RAND_pseudo_bytes((unsigned char *)myself->key, myself->keylength);
-                               if(myself->cipher)
-                                       EVP_DecryptInit_ex(&packet_ctx, myself->cipher, NULL, (unsigned char *)myself->key, (unsigned char *)myself->key + myself->cipher->key_len);
                                send_key_changed(broadcast, myself);
                                keyexpires = now + keylifetime;
                        }
index 544bbde775024a951d85525571406ca6ce0657c6..1730023d17c6f54c673896bbf4c25faf70b309f7 100644 (file)
@@ -168,6 +168,18 @@ static void receive_packet(node_t *n, vpn_packet_t *packet)
        route(n, packet);
 }
 
+static bool try_mac(const 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)
+               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);
+}
+
 static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 {
        vpn_packet_t pkt1, pkt2;
@@ -180,9 +192,15 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 
        cp();
 
+       if(!n->inkey) {
+               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) + myself->maclength) {
+       if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
                ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
                                        n->name, n->hostname);
                return;
@@ -190,12 +208,12 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 
        /* Check the message authentication code */
 
-       if(myself->digest && myself->maclength) {
-               inpkt->len -= myself->maclength;
-               HMAC(myself->digest, myself->key, myself->keylength,
+       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, myself->maclength)) {
+               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;
@@ -204,13 +222,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 
        /* Decrypt the packet */
 
-       if(myself->cipher) {
+       if(n->incipher) {
                outpkt = pkt[nextpkt++];
 
-               if(!EVP_DecryptInit_ex(&packet_ctx, NULL, NULL, NULL, NULL)
-                               || !EVP_DecryptUpdate(&packet_ctx, (unsigned char *) &outpkt->seqno, &outlen,
+               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(&packet_ctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
+                               || !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));
                        return;
@@ -253,10 +271,10 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
 
        /* Decompress the packet */
 
-       if(myself->compression) {
+       if(n->incompression) {
                outpkt = pkt[nextpkt++];
 
-               if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, myself->compression)) < 0) {
+               if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
                        ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while uncompressing packet from %s (%s)"),
                                                 n->name, n->hostname);
                        return;
@@ -315,7 +333,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
                                   n->name, n->hostname);
 
                if(!n->status.waitingforkey)
-                       send_req_key(n->nexthop->connection, myself, n);
+                       send_req_key(n);
 
                n->status.waitingforkey = true;
 
@@ -330,6 +348,8 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
                                n->name, n->hostname);
 
                send_tcppacket(n->nexthop->connection, origpkt);
+
+               return;
        }
 
        origlen = inpkt->len;
@@ -337,10 +357,10 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
 
        /* Compress the packet */
 
-       if(n->compression) {
+       if(n->outcompression) {
                outpkt = pkt[nextpkt++];
 
-               if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->compression)) < 0) {
+               if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
                        ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while compressing packet to %s (%s)"),
                                   n->name, n->hostname);
                        return;
@@ -356,13 +376,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
 
        /* Encrypt the packet */
 
-       if(n->cipher) {
+       if(n->outcipher) {
                outpkt = pkt[nextpkt++];
 
-               if(!EVP_EncryptInit_ex(&n->packet_ctx, NULL, NULL, NULL, NULL)
-                               || !EVP_EncryptUpdate(&n->packet_ctx, (unsigned char *) &outpkt->seqno, &outlen,
+               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->packet_ctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
+                               || !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));
                        goto end;
@@ -374,10 +394,10 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt)
 
        /* Add the message authentication code */
 
-       if(n->digest && n->maclength) {
-               HMAC(n->digest, n->key, n->keylength, (unsigned char *) &inpkt->seqno,
+       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->maclength;
+               inpkt->len += n->outmaclength;
        }
 
        /* Determine which socket we have to use */
@@ -476,6 +496,30 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet)
        }
 }
 
+static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
+       avl_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)
 {
        vpn_packet_t pkt;
@@ -498,11 +542,15 @@ void handle_incoming_vpn_data(int sock)
        n = lookup_node_udp(&from);
 
        if(!n) {
-               hostname = sockaddr2hostname(&from);
-               logger(LOG_WARNING, _("Received UDP packet from unknown source %s"),
-                          hostname);
-               free(hostname);
-               return;
+               n = try_harder(&from, &pkt);
+               if(n)
+                       update_node_udp(n, &from);
+               else {
+                       hostname = sockaddr2hostname(&from);
+                       logger(LOG_WARNING, _("Received UDP packet from unknown source %s"), hostname);
+                       free(hostname);
+                       return;
+               }
        }
 
        receive_udppacket(n, &pkt);
index 3eb564411e5affc45d1d8c52d0c2c84067c91d12..752677941e4ad4d4953f1e8d8eba6f0c4ee031de 100644 (file)
@@ -349,88 +349,72 @@ bool setup_myself(void)
        if(get_config_string
           (lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) {
                if(!strcasecmp(cipher, "none")) {
-                       myself->cipher = NULL;
+                       myself->incipher = NULL;
                } else {
-                       myself->cipher = EVP_get_cipherbyname(cipher);
+                       myself->incipher = EVP_get_cipherbyname(cipher);
 
-                       if(!myself->cipher) {
+                       if(!myself->incipher) {
                                logger(LOG_ERR, _("Unrecognized cipher type!"));
                                return false;
                        }
                }
        } else
-               myself->cipher = EVP_bf_cbc();
+               myself->incipher = EVP_bf_cbc();
 
-       if(myself->cipher)
-               myself->keylength = myself->cipher->key_len + myself->cipher->iv_len;
+       if(myself->incipher)
+               myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
        else
-               myself->keylength = 1;
+               myself->inkeylength = 1;
 
        myself->connection->outcipher = EVP_bf_ofb();
 
-       myself->key = xmalloc(myself->keylength);
-       RAND_pseudo_bytes((unsigned char *)myself->key, myself->keylength);
-
        if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
                keylifetime = 3600;
 
        keyexpires = now + keylifetime;
        
-       if(myself->cipher) {
-               EVP_CIPHER_CTX_init(&packet_ctx);
-               if(!EVP_DecryptInit_ex(&packet_ctx, myself->cipher, NULL, (unsigned char *)myself->key, (unsigned char *)myself->key + myself->cipher->key_len)) {
-                       logger(LOG_ERR, _("Error during initialisation of cipher for %s (%s): %s"),
-                                       myself->name, myself->hostname, ERR_error_string(ERR_get_error(), NULL));
-                       return false;
-               }
-
-       }
-
        /* Check if we want to use message authentication codes... */
 
-       if(get_config_string
-          (lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
+       if(get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
                if(!strcasecmp(digest, "none")) {
-                       myself->digest = NULL;
+                       myself->indigest = NULL;
                } else {
-                       myself->digest = EVP_get_digestbyname(digest);
+                       myself->indigest = EVP_get_digestbyname(digest);
 
-                       if(!myself->digest) {
+                       if(!myself->indigest) {
                                logger(LOG_ERR, _("Unrecognized digest type!"));
                                return false;
                        }
                }
        } else
-               myself->digest = EVP_sha1();
+               myself->indigest = EVP_sha1();
 
        myself->connection->outdigest = EVP_sha1();
 
-       if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"),
-               &myself->maclength)) {
-               if(myself->digest) {
-                       if(myself->maclength > myself->digest->md_size) {
+       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->maclength < 0) {
+                       } else if(myself->inmaclength < 0) {
                                logger(LOG_ERR, _("Bogus MAC length!"));
                                return false;
                        }
                }
        } else
-               myself->maclength = 4;
+               myself->inmaclength = 4;
 
        myself->connection->outmaclength = 0;
 
        /* Compression */
 
-       if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"),
-               &myself->compression)) {
-               if(myself->compression < 0 || myself->compression > 11) {
+       if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->incompression)) {
+               if(myself->incompression < 0 || myself->incompression > 11) {
                        logger(LOG_ERR, _("Bogus compression level!"));
                        return false;
                }
        } else
-               myself->compression = 0;
+               myself->incompression = 0;
 
        myself->connection->outcompression = 0;
 
index 83e19ed859a32197f8c886679832319deb9af82c..206486056de095597f0006f1eddd5d8df339e4c0 100644 (file)
@@ -144,6 +144,39 @@ char *sockaddr2hostname(const sockaddr_t *sa)
        return str;
 }
 
+int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b)
+{
+       int result;
+
+       cp();
+
+       result = a->sa.sa_family - b->sa.sa_family;
+
+       if(result)
+               return result;
+
+       switch (a->sa.sa_family) {
+               case AF_UNSPEC:
+                       return 0;
+
+               case AF_UNKNOWN:
+                       return strcmp(a->unknown.address, b->unknown.address);
+
+               case AF_INET:
+                       return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
+
+               case AF_INET6:
+                       return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
+
+               default:
+                       logger(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
+                                  a->sa.sa_family);
+                       cp_trace();
+                       raise(SIGFPE);
+                       exit(0);
+       }
+}
+
 int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b)
 {
        int result;
index 4ee9ce72a36f9a775880862f4e892bd6513424c1..9d3592535c267dcdcfca714045abf272f3c575cb 100644 (file)
@@ -42,16 +42,7 @@ static int node_compare(const node_t *a, const node_t *b)
 
 static int node_udp_compare(const node_t *a, const node_t *b)
 {
-       int result;
-
-       cp();
-
-       result = sockaddrcmp(&a->address, &b->address);
-
-       if(result)
-               return result;
-
-       return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
+       return sockaddrcmp(&a->address, &b->address);
 }
 
 void init_nodes(void)
@@ -78,7 +69,8 @@ node_t *new_node(void)
 
        n->subnet_tree = new_subnet_tree();
        n->edge_tree = new_edge_tree();
-       EVP_CIPHER_CTX_init(&n->packet_ctx);
+       EVP_CIPHER_CTX_init(&n->inctx);
+       EVP_CIPHER_CTX_init(&n->outctx);
        n->mtu = MTU;
        n->maxmtu = MTU;
 
@@ -89,8 +81,11 @@ void free_node(node_t *n)
 {
        cp();
 
-       if(n->key)
-               free(n->key);
+       if(n->inkey)
+               free(n->inkey);
+
+       if(n->outkey)
+               free(n->outkey);
 
        if(n->subnet_tree)
                free_subnet_tree(n->subnet_tree);
@@ -100,7 +95,8 @@ void free_node(node_t *n)
 
        sockaddrfree(&n->address);
 
-       EVP_CIPHER_CTX_cleanup(&n->packet_ctx);
+       EVP_CIPHER_CTX_cleanup(&n->inctx);
+       EVP_CIPHER_CTX_cleanup(&n->outctx);
 
        if(n->mtuevent)
                event_del(n->mtuevent);
@@ -142,6 +138,7 @@ void node_del(node_t *n)
        }
 
        avl_delete(node_tree, n);
+       avl_delete(node_udp_tree, n);
 }
 
 node_t *lookup_node(char *name)
@@ -167,6 +164,25 @@ node_t *lookup_node_udp(const sockaddr_t *sa)
        return avl_search(node_udp_tree, &n);
 }
 
+void update_node_udp(node_t *n, const sockaddr_t *sa)
+{
+       avl_delete(node_udp_tree, n);
+
+       if(n->hostname)
+               free(n->hostname);
+
+       if(sa) {
+               n->address = *sa;
+               n->hostname = sockaddr2hostname(&n->address);
+               avl_delete(node_udp_tree, n);
+               avl_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);
+       }
+}
+
 void dump_nodes(void)
 {
        avl_node_t *node;
@@ -179,8 +195,8 @@ void dump_nodes(void)
        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->cipher ? n->cipher->nid : 0,
-                          n->digest ? n->digest->type : 0, n->maclength, n->compression,
+                          n->name, n->hostname, n->outcipher ? n->outcipher->nid : 0,
+                          n->outdigest ? n->outdigest->type : 0, 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);
        }
index 55a1b5305f5f7848db958b8a983ef1a194383df7..4321c008618923f25e75b22cecd39e77ef8ed7ce 100644 (file)
@@ -51,15 +51,24 @@ typedef struct node_t {
 
        node_status_t status;
 
-       const EVP_CIPHER *cipher;               /* Cipher type for UDP packets */
-       char *key;                              /* Cipher key and iv */
-       int keylength;                          /* Cipher key and iv length */
-       EVP_CIPHER_CTX packet_ctx;              /* Cipher context */
+       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_MD *digest;                   /* Digest type for MAC */
-       int maclength;                          /* Length of MAC */
+       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 */
 
-       int compression;                        /* Compressionlevel, 0 = no compression */
+       int incompression;                      /* Compressionlevel, 0 = no compression */
+       int outcompression;                     /* Compressionlevel, 0 = no compression */
 
        struct node_t *nexthop;                 /* nearest node from us to him */
        struct node_t *via;                     /* next hop for UDP packets */
@@ -93,6 +102,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 update_node_udp(node_t *, const sockaddr_t *);
 extern void dump_nodes(void);
 
 #endif                                                 /* __TINC_NODE_H__ */
index 0664d4cfcd2b615b49ee13d40469d7d3eed00ac6..ac86198eff14eaeb06db30f7032469d70ad732a8 100644 (file)
@@ -97,9 +97,9 @@ extern bool send_add_subnet(struct connection_t *, const struct subnet_t *);
 extern bool send_del_subnet(struct connection_t *, const struct subnet_t *);
 extern bool send_add_edge(struct connection_t *, const struct edge_t *);
 extern bool send_del_edge(struct connection_t *, const struct edge_t *);
-extern bool send_key_changed(struct connection_t *, const struct node_t *);
-extern bool send_req_key(struct connection_t *, const struct node_t *, const struct node_t *);
-extern bool send_ans_key(struct connection_t *, const struct node_t *, const struct node_t *);
+extern bool send_key_changed();
+extern bool send_req_key(struct node_t *);
+extern bool send_ans_key(struct node_t *);
 extern bool send_tcppacket(struct connection_t *, struct vpn_packet_t *);
 
 /* Request handlers  */
index 06c6d3364702bee9f5a21a5edce5aae64618e82e..5baa5f409b1fcaf0a7c7b197d62da60f9259636a 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
+#include <openssl/rand.h>
 
 #include "avl_tree.h"
 #include "connection.h"
@@ -37,7 +38,7 @@
 
 bool mykeyused = false;
 
-bool send_key_changed(connection_t *c, const node_t *n)
+bool send_key_changed()
 {
        cp();
 
@@ -45,10 +46,10 @@ bool send_key_changed(connection_t *c, const node_t *n)
           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)
@@ -86,11 +87,11 @@ bool key_changed_h(connection_t *c)
        return true;
 }
 
-bool send_req_key(connection_t *c, const node_t *from, const 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)
@@ -129,7 +130,7 @@ bool req_key_h(connection_t *c)
                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;
@@ -140,27 +141,39 @@ bool req_key_h(connection_t *c)
                        return true;
                }
 
-               send_req_key(to->nexthop->connection, from, to);
+               send_request(to->nexthop->connection, "%s", c->buffer);
        }
 
        return true;
 }
 
-bool send_ans_key(connection_t *c, const node_t *from, const node_t *to)
+bool send_ans_key(node_t *to)
 {
        char *key;
 
        cp();
 
-       key = alloca(2 * from->keylength + 1);
-       bin2hex(from->key, key, from->keylength);
-       key[from->keylength * 2] = '\0';
+       if(!to->inkey) {
+               to->incipher = myself->incipher;
+               to->inkeylength = myself->inkeylength;
+               to->indigest = myself->indigest;
+               to->incompression = myself->incompression;
+               to->inkey = xmalloc(to->inkeylength);
 
-       return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY,
-                                               from->name, to->name, key,
-                                               from->cipher ? from->cipher->nid : 0,
-                                               from->digest ? from->digest->type : 0, from->maclength,
-                                               from->compression);
+               RAND_pseudo_bytes((unsigned char *)to->inkey, to->inkeylength);
+               if(to->incipher)
+                       EVP_DecryptInit_ex(&packet_ctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + to->incipher->key_len);
+       }
+
+       key = alloca(2 * to->inkeylength + 1);
+       bin2hex(to->inkey, key, to->inkeylength);
+       key[to->outkeylength * 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);
 }
 
 bool ans_key_h(connection_t *c)
@@ -214,13 +227,13 @@ bool ans_key_h(connection_t *c)
 
        /* Update our copy of the origin's packet key */
 
-       if(from->key)
-               free(from->key);
+       if(from->outkey)
+               free(from->outkey);
 
-       from->key = xstrdup(key);
-       from->keylength = strlen(key) / 2;
-       hex2bin(from->key, from->key, from->keylength);
-       from->key[from->keylength] = '\0';
+       from->outkey = xstrdup(key);
+       from->outkeylength = strlen(key) / 2;
+       hex2bin(from->outkey, from->outkey, from->outkeylength);
+       from->outkey[from->outkeylength] = '\0';
 
        from->status.validkey = true;
        from->status.waitingforkey = false;
@@ -229,41 +242,41 @@ bool ans_key_h(connection_t *c)
        /* Check and lookup cipher and digest algorithms */
 
        if(cipher) {
-               from->cipher = EVP_get_cipherbynid(cipher);
+               from->outcipher = EVP_get_cipherbynid(cipher);
 
-               if(!from->cipher) {
+               if(!from->outcipher) {
                        logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name,
                                   from->hostname);
                        return false;
                }
 
-               if(from->keylength != from->cipher->key_len + from->cipher->iv_len) {
+               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->cipher = NULL;
+               from->outcipher = NULL;
        }
 
-       from->maclength = maclength;
+       from->outmaclength = maclength;
 
        if(digest) {
-               from->digest = EVP_get_digestbynid(digest);
+               from->outdigest = EVP_get_digestbynid(digest);
 
-               if(!from->digest) {
+               if(!from->outdigest) {
                        logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name,
                                   from->hostname);
                        return false;
                }
 
-               if(from->maclength > from->digest->md_size || 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->digest = NULL;
+               from->outdigest = NULL;
        }
 
        if(compression < 0 || compression > 11) {
@@ -271,10 +284,10 @@ bool ans_key_h(connection_t *c)
                return false;
        }
        
-       from->compression = compression;
+       from->outcompression = compression;
 
-       if(from->cipher)
-               if(!EVP_EncryptInit_ex(&from->packet_ctx, from->cipher, NULL, (unsigned char *)from->key, (unsigned char *)from->key + from->cipher->key_len)) {
+       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;