From: Guus Sliepen Date: Fri, 5 Jun 2009 21:03:28 +0000 (+0200) Subject: Merge branch 'master' into 1.1 X-Git-Tag: release-1.1pre1~120 X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=commitdiff_plain;h=5a132550deb58473285e5f91705d286aef47be71 Merge branch 'master' into 1.1 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 --- 5a132550deb58473285e5f91705d286aef47be71 diff --cc doc/tincd.8.in index e4bbaeb7,7e168fd0..966cc77e --- a/doc/tincd.8.in +++ b/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 index b00a73bc,56bcb0b1..beabfeaf --- a/lib/utils.c +++ b/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/net_packet.c index 7d640cb6,40d94518..062e0be0 --- a/src/net_packet.c +++ b/src/net_packet.c @@@ -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; @@@ -170,9 -191,15 +180,15 @@@ 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; @@@ -180,19 -207,29 +196,19 @@@ /* 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; } @@@ -247,8 -288,11 +267,8 @@@ 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; } @@@ -346,9 -397,10 +368,9 @@@ /* 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 } } + static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { - avl_node_t *node; ++ 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) +void handle_incoming_vpn_data(int sock, short events, void *data) { vpn_packet_t pkt; char *hostname; diff --cc src/net_setup.c index 43adbc84,94e25b62..17eaec2b --- a/src/net_setup.c +++ b/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 */ @@@ -467,11 -503,15 +461,12 @@@ } /* - 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(); diff --cc src/net_socket.c index 43b8ada2,865df786..2dfaa2f0 --- a/src/net_socket.c +++ b/src/net_socket.c @@@ -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/node.c index 80d28d64,9d359253..5df8b667 --- a/src/node.c +++ b/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); } + void update_node_udp(node_t *n, const sockaddr_t *sa) + { - avl_delete(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); - avl_delete(node_udp_tree, n); - avl_insert(node_udp_tree, n); ++ 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); + } + } + -void dump_nodes(void) -{ - avl_node_t *node; +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 index f4fc88bb,4321c008..9b0d136f --- a/src/node.h +++ b/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 int dump_nodes(struct evbuffer *); + extern void update_node_udp(node_t *, const sockaddr_t *); -extern void dump_nodes(void); #endif /* __TINC_NODE_H__ */ diff --cc src/openssl/digest.c index 7c4dfc23,00000000..1e2557d9 mode 100644,000000..100644 --- a/src/openssl/digest.c +++ b/src/openssl/digest.c @@@ -1,84 -1,0 +1,84 @@@ +/* + digest.c -- Digest handling + Copyright (C) 2007 Guus Sliepen + + 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 + +#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_create(digest_t *digest, void *indata, size_t inlen, void *outdata) { ++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, void *indata, size_t inlen, void *cmpdata) { ++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; +} diff --cc src/openssl/digest.h index f10e67fb,00000000..deba7d3a mode 100644,000000..100644 --- a/src/openssl/digest.h +++ b/src/openssl/digest.h @@@ -1,43 -1,0 +1,43 @@@ +/* + digest.h -- header file digest.c + Copyright (C) 2007 Guus Sliepen + + 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 + +#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 *, void *indata, size_t inlen, void *outdata); - extern bool digest_verify(struct digest *, void *indata, size_t inlen, void *digestdata); ++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_auth.c index 2109cd4d,48166105..93fe23ea --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@@ -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 */ diff --cc src/protocol_key.c index 3cf4ab11,64225fd2..06ce733d --- a/src/protocol_key.c +++ b/src/protocol_key.c @@@ -22,9 -22,12 +22,10 @@@ #include "system.h" -#include -#include -#include - -#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" @@@ -33,22 -36,24 +34,22 @@@ #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; @@@ -82,13 -87,15 +83,13 @@@ 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; @@@ -120,10 -127,7 +121,8 @@@ /* 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; @@@ -134,30 -138,51 +133,42 @@@ 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]; @@@ -202,31 -227,55 +213,31 @@@ 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) { @@@ -234,15 -283,16 +245,15 @@@ 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) diff --cc src/protocol_subnet.c index 00cdde67,d40b3a33..e5927213 --- a/src/protocol_subnet.c +++ b/src/protocol_subnet.c @@@ -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 index ac0cbc6c,bec16cd3..76053a00 --- a/src/tincd.c +++ b/src/tincd.c @@@ -31,13 -31,24 +31,19 @@@ #include #endif -#include -#include -#include -#include -#include - #include LZO1X_H + #ifndef HAVE_MINGW + #include + #include + #include + #endif + #include -#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; @@@ -144,6 -215,30 +164,14 @@@ 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); + if(!event_init()) { + logger(LOG_ERR, _("Error initializing libevent!")); + return 1; + } + + if(!init_control()) + return 1; + - /* 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; - } - 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; }