Terminate a connection on any error. Furthermore, disallow del_host,
[tinc] / src / net.c
index b3474c3..9daf8c8 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -1,6 +1,6 @@
 /*
     net.c -- most of the network code
-    Copyright (C) 1998,99 Ivo Timmermans <zarq@iname.com>
+    Copyright (C) 1998,1999,2000 Ivo Timmermans <zarq@iname.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
@@ -51,7 +51,7 @@ int total_tap_out = 0;
 int total_socket_in = 0;
 int total_socket_out = 0;
 
-time_t last_ping_time = 0;
+static int seconds_till_retry;
 
 /* The global list of existing connections */
 conn_list_t *conn_list = NULL;
@@ -107,11 +107,13 @@ cp
     }
 
   total_socket_out += r;
+
+  cl->want_ping = 1;
 cp
   return 0;
 }
 
-int xrecv(conn_list_t *cl, real_packet_t *packet)
+int xrecv(conn_list_t *cl, void *packet)
 {
   vpn_packet_t vp;
   int lenin;
@@ -123,6 +125,9 @@ cp
     syslog(LOG_ERR, "Can't write to tap device: %m");
   else
     total_tap_out += lenin;
+
+  cl->want_ping = 0;
+  cl->last_ping_time = time(NULL);
 cp
   return 0;
 }
@@ -304,21 +309,6 @@ cp
   return xsend(cl, packet);
 }
 
-int send_broadcast(conn_list_t *cl, vpn_packet_t *packet)
-{
-  conn_list_t *p;
-cp
-  for(p = cl; p != NULL; p = p->next)
-    if(send_packet(p->real_ip, packet) < 0)
-      {
-       syslog(LOG_ERR, "Could not send a broadcast packet to %08lx (%08lx): %m",
-              p->vpn_ip, p->real_ip);
-       break; /* FIXME: should retry later, and send a ping over the metaconnection. */
-      }
-cp
-  return 0;
-}
-
 /*
   open the local ethertap device
 */
@@ -553,6 +543,30 @@ cp
   return 0;
 }
 
+RETSIGTYPE
+sigalrm_handler(int a)
+{
+  config_t const *cfg;
+cp
+  cfg = get_config_val(upstreamip);
+
+  if(!setup_outgoing_connection(cfg->data.ip->ip))
+    {
+      signal(SIGALRM, SIG_IGN);
+    }
+  else
+    {
+      signal(SIGALRM, sigalrm_handler);
+      seconds_till_retry += 5;
+      if(seconds_till_retry>300)    /* Don't wait more than 5 minutes. */
+        seconds_till_retry = 300;
+      alarm(seconds_till_retry);
+      syslog(LOG_ERR, "Still failed to connect to other. Will retry in %d seconds.",
+            seconds_till_retry);
+    }
+cp
+}
+
 /*
   setup all initial network connections
 */
@@ -561,7 +575,7 @@ int setup_network_connections(void)
   config_t const *cfg;
 cp
   if((cfg = get_config_val(pingtimeout)) == NULL)
-    timeout = 10;
+    timeout = 5;
   else
     timeout = cfg->data.val;
 
@@ -576,33 +590,14 @@ cp
     return 0;
 
   if(setup_outgoing_connection(cfg->data.ip->ip))
