]> git.meshlink.io Git - meshlink/blobdiff - src/net_packet.c
Merge branch 'master' of git://tinc-vpn.org/tinc into 1.1
[meshlink] / src / net_packet.c
index fc09957d0ec386c7eb6668586ef74b4f9c5e2ec5..ded80a2fb94272bb98eaf5a9bdcad34dce739007 100644 (file)
@@ -1,7 +1,9 @@
 /*
     net_packet.c -- Handles in- and outgoing VPN packets
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2010 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2011 Guus Sliepen <guus@tinc-vpn.org>
+                  2010      Timothy Redaelli <timothy@redaelli.eu>
+                  2010      Brandon Black <blblack@gmail.com>
 
     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
@@ -61,6 +63,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
@@ -83,16 +87,21 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
        }
 
        if(n->mtuprobes > 32) {
+               if(!n->minmtu) {
+                       n->mtuprobes = 31;
+                       timeout = pinginterval;
+                       goto end;
+               }
+
                ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
                n->mtuprobes = 1;
                n->minmtu = 0;
                n->maxmtu = MTU;
        }
 
-       if(n->mtuprobes >= 10 && !n->minmtu) {
+       if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) {
                ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
-               n->mtuprobes = 0;
-               return;
+               n->mtuprobes = 31;
        }
 
        if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
@@ -148,12 +157,17 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
                packet->data[0] = 1;
                send_udppacket(n, packet);
        } else {
+               if(n->mtuprobes > 30) {
+                       if(n->minmtu)
+                               n->mtuprobes = 30;
+                       else
+                               n->mtuprobes = 1;
+               }
+
                if(len > n->maxmtu)
                        len = n->maxmtu;
                if(n->minmtu < len)
                        n->minmtu = len;
-               if(n->mtuprobes > 30)
-                       n->mtuprobes = 30;
        }
 }
 
@@ -283,25 +297,32 @@ 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) {
+                               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;
@@ -356,7 +377,9 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
        vpn_packet_t *outpkt;
        int origlen;
        size_t outlen;
+#if defined(SOL_IP) && defined(IP_TOS)
        static int priority = 0;
+#endif
        int origpriority;
        int sock;
 
@@ -368,6 +391,8 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
        /* 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);
@@ -537,7 +562,9 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
 
 static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
        splay_node_t *node;
-       node_t *n, *found = NULL;
+       edge_t *e;
+       node_t *n = NULL;
+       bool hard = false;
        static time_t last_hard_try = 0;
        time_t now = time(NULL);
 
@@ -546,19 +573,29 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
        else
                last_hard_try = now;
 
-       for(node = node_tree->head; node; node = node->next) {
-               n = node->data;
+       for(node = edge_weight_tree->head; node; node = node->next) {
+               e = node->data;
 
-               if(n == myself || !n->status.reachable || !digest_active(&n->indigest))
+               if(e->to == myself)
                        continue;
 
-               if(try_mac(n, pkt)) {
-                       found = n;
-                       break;
+               if(sockaddrcmp_noport(from, &e->address)) {
+                       if(last_hard_try == now)
+                               continue;
+                       hard = true;
                }
+
+               if(!try_mac(e->to, pkt))
+                       continue;
+
+               n = e->to;
+               break;
        }
 
-       return found;
+       if(hard)
+               last_hard_try = now;
+
+       return n;
 }
 
 void handle_incoming_vpn_data(int sock, short events, void *data) {