#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
+/* The minimum size of a probe is 14 bytes, but since we normally use CBC mode
+ encryption, we can add a few extra random bytes without increasing the
+ resulting packet size. */
+#define MIN_PROBE_SIZE 18
+
int keylifetime = 0;
#ifdef HAVE_LZO
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
logger(DEBUG_TRAFFIC, LOG_INFO, "Too much time has elapsed since last UDP ping response from %s (%s), stopping UDP communication", n->name, n->hostname);
n->status.udp_confirmed = false;
+ n->maxrecentlen = 0;
n->mtuprobes = 0;
n->minmtu = 0;
n->maxmtu = MTU;
static void udp_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
if(!DATA(packet)[0]) {
- logger(DEBUG_TRAFFIC, LOG_INFO, "Got UDP probe request %d from %s (%s)", packet->len, n->name, n->hostname);
-
/* It's a probe request, send back a reply */
+ 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);
+ 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(len); memcpy(data, &len16, 2); data += 2;
- struct timeval now;
- gettimeofday(&now, NULL);
- uint32_t sec = htonl(now.tv_sec); memcpy(data, &sec, 4); data += 4;
- uint32_t usec = htonl(now.tv_usec); memcpy(data, &usec, 4); data += 4;
- packet->len = 14; // Minimum size for any probe packet.
+ packet->len = MIN_PROBE_SIZE;
} else {
/* Legacy protocol: n won't understand type 2 probe replies. */
DATA(packet)[0] = 1;
timeout_add(&n->udp_ping_timeout, &udp_probe_timeout_handler, n, &(struct timeval){udp_discovery_timeout, 0});
}
- if(probelen >= n->maxmtu + 1) {
+ if(probelen > n->maxmtu) {
logger(DEBUG_TRAFFIC, LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname);
+ n->minmtu = probelen;
n->maxmtu = MTU;
/* Set mtuprobes to 1 so that try_mtu() doesn't reset maxmtu */
n->mtuprobes = 1;
return;
+ } else if(n->mtuprobes < 0 && probelen == n->maxmtu) {
+ /* We got a maxmtu sized packet, confirming the PMTU is still valid. */
+ n->mtuprobes = -1;
}
/* If applicable, raise the minimum supported MTU */
- if(probelen > n->maxmtu)
- probelen = n->maxmtu;
if(n->minmtu < probelen) {
n->minmtu = probelen;
try_fix_mtu(n);
}
-
- /* Calculate RTT.
- The RTT is the time between the MTU probe burst was sent and the first
- reply is received.
- */
-
- struct timeval now, diff;
- gettimeofday(&now, NULL);
- timersub(&now, &n->probe_time, &diff);
-
- struct timeval probe_timestamp = now;
- if (DATA(packet)[0] == 2 && packet->len >= 11) {
- uint32_t sec; memcpy(&sec, DATA(packet) + 3, 4);
- uint32_t usec; memcpy(&usec, DATA(packet) + 7, 4);
- probe_timestamp.tv_sec = ntohl(sec);
- probe_timestamp.tv_usec = ntohl(usec);
- }
-
- n->probe_counter++;
-
- if(n->probe_counter == 1) {
- n->rtt = diff.tv_sec + diff.tv_usec * 1e-6;
- n->probe_time = probe_timestamp;
- logger(DEBUG_TRAFFIC, LOG_DEBUG, "%s (%s) RTT %.2f ms, rx packet loss %.2f %%", n->name, n->hostname, n->rtt * 1e3, n->packetloss * 1e2);
- }
}
}
origlen -= MTU/64 + 20;
}
+ if(inpkt->len > n->maxrecentlen)
+ n->maxrecentlen = inpkt->len;
+
inpkt->priority = 0;
if(!DATA(inpkt)[12] && !DATA(inpkt)[13])
int interval = n->status.udp_confirmed ? udp_discovery_keepalive_interval : udp_discovery_interval;
if(ping_tx_elapsed.tv_sec >= interval) {
- send_udp_probe_packet(n, MAX(n->minmtu, 16));
+ send_udp_probe_packet(n, MIN_PROBE_SIZE);
n->udp_ping_sent = now;
if(localdiscovery && !n->status.udp_confirmed && n->prevedge) {
n->status.send_locally = true;
- send_udp_probe_packet(n, 16);
+ send_udp_probe_packet(n, MIN_PROBE_SIZE);
n->status.send_locally = false;
}
}
return;
if(udp_discovery && !n->status.udp_confirmed) {
+ n->maxrecentlen = 0;
n->mtuprobes = 0;
n->minmtu = 0;
n->maxmtu = MTU;
/* mtuprobes == 0..19: initial discovery, send bursts with 1 second interval, mtuprobes++
mtuprobes == 20: fix MTU, and go to -1
- mtuprobes == -1: send one >maxmtu probe every pingtimeout */
+ mtuprobes == -1: send one maxmtu and one maxmtu+1 probe every pinginterval
+ mtuprobes ==-2..-3: send one maxmtu probe every second
+ mtuprobes == -4: maxmtu no longer valid, reset minmtu and maxmtu and go to 0 */
struct timeval elapsed;
- timersub(&now, &n->probe_sent_time, &elapsed);
+ timersub(&now, &n->mtu_ping_sent, &elapsed);
if(n->mtuprobes >= 0) {
if(n->mtuprobes != 0 && elapsed.tv_sec == 0 && elapsed.tv_usec < 333333)
return;
} else {
- if(elapsed.tv_sec < pingtimeout)
- return;
+ if(n->mtuprobes < -1) {
+ if(elapsed.tv_sec < 1)
+ return;
+ } else {
+ if(elapsed.tv_sec < pinginterval)
+ return;
+ }
}
+ n->mtu_ping_sent = now;
+
try_fix_mtu(n);
+ if(n->mtuprobes < -3) {
+ /* We lost three MTU probes, restart discovery */
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Decrease in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname);
+ n->mtuprobes = 0;
+ n->minmtu = 0;
+ }
+
if(n->mtuprobes < 0) {
- /* After the initial discovery, we only send one >maxmtu probe
- to detect PMTU increases. */
- if(n->maxmtu + 1 < MTU)
+ /* After the initial discovery, we only send one maxmtu and one
+ maxmtu+1 probe to detect PMTU increases. */
+ send_udp_probe_packet(n, n->maxmtu);
+ if(n->mtuprobes == -1 && n->maxmtu + 1 < MTU)
send_udp_probe_packet(n, n->maxmtu + 1);
+ n->mtuprobes--;
} else {
/* Before initial discovery begins, set maxmtu to the most likely value.
If it's underestimated, we will correct it after initial discovery. */
if(n->mtuprobes >= 0)
n->mtuprobes++;
}
-
- n->probe_counter = 0;
- n->probe_sent_time = now;
- n->probe_time = now;
-
- /* Calculate the packet loss of incoming traffic by comparing the rate of
- packets received to the rate with which the sequence number has increased.
- TODO: this is unrelated to PMTU discovery - it should be moved elsewhere.
- */
-
- if(n->received > n->prev_received)
- n->packetloss = 1.0 - (n->received - n->prev_received) / (float)(n->received_seqno - n->prev_received_seqno);
- else
- n->packetloss = n->received_seqno <= n->prev_received_seqno;
-
- n->prev_received_seqno = n->received_seqno;
- n->prev_received = n->received;
}
/* These functions try to establish a tunnel to a node (or its relay) so that
idle.
*/
-static void try_tx_sptps(node_t *n) {
+static void try_tx_sptps(node_t *n, bool mtu) {
/* If n is a TCP-only neighbor, we'll only use "cleartext" PACKET
messages anyway, so there's no need for SPTPS at all. */
/* If we do have a relay, try everything with that one instead. */
if(via != n)
- return try_tx_sptps(via);
+ return try_tx_sptps(via, mtu);
try_udp(n);
- try_mtu(n);
+ if(mtu)
+ try_mtu(n);
}
-static void try_tx_legacy(node_t *n) {
+static void try_tx_legacy(node_t *n, bool mtu) {
/* Does he have our key? If not, send one. */
if(!n->status.validkey_in)
}
try_udp(n);
- try_mtu(n);
+ if(mtu)
+ try_mtu(n);
+}
+
+void try_tx(node_t *n, bool mtu) {
+ if(n->status.sptps)
+ try_tx_sptps(n, mtu);
+ else
+ try_tx_legacy(n, mtu);
}
void send_packet(node_t *n, vpn_packet_t *packet) {
if(n->status.sptps) {
send_sptps_packet(n, packet);
- try_tx_sptps(n);
+ try_tx_sptps(n, true);
return;
}
}
send_udppacket(via, packet);
- try_tx_legacy(via);
+ try_tx_legacy(via, true);
}
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {