Changed execution of tinc-up:
[oweals/tinc.git] / src / net.c
index 9376ec3b9101b9ac19553b6fb0991bc0e1268eff..bc32b7cc7763e0e14eb27e23d1a2a64da042fba0 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -17,7 +17,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: net.c,v 1.35.4.56 2000/10/30 00:22:53 guus Exp $
+    $Id: net.c,v 1.35.4.68 2000/11/07 21:43:28 guus Exp $
 */
 
 #include "config.h"
 #include <xalloc.h>
 
 #include "conf.h"
+#include "connlist.h"
+#include "meta.h"
 #include "net.h"
 #include "netutl.h"
 #include "protocol.h"
-#include "meta.h"
-#include "connlist.h"
 #include "subnet.h"
 
 #include "system.h"
@@ -78,29 +78,52 @@ char *unknown = NULL;
 subnet_t mymac;
 
 /*
-  strip off the MAC adresses of an ethernet frame
+  Execute the given script.
+  This function doesn't really belong here.
 */
-void strip_mac_addresses(vpn_packet_t *p)
+int execute_script(const char *name)
 {
-cp
-  memmove(p->data, p->data + 12, p->len -= 12);
-cp
-}
+  char *scriptname;
+  pid_t pid;
+  char *s;
 
-/*
-  reassemble MAC addresses
-*/
-void add_mac_addresses(vpn_packet_t *p)
-{
-cp
-  memcpy(p->data + 12, p->data, p->len);
-  p->len += 12;
-  p->data[0] = p->data[6] = 0xfe;
-  p->data[1] = p->data[7] = 0xfd;
-  /* Really evil pointer stuff just below! */
-  *((ip_t*)(&p->data[2])) = (ip_t)(htonl(myself->address));
-  *((ip_t*)(&p->data[8])) = *((ip_t*)(&p->data[26]));
-cp
+  if((pid = fork()) < 0)
+    {
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "fork");
+      return -1;
+    }
+
+  if(pid)
+    {
+      return 0;
+    }
+
+  /* Child here */
+
+  if(netname)
+    {
+      asprintf(&s, "NETNAME=%s", netname);
+      putenv(s);       /* Don't free s! see man 3 putenv */
+    }
+  else
+    {
+      unsetenv("NETNAME");
+    }
+
+  chdir(confbase);     /* This cannot fail since we already read config files from this directory. */
+  
+  asprintf(&scriptname, "%s/%s", confbase, name);
+  execl(scriptname, NULL);
+
+  /* No return on success */
+  
+  if(errno != ENOENT)  /* Ignore if the file does not exist */
+    syslog(LOG_WARNING, _("Error executing `%s': %m"), scriptname);
+
+  /* No need to free things */
+
+  exit(0);
 }
 
 int xsend(conn_list_t *cl, vpn_packet_t *inpkt)
@@ -129,8 +152,6 @@ cp
 
   total_socket_out += outlen;
 
-  cl->want_ping = 1;
-
   if((send(cl->socket, (char *) &(outpkt.len), outlen, 0)) < 0)
     {
       syslog(LOG_ERR, _("Error sending packet to %s (%s): %m"),
@@ -141,7 +162,7 @@ cp
   return 0;
 }
 
-int xrecv(vpn_packet_t *inpkt)
+int xrecv(conn_list_t *cl, vpn_packet_t *inpkt)
 {
   vpn_packet_t outpkt;
   int outlen, outpad;
@@ -265,7 +286,7 @@ cp
   returned a zero exit code
 */
 void flush_queue(conn_list_t *cl, packet_queue_t **pq,
-                int (*function)(conn_list_t*,void*))
+                int (*function)(conn_list_t*,vpn_packet_t*))
 {
   queue_element_t *p, *next = NULL;
 cp
@@ -327,14 +348,27 @@ cp
         }
 
       return -1;
-   }
+    }
 
   cl = subnet->owner;
     
+  if(cl == myself)
+    {
+      if(debug_lvl >= DEBUG_TRAFFIC)
+        {
+          syslog(LOG_NOTICE, _("Packet with destination %d.%d.%d.%d is looping back to us!"),
+                IP_ADDR_V(to));
+        }
+
+      return -1;
+    }
+
   /* If we ourselves have indirectdata flag set, we should send only to our uplink! */
 
   /* FIXME - check for indirection and reprogram it The Right Way(tm) this time. */
   
