Send gratuitous type 2 probe replies.
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 11 Jan 2015 16:44:50 +0000 (17:44 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 11 Jan 2015 16:44:50 +0000 (17:44 +0100)
If we receive any traffic from another node, we periodically send back a
gratuitous type 2 probe reply with the maximum received packet length.
On the other node, this causes the udp and perhaps mtu probe timers to
be reset, so it does not need to send a probe request. Gratuitous probe
replies from another node also count as received traffic for this
purpose, so for nodes that also have a meta-connection, UDP keepalive
packets in principle can now solely be type 2 replies. This reduces the
amount of probe traffic even more.

To work, gratuitous replies should be sent slightly more often than
udp_discovery_keepalive_interval, so probe requests won't be triggered.
This also means that the timer resolution must be smaller than the
difference between the two, and at the moment it's kind of a hack.

src/net.c
src/net_packet.c
src/node.h

index 5f3f6e7..5b32bd4 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -174,7 +174,7 @@ static void timeout_handler(void *data) {
 
        }
 
 
        }
 
-       timeout_set(data, &(struct timeval){pingtimeout, rand() % 100000});
+       timeout_set(data, &(struct timeval){1, rand() % 100000});
 }
 
 static void periodic_handler(void *data) {
 }
 
 static void periodic_handler(void *data) {
index 16f8e5e..e9e2172 100644 (file)
@@ -67,7 +67,7 @@ static void send_udppacket(node_t *, vpn_packet_t *);
 unsigned replaywin = 16;
 bool localdiscovery = true;
 bool udp_discovery = true;
 unsigned replaywin = 16;
 bool localdiscovery = true;
 bool udp_discovery = true;
-int udp_discovery_keepalive_interval = 9;
+int udp_discovery_keepalive_interval = 10;
 int udp_discovery_interval = 2;
 int udp_discovery_timeout = 30;
 
 int udp_discovery_interval = 2;
 int udp_discovery_timeout = 30;
 
@@ -103,24 +103,22 @@ static void udp_probe_timeout_handler(void *data) {
 
 static void send_udp_probe_reply(node_t *n, vpn_packet_t *packet, length_t len) {
        if(!n->status.sptps && !n->status.validkey) {
 
 static void send_udp_probe_reply(node_t *n, vpn_packet_t *packet, length_t len) {
        if(!n->status.sptps && !n->status.validkey) {
-               // But not if we don't have his key.
-               logger(DEBUG_TRAFFIC, LOG_INFO, "Got UDP probe request from %s (%s) but we don't have his key yet", n->name, n->hostname);
+               logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP probe reply to %s (%s) but we don't have his key yet", n->name, n->hostname);
                return;
        }
 
                return;
        }
 
-       logger(DEBUG_TRAFFIC, LOG_INFO, "Got UDP probe request %d from %s (%s)", packet->len, n->name, n->hostname);
-
        /* Type 2 probe replies were introduced in protocol 17.3 */
        if ((n->options >> 24) >= 3) {
        /* Type 2 probe replies were introduced in protocol 17.3 */
        if ((n->options >> 24) >= 3) {
-               uint8_t *data = DATA(packet);
-               *data++ = 2;
-               uint16_t len16 = htons(MAX(len, n->maxrecentlen));
-               n->maxrecentlen = 0;
-               memcpy(data, &len16, 2);
+               DATA(packet)[0] = 2;
+               uint16_t len16 = htons(len);
+               memcpy(DATA(packet) + 1, &len16, 2);
                packet->len = MIN_PROBE_SIZE;
                packet->len = MIN_PROBE_SIZE;
+               logger(DEBUG_TRAFFIC, LOG_INFO, "Sending type 2 probe reply length %u to %s (%s)", len, n->name, n->hostname);
+
        } else {
                /* Legacy protocol: n won't understand type 2 probe replies. */
                DATA(packet)[0] = 1;
        } else {
                /* Legacy protocol: n won't understand type 2 probe replies. */
                DATA(packet)[0] = 1;
+               logger(DEBUG_TRAFFIC, LOG_INFO, "Sending type 1 probe reply length %u to %s (%s)", len, n->name, n->hostname);
        }
 
        /* Temporarily set udp_confirmed, so that the reply is sent
        }
 
        /* Temporarily set udp_confirmed, so that the reply is sent
@@ -134,7 +132,7 @@ static void send_udp_probe_reply(node_t *n, vpn_packet_t *packet, length_t len)
 
 static void udp_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
        if(!DATA(packet)[0]) {
 
 static void udp_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
        if(!DATA(packet)[0]) {
-               /* It's a probe request, send back a reply */
+               logger(DEBUG_TRAFFIC, LOG_INFO, "Got UDP probe request %d from %s (%s)", packet->len, n->name, n->hostname);
                return send_udp_probe_reply(n, packet, len);
        }
 
                return send_udp_probe_reply(n, packet, len);
        }
 
@@ -152,6 +150,9 @@ static void udp_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
           packet used. */
        n->status.udp_confirmed = true;
 
           packet used. */
        n->status.udp_confirmed = true;
 
+       // Reset the UDP ping timer.
+       n->udp_ping_sent = now;
+
        if(udp_discovery) {
                timeout_del(&n->udp_ping_timeout);
                timeout_add(&n->udp_ping_timeout, &udp_probe_timeout_handler, n, &(struct timeval){udp_discovery_timeout, 0});
        if(udp_discovery) {
                timeout_del(&n->udp_ping_timeout);
                timeout_add(&n->udp_ping_timeout, &udp_probe_timeout_handler, n, &(struct timeval){udp_discovery_timeout, 0});
@@ -282,7 +283,11 @@ static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
                        return false;
                }
                inpkt->offset += 2 * sizeof(node_id_t);
                        return false;
                }
                inpkt->offset += 2 * sizeof(node_id_t);
-               if(!sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len - 2 * sizeof(node_id_t))) {
+               n->status.udppacket = true;
+               bool result = sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len - 2 * sizeof(node_id_t));
+               n->status.udppacket = false;
+
+               if(!result) {
                        logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname);
                        return false;
                }
                        logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname);
                        return false;
                }
