From: Guus Sliepen Date: Tue, 29 Sep 2009 12:55:29 +0000 (+0200) Subject: Merge branch 'master' into 1.1 X-Git-Tag: import-tinc-1.1~587 X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=7ea85043ac1fb2096baea44f6b0af27ac0d0b2cf;p=meshlink Merge branch 'master' into 1.1 Conflicts: NEWS configure.in lib/Makefile.am lib/pidfile.c lib/pidfile.h lib/utils.c po/POTFILES.in po/nl.po src/Makefile.am src/bsd/device.c src/conf.c src/connection.c src/cygwin/device.c src/edge.c src/event.c src/graph.c src/linux/device.c src/meta.c src/mingw/device.c src/net.c src/net_packet.c src/net_setup.c src/net_socket.c src/netutl.c src/node.c src/process.c src/protocol.c src/protocol_auth.c src/protocol_edge.c src/protocol_key.c src/protocol_misc.c src/protocol_subnet.c src/raw_socket/device.c src/route.c src/solaris/device.c src/subnet.c src/tincd.c src/uml_socket/device.c --- 7ea85043ac1fb2096baea44f6b0af27ac0d0b2cf diff --cc NEWS index a993df5c,da10928c..09b02b8e --- a/NEWS +++ b/NEWS @@@ -1,9 -1,36 +1,42 @@@ +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 + + * Fixed potential crashes during shutdown and (in rare conditions) when other + nodes disconnected from the VPN. + + * Improved NAT handling: tinc now copes with mangled port numbers, and will + automatically fall back to TCP if direct UDP connection between nodes is not + possible. + + * Allow configuration files with CRLF line endings to be read on UNIX. + + * Disable old RSA keys when generating new ones. + + * Many fixes in the path MTU discovery code. + + * Tinc can now drop privileges and/or chroot itself. + + * The TunnelServer code now just ignores information from clients instead of + disconnecting them. + + * Improved performance on Windows by using the new ProcessPriority option and + by making the handling of packets received from the TAP-Win32 adapter more + efficient. + + * Code cleanups: tinc now follows the C99 standard, copyright headers have + been updated to include patch authors, checkpoint tracing and localisation + features have been removed. + + * Support for (jailbroken) iPhone and iPod Touch has been added. + + Thanks to Florian Forster, Grzegorz Dymarek and especially Michael Tokarev for + their contributions to this version of tinc. + Version 1.0.9 Dec 26 2008 * Fixed tinc as a service under Windows 2003. diff --cc configure.in index 2dba9bed,01f56ebf..1db53d1c --- a/configure.in +++ b/configure.in @@@ -1,12 -1,9 +1,10 @@@ dnl Process this file with autoconf to produce a configure script. - dnl $Id$ - - AC_PREREQ(2.59) + AC_PREREQ(2.61) AC_INIT AC_CONFIG_SRCDIR([src/tincd.c]) -AM_INIT_AUTOMAKE(tinc, 1.0-cvs) +AC_GNU_SOURCE +AM_INIT_AUTOMAKE(tinc, 1.1-cvs) AC_CONFIG_HEADERS([config.h]) AM_MAINTAINER_MODE diff --cc lib/Makefile.am index 5dfeda5f,734bb640..c96e1760 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@@ -10,6 -9,6 +9,6 @@@ libvpn_a_SOURCES = xmalloc.c utils.c ge libvpn_a_LIBADD = @LIBOBJS@ @ALLOCA@ libvpn_a_DEPENDENCIES = $(libvpn_a_LIBADD) - noinst_HEADERS = xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h gettext.h ipv6.h ipv4.h ethernet.h -noinst_HEADERS = xalloc.h pidfile.h utils.h getopt.h list.h avl_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h ++noinst_HEADERS = xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h EXTRA_DIST = diff --cc src/Makefile.am index db90897f,bdd1a3f8..3af74ca1 --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -1,7 -1,6 +1,6 @@@ ## Produce this file with automake to get Makefile.in - # $Id: Makefile.am,v 1.4.4.33 2003/08/02 15:13:08 guus Exp $ -sbin_PROGRAMS = tincd +sbin_PROGRAMS = tincd tincctl EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h raw_socket/device.c uml_socket/device.c @@@ -21,10 -18,10 +20,10 @@@ DEFAULT_INCLUDES INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib -noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h logger.h meta.h net.h netutl.h node.h process.h \ - protocol.h route.h subnet.h bsd/tunemu.h +noinst_HEADERS = cipher.h conf.h connection.h control.h crypto.h device.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h \ + protocol.h route.h rsa.h rsagen.h subnet.h bsd/tunemu.h - LIBS = @LIBS@ @LIBGCRYPT_LIBS@ @LIBINTL@ -LIBS = @LIBS@ ++LIBS = @LIBS@ @LIBGCRYPT_LIBS@ if TUNEMU LIBS += -lpcap diff --cc src/bsd/device.c index 872ad92f,ee9b0e53..1ffc960a --- a/src/bsd/device.c +++ b/src/bsd/device.c @@@ -184,23 -179,21 +179,21 @@@ void close_device(void) } bool read_packet(vpn_packet_t *packet) { - int lenin; + int inlen; - cp(); - switch(device_type) { case DEVICE_TYPE_TUN: #ifdef HAVE_TUNEMU case DEVICE_TYPE_TUNEMU: if(device_type == DEVICE_TYPE_TUNEMU) - lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14); + inlen = tunemu_read(device_fd, packet->data + 14, MTU - 14); else #else - lenin = read(device_fd, packet->data + 14, MTU - 14); + inlen = read(device_fd, packet->data + 14, MTU - 14); #endif - if(lenin <= 0) { + if(inlen <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } @@@ -226,10 -219,10 +219,10 @@@ case DEVICE_TYPE_TUNIFHEAD: { u_int32_t type; - struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}}; + struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}}; - if((lenin = readv(device_fd, vector, 2)) <= 0) { + if((inlen = readv(device_fd, vector, 2)) <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } @@@ -257,8 -250,8 +250,8 @@@ } case DEVICE_TYPE_TAP: - if((lenin = read(device_fd, packet->data, MTU)) <= 0) { + if((inlen = read(device_fd, packet->data, MTU)) <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } diff --cc src/conf.c index 827da681,e67c7ac1..b1a6f0b1 --- a/src/conf.c +++ b/src/conf.c @@@ -54,16 -52,12 +52,12 @@@ static int config_compare(const config_ return strcmp(a->file, b->file); } -void init_configuration(avl_tree_t ** config_tree) { - *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config); +void init_configuration(splay_tree_t ** config_tree) { - cp(); - + *config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config); } -void exit_configuration(avl_tree_t ** config_tree) { - avl_delete_tree(*config_tree); +void exit_configuration(splay_tree_t ** config_tree) { - cp(); - + splay_delete_tree(*config_tree); *config_tree = NULL; } @@@ -88,17 -78,13 +78,13 @@@ void free_config(config_t *cfg) free(cfg); } -void config_add(avl_tree_t *config_tree, config_t *cfg) { - avl_insert(config_tree, cfg); +void config_add(splay_tree_t *config_tree, config_t *cfg) { - cp(); - + splay_insert(config_tree, cfg); } -config_t *lookup_config(avl_tree_t *config_tree, char *variable) { +config_t *lookup_config(splay_tree_t *config_tree, char *variable) { config_t cfg, *found; - cp(); - cfg.variable = variable; cfg.file = ""; cfg.line = 0; @@@ -114,13 -100,11 +100,11 @@@ return found; } -config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg) { - avl_node_t *node; +config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *cfg) { + splay_node_t *node; config_t *found; - cp(); - - node = avl_search_node(config_tree, cfg); + node = splay_search_node(config_tree, cfg); if(node) { if(node->next) { @@@ -218,10 -192,10 +192,10 @@@ bool get_config_subnet(const config_t * /* Teach newbies what subnets are... */ if(((subnet.type == SUBNET_IPV4) - && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t))) + && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address)) || ((subnet.type == SUBNET_IPV6) - && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) { + && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) { - logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"), + logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d", cfg->variable, cfg->file, cfg->line); return false; } diff --cc src/connection.c index 4a2ba4c0,6e942f8e..ce4c7536 --- a/src/connection.c +++ b/src/connection.c @@@ -41,33 -39,31 +40,25 @@@ static int connection_compare(const con } void init_connections(void) { - cp(); - - connection_tree = avl_alloc_tree((avl_compare_t) connection_compare, (avl_action_t) free_connection); + connection_tree = splay_alloc_tree((splay_compare_t) connection_compare, (splay_action_t) free_connection); broadcast = new_connection(); - broadcast->name = xstrdup(_("everyone")); - broadcast->hostname = xstrdup(_("BROADCAST")); + broadcast->name = xstrdup("everyone"); + broadcast->hostname = xstrdup("BROADCAST"); } void exit_connections(void) { - cp(); - - avl_delete_tree(connection_tree); + splay_delete_tree(connection_tree); free_connection(broadcast); } connection_t *new_connection(void) { - cp(); - connection_t *c; - - c = xmalloc_and_zero(sizeof(connection_t)); - - if(!c) - return NULL; - - gettimeofday(&c->start, NULL); -- - return c; + return xmalloc_and_zero(sizeof(connection_t)); } void free_connection(connection_t *c) { - cp(); - + if(!c) + return; + if(c->name) free(c->name); @@@ -93,33 -105,27 +84,27 @@@ } void connection_add(connection_t *c) { - cp(); - - avl_insert(connection_tree, c); + splay_insert(connection_tree, c); } void connection_del(connection_t *c) { - cp(); - - avl_delete(connection_tree, c); + splay_delete(connection_tree, c); } -void dump_connections(void) { - avl_node_t *node; +int dump_connections(struct evbuffer *out) { + splay_node_t *node; connection_t *c; - cp(); - logger(LOG_DEBUG, "Connections:"); -- for(node = connection_tree->head; node; node = node->next) { c = node->data; - logger(LOG_DEBUG, " %s at %s options %lx socket %d status %04x outbuf %d/%d/%d", - c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof c->status), - c->outbufsize, c->outbufstart, c->outbuflen); + if(evbuffer_add_printf(out, - _(" %s at %s options %lx socket %d status %04x\n"), ++ " %s at %s options %lx socket %d status %04x\n", + c->name, c->hostname, c->options, c->socket, + bitfield_to_int(&c->status, sizeof c->status)) == -1) + return errno; } - logger(LOG_DEBUG, "End of connections."); + return 0; } bool read_connection_config(connection_t *c) { diff --cc src/cygwin/device.c index 97b2a38d,958184bd..00580764 --- a/src/cygwin/device.c +++ b/src/cygwin/device.c @@@ -153,8 -149,8 +149,8 @@@ bool setup_device(void) /* Get MAC address from tap device */ - if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) { + if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) { - logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError())); + logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError())); return false; } @@@ -231,12 -225,10 +225,10 @@@ void close_device(void) } bool read_packet(vpn_packet_t *packet) { - int lenin; + int inlen; - cp(); - - if((lenin = read(sp[0], packet->data, MTU)) <= 0) { + if((inlen = read(sp[0], packet->data, MTU)) <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } @@@ -252,15 -244,13 +244,13 @@@ } bool write_packet(vpn_packet_t *packet) { - long lenout; + long outlen; - cp(); - - ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"), + ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", packet->len, device_info); - if(!WriteFile (device_handle, packet->data, packet->len, &lenout, NULL)) { + if(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) { - logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError())); + logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError())); return false; } diff --cc src/edge.c index 3b584f39,9e1b31eb..4d674f38 --- a/src/edge.c +++ b/src/edge.c @@@ -53,27 -51,19 +51,19 @@@ static int edge_weight_compare(const ed } void init_edges(void) { - cp(); - - edge_weight_tree = avl_alloc_tree((avl_compare_t) edge_weight_compare, NULL); + edge_weight_tree = splay_alloc_tree((splay_compare_t) edge_weight_compare, NULL); } -avl_tree_t *new_edge_tree(void) { - return avl_alloc_tree((avl_compare_t) edge_compare, (avl_action_t) free_edge); +splay_tree_t *new_edge_tree(void) { - cp(); - + return splay_alloc_tree((splay_compare_t) edge_compare, (splay_action_t) free_edge); } -void free_edge_tree(avl_tree_t *edge_tree) { - avl_delete_tree(edge_tree); +void free_edge_tree(splay_tree_t *edge_tree) { - cp(); - + splay_delete_tree(edge_tree); } void exit_edges(void) { - cp(); - - avl_delete_tree(edge_weight_tree); + splay_delete_tree(edge_weight_tree); } /* Creation and deletion of connection elements */ @@@ -93,10 -79,8 +79,8 @@@ void free_edge(edge_t *e) } void edge_add(edge_t *e) { - cp(); - - avl_insert(edge_weight_tree, e); - avl_insert(e->from->edge_tree, e); + splay_insert(edge_weight_tree, e); + splay_insert(e->from->edge_tree, e); e->reverse = lookup_edge(e->to, e->from); @@@ -131,20 -111,15 +111,18 @@@ int dump_edges(struct evbuffer *out) edge_t *e; char *address; - cp(); - logger(LOG_DEBUG, "Edges:"); -- for(node = node_tree->head; node; node = node->next) { n = node->data; for(node2 = n->edge_tree->head; node2; node2 = node2->next) { e = node2->data; address = sockaddr2hostname(&e->address); - logger(LOG_DEBUG, " %s to %s at %s options %lx weight %d", - e->from->name, e->to->name, address, e->options, e->weight); + if(evbuffer_add_printf(out, - _(" %s to %s at %s options %lx weight %d\n"), ++ " %s to %s at %s options %lx weight %d\n", + e->from->name, e->to->name, address, + e->options, e->weight) == -1) { + free(address); + return errno; + } free(address); } } diff --cc src/graph.c index f2e546ee,148f23c4..5a0aab0b --- a/src/graph.c +++ b/src/graph.c @@@ -69,9 -69,10 +67,7 @@@ void mst_kruskal(void) edge_t *e; node_t *n; connection_t *c; - int nodes = 0; - int safe_edges = 0; - bool skipped; - cp(); - /* Clear MST status on connections */ for(node = connection_tree->head; node; node = node->next) { @@@ -106,131 -125,15 +102,129 @@@ if(e->reverse->connection) e->reverse->connection->status.mst = true; - safe_edges++; - ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name, e->to->name, e->weight); + } +} - if(skipped) { - skipped = false; - next = edge_weight_tree->head; - continue; +/* Implementation of Dijkstra's algorithm. + Running time: O(N^2) +*/ + +void sssp_dijkstra(void) { + splay_node_t *node, *to; + edge_t *e; + node_t *n, *m; + list_t *todo_list; + list_node_t *lnode, *nnode; + bool indirect; + - cp(); - + todo_list = list_alloc(NULL); + + ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Dijkstra's algorithm:"); + + /* Clear visited status on nodes */ + + for(node = node_tree->head; node; node = node->next) { + n = node->data; + n->status.visited = false; + n->status.indirect = true; + n->distance = -1; + } + + /* Begin with myself */ + + myself->status.indirect = false; + myself->nexthop = myself; + myself->via = myself; + myself->distance = 0; + list_insert_head(todo_list, myself); + + /* Loop while todo_list is filled */ + + while(todo_list->head) { + n = NULL; + nnode = NULL; + + /* Select node from todo_list with smallest distance */ + + for(lnode = todo_list->head; lnode; lnode = lnode->next) { + m = lnode->data; + if(!n || m->status.indirect < n->status.indirect || m->distance < n->distance) { + n = m; + nnode = lnode; + } + } + + /* Mark this node as visited and remove it from the todo_list */ + + n->status.visited = true; + list_unlink_node(todo_list, nnode); + + /* Update distance of neighbours and add them to the todo_list */ + + for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */ + e = to->data; + + if(e->to->status.visited || !e->reverse) + continue; + + /* Situation: + + / + / + ----->(n)---e-->(e->to) + \ + \ + + Where e is an edge, (n) and (e->to) are nodes. + n->address is set to the e->address of the edge left of n to n. + We are currently examining the edge e right of n from n: + + - If e->reverse->address != n->address, then e->to is probably + not reachable for the nodes left of n. We do as if the indirectdata + flag is set on edge e. + - If edge e provides for better reachability of e->to, update e->to. + */ + + if(e->to->distance < 0) + list_insert_tail(todo_list, e->to); + + indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &e->reverse->address)); + + if(e->to->distance >= 0 && (!e->to->status.indirect || indirect) && e->to->distance <= n->distance + e->weight) + continue; + + e->to->distance = n->distance + e->weight; + e->to->status.indirect = indirect; + e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop; + e->to->via = indirect ? n->via : e->to; + e->to->options = e->options; + + if(sockaddrcmp(&e->to->address, &e->address)) { + node = splay_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) + splay_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); + } + } + + ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Updating edge %s - %s weight %d distance %d", e->from->name, + e->to->name, e->weight, e->to->distance); } } @@@ -248,9 -152,11 +242,7 @@@ void sssp_bfs(void) list_t *todo_list; list_node_t *from, *todonext; bool indirect; - char *name; - char *address, *port; - char *envp[7]; - int i; - cp(); - todo_list = list_alloc(NULL); /* Clear visited status on nodes */ diff --cc src/linux/device.c index e692ca9f,35c66d55..72becd77 --- a/src/linux/device.c +++ b/src/linux/device.c @@@ -127,38 -121,36 +121,36 @@@ void close_device(void) } bool read_packet(vpn_packet_t *packet) { - int lenin; + int inlen; - cp(); - switch(device_type) { case DEVICE_TYPE_TUN: - lenin = read(device_fd, packet->data + 10, MTU - 10); + inlen = read(device_fd, packet->data + 10, MTU - 10); - if(lenin <= 0) { + if(inlen <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } - packet->len = lenin + 10; + packet->len = inlen + 10; break; case DEVICE_TYPE_TAP: - lenin = read(device_fd, packet->data, MTU); + inlen = read(device_fd, packet->data, MTU); - if(lenin <= 0) { + if(inlen <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } - packet->len = lenin; + packet->len = inlen; break; case DEVICE_TYPE_ETHERTAP: - lenin = read(device_fd, packet->data - 2, MTU + 2); + inlen = read(device_fd, packet->data - 2, MTU + 2); - if(lenin <= 0) { + if(inlen <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } diff --cc src/meta.c index 6054427c,765baeca..787ccbd0 --- a/src/meta.c +++ b/src/meta.c @@@ -33,45 -34,92 +32,41 @@@ #include "xalloc.h" bool send_meta(connection_t *c, const char *buffer, int length) { - cp(); - int outlen; - int result; -- if(!c) { - logger(LOG_ERR, _("send_meta() called with NULL pointer!")); + logger(LOG_ERR, "send_meta() called with NULL pointer!"); abort(); } - ifdebug(META) logger(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length, + ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length, c->name, c->hostname); - if(!c->outbuflen) - c->last_flushed_time = now; - - /* Find room in connection's buffer */ - if(length + c->outbuflen > c->outbufsize) { - c->outbufsize = length + c->outbuflen; - c->outbuf = xrealloc(c->outbuf, c->outbufsize); - } - - if(length + c->outbuflen + c->outbufstart > c->outbufsize) { - memmove(c->outbuf, c->outbuf + c->outbufstart, c->outbuflen); - c->outbufstart = 0; - } - /* Add our data to buffer */ if(c->status.encryptout) { - result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen, - &outlen, (unsigned char *)buffer, length); - if(!result || outlen < length) { - logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); - return false; - } else if(outlen > length) { - logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!"); - abort(); - } - c->outbuflen += outlen; - } else { - memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length); - c->outbuflen += length; - } - - return true; -} - -bool flush_meta(connection_t *c) { - int result; - - ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)", - c->outbuflen, c->name, c->hostname); - - while(c->outbuflen) { - result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0); - if(result <= 0) { - if(!errno || errno == EPIPE) { - ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", - c->name, c->hostname); - } else if(errno == EINTR) { - continue; -#ifdef EWOULDBLOCK - } else if(errno == EWOULDBLOCK) { - ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block", - c->outbuflen, c->name, c->hostname); - return true; -#endif - } else { - logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name, - c->hostname, strerror(errno)); - } + char outbuf[length]; + size_t outlen = length; + if(!cipher_encrypt(&c->outcipher, buffer, length, outbuf, &outlen, false) || outlen != length) { - logger(LOG_ERR, _("Error while encrypting metadata to %s (%s)"), ++ logger(LOG_ERR, "Error while encrypting metadata to %s (%s)", + c->name, c->hostname); return false; } - - c->outbufstart += result; - c->outbuflen -= result; + - ifdebug(META) logger(LOG_DEBUG, _("Encrypted write %p %p %p %d"), c, c->buffer, outbuf, length); ++ ifdebug(META) logger(LOG_DEBUG, "Encrypted write %p %p %p %d", c, c->buffer, outbuf, length); + bufferevent_write(c->buffer, (void *)outbuf, length); - ifdebug(META) logger(LOG_DEBUG, _("Done.")); ++ ifdebug(META) logger(LOG_DEBUG, "Done."); + } else { - ifdebug(META) logger(LOG_DEBUG, _("Unencrypted write %p %p %p %d"), c, c->buffer, buffer, length); ++ ifdebug(META) logger(LOG_DEBUG, "Unencrypted write %p %p %p %d", c, c->buffer, buffer, length); + bufferevent_write(c->buffer, (void *)buffer, length); - ifdebug(META) logger(LOG_DEBUG, _("Done.")); ++ ifdebug(META) logger(LOG_DEBUG, "Done."); } - c->outbufstart = 0; /* avoid unnecessary memmoves */ return true; } void broadcast_meta(connection_t *from, const char *buffer, int length) { - avl_node_t *node; + splay_node_t *node; connection_t *c; - cp(); - for(node = connection_tree->head; node; node = node->next) { c = node->data; @@@ -81,12 -129,11 +76,10 @@@ } bool receive_meta(connection_t *c) { - int oldlen, i, result; - int lenin, lenout, reqlen; - bool decrypted = false; + size_t inlen; char inbuf[MAXBUFSIZE]; + char *bufp = inbuf, *endp; - cp(); - /* Strategy: - Read as much as possible from the TCP socket in one go. - Decrypt it. @@@ -96,62 -143,49 +89,62 @@@ - If not, keep stuff in buffer and exit. */ - lenin = recv(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen, 0); - - if(lenin <= 0) { - if(!lenin || !errno) { - ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)", - c->name, c->hostname); - } else if(errno == EINTR) - return true; - else - logger(LOG_ERR, "Metadata socket read error for %s (%s): %s", - c->name, c->hostname, strerror(errno)); + inlen = recv(c->socket, inbuf, sizeof inbuf, 0); + if(inlen <= 0) { - logger(LOG_ERR, _("Receive callback called for %s (%s) but no data to receive: %s"), c->name, c->hostname, strerror(errno)); ++ logger(LOG_ERR, "Receive callback called for %s (%s) but no data to receive: %s", c->name, c->hostname, strerror(errno)); return false; } - oldlen = c->buflen; - c->buflen += lenin; + do { + if(!c->status.decryptin) { + endp = memchr(bufp, '\n', inlen); + if(endp) + endp++; + else + endp = bufp + inlen; - while(lenin > 0) { - /* Decrypt */ + evbuffer_add(c->buffer->input, bufp, endp - bufp); - if(c->status.decryptin && !decrypted) { - result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin); - if(!result || lenout != lenin) { - logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + inlen -= endp - bufp; + bufp = endp; + } else { + size_t outlen = inlen; - ifdebug(META) logger(LOG_DEBUG, _("Received encrypted %zu bytes"), inlen); ++ ifdebug(META) logger(LOG_DEBUG, "Received encrypted %zu bytes", inlen); + evbuffer_expand(c->buffer->input, c->buffer->input->off + inlen); + + if(!cipher_decrypt(&c->incipher, bufp, inlen, c->buffer->input->buffer + c->buffer->input->off, &outlen, false) || inlen != outlen) { - logger(LOG_ERR, _("Error while decrypting metadata from %s (%s)"), ++ logger(LOG_ERR, "Error while decrypting metadata from %s (%s)", + c->name, c->hostname); return false; } - memcpy(c->buffer + oldlen, inbuf, lenin); - decrypted = true; + c->buffer->input->off += inlen; + + inlen = 0; } - /* Are we receiving a TCPpacket? */ + while(c->buffer->input->off) { + /* Are we receiving a TCPpacket? */ + + if(c->tcplen) { + if(c->tcplen <= c->buffer->input->off) { + receive_tcppacket(c, (char *)c->buffer->input->buffer, c->tcplen); + evbuffer_drain(c->buffer->input, c->tcplen); + c->tcplen = 0; + continue; + } else { + break; + } + } - if(c->tcplen) { - if(c->tcplen <= c->buflen) { - receive_tcppacket(c, c->buffer, c->tcplen); + /* Otherwise we are waiting for a request */ - c->buflen -= c->tcplen; - lenin -= c->tcplen - oldlen; - memmove(c->buffer, c->buffer + c->tcplen, c->buflen); - oldlen = 0; - c->tcplen = 0; + char *request = evbuffer_readline(c->buffer->input); + if(request) { + bool result = receive_request(c, request); + free(request); + if(!result) + return false; continue; } else { break; diff --cc src/mingw/device.c index 2334af39,c0f5d296..b67d0d34 --- a/src/mingw/device.c +++ b/src/mingw/device.c @@@ -191,8 -187,8 +187,8 @@@ bool setup_device(void) /* Get MAC address from tap device */ - if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) { + if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) { - logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError())); + logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError())); return false; } @@@ -212,11 -208,11 +208,11 @@@ /* Set media status for newer TAP-Win32 devices */ status = true; - DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL); + DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL); - device_info = _("Windows tap device"); + device_info = "Windows tap device"; - logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info); + logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info); return true; } @@@ -235,16 -229,14 +229,14 @@@ bool read_packet(vpn_packet_t *packet) } bool write_packet(vpn_packet_t *packet) { - long lenout; + long outlen; OVERLAPPED overlapped = {0}; - cp(); - - ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"), + ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", packet->len, device_info); - if(!WriteFile(device_handle, packet->data, packet->len, &lenout, &overlapped)) { + if(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) { - logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError())); + logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError())); return false; } diff --cc src/net.c index cb6ed499,31970366..1c267f64 --- a/src/net.c +++ b/src/net.c @@@ -108,11 -158,13 +105,9 @@@ void purge(void) - Deactivate the host */ void terminate_connection(connection_t *c, bool report) { - cp(); - if(c->status.remove) - return; -- - ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Closing connection with %s (%s)"), + ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)", c->name, c->hostname); - c->status.remove = true; c->status.active = false; if(c->node) @@@ -160,13 -218,10 +155,11 @@@ end does not reply in time, we consider them dead and close the connection. */ -static void check_dead_connections(void) { - avl_node_t *node, *next; +static void timeout_handler(int fd, short events, void *event) { + splay_node_t *node, *next; connection_t *c; + time_t now = time(NULL); - cp(); - for(node = connection_tree->head; node; node = next) { next = node->next; c = node->data; @@@ -174,51 -229,98 +167,51 @@@ if(c->last_ping_time + pingtimeout < now) { if(c->status.active) { if(c->status.pinged) { - ifdebug(CONNECTIONS) logger(LOG_INFO, _("%s (%s) didn't respond to PING in %ld seconds"), + ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, now - c->last_ping_time); - c->status.timeout = true; terminate_connection(c, true); + continue; } else if(c->last_ping_time + pinginterval < now) { send_ping(c); } } else { - if(c->status.remove) { - logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...", - c->name, c->hostname, bitfield_to_int(&c->status, sizeof c->status)); - connection_del(c); - continue; - } - ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication", - c->name, c->hostname); if(c->status.connecting) { + ifdebug(CONNECTIONS) - logger(LOG_WARNING, _("Timeout while connecting to %s (%s)"), c->name, c->hostname); ++ logger(LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname); c->status.connecting = false; closesocket(c->socket); do_outgoing_connection(c); } else { - ifdebug(CONNECTIONS) logger(LOG_WARNING, _("Timeout from %s (%s) during authentication"), c->name, c->hostname); ++ ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname); terminate_connection(c, false); + continue; } } } - - 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, strerror(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"), ++ "Error while connecting to %s (%s): %s", + c->name, c->hostname, strerror(result)); + closesocket(c->socket); + do_outgoing_connection(c); + return; } } @@@ -228,110 -333,145 +221,108 @@@ } } -/* - this is where it all happens... -*/ -int main_loop(void) { - fd_set readset, writeset; - struct timeval tv; - int r, maxfd; - time_t last_ping_check, last_config_check, last_graph_dump; - event_t *event; - - last_ping_check = now; - last_config_check = now; - last_graph_dump = now; - - srand(now); - - running = true; - - while(running) { - now = time(NULL); - - // tv.tv_sec = 1 + (rand() & 7); /* Approx. 5 seconds, randomized to prevent global synchronisation effects */ - tv.tv_sec = 1; - tv.tv_usec = 0; - - maxfd = build_fdset(&readset, &writeset); - -#ifdef HAVE_MINGW - LeaveCriticalSection(&mutex); -#endif - r = select(maxfd + 1, &readset, &writeset, NULL, &tv); -#ifdef HAVE_MINGW - EnterCriticalSection(&mutex); -#endif - - if(r < 0) { - if(errno != EINTR && errno != EAGAIN) { - logger(LOG_ERR, "Error while waiting for input: %s", - strerror(errno)); - dump_connections(); - return 1; - } - - continue; - } - - check_network_activity(&readset, &writeset); - - if(do_purge) { - purge(); - do_purge = false; - } - - /* Let's check if everybody is still alive */ - - if(last_ping_check + pingtimeout < now) { - check_dead_connections(); - last_ping_check = now; - - if(routing_mode == RMODE_SWITCH) - age_subnets(); - - age_past_requests(); +static void sigterm_handler(int signal, short events, void *data) { - logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal)); ++ logger(LOG_NOTICE, "Got %s signal", strsignal(signal)); + event_loopexit(NULL); +} - /* Should we regenerate our key? */ +static void sighup_handler(int signal, short events, void *data) { - logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal)); ++ logger(LOG_NOTICE, "Got %s signal", strsignal(signal)); + reload_configuration(); +} - if(keyexpires < now) { - avl_node_t *node; - node_t *n; +int reload_configuration(void) { + connection_t *c; + splay_node_t *node, *next; + char *fname; + struct stat s; + static time_t last_config_check = 0; - ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys"); + /* Reread our own configuration file */ - for(node = node_tree->head; node; node = node->next) { - n = node->data; - if(n->inkey) { - free(n->inkey); - n->inkey = NULL; - } - } + exit_configuration(&config_tree); + init_configuration(&config_tree); - send_key_changed(broadcast, myself); - keyexpires = now + keylifetime; - } - } + if(!read_server_config()) { - logger(LOG_ERR, _("Unable to reread configuration file, exitting.")); ++ logger(LOG_ERR, "Unable to reread configuration file, exitting."); + event_loopexit(NULL); + return EINVAL; + } - if(sigalrm) { - logger(LOG_INFO, "Flushing event queue"); - expire_events(); - sigalrm = false; + /* Close connections to hosts that have a changed or deleted host config file */ + + for(node = connection_tree->head; node; node = next) { + c = node->data; + next = node->next; + + if(c->outgoing) { + free(c->outgoing->name); + if(c->outgoing->ai) + freeaddrinfo(c->outgoing->ai); + free(c->outgoing); + c->outgoing = NULL; } + + xasprintf(&fname, "%s/hosts/%s", confbase, c->name); + if(stat(fname, &s) || s.st_mtime > last_config_check) + terminate_connection(c, c->status.active); + free(fname); + } - while((event = get_expired_event())) { - event->handler(event->data); - free_event(event); - } + last_config_check = time(NULL); - if(sighup) { - connection_t *c; - avl_node_t *node; - char *fname; - struct stat s; - - sighup = false; - - /* Reread our own configuration file */ - - exit_configuration(&config_tree); - init_configuration(&config_tree); - - if(!read_server_config()) { - logger(LOG_ERR, "Unable to reread configuration file, exitting."); - return 1; - } + /* Try to make outgoing connections */ + + try_outgoing_connections(); - /* Close connections to hosts that have a changed or deleted host config file */ - - for(node = connection_tree->head; node; node = node->next) { - c = node->data; - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - if(stat(fname, &s) || s.st_mtime > last_config_check) - terminate_connection(c, c->status.active); - free(fname); - } + return 0; +} - last_config_check = now; +void retry(void) { + connection_t *c; + splay_node_t *node; - /* Try to make outgoing connections */ - - try_outgoing_connections(); - } + for(node = connection_tree->head; node; node = node->next) { + c = node->data; - /* Dump graph if wanted every 60 seconds*/ - - if(last_graph_dump + 60 < now) { - dump_graph(); - last_graph_dump = now; + if(c->outgoing && !c->node) { + if(timeout_initialized(&c->outgoing->ev)) + event_del(&c->outgoing->ev); + if(c->status.connecting) + close(c->socket); + c->outgoing->timeout = 0; + do_outgoing_connection(c); } } +} + +/* + this is where it all happens... +*/ +int main_loop(void) { + struct event timeout_event; + struct event sighup_event; + struct event sigterm_event; + struct event sigquit_event; + - cp(); - + timeout_set(&timeout_event, timeout_handler, &timeout_event); + event_add(&timeout_event, &(struct timeval){pingtimeout, 0}); + signal_set(&sighup_event, SIGHUP, sighup_handler, NULL); + signal_add(&sighup_event, NULL); + signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL); + signal_add(&sigterm_event, NULL); + signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL); + signal_add(&sigquit_event, NULL); + + if(event_loop(0) < 0) { - logger(LOG_ERR, _("Error while waiting for input: %s"), strerror(errno)); ++ logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno)); + return 1; + } + + signal_del(&sighup_event); + signal_del(&sigterm_event); + signal_del(&sigquit_event); + event_del(&timeout_event); return 0; } diff --cc src/net_packet.c index 77e29c0a,63e3592e..e430b6c9 --- a/src/net_packet.c +++ b/src/net_packet.c @@@ -61,12 -62,11 +59,10 @@@ static void send_mtu_probe_handler(int vpn_packet_t packet; int len, i; - cp(); - 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); + logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname); return; } @@@ -166,54 -162,65 +160,50 @@@ static void receive_packet(node_t *n, v route(n, packet); } - static bool try_mac(node_t *n, const vpn_packet_t *inpkt) - { -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) ++static bool try_mac(node_t *n, const vpn_packet_t *inpkt) { + if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) 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, (const char *)&inpkt->seqno + inpkt->len); } - static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) - { + 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; vpn_packet_t *outpkt = pkt[0]; - int outlen, outpad; - unsigned char hmac[EVP_MAX_MD_SIZE]; + size_t outlen; int i; - 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"), + 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) + n->inmaclength) { + if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) { - ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"), + ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)", n->name, n->hostname); return; } /* Check the message authentication code */ - 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, (const char *)&inpkt->seqno + inpkt->len)) { - ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname); ++ ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname); + return; } /* Decrypt the packet */ - if(n->incipher) { + if(cipher_active(&n->incipher)) { outpkt = pkt[nextpkt++]; + outlen = MAXSIZE; - 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); ++ ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname); return; } @@@ -227,14 -234,14 +217,14 @@@ inpkt->seqno = ntohl(inpkt->seqno); if(inpkt->seqno != n->received_seqno + 1) { - if(inpkt->seqno >= n->received_seqno + sizeof(n->late) * 8) { + if(inpkt->seqno >= n->received_seqno + sizeof n->late * 8) { - logger(LOG_WARNING, _("Lost %d packets from %s (%s)"), + logger(LOG_WARNING, "Lost %d packets from %s (%s)", inpkt->seqno - n->received_seqno - 1, n->name, n->hostname); - memset(n->late, 0, sizeof(n->late)); + memset(n->late, 0, sizeof n->late); } else if (inpkt->seqno <= n->received_seqno) { - if((n->received_seqno >= sizeof(n->late) * 8 && inpkt->seqno <= n->received_seqno - sizeof(n->late) * 8) || !(n->late[(inpkt->seqno / 8) % sizeof(n->late)] & (1 << inpkt->seqno % 8))) { + if((n->received_seqno >= sizeof n->late * 8 && inpkt->seqno <= n->received_seqno - sizeof n->late * 8) || !(n->late[(inpkt->seqno / 8) % sizeof n->late] & (1 << inpkt->seqno % 8))) { - logger(LOG_WARNING, _("Got late or replayed packet from %s (%s), seqno %d, last received %d"), + logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d", n->name, n->hostname, inpkt->seqno, n->received_seqno); return; } @@@ -363,12 -369,15 +349,12 @@@ static void send_udppacket(node_t *n, v /* Encrypt the packet */ - if(n->outcipher) { + if(cipher_active(&n->outcipher)) { outpkt = pkt[nextpkt++]; + outlen = MAXSIZE; - 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); ++ ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname); goto end; } @@@ -398,9 -408,9 +384,9 @@@ if(priorityinheritance && origpriority != priority && listen_socket[sock].sa.sa.sa_family == AF_INET) { priority = origpriority; - ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Setting outgoing packet priority to %d"), priority); + ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority); - if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */ + if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof priority)) /* SO_PRIORITY doesn't seem to work */ - logger(LOG_ERR, _("System call `%s' failed: %s"), "setsockopt", strerror(errno)); + logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno)); } #endif @@@ -458,12 -466,10 +442,10 @@@ void send_packet(const node_t *n, vpn_p /* Broadcast a packet using the minimum spanning tree */ void broadcast_packet(const node_t *from, vpn_packet_t *packet) { - avl_node_t *node; + splay_node_t *node; connection_t *c; - cp(); - - ifdebug(TRAFFIC) logger(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"), + ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)", packet->len, from->name, from->hostname); if(from != myself) { @@@ -507,16 -513,13 +489,13 @@@ static node_t *try_harder(const sockadd return n; } - void handle_incoming_vpn_data(int sock, short events, void *data) - { -void handle_incoming_vpn_data(int sock) { ++void handle_incoming_vpn_data(int sock, short events, void *data) { vpn_packet_t pkt; char *hostname; sockaddr_t from; - socklen_t fromlen = sizeof(from); + socklen_t fromlen = sizeof from; node_t *n; - cp(); - pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); if(pkt.len < 0) { diff --cc src/net_setup.c index 14520875,f7302db7..44c8d8dc --- a/src/net_setup.c +++ b/src/net_setup.c @@@ -47,61 -48,118 +46,57 @@@ static struct event device_ev bool read_rsa_public_key(connection_t *c) { FILE *fp; char *fname; - char *key; - - if(!c->rsa_key) { - c->rsa_key = RSA_new(); -// RSA_blinding_on(c->rsa_key, NULL); - } + char *n; + bool result; - cp(); - /* First, check for simple PublicKey statement */ - if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) { - BN_hex2bn(&c->rsa_key->n, key); - BN_hex2bn(&c->rsa_key->e, "FFFF"); - free(key); - return true; + if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) { + result = rsa_set_hex_public_key(&c->rsa, n, "FFFF"); + free(n); + return result; } /* Else, check for PublicKeyFile statement and read it */ - if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) { - fp = fopen(fname, "r"); - - if(!fp) { - logger(LOG_ERR, "Error reading RSA public key file `%s': %s", - fname, strerror(errno)); - free(fname); - return false; - } - - free(fname); - c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL); - fclose(fp); - - if(c->rsa_key) - return true; /* Woohoo. */ - - /* If it fails, try PEM_read_RSA_PUBKEY. */ - fp = fopen(fname, "r"); + if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) + xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - if(!fp) { - logger(LOG_ERR, "Error reading RSA public key file `%s': %s", - fname, strerror(errno)); - free(fname); - return false; - } - - free(fname); - c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL); - fclose(fp); - - if(c->rsa_key) { -// RSA_blinding_on(c->rsa_key, NULL); - return true; - } + fp = fopen(fname, "r"); - logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s", + if(!fp) { - logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"), ++ logger(LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno)); + free(fname); return false; } - /* Else, check if a harnessed public key is in the config file */ - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - fp = fopen(fname, "r"); - - if(fp) { - c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL); - fclose(fp); - } - - free(fname); - - if(c->rsa_key) - return true; - - /* Try again with PEM_read_RSA_PUBKEY. */ - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - fp = fopen(fname, "r"); - - if(fp) { - c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL); -// RSA_blinding_on(c->rsa_key, NULL); - fclose(fp); - } + result = rsa_read_pem_public_key(&c->rsa, fp); + fclose(fp); + if(!result) - logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"), fname, strerror(errno)); ++ logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno)); free(fname); - - if(c->rsa_key) - return true; - - logger(LOG_ERR, "No public key for %s specified!", c->name); - - return false; + return result; } -bool read_rsa_private_key(void) { +bool read_rsa_private_key() { FILE *fp; - char *fname, *key, *pubkey; - struct stat s; + char *fname; + char *n, *d; + bool result; + - cp(); - + /* First, check for simple PrivateKey statement */ - if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { - if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &pubkey)) { + if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) { + if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &n)) { - logger(LOG_ERR, _("PrivateKey used but no PublicKey found!")); + logger(LOG_ERR, "PrivateKey used but no PublicKey found!"); + free(d); return false; } - myself->connection->rsa_key = RSA_new(); -// RSA_blinding_on(myself->connection->rsa_key, NULL); - BN_hex2bn(&myself->connection->rsa_key->d, key); - BN_hex2bn(&myself->connection->rsa_key->n, pubkey); - BN_hex2bn(&myself->connection->rsa_key->e, "FFFF"); - free(key); - free(pubkey); + result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d); + free(n); + free(d); return true; } @@@ -120,43 -176,29 +115,43 @@@ } #if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN) + struct stat s; + if(fstat(fileno(fp), &s)) { - logger(LOG_ERR, _("Could not stat RSA private key file `%s': %s'"), fname, strerror(errno)); - logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'", - fname, strerror(errno)); ++ logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno)); free(fname); return false; } if(s.st_mode & ~0100700) - logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname); + 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)); ++ 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")); ++ 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}); } /* @@@ -299,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_aes_256_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("aes256"); - myself->connection->outcipher = EVP_aes_256_ofb(); + if(!cipher_open_by_name(&myself->incipher, cipher)) { - logger(LOG_ERR, _("Unrecognized cipher type!")); ++ 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"); - if(!myself->indigest) { - logger(LOG_ERR, "Unrecognized digest type!"); - return false; - } - } - } else - myself->indigest = EVP_sha256(); - - myself->connection->outdigest = EVP_sha256(); - - 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!")); ++ 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!")); ++ logger(LOG_ERR, "Unrecognized digest type!"); + return false; + } /* Compression */ @@@ -356,14 -425,6 +349,14 @@@ if(!setup_device()) return false; + event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL); + + if (event_add(&device_ev, NULL) < 0) { - logger(LOG_ERR, _("event_add failed: %s"), strerror(errno)); ++ logger(LOG_ERR, "event_add failed: %s", strerror(errno)); + close_device(); + return false; + } + /* Run tinc-up script to further initialize the tap interface */ xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); @@@ -409,28 -470,8 +402,28 @@@ listen_socket[listen_sockets].udp = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); - if(listen_socket[listen_sockets].udp < 0) + if(listen_socket[listen_sockets].udp < 0) { + close(listen_socket[listen_sockets].tcp); continue; + } + + event_set(&listen_socket[listen_sockets].ev_tcp, + listen_socket[listen_sockets].tcp, + EV_READ|EV_PERSIST, + handle_new_meta_connection, NULL); + if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) { - logger(LOG_EMERG, _("event_add failed: %s"), strerror(errno)); ++ logger(LOG_EMERG, "event_add failed: %s", strerror(errno)); + abort(); + } + + event_set(&listen_socket[listen_sockets].ev_udp, + listen_socket[listen_sockets].udp, + EV_READ|EV_PERSIST, + handle_incoming_vpn_data, NULL); + if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) { - logger(LOG_EMERG, _("event_add failed: %s"), strerror(errno)); ++ logger(LOG_EMERG, "event_add failed: %s", strerror(errno)); + abort(); + } ifdebug(CONNECTIONS) { hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); @@@ -440,11 -481,6 +433,11 @@@ memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen); listen_sockets++; + + if(listen_sockets >= MAXSOCKETS) { - logger(LOG_WARNING, _("Maximum of %d listening sockets reached"), MAXSOCKETS); ++ logger(LOG_WARNING, "Maximum of %d listening sockets reached", MAXSOCKETS); + break; + } } freeaddrinfo(ai); @@@ -462,10 -498,10 +455,7 @@@ /* initialize network */ - bool setup_network(void) - { - cp(); - + bool setup_network(void) { - now = time(NULL); - - init_events(); init_connections(); init_subnets(); init_nodes(); diff --cc src/net_socket.c index 47a41684,7189025c..be44a1ce --- a/src/net_socket.c +++ b/src/net_socket.c @@@ -200,12 -198,12 +197,12 @@@ 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, + logger(LOG_ERR, "Can't bind to interface %s: %s", iface, strerror(errno)); return -1; } @@@ -309,23 -305,22 +304,21 @@@ 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; if(outgoing->timeout > maxtimeout) outgoing->timeout = maxtimeout; - event = new_event(); - event->handler = (event_handler_t) setup_outgoing_connection; - event->time = now + outgoing->timeout; - event->data = outgoing; - event_add(event); + timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing); + event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0}); ifdebug(CONNECTIONS) logger(LOG_NOTICE, - _("Trying to re-establish outgoing connection in %d seconds"), + "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout); } @@@ -349,13 -341,10 +340,11 @@@ void do_outgoing_connection(connection_ begin: if(!c->outgoing->ai) { if(!c->outgoing->cfg) { - ifdebug(CONNECTIONS) logger(LOG_ERR, _("Could not set up a meta connection to %s"), + ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s", c->name); - c->status.remove = true; retry_outgoing(c->outgoing); + c->outgoing = NULL; + connection_del(c); return; } @@@ -438,21 -427,6 +427,21 @@@ return; } +void handle_meta_read(struct bufferevent *event, void *data) { - logger(LOG_EMERG, _("handle_meta_read() called")); ++ logger(LOG_EMERG, "handle_meta_read() called"); + abort(); +} + +void handle_meta_write(struct bufferevent *event, void *data) { - ifdebug(META) logger(LOG_DEBUG, _("handle_meta_write() called")); ++ ifdebug(META) logger(LOG_DEBUG, "handle_meta_write() called"); +} + +void handle_meta_connection_error(struct bufferevent *event, short what, void *data) { + connection_t *c = data; - logger(LOG_EMERG, _("handle_meta_connection_error() called: %d: %s"), what, strerror(errno)); ++ logger(LOG_EMERG, "handle_meta_connection_error() called: %d: %s", what, strerror(errno)); + terminate_connection(c, c->status.active); +} + void setup_outgoing_connection(outgoing_t *outgoing) { connection_t *c; node_t *n; @@@ -493,15 -465,6 +480,15 @@@ connection_add(c); do_outgoing_connection(c); + + event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c); + event_add(&c->inevent, NULL); + c->buffer = bufferevent_new(c->socket, handle_meta_read, handle_meta_write, handle_meta_connection_error, c); + if(!c->buffer) { - logger(LOG_EMERG, _("bufferevent_new() failed: %s"), strerror(errno)); ++ logger(LOG_EMERG, "bufferevent_new() failed: %s", strerror(errno)); + abort(); + } + bufferevent_disable(c->buffer, EV_READ); } /* @@@ -512,15 -475,14 +499,13 @@@ void handle_new_meta_connection(int soc connection_t *c; sockaddr_t sa; int fd; - socklen_t len = sizeof(sa); + socklen_t len = sizeof sa; - cp(); - 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", - strerror(errno)); - return false; ++ logger(LOG_ERR, "Accepting a new connection failed: %s", strerror(errno)); + return; } sockaddrunmap(&sa); @@@ -535,19 -497,10 +520,19 @@@ c->address = sa; c->hostname = sockaddr2hostname(&sa); c->socket = fd; - c->last_ping_time = now; + c->last_ping_time = time(NULL); - ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection from %s"), c->hostname); + ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection from %s", c->hostname); + event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c); + event_add(&c->inevent, NULL); + c->buffer = bufferevent_new(c->socket, NULL, handle_meta_write, handle_meta_connection_error, c); + if(!c->buffer) { - logger(LOG_EMERG, _("bufferevent_new() failed: %s"), strerror(errno)); ++ logger(LOG_EMERG, "bufferevent_new() failed: %s", strerror(errno)); + abort(); + } + bufferevent_disable(c->buffer, EV_READ); + configure_tcp(c); connection_add(c); @@@ -572,10 -526,8 +556,8 @@@ void try_outgoing_connections(void) char *name; outgoing_t *outgoing; connection_t *c; - avl_node_t *node; + splay_node_t *node; - cp(); - if(outgoing_list) { for(node = connection_tree->head; node; node = node->next) { c = node->data; diff --cc src/netutl.c index 480b716b,b8ecdd1e..2d8de9e8 --- a/src/netutl.c +++ b/src/netutl.c @@@ -96,12 -88,11 +88,11 @@@ void sockaddr2str(const sockaddr_t *sa return; } - err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); + err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV); if(err) { - logger(LOG_ERR, _("Error while translating addresses: %s"), + logger(LOG_ERR, "Error while translating addresses: %s", gai_strerror(err)); - cp_trace(); raise(SIGFPE); exit(0); } @@@ -128,10 -117,10 +117,10 @@@ char *sockaddr2hostname(const sockaddr_ return str; } - err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), + err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV)); if(err) { - logger(LOG_ERR, _("Error while looking up hostname: %s"), + logger(LOG_ERR, "Error while looking up hostname: %s", gai_strerror(err)); } @@@ -210,12 -192,11 +192,11 @@@ int sockaddrcmp(const sockaddr_t *a, co if(result) return result; - return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port)); + return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port); default: - logger(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"), + logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!", a->sa.sa_family); - cp_trace(); raise(SIGFPE); exit(0); } diff --cc src/node.c index ebd2c7c2,c1f12194..2ef28b59 --- a/src/node.c +++ b/src/node.c @@@ -40,39 -38,26 +38,31 @@@ static int node_compare(const node_t *a } static int node_udp_compare(const node_t *a, const node_t *b) { - return sockaddrcmp(&a->address, &b->address); + int result; + - cp(); - + result = sockaddrcmp(&a->address, &b->address); + + if(result) + return result; + + return (a->name && b->name) ? strcmp(a->name, b->name) : 0; } void init_nodes(void) { - cp(); - - node_tree = avl_alloc_tree((avl_compare_t) node_compare, (avl_action_t) free_node); - node_udp_tree = avl_alloc_tree((avl_compare_t) node_udp_compare, NULL); + node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node); + node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL); } void exit_nodes(void) { - cp(); - - avl_delete_tree(node_udp_tree); - avl_delete_tree(node_tree); + splay_delete_tree(node_udp_tree); + splay_delete_tree(node_tree); } node_t *new_node(void) { - node_t *n = xmalloc_and_zero(sizeof(*n)); + node_t *n = xmalloc_and_zero(sizeof *n); - cp(); - n->subnet_tree = new_subnet_tree(); n->edge_tree = new_edge_tree(); - EVP_CIPHER_CTX_init(&n->inctx); - EVP_CIPHER_CTX_init(&n->outctx); n->mtu = MTU; n->maxmtu = MTU; @@@ -80,8 -65,12 +70,6 @@@ } void free_node(node_t *n) { - cp(); - if(n->inkey) - free(n->inkey); - - if(n->outkey) - free(n->outkey); -- if(n->subnet_tree) free_subnet_tree(n->subnet_tree); @@@ -107,9 -95,7 +95,7 @@@ } void node_add(node_t *n) { - cp(); - - avl_insert(node_tree, n); + splay_insert(node_tree, n); } void node_del(node_t *n) { @@@ -138,11 -122,9 +122,9 @@@ node_t *lookup_node(char *name) { node_t n = {0}; - cp(); - n.name = name; - return avl_search(node_tree, &n); + return splay_search(node_tree, &n); } node_t *lookup_node_udp(const sockaddr_t *sa) { @@@ -151,14 -133,11 +133,11 @@@ 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) - { + 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); @@@ -175,21 -154,20 +154,19 @@@ } } -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; - 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"), - 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->outcipher), + digest_get_nid(&n->outdigest), digest_length(&n->outdigest), n->outcompression, n->options, bitfield_to_int(&n->status, sizeof 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/openssl/rsagen.h index e5aff63d,00000000..422d1560 mode 100644,000000..100644 --- a/src/openssl/rsagen.h +++ b/src/openssl/rsagen.h @@@ -1,31 -1,0 +1,29 @@@ +/* + rsagen.h -- RSA key generation and export + Copyright (C) 2008 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$ ++ 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., ++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef __TINC_RSAGEN_H__ +#define __TINC_RSAGEN_H__ + +#include "rsa.h" + +extern bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent); +extern bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp); +extern bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp); + +#endif diff --cc src/process.c index 546570aa,01ebe494..f0e5dd8b --- a/src/process.c +++ b/src/process.c @@@ -44,9 -44,11 +42,8 @@@ extern bool use_logfile sigset_t emptysigset; -static int saved_debug_level = -1; - static void memory_full(int size) { - logger(LOG_ERR, _("Memory exhausted (couldn't allocate %d bytes), exitting."), size); - cp_trace(); + logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size); exit(1); } @@@ -223,15 -233,86 +220,13 @@@ bool init_service(void) } #endif -#ifndef HAVE_MINGW -/* - check for an existing tinc for this net, and write pid to pidfile -*/ -static bool write_pidfile(void) { - pid_t pid; - - pid = check_pid(pidfilename); - - if(pid) { - if(netname) - fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n", - netname, (long)pid); - else - fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid); - return false; - } - - /* if it's locked, write-protected, or whatever */ - if(!write_pid(pidfilename)) { - fprintf(stderr, "Could write pid file %s: %s\n", pidfilename, strerror(errno)); - return false; - } - - return true; -} -#endif - -/* - kill older tincd for this net -*/ -bool kill_other(int signal) { -#ifndef HAVE_MINGW - pid_t pid; - - pid = read_pid(pidfilename); - - if(!pid) { - if(netname) - fprintf(stderr, "No other tincd is running for net `%s'.\n", - netname); - else - fprintf(stderr, "No other tincd is running.\n"); - return false; - } - - errno = 0; /* No error, sometimes errno is only changed on error */ - - /* ESRCH is returned when no process with that pid is found */ - if(kill(pid, signal) && errno == ESRCH) { - if(netname) - fprintf(stderr, "The tincd for net `%s' is no longer running. ", - netname); - else - fprintf(stderr, "The tincd is no longer running. "); - - fprintf(stderr, "Removing stale lock file.\n"); - remove_pid(pidfilename); - } - - return true; -#else - return remove_service(); -#endif -} - /* - Detach from current terminal, write pidfile, kill parent + Detach from current terminal */ bool detach(void) { - cp(); - setup_signals(); - /* First check if we can open a fresh new pidfile */ - #ifndef HAVE_MINGW - if(!write_pidfile()) - return false; - - /* If we succeeded in doing that, detach */ - closelogger(); #endif @@@ -342,10 -428,25 +335,9 @@@ bool execute_script(const char *name, c */ #ifndef HAVE_MINGW -static RETSIGTYPE sigterm_handler(int a) { - logger(LOG_NOTICE, "Got %s signal", "TERM"); - if(running) - running = false; - else - exit(1); -} - -static RETSIGTYPE sigquit_handler(int a) { - logger(LOG_NOTICE, "Got %s signal", "QUIT"); - if(running) - running = false; - else - exit(1); -} - static RETSIGTYPE fatal_signal_square(int a) { - logger(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a, + logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a, strsignal(a)); - cp_trace(); exit(1); } @@@ -364,17 -464,58 +355,16 @@@ static RETSIGTYPE fatal_signal_handler( close_network_connections(); sleep(5); - remove_pid(pidfilename); + exit_control(); execvp(g_argv[0], g_argv); } else { - logger(LOG_NOTICE, _("Not restarting.")); + logger(LOG_NOTICE, "Not restarting."); exit(1); } } -static RETSIGTYPE sighup_handler(int a) { - logger(LOG_NOTICE, "Got %s signal", "HUP"); - sighup = true; -} - -static RETSIGTYPE sigint_handler(int a) { - logger(LOG_NOTICE, "Got %s signal", "INT"); - - if(saved_debug_level != -1) { - logger(LOG_NOTICE, "Reverting to old debug level (%d)", - saved_debug_level); - debug_level = saved_debug_level; - saved_debug_level = -1; - } else { - logger(LOG_NOTICE, - "Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.", - debug_level); - saved_debug_level = debug_level; - debug_level = 5; - } -} - -static RETSIGTYPE sigalrm_handler(int a) { - logger(LOG_NOTICE, "Got %s signal", "ALRM"); - sigalrm = true; -} - -static RETSIGTYPE sigusr1_handler(int a) { - dump_connections(); -} - -static RETSIGTYPE sigusr2_handler(int a) { - dump_device_stats(); - dump_nodes(); - dump_edges(); - dump_subnets(); -} - -static RETSIGTYPE sigwinch_handler(int a) { - do_purge = true; -} - static RETSIGTYPE unexpected_signal_handler(int a) { - logger(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a)); - cp_trace(); + logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a)); } static RETSIGTYPE ignore_signal_handler(int a) { diff --cc src/protocol.c index 50f6fe73,f09aff65..ac4b767e --- a/src/protocol.c +++ b/src/protocol.c @@@ -68,11 -66,9 +66,9 @@@ bool check_id(const char *id) bool send_request(connection_t *c, const char *format, ...) { va_list args; - char buffer[MAXBUFSIZE]; - int len, request; + char request[MAXBUFSIZE]; + int len; - cp(); - /* Use vsnprintf instead of vxasprintf: faster, no memory fragmentation, cleanup is automatic, and there is a limit on the input buffer anyway */ @@@ -88,77 -84,79 +84,73 @@@ } ifdebug(PROTOCOL) { - sscanf(buffer, "%d", &request); ifdebug(META) - logger(LOG_DEBUG, _("Sending %s to %s (%s): %s"), + logger(LOG_DEBUG, "Sending %s to %s (%s): %s", - request_name[request], c->name, c->hostname, buffer); + request_name[atoi(request)], c->name, c->hostname, request); else - logger(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[atoi(request)], - logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[request], ++ logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[atoi(request)], c->name, c->hostname); } - buffer[len++] = '\n'; + request[len++] = '\n'; if(c == broadcast) { - broadcast_meta(NULL, buffer, len); + broadcast_meta(NULL, request, len); return true; } else - return send_meta(c, buffer, len); + return send_meta(c, request, len); } -void forward_request(connection_t *from) { - int request; - +void forward_request(connection_t *from, char *request) { - cp(); - ifdebug(PROTOCOL) { - sscanf(from->buffer, "%d", &request); ifdebug(META) - logger(LOG_DEBUG, _("Forwarding %s from %s (%s): %s"), + logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s", - request_name[request], from->name, from->hostname, - from->buffer); + request_name[atoi(request)], from->name, from->hostname, request); else - logger(LOG_DEBUG, _("Forwarding %s from %s (%s)"), + logger(LOG_DEBUG, "Forwarding %s from %s (%s)", - request_name[request], from->name, from->hostname); + request_name[atoi(request)], from->name, from->hostname); } - from->buffer[from->reqlen - 1] = '\n'; - - broadcast_meta(from, from->buffer, from->reqlen); + int len = strlen(request); + request[len] = '\n'; + broadcast_meta(from, request, len); } -bool receive_request(connection_t *c) { - int request; +bool receive_request(connection_t *c, char *request) { + int reqno = atoi(request); - cp(); - - if(sscanf(c->buffer, "%d", &request) == 1) { - if((request < 0) || (request >= LAST) || !request_handlers[request]) { + if(reqno || *request == '0') { + if((reqno < 0) || (reqno >= LAST) || !request_handlers[reqno]) { ifdebug(META) - logger(LOG_DEBUG, _("Unknown request from %s (%s): %s"), + logger(LOG_DEBUG, "Unknown request from %s (%s): %s", - c->name, c->hostname, c->buffer); + c->name, c->hostname, request); else - logger(LOG_ERR, _("Unknown request from %s (%s)"), + logger(LOG_ERR, "Unknown request from %s (%s)", c->name, c->hostname); return false; } else { ifdebug(PROTOCOL) { ifdebug(META) - logger(LOG_DEBUG, _("Got %s from %s (%s): %s"), + logger(LOG_DEBUG, "Got %s from %s (%s): %s", - request_name[request], c->name, c->hostname, - c->buffer); + request_name[reqno], c->name, c->hostname, request); else - logger(LOG_DEBUG, _("Got %s from %s (%s)"), + logger(LOG_DEBUG, "Got %s from %s (%s)", - request_name[request], c->name, c->hostname); + request_name[reqno], c->name, c->hostname); } } - if((c->allow_request != ALL) && (c->allow_request != request)) { + if((c->allow_request != ALL) && (c->allow_request != reqno)) { - logger(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name, + logger(LOG_ERR, "Unauthorized request from %s (%s)", c->name, c->hostname); return false; } - if(!request_handlers[request](c)) { + if(!request_handlers[reqno](c, request)) { /* Something went wrong. Probably scriptkiddies. Terminate. */ - logger(LOG_ERR, _("Error while processing %s from %s (%s)"), + logger(LOG_ERR, "Error while processing %s from %s (%s)", - request_name[request], c->name, c->hostname); + request_name[reqno], c->name, c->hostname); return false; } } else { @@@ -188,31 -190,25 +178,27 @@@ static struct event past_request_event bool seen_request(char *request) { past_request_t *new, p = {0}; - cp(); - p.request = request; - if(avl_search(past_request_tree, &p)) { + if(splay_search(past_request_tree, &p)) { - ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Already seen request")); + ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Already seen request"); return true; } else { - new = xmalloc(sizeof(*new)); + new = xmalloc(sizeof *new); new->request = xstrdup(request); - new->firstseen = now; - avl_insert(past_request_tree, new); + new->firstseen = time(NULL); + splay_insert(past_request_tree, new); + event_add(&past_request_event, &(struct timeval){10, 0}); return false; } } -void age_past_requests(void) { - avl_node_t *node, *next; +void age_past_requests(int fd, short events, void *data) { + splay_node_t *node, *next; past_request_t *p; int left = 0, deleted = 0; + time_t now = time(NULL); - cp(); - for(node = past_request_tree->head; node; node = next) { next = node->next; p = node->data; @@@ -224,25 -220,6 +210,21 @@@ } if(left || deleted) - ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Aging past requests: deleted %d, left %d"), + ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Aging past requests: deleted %d, left %d", deleted, left); + + if(left) + event_add(&past_request_event, &(struct timeval){10, 0}); +} + +void init_requests(void) { - cp(); - + past_request_tree = splay_alloc_tree((splay_compare_t) past_request_compare, (splay_action_t) free_past_request); + + timeout_set(&past_request_event, age_past_requests, NULL); +} + +void exit_requests(void) { - cp(); - + splay_delete_tree(past_request_tree); + + event_del(&past_request_event); } diff --cc src/protocol_auth.c index aa0fd36d,24f591a7..cb3d8e58 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@@ -38,21 -39,15 +36,17 @@@ #include "xalloc.h" bool send_id(connection_t *c) { - cp(); - + gettimeofday(&c->start, NULL); + return send_request(c, "%d %s %d", ID, myself->connection->name, myself->connection->protocol_version); } -bool id_h(connection_t *c) { +bool id_h(connection_t *c, char *request) { char name[MAX_STRING_SIZE]; - cp(); - - if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) { + if(sscanf(request, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ID", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "ID", c->name, c->hostname); return false; } @@@ -114,22 -109,24 +108,20 @@@ } bool send_metakey(connection_t *c) { - char *buffer; - int len; - bool x; - - len = RSA_size(c->rsa_key); + size_t len = rsa_size(&c->rsa); + char key[len]; + char enckey[len]; + char hexkey[2 * len + 1]; - cp(); - /* Allocate buffers for the meta key */ -- - buffer = alloca(2 * len + 1); + if(!cipher_open_blowfish_ofb(&c->outcipher)) + return false; - c->outkey = xrealloc(c->outkey, len); - - if(!c->outctx) - c->outctx = xmalloc_and_zero(sizeof(*c->outctx)); + if(!digest_open_sha1(&c->outdigest, -1)) + return false; - /* Copy random data to the buffer */ + /* Create a random key */ - RAND_pseudo_bytes((unsigned char *)c->outkey, len); + randomize(key, len); /* The message we send must be smaller than the modulus of the RSA key. By definition, for a key of k bits, the following formula holds: @@@ -141,14 -138,13 +133,14 @@@ This can be done by setting the most significant bit to zero. */ - c->outkey[0] &= 0x7F; + key[0] &= 0x7F; + + cipher_set_key_from_rsa(&c->outcipher, key, len, true); ifdebug(SCARY_THINGS) { - bin2hex(c->outkey, buffer, len); - buffer[len * 2] = '\0'; - logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s", - buffer); + bin2hex(key, hexkey, len); + hexkey[len * 2] = '\0'; - logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), hexkey); ++ logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s", hexkey); } /* Encrypt the random data @@@ -158,8 -154,9 +150,8 @@@ with a length equal to that of the modulus of the RSA key. */ - if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) { - logger(LOG_ERR, "Error during encryption of meta key for %s (%s)", - c->name, c->hostname); + if(!rsa_public_encrypt(&c->rsa, key, len, enckey)) { - logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); ++ logger(LOG_ERR, "Error during encryption of meta key for %s (%s)", c->name, c->hostname); return false; } @@@ -170,33 -167,46 +162,31 @@@ /* Send the meta key */ - x = send_request(c, "%d %d %d %d %d %s", METAKEY, - c->outcipher ? c->outcipher->nid : 0, - c->outdigest ? c->outdigest->type : 0, c->outmaclength, - c->outcompression, buffer); - - /* Further outgoing requests are encrypted with the key we just generated */ - - if(c->outcipher) { - if(!EVP_EncryptInit(c->outctx, c->outcipher, - (unsigned char *)c->outkey + len - c->outcipher->key_len, - (unsigned char *)c->outkey + len - c->outcipher->key_len - - c->outcipher->iv_len)) { - logger(LOG_ERR, "Error during initialisation of cipher for %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); - return false; - } - - c->status.encryptout = true; - } - - return x; + bool result = send_request(c, "%d %d %d %d %d %s", METAKEY, + cipher_get_nid(&c->outcipher), + digest_get_nid(&c->outdigest), c->outmaclength, + c->outcompression, hexkey); + + c->status.encryptout = true; + return result; } -bool metakey_h(connection_t *c) { - char buffer[MAX_STRING_SIZE]; +bool metakey_h(connection_t *c, char *request) { + char hexkey[MAX_STRING_SIZE]; int cipher, digest, maclength, compression; - int len; + size_t len = rsa_size(&myself->connection->rsa); + char enckey[len]; + char key[len]; - cp(); - - if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) { - logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, - c->hostname); + if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, hexkey) != 5) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname); ++ logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, c->hostname); return false; } - len = RSA_size(myself->connection->rsa_key); - /* Check if the length of the meta key is all right */ - if(strlen(buffer) != len * 2) { + if(strlen(hexkey) != len * 2) { - logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength"); + logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength"); return false; } @@@ -206,30 -223,63 +196,30 @@@ /* Decrypt the meta key */ - if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */ - logger(LOG_ERR, "Error during decryption of meta key for %s (%s)", - c->name, c->hostname); + if(!rsa_private_decrypt(&myself->connection->rsa, enckey, len, key)) { - logger(LOG_ERR, _("Error during decryption of meta key for %s (%s)"), c->name, c->hostname); ++ logger(LOG_ERR, "Error during decryption of meta key for %s (%s)", c->name, c->hostname); return false; } ifdebug(SCARY_THINGS) { - bin2hex(c->inkey, buffer, len); - buffer[len * 2] = '\0'; - logger(LOG_DEBUG, "Received random meta key (unencrypted): %s", buffer); + bin2hex(key, hexkey, len); + hexkey[len * 2] = '\0'; - logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), hexkey); ++ logger(LOG_DEBUG, "Received random meta key (unencrypted): %s", hexkey); } - /* All incoming requests will now be encrypted. */ - /* Check and lookup cipher and digest algorithms */ - if(cipher) { - c->incipher = EVP_get_cipherbynid(cipher); - - if(!c->incipher) { - logger(LOG_ERR, "%s (%s) uses unknown cipher!", c->name, c->hostname); - return false; - } - - if(!EVP_DecryptInit(c->inctx, c->incipher, - (unsigned char *)c->inkey + len - c->incipher->key_len, - (unsigned char *)c->inkey + len - c->incipher->key_len - - c->incipher->iv_len)) { - logger(LOG_ERR, "Error during initialisation of cipher from %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); - return false; - } - - c->status.decryptin = true; - } else { - c->incipher = NULL; + if(!cipher_open_by_nid(&c->incipher, cipher) || !cipher_set_key_from_rsa(&c->incipher, key, len, false)) { - logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s)"), c->name, c->hostname); ++ logger(LOG_ERR, "Error during initialisation of cipher from %s (%s)", c->name, c->hostname); + return false; } - c->inmaclength = maclength; - - if(digest) { - c->indigest = EVP_get_digestbynid(digest); - - if(!c->indigest) { - logger(LOG_ERR, "Node %s (%s) uses unknown digest!", c->name, c->hostname); - return false; - } - - if(c->inmaclength > c->indigest->md_size || c->inmaclength < 0) { - logger(LOG_ERR, "%s (%s) uses bogus MAC length!", c->name, c->hostname); - return false; - } - } else { - c->indigest = NULL; + if(!digest_open_by_nid(&c->indigest, digest, -1)) { - logger(LOG_ERR, _("Error during initialisation of digest from %s (%s)"), c->name, c->hostname); ++ logger(LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname); + return false; } - c->incompression = compression; + c->status.decryptin = true; c->allow_request = CHALLENGE; @@@ -237,13 -287,18 +227,11 @@@ } bool send_challenge(connection_t *c) { - char *buffer; - int len; + size_t len = rsa_size(&c->rsa); + char buffer[len * 2 + 1]; - 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 = xrealloc(c->hischallenge, len); /* Copy random data to the buffer */ @@@ -259,23 -314,23 +247,21 @@@ return send_request(c, "%d %s", CHALLENGE, buffer); } -bool challenge_h(connection_t *c) { +bool challenge_h(connection_t *c, char *request) { char buffer[MAX_STRING_SIZE]; - int len; + size_t len = rsa_size(&myself->connection->rsa); + size_t digestlen = digest_length(&c->outdigest); + char digest[digestlen]; - cp(); - - if(sscanf(c->buffer, "%*d " MAX_STRING, buffer) != 1) { - logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name, - c->hostname); + if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name, c->hostname); ++ logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name, c->hostname); return false; } /* Check if the length of the challenge is all right */ if(strlen(buffer) != len * 2) { - logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong challenge length"); - logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, - c->hostname, "wrong challenge length"); ++ logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge length"); return false; } @@@ -285,11 -344,24 +271,9 @@@ c->allow_request = CHAL_REPLY; - cp(); - /* Rest is done by send_chal_reply() */ - - return send_chal_reply(c); -} - -bool send_chal_reply(connection_t *c) { - char hash[EVP_MAX_MD_SIZE * 2 + 1]; - EVP_MD_CTX ctx; -- /* Calculate the hash from the challenge we received */ - if(!EVP_DigestInit(&ctx, c->indigest) - || !EVP_DigestUpdate(&ctx, c->mychallenge, RSA_size(myself->connection->rsa_key)) - || !EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL)) { - logger(LOG_ERR, "Error during calculation of response for %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); - return false; - } + digest_create(&c->indigest, buffer, len, digest); /* Convert the hash to a hexadecimal formatted string */ @@@ -298,35 -370,54 +282,33 @@@ /* Send the reply */ - return send_request(c, "%d %s", CHAL_REPLY, hash); + return send_request(c, "%d %s", CHAL_REPLY, buffer); } -bool chal_reply_h(connection_t *c) { +bool chal_reply_h(connection_t *c, char *request) { char hishash[MAX_STRING_SIZE]; - char myhash[EVP_MAX_MD_SIZE]; - EVP_MD_CTX ctx; - cp(); - - if(sscanf(c->buffer, "%*d " MAX_STRING, hishash) != 1) { + if(sscanf(request, "%*d " MAX_STRING, hishash) != 1) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHAL_REPLY", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "CHAL_REPLY", c->name, c->hostname); return false; } /* Check if the length of the hash is all right */ - if(strlen(hishash) != c->outdigest->md_size * 2) { - logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, - c->hostname, "wrong challenge reply length"); + if(strlen(hishash) != digest_length(&c->outdigest) * 2) { - logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length")); ++ logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, _("wrong challenge reply length")); return false; } /* Convert the hash to binary format */ - hex2bin(hishash, hishash, c->outdigest->md_size); + hex2bin(hishash, hishash, digest_length(&c->outdigest)); - /* Calculate the hash from the challenge we sent */ - - if(!EVP_DigestInit(&ctx, c->outdigest) - || !EVP_DigestUpdate(&ctx, c->hischallenge, RSA_size(c->rsa_key)) - || !EVP_DigestFinal(&ctx, (unsigned char *)myhash, NULL)) { - logger(LOG_ERR, "Error during calculation of response from %s (%s): %s", - c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); - return false; - } - - /* Verify the incoming hash with the calculated hash */ - - if(memcmp(hishash, myhash, c->outdigest->md_size)) { - logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, - c->hostname, "wrong challenge reply"); - - ifdebug(SCARY_THINGS) { - bin2hex(myhash, hishash, SHA_DIGEST_LENGTH); - hishash[SHA_DIGEST_LENGTH * 2] = '\0'; - logger(LOG_DEBUG, "Expected challenge reply: %s", hishash); - } + /* Verify the hash */ + if(!digest_verify(&c->outdigest, c->hischallenge, rsa_size(&c->rsa), hishash)) { - logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply")); ++ logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, _("wrong challenge reply")); return false; } @@@ -410,10 -497,8 +390,8 @@@ bool ack_h(connection_t *c, char *reque long int options; node_t *n; - cp(); - - if(sscanf(c->buffer, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) { + if(sscanf(request, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name, c->hostname); return false; } @@@ -429,17 -514,8 +407,17 @@@ } else { if(n->connection) { /* Oh dear, we already have a connection to this node. */ - ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->connection->name, n->connection->hostname); - ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection", - n->name, n->hostname); ++ ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection", n->connection->name, n->connection->hostname); + + if(n->connection->outgoing) { + if(c->outgoing) - logger(LOG_WARNING, _("Two outgoing connections to the same node!")); ++ logger(LOG_WARNING, "Two outgoing connections to the same node!"); + else + c->outgoing = n->connection->outgoing; + + n->connection->outgoing = NULL; + } + terminate_connection(n->connection, false); /* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */ graph(); diff --cc src/protocol_edge.c index 92d31dbd,57e202f6..df7e9c25 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@@ -64,11 -61,9 +61,9 @@@ bool add_edge_h(connection_t *c, char * long int options; int weight; - cp(); - - if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d", + if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %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, + logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, c->hostname); return false; } @@@ -185,10 -178,8 +178,8 @@@ bool del_edge_h(connection_t *c, char * char to_name[MAX_STRING_SIZE]; node_t *from, *to; - cp(); - - if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) { + if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name, c->hostname); return false; } diff --cc src/protocol_key.c index bc02054d,92948aa4..aae5516c --- a/src/protocol_key.c +++ b/src/protocol_key.c @@@ -34,11 -34,9 +32,9 @@@ #include "utils.h" #include "xalloc.h" -bool mykeyused = false; +static bool mykeyused = false; bool send_key_changed() { - cp(); - /* Only send this message if some other daemon requested our key previously. This reduces unnecessary key_changed broadcasts. */ @@@ -53,10 -51,8 +49,8 @@@ bool key_changed_h(connection_t *c, cha char name[MAX_STRING_SIZE]; node_t *n; - cp(); - - if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) { + if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "KEY_CHANGED", + logger(LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED", c->name, c->hostname); return false; } @@@ -94,10 -88,8 +86,8 @@@ bool req_key_h(connection_t *c, char *r char to_name[MAX_STRING_SIZE]; node_t *from, *to; - cp(); - - if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) { + if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "REQ_KEY", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name, c->hostname); return false; } @@@ -140,20 -131,22 +130,18 @@@ } bool send_ans_key(node_t *to) { - char *key; + size_t keylen = cipher_keylength(&myself->incipher); + char key[keylen * 2 + 1]; - cp(); - - // Set key parameters - to->incipher = myself->incipher; - to->inkeylength = myself->inkeylength; - to->indigest = myself->indigest; - to->inmaclength = myself->inmaclength; + cipher_open_by_nid(&to->incipher, cipher_get_nid(&myself->incipher)); + digest_open_by_nid(&to->indigest, digest_get_nid(&myself->indigest), digest_length(&myself->indigest)); 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'; // Reset sequence number and late packet window mykeyused = true; @@@ -175,12 -172,10 +163,10 @@@ bool ans_key_h(connection_t *c, char *r int cipher, digest, maclength, compression; node_t *from, *to; - cp(); - - if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d", + if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d", from_name, to_name, key, &cipher, &digest, &maclength, &compression) != 7) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ANS_KEY", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name, c->hostname); return false; } @@@ -208,34 -203,60 +194,34 @@@ return false; if(!to->status.reachable) { - logger(LOG_WARNING, _("Got %s from %s (%s) destination %s which is not reachable"), + logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable", - "ANS_KEY", c->name, c->hostname, to_name); + "ANS_KEY", c->name, c->hostname, to_name); 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) { - 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(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(!cipher_open_by_nid(&from->outcipher, cipher)) { - logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname); ++ logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname); + return false; } - from->outmaclength = maclength; - - if(digest) { - from->outdigest = EVP_get_digestbynid(digest); + if(strlen(key) / 2 != cipher_keylength(&from->outcipher)) { - logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname); ++ logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname); + return false; + } - 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, maclength)) { - logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname); ++ logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname); + return false; + } - 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(maclength != digest_length(&from->outdigest)) { - logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname); ++ logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname); + return false; } if(compression < 0 || compression > 11) { diff --cc src/protocol_misc.c index b8d2f67d,28571ef3..43df9bbc --- a/src/protocol_misc.c +++ b/src/protocol_misc.c @@@ -45,15 -40,12 +40,12 @@@ bool send_status(connection_t *c, int s return send_request(c, "%d %d %s", STATUS, statusno, statusstring); } - bool status_h(connection_t *c, char *request) - { -bool status_h(connection_t *c) { ++bool status_h(connection_t *c, char *request) { int statusno; char statusstring[MAX_STRING_SIZE]; - cp(); - - if(sscanf(c->buffer, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) { + if(sscanf(request, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "STATUS", + logger(LOG_ERR, "Got bad %s from %s (%s)", "STATUS", c->name, c->hostname); return false; } @@@ -74,53 -63,42 +63,38 @@@ bool send_error(connection_t *c, int er return send_request(c, "%d %d %s", ERROR, err, errstring); } - bool error_h(connection_t *c, char *request) - { -bool error_h(connection_t *c) { ++bool error_h(connection_t *c, char *request) { int err; char errorstring[MAX_STRING_SIZE]; - cp(); - - if(sscanf(c->buffer, "%*d %d " MAX_STRING, &err, errorstring) != 2) { + if(sscanf(request, "%*d %d " MAX_STRING, &err, errorstring) != 2) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ERROR", + logger(LOG_ERR, "Got bad %s from %s (%s)", "ERROR", c->name, c->hostname); return false; } - ifdebug(ERROR) logger(LOG_NOTICE, _("Error message from %s (%s): %d: %s"), + ifdebug(ERROR) logger(LOG_NOTICE, "Error message from %s (%s): %d: %s", c->name, c->hostname, err, errorstring); - terminate_connection(c, c->status.active); - - return true; + return false; } - bool send_termreq(connection_t *c) - { - cp(); - + bool send_termreq(connection_t *c) { return send_request(c, "%d", TERMREQ); } - bool termreq_h(connection_t *c, char *request) - { - cp(); -bool termreq_h(connection_t *c) { - terminate_connection(c, c->status.active); -- - return true; ++bool termreq_h(connection_t *c, char *request) { + return false; } - bool send_ping(connection_t *c) - { - cp(); - + bool send_ping(connection_t *c) { c->status.pinged = true; - c->last_ping_time = now; + c->last_ping_time = time(NULL); return send_request(c, "%d", PING); } - bool ping_h(connection_t *c, char *request) - { - cp(); - -bool ping_h(connection_t *c) { ++bool ping_h(connection_t *c, char *request) { return send_pong(c); } @@@ -131,10 -106,7 +102,7 @@@ bool send_pong(connection_t *c) return send_request(c, "%d", PONG); } - bool pong_h(connection_t *c, char *request) - { - cp(); - -bool pong_h(connection_t *c) { ++bool pong_h(connection_t *c, char *request) { c->status.pinged = false; /* Succesful connection, reset timeout if this is an outgoing connection. */ @@@ -163,14 -132,11 +128,11 @@@ bool send_tcppacket(connection_t *c, vp return send_meta(c, (char *)packet->data, packet->len); } - bool tcppacket_h(connection_t *c, char *request) - { -bool tcppacket_h(connection_t *c) { ++bool tcppacket_h(connection_t *c, char *request) { short int len; - cp(); - - if(sscanf(c->buffer, "%*d %hd", &len) != 1) { + if(sscanf(request, "%*d %hd", &len) != 1) { - logger(LOG_ERR, _("Got bad %s from %s (%s)"), "PACKET", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name, c->hostname); return false; } diff --cc src/protocol_subnet.c index 9c5b04c8,e7ab8b24..6ec50548 --- a/src/protocol_subnet.c +++ b/src/protocol_subnet.c @@@ -45,17 -41,14 +41,14 @@@ bool send_add_subnet(connection_t *c, c return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr); } - bool add_subnet_h(connection_t *c, char *request) - { -bool add_subnet_h(connection_t *c) { ++bool add_subnet_h(connection_t *c, char *request) { char subnetstr[MAX_STRING_SIZE]; char name[MAX_STRING_SIZE]; node_t *owner; subnet_t s = {0}, *new; - cp(); - - 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, + logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name, c->hostname); return false; } @@@ -164,17 -154,14 +154,14 @@@ bool send_del_subnet(connection_t *c, c return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr); } - bool del_subnet_h(connection_t *c, char *request) - { -bool del_subnet_h(connection_t *c) { ++bool del_subnet_h(connection_t *c, char *request) { char subnetstr[MAX_STRING_SIZE]; char name[MAX_STRING_SIZE]; node_t *owner; subnet_t s = {0}, *find; - cp(); - - 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)"), "DEL_SUBNET", c->name, + logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_SUBNET", c->name, c->hostname); return false; } diff --cc src/raw_socket/device.c index 412ba41b,30bb1845..0ee7cc20 --- a/src/raw_socket/device.c +++ b/src/raw_socket/device.c @@@ -74,8 -70,8 +70,8 @@@ bool setup_device(void) sa.sll_protocol = htons(ETH_P_ALL); sa.sll_ifindex = ifr.ifr_ifindex; - if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof(sa))) { + if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof sa)) { - logger(LOG_ERR, _("Could not bind %s to %s: %s"), device, iface, strerror(errno)); + logger(LOG_ERR, "Could not bind %s to %s: %s", device, iface, strerror(errno)); return false; } @@@ -94,12 -88,10 +88,10 @@@ void close_device(void) } bool read_packet(vpn_packet_t *packet) { - int lenin; + int inlen; - cp(); - - if((lenin = read(device_fd, packet->data, MTU)) <= 0) { + if((inlen = read(device_fd, packet->data, MTU)) <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } diff --cc src/route.c index da37473c,2da781e5..fd0c697d --- a/src/route.c +++ b/src/route.c @@@ -51,12 -49,9 +49,11 @@@ static const size_t icmp6_size = sizeof static const size_t ns_size = sizeof(struct nd_neighbor_solicit); static const size_t opt_size = sizeof(struct nd_opt_hdr); +static struct event age_subnets_event; + /* RFC 1071 */ - static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) - { + static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { uint16_t *p = data; uint32_t checksum = prevsum ^ 0xFFFF; @@@ -105,51 -99,11 +102,46 @@@ static void swap_mac_addresses(vpn_pack memcpy(&packet->data[6], &tmp, sizeof tmp); } - static void age_subnets(int fd, short events, void *data) - { -static void learn_mac(mac_t *address) { ++static void age_subnets(int fd, short events, void *data) { + subnet_t *s; + connection_t *c; + splay_node_t *node, *next, *node2; + bool left = false; + time_t now = time(NULL); + - cp(); - + for(node = myself->subnet_tree->head; node; node = next) { + next = node->next; + s = node->data; + if(s->expires && s->expires < now) { + ifdebug(TRAFFIC) { + char netstr[MAXNETSTR]; + if(net2str(netstr, sizeof netstr, s)) - logger(LOG_INFO, _("Subnet %s expired"), netstr); ++ logger(LOG_INFO, "Subnet %s expired", netstr); + } + + for(node2 = connection_tree->head; node2; node2 = node2->next) { + c = node2->data; + if(c->status.active) + send_del_subnet(c, s); + } + + subnet_del(myself, s); + } else { + if(s->expires) + left = true; + } + } + + if(left) + event_add(&age_subnets_event, &(struct timeval){10, 0}); +} + +static void learn_mac(mac_t *address) +{ subnet_t *subnet; - avl_node_t *node; + splay_node_t *node; connection_t *c; - cp(); - subnet = lookup_subnet_mac(address); /* If we don't know this MAC address yet, store it */ @@@ -700,8 -650,8 +666,8 @@@ static void route_arp(node_t *source, v /* Check if this is a valid ARP request */ if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP || - arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) { + arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof addr || ntohs(arp.arp_op) != ARPOP_REQUEST) { - ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request")); + ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request"); return; } diff --cc src/solaris/device.c index a258e34e,43938006..6fbd0538 --- a/src/solaris/device.c +++ b/src/solaris/device.c @@@ -118,12 -112,10 +112,10 @@@ void close_device(void) } bool read_packet(vpn_packet_t *packet) { - int lenin; + int inlen; - cp(); - - if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) { + if((inlen = read(device_fd, packet->data + 14, MTU - 14)) <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); return false; } diff --cc src/subnet.c index 057550ab,ef4e59e9..1cb81639 --- a/src/subnet.c +++ b/src/subnet.c @@@ -56,11 -54,10 +54,10 @@@ void subnet_cache_flush() /* Subnet comparison */ - static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) - { + static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) { int result; - result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t)); + result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address); if(result) return result; @@@ -145,34 -138,22 +138,22 @@@ int subnet_compare(const subnet_t *a, c /* Initialising trees */ - void init_subnets(void) - { - cp(); - + void init_subnets(void) { - subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet); + subnet_tree = splay_alloc_tree((splay_compare_t) subnet_compare, (splay_action_t) free_subnet); subnet_cache_flush(); } - void exit_subnets(void) - { - cp(); - + void exit_subnets(void) { - avl_delete_tree(subnet_tree); + splay_delete_tree(subnet_tree); } - splay_tree_t *new_subnet_tree(void) - { - cp(); - -avl_tree_t *new_subnet_tree(void) { - return avl_alloc_tree((avl_compare_t) subnet_compare, NULL); ++splay_tree_t *new_subnet_tree(void) { + return splay_alloc_tree((splay_compare_t) subnet_compare, NULL); } - void free_subnet_tree(splay_tree_t *subnet_tree) - { - cp(); - -void free_subnet_tree(avl_tree_t *subnet_tree) { - avl_delete_tree(subnet_tree); ++void free_subnet_tree(splay_tree_t *subnet_tree) { + splay_delete_tree(subnet_tree); } /* Allocating and freeing space for subnets */ @@@ -193,24 -168,18 +168,18 @@@ void free_subnet(subnet_t *subnet) /* Adding and removing subnets */ - void subnet_add(node_t *n, subnet_t *subnet) - { - cp(); - + void subnet_add(node_t *n, subnet_t *subnet) { subnet->owner = n; - avl_insert(subnet_tree, subnet); - avl_insert(n->subnet_tree, subnet); + splay_insert(subnet_tree, subnet); + splay_insert(n->subnet_tree, subnet); subnet_cache_flush(); } - void subnet_del(node_t *n, subnet_t *subnet) - { - cp(); - + void subnet_del(node_t *n, subnet_t *subnet) { - avl_delete(n->subnet_tree, subnet); - avl_delete(subnet_tree, subnet); + splay_delete(n->subnet_tree, subnet); + splay_delete(subnet_tree, subnet); subnet_cache_flush(); } @@@ -357,19 -319,13 +319,13 @@@ bool net2str(char *netstr, int len, con /* Subnet lookup routines */ - subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) - { - cp(); - + subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) { - return avl_search(owner->subnet_tree, subnet); + return splay_search(owner->subnet_tree, subnet); } - subnet_t *lookup_subnet_mac(const mac_t *address) - { + subnet_t *lookup_subnet_mac(const mac_t *address) { subnet_t *p, subnet = {0}; - cp(); - subnet.type = SUBNET_MAC; subnet.net.mac.address = *address; subnet.owner = NULL; @@@ -379,14 -335,11 +335,11 @@@ return p; } - subnet_t *lookup_subnet_ipv4(const ipv4_t *address) - { + subnet_t *lookup_subnet_ipv4(const ipv4_t *address) { subnet_t *p, *r = NULL, subnet = {0}; - avl_node_t *n; + splay_node_t *n; int i; - cp(); - // Check if this address is cached for(i = 0; i < 2; i++) { @@@ -426,14 -379,11 +379,11 @@@ return r; } - subnet_t *lookup_subnet_ipv6(const ipv6_t *address) - { + subnet_t *lookup_subnet_ipv6(const ipv6_t *address) { subnet_t *p, *r = NULL, subnet = {0}; - avl_node_t *n; + splay_node_t *n; int i; - cp(); - // Check if this address is cached for(i = 0; i < 2; i++) { @@@ -540,22 -490,19 +490,19 @@@ void subnet_update(node_t *owner, subne free(envp[i]); } - int dump_subnets(struct evbuffer *out) - { -void dump_subnets(void) { ++int dump_subnets(struct evbuffer *out) { char netstr[MAXNETSTR]; subnet_t *subnet; - avl_node_t *node; - - logger(LOG_DEBUG, "Subnet list:"); + splay_node_t *node; - cp(); - for(node = subnet_tree->head; node; node = node->next) { subnet = node->data; if(!net2str(netstr, sizeof netstr, subnet)) continue; - if(evbuffer_add_printf(out, _(" %s owner %s\n"), - logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name); ++ if(evbuffer_add_printf(out, " %s owner %s\n", + netstr, subnet->owner->name) == -1) + return errno; } - logger(LOG_DEBUG, "End of subnet list."); + return 0; } diff --cc src/tincd.c index 48f5faf8,8c2b12de..1a9bad0d --- a/src/tincd.c +++ b/src/tincd.c @@@ -105,25 -118,26 +105,24 @@@ static struct WSAData wsa_state CRITICAL_SECTION mutex; #endif - static void usage(bool status) - { + static void usage(bool status) { if(status) - fprintf(stderr, _("Try `%s --help\' for more information.\n"), + fprintf(stderr, "Try `%s --help\' for more information.\n", program_name); else { - printf(_("Usage: %s [option]...\n\n"), program_name); - printf(_( " -c, --config=DIR Read configuration options from DIR.\n" + 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" + " -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")); ++ " --version Output version information and exit.\n\n"); + printf("Report bugs to tinc@tinc-vpn.org.\n"); } } @@@ -353,16 -514,11 +345,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!")); ++ logger(LOG_ERR, "Error initializing libevent!"); + return 1; + } + + if(!init_control()) + return 1; + g_argv = argv; init_configuration(&config_tree); @@@ -454,13 -618,17 +445,13 @@@ int main2(int argc, char **argv) close_network_connections(); end: - logger(LOG_NOTICE, _("Terminating")); + 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(); diff --cc src/uml_socket/device.c index ec9dcb1e,3523f647..ddb4563b --- a/src/uml_socket/device.c +++ b/src/uml_socket/device.c @@@ -175,10 -169,8 +169,8 @@@ void close_device(void) } bool read_packet(vpn_packet_t *packet) { - int lenin; + int inlen; - cp(); - switch(state) { case 0: { struct sockaddr sa; @@@ -205,8 -197,8 +197,8 @@@ } case 1: { - if((lenin = read(request_fd, &request, sizeof request)) != sizeof request) { + if((inlen = read(request_fd, &request, sizeof request)) != sizeof request) { - logger(LOG_ERR, _("Error while reading request from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading request from %s %s: %s", device_info, device, strerror(errno)); running = false; return false; @@@ -235,8 -227,8 +227,8 @@@ } case 2: { - if((lenin = read(data_fd, packet->data, MTU)) <= 0) { + if((inlen = read(data_fd, packet->data, MTU)) <= 0) { - logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, + logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); running = false; return false;