+  /* Connections are now opened beforehand...
+
   if(!cl->status.dataopen)
     if(setup_vpn_connection(cl) < 0)
       {
@@ -342,6 +376,7 @@ cp
               cl->name, cl->hostname);
         return -1;
       }
+  */
       
   if(!cl->status.validkey)
     {
@@ -380,11 +415,10 @@ int setup_tap_fd(void)
   int nfd;
   const char *tapfname;
   config_t const *cfg;
-  char *envvar;
   struct ifreq ifr;
 
 cp  
-  if((cfg = get_config_val(config, tapdevice)))
+  if((cfg = get_config_val(config, config_tapdevice)))
     tapfname = cfg->data.ptr;
   else
 #ifdef HAVE_TUNTAP
@@ -421,19 +455,11 @@ cp
     strncpy(ifr.ifr_name, netname, IFNAMSIZ);
 cp
   if (!ioctl(tap_fd, TUNSETIFF, (void *) &ifr))
-  { 
+  {
     syslog(LOG_INFO, _("%s is a new style tun/tap device"), tapfname);
     taptype = TAP_TYPE_TUNTAP;
   }
 #endif
-
-  /* Add name of network interface to environment (for scripts) */
-
-  ioctl(tap_fd, SIOCGIFNAME, (void *) &ifr);
-  asprintf(&envvar, "IFNAME=%s", ifr.ifr_name);
-  putenv(envvar);
-  free(envvar);
-  
 cp
   return 0;
 }
@@ -457,24 +483,27 @@ cp
 
   if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
     {
-      syslog(LOG_ERR, _("setsockopt: %m"));
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "setsockopt");
       return -1;
     }
 
   if(setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)))
     {
-      syslog(LOG_ERR, _("setsockopt: %m"));
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "setsockopt");
       return -1;
     }
 
   flags = fcntl(nfd, F_GETFL);
   if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
     {
-      syslog(LOG_ERR, _("fcntl: %m"));
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "fcntl");
       return -1;
     }
 
-  if((cfg = get_config_val(config, interface)))
+  if((cfg = get_config_val(config, config_interface)))
     {
       if(setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, cfg->data.ptr, strlen(cfg->data.ptr)))
         {
@@ -487,7 +516,7 @@ cp
   a.sin_family = AF_INET;
   a.sin_port = htons(port);
   
-  if((cfg = get_config_val(config, interfaceip)))
+  if((cfg = get_config_val(config, config_interfaceip)))
     a.sin_addr.s_addr = htonl(cfg->data.ip->address);
   else
     a.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -500,7 +529,8 @@ cp
 
   if(listen(nfd, 3))
     {
-      syslog(LOG_ERR, _("listen: %m"));
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "listen");
       return -1;
     }
 cp
@@ -525,14 +555,16 @@ cp
 
   if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
     {
-      syslog(LOG_ERR, _("setsockopt: %m"));
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "setsockopt");
       return -1;
     }
 
   flags = fcntl(nfd, F_GETFL);
   if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
     {
-      syslog(LOG_ERR, _("fcntl: %m"));
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "fcntl");
       return -1;
     }
 
@@ -562,7 +594,7 @@ cp
   if(debug_lvl >= DEBUG_CONNECTIONS)
     syslog(LOG_INFO, _("Trying to connect to %s"), cl->hostname);
 
-  if((cfg = get_config_val(cl->config, port)) == NULL)
+  if((cfg = get_config_val(cl->config, config_port)) == NULL)
     cl->port = 655;
   else
     cl->port = cfg->data.val;
