From: Guus Sliepen Date: Mon, 2 Nov 2009 13:24:27 +0000 (+0100) Subject: Merge branch 'master' into 1.1 X-Git-Tag: release-1.1pre1~109 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=108b238915c5f58b3d94ab433dc5d04e064c2b11;p=oweals%2Ftinc.git Merge branch 'master' into 1.1 Conflicts: NEWS README configure.in doc/tinc.texi doc/tincd.8.in src/Makefile.am src/connection.c src/edge.c src/meta.c src/net.c src/net.h src/net_packet.c src/net_setup.c src/net_socket.c src/node.c src/openssl/rsagen.h src/protocol_auth.c src/protocol_edge.c src/subnet.c --- 108b238915c5f58b3d94ab433dc5d04e064c2b11 diff --cc NEWS index 09b02b8,330efbc..51f11be --- a/NEWS +++ b/NEWS @@@ -1,10 -1,21 +1,27 @@@ +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.10 not yet released + Version 1.0.11 Nov 1 2009 + + * Fixed potential crash when the HUP signal is sent. + + * Fixes handling of weighted Subnets in switch and hub modes, preventing + unnecessary broadcasts. + + * Works around a MinGW bug that caused packets to Windows nodes to always be + sent via TCP. + + * Improvements to the PMTU discovery code, especially on Windows. + + * Use UDP again in certain cases where 1.0.10 was too conservative and fell + back to TCP unnecessarily. + + * Allow fast roaming of hosts to other nodes in a switched VPN. + + Version 1.0.10 Oct 18 2009 * Fixed potential crashes during shutdown and (in rare conditions) when other nodes disconnected from the VPN. diff --cc src/Makefile.am index 3af74ca,491f011..bb78d4d --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -32,12 -30,7 +32,10 @@@ endi tincd_LDADD = \ $(top_builddir)/lib/libvpn.a -AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" +tincctl_LDADD = \ + $(top_builddir)/lib/libvpn.a + - localedir = $(datadir)/locale - - AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" ++AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" dist-hook: rm -f `find . -type l` diff --cc src/meta.c index 787ccbd,4c52464..1bb634f --- a/src/meta.c +++ b/src/meta.c @@@ -89,10 -141,18 +89,17 @@@ bool receive_meta(connection_t *c) - If not, keep stuff in buffer and exit. */ - lenin = recv(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen, 0); + inlen = recv(c->socket, inbuf, sizeof inbuf, 0); - if(lenin <= 0) { - if(!lenin || !errno) { + if(inlen <= 0) { - logger(LOG_ERR, "Receive callback called for %s (%s) but no data to receive: %s", c->name, c->hostname, strerror(errno)); ++ if(!inlen || !errno) { + ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", + c->name, c->hostname); + } else if(sockwouldblock(sockerrno)) + return true; + else + logger(LOG_ERR, "Metadata socket read error for %s (%s): %s", + c->name, c->hostname, sockstrerror(sockerrno)); - return false; } @@@ -150,9 -189,39 +157,7 @@@ break; } } - - /* Otherwise we are waiting for a request */ - - reqlen = 0; - - for(i = oldlen; i < c->buflen; i++) { - if(c->buffer[i] == '\n') { - c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */ - reqlen = i + 1; - break; - } - } - - if(reqlen) { - c->reqlen = reqlen; - if(!receive_request(c)) - return false; - - c->buflen -= reqlen; - lenin -= reqlen - oldlen; - memmove(c->buffer, c->buffer + reqlen, c->buflen); - oldlen = 0; - continue; - } else { - break; - } - } - - if(c->buflen >= MAXBUFSIZE) { - logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)", - c->name, c->hostname); - return false; - } + } while(inlen); - c->last_ping_time = time(NULL); - return true; } diff --cc src/net.c index 1c267f6,3f17083..9445b68 --- a/src/net.c +++ b/src/net.c @@@ -188,30 -254,73 +188,30 @@@ static void timeout_handler(int fd, sho } } } - - if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout < now) { - if(c->status.active) { - ifdebug(CONNECTIONS) logger(LOG_INFO, - "%s (%s) could not flush for %ld seconds (%d bytes remaining)", - c->name, c->hostname, now - c->last_flushed_time, c->outbuflen); - c->status.timeout = true; - terminate_connection(c, true); - } - } } -} - -/* - check all connections to see if anything - happened on their sockets -*/ -static void check_network_activity(fd_set * readset, fd_set * writeset) { - connection_t *c; - avl_node_t *node; - int result, i; - socklen_t len = sizeof(result); - vpn_packet_t packet; - - /* check input from kernel */ - if(device_fd >= 0 && FD_ISSET(device_fd, readset)) { - if(read_packet(&packet)) { - packet.priority = 0; - route(myself, &packet); - } - } - - /* check meta connections */ - for(node = connection_tree->head; node; node = node->next) { - c = node->data; - - if(c->status.remove) - continue; - - if(FD_ISSET(c->socket, readset)) { - if(c->status.connecting) { - c->status.connecting = false; - getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len); - - if(!result) - finish_connecting(c); - else { - ifdebug(CONNECTIONS) logger(LOG_DEBUG, - "Error while connecting to %s (%s): %s", - c->name, c->hostname, sockstrerror(result)); - closesocket(c->socket); - do_outgoing_connection(c); - continue; - } - } - if(!receive_meta(c)) { - terminate_connection(c, c->status.active); - continue; - } - } + event_add(event, &(struct timeval){pingtimeout, 0}); +} - if(FD_ISSET(c->socket, writeset)) { - if(!flush_meta(c)) { - terminate_connection(c, c->status.active); - continue; - } +void handle_meta_connection_data(int fd, short events, void *data) { + connection_t *c = data; + int result; + socklen_t len = sizeof result; + + if(c->status.connecting) { + c->status.connecting = false; + + getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len); + + if(!result) + finish_connecting(c); + else { + ifdebug(CONNECTIONS) logger(LOG_DEBUG, + "Error while connecting to %s (%s): %s", - c->name, c->hostname, strerror(result)); ++ c->name, c->hostname, sockstrerror(result)); + closesocket(c->socket); + do_outgoing_connection(c); + return; } } diff --cc src/net_packet.c index e430b6c,e501153..aaa0c72 --- a/src/net_packet.c +++ b/src/net_packet.c @@@ -54,15 -54,22 +50,22 @@@ static void send_udppacket(node_t *, vp #define MAX_SEQNO 1073741824 + // mtuprobes == 1..30: initial discovery, send bursts with 1 second interval + // mtuprobes == 31: sleep pinginterval seconds + // mtuprobes == 32: send 1 burst, sleep pingtimeout second + // mtuprobes == 33: no response from other side, restart PMTU discovery process + -void send_mtu_probe(node_t *n) { +static void send_mtu_probe_handler(int fd, short events, void *data) { + node_t *n = data; vpn_packet_t packet; int len, i; + int timeout = 1; n->mtuprobes++; - n->mtuevent = NULL; - if(!n->status.reachable) { - logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname); + if(!n->status.reachable || !n->status.validkey) { + ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname); + n->mtuprobes = 0; return; } @@@ -92,13 -122,12 +118,14 @@@ send_udppacket(n, &packet); } - event_add(&n->mtuevent, &(struct timeval){1, 0}); + end: - n->mtuevent = new_event(); - n->mtuevent->handler = (event_handler_t)send_mtu_probe; - n->mtuevent->data = n; - n->mtuevent->time = now + timeout; - event_add(n->mtuevent); ++ event_add(&n->mtuevent, &(struct timeval){timeout, 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, length_t len) { @@@ -466,9 -521,10 +500,11 @@@ 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; + static time_t last_hard_try = 0; ++ time_t now = time(NULL); for(node = edge_weight_tree->head; node; node = node->next) { e = node->data; diff --cc src/net_setup.c index 44c8d8d,cbf631f..de2d0fe --- a/src/net_setup.c +++ b/src/net_setup.c @@@ -292,36 -339,65 +292,36 @@@ 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(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) - cipher = xstrdup("aes256"); ++ cipher = xstrdup("blowfish"); - if(myself->incipher) - myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len; - else - myself->inkeylength = 1; - - 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("sha256"); ++ digest = xstrdup("sha1"); - 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; + int maclength = 4; + get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &maclength); + + if(maclength < 0) { + logger(LOG_ERR, "Bogus MAC length!"); + return false; + } - myself->connection->outmaclength = 0; + if(!digest_open_by_name(&myself->indigest, digest, maclength)) { + logger(LOG_ERR, "Unrecognized digest type!"); + return false; + } /* Compression */ diff --cc src/net_socket.c index be44a1c,46e0532..d05dfd5 --- a/src/net_socket.c +++ b/src/net_socket.c @@@ -197,13 -193,13 +192,13 @@@ int setup_listen_socket(const sockaddr_ #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); + memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); - if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) { + if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr)) { closesocket(nfd); logger(LOG_ERR, "Can't bind to interface %s: %s", iface, - strerror(errno)); + strerror(sockerrno)); return -1; } #else @@@ -446,6 -427,8 +441,8 @@@ void setup_outgoing_connection(outgoing connection_t *c; node_t *n; - outgoing->event = NULL; ++ event_del(&outgoing->ev); + n = lookup_node(outgoing->name); if(n) @@@ -504,8 -478,8 +501,8 @@@ void handle_new_meta_connection(int soc fd = accept(sock, &sa.sa, &len); if(fd < 0) { - logger(LOG_ERR, "Accepting a new connection failed: %s", strerror(errno)); + logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno)); - return false; + return; } sockaddrunmap(&sa); diff --cc src/protocol_auth.c index c783189,c2df4cd..a38b9ad --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@@ -387,10 -494,10 +387,10 @@@ bool ack_h(connection_t *c, char *reque char hisport[MAX_STRING_SIZE]; char *hisaddress, *dummy; int weight, mtu; - long int options; + uint32_t options; node_t *n; - if(sscanf(request, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) { - 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_edge.c index df7e9c2,300333b..4aad53f --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@@ -58,10 -58,10 +58,10 @@@ bool add_edge_h(connection_t *c, char * char to_address[MAX_STRING_SIZE]; char to_port[MAX_STRING_SIZE]; sockaddr_t address; - long int options; + uint32_t options; int weight; - if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d", - if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d", ++ if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %x %d", from_name, to_name, to_address, to_port, &options, &weight) != 6) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, c->hostname); diff --cc src/protocol_subnet.c index 6ec5054,ba75c89..ea112b9 --- a/src/protocol_subnet.c +++ b/src/protocol_subnet.c @@@ -45,9 -45,9 +45,9 @@@ bool add_subnet_h(connection_t *c, cha char subnetstr[MAX_STRING_SIZE]; char name[MAX_STRING_SIZE]; node_t *owner; - subnet_t s = {0}, *new; + subnet_t s = {0}, *new, *old; - if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { + if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name, c->hostname); return false; @@@ -140,8 -140,13 +140,13 @@@ /* Tell the rest */ if(!tunnelserver) - forward_request(c); + forward_request(c, request); + /* Fast handoff of roaming MAC addresses */ + + if(s.type == SUBNET_MAC && owner != myself && (old = lookup_subnet(myself, &s)) && old->expires) - old->expires = now; ++ old->expires = 1; + return true; } diff --cc src/route.c index 600c53d,5c69671..758801b --- a/src/route.c +++ b/src/route.c @@@ -152,8 -115,9 +152,9 @@@ static void learn_mac(mac_t *address) subnet = new_subnet(); subnet->type = SUBNET_MAC; - subnet->expires = now + macexpire; + subnet->expires = time(NULL) + macexpire; subnet->net.mac.address = *address; + subnet->weight = 10; subnet_add(myself, subnet); /* And tell all other tinc daemons it's our MAC */ diff --cc src/subnet.c index 1cb8163,3d1168d..29ea96d --- a/src/subnet.c +++ b/src/subnet.c @@@ -324,7 -330,20 +330,20 @@@ subnet_t *lookup_subnet(const node_t *o } subnet_t *lookup_subnet_mac(const mac_t *address) { - subnet_t *p, subnet = {0}; + subnet_t *p, *r = NULL, subnet = {0}; - avl_node_t *n; ++ splay_node_t *n; + int i; + + // Check if this address is cached + + for(i = 0; i < 2; i++) { + if(!cache_mac_valid[i]) + continue; + if(!memcmp(address, &cache_mac_address[i], sizeof *address)) + return cache_mac_subnet[i]; + } + + // Search all subnets for a matching one subnet.type = SUBNET_MAC; subnet.net.mac.address = *address;