largely completing gnunet-nat tool, using new service API (but untested)
authorChristian Grothoff <christian@grothoff.org>
Sun, 27 Nov 2016 13:43:02 +0000 (14:43 +0100)
committerChristian Grothoff <christian@grothoff.org>
Sun, 27 Nov 2016 13:43:02 +0000 (14:43 +0100)
src/include/gnunet_strings_lib.h
src/nat/Makefile.am
src/nat/gnunet-nat.c
src/util/strings.c

index 15d4f57ac0a177ce4771fa7531daa9efffec1618..0328882ddb64ce0afae89f99492be2a38d8fbbef 100644 (file)
@@ -349,25 +349,27 @@ GNUNET_STRINGS_base64_encode (const char *data, size_t len, char **output);
  *
  * @param data the data to encode
  * @param len the length of the input
- * @param output where to write the output (*output should be NULL,
+ * @param[out] output where to write the output (*output should be NULL,
  *   is allocated)
  * @return the size of the output
  */
 size_t
-GNUNET_STRINGS_base64_decode (const char *data, size_t len, char **output);
+GNUNET_STRINGS_base64_decode (const char *data,
+                             size_t len,
+                             char **output);
 
 
 /**
  * Parse a path that might be an URI.
  *
  * @param path path to parse. Must be NULL-terminated.
- * @param scheme_part a pointer to 'char *' where a pointer to a string that
+ * @param[out] scheme_part pointer to a string that
  *        represents the URI scheme will be stored. Can be NULL. The string is
  *        allocated by the function, and should be freed by GNUNET_free() when
  *        it is no longer needed.
  * @param path_part a pointer to 'const char *' where a pointer to the path
  *        part of the URI will be stored. Can be NULL. Points to the same block
- *        of memory as 'path', and thus must not be freed. Might point to '\0',
+ *        of memory as @a path, and thus must not be freed. Might point to '\0',
  *        if path part is zero-length.
  * @return #GNUNET_YES if it's an URI, #GNUNET_NO otherwise. If 'path' is not
  *         an URI, '* scheme_part' and '*path_part' will remain unchanged
@@ -474,6 +476,21 @@ GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr,
                                struct sockaddr_in *r_buf);
 
 
+/**
+ * Parse an address given as a string into a 
+ * `struct sockaddr`.
+ *
+ * @param addr the address
+ * @param[out] af set to the parsed address family (i.e. AF_INET)
+ * @param[out] sa set to the parsed address
+ * @return 0 on error, otherwise number of bytes in @a sa
+ */
+size_t
+GNUNET_STRINGS_parse_socket_addr (const char *addr,
+                                 uint8_t *af,
+                                 struct sockaddr **sa);
+
+
 /**
  * Tries to convert @a addr string to an IP (v4 or v6) address.
  * Will automatically decide whether to treat 'addr' as v4 or v6 address.
index d8d50e1a42e7f65a74ad66f1f46044c91a17bf8a..c3477930d9d71ca072c330d868329f0e480b6593 100644 (file)
@@ -58,7 +58,7 @@ gnunet_helper_nat_client_SOURCES = \
 gnunet_nat_SOURCES = \
   gnunet-nat.c nat.h
 gnunet_nat_LDADD = \
-  libgnunetnat.la \
+  libgnunetnatnew.la \
   $(top_builddir)/src/util/libgnunetutil.la
 
 
index 10d5aef8e46b2df648631ba9e6b3736297b1c52d..6be3319b51067b2f97a8663175f25612a87f0a97 100644 (file)
@@ -39,9 +39,9 @@ static int global_ret;
 static struct GNUNET_NAT_AutoHandle *ah;
 
 /**
- * Port we use.
+ * Port we advertise.
  */ 
-static unsigned int port;
+static unsigned int adv_port;
 
 /**
  * Flag set to 1 if we use IPPROTO_UDP.
@@ -197,6 +197,68 @@ auto_config_cb (void *cls,
 }
 
 
+/**
+ * Function called to report success or failure for
+ * NAT configuration test.
+ *
+ * @param cls closure
+ * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
+ */
+static void
+test_report_cb (void *cls,
+               enum GNUNET_NAT_StatusCode result)
+{
+  nt = NULL;
+  PRINTF ("NAT test result: %s\n",
+         GNUNET_NAT_status2string (result));
+  test_finished ();
+}
+
+
+/**
+ * Signature of the callback passed to #GNUNET_NAT_register() for
+ * a function to call whenever our set of 'valid' addresses changes.
+ *
+ * @param cls closure
+ * @param add_remove #GNUNET_YES to add a new public IP address, 
+ *                   #GNUNET_NO to remove a previous (now invalid) one
+ * @param ac address class the address belongs to
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual length of the @a addr
+ */
+static void
+address_cb (void *cls,
+           int add_remove,
+           enum GNUNET_NAT_AddressClass ac,
+           const struct sockaddr *addr,
+           socklen_t addrlen)
+{
+  // FIXME: print!
+}
+
+
+/**
+ * Signature of the callback passed to #GNUNET_NAT_register().
+ * for a function to call whenever someone asks us to do connection
+ * reversal.
+ *
+ * @param cls closure
+ * @param local_addr address where we received the request
+ * @param local_addrlen actual length of the @a local_addr
+ * @param remote_addr public IP address of the other peer
+ * @param remote_addrlen actual length of the @a remote_addr
+ */
+static void
+reversal_cb (void *cls,
+            const struct sockaddr *local_addr,
+            socklen_t local_addrlen,
+            const struct sockaddr *remote_addr,
+            socklen_t remote_addrlen)
+{
+  // FIXME: print!
+}
+
+
 /**
  * Task run on shutdown.
  *
@@ -237,6 +299,14 @@ run (void *cls,
      const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
+  uint8_t af;
+  struct sockaddr_in bind_sa;
+  struct sockaddr_in extern_sa;
+  struct sockaddr *local_sa;
+  struct sockaddr *remote_sa;
+  size_t local_len;
+  size_t remote_len;
+  
   if (use_tcp && use_udp)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
@@ -256,6 +326,130 @@ run (void *cls,
     global_ret = 1;
     return;
   }
+  if (NULL != bind_addr)
+  {
+    if (GNUNET_OK !=
+       GNUNET_STRINGS_to_address_ipv4 (bind_addr,
+                                       strlen (bind_addr),
+                                       &bind_sa))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Invalid socket address `%s'\n",
+                 bind_addr);
+      global_ret = 1;
+      return;
+    }
+  }
+  if (NULL != extern_addr)
+  {
+    if (GNUNET_OK !=
+       GNUNET_STRINGS_to_address_ipv4 (extern_addr,
+                                       strlen (extern_addr),
+                                       &extern_sa))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Invalid socket address `%s'\n",
+                 extern_addr);
+      global_ret = 1;
+      return;
+    }
+  }
+  if (NULL != local_addr)
+  {
+    local_len = GNUNET_STRINGS_parse_socket_addr (local_addr,
+                                                 &af,
+                                                 &local_sa);
+    if (0 == local_len)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Invalid socket address `%s'\n",
+                 local_addr);
+      global_ret = 1;
+      return;
+    }
+  }
+  if (NULL != remote_addr)
+  {
+    remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
+                                                  &af,
+                                                  &remote_sa);
+    if (0 == remote_len)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Invalid socket address `%s'\n",
+                 remote_addr);
+      global_ret = 1;
+      return;
+    }
+  }
+
+  if (NULL != bind_addr)
+  {
+    if (NULL == extern_addr)
+      extern_sa = bind_sa;
+    nt = GNUNET_NAT_test_start (c,
+                               proto,
+                               bind_sa.sin_addr,
+                               ntohs (bind_sa.sin_port),
+                               extern_sa.sin_addr,
+                               ntohs (extern_sa.sin_port),
+                               &test_report_cb,
+                               NULL);
+  }
+
+  if (NULL != local_addr)
+  {
+    nh = GNUNET_NAT_register (c,
+                             proto,
+                             (uint16_t) adv_port,
+                             1,
+                             (const struct sockaddr **) &local_sa,
+                             &local_len,
+                             &address_cb,
+                             (listen_reversal) ? &reversal_cb : NULL,
+                             NULL);
+  }
+
+  if (NULL != remote_addr)
+  {
+    int ret;
+    
+    if ( (NULL == nh) ||
+        (sizeof (struct sockaddr_in) != local_len) )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Require IPv4 local address to initiate connection reversal\n");
+      global_ret = 1;
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+    if (sizeof (struct sockaddr_in) != remote_len)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Require IPv4 reversal target address\n");
+      global_ret = 1;
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+    ret = GNUNET_NAT_request_reversal (nh,
+                                      (const struct sockaddr_in *) &local_sa,
+                                      (const struct sockaddr_in *) &remote_sa);
+    switch (ret)
+    {
+    case GNUNET_SYSERR:
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Connection reversal internal error\n");
+      break;
+    case GNUNET_NO:
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 "Connection reversal unavailable\n");
+      break;
+    case GNUNET_OK:
+      /* operation in progress */
+      break;
+    }
+  }
+  
   if (do_auto)
   {
     ah = GNUNET_NAT_autoconfig_start (c,
@@ -285,22 +479,22 @@ main (int argc,
      GNUNET_NO, &GNUNET_GETOPT_set_one, &do_auto },
     {'b', "bind", "ADDRESS",
      gettext_noop ("which IP and port are we bound to"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &bind_addr},
+     GNUNET_YES, &GNUNET_GETOPT_set_string, &bind_addr },
     {'e', "external", "ADDRESS",
      gettext_noop ("which external IP and port should be used to test"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr},
+     GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr },
     {'l', "local", "ADDRESS",
      gettext_noop ("which IP and port are we locally using to listen to for connection reversals"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr},
+     GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr },
     {'r', "remote", "ADDRESS",
      gettext_noop ("which remote IP and port should be asked for connection reversal"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr},
+     GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr },
     {'L', "listen", NULL,
      gettext_noop ("listen for connection reversal requests"),
      GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal },
     {'p', "port", NULL,
-     gettext_noop ("port to use"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &port},
+     gettext_noop ("port to use to advertise"),
+     GNUNET_YES, &GNUNET_GETOPT_set_uint, &adv_port },
     {'s', "stun", NULL,
      gettext_noop ("enable STUN processing"),
      GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun },
index 6a6cad6fe8b05304ac48d61c71c3ebb5467d331f..46eab856f0be6425a3f83c244e1c258cd703cb2b 100644 (file)
@@ -1209,7 +1209,7 @@ GNUNET_STRINGS_check_filename (const char *filename,
 
 
 /**
- * Tries to convert 'zt_addr' string to an IPv6 address.
+ * Tries to convert @a zt_addr string to an IPv6 address.
  * The string is expected to have the format "[ABCD::01]:80".
  *
  * @param zt_addr 0-terminated string. May be mangled by the function.
@@ -1292,7 +1292,8 @@ GNUNET_STRINGS_to_address_ipv6 (const char *zt_addr,
  *         the contents of @a r_buf are undefined.
  */
 int
-GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen,
+GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr,
+                               uint16_t addrlen,
                                struct sockaddr_in *r_buf)
 {
   unsigned int temps[4];
@@ -1301,7 +1302,13 @@ GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen,
 
   if (addrlen < 9)
     return GNUNET_SYSERR;
-  cnt = SSCANF (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port);
+  cnt = SSCANF (zt_addr,
+               "%u.%u.%u.%u:%u",
+               &temps[0],
+               &temps[1],
+               &temps[2],
+               &temps[3],
+               &port);
   if (5 != cnt)
     return GNUNET_SYSERR;
   for (cnt = 0; cnt < 4; cnt++)
@@ -1328,8 +1335,8 @@ GNUNET_STRINGS_to_address_ipv4 (const char *zt_addr, uint16_t addrlen,
  * @param addrlen number of bytes in @a addr (if addr is 0-terminated,
  *        0-terminator should not be counted towards addrlen).
  * @param r_buf a buffer to fill.
- * @return #GNUNET_OK if conversion succeded. GNUNET_SYSERR otherwise, in which
- *         case the contents of r_buf are undefined.
+ * @return #GNUNET_OK if conversion succeded. #GNUNET_SYSERR otherwise, in which
+ *         case the contents of @a r_buf are undefined.
  */
 int
 GNUNET_STRINGS_to_address_ip (const char *addr,
@@ -1346,6 +1353,62 @@ GNUNET_STRINGS_to_address_ip (const char *addr,
 }
 
 
+/**
+ * Parse an address given as a string into a 
+ * `struct sockaddr`.
+ *
+ * @param addr the address
+ * @param[out] af set to the parsed address family (i.e. AF_INET)
+ * @param[out] sa set to the parsed address
+ * @return 0 on error, otherwise number of bytes in @a sa
+ */
+size_t
+GNUNET_STRINGS_parse_socket_addr (const char *addr,
+                                 uint8_t *af,
+                                 struct sockaddr **sa)
+{
+  char *cp = GNUNET_strdup (addr);
+
+  *af = AF_UNSPEC;
+  if ('[' == *addr)
+  {
+    /* IPv6 */    
+    *sa = GNUNET_malloc (sizeof (struct sockaddr_in6));
+    if (GNUNET_OK !=
+       GNUNET_STRINGS_to_address_ipv6 (cp,
+                                       strlen (cp),
+                                       (struct sockaddr_in6 *) *sa))
+    {
+      GNUNET_free (*sa);
+      *sa = NULL;
+      GNUNET_free (cp);
+      return 0;
+    }
+    *af = AF_INET6;
+    GNUNET_free (cp);
+    return sizeof (struct sockaddr_in6);
+  }
+  else
+  {
+    /* IPv4 */
+    *sa = GNUNET_malloc (sizeof (struct sockaddr_in));
+    if (GNUNET_OK !=
+       GNUNET_STRINGS_to_address_ipv4 (cp,
+                                       strlen (cp),
+                                       (struct sockaddr_in *) *sa))
+    {
+      GNUNET_free (*sa);
+      *sa = NULL;
+      GNUNET_free (cp);
+      return 0;
+    }
+    *af = AF_INET;
+    GNUNET_free (cp);
+    return sizeof (struct sockaddr_in);
+  }
+}
+
+
 /**
  * Makes a copy of argv that consists of a single memory chunk that can be
  * freed with a single call to GNUNET_free();
@@ -1388,7 +1451,10 @@ _make_continuous_arg_copy (int argc,
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
  */
 int
-GNUNET_STRINGS_get_utf8_args (int argc, char *const *argv, int *u8argc, char *const **u8argv)
+GNUNET_STRINGS_get_utf8_args (int argc,
+                             char *const *argv,
+                             int *u8argc,
+                             char *const **u8argv)
 {
 #if WINDOWS
   wchar_t *wcmd;