- doxygen
[oweals/gnunet.git] / src / pt / test_gns_vpn.c
index 0c6e42500fc51c8d08cb476f6557a71c3757e5e2..e686ce8b49360bdf81d494f39361c12601eaea7f 100644 (file)
@@ -4,7 +4,7 @@
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 #include <microhttpd.h>
 #include "gnunet_namestore_service.h"
 #include "gnunet_gns_service.h"
 #include <microhttpd.h>
 #include "gnunet_namestore_service.h"
 #include "gnunet_gns_service.h"
-#include "gnunet_testing_lib-new.h"
+#include "gnunet_testing_lib.h"
 
 #define PORT 8080
 
 #define PORT 8080
-#define TEST_DOMAIN "www.gnunet"
+#define TEST_DOMAIN "www.gnu"
 
 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
 
 
 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
 
@@ -217,9 +217,9 @@ curl_main ()
     }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download complete, shutting down!\n");
     do_shutdown ();
     }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download complete, shutting down!\n");
     do_shutdown ();
-    return;    
+    return;
   }
   }
-  GNUNET_assert (CURLM_OK == curl_multi_fdset (multi, &rs, &ws, &es, &max)); 
+  GNUNET_assert (CURLM_OK == curl_multi_fdset (multi, &rs, &ws, &es, &max));
   if ( (CURLM_OK != curl_multi_timeout (multi, &timeout)) ||
        (-1 == timeout) )
     delay = GNUNET_TIME_UNIT_SECONDS;
   if ( (CURLM_OK != curl_multi_timeout (multi, &timeout)) ||
        (-1 == timeout) )
     delay = GNUNET_TIME_UNIT_SECONDS;
@@ -236,13 +236,14 @@ curl_main ()
                                              &nrs,
                                              &nws,
                                              &curl_task,
                                              &nrs,
                                              &nws,
                                              &curl_task,
-                                             NULL);  
+                                             NULL);
 }
 
 }
 
+
 static void
 start_curl (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 static void
 start_curl (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  GNUNET_asprintf (&url, 
+  GNUNET_asprintf (&url,
                   "http://%s/hello_world",     
                   TEST_DOMAIN);
   curl = curl_easy_init ();
                   "http://%s/hello_world",     
                   TEST_DOMAIN);
   curl = curl_easy_init ();
@@ -261,6 +262,15 @@ start_curl (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   curl_main ();
 }
 
   curl_main ();
 }
 
+
+static void
+disco_ns (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  GNUNET_NAMESTORE_disconnect (namestore);
+  namestore = NULL;
+}
+
+
 /**
  * Callback invoked from the namestore service once record is
  * created.
 /**
  * Callback invoked from the namestore service once record is
  * created.
@@ -270,33 +280,29 @@ start_curl (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  *                will match 'result_af' from the request
  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
  *                that the VPN allocated for the redirection;
  *                will match 'result_af' from the request
  * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
  *                that the VPN allocated for the redirection;
- *                traffic to this IP will now be redirected to the 
+ *                traffic to this IP will now be redirected to the
  *                specified target peer; NULL on error
  */
 static void
 commence_testing (void *cls, int32_t success, const char *emsg)
 {
  *                specified target peer; NULL on error
  */
 static void
 commence_testing (void *cls, int32_t success, const char *emsg)
 {
-  GNUNET_NAMESTORE_disconnect (namestore);
-  
+  GNUNET_SCHEDULER_add_now (&disco_ns, NULL);
+
   if ((emsg != NULL) && (GNUNET_YES != success))
   {
   if ((emsg != NULL) && (GNUNET_YES != success))
   {
-    fprintf (stderr, 
+    fprintf (stderr,
             "NS failed to create record %s\n", emsg);
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
             "NS failed to create record %s\n", emsg);
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
-  
-  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), start_curl, NULL);
-
+  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10), &start_curl, NULL);
 }
 
 
 }
 
 
-
-
 /**
  * Function to keep the HTTP server running.
  */
 /**
  * Function to keep the HTTP server running.
  */
-static void 
+static void
 mhd_main (void);
 
 
 mhd_main (void);
 
 
@@ -310,7 +316,7 @@ mhd_task (void *cls,
 }
 
 
 }
 
 
-static void 
+static void
 mhd_main ()
 {
   struct GNUNET_NETWORK_FDSet nrs;
 mhd_main ()
 {
   struct GNUNET_NETWORK_FDSet nrs;
@@ -345,9 +351,10 @@ mhd_main ()
                                             &nrs,
                                             &nws,
                                             &mhd_task,
                                             &nrs,
                                             &nws,
                                             &mhd_task,
-                                            NULL);  
+                                            NULL);
 }
 
 }
 
