#include "system.h"
-#include <openssl/rand.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/hmac.h>
-
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif
unsigned replaywin = 16;
bool localdiscovery = false;
+sockaddr_t localdiscovery_address;
#define MAX_SEQNO 1073741824
}
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
- logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
-
if(!packet->data[0]) {
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Got MTU probe request %d from %s (%s)", packet->len, n->name, n->hostname);
+
/* It's a probe request, send back a reply */
- packet->data[0] = 1;
+ /* Type 2 probe replies were introduced in protocol 17.3 */
+ if ((n->options >> 24) == 3) {
+ uint8_t* data = packet->data;
+ *data++ = 2;
+ uint16_t len16 = htons(len); memcpy(data, &len16, 2); data += 2;
+ } else {
+ /* Legacy protocol: n won't understand type 2 probe replies. */
+ packet->data[0] = 1;
+ }
/* Temporarily set udp_confirmed, so that the reply is sent
back exactly the way it came in. */
send_udppacket(n, packet);
n->status.udp_confirmed = udp_confirmed;
} else {
+ length_t probelen = len;
+ if (packet->data[0] == 2) {
+ if (len < 3)
+ logger(DEBUG_TRAFFIC, LOG_WARNING, "Received invalid (too short) MTU probe reply from %s (%s)", n->name, n->hostname);
+ else {
+ uint16_t probelen16; memcpy(&probelen16, packet->data + 1, 2); probelen = ntohs(probelen16);
+ }
+ }
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Got type %d MTU probe reply %d from %s (%s)", packet->data[0], probelen, n->name, n->hostname);
+
/* It's a valid reply: now we know bidirectional communication
is possible using the address and socket that the reply
packet used. */
/* If we haven't established the PMTU yet, restart the discovery process. */
if(n->mtuprobes > 30) {
- if (len == n->maxmtu + 8) {
+ if (probelen == n->maxmtu + 8) {
logger(DEBUG_TRAFFIC, LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname);
n->maxmtu = MTU;
n->mtuprobes = 10;
/* If applicable, raise the minimum supported MTU */
- if(len > n->maxmtu)
- len = n->maxmtu;
- if(n->minmtu < len)
- n->minmtu = len;
+ if(probelen > n->maxmtu)
+ probelen = n->maxmtu;
+ if(n->minmtu < probelen)
+ n->minmtu = probelen;
/* Calculate RTT and bandwidth.
The RTT is the time between the MTU probe burst was sent and the first
n->rtt = diff.tv_sec + diff.tv_usec * 1e-6;
n->probe_time = now;
} else if(n->probe_counter == 3) {
- n->bandwidth = 2.0 * len / (diff.tv_sec + diff.tv_usec * 1e-6);
+ n->bandwidth = 2.0 * probelen / (diff.tv_sec + diff.tv_usec * 1e-6);
logger(DEBUG_TRAFFIC, LOG_DEBUG, "%s (%s) RTT %.2f ms, burst bandwidth %.3f Mbit/s, rx packet loss %.2f %%", n->name, n->hostname, n->rtt * 1e3, n->bandwidth * 8e-6, n->packetloss * 1e2);
}
}
if(n->status.sptps)
return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
- if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest))
+ if(!digest_active(n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest))
return false;
- return digest_verify(&n->indigest, &inpkt->seqno, inpkt->len - n->indigest.maclength, (const char *)&inpkt->seqno + inpkt->len - n->indigest.maclength);
+ return digest_verify(n->indigest, &inpkt->seqno, inpkt->len - digest_length(n->indigest), (const char *)&inpkt->seqno + inpkt->len - digest_length(n->indigest));
}
static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
size_t outlen;
if(n->status.sptps) {
+ if(!n->sptps.state) {
+ if(!n->status.waitingforkey) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but we haven't exchanged keys yet", n->name, n->hostname);
+ send_req_key(n);
+ } else {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
+ }
+ return;
+ }
sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
return;
}
- if(!cipher_active(&n->incipher)) {
- logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
- n->name, n->hostname);
+ if(!cipher_active(n->incipher)) {
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
return;
}
/* Check packet length */
- if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
+ if(inpkt->len < sizeof inpkt->seqno + digest_length(n->indigest)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got too short packet from %s (%s)",
n->name, n->hostname);
return;
/* Check the message authentication code */
- if(digest_active(&n->indigest)) {
- inpkt->len -= n->indigest.maclength;
- if(!digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
+ if(digest_active(n->indigest)) {
+ inpkt->len -= digest_length(n->indigest);
+ if(!digest_verify(n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
return;
}
}
/* Decrypt the packet */
- if(cipher_active(&n->incipher)) {
+ if(cipher_active(n->incipher)) {
outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
- if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
+ if(!cipher_decrypt(n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
return;
}
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
vpn_packet_t outpkt;
+ if(len > sizeof outpkt.data)
+ return;
+
outpkt.len = len;
if(c->options & OPTION_TCPONLY)
outpkt.priority = 0;
logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
if(!n->status.waitingforkey)
send_req_key(n);
- else if(n->last_req_key + 10 < time(NULL)) {
+ else if(n->last_req_key + 10 < now.tv_sec) {
logger(DEBUG_ALWAYS, LOG_DEBUG, "No key from %s after 10 seconds, restarting SPTPS", n->name);
sptps_stop(&n->sptps);
n->status.waitingforkey = false;
*sock = rand() % listen_sockets;
if(listen_socket[*sock].sa.sa.sa_family == AF_INET6) {
- broadcast_ipv6.in6.sin6_port = n->prevedge->address.in.sin_port;
- broadcast_ipv6.in6.sin6_scope_id = listen_socket[*sock].sa.in6.sin6_scope_id;
- *sa = &broadcast_ipv6;
+ if(localdiscovery_address.sa.sa_family == AF_INET6) {
+ localdiscovery_address.in6.sin6_port = n->prevedge->address.in.sin_port;
+ *sa = &localdiscovery_address;
+ } else {
+ broadcast_ipv6.in6.sin6_port = n->prevedge->address.in.sin_port;
+ broadcast_ipv6.in6.sin6_scope_id = listen_socket[*sock].sa.in6.sin6_scope_id;
+ *sa = &broadcast_ipv6;
+ }
} else {
- broadcast_ipv4.in.sin_port = n->prevedge->address.in.sin_port;
- *sa = &broadcast_ipv4;
+ if(localdiscovery_address.sa.sa_family == AF_INET) {
+ localdiscovery_address.in.sin_port = n->prevedge->address.in.sin_port;
+ *sa = &localdiscovery_address;
+ } else {
+ broadcast_ipv4.in.sin_port = n->prevedge->address.in.sin_port;
+ *sa = &broadcast_ipv4;
+ }
}
}
/* Encrypt the packet */
- if(cipher_active(&n->outcipher)) {
+ if(cipher_active(n->outcipher)) {
outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
- if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
+ if(!cipher_encrypt(n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
goto end;
}
/* Add the message authentication code */
- if(digest_active(&n->outdigest)) {
- digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len);
- inpkt->len += digest_length(&n->outdigest);
+ if(digest_active(n->outdigest)) {
+ if(!digest_create(n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len)) {
+ logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
+ goto end;
+ }
+
+ inpkt->len += digest_length(n->outdigest);
}
/* Send the packet */