gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] branch master updated (948983f -> 1466de2)


From: gnunet
Subject: [GNUnet-SVN] [gnunet] branch master updated (948983f -> 1466de2)
Date: Wed, 30 Nov 2016 11:14:06 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository gnunet.

    from 948983f  note that port is not patched
     new 2706870  handle ports for interface scan data properly
     new 1b4333f  towards moving STUN logic into new NAT service
     new e43df97  moving basic logic for launching nat-server helper to new NAT 
service
     new 738cbe3  moving basic logic for launching nat-client helper to new NAT 
service
     new 1466de2  decided to keep NAT test logic in client library

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/include/gnunet_nat_service.h       | 102 +++++---
 src/include/gnunet_protocols.h         |  10 -
 src/nat/Makefile.am                    |   9 +-
 src/nat/gnunet-service-nat.c           | 208 ++++++++++++-----
 src/nat/gnunet-service-nat_helper.c    | 410 +++++++++++++++++++++++++++++++++
 src/nat/gnunet-service-nat_helper.h    |  89 +++++++
 src/nat/gnunet-service-nat_stun.c      | 211 +++++++++++++++++
 src/nat/gnunet-service-nat_stun.h      |  61 +++++
 src/nat/nat.h                          |  55 -----
 src/nat/nat_api.c                      | 152 +-----------
 src/nat/nat_api_stun.c                 | 261 +++++++++++++++++++++
 src/nat/{nat_test.c => nat_api_test.c} |   3 +-
 src/nat/nat_stun.c                     | 126 ----------
 src/nat/nat_stun.h                     | 170 ++++++++++++--
 14 files changed, 1423 insertions(+), 444 deletions(-)
 create mode 100644 src/nat/gnunet-service-nat_helper.c
 create mode 100644 src/nat/gnunet-service-nat_helper.h
 create mode 100644 src/nat/gnunet-service-nat_stun.c
 create mode 100644 src/nat/gnunet-service-nat_stun.h
 create mode 100644 src/nat/nat_api_stun.c
 copy src/nat/{nat_test.c => nat_api_test.c} (99%)

diff --git a/src/include/gnunet_nat_service.h b/src/include/gnunet_nat_service.h
index a590695..378f5a8 100644
--- a/src/include/gnunet_nat_service.h
+++ b/src/include/gnunet_nat_service.h
@@ -198,37 +198,6 @@ GNUNET_NAT_register (const struct 
GNUNET_CONFIGURATION_Handle *cfg,
 
 
 /**
- * Handle an incoming STUN message.  This function is useful as
- * some GNUnet service may be listening on a UDP port and might
- * thus receive STUN messages while trying to receive other data.
- * In this case, this function can be used to act as a proper
- * STUN server (if desired).
- *
- * The function does some basic sanity checks on packet size and
- * content, try to extract a bit of information, and possibly replies
- * if this is an actual STUN message.
- * 
- * At the moment this only processes BIND requests, and returns the
- * externally visible address of the request. 
- *
- * @param nh handle to the NAT service
- * @param sender_addr address from which we got @a data
- * @param sender_addr_len number of bytes in @a sender_addr
- * @param data the packet
- * @param data_size number of bytes in @a data
- * @return #GNUNET_OK on success
- *         #GNUNET_NO if the packet is not a STUN packet
- *         #GNUNET_SYSERR on internal error handling the packet
- */
-int
-GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
-                              const struct sockaddr *sender_addr,
-                              size_t sender_addr_len,
-                              const void *data,
-                               size_t data_size);
-
-
-/**
  * Test if the given address is (currently) a plausible IP address for
  * this peer.  Mostly a convenience function so that clients do not
  * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
@@ -398,6 +367,77 @@ typedef void
 
 
 /**
+ * Handle an incoming STUN message.  This function is useful as
+ * some GNUnet service may be listening on a UDP port and might
+ * thus receive STUN messages while trying to receive other data.
+ * In this case, this function can be used to process replies
+ * to STUN requests.
+ *
+ * The function does some basic sanity checks on packet size and
+ * content, try to extract a bit of information.
+ * 
+ * At the moment this only processes BIND requests, and returns the
+ * externally visible address of the request to the rest of the
+ * NAT logic.
+ *
+ * @param nh handle to the NAT service
+ * @param sender_addr address from which we got @a data
+ * @param sender_addr_len number of bytes in @a sender_addr
+ * @param data the packet
+ * @param data_size number of bytes in @a data
+ * @return #GNUNET_OK on success
+ *         #GNUNET_NO if the packet is not a STUN packet
+ *         #GNUNET_SYSERR on internal error handling the packet
+ */
+int
+GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
+                              const struct sockaddr *sender_addr,
+                              size_t sender_addr_len,
+                              const void *data,
+                               size_t data_size);
+
+
+/**
+ * Handle to a request given to the resolver.  Can be used to cancel
+ * the request prior to the timeout or successful execution.  Also
+ * used to track our internal state for the request.
+ */
+struct GNUNET_NAT_STUN_Handle;
+
+
+/**
+ * Make Generic STUN request. Sends a generic stun request to the
+ * server specified using the specified socket.  If we do this,
+ * we need to watch for possible responses and call
+ * #GNUNET_NAT_stun_handle_packet() on incoming packets.
+ *
+ * @param server the address of the stun server
+ * @param port port of the stun server, in host byte order
+ * @param sock the socket used to send the request, must be a
+ *             UDP socket
+ * @param cb callback in case of error
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct GNUNET_NAT_STUN_Handle *
+GNUNET_NAT_stun_make_request (const char *server,
+                              uint16_t port,
+                              struct GNUNET_NETWORK_Handle *sock,
+                              GNUNET_NAT_TestCallback cb,
+                              void *cb_cls);
+
+
+/**
+ * Cancel active STUN request. Frees associated resources
+ * and ensures that the callback is no longer invoked.
+ *
+ * @param rh request to cancel
+ */
+void
+GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh);
+
+
+/**
  * Start testing if NAT traversal works using the given configuration
  * (IPv4-only).  The transport adapters should be down while using
  * this function.
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index db479d2..f9b7d3c 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -2818,16 +2818,6 @@ extern "C"
 #define GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE 1064
 
 /**
- * Message to ask NAT service to test an address.
- */
-#define GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST 1065
-
-/**
- * Message from NAT service with the address test result.
- */
-#define GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT 1066
-
-/**
  * Message to ask NAT service to request autoconfiguration.
  */
 #define GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG 1067
diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am
index c347793..d304a57 100644
--- a/src/nat/Makefile.am
+++ b/src/nat/Makefile.am
@@ -84,7 +84,10 @@ libgnunetnat_la_LDFLAGS = \
   -version-info 1:1:1
 
 libgnunetnatnew_la_SOURCES = \
-  nat_api.c nat.h
+  nat_api.c \
+  nat_api_stun.c nat_stun.h \
+  nat_api_test.c \
+  nat.h
 libgnunetnatnew_la_LIBADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(GN_LIBINTL) @EXT_LIBS@ 
@@ -93,7 +96,9 @@ libgnunetnatnew_la_LDFLAGS = \
   -version-info 2:0:0
 
 gnunet_service_nat_SOURCES = \
- gnunet-service-nat.c
+ gnunet-service-nat.c \
+ gnunet-service-nat_stun.c gnunet-service-nat_stun.h \
+ gnunet-service-nat_helper.c gnunet-service-nat_helper.h
 gnunet_service_nat_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c
index 548cf1c..1ae0ef2 100644
--- a/src/nat/gnunet-service-nat.c
+++ b/src/nat/gnunet-service-nat.c
@@ -26,6 +26,14 @@
  * The purpose of this service is to enable transports to 
  * traverse NAT routers, by providing traversal options and
  * knowledge about the local network topology.
