From ae5b56c03d1e1af7561d7f1d1d8a333c3a9691ff Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 11 Jan 2015 17:44:50 +0100 Subject: [PATCH] Send gratuitous type 2 probe replies. 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 | 2 +- src/net_packet.c | 60 ++++++++++++++++++++++++++++++++++++++---------- src/node.h | 2 ++ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/net.c b/src/net.c index 5f3f6e78..5b32bd40 100644 --- 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) { diff --git a/src/net_packet.c b/src/net_packet.c index 16f8e5ed..e9e2172c 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -67,7 +67,7 @@ static void send_udppacket(node_t *, vpn_packet_t *); 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; @@ -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) { - // 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; } - 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) { - 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; + 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; + 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 @@ -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]) { - /* 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); } @@ -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; + // 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}); @@ -282,7 +283,11 @@ static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) { 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; } @@ -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) { + 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); + if(inpkt.len > from->maxrecentlen) + from->maxrecentlen = inpkt.len; 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; } @@ -863,6 +877,28 @@ static void try_udp(node_t* n) { 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); diff --git a/src/node.h b/src/node.h index 03bd0208..5fe6dfa6 100644 --- a/src/node.h +++ b/src/node.h @@ -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 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; @@ -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 */ + 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 */ -- 2.20.1