/* It's a probe request, send back a reply */
/* Type 2 probe replies were introduced in protocol 17.3 */
- if ((n->options >> 24) == 3) {
+ if ((n->options >> 24) >= 3) {
uint8_t* data = packet->data;
*data++ = 2;
uint16_t len16 = htons(len); memcpy(data, &len16, 2); data += 2;
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) {
+static bool 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 = pkt[0];
size_t outlen;
if(n->status.sptps) {
} else {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
}
- return;
+ return false;
}
- sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
- return;
+ return sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
}
if(!n->status.validkey) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet", n->name, n->hostname);
- return;
+ return false;
}
/* Check packet length */
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;
+ return false;
}
/* Check the message authentication code */
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;
+ return false;
}
}
/* Decrypt the packet */
if(cipher_active(n->incipher)) {
- outpkt = pkt[nextpkt++];
+ vpn_packet_t *outpkt = pkt[nextpkt++];
outlen = MAXSIZE;
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;
+ return false;
}
outpkt->len = outlen;
/* Check the sequence number */
inpkt->len -= sizeof inpkt->seqno;
- inpkt->seqno = ntohl(inpkt->seqno);
+ uint32_t seqno;
+ memcpy(&seqno, inpkt->seqno, sizeof seqno);
+ seqno = ntohl(seqno);
if(replaywin) {
- if(inpkt->seqno != n->received_seqno + 1) {
- if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
+ if(seqno != n->received_seqno + 1) {
+ if(seqno >= n->received_seqno + replaywin * 8) {
if(n->farfuture++ < replaywin >> 2) {
logger(DEBUG_ALWAYS, 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;
+ n->name, n->hostname, seqno - n->received_seqno - 1, n->farfuture);
+ return false;
}
logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
- inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
+ seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin);
- } 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))) {
+ } else if (seqno <= n->received_seqno) {
+ if((n->received_seqno >= replaywin * 8 && seqno <= n->received_seqno - replaywin * 8) || !(n->late[(seqno / 8) % replaywin] & (1 << seqno % 8))) {
logger(DEBUG_ALWAYS, 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;
+ n->name, n->hostname, seqno, n->received_seqno);
+ return false;
}
} else {
- for(int i = n->received_seqno + 1; i < inpkt->seqno; i++)
+ for(int i = n->received_seqno + 1; i < seqno; i++)
n->late[(i / 8) % replaywin] |= 1 << i % 8;
}
}
n->farfuture = 0;
- n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
+ n->late[(seqno / 8) % replaywin] &= ~(1 << seqno % 8);
}
- if(inpkt->seqno > n->received_seqno)
- n->received_seqno = inpkt->seqno;
+ if(seqno > n->received_seqno)
+ n->received_seqno = seqno;
n->received++;
length_t origlen = inpkt->len;
if(n->incompression) {
- outpkt = pkt[nextpkt++];
+ vpn_packet_t *outpkt = pkt[nextpkt++];
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while uncompressing packet from %s (%s)",
n->name, n->hostname);
- return;
+ return false;
}
inpkt = outpkt;
mtu_probe_h(n, inpkt, origlen);
else
receive_packet(n, inpkt);
+ return true;
}
void receive_tcppacket(connection_t *c, const char *buffer, int len) {
size_t outlen;
#if defined(SOL_IP) && defined(IP_TOS)
static int priority = 0;
-#endif
int origpriority = origpkt->priority;
+#endif
if(!n->status.reachable) {
logger(DEBUG_TRAFFIC, LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
/* Add sequence number */
- inpkt->seqno = htonl(++(n->sent_seqno));
+ uint32_t seqno = htonl(++(n->sent_seqno));
+ memcpy(inpkt->seqno, &seqno, sizeof inpkt->seqno);
inpkt->len += sizeof inpkt->seqno;
/* Encrypt the packet */
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)) {
- if(!digest_create(n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len)) {
+ if(!digest_create(n->outdigest, inpkt->seqno, inpkt->len, inpkt->seqno + inpkt->len)) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
goto end;
}
}
#endif
- if(sendto(listen_socket[sock].udp.fd, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+ if(sendto(listen_socket[sock].udp.fd, inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
if(!sa)
choose_udp_address(to, &sa, &sock);
- if(sendto(listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+ bool add_srcid = (to->options >> 24) >= 4;
+ size_t overhead = 0;
+ if (add_srcid) overhead += sizeof myself->id;
+ char buf[len + overhead]; char* buf_ptr = buf;
+ if(add_srcid) {
+ memcpy(buf_ptr, &myself->id, sizeof myself->id); buf_ptr += sizeof myself->id;
+ }
+ /* TODO: if this copy turns out to be a performance concern, change sptps_send_record() to add some "pre-padding" to the buffer and use that instead */
+ memcpy(buf_ptr, data, len); buf_ptr += len;
+
+ if(sendto(listen_socket[sock].udp.fd, buf, buf_ptr - buf, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
// Compensate for SPTPS overhead
len -= SPTPS_DATAGRAM_OVERHEAD;
// usually distributes the sending of broadcast packets over all nodes.
case BMODE_MST:
for list_each(connection_t, c, connection_list)
- if(c->status.active && c->status.mst && c != from->nexthop->connection)
+ if(c->edge && c->status.mst && c != from->nexthop->connection)
send_packet(c->node, packet);
break;
char *hostname;
sockaddr_t from = {{0}};
socklen_t fromlen = sizeof from;
- node_t *n;
+ node_t *n = NULL;
int len;
- len = recvfrom(ls->udp.fd, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
+ len = recvfrom(ls->udp.fd, &pkt.srcid, MAXSIZE, 0, &from.sa, &fromlen);
if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno))
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
- n = lookup_node_udp(&from);
+ if(len >= sizeof pkt.srcid)
+ n = lookup_node_id(&pkt.srcid);
+ if(n)
+ pkt.len -= sizeof pkt.srcid;
+ else {
+ /* Most likely an old-style packet without a source ID. */
+ memmove(pkt.seqno, &pkt.srcid, sizeof pkt - offsetof(vpn_packet_t, seqno));
+ n = lookup_node_udp(&from);
+ }
- if(!n) {
+ if(!n)
n = try_harder(&from, &pkt);
- if(n)
- update_node_udp(n, &from);
- else if(debug_level >= DEBUG_PROTOCOL) {
+
+ if(!n) {
+ if(debug_level >= DEBUG_PROTOCOL) {
hostname = sockaddr2hostname(&from);
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname);
- return;
}
- else
- return;
+ return;
}
- n->sock = ls - listen_socket;
+ if(!receive_udppacket(n, &pkt))
+ return;
- receive_udppacket(n, &pkt);
+ n->sock = ls - listen_socket;
+ if(sockaddrcmp(&from, &n->address))
+ update_node_udp(n, &from);
}
void handle_device_data(void *data, int flags) {