/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2005 Ivo Timmermans,
- 2000-2014 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2016 Guus Sliepen <guus@tinc-vpn.org>
2010 Timothy Redaelli <timothy@redaelli.eu>
2010 Brandon Black <blblack@gmail.com>
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)",
+ logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
n->name, n->hostname, seqno - n->received_seqno - 1, n->farfuture);
return false;
}
- logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
+ logger(DEBUG_TRAFFIC, LOG_WARNING, "Lost %d packets from %s (%s)",
seqno - n->received_seqno - 1, n->name, n->hostname);
memset(n->late, 0, replaywin);
} 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",
+ logger(DEBUG_TRAFFIC, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
n->name, n->hostname, seqno, n->received_seqno);
return false;
}
bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) {
if (len < sizeof(node_id_t) + sizeof(node_id_t)) {
- logger(DEBUG_ALWAYS, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname);
+ logger(DEBUG_PROTOCOL, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname);
return false;
}
uint8_t type = 0;
int offset = 0;
- if(!(DATA(origpkt)[12] | DATA(origpkt)[13])) {
+ if((!(DATA(origpkt)[12] | DATA(origpkt)[13])) && (n->sptps.outstate)) {
sptps_send_record(&n->sptps, PKT_PROBE, (char *)DATA(origpkt), origpkt->len);
return;
}
vpn_packet_t *outpkt;
int origlen = origpkt->len;
size_t outlen;
-#if defined(SOL_IP) && defined(IP_TOS)
- static int priority = 0;
int origpriority = origpkt->priority;
-#endif
pkt1.offset = DEFAULT_PACKET_OFFSET;
pkt2.offset = DEFAULT_PACKET_OFFSET;
if(!sa)
choose_udp_address(n, &sa, &sock);
-#if defined(SOL_IP) && defined(IP_TOS)
- if(priorityinheritance && origpriority != priority
- && listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
- priority = origpriority;
- logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
- if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
- logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
- }
+ if(priorityinheritance && origpriority != listen_socket[sock].priority) {
+ listen_socket[sock].priority = origpriority;
+ switch(sa->sa.sa_family) {
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ case AF_INET:
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority);
+ if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IP, IP_TOS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */
+ logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
+ break;
+#endif
+#if defined(IPPROTO_IPV6) & defined(IPV6_TCLASS)
+ case AF_INET6:
+ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority);
+ if(setsockopt(listen_socket[sock].udp.fd, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof origpriority)) /* SO_PRIORITY doesn't seem to work */
+ logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", sockstrerror(sockerrno));
+ break;
#endif
+ default:
+ break;
+ }
+ }
- if(sendto(listen_socket[sock].udp.fd, SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+ if(sendto(listen_socket[sock].udp.fd, (void *)SEQNO(inpkt), inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
char buf[len + sizeof to->id + sizeof from->id]; char* buf_ptr = buf;
memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id;
memcpy(buf_ptr, &from->id, sizeof from->id); buf_ptr += sizeof from->id;
- memcpy(buf_ptr, data, len); buf_ptr += len;
+ memcpy(buf_ptr, data, len);
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (TCP)", from->name, from->hostname, to->name, to->hostname, to->nexthop->name, to->nexthop->hostname);
return send_sptps_tcppacket(to->nexthop->connection, buf, sizeof buf);
}
return match;
}
-void handle_incoming_vpn_data(void *data, int flags) {
- listen_socket_t *ls = data;
- vpn_packet_t pkt;
+static void handle_incoming_vpn_packet(listen_socket_t *ls, vpn_packet_t *pkt, sockaddr_t *addr) {
char *hostname;
node_id_t nullid = {};
- sockaddr_t addr = {};
- socklen_t addrlen = sizeof addr;
node_t *from, *to;
bool direct = false;
- pkt.offset = 0;
- int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
-
- if(len <= 0 || len > MAXSIZE) {
- if(!sockwouldblock(sockerrno))
- logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
- return;
- }
-
- pkt.len = len;
-
- sockaddrunmap(&addr); /* Some braindead IPv6 implementations do stupid things. */
+ sockaddrunmap(addr); /* Some braindead IPv6 implementations do stupid things. */
// Try to figure out who sent this packet.
- node_t *n = lookup_node_udp(&addr);
+ node_t *n = lookup_node_udp(addr);
if(n && !n->status.udp_confirmed)
n = NULL; // Don't believe it if we don't have confirmation yet.
if(!n) {
// It might be from a 1.1 node, which might have a source ID in the packet.
- pkt.offset = 2 * sizeof(node_id_t);
- from = lookup_node_id(SRCID(&pkt));
- if(from && !memcmp(DSTID(&pkt), &nullid, sizeof nullid) && from->status.sptps) {
- if(sptps_verify_datagram(&from->sptps, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t)))
+ pkt->offset = 2 * sizeof(node_id_t);
+ from = lookup_node_id(SRCID(pkt));
+ if(from && !memcmp(DSTID(pkt), &nullid, sizeof nullid) && from->status.sptps) {
+ if(sptps_verify_datagram(&from->sptps, DATA(pkt), pkt->len - 2 * sizeof(node_id_t)))
n = from;
else
goto skip_harder;
}
if(!n) {
- pkt.offset = 0;
- n = try_harder(&addr, &pkt);
+ pkt->offset = 0;
+ n = try_harder(addr, pkt);
}
skip_harder:
if(!n) {
if(debug_level >= DEBUG_PROTOCOL) {
- hostname = sockaddr2hostname(&addr);
+ hostname = sockaddr2hostname(addr);
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
free(hostname);
}
return;
}
- pkt.offset = 0;
+ pkt->offset = 0;
if(n->status.sptps) {
bool relay_enabled = (n->options >> 24) >= 4;
if (relay_enabled) {
- pkt.offset = 2 * sizeof(node_id_t);
- pkt.len -= pkt.offset;
+ pkt->offset = 2 * sizeof(node_id_t);
+ pkt->len -= pkt->offset;
}
- if(!memcmp(DSTID(&pkt), &nullid, sizeof nullid) || !relay_enabled) {
+ if(!memcmp(DSTID(pkt), &nullid, sizeof nullid) || !relay_enabled) {
direct = true;
from = n;
to = myself;
} else {
- from = lookup_node_id(SRCID(&pkt));
- to = lookup_node_id(DSTID(&pkt));
+ from = lookup_node_id(SRCID(pkt));
+ to = lookup_node_id(DSTID(pkt));
}
if(!from || !to) {
logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname);
/* If we're not the final recipient, relay the packet. */
if(to != myself) {
- send_sptps_data(to, from, 0, DATA(&pkt), pkt.len);
+ send_sptps_data(to, from, 0, DATA(pkt), pkt->len);
try_tx(to, true);
return;
}
from = n;
}
- if(!receive_udppacket(from, &pkt))
+ if(!receive_udppacket(from, pkt))
return;
n->sock = ls - listen_socket;
- if(direct && sockaddrcmp(&addr, &n->address))
- update_node_udp(n, &addr);
+ if(direct && sockaddrcmp(addr, &n->address))
+ update_node_udp(n, addr);
/* If the packet went through a relay, help the sender find the appropriate MTU
through the relay path. */
send_mtu_info(myself, n, MTU);
}
+void handle_incoming_vpn_data(void *data, int flags) {
+ listen_socket_t *ls = data;
+
+#ifdef HAVE_RECVMMSG
+#define MAX_MSG 64
+ static int num = MAX_MSG;
+ static vpn_packet_t pkt[MAX_MSG];
+ static sockaddr_t addr[MAX_MSG];
+ static struct mmsghdr msg[MAX_MSG];
+ static struct iovec iov[MAX_MSG];
+
+ for(int i = 0; i < num; i++) {
+ pkt[i].offset = 0;
+
+ iov[i] = (struct iovec){
+ .iov_base = DATA(&pkt[i]),
+ .iov_len = MAXSIZE,
+ };
+
+ msg[i].msg_hdr = (struct msghdr){
+ .msg_name = &addr[i].sa,
+ .msg_namelen = sizeof addr[i],
+ .msg_iov = &iov[i],
+ .msg_iovlen = 1,
+ };
+ }
+
+ num = recvmmsg(ls->udp.fd, msg, MAX_MSG, MSG_DONTWAIT, NULL);
+
+ if(num < 0) {
+ if(!sockwouldblock(sockerrno))
+ logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+ return;
+ }
+
+ for(int i = 0; i < num; i++) {
+ pkt[i].len = msg[i].msg_len;
+ if(pkt[i].len <= 0 || pkt[i].len > MAXSIZE)
+ continue;
+ handle_incoming_vpn_packet(ls, &pkt[i], &addr[i]);
+ }
+#else
+ vpn_packet_t pkt;
+ sockaddr_t addr = {};
+ socklen_t addrlen = sizeof addr;
+
+ pkt.offset = 0;
+ int len = recvfrom(ls->udp.fd, (void *)DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
+
+ if(len <= 0 || len > MAXSIZE) {
+ if(!sockwouldblock(sockerrno))
+ logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+ return;
+ }
+
+ pkt.len = len;
+
+ handle_incoming_vpn_packet(ls, &pkt, &addr);
+#endif
+}
+
void handle_device_data(void *data, int flags) {
vpn_packet_t packet;
packet.offset = DEFAULT_PACKET_OFFSET;