Import Upstream version 1.1~pre2

This commit is contained in:
Guus Sliepen 2019-08-26 13:44:49 +02:00
parent a04a7bcd67
commit 02de1cd2f1
172 changed files with 32291 additions and 25994 deletions

View file

@ -1,7 +1,7 @@
/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2005 Ivo Timmermans,
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
2010 Timothy Redaelli <timothy@redaelli.eu>
2010 Brandon Black <blblack@gmail.com>
@ -36,12 +36,14 @@
#include LZO1X_H
#endif
#include "avl_tree.h"
#include "splay_tree.h"
#include "cipher.h"
#include "conf.h"
#include "connection.h"
#include "crypto.h"
#include "digest.h"
#include "device.h"
#include "ethernet.h"
#include "event.h"
#include "graph.h"
#include "logger.h"
#include "net.h"
@ -53,7 +55,6 @@
#include "xalloc.h"
int keylifetime = 0;
int keyexpires = 0;
#ifdef HAVE_LZO
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
#endif
@ -61,33 +62,21 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
static void send_udppacket(node_t *, vpn_packet_t *);
unsigned replaywin = 16;
bool localdiscovery = false;
#define MAX_SEQNO 1073741824
/* mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
mtuprobes == 31: sleep pinginterval seconds
mtuprobes == 32: send 1 burst, sleep pingtimeout second
mtuprobes == 33: no response from other side, restart PMTU discovery process
// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
// mtuprobes == 31: sleep pinginterval seconds
// mtuprobes == 32: send 1 burst, sleep pingtimeout second
// mtuprobes == 33: no response from other side, restart PMTU discovery process
Probes are sent in batches of at least three, with random sizes between the
lower and upper boundaries for the MTU thus far discovered.
After the initial discovery, a fourth packet is added to each batch with a
size larger than the currently known PMTU, to test if the PMTU has increased.
In case local discovery is enabled, another packet is added to each batch,
which will be broadcast to the local network.
*/
void send_mtu_probe(node_t *n) {
static void send_mtu_probe_handler(int fd, short events, void *data) {
node_t *n = data;
vpn_packet_t packet;
int len, i;
int timeout = 1;
n->mtuprobes++;
n->mtuevent = NULL;
if(!n->status.reachable || !n->status.validkey) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
@ -114,12 +103,10 @@ void send_mtu_probe(node_t *n) {
}
if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
if(n->minmtu > n->maxmtu) {
if(n->minmtu > n->maxmtu)
n->minmtu = n->maxmtu;
} else {
else
n->maxmtu = n->minmtu;
}
n->mtu = n->minmtu;
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
n->mtuprobes = 31;
@ -132,32 +119,19 @@ void send_mtu_probe(node_t *n) {
timeout = pingtimeout;
}
for(i = 0; i < 4 + localdiscovery; i++) {
if(i == 0) {
if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) {
continue;
}
len = n->maxmtu + 8;
} else if(n->maxmtu <= n->minmtu) {
for(i = 0; i < 3; i++) {
if(n->maxmtu <= n->minmtu)
len = n->maxmtu;
} else {
else
len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
}
if(len < 64) {
if(len < 64)
len = 64;
}
memset(packet.data, 0, 14);
RAND_bytes(packet.data + 14, len - 14);
randomize(packet.data + 14, len - 14);
packet.len = len;
if(i >= 4 && n->mtuprobes <= 10) {
packet.priority = -1;
} else {
packet.priority = 0;
}
packet.priority = 0;
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
@ -165,14 +139,16 @@ void send_mtu_probe(node_t *n) {
}
end:
n->mtuevent = new_event();
n->mtuevent->handler = (event_handler_t)send_mtu_probe;
n->mtuevent->data = n;
n->mtuevent->time = now + timeout;
event_add(n->mtuevent);
event_add(&n->mtuevent, &(struct timeval){timeout, 0});
}
void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
void send_mtu_probe(node_t *n) {
if(!timeout_initialized(&n->mtuevent))
timeout_set(&n->mtuevent, send_mtu_probe_handler, n);
send_mtu_probe_handler(0, 0, n);
}
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
if(!packet->data[0]) {
@ -180,27 +156,16 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
send_udppacket(n, packet);
} else {
if(n->mtuprobes > 30) {
if(len == n->maxmtu + 8) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname);
n->maxmtu = MTU;
n->mtuprobes = 10;
return;
}
if(n->minmtu) {
if(n->minmtu)
n->mtuprobes = 30;
} else {
else
n->mtuprobes = 1;
}
}
if(len > n->maxmtu) {
if(len > n->maxmtu)
len = n->maxmtu;
}
if(n->minmtu < len) {
if(n->minmtu < len)
n->minmtu = len;
}
}
}
@ -214,28 +179,27 @@ static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t l
lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem);
return lzolen;
#else
return 0;
return -1;
#endif
} else if(level < 10) {
#ifdef HAVE_ZLIB
unsigned long destlen = MAXSIZE;
if(compress2(dest, &destlen, source, len, level) == Z_OK) {
if(compress2(dest, &destlen, source, len, level) == Z_OK)
return destlen;
} else
else
#endif
return 0;
return -1;
} else {
#ifdef HAVE_LZO
lzo_uint lzolen = MAXSIZE;
lzo1x_999_compress(source, len, dest, &lzolen, lzo_wrkmem);
return lzolen;
#else
return 0;
return -1;
#endif
}
return 0;
return -1;
}
static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
@ -245,25 +209,20 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
} else if(level > 9) {
#ifdef HAVE_LZO
lzo_uint lzolen = MAXSIZE;
if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK) {
if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK)
return lzolen;
} else
else
#endif
return 0;
return -1;
}
#ifdef HAVE_ZLIB
else {
unsigned long destlen = MAXSIZE;
if(uncompress(dest, &destlen, source, len) == Z_OK) {
if(uncompress(dest, &destlen, source, len) == Z_OK)
return destlen;
} else {
return 0;
}
else
return -1;
}
#endif
return -1;
@ -273,104 +232,91 @@ static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t
static void receive_packet(node_t *n, vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
packet->len, n->name, n->hostname);
packet->len, n->name, n->hostname);
n->in_packets++;
n->in_bytes += packet->len;
route(n, packet);
}
static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) {
unsigned char hmac[EVP_MAX_MD_SIZE];
if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest))
return false;
}
HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL);
return !memcmp_constant_time(hmac, (char *) &inpkt->seqno + inpkt->len - n->inmaclength, n->inmaclength);
return digest_verify(&n->indigest, &inpkt->seqno, inpkt->len - n->indigest.maclength, (const char *)&inpkt->seqno + inpkt->len - n->indigest.maclength);
}
static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
vpn_packet_t pkt1, pkt2;
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
int nextpkt = 0;
vpn_packet_t *outpkt;
int outlen, outpad;
unsigned char hmac[EVP_MAX_MD_SIZE];
vpn_packet_t *outpkt = pkt[0];
size_t outlen;
if(!n->inkey) {
if(!cipher_active(&n->incipher)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
n->name, n->hostname);
n->name, n->hostname);
return;
}
/* Check packet length */
if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)",
n->name, n->hostname);
n->name, n->hostname);
return;
}
/* Check the message authentication code */
if(n->indigest && n->inmaclength) {
inpkt->len -= n->inmaclength;
HMAC(n->indigest, n->inkey, n->inkeylength,
(unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
if(memcmp_constant_time(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)",
n->name, n->hostname);
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)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
return;
}
}
/* Decrypt the packet */
if(n->incipher) {
if(cipher_active(&n->incipher)) {
outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
if(!EVP_DecryptInit_ex(n->inctx, NULL, NULL, NULL, NULL)
|| !EVP_DecryptUpdate(n->inctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_DecryptFinal_ex(n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s): %s",
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
return;
}
outpkt->len = outlen + outpad;
outpkt->len = outlen;
inpkt = outpkt;
}
/* Check the sequence number */
inpkt->len -= sizeof(inpkt->seqno);
inpkt->len -= sizeof inpkt->seqno;
inpkt->seqno = ntohl(inpkt->seqno);
if(replaywin) {
if(inpkt->seqno != n->received_seqno + 1) {
if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
if(n->farfuture++ < replaywin >> 2) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
return;
}
ifdebug(TRAFFIC) logger(LOG_WARNING, "Lost %d packets from %s (%s)",
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
logger(LOG_WARNING, "Lost %d packets from %s (%s)",
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin);
} else if(inpkt->seqno <= n->received_seqno) {
} else if (inpkt->seqno <= n->received_seqno) {
if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, inpkt->seqno, n->received_seqno);
logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, inpkt->seqno, n->received_seqno);
return;
}
} else {
for(uint32_t i = n->received_seqno + 1; i < inpkt->seqno; i++) {
for(int i = n->received_seqno + 1; i < inpkt->seqno; i++)
n->late[(i / 8) % replaywin] |= 1 << i % 8;
}
}
}
@ -378,13 +324,11 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
}
if(inpkt->seqno > n->received_seqno) {
if(inpkt->seqno > n->received_seqno)
n->received_seqno = inpkt->seqno;
}
if(n->received_seqno > MAX_SEQNO) {
keyexpires = 0;
}
if(n->received_seqno > MAX_SEQNO)
regenerate_key();
/* Decompress the packet */
@ -393,41 +337,33 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
if(n->incompression) {
outpkt = pkt[nextpkt++];
if(!(outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression))) {
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)",
n->name, n->hostname);
n->name, n->hostname);
return;
}
inpkt = outpkt;
origlen -= MTU / 64 + 20;
origlen -= MTU/64 + 20;
}
inpkt->priority = 0;
if(!inpkt->data[12] && !inpkt->data[13]) {
if(!inpkt->data[12] && !inpkt->data[13])
mtu_probe_h(n, inpkt, origlen);
} else {
else
receive_packet(n, inpkt);
}
}
void receive_tcppacket(connection_t *c, const char *buffer, length_t len) {
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) {
if(c->options & OPTION_TCPONLY)
outpkt.priority = 0;
} else {
else
outpkt.priority = -1;
}
memcpy(outpkt.data, buffer, len);
receive_packet(c->node, &outpkt);
@ -439,9 +375,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
vpn_packet_t *inpkt = origpkt;
int nextpkt = 0;
vpn_packet_t *outpkt;
int origlen;
int outlen, outpad;
int origpriority;
int origlen = origpkt->len;
size_t outlen;
#if defined(SOL_IP) && defined(IP_TOS)
static int priority = 0;
int origpriority = origpkt->priority;
#endif
int sock;
if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
@ -451,9 +391,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
/* Make sure we have a valid key */
if(!n->status.validkey) {
time_t now = time(NULL);
ifdebug(TRAFFIC) logger(LOG_INFO,
"No valid key known yet for %s (%s), forwarding via TCP",
n->name, n->hostname);
"No valid key known yet for %s (%s), forwarding via TCP",
n->name, n->hostname);
if(n->last_req_key + 10 <= now) {
send_req_key(n);
@ -467,29 +409,25 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
ifdebug(TRAFFIC) logger(LOG_INFO,
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
if(n != n->nexthop) {
if(n != n->nexthop)
send_packet(n->nexthop, origpkt);
} else {
else
send_tcppacket(n->nexthop->connection, origpkt);
}
return;
}
origlen = inpkt->len;
origpriority = inpkt->priority;
/* Compress the packet */
if(n->outcompression) {
outpkt = pkt[nextpkt++];
if(!(outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression))) {
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)",
n->name, n->hostname);
n->name, n->hostname);
return;
}
@ -499,127 +437,59 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
/* Add sequence number */
inpkt->seqno = htonl(++(n->sent_seqno));
inpkt->len += sizeof(inpkt->seqno);
inpkt->len += sizeof inpkt->seqno;
/* Encrypt the packet */
if(n->outcipher) {
if(cipher_active(&n->outcipher)) {
outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
if(!EVP_EncryptInit_ex(n->outctx, NULL, NULL, NULL, NULL)
|| !EVP_EncryptUpdate(n->outctx, (unsigned char *) &outpkt->seqno, &outlen,
(unsigned char *) &inpkt->seqno, inpkt->len)
|| !EVP_EncryptFinal_ex(n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s): %s",
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
goto end;
}
outpkt->len = outlen + outpad;
outpkt->len = outlen;
inpkt = outpkt;
}
/* Add the message authentication code */
if(n->outdigest && n->outmaclength) {
HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno,
inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
inpkt->len += n->outmaclength;
if(digest_active(&n->outdigest)) {
digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len);
inpkt->len += digest_length(&n->outdigest);
}
/* Determine which socket we have to use */
if(n->address.sa.sa_family != listen_socket[n->sock].sa.sa.sa_family) {
for(int sock = 0; sock < listen_sockets; sock++) {
if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family) {
n->sock = sock;
break;
}
}
}
for(sock = 0; sock < listen_sockets; sock++)
if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family)
break;
if(sock >= listen_sockets)
sock = 0; /* If none is available, just use the first and hope for the best. */
/* Send the packet */
struct sockaddr *sa;
socklen_t sl;
int sock;
sockaddr_t broadcast;
/* Overloaded use of priority field: -1 means local broadcast */
if(origpriority == -1 && n->prevedge) {
sock = rand() % listen_sockets;
memset(&broadcast, 0, sizeof(broadcast));
if(listen_socket[sock].sa.sa.sa_family == AF_INET6) {
broadcast.in6.sin6_family = AF_INET6;
broadcast.in6.sin6_addr.s6_addr[0x0] = 0xff;
broadcast.in6.sin6_addr.s6_addr[0x1] = 0x02;
broadcast.in6.sin6_addr.s6_addr[0xf] = 0x01;
broadcast.in6.sin6_port = n->prevedge->address.in.sin_port;
broadcast.in6.sin6_scope_id = listen_socket[sock].sa.in6.sin6_scope_id;
} else {
broadcast.in.sin_family = AF_INET;
broadcast.in.sin_addr.s_addr = -1;
broadcast.in.sin_port = n->prevedge->address.in.sin_port;
}
sa = &broadcast.sa;
sl = SALEN(broadcast.sa);
} else {
if(origpriority == -1) {
origpriority = 0;
}
sa = &(n->address.sa);
sl = SALEN(n->address.sa);
sock = n->sock;
#if defined(SOL_IP) && defined(IP_TOS)
if(priorityinheritance && origpriority != priority
&& listen_socket[sock].sa.sa.sa_family == AF_INET) {
priority = origpriority;
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof priority)) /* SO_PRIORITY doesn't seem to work */
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
if(priorityinheritance && origpriority != listen_socket[n->sock].priority) {
listen_socket[n->sock].priority = origpriority;
switch(listen_socket[n->sock].sa.sa.sa_family) {
#if defined(IP_TOS)
case AF_INET:
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority);
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IP, IP_TOS, (void *)&origpriority, sizeof(origpriority))) { /* SO_PRIORITY doesn't seem to work */
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
break;
#endif
#if defined(IPV6_TCLASS)
case AF_INET6:
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority);
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof(origpriority))) {
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
break;
#endif
default:
break;
}
}
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) {
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
}
if(n->mtu >= origlen) {
if(n->mtu >= origlen)
n->mtu = origlen - 1;
}
} else {
ifdebug(TRAFFIC) logger(LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
}
} else
logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
}
end:
@ -629,170 +499,154 @@ end:
/*
send a packet to the given vpn ip.
*/
void send_packet(const node_t *n, vpn_packet_t *packet) {
void send_packet(node_t *n, vpn_packet_t *packet) {
node_t *via;
if(n == myself) {
if(overwrite_mac) {
memcpy(packet->data, mymac.x, ETH_ALEN);
}
devops.write(packet);
if(overwrite_mac)
memcpy(packet->data, mymac.x, ETH_ALEN);
n->out_packets++;
n->out_bytes += packet->len;
write_packet(packet);
return;
}
ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)",
packet->len, n->name, n->hostname);
packet->len, n->name, n->hostname);
if(!n->status.reachable) {
ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable",
n->name, n->hostname);
n->name, n->hostname);
return;
}
n->out_packets++;
n->out_bytes += packet->len;
via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
if(via != n)
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)",
n->name, via->name, n->via->hostname);
n->name, via->name, n->via->hostname);
if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
if(!send_tcppacket(via->connection, packet)) {
if(!send_tcppacket(via->connection, packet))
terminate_connection(via->connection, true);
}
} else {
} else
send_udppacket(via, packet);
}
}
/* Broadcast a packet using the minimum spanning tree */
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
avl_node_t *node;
splay_node_t *node;
connection_t *c;
node_t *n;
// Always give ourself a copy of the packet.
if(from != myself) {
send_packet(myself, packet);
}
// In TunnelServer mode, do not forward broadcast packets.
// The MST might not be valid and create loops.
if(tunnelserver || broadcast_mode == BMODE_NONE) {
return;
}
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
packet->len, from->name, from->hostname);
packet->len, from->name, from->hostname);
switch(broadcast_mode) {
// In MST mode, broadcast packets travel via the Minimum Spanning Tree.
// This guarantees all nodes receive the broadcast packet, and
// usually distributes the sending of broadcast packets over all nodes.
case BMODE_MST:
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
if(from != myself) {
send_packet(myself, packet);
if(c->status.active && c->status.mst && c != from->nexthop->connection) {
send_packet(c->node, packet);
}
}
// In TunnelServer mode, do not forward broadcast packets.
// The MST might not be valid and create loops.
if(tunnelserver)
return;
}
break;
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
// In direct mode, we send copies to each node we know of.
// However, this only reaches nodes that can be reached in a single hop.
// We don't have enough information to forward broadcast packets in this case.
case BMODE_DIRECT:
if(from != myself) {
break;
}
for(node = node_udp_tree->head; node; node = node->next) {
n = node->data;
if(n->status.reachable && n != myself && ((n->via == myself && n->nexthop == n) || n->via == n)) {
send_packet(n, packet);
}
}
break;
default:
break;
if(c->status.active && c->status.mst && c != from->nexthop->connection)
send_packet(c->node, packet);
}
}
static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
avl_node_t *node;
splay_node_t *node;
edge_t *e;
node_t *n = NULL;
bool hard = false;
static time_t last_hard_try = 0;
time_t now = time(NULL);
if(last_hard_try == now)
return NULL;
else
last_hard_try = now;
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
if(e->to == myself) {
if(e->to == myself)
continue;
if(sockaddrcmp_noport(from, &e->address)) {
if(last_hard_try == now)
continue;
hard = true;
}
if(last_hard_try == now && sockaddrcmp_noport(from, &e->address)) {
if(!try_mac(e->to, pkt))
continue;
}
if(!try_mac(e->to, pkt)) {
continue;
}
n = e->to;
break;
}
last_hard_try = now;
if(hard)
last_hard_try = now;
return n;
}
void handle_incoming_vpn_data(int sock) {
void handle_incoming_vpn_data(int sock, short events, void *data) {
vpn_packet_t pkt;
char *hostname;
sockaddr_t from;
socklen_t fromlen = sizeof(from);
socklen_t fromlen = sizeof from;
node_t *n;
int len;
ssize_t len = recvfrom(listen_socket[sock].udp, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
if(len <= 0 || len > UINT16_MAX) {
if(len >= 0) {
logger(LOG_ERR, "Receiving packet with invalid size");
} else if(!sockwouldblock(sockerrno)) {
if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno))
logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
}
return;
}
pkt.len = len;
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
n = lookup_node_udp(&from);
if(!n) {
n = try_harder(&from, &pkt);
if(n) {
if(n)
update_node_udp(n, &from);
} else ifdebug(PROTOCOL) {
else ifdebug(PROTOCOL) {
hostname = sockaddr2hostname(&from);
logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname);
return;
} else {
return;
}
else
return;
}
n->sock = sock;
receive_udppacket(n, &pkt);
}
void handle_device_data(int sock, short events, void *data) {
vpn_packet_t packet;
packet.priority = 0;
if(read_packet(&packet)) {
myself->in_packets++;
myself->in_bytes += packet.len;
route(myself, &packet);
}
}