From: Sven-Haegar Koch Date: Fri, 26 Mar 2010 15:51:03 +0000 (+0100) Subject: Merge branch 'master' into 1.1 X-Git-Tag: release-1.1pre1~83 X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=commitdiff_plain;h=103543aa2c15d9f1e2aa313a2e593a7524cce484 Merge branch 'master' into 1.1 Conflicts: NEWS README configure.in have.h src/conf.c src/conf.h src/net.c src/net_packet.c src/protocol_key.c src/protocol_subnet.c src/route.c src/tincd.c --- 103543aa2c15d9f1e2aa313a2e593a7524cce484 diff --cc NEWS index 51f11be3,942398ef..3b065969 --- a/NEWS +++ b/NEWS @@@ -1,9 -1,18 +1,24 @@@ +Version 1.1-cvs Work in progress + + * Use libevent to handle I/O events and timeouts. + + * Use splay trees instead of AVL trees. + + Version 1.0.12 Feb 3 2010 + + * Really allow fast roaming of hosts to other nodes in a switched VPN. + + * Fixes missing or incorrect environment variables when calling host-up/down + and subnet-up/down scripts in some cases. + + * Allow port to be specified in Address statements. + + * Clamp MSS of TCP packets to the discovered path MTU. + + * Let two nodes behind NAT learn each others current UDP address and port via + a third node, potentially allowing direct communications in a similar way to + STUN. + Version 1.0.11 Nov 1 2009 * Fixed potential crash when the HUP signal is sent. diff --cc README index 01ea9507,9cc1042f..3f21f25d --- a/README +++ b/README @@@ -1,7 -1,7 +1,7 @@@ -This is the README file for tinc version 1.0.12. Installation +This is the README file for tinc version 1.1-cvs. Installation instructions may be found in the INSTALL file. - tinc is Copyright (C) 1998-2009 by: + tinc is Copyright (C) 1998-2010 by: Ivo Timmermans, Guus Sliepen , diff --cc doc/tinc.texi index 094c54db,a938c272..f4b98dd7 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@@ -37,10 -37,9 +37,10 @@@ permission notice identical to this one @page @vskip 0pt plus 1filll +@cindex copyright This is the info manual for @value{PACKAGE} version @value{VERSION}, a Virtual Private Network daemon. - Copyright @copyright{} 1998-2009 Ivo Timmermans, + Copyright @copyright{} 1998-2010 Ivo Timmermans, Guus Sliepen and Wessel Dankers . diff --cc have.h index 92914ea0,cf5c173a..89454feb --- a/have.h +++ b/have.h @@@ -101,10 -96,10 +101,14 @@@ #include #endif +#ifdef HAVE_SYS_UN_H +#include +#endif + + #ifdef HAVE_DIRENT_H + #include + #endif + /* SunOS really wants sys/socket.h BEFORE net/if.h, and FreeBSD wants these lines below the rest. */ diff --cc src/conf.c index b1a6f0b1,f64fb221..42866b83 --- a/src/conf.c +++ b/src/conf.c @@@ -279,10 -237,10 +237,11 @@@ static char *readline(FILE * fp, char * Parse a configuration file and put the results in the configuration tree starting at *base. */ -bool read_config_file(avl_tree_t *config_tree, const char *fname) { +int read_config_file(splay_tree_t *config_tree, const char *fname) { + int err = -2; /* Parse error */ FILE *fp; - char *buffer, *line; + char buffer[MAX_STRING_SIZE]; + char *line; char *variable, *value, *eol; int lineno = 0; int len; diff --cc src/connection.h index 6d295312,5aac4a66..0f2b1d6a --- a/src/connection.h +++ b/src/connection.h @@@ -29,19 -29,19 +29,20 @@@ #define OPTION_INDIRECT 0x0001 #define OPTION_TCPONLY 0x0002 #define OPTION_PMTU_DISCOVERY 0x0004 + #define OPTION_CLAMP_MSS 0x0008 typedef struct connection_status_t { - int pinged:1; /* sent ping */ - int active:1; /* 1 if active.. */ - int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */ - int termreq:1; /* the termination of this connection was requested */ - int remove:1; /* Set to 1 if you want this connection removed */ - int timeout:1; /* 1 if gotten timeout */ - int encryptout:1; /* 1 if we can encrypt outgoing traffic */ - int decryptin:1; /* 1 if we have to decrypt incoming traffic */ - int mst:1; /* 1 if this connection is part of a minimum spanning tree */ - int unused:23; + int pinged:1; /* sent ping */ + int active:1; /* 1 if active.. */ + int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */ + int termreq:1; /* the termination of this connection was requested */ + int remove_unused:1; /* Set to 1 if you want this connection removed */ + int timeout_unused:1; /* 1 if gotten timeout */ + int encryptout:1; /* 1 if we can encrypt outgoing traffic */ + int decryptin:1; /* 1 if we have to decrypt incoming traffic */ + int mst:1; /* 1 if this connection is part of a minimum spanning tree */ + int control:1; + int unused:22; } connection_status_t; #include "edge.h" diff --cc src/net_packet.c index b50ddc4f,a438d3e9..fc09957d --- a/src/net_packet.c +++ b/src/net_packet.c @@@ -20,17 -20,26 +20,28 @@@ #include "system.h" + #include + #include + #include + #include + #include + + #ifdef HAVE_ZLIB #include + #endif + + #ifdef HAVE_LZO #include LZO1X_H + #endif -#include "avl_tree.h" +#include "splay_tree.h" +#include "cipher.h" #include "conf.h" #include "connection.h" +#include "crypto.h" +#include "digest.h" #include "device.h" #include "ethernet.h" -#include "event.h" #include "graph.h" #include "list.h" #include "logger.h" diff --cc src/net_setup.c index c643449b,70291bff..9a0c78bd --- a/src/net_setup.c +++ b/src/net_setup.c @@@ -127,33 -187,79 +127,92 @@@ 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() { + 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}); } + /* + Read Subnets from all host config files + */ + static void load_all_subnets(void) { + DIR *dir; + struct dirent *ent; + char *dname; + char *fname; + avl_tree_t *config_tree; + config_t *cfg; + subnet_t *s; + node_t *n; + bool result; + + xasprintf(&dname, "%s/hosts", confbase); + dir = opendir(dname); + if(!dir) { + logger(LOG_ERR, "Could not open %s: %s", dname, strerror(errno)); + free(dname); + return; + } + + while((ent = readdir(dir))) { + if(!check_id(ent->d_name)) + continue; + + n = lookup_node(ent->d_name); + if(n) + continue; + + #ifdef _DIRENT_HAVE_D_TYPE + //if(ent->d_type != DT_REG) + // continue; + #endif + + xasprintf(&fname, "%s/hosts/%s", confbase, ent->d_name); + init_configuration(&config_tree); + result = read_config_file(config_tree, fname); + free(fname); + if(!result) + continue; + + n = new_node(); + n->name = xstrdup(ent->d_name); + node_add(n); + + for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) { + if(!get_config_subnet(cfg, &s)) + continue; + + subnet_add(n, s); + } + + exit_configuration(&config_tree); + } + + closedir(dir); + } + /* Configure node_t myself and set up the local sockets (listen only) */ diff --cc src/net_socket.c index d05dfd5c,96e268fa..5eef3875 --- a/src/net_socket.c +++ b/src/net_socket.c @@@ -258,11 -259,15 +258,15 @@@ int setup_vpn_in_socket(const sockaddr_ #endif option = 1; - setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option); - #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) + #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) - setsockopt(nfd, SOL_IPV6, IPV6_V6ONLY, &option, sizeof option); + setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, &option, sizeof option); + #endif + + #if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT) + #define IP_DONTFRAGMENT IP_DONTFRAG #endif #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) diff --cc src/node.h index f5ebde3b,83e89c7d..a9322aa5 --- a/src/node.h +++ b/src/node.h @@@ -46,12 -45,23 +46,13 @@@ typedef struct node_t char *hostname; /* the hostname of its real ip */ node_status_t status; + time_t last_req_key; - 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 */ + + cipher_t outcipher; /* Cipher for UDP packets */ + digest_t outdigest; /* Digest for UDP packets */ int incompression; /* Compressionlevel, 0 = no compression */ int outcompression; /* Compressionlevel, 0 = no compression */ diff --cc src/protocol_auth.c index 85272301,06735dcf..cf6b26f2 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@@ -400,8 -501,9 +405,9 @@@ bool ack_h(connection_t *c, char *reque int weight, mtu; uint32_t options; node_t *n; + bool choice; - if(sscanf(c->buffer, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) { + if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &weight, &options) != 3) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name, c->hostname); return false; diff --cc src/protocol_key.c index 3b022679,67f40af4..069cfd5f --- a/src/protocol_key.c +++ b/src/protocol_key.c @@@ -32,20 -34,24 +32,24 @@@ #include "utils.h" #include "xalloc.h" -bool mykeyused = false; +static bool mykeyused = false; - bool send_key_changed() { - /* Only send this message if some other daemon requested our key previously. - This reduces unnecessary key_changed broadcasts. - */ + void send_key_changed() { + avl_node_t *node; + connection_t *c; - if(!mykeyused) - return true; + send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name); + + /* Immediately send new keys to directly connected nodes to keep UDP mappings alive */ - return send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name); + for(node = connection_tree->head; node; node = node->next) { + c = node->data; + if(c->status.active && c->node && c->node->status.reachable) + send_ans_key(c->node); + } } -bool key_changed_h(connection_t *c) { +bool key_changed_h(connection_t *c, char *request) { char name[MAX_STRING_SIZE]; node_t *n; @@@ -161,12 -183,14 +170,14 @@@ bool ans_key_h(connection_t *c, char *r char from_name[MAX_STRING_SIZE]; char to_name[MAX_STRING_SIZE]; char key[MAX_STRING_SIZE]; - char address[MAX_STRING_SIZE] = ""; - char port[MAX_STRING_SIZE] = ""; - int cipher, digest, maclength, compression; ++ char address[MAX_STRING_SIZE] = ""; ++ char port[MAX_STRING_SIZE] = ""; + int cipher, digest, maclength, compression, keylen; node_t *from, *to; - if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING, + if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d", from_name, to_name, key, &cipher, &digest, &maclength, - &compression) != 7) { + &compression, address, port) < 7) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name, c->hostname); return false; @@@ -234,16 -296,22 +250,22 @@@ 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 true; - } + /* Update our copy of the origin's packet key */ + + hex2bin(key, key, keylen); + cipher_set_key(&from->outcipher, key, false); + digest_set_key(&from->outdigest, key, keylen); from->status.validkey = true; + from->status.waitingforkey = false; from->sent_seqno = 0; + if(*address && *port) { + ifdebug(PROTOCOL) logger(LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port); + sockaddr_t sa = str2sockaddr(address, port); + update_node_udp(from, &sa); + } + if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes) send_mtu_probe(from); diff --cc src/protocol_subnet.c index ea112b9d,9ae491d0..65ab6e13 --- a/src/protocol_subnet.c +++ b/src/protocol_subnet.c @@@ -228,10 -221,14 +222,15 @@@ bool del_subnet_h(connection_t *c, cha return true; } + if(tunnelserver) + return true; + /* Tell the rest */ - forward_request(c); + if(!tunnelserver) + forward_request(c, request); + if(strictsubnets) + return true; /* Finally, delete it. */ diff --cc src/route.c index 3c0cf5b5,853b7f5b..f18bd268 --- a/src/route.c +++ b/src/route.c @@@ -48,9 -50,8 +50,10 @@@ static const size_t ip6_size = sizeof(s static const size_t icmp6_size = sizeof(struct icmp6_hdr); static const size_t ns_size = sizeof(struct nd_neighbor_solicit); static const size_t opt_size = sizeof(struct nd_opt_hdr); + #define max(a, b) ((a) > (b) ? (a) : (b)) +static struct event age_subnets_event; + /* RFC 1071 */ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { diff --cc src/tincd.c index 9c6009e1,3debb3e4..21623647 --- a/src/tincd.c +++ b/src/tincd.c @@@ -377,8 -547,14 +386,9 @@@ int main(int argc, char **argv) logger(LOG_ERR, "Error initializing LZO compressor!"); return 1; } + #endif #ifdef HAVE_MINGW - if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) { - logger(LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError())); - return 1; - } - if(!do_detach || !init_service()) return main2(argc, argv); else