Detect and prevent two nodes with the same Name being on the VPN simultaneously.
[oweals/tinc.git] / src / net.c
index 309ebe4e8fb699ebc23bfaaf2561770adebd84c6..ee58ac0a0b943bf1f2e1c8e0f9bba3f179189925 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -44,6 +44,8 @@ bool do_purge = false;
 volatile bool running = false;
 
 time_t now = 0;
+int contradicting_add_edge = 0;
+int contradicting_del_edge = 0;
 
 /* Purge edges and subnets of unreachable nodes. Use carefully. */
 
@@ -68,9 +70,9 @@ static void purge(void) {
                        for(snode = n->subnet_tree->head; snode; snode = snext) {
                                snext = snode->next;
                                s = snode->data;
+                               send_del_subnet(broadcast, s);
                                if(!strictsubnets)
-                                       send_del_subnet(broadcast, s);
-                               subnet_del(n, s);
+                                       subnet_del(n, s);
                        }
 
                        for(enode = n->edge_tree->head; enode; enode = enext) {
@@ -98,7 +100,8 @@ static void purge(void) {
                                        break;
                        }
 
-                       if(!enode)
+                       if(!enode && (!strictsubnets || !n->subnet_tree->head))
+                               /* in strictsubnets mode do not delete nodes with subnets */
                                node_del(n);
                }
        }
@@ -296,7 +299,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
                if(FD_ISSET(c->socket, readset)) {
                        if(c->status.connecting) {
                                c->status.connecting = false;
-                               getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
+                               getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);
 
                                if(!result)
                                        finish_connecting(c);
@@ -414,6 +417,19 @@ int main_loop(void) {
                                send_key_changed(broadcast, myself);
                                keyexpires = now + keylifetime;
                        }
+
+                       if(contradicting_del_edge && contradicting_add_edge) {
+                               logger(LOG_WARNING, "Possible node with same Name as us!");
+
+                               if(rand() % 3 == 0) {
+                                       logger(LOG_ERR, "Shutting down, check configuration of all nodes for duplicate Names!");
+                                       running = false;
+                                       break;
+                               }
+
+                               contradicting_add_edge = 0;
+                               contradicting_del_edge = 0;
+                       }
                }
 
                if(sigalrm) {
@@ -488,6 +504,36 @@ int main_loop(void) {
 
                        last_config_check = now;
 
+                       /* If StrictSubnet is set, expire deleted Subnets and read new ones in */
+
+                       if(strictsubnets) {
+                               subnet_t *subnet;
+
+                               for(node = subnet_tree->head; node; node = node->next) {
+                                       subnet = node->data;
+                                       subnet->expires = 1;
+                               }
+
+                               load_all_subnets();
+
+                               for(node = subnet_tree->head; node; node = next) {
+                                       next = node->next;
+                                       subnet = node->data;
+                                       if(subnet->expires == 1) {
+                                               send_del_subnet(broadcast, subnet);
+                                               if(subnet->owner->status.reachable)
+                                                       subnet_update(subnet->owner, subnet, false);
+                                               subnet_del(subnet->owner, subnet);
+                                       } else if(subnet->expires == -1) {
+                                               subnet->expires = 0;
+                                       } else {
+                                               send_add_subnet(broadcast, subnet);
+                                               if(subnet->owner->status.reachable)
+                                                       subnet_update(subnet->owner, subnet, true);
+                                       }
+                               }
+                       }
+
                        /* Try to make outgoing connections */
                        
                        try_outgoing_connections();