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.
- 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) {
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;
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);
- 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
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);
}
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});
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;
}
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;
}
+ if(from->status.udppacket && inpkt.len > from->maxrecentlen)
+ from->maxrecentlen = inpkt.len;
+
receive_packet(from, &inpkt);
return true;
}
receive_packet(from, &inpkt);
return true;
}
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);
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;
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 */