Configurable ReplayWindow size, zero disables
authorBrandon L Black <blblack@gmail.com>
Sat, 13 Nov 2010 18:05:50 +0000 (12:05 -0600)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 13 Nov 2010 20:25:46 +0000 (21:25 +0100)
doc/tinc.conf.5.in
src/net.h
src/net_packet.c
src/net_setup.c
src/node.c
src/node.h
src/protocol_key.c

index 66aee4b6e59900d89c0c9285f9bf5b980f14fb25..ce690308c05bec244d655b30e624ae47312a2a6a 100644 (file)
@@ -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
index 8c92fc3e9687725f8db7b3ca301a3ec9a92403d3..55856e2b57c84618325dc7064cdd16f2dc697a26 100644 (file)
--- 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;
index 44ab55d42c8a550f1fddad9a36c88aec0c813377..b35f72d4aa744657ab95691cd6adf6b5d9fb07d7 100644 (file)
@@ -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;
index e7d3e40bd9f1e15df3a27cdaf94a9bb570a99f4f..b46d1ae56096df27db4602aef0bf1b2bac391fa8 100644 (file)
@@ -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;
index b323dca3f3c52de8bdde53811c4adda33757e416..a533cee61ffe8e72441bd4bb8bb70fab44b0a276 100644 (file)
@@ -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);
index 83e89c7d183c05c6a625a6c524832f014f2d6a13..de0f8c830bdec2bb80a9253c3ed3176dd581be90 100644 (file)
@@ -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 */
index b326b8d70a1fb75657f95080dec51079fa876ab1..fbd7cabb8babafdd89fd09ac16a4fa46254bc8f8 100644 (file)
@@ -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];