Support normal socket (non-NSP) name lookups in resolver (for testing)
[oweals/gnunet.git] / src / exit / gnunet-helper-exit.c
index d1db2a6e649ebb78c3a83ce704e4cb9cc4ada7f4..e87aac5599401365e51581d4c2944b199e0070e2 100644 (file)
@@ -19,7 +19,7 @@
 */
 
 /**
- * @file exit/gnunet-helper-exit.c 
+ * @file exit/gnunet-helper-exit.c
  *
  * @brief the helper for exit nodes. Opens a virtual
  * network-interface, sends data received on the if to stdout, sends
@@ -47,6 +47,7 @@
 /**
  * Need 'struct GNUNET_MessageHeader'.
  */
+#include "gnunet_crypto_lib.h"
 #include "gnunet_common.h"
 
 /**
  */
 #include "gnunet_protocols.h"
 
+/**
+ * Should we print (interesting|debug) messages that can happen during
+ * normal operation?
+ */
+#define DEBUG GNUNET_NO
+
 /**
  * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
  */
 /**
  * Path to 'sysctl' binary.
  */
-#define SBIN_SYSCTL "/sbin/sysctl"
+static const char *sbin_sysctl;
 
 /**
  * Path to 'iptables' binary.
  */
-#define SBIN_IPTABLES "/sbin/iptables"
+static const char *sbin_iptables;
 
 
 #ifndef _LINUX_IN6_H
 struct in6_ifreq
 {
   struct in6_addr ifr6_addr;
-  uint32_t ifr6_prefixlen;
-  unsigned int ifr6_ifindex;
+  uint32_t ifr6_prefixlen; /* __u32 in the original */
+  int ifr6_ifindex;
 };
 #endif
 
 
+/**
+ * Open '/dev/null' and make the result the given
+ * file descriptor.
+ *
+ * @param target_fd desired FD to point to /dev/null
+ * @param flags open flags (O_RDONLY, O_WRONLY)
+ */
+static void
+open_dev_null (int target_fd,
+              int flags)
+{
+  int fd;
+
+  fd = open ("/dev/null", flags);
+  if (-1 == fd)
+    abort ();
+  if (fd == target_fd)
+    return;
+  if (-1 == dup2 (fd, target_fd))
+  {
+    (void) close (fd);
+    abort ();
+  }
+  (void) close (fd);
+}
+
 
 /**
  * Run the given command and wait for it to complete.
- * 
+ *
  * @param file name of the binary to run
  * @param cmd command line arguments (as given to 'execv')
  * @return 0 on success, 1 on any error
  */
 static int