+
 static void
 run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *cfg,
 static void
 run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *cfg,
@@ -356,11 +363,11 @@ run (void *cls,
   enum MHD_FLAG flags;
   struct GNUNET_PeerIdentity id;
   struct GNUNET_CRYPTO_HashAsciiEncoded peername;
   enum MHD_FLAG flags;
   struct GNUNET_PeerIdentity id;
   struct GNUNET_CRYPTO_HashAsciiEncoded peername;
-  struct GNUNET_CRYPTO_RsaPrivateKey *host_key;
-  struct GNUNET_NAMESTORE_RecordData rd;
+  struct GNUNET_CRYPTO_EddsaPrivateKey *host_key;
+  struct GNUNET_GNSRECORD_Data rd;
   char *rd_string;
   char *zone_keyfile;
   char *rd_string;
   char *zone_keyfile;
-  
+
   GNUNET_TESTING_peer_get_identity (peer, &id);
   GNUNET_CRYPTO_hash_to_enc ((struct GNUNET_HashCode*)&id, &peername);
 
   GNUNET_TESTING_peer_get_identity (peer, &id);
   GNUNET_CRYPTO_hash_to_enc ((struct GNUNET_HashCode*)&id, &peername);
 
@@ -376,7 +383,7 @@ run (void *cls,
                          MHD_OPTION_END);
   GNUNET_assert (NULL != mhd);
   mhd_main ();
                          MHD_OPTION_END);
   GNUNET_assert (NULL != mhd);
   mhd_main ();
-  
+
   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
                                                             "ZONEKEY",
                                                             &zone_keyfile))
   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
                                                             "ZONEKEY",
                                                             &zone_keyfile))
@@ -385,55 +392,142 @@ run (void *cls,
     return;
   }
 
     return;
   }
 
-  host_key = GNUNET_CRYPTO_rsa_key_create_from_file (zone_keyfile);
-  rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value;
-  GNUNET_asprintf (&rd_string, "6 %s %s", (char*)&peername, "www.gnunet.");
-  GNUNET_assert (GNUNET_OK == GNUNET_NAMESTORE_string_to_value (GNUNET_GNS_RECORD_VPN,
+  host_key = GNUNET_CRYPTO_eddsa_key_create_from_file (zone_keyfile);
+  rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
+  GNUNET_asprintf (&rd_string, "6 %s %s", (char*)&peername, "www.gnu.");
+  GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_string_to_value (GNUNET_GNSRECORD_TYPE_VPN,
                                                                rd_string,
                                                                (void**)&rd.data,
                                                                &rd.data_size));
                                                                rd_string,
                                                                (void**)&rd.data,
                                                                &rd.data_size));
-  rd.record_type = GNUNET_GNS_RECORD_VPN;
-
-  GNUNET_NAMESTORE_record_create (namestore,
-                                  host_key,
-                                  "www",
-                                  &rd,
-                                  &commence_testing,
-                                  NULL);
+  rd.record_type = GNUNET_GNSRECORD_TYPE_VPN;
+
+  GNUNET_NAMESTORE_records_store (namestore,
+                                 host_key,
+                                 "www",
+                                 1, &rd,
+                                 &commence_testing,
+                                 NULL);
   GNUNET_free ((void**)rd.data);
   GNUNET_free (rd_string);
   GNUNET_free (zone_keyfile);
   GNUNET_free ((void**)rd.data);
   GNUNET_free (rd_string);
   GNUNET_free (zone_keyfile);