+ *
+ * TODO:
+ * - call GN_start_gnunet_nat_server_() if possible (i.e.
+ *   when we find we have a non-global IPv4 address)
+ * - implement handle_test
+ * - implement autoconfig
+ * - implmeent UPnPC/PMP-based NAT traversal
+ * - implement NEW logic for external IP detection
  */
 #include "platform.h"
 #include <math.h>
@@ -34,6 +42,8 @@
 #include "gnunet_signatures.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_nat_service.h"
+#include "gnunet-service-nat_stun.h"
+#include "gnunet-service-nat_helper.h"
 #include "nat.h"
 #include <gcrypt.h>
 
@@ -134,8 +144,6 @@ struct LocalAddressList
 };
 
 
-
-
 /**
  * Handle to our current configuration.
  */
@@ -362,6 +370,7 @@ handle_stun (void *cls,
   const void *payload;
   size_t sa_len;
   size_t payload_size;
+  struct sockaddr_in external_addr;
 
   sa_len = ntohs (message->sender_addr_size);
   payload_size = ntohs (message->payload_size);
@@ -388,7 +397,28 @@ handle_stun (void *cls,
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received HANDLE_STUN message from client\n");
-  // FIXME: actually handle STUN request!
+  if (GNUNET_OK ==
+      GNUNET_NAT_stun_handle_packet_ (payload,
+                                     payload_size,
+                                     &external_addr))
+  {     
+    /* FIXME: do something with "external_addr"! We 
+       now know that a server at "sa" claims that
+       we are visible at IP "external_addr". 
+
+       We should (for some fixed period of time) tell
+       all of our clients that listen to a NAT'ed address
+       that they might want to consider the given 'external_ip'
+       as their public IP address (this includes TCP and UDP
+       clients, even if only UDP sends STUN requests).
+
+       If we do not get a renewal, the "external_addr" should be
+       removed again.  The timeout frequency should be configurable
+       (with a sane default), so that the UDP plugin can tell how
+       often to re-request STUN.
+    */
+    
+  }
   GNUNET_SERVICE_client_continue (ch->client);
 }
 
@@ -485,33 +515,14 @@ handle_request_connection_reversal (void *cls,
     GNUNET_SERVICE_client_drop (ch->client);
     return;
   }
-  /* FIXME: actually run the logic! */
+  /* FIXME: actually run the logic by
+     calling 'GN_request_connection_reversal()' */
   
   GNUNET_SERVICE_client_continue (ch->client);
 }
 
 
 /**
- * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST message from
- * client.
- *
- * @param cls client who sent the message
- * @param message the message received
- */
-static void
-handle_test (void *cls,
-            const struct GNUNET_NAT_RequestTestMessage *message)
-{
-  struct ClientHandle *ch = cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Received REQUEST_TEST message from client\n");
-  /* FIXME: actually process test request */
-  GNUNET_SERVICE_client_continue (ch->client);
-}
-
-
-/**
  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
  * from client.
  *
@@ -669,6 +680,42 @@ match_ipv6 (const char *network,
 
 
 /**
+ * Test if the given IPv4 address is in a known range
+ * for private networks.
+ *
+ * @param ip address to test
+ * @return #GNUNET_YES if @a ip is in a NAT range
+ */
+static int
+is_nat_v4 (const struct in_addr *ip)
+{
+  return
+    match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
+    match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
+    match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
+    match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
+    match_ipv4 ("172.16.0.0", ip, 16);  /* RFC 1918 */
+}
+
+
+/**
+ * Test if the given IPv6 address is in a known range
+ * for private networks.
+ *
+ * @param ip address to test
+ * @return #GNUNET_YES if @a ip is in a NAT range
+ */
+static int
+is_nat_v6 (const struct in6_addr *ip)
+{
+  return
+    match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
+    match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
+    match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
+}
+
+
+/**
  * Callback function invoked for each interface found.  Adds them
  * to our new address list.
  *
@@ -693,40 +740,33 @@ ifc_proc (void *cls,
   struct IfcProcContext *ifc_ctx = cls;
   struct LocalAddressList *lal;
   size_t alen;
-  const void *ip;
-  const struct in6_addr *v6;
+  const struct in_addr *ip4;
+  const struct in6_addr *ip6;
   enum GNUNET_NAT_AddressClass ac;
 
   switch (addr->sa_family)
   {
   case AF_INET:
     alen = sizeof (struct sockaddr_in);
-    ip = &((const struct sockaddr_in *) addr)->sin_addr;
-    if (match_ipv4 ("127.0.0.0", ip, 8))
+    ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
+    if (match_ipv4 ("127.0.0.0", ip4, 8))
       ac = GNUNET_NAT_AC_LOOPBACK;
-    else if (match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
-            match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
-            match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
-            match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
-            match_ipv4 ("172.16.0.0", ip, 16))  /* RFC 1918 */
+    else if (is_nat_v4 (ip4))
       ac = GNUNET_NAT_AC_LAN;
     else
       ac = GNUNET_NAT_AC_GLOBAL;
     break;
   case AF_INET6:
     alen = sizeof (struct sockaddr_in6);
-    ip = &((const struct sockaddr_in6 *) addr)->sin6_addr;
-    if (match_ipv6 ("::1", ip, 128))
+    ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
+    if (match_ipv6 ("::1", ip6, 128))
       ac = GNUNET_NAT_AC_LOOPBACK;
-    else if (match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
-            match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
-            match_ipv6 ("fe80::", ip, 10)) /* RFC 4291, link-local */
+    else if (is_nat_v6 (ip6))
       ac = GNUNET_NAT_AC_LAN;
     else
       ac = GNUNET_NAT_AC_GLOBAL;
-    v6 = ip;
-    if ( (v6->s6_addr[11] == 0xFF) &&
-        (v6->s6_addr[12] == 0xFE) )
+    if ( (ip6->s6_addr[11] == 0xFF) &&
+        (ip6->s6_addr[12] == 0xFE) )
     {
       /* contains a MAC, be extra careful! */
       ac |= GNUNET_NAT_AC_PRIVATE;
@@ -755,6 +795,39 @@ ifc_proc (void *cls,
 
 
 /**
+ * Notify client about a change in the list
+ * of addresses this peer has.
+ *
+ * @param delta the entry in the list that changed
+ * @param ch client to contact
+ * @param add #GNUNET_YES to add, #GNUNET_NO to remove
+ * @param addr the address that changed
+ * @param addr_len number of bytes in @a addr
+ */
+static void
+notify_client (struct LocalAddressList *delta,
+              struct ClientHandle *ch,
+              int add,
+              const void *addr,
+              size_t addr_len)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
+
+  env = GNUNET_MQ_msg_extra (msg,
+                            addr_len,
+                            GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
+  msg->add_remove = htonl (add);
+  msg->addr_class = htonl (delta->ac);
+  GNUNET_memcpy (&msg[1],
+                addr,
+                addr_len);
+  GNUNET_MQ_send (ch->mq,
+                 env);
+}                     
+
+
+/**
  * Notify all clients about a change in the list
  * of addresses this peer has.
  *
@@ -769,9 +842,9 @@ notify_clients (struct LocalAddressList *delta,
        NULL != ch;
        ch = ch->next)
   {
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
     size_t alen;
+    struct sockaddr_in v4;
+    struct sockaddr_in6 v6;
     
     if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
       continue;
@@ -779,25 +852,48 @@ notify_clients (struct LocalAddressList *delta,
     {
     case AF_INET:
       alen = sizeof (struct sockaddr_in);
+      GNUNET_memcpy (&v4,
+                    &delta->addr,
+                    alen);
+      for (unsigned int i=0;i<ch->num_addrs;i++)
+      {
+       const struct sockaddr_in *c4;
+       
+       if (AF_INET != ch->addrs[i]->sa_family)
+         continue; /* IPv4 not relevant */
+       c4 = (const struct sockaddr_in *) ch->addrs[i];
+       v4.sin_port = c4->sin_port;
+       notify_client (delta,
+                      ch,
+                      add,
+                      &v4,
+                      alen);
+      }
       break;
     case AF_INET6:
       alen = sizeof (struct sockaddr_in6);
+      GNUNET_memcpy (&v6,
+                    &delta->addr,
+                    alen);
+      for (unsigned int i=0;i<ch->num_addrs;i++)
+      {
+       const struct sockaddr_in6 *c6;
+       
+       if (AF_INET6 != ch->addrs[i]->sa_family)
+         continue; /* IPv4 not relevant */
+       c6 = (const struct sockaddr_in6 *) ch->addrs[i];
+       v6.sin6_port = c6->sin6_port;
+       notify_client (delta,
+                      ch,
+                      add,
+                      &v6,
+                      alen);
+      }
       break;
     default:
       GNUNET_break (0);
       continue;
     }