@@ -613,7 +645,7 @@ int setup_outgoing_connection(char *name)
 {
   conn_list_t *ncn;
   struct hostent *h;
-  config_t *cfg;
+  config_t const *cfg;
 cp
   if(check_id(name))
     {
@@ -631,7 +663,7 @@ cp
       return -1;
     }
     
-  if(!(cfg = get_config_val(ncn->config, address)))
+  if(!(cfg = get_config_val(ncn->config, config_address)))
     {
       syslog(LOG_ERR, _("No address specified for %s"));
       free_conn_list(ncn);
@@ -660,7 +692,6 @@ cp
   ncn->buffer = xmalloc(MAXBUFSIZE);
   ncn->buflen = 0;
   ncn->last_ping_time = time(NULL);
-  ncn->want_ping = 0;
 
   conn_list_add(ncn);
 
@@ -675,6 +706,7 @@ cp
 int setup_myself(void)
 {
   config_t const *cfg;
+  config_t *next;
   subnet_t *net;
 cp
   myself = new_conn_list();
@@ -683,7 +715,7 @@ cp
   myself->flags = 0;
   myself->protocol_version = PROT_CURRENT;
 
-  if(!(cfg = get_config_val(config, tincname))) /* Not acceptable */
+  if(!(cfg = get_config_val(config, config_name))) /* Not acceptable */
     {
       syslog(LOG_ERR, _("Name for tinc daemon required!"));
       return -1;
@@ -697,7 +729,7 @@ cp
       return -1;
     }
 cp
-  if(!(cfg = get_config_val(config, privatekey)))
+  if(!(cfg = get_config_val(config, config_privatekey)))
     {
       syslog(LOG_ERR, _("Private key for tinc daemon required!"));
       return -1;
@@ -715,7 +747,7 @@ cp
       return -1;
     }
 cp  
-  if(!(cfg = get_config_val(myself->config, publickey)))
+  if(!(cfg = get_config_val(myself->config, config_publickey)))
     {
       syslog(LOG_ERR, _("Public key for tinc daemon required!"));
       return -1;
@@ -731,22 +763,22 @@ cp
       return -1;
     }
 */
-  if(!(cfg = get_config_val(myself->config, port)))
+  if(!(cfg = get_config_val(myself->config, config_port)))
     myself->port = 655;
   else
     myself->port = cfg->data.val;
 
-  if((cfg = get_config_val(myself->config, indirectdata)))
+  if((cfg = get_config_val(myself->config, config_indirectdata)))
     if(cfg->data.val == stupid_true)
       myself->flags |= EXPORTINDIRECTDATA;
 
-  if((cfg = get_config_val(myself->config, tcponly)))
+  if((cfg = get_config_val(myself->config, config_tcponly)))
     if(cfg->data.val == stupid_true)
       myself->flags |= TCPONLY;
 
 /* Read in all the subnets specified in the host configuration file */
 
-  for(cfg = myself->config; (cfg = get_config_val(cfg, subnet)); cfg = cfg->next)
+  for(next = myself->config; (cfg = get_config_val(next, config_subnet)); next = cfg->next)
     {
       net = new_subnet();
       net->type = SUBNET_IPV4;
@@ -770,13 +802,6 @@ cp
       return -1;
     }
 
-  if((myself->socket = setup_vpn_in_socket(myself->port)) < 0)
-    {
-      syslog(LOG_ERR, _("Unable to set up an incoming vpn data socket!"));
-      close(myself->meta_socket);
-      return -1;
-    }
-
   /* Generate packet encryption key */
 
   myself->cipher_pkttype = EVP_bf_cfb();
@@ -786,7 +811,7 @@ cp
   myself->cipher_pktkey = (char *)xmalloc(myself->cipher_pktkeylength);
   RAND_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength);
 
-  if(!(cfg = get_config_val(config, keyexpire)))
+  if(!(cfg = get_config_val(config, config_keyexpire)))
     keylifetime = 3600;
   else
     keylifetime = cfg->data.val;
@@ -807,7 +832,7 @@ sigalrm_handler(int a)
 {
   config_t const *cfg;
 cp
-  cfg = get_config_val(upstreamcfg, connectto);
+  cfg = get_config_val(upstreamcfg, config_connectto);
 
   if(!cfg && upstreamcfg == config)
     /* No upstream IP given, we're listen only. */
@@ -821,7 +846,7 @@ cp
           signal(SIGALRM, SIG_IGN);
           return;
         }
-      cfg = get_config_val(upstreamcfg, connectto); /* Or else we try the next ConnectTo line */
+      cfg = get_config_val(upstreamcfg, config_connectto); /* Or else we try the next ConnectTo line */
     }
 
   signal(SIGALRM, sigalrm_handler);
@@ -841,12 +866,17 @@ cp
 int setup_network_connections(void)
 {
   config_t const *cfg;
-  char *scriptname;
 cp
-  if((cfg = get_config_val(config, pingtimeout)) == NULL)
-    timeout = 5;
+  if((cfg = get_config_val(config, config_pingtimeout)) == NULL)
+    timeout = 60;
   else
-    timeout = cfg->data.val;
+    {
+      timeout = cfg->data.val;
+      if(timeout < 1)
+        {
+          timeout = 86400;
+        }
+     }
 
   if(setup_tap_fd() < 0)
     return -1;
@@ -855,23 +885,9 @@ cp
     return -1;
 
   /* Run tinc-up script to further initialize the tap interface */
-
-  asprintf(&scriptname, "%s/tinc-up", confbase);
-
-  if(!fork())
-    {
-
-      execl(scriptname, NULL);
-
-      if(errno != ENOENT)
-        syslog(LOG_WARNING, _("Error while executing %s: %m"), scriptname);
-
-      exit(0);
-    }
-
-  free(scriptname);
-
-  if(!(cfg = get_config_val(config, connectto)))
+  execute_script("tinc-up");
+  
+  if(!(cfg = get_config_val(config, config_connectto)))
     /* No upstream IP given, we're listen only. */
     return 0;
 
@@ -880,7 +896,7 @@ cp
       upstreamcfg = cfg->next;
       if(!setup_outgoing_connection(cfg->data.ptr))   /* function returns 0 when there are no problems */
         return 0;
-      cfg = get_config_val(upstreamcfg, connectto); /* Or else we try the next ConnectTo line */
+      cfg = get_config_val(upstreamcfg, config_connectto); /* Or else we try the next ConnectTo line */
     }
     
   signal(SIGALRM, sigalrm_handler);
@@ -898,7 +914,6 @@ cp
 void close_network_connections(void)
 {
   conn_list_t *p;
-  char *scriptname;
 cp
   for(p = conn_list; p != NULL; p = p->next)
     {
@@ -910,28 +925,15 @@ cp
     if(myself->status.active)
       {
        close(myself->meta_socket);
-       close(myself->socket);
         free_conn_list(myself);
         myself = NULL;
       }
 
-  /* Execute tinc-down script right before shutting down the interface */
-
-  asprintf(&scriptname, "%s/tinc-down", confbase);
-
-  if(!fork())
-    {
-      execl(scriptname, NULL);
-
-      if(errno != ENOENT)
-        syslog(LOG_WARNING, _("Error while executing %s: %m"), scriptname);
+  close(tap_fd);
 
-      exit(0);
-    }
-      
-  free(scriptname);
+  /* Execute tinc-down script right after shutting down the interface */
+  execute_script("tinc-down");
 
-  close(tap_fd);
   destroy_conn_list();
 
   syslog(LOG_NOTICE, _("Terminating"));
@@ -946,6 +948,7 @@ int setup_vpn_connection(conn_list_t *cl)
 {
   int nfd, flags;
   struct sockaddr_in a;
+  const int one = 1;
 cp
   if(debug_lvl >= DEBUG_TRAFFIC)
     syslog(LOG_DEBUG, _("Opening UDP socket to %s"), cl->hostname);
@@ -957,6 +960,32 @@ cp
       return -1;
     }
 
+  if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
+    {
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "setsockopt");
+      return -1;
+    }
+
+  flags = fcntl(nfd, F_GETFL);
+  if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
+    {
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "fcntl");
+      return -1;
+    }
+
+  memset(&a, 0, sizeof(a));
+  a.sin_family = AF_INET;
+  a.sin_port = htons(myself->port);
+  a.sin_addr.s_addr = htonl(INADDR_ANY);
+
+  if(bind(nfd, (struct sockaddr *)&a, sizeof(struct sockaddr)))
+    {
+      syslog(LOG_ERR, _("Can't bind to port %hd/udp: %m"), myself->port);
+      return -1;
+    }
+
   a.sin_family = AF_INET;
   a.sin_port = htons(cl->port);
   a.sin_addr.s_addr = htonl(cl->address);
@@ -996,7 +1025,8 @@ cp
 
   if(getpeername(sfd, &ci, &len) < 0)
     {
-      syslog(LOG_ERR, _("Error: getpeername: %m"));
+      syslog(LOG_ERR, _("System call `%s' failed: %m"),
+            "getpeername");
       return NULL;
     }
 
@@ -1008,7 +1038,6 @@ cp
   p->buffer = xmalloc(MAXBUFSIZE);
   p->buflen = 0;
   p->last_ping_time = time(NULL);
-  p->want_ping = 0;
   
   if(debug_lvl >= DEBUG_CONNECTIONS)
     syslog(LOG_NOTICE, _("Connection from %s port %d"),
@@ -1037,7 +1066,6 @@ cp
     }
 
   FD_SET(myself->meta_socket, fs);
-  FD_SET(myself->socket, fs);
   FD_SET(tap_fd, fs);
 cp
 }
