X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fnet_packet.c;h=f8c6ac9bce847fb1dfeca8b57497c535ed9e0b44;hp=69835eef5faa9bf4f92a3d1c91143d9743e3f80f;hb=c544e5e8fe22250b230a46f0340483db5403a6c1;hpb=eca357ed916c9782a64a68a2f30b144d84027795 diff --git a/src/net_packet.c b/src/net_packet.c index 69835eef..f8c6ac9b 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -1,7 +1,7 @@ /* net_packet.c -- Handles in- and outgoing VPN packets Copyright (C) 1998-2005 Ivo Timmermans, - 2000-2014 Guus Sliepen + 2000-2016 Guus Sliepen 2010 Timothy Redaelli 2010 Brandon Black @@ -458,7 +458,7 @@ bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) { /* This can happen in the form of a race condition if the node just became unreachable. */ logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot relay TCP packet from %s (%s) because the destination, %s (%s), is unreachable", from->name, from->hostname, to->name, to->hostname); - return; + return true; } /* Help the sender reach us over UDP. @@ -621,10 +621,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { 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; @@ -719,15 +716,27 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { if(!sa) choose_udp_address(n, &sa, &sock); + if(priorityinheritance && origpriority != listen_socket[sock].priority) { + listen_socket[sock].priority = origpriority; + switch(sa->sa.sa_family) { #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)); - } + case AF_INET: + logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority); + if(setsockopt(listen_socket[sock].udp.fd, SOL_IP, IP_TOS, &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, &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(sockmsgsize(sockerrno)) { @@ -1252,8 +1261,12 @@ void send_packet(node_t *n, vpn_packet_t *packet) { // If it's for myself, write it to the tun/tap device. if(n == myself) { - if(overwrite_mac) + if(overwrite_mac) { memcpy(DATA(packet), mymac.x, ETH_ALEN); + // Use an arbitrary fake source address. + memcpy(DATA(packet) + ETH_ALEN, DATA(packet), ETH_ALEN); + DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF; + } n->out_packets++; n->out_bytes += packet->len; devops.write(packet); @@ -1389,42 +1402,27 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { 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; @@ -1432,36 +1430,36 @@ void handle_incoming_vpn_data(void *data, int flags) { } 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); @@ -1487,7 +1485,7 @@ skip_harder: /* 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; } @@ -1496,12 +1494,12 @@ skip_harder: 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. */ @@ -1510,6 +1508,67 @@ skip_harder: 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, 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;