-    return -1;
-cp
-  return 0;
-}
-
-RETSIGTYPE
-sigalrm_handler(int a)
-{
-  config_t const *cfg;
-  static int seconds_till_retry;
-cp
-  cfg = get_config_val(upstreamip);
-
-  if(!setup_outgoing_connection(cfg->data.ip->ip))
-    {
-      signal(SIGALRM, SIG_IGN);
-      seconds_till_retry = 5;
-    }
-  else
     {
       signal(SIGALRM, sigalrm_handler);
-      seconds_till_retry += 5;
+      seconds_till_retry = 300;
       alarm(seconds_till_retry);
-      syslog(LOG_ERR, "Still failed to connect to other. Will retry in %d seconds.",
-            seconds_till_retry);
+      syslog(LOG_NOTICE, "Try to re-establish outgoing connection in 5 minutes.");
     }
 cp
+  return 0;
 }
 
 /*
@@ -666,8 +661,8 @@ cp
 
   if(connect(nfd, (struct sockaddr *)&a, sizeof(a)) == -1)
     {
-      syslog(LOG_ERR, "Create connection to %08lx:%d failed: %m", ntohs(cl->real_ip),
-            cl->port);
+      syslog(LOG_ERR, "Connecting to " IP_ADDR_S ":%d failed: %m",
+            IP_ADDR_V(cl->real_ip), cl->port);
       return -1;
     }
 
@@ -707,6 +702,8 @@ cp
   p->meta_socket = sfd;
   p->status.meta = 1;
   p->buflen = 0;
+  p->last_ping_time = time(NULL);
+  p->want_ping = 0;
   
   syslog(LOG_NOTICE, "Connection from %s:%d", p->hostname, htons(ci.sin_port));
 
@@ -831,62 +828,54 @@ cp
 
   if(cl->status.outgoing)
     {
-      alarm(5);
       signal(SIGALRM, sigalrm_handler);
+      seconds_till_retry = 5;
+      alarm(seconds_till_retry);
       syslog(LOG_NOTICE, "Try to re-establish outgoing connection in 5 seconds.");
     }
   
+  cl->status.active = 0;
   cl->status.remove = 1;
 cp
 }
 
 /*
-  send out a ping request to all active
-  connections
-*/
-int send_broadcast_ping(void)
-{
-  conn_list_t *p;
-cp
-  for(p = conn_list; p != NULL; p = p->next)
-    {
-      if(p->status.remove)
-       continue;
-      if(p->status.active && p->status.meta)
-       {
-         if(send_ping(p))
-           terminate_connection(p);
-         else
-           {
-             p->status.pinged = 1;
-             p->status.got_pong = 0;
-           }
-       }
-    }
-
-  last_ping_time = time(NULL);
-cp
-  return 0;
-}
-
-/*
-  end all connections that did not respond
-  to the ping probe in time
+  Check if the other end is active.
+  If we have sent packets, but didn't receive any,
+  then possibly the other end is dead. We send a
+  PING request over the meta connection. If the other
+  end does not reply in time, we consider them dead
+  and close the connection.
 */
 int check_dead_connections(void)
 {
   conn_list_t *p;
+  time_t now;
 cp
+  now = time(NULL);
   for(p = conn_list; p != NULL; p = p->next)
     {
       if(p->status.remove)
        continue;
-      if(p->status.active && p->status.meta && p->status.pinged && !p->status.got_pong)
+      if(p->status.active && p->status.meta)
        {
-         syslog(LOG_INFO, "%s (" IP_ADDR_S ") didn't respond to ping",
-                p->hostname, IP_ADDR_V(p->vpn_ip));
-         p->status.timeout = 1;
-         terminate_connection(p);
+          if(p->last_ping_time + timeout < now)
+            {
+              if(p->status.pinged && !p->status.got_pong)
+                {
+                 syslog(LOG_INFO, "%s (" IP_ADDR_S ") didn't respond to ping",
+                        p->hostname, IP_ADDR_V(p->vpn_ip));
+                 p->status.timeout = 1;
+                 terminate_connection(p);
+                }
+              else if(p->want_ping)
+                {
+                  send_ping(p);
+                  p->last_ping_time = now;
+                  p->status.pinged = 1;
+                  p->status.got_pong = 0;
+                }
+            }
        }
     }
 cp
@@ -946,8 +935,8 @@ cp
 
   if(cl->buflen >= MAXBUFSIZE)
     {
-      syslog(LOG_ERR, "Metadata read buffer full! Discarding contents.");
-      cl->buflen = 0;
+      syslog(LOG_ERR, "Metadata read buffer overflow.");
+      return -1;
     }
 
   lenin = read(cl->meta_socket, cl->buffer, MAXBUFSIZE-cl->buflen);
@@ -982,17 +971,22 @@ cp
               if(request_handlers[request] == NULL)
                 {
                   syslog(LOG_ERR, "Unknown request: %s", cl->buffer);
-                  return 0;
+                  return -1;
                 }
 
               if(debug_lvl > 3)
                 syslog(LOG_DEBUG, "Got request: %s", cl->buffer);                             
 
-              request_handlers[request](cl);
+              if(request_handlers[request](cl))  /* Something went wrong. Probably scriptkiddies. Terminate. */
+                {
+                  syslog(LOG_ERR, "Error while processing request from IP_ADDR_S", IP_ADDR_V(cl->real_ip));
+                  return -1;
+                }
             }
           else
             {
-              syslog(LOG_ERR, "Bogus data received: %s", cl->buffer);
+              syslog(LOG_ERR, "Bogus data received.");
+              return -1;
             }
 
           cl->buflen -= cl->reqlen;
@@ -1004,6 +998,9 @@ cp
           break;
         }
     }
+
+  cl->last_ping_time = time(NULL);
+  cl->want_ping = 0;
 cp  
   return 0;
 }
@@ -1115,8 +1112,9 @@ void main_loop(void)
   fd_set fset;
   struct timeval tv;
   int r;
+  time_t last_ping_check;
 cp
-  last_ping_time = time(NULL);
+  last_ping_check = time(NULL);
 
   for(;;)
     {
@@ -1134,11 +1132,11 @@ cp
           return;
         }
 
-      if(r == 0 || last_ping_time + timeout < time(NULL))
-       /* Timeout... hm... something might be wrong. */
+      if(last_ping_check + timeout < time(NULL))
+       /* Let's check if everybody is still alive */
        {
          check_dead_connections();
-         send_broadcast_ping();
+          last_ping_check = time(NULL);
          continue;
        }