@@ -1047,18 +1075,16 @@ cp
   udp socket and write it to the ethertap
   device after being decrypted
 */
-int handle_incoming_vpn_data()
+int handle_incoming_vpn_data(conn_list_t *cl)
 {
   vpn_packet_t pkt;
   int x, l = sizeof(x);
-  struct sockaddr from;
   int lenin;
-  socklen_t fromlen = sizeof(from);
 cp
-  if(getsockopt(myself->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
+  if(getsockopt(cl->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
     {
       syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m"),
-            __FILE__, __LINE__, myself->socket);
+            __FILE__, __LINE__, cl->socket);
       return -1;
     }
   if(x)
@@ -1067,7 +1093,7 @@ cp
       return -1;
     }
 
-  if((lenin = recvfrom(myself->socket, (char *) &(pkt.len), MTU, 0, &from, &fromlen)) <= 0)
+  if((lenin = recv(cl->socket, (char *) &(pkt.len), MTU, 0)) <= 0)
     {
       syslog(LOG_ERR, _("Receiving packet failed: %m"));
       return -1;
@@ -1075,11 +1101,12 @@ cp
 
   if(debug_lvl >= DEBUG_TRAFFIC)
     {
-      syslog(LOG_DEBUG, _("Received packet of %d bytes"), lenin);
-    } 
+      syslog(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"), lenin,
+             cl->name, cl->hostname);
+    }
 
 cp
-  return xrecv(&pkt);
+  return xrecv(cl, &pkt);
 }
 
 /*
@@ -1162,7 +1189,7 @@ cp
        {
           if(p->last_ping_time + timeout < now)
             {
-              if(p->status.pinged && !p->status.got_pong)
+              if(p->status.pinged)
                 {
                   if(debug_lvl >= DEBUG_PROTOCOL)
                    syslog(LOG_INFO, _("%s (%s) didn't respond to PING"),
@@ -1170,12 +1197,9 @@ cp
                  p->status.timeout = 1;
                  terminate_connection(p);
                 }
-              else if(p->want_ping)
+              else
                 {
                   send_ping(p);
-                  p->last_ping_time = now;
-                  p->status.pinged = 1;
-                  p->status.got_pong = 0;
                 }
             }
        }
@@ -1220,7 +1244,6 @@ cp
 void check_network_activity(fd_set *f)
 {
   conn_list_t *p;
-  int x, l = sizeof(x);
 cp
   for(p = conn_list; p != NULL; p = p->next)
     {
@@ -1230,16 +1253,15 @@ cp
       if(p->status.dataopen)
        if(FD_ISSET(p->socket, f))
          {
-           /*
-             The only thing that can happen to get us here is apparently an
-             error on this outgoing(!) UDP socket that isn't immediate (i.e.
-             something that will not trigger an error directly on send()).
-             I've once got here when it said `No route to host'.
-           */
+            handle_incoming_vpn_data(p);
+
+            /* Old error stuff (FIXME: copy this to handle_incoming_vpn_data()
+            
            getsockopt(p->socket, SOL_SOCKET, SO_ERROR, &x, &l);
            syslog(LOG_ERR, _("Outgoing data socket error for %s (%s): %s"),
                    p->name, p->hostname, strerror(x));
            terminate_connection(p);
+            */
            return;
          }  
 
@@ -1252,9 +1274,6 @@ cp
            } 
     }
   
-  if(FD_ISSET(myself->socket, f))
-    handle_incoming_vpn_data();
-
   if(FD_ISSET(myself->meta_socket, f))
     handle_new_meta_connection();
 cp