Fix edge updates containing local address changes.
authorEtienne Dechamps <etienne@edechamps.fr>
Sun, 18 Dec 2016 14:25:20 +0000 (14:25 +0000)
committerEtienne Dechamps <etienne@edechamps.fr>
Sun, 18 Dec 2016 17:14:16 +0000 (17:14 +0000)
This commit fixes a logic bug in the edge update code where local
address changes are not taken into account if they are bundled in with
other changes. This bug breaks local discovery in some scenarios.

The regression was introduced by commit
e4670fc4a0576eb76f1807ce29fa9455dd247632.

src/protocol_edge.c

index dc0cf0512f6afcffc32510522192ea6e33150da7..1d7212275c7652d6bc86fb30dfe81c94887ebd2d 100644 (file)
@@ -132,7 +132,13 @@ bool add_edge_h(connection_t *c, const char *request) {
        e = lookup_edge(from, to);
 
        if(e) {
-               if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
+               // local_address.sa.sa_family will be 0 if we got it from older tinc versions
+               // local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions
+               // but for edge which does not have local_address
+               bool new_local_address = local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN &&
+                       sockaddrcmp(&e->local_address, &local_address);
+
+               if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address) || new_local_address) {
                        if(from == myself) {
                                logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
                                                   "ADD_EDGE", c->name, c->hostname);
@@ -147,6 +153,10 @@ bool add_edge_h(connection_t *c, const char *request) {
                                        sockaddrfree(&e->address);
                                        e->address = address;
                                }
+                               if(new_local_address) {
+                                       sockaddrfree(&e->local_address);
+                                       e->local_address = local_address;
+                               }
                                if(e->weight != weight) {
                                        splay_node_t *node = splay_unlink(edge_weight_tree, e);
                                        e->weight = weight;
@@ -155,36 +165,6 @@ bool add_edge_h(connection_t *c, const char *request) {
 
                                goto done;
                        }
-               } else if(sockaddrcmp(&e->local_address, &local_address)) {
-                       if(from == myself) {
-                               if(e->local_address.sa.sa_family && local_address.sa.sa_family) {
-                                       // Someone has the wrong local address for ourself. Correct then.
-                                       logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
-                                                          "ADD_EDGE", c->name, c->hostname);
-                                       send_add_edge(c, e);
-                                       sockaddrfree(&local_address);
-                                       return true;
-                               }
-                               // Otherwise, just ignore it.
-                               sockaddrfree(&local_address);
-                               return true;
-                       } else if(local_address.sa.sa_family && local_address.sa.sa_family != AF_UNKNOWN) {
-                               // We learned a new local address for this edge.
-                               // local_address.sa.sa_family will be 0 if we got it from older tinc versions
-                               // local_address.sa.sa_family will be 255 (AF_UNKNOWN) if we got it from newer versions
-                               // but for edge which does not have local_address
-                               sockaddrfree(&e->local_address);
-                               e->local_address = local_address;
-
-                               // Tell others about it.
-                               if(!tunnelserver)
-                                       forward_request(c, request);
-
-                               return true;
-                       } else {
-                               sockaddrfree(&local_address);
-                               return true;
-                       }
                } else {
                        sockaddrfree(&local_address);
                        return true;