+/* These functions try to establish a tunnel to a node (or its relay) so that
+ packets can be sent (e.g. exchange keys).
+ If a tunnel is already established, it tries to improve it (e.g. by trying
+ to establish a UDP tunnel instead of TCP). This function makes no
+ guarantees - it is up to the caller to check the node's state to figure out
+ if TCP and/or UDP is usable. By calling this function repeatedly, the
+ tunnel is gradually improved until we hit the wall imposed by the underlying
+ network environment. It is recommended to call this function every time a
+ packet is sent (or intended to be sent) to a node, so that the tunnel keeps
+ improving as packets flow, and then gracefully downgrades itself as it goes
+ idle.
+*/
+
+static void try_tx_sptps(node_t *n, bool mtu) {
+ /* If n is a TCP-only neighbor, we'll only use "cleartext" PACKET
+ messages anyway, so there's no need for SPTPS at all. */
+
+ if(n->connection && ((myself->options | n->options) & OPTION_TCPONLY))
+ return;
+
+ /* Otherwise, try to do SPTPS authentication with n if necessary. */
+
+ try_sptps(n);
+
+ /* Do we need to statically relay packets? */
+
+ node_t *via = (n->via == myself) ? n->nexthop : n->via;
+
+ /* If we do have a static relay, try everything with that one instead, if it supports relaying. */
+
+ if(via != n) {
+ if((via->options >> 24) < 4)
+ return;
+ return try_tx(via, mtu);
+ }
+
+ /* Otherwise, try to establish UDP connectivity. */
+
+ try_udp(n);
+ if(mtu)
+ try_mtu(n);
+
+ /* If we don't have UDP connectivity (yet), we need to use a dynamic relay (nexthop)
+ while we try to establish direct connectivity. */
+
+ if(!n->status.udp_confirmed && n != n->nexthop && (n->nexthop->options >> 24) >= 4)
+ try_tx(n->nexthop, mtu);
+}
+
+static void try_tx_legacy(node_t *n, bool mtu) {
+ /* Does he have our key? If not, send one. */
+
+ if(!n->status.validkey_in)
+ send_ans_key(n);
+
+ /* Check if we already have a key, or request one. */
+
+ if(!n->status.validkey) {
+ if(n->last_req_key + 10 <= now.tv_sec) {
+ send_req_key(n);
+ n->last_req_key = now.tv_sec;
+ }
+ return;
+ }
+
+ try_udp(n);
+ if(mtu)
+ try_mtu(n);
+}
+
+void try_tx(node_t *n, bool mtu) {
+ if(!n->status.reachable)
+ return;
+ if(n->status.sptps)
+ try_tx_sptps(n, mtu);
+ else
+ try_tx_legacy(n, mtu);
+}
+
+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) {
+ 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);
+ return;
+ }
+
+ logger(DEBUG_TRAFFIC, LOG_ERR, "Sending packet of %d bytes to %s (%s)", packet->len, n->name, n->hostname);
+
+ // If the node is not reachable, drop it.
+
+ if(!n->status.reachable) {
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Node %s (%s) is not reachable", n->name, n->hostname);
+ return;
+ }
+
+ // Keep track of packet statistics.
+
+ n->out_packets++;
+ n->out_bytes += packet->len;
+
+ // Check if it should be sent as an SPTPS packet.
+
+ if(n->status.sptps) {
+ send_sptps_packet(n, packet);
+ try_tx(n, true);
+ return;
+ }
+
+ // Determine which node to actually send it to.
+
+ node_t *via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
+
+ if(via != n)
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet to %s via %s (%s)", n->name, via->name, n->via->hostname);
+
+ // Try to send via UDP, unless TCP is forced.
+
+ if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
+ if(!send_tcppacket(via->connection, packet))
+ terminate_connection(via->connection, true);
+ return;
+ }
+
+ send_udppacket(via, packet);
+ try_tx(via, true);
+}
+
+void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
+ // 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;
+
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
+ 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 list_each(connection_t, c, connection_list)
+ if(c->edge && c->status.mst && c != from->nexthop->connection)
+ send_packet(c->node, packet);
+ break;
+
+ // 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 splay_each(node_t, n, node_tree)
+ if(n->status.reachable && n != myself && ((n->via == myself && n->nexthop == n) || n->via == n))
+ send_packet(n, packet);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* We got a packet from some IP address, but we don't know who sent it. Try to
+ verify the message authentication code against all active session keys.
+ Since this is actually an expensive operation, we only do a full check once
+ a minute, the rest of the time we only check against nodes for which we know
+ an IP address that matches the one from the packet. */
+
+static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
+ node_t *match = NULL;
+ bool hard = false;
+ static time_t last_hard_try = 0;
+
+ for splay_each(node_t, n, node_tree) {
+ if(!n->status.reachable || n == myself)
+ continue;
+
+ if(!n->status.validkey_in && !(n->status.sptps && n->sptps.instate))
+ continue;
+
+ bool soft = false;
+
+ for splay_each(edge_t, e, n->edge_tree) {
+ if(!e->reverse)
+ continue;
+ if(!sockaddrcmp_noport(from, &e->reverse->address)) {
+ soft = true;
+ break;
+ }
+ }
+
+ if(!soft) {
+ if(last_hard_try == now.tv_sec)
+ continue;
+ hard = true;
+ }
+
+ if(!try_mac(n, pkt))
+ continue;
+
+ match = n;
+ break;
+ }
+
+ if(hard)
+ last_hard_try = now.tv_sec;
+
+ return match;
+}
+
+static void handle_incoming_vpn_packet(listen_socket_t *ls, vpn_packet_t *pkt, sockaddr_t *addr) {
+ char *hostname;
+ node_id_t nullid = {};
+ node_t *from, *to;
+ bool direct = false;
+
+ sockaddrunmap(addr); /* Some braindead IPv6 implementations do stupid things. */
+
+ // Try to figure out who sent this packet.
+
+ 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)))
+ n = from;
+ else
+ goto skip_harder;
+ }
+ }
+
+ if(!n) {
+ pkt->offset = 0;
+ n = try_harder(addr, pkt);
+ }
+
+skip_harder:
+ if(!n) {
+ if(debug_level >= DEBUG_PROTOCOL) {
+ hostname = sockaddr2hostname(addr);
+ logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
+ free(hostname);
+ }
+ return;
+ }
+
+ 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;
+ }
+
+ 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));
+ }
+ 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);
+ return;
+ }
+
+ if(!to->status.reachable) {
+ /* This can happen in the form of a race condition
+ if the node just became unreachable. */
+ logger(DEBUG_TRAFFIC, LOG_WARNING, "Cannot relay packet from %s (%s) because the destination, %s (%s), is unreachable", from->name, from->hostname, to->name, to->hostname);
+ return;
+ }
+
+ /* The packet is supposed to come from the originator or its static relay
+ (i.e. with no dynamic relays in between).
+ If it did not, "help" the static relay by sending it UDP info.
+ Note that we only do this if we're the destination or the static relay;
+ otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
+
+ if(n != from->via && to->via == myself)
+ send_udp_info(myself, from);
+
+ /* If we're not the final recipient, relay the packet. */
+
+ if(to != myself) {
+ send_sptps_data(to, from, 0, DATA(pkt), pkt->len);
+ try_tx(to, true);
+ return;
+ }
+ } else {
+ direct = true;
+ from = n;
+ }
+
+ if(!receive_udppacket(from, pkt))
+ return;
+
+ n->sock = ls - listen_socket;
+ 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. */
+
+ if(!direct)
+ 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;
+ packet.priority = 0;
+
+ if(devops.read(&packet)) {
+ myself->in_packets++;
+ myself->in_bytes += packet.len;
+ route(myself, &packet);
+ }
+}