-    env = GNUNET_MQ_msg_extra (msg,
-                              alen,
-                              GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
-    msg->add_remove = htonl (add);
-    msg->addr_class = htonl (delta->ac);
-    GNUNET_memcpy (&msg[1],
-                  &delta->addr,
-                  alen);
-    /* FIXME: what about the port number? */
-    GNUNET_MQ_send (ch->mq,
-                   env);
   }
 }
 
@@ -964,10 +1060,6 @@ GNUNET_SERVICE_MAIN
                        GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
                        struct GNUNET_NAT_RequestConnectionReversalMessage,
                        NULL),
- GNUNET_MQ_hd_fixed_size (test,
-                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST,
-                         struct GNUNET_NAT_RequestTestMessage,
-                         NULL),
  GNUNET_MQ_hd_var_size (autoconfig_request,
                        GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
                        struct GNUNET_NAT_AutoconfigRequestMessage,
diff --git a/src/nat/gnunet-service-nat_helper.c 
b/src/nat/gnunet-service-nat_helper.c
new file mode 100644
index 0000000..e476da1
--- /dev/null
+++ b/src/nat/gnunet-service-nat_helper.c
@@ -0,0 +1,410 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
+
+     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 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file nat/gnunet-service-nat_helper.c
+ * @brief runs the gnunet-helper-nat-server
+ * @author Milan Bouchet-Valat
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet-service-nat_helper.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
+
+/**
+ * Information we keep per NAT helper process.
+ */
+struct HelperContext
+{
+
+  /**
+   * IP address we pass to the NAT helper.
+   */
+  const char *internal_address;
+
+  /**
+   * Function to call if we receive a reversal request.
+   */
+  GN_ReversalCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+  
+  /**
+   * How long do we wait for restarting a crashed gnunet-helper-nat-server?
+   */
+  struct GNUNET_TIME_Relative server_retry_delay;
+
+  /**
+   * ID of select gnunet-helper-nat-server stdout read task
+   */
+  struct GNUNET_SCHEDULER_Task *server_read_task;
+
+  /**
+   * The process id of the server process (if behind NAT)
+   */
+  struct GNUNET_OS_Process *server_proc;
+
+  /**
+   * stdout pipe handle for the gnunet-helper-nat-server process
+   */
+  struct GNUNET_DISK_PipeHandle *server_stdout;
+
+  /**
+   * stdout file handle (for reading) for the gnunet-helper-nat-server process
+   */
+  const struct GNUNET_DISK_FileHandle *server_stdout_handle;
+};
+
+
+/**
+ * Task that restarts the gnunet-helper-nat-server process after a crash
+ * after a certain delay.
+ *
+ * @param cls a `struct HelperContext`
+ */
+static void
+restart_nat_server (void *cls);
+
+
+/**
+ * Try again starting the helper later
+ *
+ * @param h context of the helper
+ */
+static void
+try_again (struct HelperContext *h)
+{
+  GNUNET_assert (NULL == h->server_read_task);
+  h->server_retry_delay
+    = GNUNET_TIME_STD_BACKOFF (h->server_retry_delay);
+  h->server_read_task
+    = GNUNET_SCHEDULER_add_delayed (h->server_retry_delay,
+                                   &restart_nat_server,
+                                   h);
+}
+
+
+/**
+ * We have been notified that gnunet-helper-nat-server has written
+ * something to stdout.  Handle the output, then reschedule this
+ * function to be called again once more is available.
+ *
+ * @param cls the `struct HelperContext`
+ */
+static void
+nat_server_read (void *cls)
+{
+  struct HelperContext *h = cls;
+  char mybuf[40];
+  ssize_t bytes;
+  int port;
+  const char *port_start;
+  struct sockaddr_in sin_addr;
+
+  h->server_read_task = NULL;
+  memset (mybuf,
+         0,
+         sizeof (mybuf));
+  bytes 
+    = GNUNET_DISK_file_read (h->server_stdout_handle,
+                            mybuf,
+                            sizeof (mybuf));
+  if (bytes < 1)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Finished reading from server stdout with code: %d\n",
+         bytes);
+    if (0 != GNUNET_OS_process_kill (h->server_proc,
+-                                   GNUNET_TERM_SIG))
+      GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
+                               "nat",
+                               "kill");
+    GNUNET_OS_process_wait (h->server_proc);
+    GNUNET_OS_process_destroy (h->server_proc);
+    h->server_proc = NULL;
+    GNUNET_DISK_pipe_close (h->server_stdout);
+    h->server_stdout = NULL;
+    h->server_stdout_handle = NULL;
+    try_again (h);
+    return;
+  }
+
+  port_start = NULL;
+  for (size_t i = 0; i < sizeof (mybuf); i++)
+  {
+    if (mybuf[i] == '\n')
+    {
+      mybuf[i] = '\0';
+      break;
+    }
+    if ((mybuf[i] == ':') && (i + 1 < sizeof (mybuf)))
+    {
+      mybuf[i] = '\0';
+      port_start = &mybuf[i + 1];
+    }
+  }
+
+  /* construct socket address of sender */
+  memset (&sin_addr,
+         0,
+         sizeof (sin_addr));
+  sin_addr.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sin_addr.sin_len = sizeof (sin_addr);
+#endif
+  if ( (NULL == port_start) ||
+       (1 != SSCANF (port_start,
+                    "%d",
+                    &port)) ||
+       (-1 == inet_pton (AF_INET,
+                        mybuf,
+                        &sin_addr.sin_addr)))
+  {
+    /* should we restart gnunet-helper-nat-server? */
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+        "nat",
+         _("gnunet-helper-nat-server generated malformed address `%s'\n"),
+         mybuf);
+    h->server_read_task 
+      = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        h->server_stdout_handle,
+                                        &nat_server_read,
+                                       h);
+    return;
+  }
+  sin_addr.sin_port = htons ((uint16_t) port);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "gnunet-helper-nat-server read: %s:%d\n",
+       mybuf,
+       port);
+  h->cb (h->cb_cls,
+        &sin_addr);
+  h->server_read_task 
+    = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+                                      h->server_stdout_handle,
+                                     &nat_server_read,
+                                      h);
+}
+
+
+/**
+ * Task that restarts the gnunet-helper-nat-server process after a crash
+ * after a certain delay.
+ *
+ * @param cls a `struct HelperContext`
+ */
+static void
+restart_nat_server (void *cls)
+{
+  struct HelperContext *h = cls;
+  char *binary;
+  
+  h->server_read_task = NULL;
+  h->server_stdout 
+    = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES,
+                       GNUNET_NO, GNUNET_YES);
+  if (NULL == h->server_stdout)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                        "pipe");
+    try_again (h);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Starting `%s' at `%s'\n",
+       "gnunet-helper-nat-server",
+       h->internal_address);
+  /* Start the server process */
+  binary
+    = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
+  h->server_proc 
+    = GNUNET_OS_start_process (GNUNET_NO,
+                              0,
+                              NULL,
+                              h->server_stdout,
+                              NULL,
+                              binary,
+                              "gnunet-helper-nat-server",
+                              h->internal_address,
+                              NULL);
+  GNUNET_free (binary);
+  if (NULL == h->server_proc)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+        "nat",
+        _("Failed to start %s\n"),
+        "gnunet-helper-nat-server");
+    GNUNET_DISK_pipe_close (h->server_stdout);
+    h->server_stdout = NULL;
+    try_again (h);
+    return;
+  }
+  /* Close the write end of the read pipe */
+  GNUNET_DISK_pipe_close_end (h->server_stdout,
+                             GNUNET_DISK_PIPE_END_WRITE);
+  h->server_stdout_handle 
+    = GNUNET_DISK_pipe_handle (h->server_stdout,
+                              GNUNET_DISK_PIPE_END_READ);
+  h->server_read_task 
+    = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+                                     h->server_stdout_handle,
+                                     &nat_server_read,
+                                     h);
+}
+
+
+/**
+ * Start the gnunet-helper-nat-server and process incoming
+ * requests.
+ *
+ * @param internal_address
+ * @param cb function to call if we receive a request
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct HelperContext *
+GN_start_gnunet_nat_server_ (const char *internal_address,
+                            GN_ReversalCallback cb,
+                            void *cb_cls)
+{
+  struct HelperContext *h;
+
+  h = GNUNET_new (struct HelperContext);
+  h->cb = cb;
+  h->cb_cls = cb_cls;
+  h->internal_address
+    = internal_address;
+  if (NULL == h->server_stdout)
+  {
+    GN_stop_gnunet_nat_server_ (h);
+    return NULL;
+  }
+  return h;
+}
+
+
+/**
+ * Start the gnunet-helper-nat-server and process incoming
+ * requests.
+ *
+ * @param h helper context to stop
+ */
+void
+GN_stop_gnunet_nat_server_ (struct HelperContext *h)
+{  
+  if (NULL != h->server_read_task)
+  {
+    GNUNET_SCHEDULER_cancel (h->server_read_task);
+    h->server_read_task = NULL;
+  }
+    if (NULL != h->server_proc)
+  {
+    if (0 != GNUNET_OS_process_kill (h->server_proc,
+                                     GNUNET_TERM_SIG))
+      GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
+                                "nat",
+                                "kill");
+    GNUNET_OS_process_wait (h->server_proc);
+    GNUNET_OS_process_destroy (h->server_proc);
+    h->server_proc = NULL;
+    GNUNET_DISK_pipe_close (h->server_stdout);
+    h->server_stdout = NULL;
+    h->server_stdout_handle = NULL;
+  }
+  if (NULL != h->server_stdout)
+  {
+    GNUNET_DISK_pipe_close (h->server_stdout);
+    h->server_stdout = NULL;
+    h->server_stdout_handle = NULL;
+  }
+  GNUNET_free (h);
+}
+
+
+/**
+ * We want to connect to a peer that is behind NAT.  Run the
+ * gnunet-helper-nat-client to send dummy ICMP responses to cause
+ * that peer to connect to us (connection reversal).
+ *
+ * @param internal_address out internal address to use
+ * @param sa the address of the peer (IPv4-only)
+ * @return #GNUNET_SYSERR on error,
+ *         #GNUNET_OK otherwise
+ */
+int
+GN_request_connection_reversal (const char *internal_address,
+                               const struct sockaddr_in *sa)
+{
+  char inet4[INET_ADDRSTRLEN];
+  char port_as_string[6];
+  struct GNUNET_OS_Process *proc;
+  char *binary;
+
+  GNUNET_assert (sa->sin_family == AF_INET);
+  if (NULL == inet_ntop (AF_INET,
+                        &sa->sin_addr,
+                        inet4,
+                        INET_ADDRSTRLEN))
+  {
+    GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
+                              "nat",
+                              "inet_ntop");
+    return GNUNET_SYSERR;
+  }
+  GNUNET_snprintf (port_as_string,
+                   sizeof (port_as_string),
+                   "%d",
+                   ntohs (sa->sin_port));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       _("Running gnunet-helper-nat-client %s %s %u\n"),
+       internal_address,
+       inet4,
+       ntohs (sa->sin_port));
+  binary
+    = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
+  proc
+    = GNUNET_OS_start_process (GNUNET_NO,
+                              0,
+                              NULL,
+                              NULL,
+                              NULL,
+                               binary,
+                               "gnunet-helper-nat-client",
+                               internal_address,
+                               inet4,
+                              port_as_string,
+                              NULL);
+  GNUNET_free (binary);
+  if (NULL == proc)
+    return GNUNET_SYSERR;
+  /* we know that the gnunet-helper-nat-client will terminate virtually
+   * instantly */
+  GNUNET_OS_process_wait (proc);
+  GNUNET_OS_process_destroy (proc);
+  return GNUNET_OK;
+}
+
+
+/* end of gnunet-service-nat_helper.c */
diff --git a/src/nat/gnunet-service-nat_helper.h 
b/src/nat/gnunet-service-nat_helper.h
new file mode 100644
index 0000000..861d62c
--- /dev/null
+++ b/src/nat/gnunet-service-nat_helper.h
@@ -0,0 +1,89 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
+
+     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 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file nat/gnunet-service-nat_helper.h
+ * @brief runs the gnunet-helper-nat-server
+ * @author Milan Bouchet-Valat
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Information we keep per NAT helper process.
+ */
+struct HelperContext;
+
+
+/**
+ * Function called whenever we get a connection reversal
+ * request from another peer.
+ *
+ * @param cls closure
+ * @param ra IP address of the peer who wants us to connect to it 
+ */
+typedef void
+(*GN_ReversalCallback) (void *cls,
+                       const struct sockaddr_in *ra);
+
+
+/**
+ * Start the gnunet-helper-nat-server and process incoming
+ * requests.
+ *
+ * @param internal_address
+ * @param cb function to call if we receive a request
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct HelperContext *
+GN_start_gnunet_nat_server_ (const char *internal_address,
+                            GN_ReversalCallback cb,
+                            void *cb_cls);
+
+                       
+/**
+ * Start the gnunet-helper-nat-server and process incoming
+ * requests.
+ *
+ * @param h helper context to stop
+ */
+void
+GN_stop_gnunet_nat_server_ (struct HelperContext *h);
+
+
+/**
+ * We want to connect to a peer that is behind NAT.  Run the
+ * gnunet-helper-nat-client to send dummy ICMP responses to cause
+ * that peer to connect to us (connection reversal).
+ *
+ * @param internal_address out internal address to use
+ * @param sa the address of the peer (IPv4-only)
+ * @return #GNUNET_SYSERR on error,
+ *         #GNUNET_OK otherwise
+ */
+int
+GN_request_connection_reversal (const char *internal_address,
+                               const struct sockaddr_in *sa);
+
+
+/* end of gnunet-service-nat_helper.h */
diff --git a/src/nat/gnunet-service-nat_stun.c 
b/src/nat/gnunet-service-nat_stun.c
new file mode 100644
index 0000000..6f3ea10
--- /dev/null
+++ b/src/nat/gnunet-service-nat_stun.c
@@ -0,0 +1,211 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2015, 2016 GNUnet e.V.
+
+     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 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * This code provides some support for doing STUN transactions.  We
+ * receive the simplest possible packet as the STUN server and try
+ * to respond properly.
+ *
+ * All STUN packets start with a simple header made of a type,
+ * length (excluding the header) and a 16-byte random transaction id.
+ * Following the header we may have zero or more attributes, each
+ * structured as a type, length and a value (whose format depends
+ * on the type, but often contains addresses).
+ * Of course all fields are in network format.
+ *
+ * This code was based on ministun.c.
+ *
+ * @file nat/gnunet-service-nat_stun.c
+ * @brief Functions for STUN functionality
+ * @author Bruno Souza Cabral
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "nat_stun.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
+
+
+/**
+ * Context for #stun_get_mapped(). 
+ * Used to store state across processing attributes.
+ */
+struct StunState
+{
+  uint16_t attr;
+};
+
+
+/**
+ * Extract the STUN_MAPPED_ADDRESS from the stun response.
+ * This is used as a callback for stun_handle_response
+ * when called from stun_request.
+ *
+ * @param[out] st pointer where we will set the type
+ * @param attr received stun attribute
+ * @param magic Magic cookie
+ * @param[out] arg pointer to a sockaddr_in where we will set the reported IP 
and port
+ * @return #GNUNET_OK if @a arg was initialized
+ */
+static int
+stun_get_mapped (struct StunState *st,
+                 const struct stun_attr *attr,
+                uint32_t magic,
+                 struct sockaddr_in *arg)
+{
+  const struct stun_addr *returned_addr;
+  struct sockaddr_in *sa = (struct sockaddr_in *) arg;
+  uint16_t type = ntohs (attr->attr);
+
+  switch (type)
+  {
+  case STUN_MAPPED_ADDRESS:
+    if ( (st->attr == STUN_XOR_MAPPED_ADDRESS) ||
+        (st->attr == STUN_MS_XOR_MAPPED_ADDRESS) )
+      return GNUNET_NO;
+    magic = 0;
+    break;
+  case STUN_MS_XOR_MAPPED_ADDRESS:
+    if (st->attr == STUN_XOR_MAPPED_ADDRESS)
+      return GNUNET_NO;
+    break;
+  case STUN_XOR_MAPPED_ADDRESS:
+    break;
+  default:
+    return GNUNET_NO;
+  }  
+  
+  if (ntohs (attr->len) < sizeof (struct stun_addr))
+    return GNUNET_NO;
+  returned_addr = (const struct stun_addr *)(attr + 1);
+  if (AF_INET != returned_addr->family)
+    return GNUNET_NO;
+  st->attr = type;
+  sa->sin_family = AF_INET;
+  sa->sin_port = returned_addr->port ^ htons (ntohl(magic) >> 16);
+  sa->sin_addr.s_addr = returned_addr->addr ^ magic;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle an incoming STUN response.  Do some basic sanity checks on
+ * packet size and content, try to extract information.
+ * At the moment this only processes BIND requests,
+ * and returns the externally visible address of the original
+ * request.
+ *
+ * @param data the packet
+ * @param len the length of the packet in @a data
+ * @param[out] arg sockaddr_in where we will set our discovered address
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_NO if the packet is invalid (not a stun packet)
+ */
+int
+GNUNET_NAT_stun_handle_packet_ (const void *data,
+                               size_t len,
+                               struct sockaddr_in *arg)
+{
+  const struct stun_header *hdr;
+  const struct stun_attr *attr;
+  struct StunState st;
+  uint32_t advertised_message_size;
+  uint32_t message_magic_cookie;
+  int ret = GNUNET_SYSERR;
+
+  /* On entry, 'len' is the length of the UDP payload. After the
+   * initial checks it becomes the size of unprocessed options,
+   * while 'data' is advanced accordingly.
+   */
+  if (len < sizeof(struct stun_header))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Packet too short to be a STUN packet\n");
+    return GNUNET_NO;
+  }
+  hdr = data;
+  /* Skip header as it is already in hdr */
+  len -= sizeof(struct stun_header);
+  data += sizeof(struct stun_header);
+
+  /* len as advertised in the message */
+  advertised_message_size = ntohs (hdr->msglen);
+  message_magic_cookie = ntohl (hdr->magic);
+  /* Compare if the cookie match */
+  if (STUN_MAGIC_COOKIE != message_magic_cookie)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Invalid magic cookie for STUN packet\n");
+    return GNUNET_NO;
+  }
+
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "STUN Packet, msg %s (%04x), length: %d\n",
+       stun_msg2str (ntohs (hdr->msgtype)),
+       ntohs (hdr->msgtype),
+       advertised_message_size);
+  if (advertised_message_size > len)
+  {
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "Scrambled STUN packet length (got %d, expecting %d)\n",
+         advertised_message_size,
+         (int) len);
+    return GNUNET_NO;
+  }
+  len = advertised_message_size;
+  memset (&st, 0, sizeof(st));
+
+  while (len > 0)
+  {
+    if (len < sizeof (struct stun_attr))
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           "Attribute too short (got %d, expecting %d)\n",
+           (int) len,
+           (int) sizeof (struct stun_attr));
+      break;
+    }
+    attr = (const struct stun_attr *) data;
+
+    /* compute total attribute length */
+    advertised_message_size = ntohs (attr->len) + sizeof (struct stun_attr);
+
+    /* Check if we still have space in our buffer */
+    if (advertised_message_size > len)
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           "Inconsistent attribute (length %d exceeds remaining msg len %d)\n",
+           advertised_message_size,
+           (int) len);
+      break;
+    }
+    if (GNUNET_OK ==
+       stun_get_mapped (&st,
+                        attr,
+                        hdr->magic,
+                        arg))
+      ret = GNUNET_OK;
+    data += advertised_message_size;
+    len -= advertised_message_size;
+  }
+  return ret;
+}
+
+/* end of gnunet-service-nat_stun.c */
diff --git a/src/nat/gnunet-service-nat_stun.h 
b/src/nat/gnunet-service-nat_stun.h
new file mode 100644
index 0000000..3d7e18f
--- /dev/null
+++ b/src/nat/gnunet-service-nat_stun.h
@@ -0,0 +1,61 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2015, 2016 GNUnet e.V.
+
+     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 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * This code provides some support for doing STUN transactions.  We
+ * receive the simplest possible packet as the STUN server and try
+ * to respond properly.
+ *
+ * All STUN packets start with a simple header made of a type,
+ * length (excluding the header) and a 16-byte random transaction id.
+ * Following the header we may have zero or more attributes, each
+ * structured as a type, length and a value (whose format depends
+ * on the type, but often contains addresses).
+ * Of course all fields are in network format.
+ *
+ * This code was based on ministun.c.
+ *
+ * @file nat/gnunet-service-nat_stun.h
+ * @brief Functions for STUN functionality
+ * @author Bruno Souza Cabral
+ */
+#ifndef GNUNET_SERVICE_NAT_STUN_H
+#define GNUNET_SERVICE_NAT_STUN_H
+
+#include "platform.h"
+
+/**
+ * Handle an incoming STUN response.  Do some basic sanity checks on
+ * packet size and content, try to extract information.
+ * At the moment this only processes BIND requests,
+ * and returns the externally visible address of the original
+ * request.
+ *
+ * @param data the packet
+ * @param len the length of the packet in @a data
+ * @param[out] arg sockaddr_in where we will set our discovered address
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_NO if the packet is invalid (not a stun packet)
+ */
+int
+GNUNET_NAT_stun_handle_packet_ (const void *data,
+                               size_t len,
+                               struct sockaddr_in *arg);
+
+#endif
diff --git a/src/nat/nat.h b/src/nat/nat.h
index a385ced..6df72c0 100644
--- a/src/nat/nat.h
+++ b/src/nat/nat.h
@@ -234,61 +234,6 @@ struct GNUNET_NAT_AddressChangeNotificationMessage
 
 
 /**
- * Client requesting test of network connectivity.
- */
-struct GNUNET_NAT_RequestTestMessage
-{
-  /**
-   * Header with type #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Port to bind to, in NBO
-   */
-  uint16_t bind_port GNUNET_PACKED;
-
-  /**
-   * Port external verifier should try to connect to, in NBO.
-   */
-  uint16_t extern_port GNUNET_PACKED;
-
-  /**
-   * IPv4 to bind to, in NBO.
-   */
-  struct in_addr bind_ip GNUNET_PACKED;
-
-  /**
-   * IPv4 external verifier should try to connect to, in NBO.
-   */
-  struct in_addr extern_ip GNUNET_PACKED;
-  
-  /**
-   * IP protocol to use, i.e. IPPROTO_UDP or IPPROTO_TCP.
-   */
-  uint8_t proto;
-
-};
-
-
-/**
- * Service responding with network connectivity test result.
- */
-struct GNUNET_NAT_TestResultMessage
-{
-  /**
-   * Header with type #GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * An `enum GNUNET_NAT_StatusCode` in NBO.
-   */
-  int32_t status_code GNUNET_PACKED;
-};
-
-
-/**
  * Client requesting automatic configuration.
  */
 struct GNUNET_NAT_AutoconfigRequestMessage
