Handle UDP packets from different and ports than advertised.
[tinc] / src / protocol_key.c
index cc927ba..5baa5f4 100644 (file)
@@ -1,7 +1,7 @@
 /*
     protocol_key.c -- handle the meta-protocol, key exchange
     Copyright (C) 1999-2005 Ivo Timmermans,
-                  2000-2006 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2009 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
@@ -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;
@@ -283,7 +296,5 @@ bool ans_key_h(connection_t *c)
        if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes)
                send_mtu_probe(from);
 
-       flush_queue(from);
-
        return true;
 }