-void send_packet(node_t *n, vpn_packet_t *packet)
-{
- node_t *via;
-cp
- if(debug_lvl >= DEBUG_TRAFFIC)
- syslog(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"),
- packet->len, n->name, n->hostname);
-
- if(n == myself)
- {
- if(debug_lvl >= DEBUG_TRAFFIC)
- {
- syslog(LOG_NOTICE, _("Packet is looping back to us!"));
- }
-
- return;
- }
-
- if(!n->status.reachable)
- {
- if(debug_lvl >= DEBUG_TRAFFIC)
- syslog(LOG_INFO, _("Node %s (%s) is not reachable"),
- n->name, n->hostname);
- return;
- }
-
- via = (n->via == myself)?n->nexthop:n->via;
-
- if(via != n && debug_lvl >= DEBUG_TRAFFIC)
- syslog(LOG_ERR, _("Sending packet to %s via %s (%s)"),
- n->name, via->name, n->via->hostname);
-
- if((myself->options | via->options) & OPTION_TCPONLY)
- {
- if(send_tcppacket(via->connection, packet))
- terminate_connection(via->connection, 1);
- }
- else
- send_udppacket(via, packet);
-}
-
-/* Broadcast a packet using the minimum spanning tree */
-
-void broadcast_packet(node_t *from, vpn_packet_t *packet)
-{
- avl_node_t *node;
- connection_t *c;
-cp
- if(debug_lvl >= DEBUG_TRAFFIC)
- syslog(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"),
- packet->len, from->name, from->hostname);
-
- for(node = connection_tree->head; node; node = node->next)
- {
- c = (connection_t *)node->data;
- if(c->status.active && c->status.mst && c != from->nexthop->connection)
- send_packet(c->node, packet);
- }
-cp
-}
-
-void flush_queue(node_t *n)
-{
- list_node_t *node, *next;
-cp
- if(debug_lvl >= DEBUG_TRAFFIC)
- syslog(LOG_INFO, _("Flushing queue for %s (%s)"), n->name, n->hostname);
-
- for(node = n->queue->head; node; node = next)
- {
- next = node->next;
- send_udppacket(n, (vpn_packet_t *)node->data);
- list_delete_node(n->queue, node);
- }
-cp
-}
-
-void handle_incoming_vpn_data(int sock)
-{
- vpn_packet_t pkt;
- int x, l = sizeof(x);
- char *hostname;
- sockaddr_t from;
- socklen_t fromlen = sizeof(from);
- node_t *n;
-cp
- if(getsockopt(sock, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
- {
- syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%s"),
- __FILE__, __LINE__, sock, strerror(errno));
- cp_trace();
- exit(1);
- }
- if(x)
- {
- syslog(LOG_ERR, _("Incoming data socket error: %s"), strerror(x));
- return;
- }
-
- if((pkt.len = recvfrom(sock, (char *)&pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen)) <= 0)
- {
- syslog(LOG_ERR, _("Receiving packet failed: %s"), strerror(errno));
- return;
- }
-
- sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
-
- n = lookup_node_udp(&from);
-
- if(!n)
- {
- hostname = sockaddr2hostname(&from);
- syslog(LOG_WARNING, _("Received UDP packet from unknown source %s"), hostname);
- free(hostname);
- return;
- }
-
- if(n->connection)
- n->connection->last_ping_time = now;
-
- receive_udppacket(n, &pkt);
-cp
+
+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);