tinc-gui: Reformat codebase according to PEP8
[tinc] / src / net_packet.c
index 245ce62..fc5720a 100644 (file)
@@ -64,7 +64,7 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999
 
 static void send_udppacket(node_t *, vpn_packet_t *);
 
-unsigned replaywin = 16;
+unsigned replaywin = 32;
 bool localdiscovery = true;
 bool udp_discovery = true;
 int udp_discovery_keepalive_interval = 10;
@@ -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;
@@ -428,6 +434,64 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
        receive_packet(c->node, &outpkt);
 }
 
+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);
+               return false;
+       }
+
+       node_t *to = lookup_node_id((node_id_t *)data);
+       data += sizeof(node_id_t); len -= sizeof(node_id_t);
+       if(!to) {
+               logger(DEBUG_PROTOCOL, LOG_ERR, "Got TCP SPTPS packet from %s (%s) with unknown destination ID", c->name, c->hostname);
+               return true;
+       }
+
+       node_t *from = lookup_node_id((node_id_t *)data);
+       data += sizeof(node_id_t); len -= sizeof(node_id_t);
+       if(!from) {
+               logger(DEBUG_PROTOCOL, LOG_ERR, "Got TCP SPTPS packet from %s (%s) with unknown source ID", c->name, c->hostname);
+               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. */
+       if(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, len);
+               try_tx(to, true);
+               return true;
+       }
+
+       /* The packet is for us */
+
+       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;
+       }
+
+       send_mtu_info(myself, from, MTU);
+       return true;
+}
+
 static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
        if(!n->status.validkey && !n->connection)
                return;
@@ -681,7 +745,7 @@ end:
 #endif
 }
 
-static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void *data, size_t len) {
+bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_t len) {
        node_t *relay = (to->via != myself && (type == PKT_PROBE || (len - SPTPS_DATAGRAM_OVERHEAD) <= to->via->minmtu)) ? to->via : to->nexthop;
        bool direct = from == myself && to == relay;
        bool relay_supported = (relay->options >> 24) >= 4;
@@ -690,15 +754,25 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
        /* 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(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;
+                       memcpy(buf_ptr, data, len); buf_ptr += 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);
+               }
+
                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 {
-                       return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, REQ_SPTPS, buf);
+                       return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, from->name, to->name, SPTPS_PACKET, buf);
                }
        }
 
@@ -725,7 +799,7 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
                choose_local_address(relay, &sa, &sock);
        if(!sa)
                choose_udp_address(relay, &sa, &sock);
-       logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname);
+       logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (UDP)", from->name, from->hostname, to->name, to->hostname, relay->name, relay->hostname);
        if(sendto(listen_socket[sock].udp.fd, buf, buf_ptr - buf, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
                if(sockmsgsize(sockerrno)) {
                        // Compensate for SPTPS overhead
@@ -744,10 +818,6 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
        return true;
 }
 
-bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
-       return send_sptps_data_priv(handle, myself, type, data, len);
-}
-
 bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t len) {
        node_t *from = handle;
 
@@ -1127,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. */
 
@@ -1147,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) {
@@ -1172,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
@@ -1208,7 +1278,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;
        }
 
@@ -1228,7 +1298,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) {
@@ -1286,7 +1356,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;
@@ -1376,10 +1446,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;
@@ -1392,6 +1468,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.
@@ -1404,8 +1487,8 @@ skip_harder:
                /* If we're not the final recipient, relay the packet. */
 
                if(to != myself) {
-                       send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
-                       try_tx_sptps(n, true);
+                       send_sptps_data(to, from, 0, DATA(&pkt), pkt.len);
+                       try_tx(to, true);
                        return;
                }
        } else {
@@ -1413,7 +1496,6 @@ skip_harder:
                from = n;
        }
 
-       pkt.offset = 0;
        if(!receive_udppacket(from, &pkt))
                return;