Brandon L Black
2010-Nov-13 18:05 UTC
[PATCH 1/4] Experimental IFF_ONE_QUEUE support for Linux
--- doc/tinc.conf.5.in | 3 +++ src/linux/device.c | 7 +++++++ 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 2bfd5fe..01f7f81 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -255,6 +255,9 @@ a lookup if your DNS server is not responding. This does not affect resolving hostnames to IP addresses from the host configuration files. +.It Va IffOneQueue Li = yes | no Po no Pc Bq experimental +(Linux only) Set IFF_ONE_QUEUE flag on TUN/TAP devices. + .It Va Interface Li = Ar interface Defines the name of the interface corresponding to the virtual network device. Depending on the operating system and the type of device this may or may not actually set the name of the interface. diff --git a/src/linux/device.c b/src/linux/device.c index 6c828c0..0632d51 100644 --- a/src/linux/device.c +++ b/src/linux/device.c @@ -52,6 +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); @@ -84,6 +85,12 @@ bool setup_device(void) { 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); -- 1.7.3.2
Brandon L Black
2010-Nov-13 18:05 UTC
[PATCH 2/4] Configurable SO_RCVBUF/SO_SNDBUF for the UDP socket
--- doc/tinc.conf.5.in | 8 ++++++++ src/net.h | 2 ++ src/net_setup.c | 14 ++++++++++++++ src/net_socket.c | 8 ++++++++ 4 files changed, 32 insertions(+), 0 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 01f7f81..66aee4b 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -356,6 +356,14 @@ and will only allow connections with nodes for which host config files are prese .Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ directory. Setting this options also implicitly sets StrictSubnets. + +.It Va UDPRcvBuf Li = Ar bytes Pq OS default +Sets the socket receive buffer size for the UDP socket, in bytes. +If unset, the default buffer size will be used by the operating system. + +.It Va UDPSndBuf Li = Ar bytes Pq OS default +Sets the socket send buffer size for the UDP socket, in bytes. +If unset, the default buffer size will be used by the operating system. .El .Sh HOST CONFIGURATION FILES diff --git a/src/net.h b/src/net.h index eae979c..8c92fc3 100644 --- a/src/net.h +++ b/src/net.h @@ -111,6 +111,8 @@ 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; diff --git a/src/net_setup.c b/src/net_setup.c index f4e5637..e7d3e40 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -405,6 +405,20 @@ bool setup_myself(void) { } 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_string(lookup_config(config_tree, "AddressFamily"), &afname)) { if(!strcasecmp(afname, "IPv4")) addressfamily = AF_INET; diff --git a/src/net_socket.c b/src/net_socket.c index 762c0a2..20029e8 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -44,6 +44,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; @@ -261,6 +263,12 @@ int setup_vpn_in_socket(const sockaddr_t *sa) { option = 1; 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", option, 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", option, 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); -- 1.7.3.2
Brandon L Black
2010-Nov-13 18:05 UTC
[PATCH 3/4] Configurable ReplayWindow size, zero disables
--- doc/tinc.conf.5.in | 10 ++++++++++ src/net.h | 1 + src/net_packet.c | 36 ++++++++++++++++++++---------------- src/net_setup.c | 9 +++++++++ src/node.c | 1 + src/node.h | 2 +- src/protocol_key.c | 2 +- 7 files changed, 43 insertions(+), 18 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 66aee4b..ce69030 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -344,6 +344,16 @@ specified in the configuration file. When this option is used the priority of the tincd process will be adjusted. Increasing the priority may help to reduce latency and packet loss on the VPN. +.It Va ReplayWindow Li = Ar bytes Pq 16 +This is the size of the replay tracking window for each remote node, in bytes. +The window is a bitfield which tracks 1 packet per bit, so for example +the default setting of 16 will track up to 128 packets in the window. In high +bandwidth scenarios, setting this to a higher value can reduce packet loss from +the interaction of replay tracking with underlying real packet loss and/or +reordering. Setting this to zero will disable replay tracking completely and +pass all traffic, but leaves tinc vulnerable to replay-based attacks on your +traffic. + .It Va StrictSubnets Li = yes | no Po no Pc Bq experimental When this option is enabled tinc will only use Subnet statements which are present in the host config files in the local diff --git a/src/net.h b/src/net.h index 8c92fc3..55856e2 100644 --- a/src/net.h +++ b/src/net.h @@ -106,6 +106,7 @@ extern list_t *outgoing_list; 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; diff --git a/src/net_packet.c b/src/net_packet.c index 44ab55d..b35f72d 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -60,6 +60,8 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999 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 @@ -293,25 +295,27 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { 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) { + 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->late[(inpkt->seqno / 8) % sizeof(n->late)] &= ~(1 << inpkt->seqno % 8); + n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8); + } if(inpkt->seqno > n->received_seqno) n->received_seqno = inpkt->seqno; diff --git a/src/net_setup.c b/src/net_setup.c index e7d3e40..b46d1ae 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -276,6 +276,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(); @@ -419,6 +420,14 @@ bool setup_myself(void) { } } + 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; diff --git a/src/node.c b/src/node.c index b323dca..a533cee 100644 --- a/src/node.c +++ b/src/node.c @@ -54,6 +54,7 @@ void exit_nodes(void) { node_t *new_node(void) { 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); diff --git a/src/node.h b/src/node.h index 83e89c7..de0f8c8 100644 --- a/src/node.h +++ b/src/node.h @@ -77,7 +77,7 @@ typedef struct node_t { 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 */ + 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 */ diff --git a/src/protocol_key.c b/src/protocol_key.c index b326b8d..fbd7cab 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -163,7 +163,7 @@ bool send_ans_key(node_t *to) { // 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]; -- 1.7.3.2
Brandon L Black
2010-Nov-13 18:05 UTC
[PATCH 4/4] Improved handling of queue-jumping packets on receive
--- src/net_packet.c | 9 +++++++-- src/node.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/net_packet.c b/src/net_packet.c index b35f72d..9c55129 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -298,9 +298,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { 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))) { @@ -313,7 +317,8 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { n->late[(i / 8) % replaywin] |= 1 << i % 8; } } - + + n->farfuture = 0; n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8); } diff --git a/src/node.h b/src/node.h index de0f8c8..7bac28e 100644 --- a/src/node.h +++ b/src/node.h @@ -77,6 +77,7 @@ typedef struct node_t { uint32_t sent_seqno; /* Sequence number last sent to this node */ uint32_t received_seqno; /* Sequence number last received from this node */ + 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 */ -- 1.7.3.2