From: Guus Sliepen Date: Fri, 19 Nov 2010 12:22:48 +0000 (+0000) Subject: Merge branch 'master' into 1.1 X-Git-Tag: release-1.1pre1~67 X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=commitdiff_plain;h=886a6f61a1f4cc48a77b42d10f34f9126377d904;hp=-c Merge branch 'master' into 1.1 Conflicts: src/net_packet.c src/openssl/rsagen.h src/protocol_auth.c src/protocol_key.c --- 886a6f61a1f4cc48a77b42d10f34f9126377d904 diff --combined src/dropin.c index 89039da3,52fb5b86..52fb5b86 --- a/src/dropin.c +++ b/src/dropin.c @@@ -163,3 -163,10 +163,10 @@@ int gettimeofday(struct timeval *tv, vo return 0; } #endif + + #ifdef HAVE_MINGW + int usleep(long usec) { + Sleep(usec / 1000); + return 0; + } + #endif diff --combined src/linux/device.c index 4dbe38d5,0632d51a..0cfc546e --- a/src/linux/device.c +++ b/src/linux/device.c @@@ -52,6 -52,7 +52,7 @@@ static uint64_t device_total_out = 0 bool setup_device(void) { struct ifreq ifr; + bool t1q = false; if(!get_config_string(lookup_config(config_tree, "Device"), &device)) device = xstrdup(DEFAULT_DEVICE); @@@ -73,7 -74,7 +74,7 @@@ #ifdef HAVE_LINUX_IF_TUN_H /* Ok now check if this is an old ethertap or a new tun/tap thingie */ - memset(&ifr, 0, sizeof(ifr)); + memset(&ifr, 0, sizeof ifr); if(routing_mode == RMODE_ROUTER) { ifr.ifr_flags = IFF_TUN; device_type = DEVICE_TYPE_TUN; @@@ -84,6 -85,12 +85,12 @@@ device_info = "Linux tun/tap device (tap mode)"; } + #ifdef IFF_ONE_QUEUE + /* Set IFF_ONE_QUEUE flag... */ + if(get_config_bool(lookup_config(config_tree, "IffOneQueue"), &t1q) && t1q) + ifr.ifr_flags |= IFF_ONE_QUEUE; + #endif + if(iface) strncpy(ifr.ifr_name, iface, IFNAMSIZ); @@@ -121,41 -128,41 +128,41 @@@ void close_device(void) } bool read_packet(vpn_packet_t *packet) { - int lenin; + int inlen; 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", 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", 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", device_info, device, strerror(errno)); return false; } - packet->len = lenin - 2; + packet->len = inlen - 2; break; } diff --combined src/net.h index f53c27a4,55856e2b..9b625a0d --- a/src/net.h +++ b/src/net.h @@@ -21,9 -21,9 +21,9 @@@ #ifndef __TINC_NET_H__ #define __TINC_NET_H__ -#include - #include "ipv6.h" +#include "cipher.h" +#include "digest.h" #ifdef ENABLE_JUMBOGRAMS #define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ @@@ -31,10 -31,10 +31,10 @@@ #define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ #endif -#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */ +#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */ #define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */ -#define MAXSOCKETS 128 /* Overkill... */ +#define MAXSOCKETS 8 /* Probably overkill... */ typedef struct mac_t { uint8_t x[6]; @@@ -84,8 -84,6 +84,8 @@@ typedef struct vpn_packet_t } vpn_packet_t; typedef struct listen_socket_t { + struct event ev_tcp; + struct event ev_udp; int tcp; int udp; sockaddr_t sa; @@@ -100,7 -98,7 +100,7 @@@ typedef struct outgoing_t struct config_t *cfg; struct addrinfo *ai; struct addrinfo *aip; - struct event *event; + struct event ev; } outgoing_t; extern list_t *outgoing_list; @@@ -108,12 -106,18 +108,15 @@@ extern int maxoutbufsize; extern int seconds_till_retry; extern int addressfamily; + extern unsigned replaywin; extern listen_socket_t listen_socket[MAXSOCKETS]; extern int listen_sockets; -extern int keyexpires; extern int keylifetime; + extern int udp_rcvbuf; + extern int udp_sndbuf; extern bool do_prune; -extern bool do_purge; extern char *myport; -extern time_t now; extern int contradicting_add_edge; extern int contradicting_del_edge; @@@ -122,10 -126,10 +125,10 @@@ #include "node.h" extern void retry_outgoing(outgoing_t *); -extern void handle_incoming_vpn_data(int); +extern void handle_incoming_vpn_data(int, short, void *); extern void finish_connecting(struct connection_t *); extern void do_outgoing_connection(struct connection_t *); -extern bool handle_new_meta_connection(int); +extern void handle_new_meta_connection(int, short, void *); extern int setup_listen_socket(const sockaddr_t *); extern int setup_vpn_in_socket(const sockaddr_t *); extern void send_packet(const struct node_t *, vpn_packet_t *); @@@ -140,12 -144,6 +143,12 @@@ extern void terminate_connection(struc extern void flush_queue(struct node_t *); extern bool read_rsa_public_key(struct connection_t *); extern void send_mtu_probe(struct node_t *); +extern void handle_device_data(int, short, void *); +extern void handle_meta_connection_data(int, short, void *); +extern void regenerate_key(); +extern void purge(void); +extern void retry(void); +extern int reload_configuration(void); extern void load_all_subnets(); #ifndef HAVE_MINGW diff --combined src/net_packet.c index b444bc93,9e5ef465..7be46620 --- a/src/net_packet.c +++ b/src/net_packet.c @@@ -3,6 -3,7 +3,7 @@@ Copyright (C) 1998-2005 Ivo Timmermans, 2000-2010 Guus Sliepen 2010 Timothy Redaelli + 2010 Brandon Black 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 @@@ -35,14 -36,12 +36,14 @@@ #include LZO1X_H #endif -#include "avl_tree.h" +#include "splay_tree.h" +#include "cipher.h" #include "conf.h" #include "connection.h" +#include "crypto.h" +#include "digest.h" #include "device.h" #include "ethernet.h" -#include "event.h" #include "graph.h" #include "list.h" #include "logger.h" @@@ -62,6 -61,8 +63,8 @@@ static char lzo_wrkmem[LZO1X_999_MEM_CO static void send_udppacket(node_t *, vpn_packet_t *); + unsigned replaywin = 16; + #define MAX_SEQNO 1073741824 // mtuprobes == 1..30: initial discovery, send bursts with 1 second interval @@@ -69,13 -70,13 +72,13 @@@ // mtuprobes == 32: send 1 burst, sleep pingtimeout second // mtuprobes == 33: no response from other side, restart PMTU discovery process -void send_mtu_probe(node_t *n) { +static void send_mtu_probe_handler(int fd, short events, void *data) { + node_t *n = data; vpn_packet_t packet; int len, i; int timeout = 1; n->mtuprobes++; - n->mtuevent = NULL; if(!n->status.reachable || !n->status.validkey) { ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname); @@@ -123,7 -124,7 +126,7 @@@ len = 64; memset(packet.data, 0, 14); - RAND_pseudo_bytes(packet.data + 14, len - 14); + randomize(packet.data + 14, len - 14); packet.len = len; packet.priority = 0; @@@ -133,13 -134,11 +136,13 @@@ } end: - n->mtuevent = new_event(); - n->mtuevent->handler = (event_handler_t)send_mtu_probe; - n->mtuevent->data = n; - n->mtuevent->time = now + timeout; - event_add(n->mtuevent); + event_add(&n->mtuevent, &(struct timeval){timeout, 0}); +} + +void send_mtu_probe(node_t *n) { + if(!timeout_initialized(&n->mtuevent)) + timeout_set(&n->mtuevent, send_mtu_probe_handler, n); + send_mtu_probe_handler(0, 0, n); } void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { @@@ -226,11 -225,15 +229,11 @@@ static void receive_packet(node_t *n, v route(n, packet); } -static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) { - unsigned char hmac[EVP_MAX_MD_SIZE]; - - if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof inpkt->seqno + n->inmaclength) +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 - n->indigest.maclength, (const char *)&inpkt->seqno + inpkt->len - n->indigest.maclength); } static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { @@@ -238,10 -241,11 +241,10 @@@ 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; - if(!n->inkey) { + if(!cipher_active(&n->incipher)) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname); return; @@@ -249,7 -253,7 +252,7 @@@ /* 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)", n->name, n->hostname); return; @@@ -257,58 -261,73 +260,65 @@@ /* 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); + if(digest_active(&n->indigest)) { + inpkt->len -= n->indigest.maclength; + if(!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); 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); return; } - outpkt->len = outlen + outpad; + outpkt->len = outlen; inpkt = outpkt; } /* Check the sequence number */ - inpkt->len -= sizeof(inpkt->seqno); + inpkt->len -= sizeof inpkt->seqno; inpkt->seqno = ntohl(inpkt->seqno); - if(inpkt->seqno != n->received_seqno + 1) { - if(inpkt->seqno >= n->received_seqno + sizeof n->late * 8) { - 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); - } 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))) { - 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; + if(replaywin) { + if(inpkt->seqno != n->received_seqno + 1) { + if(inpkt->seqno >= n->received_seqno + replaywin * 8) { + if(n->farfuture++ < replaywin >> 2) { + logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)", + n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture); + return; + } + logger(LOG_WARNING, "Lost %d packets from %s (%s)", + inpkt->seqno - n->received_seqno - 1, n->name, n->hostname); + memset(n->late, 0, replaywin); + } else if (inpkt->seqno <= n->received_seqno) { + if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) { + 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; + } + } else { + for(i = n->received_seqno + 1; i < inpkt->seqno; i++) + n->late[(i / 8) % replaywin] |= 1 << i % 8; } - } else { - for(i = n->received_seqno + 1; i < inpkt->seqno; i++) - n->late[(i / 8) % sizeof n->late] |= 1 << i % 8; } + + n->farfuture = 0; + n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8); } - - n->late[(inpkt->seqno / 8) % sizeof n->late] &= ~(1 << inpkt->seqno % 8); if(inpkt->seqno > n->received_seqno) n->received_seqno = inpkt->seqno; if(n->received_seqno > MAX_SEQNO) - keyexpires = 0; + regenerate_key(); /* Decompress the packet */ @@@ -356,7 -375,7 +366,7 @@@ static void send_udppacket(node_t *n, v int nextpkt = 0; vpn_packet_t *outpkt; int origlen; - int outlen, outpad; + size_t outlen; #if defined(SOL_IP) && defined(IP_TOS) static int priority = 0; #endif @@@ -371,8 -390,6 +381,8 @@@ /* Make sure we have a valid key */ if(!n->status.validkey) { + time_t now = time(NULL); + ifdebug(TRAFFIC) logger(LOG_INFO, "No valid key known yet for %s (%s), forwarding via TCP", n->name, n->hostname); @@@ -420,28 -437,32 +430,28 @@@ /* Add sequence number */ inpkt->seqno = htonl(++(n->sent_seqno)); - inpkt->len += sizeof(inpkt->seqno); + inpkt->len += sizeof inpkt->seqno; /* 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); goto end; } - outpkt->len = outlen + outpad; + outpkt->len = outlen; inpkt = outpkt; } /* Add the message authentication code */ - if(n->outdigest && n->outmaclength) { - HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno, - inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL); - inpkt->len += n->outmaclength; + if(digest_active(&n->outdigest)) { + digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len); + inpkt->len += digest_length(&n->outdigest); } /* Determine which socket we have to use */ @@@ -460,7 -481,7 +470,7 @@@ && listen_socket[sock].sa.sa.sa_family == AF_INET) { priority = origpriority; 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)); } #endif @@@ -517,7 -538,7 +527,7 @@@ 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; ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)", @@@ -541,49 -562,48 +551,49 @@@ } static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { - avl_node_t *node; - edge_t *e; - node_t *n = NULL; + splay_node_t *node; + node_t *n, *found = NULL; static time_t last_hard_try = 0; + time_t now = time(NULL); - for(node = edge_weight_tree->head; node; node = node->next) { - e = node->data; - - if(sockaddrcmp_noport(from, &e->address)) { - if(last_hard_try == now) - continue; - last_hard_try = now; - } + if(last_hard_try == now) + return NULL; + else + last_hard_try = now; - if(!n) - n = e->to; + for(node = node_tree->head; node; node = node->next) { + n = node->data; - if(!try_mac(e->to, pkt)) + if(n == myself || !n->status.reachable || !digest_active(&n->indigest)) continue; - n = e->to; - break; + if(try_mac(n, pkt)) { + found = n; + break; + } } - return n; + return found; } -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; + int len; - pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); + len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); - if(pkt.len < 0) { + if(len <= 0 || len > MAXSIZE) { if(!sockwouldblock(sockerrno)) logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno)); return; } + pkt.len = len; + sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */ n = lookup_node_udp(&from); @@@ -604,10 -624,3 +614,10 @@@ receive_udppacket(n, &pkt); } + +void handle_device_data(int sock, short events, void *data) { + vpn_packet_t packet; + + if(read_packet(&packet)) + route(myself, &packet); +} diff --combined src/net_setup.c index 9c188957,cc6ef680..c51c1336 --- a/src/net_setup.c +++ b/src/net_setup.c @@@ -3,6 -3,7 +3,7 @@@ Copyright (C) 1998-2005 Ivo Timmermans, 2000-2010 Guus Sliepen 2006 Scott Lamb + 2010 Brandon Black 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 @@@ -21,13 -22,17 +22,13 @@@ #include "system.h" -#include -#include -#include -#include -#include - -#include "avl_tree.h" +#include "splay_tree.h" +#include "cipher.h" #include "conf.h" #include "connection.h" +#include "control.h" #include "device.h" -#include "event.h" +#include "digest.h" #include "graph.h" #include "logger.h" #include "net.h" @@@ -35,73 -40,130 +36,73 @@@ #include "process.h" #include "protocol.h" #include "route.h" +#include "rsa.h" #include "subnet.h" #include "utils.h" #include "xalloc.h" char *myport; +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; /* 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", 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)); 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; - if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { - if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) { + /* First, check for simple PrivateKey statement */ + + if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) { + if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) { 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; } + /* Else, check for PrivateKeyFile statement and read it */ + if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) xasprintf(&fname, "%s/rsa_key.priv", confbase); @@@ -115,10 -177,9 +116,10 @@@ } #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)); free(fname); return false; } @@@ -127,31 -188,18 +128,31 @@@ logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname); #endif - myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + result = rsa_read_pem_private_key(&myself->connection->rsa, fp); fclose(fp); - if(!myself->connection->rsa_key) { - logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", - fname, strerror(errno)); - free(fname); - return false; + if(!result) + logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno)); + free(fname); + return result; +} + +static struct event keyexpire_event; + +static void keyexpire_handler(int fd, short events, void *data) { + regenerate_key(); +} + +void regenerate_key() { + if(timeout_initialized(&keyexpire_event)) { + ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys"); + event_del(&keyexpire_event); + send_key_changed(broadcast, myself); + } else { + timeout_set(&keyexpire_event, keyexpire_handler, NULL); } - free(fname); - return true; + event_add(&keyexpire_event, &(struct timeval){keylifetime, 0}); } /* @@@ -162,7 -210,7 +163,7 @@@ void load_all_subnets(void) struct dirent *ent; char *dname; char *fname; - avl_tree_t *config_tree; + splay_tree_t *config_tree; config_t *cfg; subnet_t *s, *s2; node_t *n; @@@ -229,6 -277,7 +230,7 @@@ bool setup_myself(void) struct addrinfo *ai, *aip, hint = {0}; bool choice; int i, err; + int replaywin_int; myself = new_node(); myself->connection = new_connection(); @@@ -358,6 -407,28 +360,28 @@@ } else maxtimeout = 900; + if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) { + if(udp_rcvbuf <= 0) { + logger(LOG_ERR, "UDPRcvBuf cannot be negative!"); + return false; + } + } + + if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) { + if(udp_sndbuf <= 0) { + logger(LOG_ERR, "UDPSndBuf cannot be negative!"); + return false; + } + } + + if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) { + if(replaywin_int < 0) { + logger(LOG_ERR, "ReplayWindow cannot be negative!"); + return false; + } + replaywin = (unsigned)replaywin_int; + } + if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) { if(!strcasecmp(afname, "IPv4")) addressfamily = AF_INET; @@@ -376,36 -447,65 +400,36 @@@ /* Generate packet encryption key */ - if(get_config_string - (lookup_config(config_tree, "Cipher"), &cipher)) { - if(!strcasecmp(cipher, "none")) { - myself->incipher = NULL; - } else { - myself->incipher = EVP_get_cipherbyname(cipher); + if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher)) + cipher = xstrdup("blowfish"); - if(!myself->incipher) { - logger(LOG_ERR, "Unrecognized cipher type!"); - return false; - } - } - } else - myself->incipher = EVP_bf_cbc(); - - if(myself->incipher) - myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len; - else - myself->inkeylength = 1; - - myself->connection->outcipher = EVP_bf_ofb(); + if(!cipher_open_by_name(&myself->incipher, cipher)) { + logger(LOG_ERR, "Unrecognized cipher type!"); + return false; + } if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; - keyexpires = now + keylifetime; - + regenerate_key(); + /* Check if we want to use message authentication codes... */ - if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) { - if(!strcasecmp(digest, "none")) { - myself->indigest = NULL; - } else { - myself->indigest = EVP_get_digestbyname(digest); + if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) + digest = xstrdup("sha1"); - if(!myself->indigest) { - logger(LOG_ERR, "Unrecognized digest type!"); - return false; - } - } - } else - myself->indigest = EVP_sha1(); - - myself->connection->outdigest = EVP_sha1(); - - if(get_config_int(lookup_config(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(config_tree, "MACLength"), &maclength); + + if(maclength < 0) { + logger(LOG_ERR, "Bogus MAC length!"); + return false; + } - myself->connection->outmaclength = 0; + if(!digest_open_by_name(&myself->indigest, digest, maclength)) { + logger(LOG_ERR, "Unrecognized digest type!"); + return false; + } /* Compression */ @@@ -436,16 -536,6 +460,16 @@@ if(!setup_device()) return false; + if(device_fd >= 0) { + 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)); + 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 ? : ""); @@@ -455,7 -545,7 +479,7 @@@ execute_script("tinc-up", envp); - for(i = 0; i < 5; i++) + for(i = 0; i < 4; i++) free(envp[i]); /* Run subnet-up scripts for our own subnets */ @@@ -491,28 -581,8 +515,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_ERR, "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_ERR, "event_add failed: %s", strerror(errno)); + abort(); + } ifdebug(CONNECTIONS) { hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); @@@ -522,11 -592,6 +546,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); + break; + } } freeaddrinfo(ai); @@@ -545,6 -610,9 +569,6 @@@ initialize network */ bool setup_network(void) { - now = time(NULL); - - init_events(); init_connections(); init_subnets(); init_nodes(); @@@ -576,7 -644,7 +600,7 @@@ close all open network connections */ void close_network_connections(void) { - avl_node_t *node, *next; + splay_node_t *node, *next; connection_t *c; char *envp[5]; int i; @@@ -584,10 -652,17 +608,10 @@@ for(node = connection_tree->head; node; node = next) { next = node->next; c = node->data; - c->outgoing = NULL; + c->outgoing = false; terminate_connection(c, false); } - for(list_node_t *node = outgoing_list->head; node; node = node->next) { - outgoing_t *outgoing = node->data; - - if(outgoing->event) - event_del(outgoing->event); - } - list_delete_list(outgoing_list); if(myself && myself->connection) { @@@ -597,8 -672,6 +621,8 @@@ } for(i = 0; i < listen_sockets; i++) { + event_del(&listen_socket[i].ev_tcp); + event_del(&listen_socket[i].ev_udp); close(listen_socket[i].tcp); close(listen_socket[i].udp); } @@@ -614,6 -687,7 +638,6 @@@ exit_subnets(); exit_nodes(); exit_connections(); - exit_events(); execute_script("tinc-down", envp); diff --combined src/net_socket.c index 44d7f771,2e6b0685..e20076fb --- a/src/net_socket.c +++ b/src/net_socket.c @@@ -22,9 -22,10 +22,9 @@@ #include "system.h" -#include "avl_tree.h" +#include "splay_tree.h" #include "conf.h" #include "connection.h" -#include "event.h" #include "logger.h" #include "meta.h" #include "net.h" @@@ -43,6 -44,8 +43,8 @@@ int addressfamily = AF_UNSPEC; int maxtimeout = 900; int seconds_till_retry = 5; + int udp_rcvbuf = 0; + int udp_sndbuf = 0; listen_socket_t listen_socket[MAXSOCKETS]; int listen_sockets; @@@ -69,12 -72,12 +71,12 @@@ static void configure_tcp(connection_t #if defined(SOL_TCP) && defined(TCP_NODELAY) option = 1; - setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof(option)); + setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof option); #endif #if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY) option = IPTOS_LOWDELAY; - setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof(option)); + setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option); #endif } @@@ -180,7 -183,7 +182,7 @@@ int setup_listen_socket(const sockaddr_ /* Optimize TCP settings */ option = 1; - setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option); #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) @@@ -192,10 -195,10 +194,10 @@@ #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, (void *)&ifr, sizeof(ifr))) { + if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof ifr)) { closesocket(nfd); logger(LOG_ERR, "Can't bind to interface %s: %s", iface, strerror(sockerrno)); @@@ -258,8 -261,14 +260,14 @@@ int setup_vpn_in_socket(const sockaddr_ #endif option = 1; - setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option)); + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option); + if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf))) + logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno)); + + if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf))) + logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno)); + #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if(sa->sa.sa_family == AF_INET6) setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option); @@@ -313,18 -322,19 +321,18 @@@ return nfd; } /* int setup_vpn_in_socket */ +static void retry_outgoing_handler(int fd, short events, void *data) { + setup_outgoing_connection(data); +} + void retry_outgoing(outgoing_t *outgoing) { outgoing->timeout += 5; if(outgoing->timeout > maxtimeout) outgoing->timeout = maxtimeout; - if(outgoing->event) - event_del(outgoing->event); - outgoing->event = new_event(); - outgoing->event->handler = (event_handler_t) setup_outgoing_connection; - outgoing->event->time = now + outgoing->timeout; - outgoing->event->data = outgoing; - event_add(outgoing->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", @@@ -336,8 -346,7 +344,8 @@@ void finish_connecting(connection_t *c configure_tcp(c); - c->last_ping_time = now; + c->last_ping_time = time(NULL); + c->status.connecting = false; send_id(c); } @@@ -356,9 -365,9 +364,9 @@@ begin if(!c->outgoing->cfg) { 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; } @@@ -441,26 -450,11 +449,26 @@@ return; } +void handle_meta_read(struct bufferevent *event, void *data) { + logger(LOG_ERR, "handle_meta_read() called"); + abort(); +} + +void handle_meta_write(struct bufferevent *event, void *data) { + 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_ERR, "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; - outgoing->event = NULL; + event_del(&outgoing->ev); n = lookup_node(outgoing->name); @@@ -491,37 -485,28 +499,37 @@@ } c->outgoing = outgoing; - c->last_ping_time = now; + c->last_ping_time = time(NULL); 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_ERR, "bufferevent_new() failed: %s", strerror(errno)); + abort(); + } + bufferevent_disable(c->buffer, EV_READ); } /* accept a new tcp connect and create a new connection */ -bool handle_new_meta_connection(int sock) { +void handle_new_meta_connection(int sock, short events, void *data) { connection_t *c; sockaddr_t sa; int fd; - socklen_t len = sizeof(sa); + socklen_t len = sizeof sa; fd = accept(sock, &sa.sa, &len); if(fd < 0) { logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno)); - return false; + return; } sockaddrunmap(&sa); @@@ -536,25 -521,18 +544,25 @@@ 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); + 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_ERR, "bufferevent_new() failed: %s", strerror(errno)); + abort(); + } + bufferevent_disable(c->buffer, EV_READ); + configure_tcp(c); connection_add(c); c->allow_request = ID; send_id(c); - - return true; } void free_outgoing(outgoing_t *outgoing) { @@@ -585,7 -563,7 +593,7 @@@ void try_outgoing_connections(void) continue; } - outgoing = xmalloc_and_zero(sizeof(*outgoing)); + outgoing = xmalloc_and_zero(sizeof *outgoing); outgoing->name = name; list_insert_tail(outgoing_list, outgoing); setup_outgoing_connection(outgoing); diff --combined src/node.c index 0159f9dd,7bcad892..862bd696 --- a/src/node.c +++ b/src/node.c @@@ -20,8 -20,7 +20,8 @@@ #include "system.h" -#include "avl_tree.h" +#include "control_common.h" +#include "splay_tree.h" #include "logger.h" #include "net.h" #include "netutl.h" @@@ -29,8 -28,8 +29,8 @@@ #include "utils.h" #include "xalloc.h" -avl_tree_t *node_tree; /* Known nodes, sorted by name */ -avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */ +splay_tree_t *node_tree; /* Known nodes, sorted by name */ +splay_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */ node_t *myself; @@@ -39,31 -38,27 +39,32 @@@ 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; + + 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) { - 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) { - 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); + if(replaywin) n->late = xmalloc_and_zero(replaywin); 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; @@@ -71,6 -66,12 +72,6 @@@ } void free_node(node_t *n) { - if(n->inkey) - free(n->inkey); - - if(n->outkey) - free(n->outkey); - if(n->subnet_tree) free_subnet_tree(n->subnet_tree); @@@ -79,12 -80,11 +80,12 @@@ sockaddrfree(&n->address); - EVP_CIPHER_CTX_cleanup(&n->inctx); - EVP_CIPHER_CTX_cleanup(&n->outctx); + cipher_close(&n->incipher); + digest_close(&n->indigest); + cipher_close(&n->outcipher); + digest_close(&n->outdigest); - if(n->mtuevent) - event_del(n->mtuevent); + event_del(&n->mtuevent); if(n->hostname) free(n->hostname); @@@ -92,15 -92,18 +93,18 @@@ if(n->name) free(n->name); + if(n->late) + free(n->late); + free(n); } void node_add(node_t *n) { - avl_insert(node_tree, n); + splay_insert(node_tree, n); } void node_del(node_t *n) { - avl_node_t *node, *next; + splay_node_t *node, *next; edge_t *e; subnet_t *s; @@@ -116,8 -119,8 +120,8 @@@ edge_del(e); } - avl_delete(node_udp_tree, n); - avl_delete(node_tree, n); + splay_delete(node_udp_tree, n); + splay_delete(node_tree, n); } node_t *lookup_node(char *name) { @@@ -125,7 -128,7 +129,7 @@@ n.name = name; - return avl_search(node_tree, &n); + return splay_search(node_tree, &n); } node_t *lookup_node_udp(const sockaddr_t *sa) { @@@ -134,11 -137,11 +138,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) { - avl_delete(node_udp_tree, n); + splay_delete(node_udp_tree, n); if(n->hostname) free(n->hostname); @@@ -146,8 -149,8 +150,8 @@@ if(sa) { n->address = *sa; n->hostname = sockaddr2hostname(&n->address); - avl_insert(node_udp_tree, n); - ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname); + splay_insert(node_udp_tree, n); + logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname); } else { memset(&n->address, 0, sizeof n->address); n->hostname = 0; @@@ -155,18 -158,20 +159,18 @@@ } } -void dump_nodes(void) { - avl_node_t *node; +bool dump_nodes(connection_t *c) { + splay_node_t *node; node_t *n; - logger(LOG_DEBUG, "Nodes:"); - for(node = node_tree->head; node; node = node->next) { n = node->data; - logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %x 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, + send_request(c, "%d %d %s at %s cipher %d digest %d maclength %zd compression %d options %x status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d)", CONTROL, REQ_DUMP_NODES, + 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); } - logger(LOG_DEBUG, "End of nodes."); + return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES); } diff --combined src/node.h index a9322aa5,7bac28e3..4eb216f4 --- a/src/node.h +++ b/src/node.h @@@ -21,10 -21,9 +21,10 @@@ #ifndef __TINC_NODE_H__ #define __TINC_NODE_H__ -#include "avl_tree.h" +#include "splay_tree.h" +#include "cipher.h" #include "connection.h" -#include "event.h" +#include "digest.h" #include "list.h" #include "subnet.h" @@@ -48,39 -47,49 +48,40 @@@ typedef struct node_t node_status_t status; time_t last_req_key; - const EVP_CIPHER *incipher; /* Cipher type for UDP packets received from him */ - char *inkey; /* Cipher key and iv */ - int inkeylength; /* Cipher key and iv length */ - EVP_CIPHER_CTX inctx; /* Cipher context */ - - const EVP_CIPHER *outcipher; /* Cipher type for UDP packets sent to him*/ - char *outkey; /* Cipher key and iv */ - int outkeylength; /* Cipher key and iv length */ - EVP_CIPHER_CTX outctx; /* Cipher context */ - - const EVP_MD *indigest; /* Digest type for MAC of packets received from him */ - int inmaclength; /* Length of MAC */ - - const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/ - int outmaclength; /* Length of MAC */ + cipher_t incipher; /* Cipher for UDP packets */ + digest_t indigest; /* Digest for UDP packets */ + + cipher_t outcipher; /* Cipher for UDP packets */ + digest_t outdigest; /* Digest for UDP packets */ int incompression; /* Compressionlevel, 0 = no compression */ int outcompression; /* Compressionlevel, 0 = no compression */ + int distance; struct node_t *nexthop; /* nearest node from us to him */ struct node_t *via; /* next hop for UDP packets */ - avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ + splay_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ - avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ + splay_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */ uint32_t sent_seqno; /* Sequence number last sent to this node */ uint32_t received_seqno; /* Sequence number last received from this node */ - unsigned char late[16]; /* Bitfield marking late packets */ + uint32_t farfuture; /* Packets in a row that have arrived from the far future */ + unsigned char* late; /* Bitfield marking late packets */ length_t mtu; /* Maximum size of packets to send to this node */ length_t minmtu; /* Probed minimum MTU */ length_t maxmtu; /* Probed maximum MTU */ int mtuprobes; /* Number of probes */ - event_t *mtuevent; /* Probe event */ + struct event mtuevent; /* Probe event */ } node_t; extern struct node_t *myself; -extern avl_tree_t *node_tree; -extern avl_tree_t *node_udp_tree; +extern splay_tree_t *node_tree; +extern splay_tree_t *node_udp_tree; extern void init_nodes(void); extern void exit_nodes(void); @@@ -90,7 -99,7 +91,7 @@@ extern void node_add(node_t *) extern void node_del(node_t *); extern node_t *lookup_node(char *); extern node_t *lookup_node_udp(const sockaddr_t *); +extern bool dump_nodes(struct connection_t *); extern void update_node_udp(node_t *, const sockaddr_t *); -extern void dump_nodes(void); #endif /* __TINC_NODE_H__ */ diff --combined src/process.c index 77454f75,0007943a..d588a3fd --- a/src/process.c +++ b/src/process.c @@@ -22,11 -22,11 +22,11 @@@ #include "conf.h" #include "connection.h" +#include "control.h" #include "device.h" #include "edge.h" #include "logger.h" #include "node.h" -#include "pidfile.h" #include "process.h" #include "subnet.h" #include "utils.h" @@@ -34,16 -34,21 +34,16 @@@ /* If zero, don't detach from the terminal. */ bool do_detach = true; -bool sighup = false; bool sigalrm = false; extern char *identname; -extern char *pidfilename; extern char **g_argv; extern bool use_logfile; -extern volatile bool running; #ifndef HAVE_MINGW sigset_t emptysigset; #endif -static int saved_debug_level = -1; - static void memory_full(int size) { logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size); exit(1); @@@ -166,11 -171,19 +166,11 @@@ DWORD WINAPI controlhandler(DWORD reque return ERROR_CALL_NOT_IMPLEMENTED; } - if(running) { - running = false; - status.dwWaitHint = 30000; - status.dwCurrentState = SERVICE_STOP_PENDING; - SetServiceStatus(statushandle, &status); - return NO_ERROR; - } else { - status.dwWaitHint = 0; - status.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(statushandle, &status); - exit(1); - } - + event_loopexit(NULL); + status.dwWaitHint = 30000; + status.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(statushandle, &status); + return NO_ERROR; } VOID WINAPI run_service(DWORD argc, LPTSTR* argv) { @@@ -227,13 -240,86 +227,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) { 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 @@@ -244,6 -330,13 +244,6 @@@ strerror(errno)); return false; } - - /* Now UPDATE the pid in the pidfile, because we changed it... */ - - if(!write_pid(pidfilename)) { - fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno)); - return false; - } #else if(!statushandle) exit(install_service()); @@@ -263,7 -356,7 +263,7 @@@ bool execute_script(const char *name, char **envp) { #ifdef HAVE_SYSTEM int status, len; - char *scriptname, *p; + char *scriptname; int i; #ifndef HAVE_MINGW @@@ -304,7 -397,7 +304,7 @@@ for(i = 0; envp[i]; i++) { char *e = strchr(envp[i], '='); if(e) { - p = alloca(e - envp[i] + 1); + char p[e - envp[i] + 1]; strncpy(p, envp[i], e - envp[i]); p[e - envp[i]] = '\0'; putenv(p); @@@ -342,6 -435,22 +342,6 @@@ */ #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, strsignal(a)); @@@ -362,7 -471,7 +362,7 @@@ 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."); @@@ -370,6 -479,48 +370,6 @@@ } } -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)); } @@@ -382,11 -533,19 +382,11 @@@ static struct int signal; void (*handler)(int); } sighandlers[] = { - {SIGHUP, sighup_handler}, - {SIGTERM, sigterm_handler}, - {SIGQUIT, sigquit_handler}, {SIGSEGV, fatal_signal_handler}, {SIGBUS, fatal_signal_handler}, {SIGILL, fatal_signal_handler}, {SIGPIPE, ignore_signal_handler}, - {SIGINT, sigint_handler}, - {SIGUSR1, sigusr1_handler}, - {SIGUSR2, sigusr2_handler}, {SIGCHLD, ignore_signal_handler}, - {SIGALRM, sigalrm_handler}, - {SIGWINCH, sigwinch_handler}, {0, NULL} }; #endif @@@ -413,7 -572,7 +413,7 @@@ void setup_signals(void) /* If we didn't detach, allow coredumps */ if(!do_detach) - sighandlers[3].handler = SIG_DFL; + sighandlers[0].handler = SIG_DFL; /* Then, for each known signal that we want to catch, assign a handler to the signal, with error checking this time. */ diff --combined src/protocol_key.c index f57dc2ea,fbd7cabb..ec5a690f --- a/src/protocol_key.c +++ b/src/protocol_key.c @@@ -20,10 -20,12 +20,10 @@@ #include "system.h" -#include -#include -#include - -#include "avl_tree.h" +#include "splay_tree.h" +#include "cipher.h" #include "connection.h" +#include "crypto.h" #include "logger.h" #include "net.h" #include "netutl.h" @@@ -32,10 -34,10 +32,10 @@@ #include "utils.h" #include "xalloc.h" -bool mykeyused = false; +static bool mykeyused = false; void send_key_changed() { - avl_node_t *node; + splay_node_t *node; connection_t *c; send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name); @@@ -49,17 -51,22 +49,17 @@@ } } -bool key_changed_h(connection_t *c) { +bool key_changed_h(connection_t *c, char *request) { char name[MAX_STRING_SIZE]; node_t *n; - 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", c->name, c->hostname); return false; } - if(!check_id(name)) { - logger(LOG_ERR, "Got bad %s from %s (%s): %s", "KEY_CHANGED", c->name, c->hostname, "invalid name"); - return false; - } - - if(seen_request(c->buffer)) + if(seen_request(request)) return true; n = lookup_node(name); @@@ -76,7 -83,7 +76,7 @@@ /* Tell the others */ if(!tunnelserver) - forward_request(c); + forward_request(c, request); return true; } @@@ -85,12 -92,12 +85,12 @@@ bool send_req_key(node_t *to) return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name); } -bool req_key_h(connection_t *c) { +bool req_key_h(connection_t *c, char *request) { char from_name[MAX_STRING_SIZE]; char to_name[MAX_STRING_SIZE]; node_t *from, *to; - 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, c->hostname); return false; @@@ -120,7 -127,6 +120,7 @@@ /* Check if this key request is for us */ if(to == myself) { /* Yes, send our own key back */ + send_ans_key(from); } else { if(tunnelserver) @@@ -132,50 -138,55 +132,50 @@@ return true; } - send_request(to->nexthop->connection, "%s", c->buffer); + send_request(to->nexthop->connection, "%s", request); } return true; } bool send_ans_key(node_t *to) { - // Set key parameters - to->incipher = myself->incipher; - to->inkeylength = myself->inkeylength; - to->indigest = myself->indigest; - to->inmaclength = myself->inmaclength; + size_t keylen = cipher_keylength(&myself->incipher); + char key[keylen * 2 + 1]; + + 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); + digest_set_key(&to->indigest, key, keylen); - // 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; to->received_seqno = 0; - memset(to->late, 0, sizeof(to->late)); + if(replaywin) memset(to->late, 0, replaywin); - // Convert to hexadecimal and send - char key[2 * to->inkeylength + 1]; - bin2hex(to->inkey, key, to->inkeylength); - key[to->inkeylength * 2] = '\0'; - - return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY, - myself->name, to->name, key, - to->incipher ? to->incipher->nid : 0, - to->indigest ? to->indigest->type : 0, to->inmaclength, - to->incompression); + return send_request(to->nexthop->connection, "%d %s %s %s %d %d %zu %d", ANS_KEY, + myself->name, to->name, key, + cipher_get_nid(&to->incipher), + digest_get_nid(&to->indigest), + digest_length(&to->indigest), + to->incompression); } -bool ans_key_h(connection_t *c) { +bool ans_key_h(connection_t *c, char *request) { char from_name[MAX_STRING_SIZE]; char to_name[MAX_STRING_SIZE]; char key[MAX_STRING_SIZE]; - char address[MAX_STRING_SIZE] = ""; - char port[MAX_STRING_SIZE] = ""; - int cipher, digest, maclength, compression; + char address[MAX_STRING_SIZE] = ""; + char port[MAX_STRING_SIZE] = ""; + int cipher, digest, maclength, compression, keylen; node_t *from, *to; - if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING, + if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING, from_name, to_name, key, &cipher, &digest, &maclength, &compression, address, port) < 7) { logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name, @@@ -212,7 -223,7 +212,7 @@@ if(!to->status.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; } @@@ -220,37 -231,60 +220,37 @@@ char *address, *port; ifdebug(PROTOCOL) logger(LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name); sockaddr2str(&from->address, &address, &port); - send_request(to->nexthop->connection, "%s %s %s", c->buffer, address, port); + send_request(to->nexthop->connection, "%s %s %s", request, address, port); free(address); free(port); 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); - /* 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 true; - } - - 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 true; - } - } 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); + return false; } - from->outmaclength = maclength; + keylen = strlen(key) / 2; - if(digest) { - from->outdigest = EVP_get_digestbynid(digest); + if(keylen != cipher_keylength(&from->outcipher)) { + 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 true; - } + if(!digest_open_by_nid(&from->outdigest, digest, maclength)) { + 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 true; - } - } else { - from->outdigest = NULL; + if(maclength != digest_length(&from->outdigest)) { + logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname); + return false; } if(compression < 0 || compression > 11) { @@@ -260,11 -294,12 +260,11 @@@ from->outcompression = compression; - if(from->outcipher) - if(!EVP_EncryptInit_ex(&from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + from->outcipher->key_len)) { - logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s", - from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL)); - return true; - } + /* Update our copy of the origin's packet key */ + + hex2bin(key, key, keylen); + cipher_set_key(&from->outcipher, key, false); + digest_set_key(&from->outdigest, key, keylen); from->status.validkey = true; from->sent_seqno = 0;