diff --git a/src/nat/nat_api.c b/src/nat/nat_api.c
index 421befa..cab2b65 100644
--- a/src/nat/nat_api.c
+++ b/src/nat/nat_api.c
@@ -544,15 +544,15 @@ test_stun_packet (const void *data,
  * Handle an incoming STUN message.  This function is useful as
  * some GNUnet service may be listening on a UDP port and might
  * thus receive STUN messages while trying to receive other data.
- * In this case, this function can be used to act as a proper
- * STUN server (if desired).
+ * In this case, this function can be used to process replies
+ * to STUN requests.
  *
  * The function does some basic sanity checks on packet size and
- * content, try to extract a bit of information, and possibly replies
- * if this is an actual STUN message.
+ * content, try to extract a bit of information.
  * 
  * At the moment this only processes BIND requests, and returns the
- * externally visible address of the request. 
+ * externally visible address of the request to the rest of the
+ * NAT logic.
  *
  * @param nh handle to the NAT service
  * @param sender_addr address from which we got @a data
@@ -693,148 +693,6 @@ GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
 }
 
 
-/**
- * Handle to a NAT test.
- */
-struct GNUNET_NAT_Test
-{
-
-  /**
-   * Configuration we use.
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-  
-  /**
-   * Message queue for communicating with the NAT service.
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Function called to report success or failure for
-   * NAT configuration test.
-   */
-  GNUNET_NAT_TestCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-};
-
-
-/**
- * Handle result for a NAT test from the service.
- *
- * @param cls our `struct GNUNET_NAT_Test *`
- * @param rm message with the result of the test
- */
-static void
-handle_test_result (void *cls,
-                   const struct GNUNET_NAT_TestResultMessage *rm)
-{
-  struct GNUNET_NAT_Test *tst = cls;
-  enum GNUNET_NAT_StatusCode sc;
-
-  sc = (enum GNUNET_NAT_StatusCode) ntohl (rm->status_code);
-  tst->cb (tst->cb_cls,
-          sc);
-  GNUNET_NAT_test_stop (tst);  
-}
-                   
-
-/**
- * Handle queue errors by reporting test failure.
- *
- * @param cls the `struct GNUNET_NAT_Test *`
- * @param error details about the error
- */
-static void
-tst_error_handler (void *cls,
-                 enum GNUNET_MQ_Error error)
-{
-  struct GNUNET_NAT_Test *tst = cls;
-
-  tst->cb (tst->cb_cls,
-          GNUNET_NAT_ERROR_IPC_FAILURE);
-  GNUNET_NAT_test_stop (tst);
-}
-
-
-/**
- * Start testing if NAT traversal works using the given configuration
- * (IPv4-only).  The transport adapters should be down while using
- * this function.
- *
- * @param cfg configuration for the NAT traversal
- * @param proto protocol to test, i.e. IPPROTO_TCP or IPPROTO_UDP
- * @param bind_ip IPv4 address to bind to
- * @param bnd_port port to bind to, 0 to test connection reversal
- * @param extern_ip IPv4 address to externally advertise
- * @param extern_port externally advertised port to use
- * @param report function to call with the result of the test
- * @param report_cls closure for @a report
- * @return handle to cancel NAT test
- */
-struct GNUNET_NAT_Test *
-GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                       uint8_t proto,
-                      struct in_addr bind_ip,
-                       uint16_t bnd_port,
-                      struct in_addr extern_ip,
-                       uint16_t extern_port,
-                       GNUNET_NAT_TestCallback report,
-                       void *report_cls)
-{
-  struct GNUNET_NAT_Test *tst = GNUNET_new (struct GNUNET_NAT_Test);
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_fixed_size (test_result,
-                            GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT,
-                            struct GNUNET_NAT_TestResultMessage,
-                            tst),
-    GNUNET_MQ_handler_end ()
-  };
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_NAT_RequestTestMessage *req;
-
-  tst->cb = report;
-  tst->cb_cls = report_cls;
-  tst->mq = GNUNET_CLIENT_connecT (cfg,
-                                  "nat",
-                                  handlers,
-                                  &tst_error_handler,
-                                  tst);
-  if (NULL == tst->mq)
-  {
-    GNUNET_break (0);
-    GNUNET_free (tst);
-    return NULL;
-  }
-  env = GNUNET_MQ_msg (req,
-                      GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST);
-  req->bind_port = htons (bnd_port);
-  req->extern_port = htons (extern_port);
-  req->bind_ip = bind_ip;
-  req->extern_ip = extern_ip;
-  req->proto = proto;
-  GNUNET_MQ_send (tst->mq,
-                 env);
-  return tst;
-}
-
-
-/**
- * Stop an active NAT test.
- *
- * @param tst test to stop.
- */
-void
-GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
-{
-  GNUNET_MQ_destroy (tst->mq);
-  GNUNET_free (tst);
-}
-
 
 /**
  * Handle to auto-configuration in progress.
diff --git a/src/nat/nat_api_stun.c b/src/nat/nat_api_stun.c
new file mode 100644
index 0000000..0d4ba86
--- /dev/null
+++ b/src/nat/nat_api_stun.c
@@ -0,0 +1,261 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2015, 2016 GNUnet e.V.
+
+     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 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * This code provides some support for doing STUN transactions.
+ * We send simplest possible packet ia REQUEST with BIND to a STUN server.
+ *
+ * All STUN packets start with a simple header made of a type,
+ * length (excluding the header) and a 16-byte random transaction id.
+ * Following the header we may have zero or more attributes, each
+ * structured as a type, length and a value (whose format depends
+ * on the type, but often contains addresses).
+ * Of course all fields are in network format.
+ *
+ * This code was based on ministun.c.
+ *
+ * @file nat/nat_api_stun.c
+ * @brief Functions for STUN functionality
+ * @author Bruno Souza Cabral
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_nat_lib.h"
+
+
+#include "nat_stun.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
+
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+
+/**
+ * Handle to a request given to the resolver.  Can be used to cancel
+ * the request prior to the timeout or successful execution.  Also
+ * used to track our internal state for the request.
+ */
+struct GNUNET_NAT_STUN_Handle
+{
+
+  /**
+   * Handle to a pending DNS lookup request.
+   */
+  struct GNUNET_RESOLVER_RequestHandle *dns_active;
+
+  /**
+   * Handle to the listen socket
+   */
+  struct GNUNET_NETWORK_Handle *sock;
+
+  /**
+   * Stun server address
+   */
+  char *stun_server;
+
+  /**
+   * Function to call when a error occours
+   */
+  GNUNET_NAT_STUN_ErrorCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Do we got a DNS resolution successfully?
+   */
+  int dns_success;
+
+  /**
+   * STUN port
+   */
+  uint16_t stun_port;
+
+};
+
+
+/**
+ * Encode a class and method to a compatible STUN format
+ *
+ * @param msg_class class to be converted
+ * @param method method to be converted
+ * @return message in a STUN compatible format
+ */
+static int
+encode_message (enum StunClasses msg_class,
+                enum StunMethods method)
+{
+  return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
+    (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
+}
+
+
+/**
+ * Fill the stun_header with a random request_id
+ *
+ * @param req, stun header to be filled
+ */
+static void
+generate_request_id (struct stun_header *req)
+{
+  req->magic = htonl(STUN_MAGIC_COOKIE);
+  for (unsigned int x = 0; x < 3; x++)
+    req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                              UINT32_MAX);
+}
+
+
+/**
+ * Try to establish a connection given the specified address.
+ *
+ * @param cls our `struct GNUNET_NAT_STUN_Handle *`
+ * @param addr address to try, NULL for "last call"
+ * @param addrlen length of @a addr
+ */
+static void
+stun_dns_callback (void *cls,
+                   const struct sockaddr *addr,
+                   socklen_t addrlen)
+{
+  struct GNUNET_NAT_STUN_Handle *rh = cls;
+  struct stun_header req;
+  struct sockaddr_in server;
+
+  if (NULL == addr)
+  {
+    rh->dns_active = NULL;
+    if (GNUNET_NO == rh->dns_success)
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           "Error resolving host %s\n",
+           rh->stun_server);
+      rh->cb (rh->cb_cls,
+              GNUNET_NAT_ERROR_NOT_ONLINE);
+    }
+    else if (GNUNET_SYSERR == rh->dns_success)
+    {
+      rh->cb (rh->cb_cls,
+             GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
+    }
+    else
+    {
+      rh->cb (rh->cb_cls,
+             GNUNET_NAT_ERROR_SUCCESS);
+    }
+    GNUNET_NAT_stun_make_request_cancel (rh);
+    return;
+  }
+
+  rh->dns_success = GNUNET_YES;
+  memset (&server, 0, sizeof(server));
+  server.sin_family = AF_INET;
+  server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
+  server.sin_port = htons (rh->stun_port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  server.sin_len = (u_char) sizeof (struct sockaddr_in);
+#endif
+
+  /* Craft the simplest possible STUN packet. A request binding */
+  generate_request_id (&req);
+  req.msglen = htons (0);
+  req.msgtype = htons (encode_message (STUN_REQUEST,
+                                      STUN_BINDING));
+
+  /* Send the packet */
+  if (-1 ==
+      GNUNET_NETWORK_socket_sendto (rh->sock,
+                                   &req,
+                                   sizeof (req),
+                                   (const struct sockaddr *) &server,
+                                   sizeof (server)))
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                         "sendto");
+    rh->dns_success = GNUNET_SYSERR;
+    return;
+  }
+}
+
+
+/**
+ * Make Generic STUN request. Sends a generic stun request to the
+ * server specified using the specified socket, possibly waiting for
+ * a reply and filling the 'reply' field with the externally visible
+ * address.
+ *
+ * @param server the address of the stun server
+ * @param port port of the stun server, in host byte order
+ * @param sock the socket used to send the request
+ * @param cb callback in case of error
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct GNUNET_NAT_STUN_Handle *
+GNUNET_NAT_stun_make_request (const char *server,
+                              uint16_t port,
+                              struct GNUNET_NETWORK_Handle *sock,
+                              GNUNET_NAT_STUN_ErrorCallback cb,
+                              void *cb_cls)
+{
+  struct GNUNET_NAT_STUN_Handle *rh;
+
+  rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle);
+  rh->sock = sock;
+  rh->cb = cb;
+  rh->cb_cls = cb_cls;
+  rh->stun_server = GNUNET_strdup (server);
+  rh->stun_port = port;
+  rh->dns_success = GNUNET_NO;
+  rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server,
+                                           AF_INET,
+                                           TIMEOUT,
+                                           &stun_dns_callback, rh);
+  if (NULL == rh->dns_active)
+  {
+    GNUNET_NAT_stun_make_request_cancel (rh);
+    return NULL;
+  }
+  return rh;
+}
+
+
+/**
+ * Cancel active STUN request. Frees associated resources
+ * and ensures that the callback is no longer invoked.
+ *
+ * @param rh request to cancel
+ */
+void
+GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh)
+{
+  if (NULL != rh->dns_active)
+  {
+    GNUNET_RESOLVER_request_cancel (rh->dns_active);
+    rh->dns_active = NULL;
+  }
+  GNUNET_free (rh->stun_server);
+  GNUNET_free (rh);
+}
+
+
+/* end of nat_stun.c */
diff --git a/src/nat/nat_test.c b/src/nat/nat_api_test.c
similarity index 99%
copy from src/nat/nat_test.c
copy to src/nat/nat_api_test.c
index 803ff23..d47c140 100644
--- a/src/nat/nat_test.c
+++ b/src/nat/nat_api_test.c
@@ -17,9 +17,8 @@
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
-
 /**
- * @file nat/nat_test.c
+ * @file nat/nat_api_test.c
  * @brief functions to test if the NAT configuration is successful at 
achieving NAT traversal (with the help of a gnunet-nat-server)
  * @author Christian Grothoff
  */
