Make sure the packet source MAC address is always set.
[tinc] / src / net_packet.c
index 1fdc0fe..6f72e05 100644 (file)
@@ -260,7 +260,7 @@ static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
        if(!n->status.validkey_in || !digest_active(n->indigest) || inpkt->len < sizeof(seqno_t) + digest_length(n->indigest))
                return false;
 
-       return digest_verify(n->indigest, SEQNO(inpkt), inpkt->len - digest_length(n->indigest), DATA(inpkt) + inpkt->len - digest_length(n->indigest));
+       return digest_verify(n->indigest, inpkt->data, inpkt->len - digest_length(n->indigest), inpkt->data + inpkt->len - digest_length(n->indigest));
 #endif
 }
 
@@ -282,13 +282,19 @@ static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
                        }
                        return false;
                }
-               inpkt->offset += 2 * sizeof(node_id_t);
                n->status.udppacket = true;
-               bool result = sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len - 2 * sizeof(node_id_t));
+               bool result = sptps_receive_data(&n->sptps, DATA(inpkt), inpkt->len);
                n->status.udppacket = false;
 
                if(!result) {
-                       logger(DEBUG_TRAFFIC, LOG_ERR, "Got bad packet from %s (%s)", n->name, n->hostname);
+                       /* Uh-oh. It might be that the tunnel is stuck in some corrupted state,
+                          so let's restart SPTPS in case that helps. But don't do that too often
+                          to prevent storms, and because that would make life a little too easy
+                          for external attackers trying to DoS us. */
+                       if(n->last_req_key < now.tv_sec - 10) {
+                               logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode raw TCP packet from %s (%s), restarting SPTPS", n->name, n->hostname);
+                               send_req_key(n);
+                       }
                        return false;
                }
                return true;
@@ -448,6 +454,13 @@ bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) {
                return true;
        }
 
+       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 TCP packet from %s (%s) because the destination, %s (%s), is unreachable", from->name, from->hostname, to->name, to->hostname);
+               return true;
+       }
+
        /* Help the sender reach us over UDP.
           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. */
@@ -464,11 +477,17 @@ bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) {
 
        /* The packet is for us */
 
-       if(!from->status.validkey) {
-               logger(DEBUG_PROTOCOL, LOG_ERR, "Got SPTPS packet from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
+       if(!sptps_receive_data(&from->sptps, data, len)) {
+               /* Uh-oh. It might be that the tunnel is stuck in some corrupted state,
+                  so let's restart SPTPS in case that helps. But don't do that too often
+                  to prevent storms. */
+               if(from->last_req_key < now.tv_sec - 10) {
+                       logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode raw TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname);
+                       send_req_key(from);
+               }
                return true;
        }
-       sptps_receive_data(&from->sptps, data, len);
+
        send_mtu_info(myself, from, MTU);
        return true;
 }
@@ -735,7 +754,7 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_
        /* 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. */
 
        if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) {
-               if((from != myself || to->status.validkey) && (to->nexthop->connection->options >> 24) >= 7) {
+               if(type != SPTPS_HANDSHAKE && (to->nexthop->connection->options >> 24) >= 7) {
                        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;
@@ -746,9 +765,10 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_
 
                char buf[len * 4 / 3 + 5];
                b64encode(data, buf, len);
-               /* If no valid key is known yet, send the packets using ANS_KEY requests,
-                  to ensure we get to learn the reflexive UDP address. */
-               if(from == myself && !to->status.validkey) {
+               /* If this is a handshake packet, use ANS_KEY instead of REQ_KEY, for two reasons:
+                   - We don't want intermediate nodes to switch to UDP to relay these packets;
+                   - ANS_KEY allows us to learn the reflexive UDP address. */
+               if(type == SPTPS_HANDSHAKE) {
                        to->incompression = myself->incompression;
                        return send_request(to->nexthop->connection, "%d %s %s %s -1 -1 -1 %d", ANS_KEY, from->name, to->name, buf, to->incompression);
                } else {
@@ -1177,15 +1197,13 @@ static void try_tx_sptps(node_t *n, bool mtu) {
 
        node_t *via = (n->via == myself) ? n->nexthop : n->via;
 
-       /* If the static relay doesn't support SPTPS, everything goes via TCP anyway. */
-
-       if((via->options >> 24) < 4)
-               return;
-
-       /* If we do have a static relay, try everything with that one instead. */
+       /* If we do have a static relay, try everything with that one instead, if it supports relaying. */
 
-       if(via != n)
-               return try_tx_sptps(via, mtu);
+       if(via != n) {
+               if((via->options >> 24) < 4)
+                       return;
+               return try_tx(via, mtu);
+       }
 
        /* Otherwise, try to establish UDP connectivity. */
 
@@ -1197,7 +1215,7 @@ static void try_tx_sptps(node_t *n, bool mtu) {
           while we try to establish direct connectivity. */
 
        if(!n->status.udp_confirmed && n != n->nexthop && (n->nexthop->options >> 24) >= 4)
-               try_tx_sptps(n->nexthop, mtu);
+               try_tx(n->nexthop, mtu);
 }
 
 static void try_tx_legacy(node_t *n, bool mtu) {
@@ -1222,6 +1240,8 @@ static void try_tx_legacy(node_t *n, bool mtu) {
 }
 
 void try_tx(node_t *n, bool mtu) {
+       if(!n->status.reachable)
+               return;
        if(n->status.sptps)
                try_tx_sptps(n, mtu);
        else
@@ -1232,8 +1252,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);
@@ -1258,7 +1282,7 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
 
        if(n->status.sptps) {
                send_sptps_packet(n, packet);
-               try_tx_sptps(n, true);
+               try_tx(n, true);
                return;
        }
 
@@ -1278,7 +1302,7 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
        }
 
        send_udppacket(via, packet);
-       try_tx_legacy(via, true);
+       try_tx(via, true);
 }
 
 void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
@@ -1336,7 +1360,7 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
                if(!n->status.reachable || n == myself)
                        continue;
 
-               if((n->status.sptps && !n->sptps.instate) || !n->status.validkey_in)
+               if(!n->status.validkey_in && !(n->status.sptps && n->sptps.instate))
                        continue;
 
                bool soft = false;
@@ -1426,10 +1450,16 @@ skip_harder:
                return;
        }
 
+       pkt.offset = 0;
+
        if(n->status.sptps) {
-               pkt.offset = 2 * sizeof(node_id_t);
+               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)) {
+               if(!memcmp(DSTID(&pkt), &nullid, sizeof nullid) || !relay_enabled) {
                        direct = true;
                        from = n;
                        to = myself;
@@ -1442,6 +1472,13 @@ skip_harder:
                        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.
@@ -1454,8 +1491,8 @@ 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 - 2 * sizeof(node_id_t));
-                       try_tx_sptps(to, true);
+                       send_sptps_data(to, from, 0, DATA(&pkt), pkt.len);
+                       try_tx(to, true);
                        return;
                }
        } else {
@@ -1463,7 +1500,6 @@ skip_harder:
                from = n;
        }
 
-       pkt.offset = 0;
        if(!receive_udppacket(from, &pkt))
                return;