diff --git a/src/graph.c b/src/graph.c index e0c48d42..87bb2204 100644 --- a/src/graph.c +++ b/src/graph.c @@ -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; diff --git a/src/net.c b/src/net.c index 0cdc72cc..7f17252d 100644 --- 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; } diff --git a/src/net_packet.c b/src/net_packet.c index 544bbde7..1730023d 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -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); diff --git a/src/net_setup.c b/src/net_setup.c index 3eb56441..75267794 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -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; diff --git a/src/netutl.c b/src/netutl.c index 83e19ed8..20648605 100644 --- a/src/netutl.c +++ b/src/netutl.c @@ -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; diff --git a/src/node.c b/src/node.c index 4ee9ce72..9d359253 100644 --- a/src/node.c +++ b/src/node.c @@ -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); } diff --git a/src/node.h b/src/node.h index 55a1b530..4321c008 100644 --- a/src/node.h +++ b/src/node.h @@ -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 */ - int compression; /* Compressionlevel, 0 = no compression */ + const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/ + int outmaclength; /* Length of MAC */ + + 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__ */ diff --git a/src/protocol.h b/src/protocol.h index 0664d4cf..ac86198e 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -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 */ diff --git a/src/protocol_key.c b/src/protocol_key.c index 06c6d336..5baa5f40 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -24,6 +24,7 @@ #include #include +#include #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;