@@ -766,8 +771,14 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t
        inpkt.offset = DEFAULT_PACKET_OFFSET;
 
        if(type == PKT_PROBE) {
        inpkt.offset = DEFAULT_PACKET_OFFSET;
 
        if(type == PKT_PROBE) {
+               if(!from->status.udppacket) {
+                       logger(DEBUG_ALWAYS, LOG_ERR, "Got SPTPS PROBE packet from %s (%s) via TCP", from->name, from->hostname);
+                       return false;
+               }
                inpkt.len = len;
                memcpy(DATA(&inpkt), data, len);
                inpkt.len = len;
                memcpy(DATA(&inpkt), data, len);
+               if(inpkt.len > from->maxrecentlen)
+                       from->maxrecentlen = inpkt.len;
                udp_probe_h(from, &inpkt, len);
                return true;
        }
                udp_probe_h(from, &inpkt, len);
                return true;
        }
@@ -819,6 +830,9 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t
                }
        }
 
                }
        }
 
+       if(from->status.udppacket && inpkt.len > from->maxrecentlen)
+               from->maxrecentlen = inpkt.len;
+
        receive_packet(from, &inpkt);
        return true;
 }
        receive_packet(from, &inpkt);
        return true;
 }
@@ -863,6 +877,28 @@ static void try_udp(node_t* n) {
        if(!udp_discovery)
                return;
 
        if(!udp_discovery)
                return;
 
+       /* Send gratuitous probe replies to 1.1 nodes. */
+
+       if((n->options >> 24) >= 3 && n->status.udp_confirmed) {
+               struct timeval ping_tx_elapsed;
+               timersub(&now, &n->udp_reply_sent, &ping_tx_elapsed);
+
+               if(ping_tx_elapsed.tv_sec >= udp_discovery_keepalive_interval - 1) {
+                       n->udp_reply_sent = now;
+                       if(n->maxrecentlen) {
+                               vpn_packet_t pkt;
+                               pkt.len = n->maxrecentlen;
+                               pkt.offset = DEFAULT_PACKET_OFFSET;
+                               memset(DATA(&pkt), 0, 14);
+                               randomize(DATA(&pkt) + 14, MIN_PROBE_SIZE - 14);
+                               send_udp_probe_reply(n, &pkt, pkt.len);
+                               n->maxrecentlen = 0;
+                       }
+               }
+       }
+
+       /* Probe request */
+
        struct timeval ping_tx_elapsed;
        timersub(&now, &n->udp_ping_sent, &ping_tx_elapsed);
 
        struct timeval ping_tx_elapsed;
        timersub(&now, &n->udp_ping_sent, &ping_tx_elapsed);
 
index 03bd020..5fe6dfa 100644 (file)
@@ -38,6 +38,7 @@ typedef struct node_status_t {
        unsigned int sptps:1;                   /* 1 if this node supports SPTPS */
        unsigned int udp_confirmed:1;           /* 1 if the address is one that we received UDP traffic on */
        unsigned int send_locally:1;            /* 1 if the next UDP packet should be sent on the local network */
        unsigned int sptps:1;                   /* 1 if this node supports SPTPS */
        unsigned int udp_confirmed:1;           /* 1 if the address is one that we received UDP traffic on */
        unsigned int send_locally:1;            /* 1 if the next UDP packet should be sent on the local network */
+       unsigned int udppacket:1;               /* 1 if the most recently received packet was UDP */
        unsigned int validkey_in;               /* 1 if we have sent a valid key to him */
        unsigned int unused:22;
 } node_status_t;
        unsigned int validkey_in;               /* 1 if we have sent a valid key to him */
        unsigned int unused:22;
 } node_status_t;
@@ -88,6 +89,7 @@ typedef struct node_t {
        uint32_t farfuture;                     /* Packets in a row that have arrived from the far future */
        unsigned char* late;                    /* 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 */
 
+       struct timeval udp_reply_sent;          /* Last time a (gratuitous) UDP probe reply was sent */
        struct timeval udp_ping_sent;           /* Last time a UDP probe was sent */
        timeout_t udp_ping_timeout;             /* Ping timeout event */
 
        struct timeval udp_ping_sent;           /* Last time a UDP probe was sent */
        timeout_t udp_ping_timeout;             /* Ping timeout event */