-fork_and_exec (const char *file, 
+fork_and_exec (const char *file,
               char *const cmd[])
 {
   int status;
@@ -102,29 +135,35 @@ fork_and_exec (const char *file,
   pid = fork ();
   if (-1 == pid)
   {
-    fprintf (stderr, 
-            "fork failed: %s\n", 
+    fprintf (stderr,
+            "fork failed: %s\n",
             strerror (errno));
     return 1;
   }
   if (0 == pid)
   {
     /* we are the child process */
+    /* close stdin/stdout to not cause interference
+       with the helper's main protocol! */
+    (void) close (0);
+    open_dev_null (0, O_RDONLY);
+    (void) close (1);
+    open_dev_null (1, O_WRONLY);
     (void) execv (file, cmd);
     /* can only get here on error */
-    fprintf (stderr, 
-            "exec `%s' failed: %s\n", 
+    fprintf (stderr,
+            "exec `%s' failed: %s\n",
             file,
             strerror (errno));
     _exit (1);
   }
   /* keep running waitpid as long as the only error we get is 'EINTR' */
   while ( (-1 == (ret = waitpid (pid, &status, 0))) &&
-         (errno == EINTR) ); 
+         (errno == EINTR) );
   if (-1 == ret)
   {
-    fprintf (stderr, 
-            "waitpid failed: %s\n", 
+    fprintf (stderr,
+            "waitpid failed: %s\n",
             strerror (errno));
     return 1;
   }
@@ -164,6 +203,7 @@ init_tun (char *dev)
   if (fd >= FD_SETSIZE)
   {
     fprintf (stderr, "File descriptor to large: %d", fd);
+    (void) close (fd);
     return -1;
   }
 
@@ -175,7 +215,8 @@ init_tun (char *dev)
 
   if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr))
   {
-    fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun",
+    fprintf (stderr,
+            "Error with ioctl on `%s': %s\n", "/dev/net/tun",
              strerror (errno));
     (void) close (fd);
     return -1;
@@ -196,16 +237,16 @@ static void
 set_address6 (const char *dev, const char *address, unsigned long prefix_len)
 {
   struct ifreq ifr;
-  struct in6_ifreq ifr6;
   struct sockaddr_in6 sa6;
   int fd;
+  struct in6_ifreq ifr6;
 
   /*
    * parse the new address
    */
   memset (&sa6, 0, sizeof (struct sockaddr_in6));
   sa6.sin6_family = AF_INET6;
-  if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
+  if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr))
   {
     fprintf (stderr, "Failed to parse address `%s': %s\n", address,
              strerror (errno));
@@ -470,7 +511,9 @@ run (int fd_tun)
         }
         else if (0 == buftun_size)
         {
+#if DEBUG
           fprintf (stderr, "EOF on tun\n");
+#endif
           shutdown (fd_tun, SHUT_RD);
           shutdown (1, SHUT_WR);
           read_open = 0;
@@ -492,7 +535,10 @@ run (int fd_tun)
 
         if (-1 == written)
         {
-          fprintf (stderr, "write-error to stdout: %s\n", strerror (errno));
+#if !DEBUG
+         if (errno != EPIPE)
+#endif
+           fprintf (stderr, "write-error to stdout: %s\n", strerror (errno));
           shutdown (fd_tun, SHUT_RD);
           shutdown (1, SHUT_WR);
           read_open = 0;
@@ -523,7 +569,9 @@ run (int fd_tun)
         }
         else if (0 == bufin_size)
         {
+#if DEBUG
           fprintf (stderr, "EOF on stdin\n");
+#endif
           shutdown (0, SHUT_RD);
           shutdown (fd_tun, SHUT_WR);
           write_open = 0;
@@ -589,9 +637,9 @@ PROCESS_BUFFER:
  * Open VPN tunnel interface.
  *
  * @param argc must be 6
- * @param argv 0: binary name ("gnunet-helper-vpn")
- *             1: tunnel interface name ("gnunet-vpn")
- *             2: IPv4 "physical" interface name ("eth0"), or "%" to not do IPv4 NAT
+ * @param argv 0: binary name ("gnunet-helper-exit")
+ *             1: tunnel interface name ("gnunet-exit")
+ *             2: IPv4 "physical" interface name ("eth0"), or "-" to not do IPv4 NAT
  *             3: IPv6 address ("::1"), or "-" to skip IPv6
  *             4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"]
  *             5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4
@@ -606,7 +654,7 @@ main (int argc, char **argv)
 
   if (7 != argc)
   {
-    fprintf (stderr, "Fatal: must supply 5 arguments!\n");
+    fprintf (stderr, "Fatal: must supply 6 arguments!\n");
     return 1;
   }
   if ( (0 == strcmp (argv[3], "-")) &&
@@ -615,13 +663,41 @@ main (int argc, char **argv)
     fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n");
     return 1;
   }
+  if (0 == access ("/sbin/iptables", X_OK))
+    sbin_iptables = "/sbin/iptables";
+  else if (0 == access ("/usr/sbin/iptables", X_OK))
+    sbin_iptables = "/usr/sbin/iptables";
+  else
+  {
+    fprintf (stderr,
+            "Fatal: executable iptables not found in approved directories: %s\n",
+            strerror (errno));
+    return 1;
+  }
+  if (0 == access ("/sbin/sysctl", X_OK))
+    sbin_sysctl = "/sbin/sysctl";
+  else if (0 == access ("/usr/sbin/sysctl", X_OK))
+    sbin_sysctl = "/usr/sbin/sysctl";
+  else
+  {
+    fprintf (stderr,
+            "Fatal: executable sysctl not found in approved directories: %s\n",
+            strerror (errno));
+    return 1;
+  }
 
   strncpy (dev, argv[1], IFNAMSIZ);
   dev[IFNAMSIZ - 1] = '\0';
 
   if (-1 == (fd_tun = init_tun (dev)))
   {
-    fprintf (stderr, "Fatal: could not initialize tun-interface\n");
+    fprintf (stderr,
+            "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
+            dev,
+            argv[3],
+            argv[4],
+            argv[5],
+            argv[6]);
     return 1;
   }
 
@@ -630,25 +706,25 @@ main (int argc, char **argv)
     {
       const char *address = argv[3];
       long prefix_len = atol (argv[4]);
-      
+
       if ((prefix_len < 1) || (prefix_len > 127))
       {
        fprintf (stderr, "Fatal: prefix_len out of range\n");
        return 1;
-      }      
-      set_address6 (dev, address, prefix_len);    
+      }
+      set_address6 (dev, address, prefix_len);
     }
     {
       char *const sysctl_args[] =
        {
          "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL
        };
-      if (0 != fork_and_exec (SBIN_SYSCTL,
+      if (0 != fork_and_exec (sbin_sysctl,
                              sysctl_args))
       {
        fprintf (stderr,
                 "Failed to enable IPv6 forwarding.  Will continue anyway.\n");
-      }    
+      }
     }
   }
 
@@ -657,7 +733,7 @@ main (int argc, char **argv)
     {
       const char *address = argv[5];
       const char *mask = argv[6];
-      
+
       set_address4 (dev, address, mask);
     }
     {
@@ -665,28 +741,28 @@ main (int argc, char **argv)
        {
          "sysctl", "-w", "net.ipv4.ip_forward=1", NULL
        };
-      if (0 != fork_and_exec (SBIN_SYSCTL,
+      if (0 != fork_and_exec (sbin_sysctl,
                              sysctl_args))
       {
        fprintf (stderr,
                 "Failed to enable IPv4 forwarding.  Will continue anyway.\n");
-      }    
+      }
     }
-    if (0 != strcmp (argv[2], "%"))
+    if (0 != strcmp (argv[2], "-"))
     {
       char *const iptables_args[] =
        {
          "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j", "MASQUERADE", NULL
        };
-      if (0 != fork_and_exec (SBIN_IPTABLES,
+      if (0 != fork_and_exec (sbin_iptables,
                              iptables_args))
       {
        fprintf (stderr,
                 "Failed to enable IPv4 masquerading (NAT).  Will continue anyway.\n");
-      }    
+      }
     }
   }
-  
+
   uid_t uid = getuid ();
 #ifdef HAVE_SETRESUID
   if (0 != setresuid (uid, uid, uid))
@@ -713,7 +789,7 @@ main (int argc, char **argv)
   run (fd_tun);
   global_ret = 0;
  cleanup:
-  close (fd_tun);
+  (void) close (fd_tun);
   return global_ret;
 }