Make datagram SPTPS key exchange more robust.
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 7 Oct 2012 11:31:19 +0000 (13:31 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 7 Oct 2012 11:31:19 +0000 (13:31 +0200)
Similar to old style key exchange requests, keep track of whether a key
exchange is already in progress and how long it took. If no key is known yet
or if key exchange takes too long, (re)start a new key exchange.

src/graph.c
src/net_packet.c
src/node.h
src/protocol_key.c

index 98eb469..621dd9b 100644 (file)
@@ -234,6 +234,10 @@ static void check_reachability(void) {
                        /* TODO: only clear status.validkey if node is unreachable? */
 
                        n->status.validkey = false;
+                       if(n->status.sptps) {
+                               sptps_stop(&n->sptps);
+                               n->status.waitingforkey = false;
+                       }
                        n->last_req_key = 0;
 
                        n->maxmtu = MTU;
index abfb55c..371632f 100644 (file)
@@ -389,39 +389,48 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
 }
 
 static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
-       if(n->status.sptps) {
-               uint8_t type = 0;
-               int offset = 0;
-
-               if(!(origpkt->data[12] | origpkt->data[13])) {
-                       sptps_send_record(&n->sptps, PKT_PROBE, (char *)origpkt->data, origpkt->len);
-                       return;
+       if(!n->status.validkey) {
+               logger(DEBUG_TRAFFIC, LOG_INFO, "No valid key known yet for %s (%s)", n->name, n->hostname);
+               if(!n->status.waitingforkey)
+                       send_req_key(n);
+               else if(n->last_req_key + 10 < time(NULL)) {
+                       sptps_stop(&n->sptps);
+                       n->status.waitingforkey = false;
+                       send_req_key(n);
                }
+       }
 
-               if(routing_mode == RMODE_ROUTER)
-                       offset = 14;
-               else
-                       type = PKT_MAC;
+       uint8_t type = 0;
+       int offset = 0;
 
-               if(origpkt->len < offset)
-                       return;
-
-               vpn_packet_t outpkt;
+       if(!(origpkt->data[12] | origpkt->data[13])) {
+               sptps_send_record(&n->sptps, PKT_PROBE, (char *)origpkt->data, origpkt->len);
+               return;
+       }
 
-               if(n->outcompression) {
-                       int len = compress_packet(outpkt.data + offset, origpkt->data + offset, origpkt->len - offset, n->outcompression);
-                       if(len < 0) {
-                               logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)", n->name, n->hostname);
-                       } else if(len < origpkt->len - offset) {
-                               outpkt.len = len + offset;
-                               origpkt = &outpkt;
-                               type |= PKT_COMPRESSED;
-                       }
-               }
+       if(routing_mode == RMODE_ROUTER)
+               offset = 14;
+       else
+               type = PKT_MAC;
 
-               sptps_send_record(&n->sptps, type, (char *)origpkt->data + offset, origpkt->len - offset);
+       if(origpkt->len < offset)
                return;
+
+       vpn_packet_t outpkt;
+
+       if(n->outcompression) {
+               int len = compress_packet(outpkt.data + offset, origpkt->data + offset, origpkt->len - offset, n->outcompression);
+               if(len < 0) {
+                       logger(DEBUG_TRAFFIC, LOG_ERR, "Error while compressing packet to %s (%s)", n->name, n->hostname);
+               } else if(len < origpkt->len - offset) {
+                       outpkt.len = len + offset;
+                       origpkt = &outpkt;
+                       type |= PKT_COMPRESSED;
+               }
        }
+
+       sptps_send_record(&n->sptps, type, (char *)origpkt->data + offset, origpkt->len - offset);
+       return;
 }
 
 static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
@@ -620,6 +629,7 @@ bool receive_sptps_record(void *handle, uint8_t type, const char *data, uint16_t
 
        if(type == SPTPS_HANDSHAKE) {
                from->status.validkey = true;
+               from->status.waitingforkey = false;
                logger(DEBUG_META, LOG_INFO, "SPTPS key exchange with %s (%s) succesful", from->name, from->hostname);
                return true;
        }
index dad926c..d6d07d4 100644 (file)
@@ -30,7 +30,7 @@
 typedef struct node_status_t {
        unsigned int unused_active:1;           /* 1 if active (not used for nodes) */
        unsigned int validkey:1;                /* 1 if we currently have a valid key for him */
-       unsigned int unused_waitingforkey:1;    /* 1 if we already sent out a request */
+       unsigned int waitingforkey:1;           /* 1 if we already sent out a request */
        unsigned int visited:1;                 /* 1 if this node has been visited by one of the graph algorithms */
        unsigned int reachable:1;               /* 1 if this node is reachable in the graph */
        unsigned int indirect:1;                /* 1 if this node is not directly reachable by us */
index 802f7ca..3e8d29a 100644 (file)
@@ -116,6 +116,8 @@ bool send_req_key(node_t *to) {
                snprintf(label, sizeof label, "tinc UDP key expansion %s %s", myself->name, to->name);
                sptps_stop(&to->sptps);
                to->status.validkey = false;
+               to->status.waitingforkey = true;
+               to->last_req_key = time(NULL);
                to->incompression = myself->incompression;
                return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, sizeof label, send_initial_sptps_data, receive_sptps_record); 
        }
@@ -172,6 +174,8 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
                        snprintf(label, sizeof label, "tinc UDP key expansion %s %s", from->name, myself->name);
                        sptps_stop(&from->sptps);
                        from->status.validkey = false;
+                       from->status.waitingforkey = true;
+                       from->last_req_key = time(NULL);
                        sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record); 
                        sptps_receive_data(&from->sptps, buf, len);
                        return true;