diff --git a/src/nat/nat_stun.c b/src/nat/nat_stun.c
index b914abb..62916ab 100644
--- a/src/nat/nat_stun.c
+++ b/src/nat/nat_stun.c
@@ -104,32 +104,6 @@ struct StunState
 
 
 /**
- * Convert a message to a StunClass
- *
- * @param msg the received message
- * @return the converted StunClass
- */
-static int
-decode_class(int msg)
-{
-  /* Sorry for the magic, but this maps the class according to rfc5245 */
-  return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
-}
-
-/**
- * Convert a message to a StunMethod
- *
- * @param msg the received message
- * @return the converted StunMethod
- */
-static int
-decode_method(int msg)
-{
-  return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
-}
-
-
-/**
  * Encode a class and method to a compatible STUN format
  *
  * @param msg_class class to be converted
@@ -146,106 +120,6 @@ encode_message (enum StunClasses msg_class,
 
 
 /**
- * Print a class and method from a STUN message
- *
- * @param msg
- * @return string with the message class and method
- */
-static const char *
-stun_msg2str(int msg)
-{
-  static const struct {
-    enum StunClasses value;
-    const char *name;
-  } classes[] = {
-    { STUN_REQUEST, "Request" },
-    { STUN_INDICATION, "Indication" },
-    { STUN_RESPONSE, "Response" },
-    { STUN_ERROR_RESPONSE, "Error Response" },
-    { 0, NULL }
-  };
-  static const struct {
-    enum StunMethods value;
-    const char *name;
-  } methods[] = {
-    { STUN_BINDING, "Binding" },
-    { 0, NULL }
-  };
-  static char result[32];
-  const char *msg_class = NULL;
-  const char *method = NULL;
-  int i;
-  int value;
-
-  value = decode_class(msg);
-  for (i = 0; classes[i].name; i++)
-  {
-    msg_class = classes[i].name;
-    if (classes[i].value == value)
-      break;
-  }
-  value = decode_method(msg);
-  for (i = 0; methods[i].name; i++)
-  {
-    method = methods[i].name;
-    if (methods[i].value == value)
-      break;
-  }
-  GNUNET_snprintf (result,
-                   sizeof(result),
-                   "%s %s",
-                   method ? : "Unknown Method",
-                   msg_class ? : "Unknown Class Message");
-  return result;
-}
-
-
-/**
- * Print attribute name
- *
- * @param msg with a attribute type
- * @return string with the attribute name
- */
-static const char *
-stun_attr2str (int msg)
-{
-  static const struct {
-    enum StunAttributes value;
-    const char *name;
-  } attrs[] = {
-    { STUN_MAPPED_ADDRESS, "Mapped Address" },
-    { STUN_RESPONSE_ADDRESS, "Response Address" },
-    { STUN_CHANGE_ADDRESS, "Change Address" },
-    { STUN_SOURCE_ADDRESS, "Source Address" },
-    { STUN_CHANGED_ADDRESS, "Changed Address" },
-    { STUN_USERNAME, "Username" },
-    { STUN_PASSWORD, "Password" },
-    { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
-    { STUN_ERROR_CODE, "Error Code" },
-    { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
-    { STUN_REFLECTED_FROM, "Reflected From" },
-    { STUN_REALM, "Realm" },
-    { STUN_NONCE, "Nonce" },
-    { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
-    { STUN_MS_VERSION, "MS Version" },
-    { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
-    { STUN_SOFTWARE, "Software" },
-    { STUN_ALTERNATE_SERVER, "Alternate Server" },
-    { STUN_FINGERPRINT, "Fingerprint" },
-    { 0, NULL }
-  };
-  unsigned int i;
-
-  for (i = 0; attrs[i].name; i++)
-  {
-    if (attrs[i].value == msg)
-      return attrs[i].name;
-  }
-  return "Unknown Attribute";
-}
-
-
-/**
  * Fill the stun_header with a random request_id
  *
  * @param req, stun header to be filled
diff --git a/src/nat/nat_stun.h b/src/nat/nat_stun.h
index f8d99b1..4c6c178 100644
--- a/src/nat/nat_stun.h
+++ b/src/nat/nat_stun.h
@@ -17,15 +17,14 @@
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
-
 /**
- * Testcase for STUN server resolution
+ * Message types for STUN server resolution
  *
  * @file nat/nat_stun.h
  * @brief Testcase for STUN library
  * @author Bruno Souza Cabral
  * @autor Mark Spencer (Original code borrowed from Asterisk)
- *
+ * @author Christian Grothoff
  */
 
 
@@ -34,7 +33,10 @@
 
 #define STUN_MAGIC_COOKIE      0x2112A442
 
-typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id;
+typedef struct {
+  uint32_t id[3];
+} GNUNET_PACKED stun_trans_id;
+
 
 struct stun_header
 {
@@ -44,32 +46,47 @@ struct stun_header
   stun_trans_id id;
 } GNUNET_PACKED;
 
+
 struct stun_attr
 {
   uint16_t attr;
   uint16_t len;
 } GNUNET_PACKED;
 
-/*
+
+/**
  * The format normally used for addresses carried by STUN messages.
  */
 struct stun_addr
 {
   uint8_t  unused;
+
+  /**
+   * Address family, we expect AF_INET.
+   */
   uint8_t  family;
+
+  /**
+   * Port number.
+   */
   uint16_t port;
+  
+  /**
+   * IPv4 address. Should this be "struct in_addr"?
+   */
   uint32_t   addr;
 } GNUNET_PACKED;
 
 
-
-/* STUN message classes */
+/**
+ * STUN message classes 
+ */
 enum StunClasses {
-    INVALID_CLASS = 0,
-    STUN_REQUEST = 0x0000,
-    STUN_INDICATION = 0x0001,
-    STUN_RESPONSE = 0x0002,
-    STUN_ERROR_RESPONSE = 0x0003
+  INVALID_CLASS = 0,
+  STUN_REQUEST = 0x0000,
+  STUN_INDICATION = 0x0001,
+  STUN_RESPONSE = 0x0002,
+  STUN_ERROR_RESPONSE = 0x0003
 };
 
 enum StunMethods {
@@ -84,7 +101,9 @@ enum StunMethods {
   STUN_CHANNEL_BIND = 0x0009
 };
 
-/* Basic attribute types in stun messages.
+
+/**
+ * Basic attribute types in stun messages.
  * Messages can also contain custom attributes (codes above 0x7fff)
  */
 enum StunAttributes {
@@ -108,3 +127,128 @@ enum StunAttributes {
   STUN_ALTERNATE_SERVER = 0x8023,
   STUN_FINGERPRINT = 0x8028
 };
+
+
+/**
+ * Convert a message to a StunClass
+ *
+ * @param msg the received message
+ * @return the converted StunClass
+ */
+static int
+decode_class(int msg)
+{
+  /* Sorry for the magic, but this maps the class according to rfc5245 */
+  return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
+}
+
+/**
+ * Convert a message to a StunMethod
+ *
+ * @param msg the received message
+ * @return the converted StunMethod
+ */
+static int
+decode_method(int msg)
+{
+  return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
+}
+
+
+/**
+ * Print a class and method from a STUN message
+ *
+ * @param msg
+ * @return string with the message class and method
+ */
+static const char *
+stun_msg2str (int msg)
+{
+  static const struct {
+    enum StunClasses value;
+    const char *name;
+  } classes[] = {
+    { STUN_REQUEST, "Request" },
+    { STUN_INDICATION, "Indication" },
+    { STUN_RESPONSE, "Response" },
+    { STUN_ERROR_RESPONSE, "Error Response" },
+    { 0, NULL }
+  };
+  static const struct {
+    enum StunMethods value;
+    const char *name;
+  } methods[] = {
+    { STUN_BINDING, "Binding" },
+    { 0, NULL }
+  };
+  static char result[64];
+  const char *msg_class = NULL;
+  const char *method = NULL;
+  int value;
+
+  value = decode_class (msg);
+  for (unsigned int i = 0; classes[i].name; i++)
+    if (classes[i].value == value)
+    {
+      msg_class = classes[i].name;
+      break;
+    }
+  value = decode_method (msg);
+  for (unsigned int i = 0; methods[i].name; i++)
+    if (methods[i].value == value)
+    {
+      method = methods[i].name;
+      break;
+    }
+  GNUNET_snprintf (result,
+                   sizeof(result),
+                   "%s %s",
+                   method ? : "Unknown Method",
+                   msg_class ? : "Unknown Class Message");
+  return result;
+}
+
+
+/**
+ * Print attribute name
+ *
+ * @param msg with a attribute type
+ * @return string with the attribute name
+ */
+static const char *
+stun_attr2str (enum StunAttributes msg)
+{
+  static const struct {
+    enum StunAttributes value;
+    const char *name;
+  } attrs[] = {
+    { STUN_MAPPED_ADDRESS, "Mapped Address" },
+    { STUN_RESPONSE_ADDRESS, "Response Address" },
+    { STUN_CHANGE_ADDRESS, "Change Address" },
+    { STUN_SOURCE_ADDRESS, "Source Address" },
+    { STUN_CHANGED_ADDRESS, "Changed Address" },
+    { STUN_USERNAME, "Username" },
+    { STUN_PASSWORD, "Password" },
+    { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
+    { STUN_ERROR_CODE, "Error Code" },
+    { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
+    { STUN_REFLECTED_FROM, "Reflected From" },
+    { STUN_REALM, "Realm" },
+    { STUN_NONCE, "Nonce" },
+    { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
+    { STUN_MS_VERSION, "MS Version" },
+    { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
+    { STUN_SOFTWARE, "Software" },
+    { STUN_ALTERNATE_SERVER, "Alternate Server" },
+    { STUN_FINGERPRINT, "Fingerprint" },
+    { 0, NULL }
+  };
+
+  for (unsigned int i = 0; attrs[i].name; i++)
+    if (attrs[i].value == msg)
+      return attrs[i].name;
+  return "Unknown Attribute";
+}
+
+
+/* end of nat_stun.h */

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]