static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
if(n->status.sptps)
- return sptps_verify_datagram(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
+ return sptps_verify_datagram(&n->sptps, ((sptps_packet_t *)inpkt)->data, inpkt->len);
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 - digest_length(n->indigest), (const char *)&inpkt->seqno + inpkt->len - digest_length(n->indigest));
+ return digest_verify(n->indigest, (const char *)&inpkt->seqno, inpkt->len - digest_length(n->indigest), (const char *)&inpkt->seqno + inpkt->len - digest_length(n->indigest));
}
static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
}
return false;
}
- return sptps_receive_data(&n->sptps, (char *)&inpkt->seqno, inpkt->len);
+ if(!sptps_receive_data(&n->sptps, ((sptps_packet_t *)&inpkt)->data, inpkt->len)) {
+ logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname);
+ return false;
+ }
+ return true;
}
if(!n->status.validkey) {
/* Check the sequence number */
inpkt->len -= sizeof inpkt->seqno;
- uint32_t seqno;
- memcpy(&seqno, inpkt->seqno, sizeof seqno);
- seqno = ntohl(seqno);
+ uint32_t seqno = ntohl(inpkt->seqno);
if(replaywin) {
if(seqno != n->received_seqno + 1) {
receive_packet(c->node, &outpkt);
}
+static bool try_sptps(node_t *n) {
+ if(n->status.validkey)
+ return true;
+
+ 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 < 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;
+ send_req_key(n);
+ }
+
+ return false;
+}
+
static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
- if(!n->status.validkey) {
- 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 < 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;
- send_req_key(n);
- }
+ if (!try_sptps(n))
return;
- }
uint8_t type = 0;
int offset = 0;
/* Add sequence number */
- uint32_t seqno = htonl(++(n->sent_seqno));
- memcpy(inpkt->seqno, &seqno, sizeof inpkt->seqno);
+ inpkt->seqno = htonl(++(n->sent_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, 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, 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;
origpkt->len = origlen;
}
-static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const char *data, size_t len) {
+static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void *data, size_t len) {
node_t *relay = (to->via != myself && (type == PKT_PROBE || (len - SPTPS_DATAGRAM_OVERHEAD) <= to->via->minmtu)) ? to->via : to->nexthop;
bool direct = from == myself && to == relay;
bool relay_supported = (relay->options >> 24) >= 4;
+ bool tcponly = (myself->options | relay->options) & OPTION_TCPONLY;
+
+ /* We don't really need the relay's key, but we need to establish a UDP tunnel with it and discover its MTU. */
+ if (!direct && relay_supported && !tcponly)
+ try_sptps(relay);
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU.
TODO: When relaying, the original sender does not know the end-to-end PMTU (it only knows the PMTU of the first hop).
This can lead to scenarios where large packets are sent over UDP to relay, but then relay has no choice but fall back to TCP. */
- if(type == SPTPS_HANDSHAKE || ((myself->options | relay->options) & OPTION_TCPONLY) || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) {
+ if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) {
char buf[len * 4 / 3 + 5];
b64encode(data, buf, len);
/* If no valid key is known yet, send the packets using ANS_KEY requests,
if(relay_supported) {
if(direct) {
/* Inform the recipient that this packet was sent directly. */
- node_id_t nullid = {0};
+ node_id_t nullid = {};
memcpy(buf_ptr, &nullid, sizeof nullid); buf_ptr += sizeof nullid;
} else {
memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id;
void handle_incoming_vpn_data(void *data, int flags) {
listen_socket_t *ls = data;
vpn_packet_t pkt;
+ sptps_packet_t *spkt = (sptps_packet_t *)&pkt;
char *hostname;
sockaddr_t from = {{0}};
socklen_t fromlen = sizeof from;
node_t *to = myself;
int len;
- len = recvfrom(ls->udp.fd, &pkt.dstid, MAXSIZE, 0, &from.sa, &fromlen);
+ len = recvfrom(ls->udp.fd, &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno))
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
bool direct = false;
- if(len >= sizeof pkt.dstid + sizeof pkt.srcid) {
- n = lookup_node_id(&pkt.srcid);
+ if(len >= sizeof spkt->dstid + sizeof spkt->srcid) {
+ n = lookup_node_id(&spkt->srcid);
if(n) {
- node_id_t nullid = {0};
- if(memcmp(&pkt.dstid, &nullid, sizeof nullid) == 0) {
+ node_id_t nullid = {};
+ if(memcmp(&spkt->dstid, &nullid, sizeof nullid) == 0) {
/* A zero dstid is used to indicate a direct, non-relayed packet. */
direct = true;
} else {
- to = lookup_node_id(&pkt.dstid);
+ to = lookup_node_id(&spkt->dstid);
if(!to) {
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet presumably sent by %s (%s) but with unknown destination ID", n->name, n->hostname);
return;
}
}
- pkt.len -= sizeof pkt.dstid + sizeof pkt.srcid;
+ pkt.len -= sizeof spkt->dstid + sizeof spkt->srcid;
}
}
return;
}
- send_sptps_data_priv(to, n, 0, pkt.seqno, pkt.len);
+ send_sptps_data_priv(to, n, 0, spkt->data, pkt.len);
return;
}
if(!n) {
/* Most likely an old-style packet without node IDs. */
direct = true;
- memmove(pkt.seqno, &pkt.dstid, sizeof pkt - offsetof(vpn_packet_t, seqno));
n = lookup_node_udp(&from);
}