Always try next Address when an outgoing connection fails to authenticate.
[tinc] / src / net.c
index 6700a29..0496a86 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -1,8 +1,9 @@
 /*
     net.c -- most of the network code
     Copyright (C) 1998-2005 Ivo Timmermans,
-                  2000-2011 Guus Sliepen <guus@tinc-vpn.org>
+                  2000-2012 Guus Sliepen <guus@tinc-vpn.org>
                   2006      Scott Lamb <slamb@slamb.org>
+                 2011      Loïc Grenié <loic.grenie@gmail.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -49,6 +50,7 @@ bool graph_dump = false;
 time_t now = 0;
 int contradicting_add_edge = 0;
 int contradicting_del_edge = 0;
+static int sleeptime = 10;
 
 /* Purge edges and subnets of unreachable nodes. Use carefully. */
 
@@ -73,7 +75,7 @@ static void purge(void) {
                        for(snode = n->subnet_tree->head; snode; snode = snext) {
                                snext = snode->next;
                                s = snode->data;
-                               send_del_subnet(broadcast, s);
+                               send_del_subnet(everyone, s);
                                if(!strictsubnets)
                                        subnet_del(n, s);
                        }
@@ -82,7 +84,7 @@ static void purge(void) {
                                enext = enode->next;
                                e = enode->data;
                                if(!tunnelserver)
-                                       send_del_edge(broadcast, e);
+                                       send_del_edge(everyone, e);
                                edge_del(e);
                        }
                }
@@ -181,7 +183,7 @@ void terminate_connection(connection_t *c, bool report) {
 
        if(c->edge) {
                if(report && !tunnelserver)
-                       send_del_edge(broadcast, c->edge);
+                       send_del_edge(everyone, c->edge);
 
                edge_del(c->edge);
 
@@ -196,24 +198,20 @@ void terminate_connection(connection_t *c, bool report) {
                        e = lookup_edge(c->node, myself);
                        if(e) {
                                if(!tunnelserver)
-                                       send_del_edge(broadcast, e);
+                                       send_del_edge(everyone, e);
                                edge_del(e);
                        }
                }
        }
 
+       free_connection_partially(c);
+
        /* Check if this was our outgoing connection */
 
        if(c->outgoing) {
-               retry_outgoing(c->outgoing);
-               c->outgoing = NULL;
+               c->status.remove = false;
+               do_outgoing_connection(c);      
        }
-
-       free(c->outbuf);
-       c->outbuf = NULL;
-       c->outbuflen = 0;
-       c->outbufsize = 0;
-       c->outbufstart = 0;
 }
 
 /*
@@ -287,7 +285,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
 
        /* check input from kernel */
        if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
-               if(read_packet(&packet)) {
+               if(devops.read(&packet)) {
                        errors = 0;
                        packet.priority = 0;
                        route(myself, &packet);
@@ -341,7 +339,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset) {
 
        for(i = 0; i < listen_sockets; i++) {
                if(FD_ISSET(listen_socket[i].udp, readset))
-                       handle_incoming_vpn_data(listen_socket[i].udp);
+                       handle_incoming_vpn_data(i);
 
                if(FD_ISSET(listen_socket[i].tcp, readset))
                        handle_new_meta_connection(listen_socket[i].tcp);
@@ -463,18 +461,25 @@ int main_loop(void) {
                                keyexpires = now + keylifetime;
                        }
 
-                       if(contradicting_del_edge > 10 && contradicting_add_edge > 10) {
-                               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;
+                       /* Detect ADD_EDGE/DEL_EDGE storms that are caused when
+                        * two tinc daemons with the same name are on the VPN.
+                        * If so, sleep a while. If this happens multiple times
+                        * in a row, sleep longer. */
+
+                       if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
+                               logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
+                               usleep(sleeptime * 1000000LL);
+                               sleeptime *= 2;
+                               if(sleeptime < 0)
+                                       sleeptime = 3600;
+                       } else {
+                               sleeptime /= 2;
+                               if(sleeptime < 10)
+                                       sleeptime = 10;
                        }
+
+                       contradicting_add_edge = 0;
+                       contradicting_del_edge = 0;
                }
 
                if(sigalrm) {
@@ -500,6 +505,8 @@ int main_loop(void) {
                        struct stat s;
                        
                        sighup = false;
+
+                       reopenlogger();
                        
                        /* Reread our own configuration file */
 
@@ -565,14 +572,14 @@ int main_loop(void) {
                                        next = node->next;
                                        subnet = node->data;
                                        if(subnet->expires == 1) {
-                                               send_del_subnet(broadcast, subnet);
+                                               send_del_subnet(everyone, 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);
+                                               send_add_subnet(everyone, subnet);
                                                if(subnet->owner->status.reachable)
                                                        subnet_update(subnet->owner, subnet, true);
                                        }