-  GNUNET_CRYPTO_rsa_key_free (host_key);
+  GNUNET_free (host_key);
 }
 
 
 /**
 }
 
 
 /**
- * Test if the given AF is supported by this system.
- * 
- * @param af to test
- * @return GNUNET_OK if the AF is supported
+ * 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 int
-test_af (int af)
+static void
+open_dev_null (int target_fd,
+              int flags)
 {
 {
-  int s;
+  int fd;
 
 
-  s = socket (af, SOCK_STREAM, 0);
-  if (-1 == s)
+  fd = open ("/dev/null", flags);
+  if (-1 == fd)
+    abort ();
+  if (fd == target_fd)
+    return;
+  if (-1 == dup2 (fd, target_fd))
   {
   {
-    if (EAFNOSUPPORT == errno)
-      return GNUNET_NO;
-    fprintf (stderr, "Failed to create test socket: %s\n", STRERROR (errno));
-    return GNUNET_SYSERR;
+    (void) close (fd);
+    abort ();
   }
   }
-  close (s);
-  return GNUNET_OK;
+  (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,
+              char *const cmd[])
+{
+  int status;
+  pid_t pid;
+  pid_t ret;
+
+  pid = fork ();
+  if (-1 == pid)
+  {
+    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",
+            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) );
+  if (-1 == ret)
+  {
+    fprintf (stderr,
+            "waitpid failed: %s\n",
+            strerror (errno));
+    return 1;
+  }
+  if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
+    return 1;
+  /* child process completed and returned success, we're happy */
+  return 0;
+}
+
 int
 main (int argc, char *const *argv)
 {
 int
 main (int argc, char *const *argv)
 {
+  char *sbin_iptables;
+  char *bin_vpn;
+  char *bin_exit;
+  char *bin_dns;
+  char *const iptables_args[] =
+  {
+    "iptables", "-t", "mangle", "-L", "-v", NULL
+  };
+
+  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,
+            "Executable iptables not found in approved directories: %s, skipping\n",
+            strerror (errno));
+    return 0;
+  }
+
+  if (0 != fork_and_exec (sbin_iptables, iptables_args))
+  {
+    fprintf (stderr,
+             "Failed to run `iptables -t mangle -L -v'. Skipping test.\n");
+    return 0;
+  }
+
   if (0 != ACCESS ("/dev/net/tun", R_OK))
   {
     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
   if (0 != ACCESS ("/dev/net/tun", R_OK))
   {
     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
@@ -443,34 +537,44 @@ main (int argc, char *const *argv)
             "WARNING: System unable to run test, skipping.\n");
     return 0;
   }
             "WARNING: System unable to run test, skipping.\n");
     return 0;
   }
-  if ( (GNUNET_YES !=
-       GNUNET_OS_check_helper_binary ("gnunet-helper-vpn")) ||
-       (GNUNET_YES !=
-       GNUNET_OS_check_helper_binary ("gnunet-helper-exit")) ||
-       (GNUNET_YES !=
-  GNUNET_OS_check_helper_binary ("gnunet-helper-dns")))
+
+  bin_vpn = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
+  bin_exit = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-exit");
+  bin_dns = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
+  if ( (0 != geteuid ()) &&
+       ( (GNUNET_YES !=
+         GNUNET_OS_check_helper_binary (bin_vpn, GNUNET_YES, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) || //ipv4 only please!
+        (GNUNET_YES !=
+         GNUNET_OS_check_helper_binary (bin_exit, GNUNET_YES, "-d gnunet-vpn - - - 169.1.3.3.7 255.255.255.0")) || //no nat, ipv4 only
+        (GNUNET_YES !=
+         GNUNET_OS_check_helper_binary (bin_dns, GNUNET_YES, NULL))) ) // TODO: once we have a windows-testcase, add test parameters here
   {
     fprintf (stderr,
             "WARNING: gnunet-helper-{exit,vpn,dns} binaries in $PATH are not SUID, refusing to run test (as it would have to fail).\n");
     fprintf (stderr,
             "Change $PATH ('.' in $PATH before $GNUNET_PREFIX/bin is problematic) or permissions (run 'make install' as root) to fix this!\n");
   {
     fprintf (stderr,
             "WARNING: gnunet-helper-{exit,vpn,dns} binaries in $PATH are not SUID, refusing to run test (as it would have to fail).\n");
     fprintf (stderr,
             "Change $PATH ('.' in $PATH before $GNUNET_PREFIX/bin is problematic) or permissions (run 'make install' as root) to fix this!\n");
+    GNUNET_free (bin_vpn);
+    GNUNET_free (bin_exit);
+    GNUNET_free (bin_dns);
     return 0;
   }
     return 0;
   }
-  GNUNET_CRYPTO_setup_hostkey ("test_gns_vpn.conf");
-  
+  GNUNET_free (bin_vpn);
+  GNUNET_free (bin_exit);
+  GNUNET_free (bin_dns);
+
   dest_ip = "169.254.86.1";
   dest_af = AF_INET;
   src_af = AF_INET;
 
   dest_ip = "169.254.86.1";
   dest_af = AF_INET;
   src_af = AF_INET;
 
-  if (GNUNET_OK == test_af (AF_INET6))
+  if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
     use_v6 = GNUNET_YES;
   else
     use_v6 = GNUNET_NO;
     use_v6 = GNUNET_YES;
   else
     use_v6 = GNUNET_NO;
-  
-  if ( (GNUNET_OK != test_af (src_af)) ||
-       (GNUNET_OK != test_af (dest_af)) )
+
+  if ( (GNUNET_OK != GNUNET_NETWORK_test_pf (src_af)) ||
+       (GNUNET_OK != GNUNET_NETWORK_test_pf (dest_af)) )
   {
   {
-    fprintf (stderr, 
+    fprintf (stderr,
             "Required address families not supported by this system, skipping test.\n");
     return 0;
   }
             "Required address families not supported by this system, skipping test.\n");
     return 0;
   }