separate service for autoconfiguration from NAT traversal
authorChristian Grothoff <christian@grothoff.org>
Fri, 6 Jan 2017 12:26:38 +0000 (13:26 +0100)
committerChristian Grothoff <christian@grothoff.org>
Fri, 6 Jan 2017 12:26:38 +0000 (13:26 +0100)
27 files changed:
configure.ac
doc/man/Makefile.am
doc/man/gnunet-nat-auto.1 [new file with mode: 0644]
doc/man/gnunet-nat.1
po/POTFILES.in
src/Makefile.am
src/include/Makefile.am
src/include/gnunet_nat_auto_service.h [new file with mode: 0644]
src/include/gnunet_nat_service.h
src/include/gnunet_protocols.h
src/nat-auto/.gitignore [new file with mode: 0644]
src/nat-auto/Makefile.am [new file with mode: 0644]
src/nat-auto/gnunet-nat-auto.c [new file with mode: 0644]
src/nat-auto/gnunet-nat-server.c [new file with mode: 0644]
src/nat-auto/gnunet-service-nat-auto.c [new file with mode: 0644]
src/nat-auto/nat-auto.conf.in [new file with mode: 0644]
src/nat-auto/nat-auto.h [new file with mode: 0644]
src/nat-auto/nat_auto_api.c [new file with mode: 0644]
src/nat-auto/nat_auto_api_test.c [new file with mode: 0644]
src/nat/Makefile.am
src/nat/gnunet-nat-server.c [deleted file]
src/nat/gnunet-nat.c
src/nat/gnunet-service-nat.c
src/nat/nat.conf.in
src/nat/nat.h
src/nat/nat_api_auto.c [deleted file]
src/nat/nat_api_test.c [deleted file]

index c41bcc4b505fad3d5f29c9b373ff03ba7d22e689..dade7d2111f6c7ea202a55c688b1c3b5b3361379 100644 (file)
@@ -1596,6 +1596,8 @@ src/namestore/Makefile
 src/namestore/namestore.conf
 src/nat/Makefile
 src/nat/nat.conf
+src/nat-auto/Makefile
+src/nat-auto/nat-auto.conf
 src/nse/Makefile
 src/nse/nse.conf
 src/peerinfo/Makefile
index ff1e462b777e08de49f52cb335f17394f94cebe5..c40363b59b51a7ba87cbb49e9ca495be65640be6 100644 (file)
@@ -25,6 +25,7 @@ man_MANS = \
   gnunet-namestore.1 \
   gnunet-namestore-fcfsd.1 \
   gnunet-nat.1 \
+  gnunet-nat-auto.1 \
   gnunet-nat-server.1 \
   gnunet-peerinfo.1 \
   gnunet-publish.1 \
diff --git a/doc/man/gnunet-nat-auto.1 b/doc/man/gnunet-nat-auto.1
new file mode 100644 (file)
index 0000000..310f14d
--- /dev/null
@@ -0,0 +1,59 @@
+.TH GNUNET\-NAT\-AUTO 1 "6 Jan 2017" "GNUnet"
+
+.SH NAME
+gnunet\-nat\-auto \- autoconfigure and test NAT traversal
+
+.SH SYNOPSIS
+.B gnunet\-nat\-auto
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+
+This tool allows testing various NAT traversal functions, as well
+as attempting auto\-configuration.
+
+.SH OPTIONS
+.B
+.IP "\-a,  \-\-auto"
+Attempt auto\-configuration for NAT traversal.
+
+.B
+.IP "\-b ADDRESS,  \-\-bind=ADDRESS"
+Assume that the service is (locally) bound to ADDRESS.
+
+.B
+.IP "\-c FILENAME,  \-\-config=FILENAME"
+Use the configuration file FILENAME.
+
+.B
+.IP "\-e ADDRESS,  \-\-external=ADDRESS"
+Assume that ADDRESS is the globally visible address of the peer.
+
+.IP "\-t,  \-\-tcp"
+Use TCP.
+
+.B
+.IP "\-u,  \-\-udp"
+Use UDP.
+
+.B
+.IP "\-w,  \-\-write"
+Write configuration to configuration file, useful in combination with autoconfiguration (\-a).
+
+.SH EXAMPLES
+.PP
+
+\fBAutomatic configuration:\fR
+
+Probe and write result to configuration:
+
+  # gnunet\-nat\-auto \-aw
+  
+
+.SH BUGS
+Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <gnunet\-developers@gnu.org>
+
+.SH SEE ALSO
+gnunet\-transport(1) gnunet\-nat(1)
+
index 01e0267a4e74966e4a98a9f1374fad1f6fd7ad1f..a8a82883b7e417915594b3de43e55d1c4b2190ac 100644 (file)
@@ -14,9 +14,6 @@ This tool allows testing various NAT traversal functions, as well
 as attempting auto\-configuration.
 
 .SH OPTIONS
-.B
-.IP "\-a,  \-\-auto"
-Attempt auto\-configuration for NAT traversal.
 
 .B
 .IP "\-b ADDRESS,  \-\-bind=ADDRESS"
@@ -54,10 +51,6 @@ Use TCP.
 .IP "\-u,  \-\-udp"
 Use UDP.
 
-.B
-.IP "\-w,  \-\-write"
-Write configuration to configuration file, useful in combination with autoconfiguration (\-a).
-
 .B
 .IP "\-W,  \-\-watch"
 Watch for connection reversal requests.  
@@ -103,12 +96,6 @@ XXX:
 
   # gnunet-nat FIXME -s
 
-\fBAutomatic configuration:\fR
-
-Probe and write result to configuration:
-
-  # gnunet-nat -aw
-  
 
 .SH BUGS
 Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <gnunet\-developers@gnu.org>
index 56af200ff5f0d34c35c783d1a7cf608fe0f7385b..e1c3ec697d48e983b597595582b95edafa33bcaf 100644 (file)
@@ -237,19 +237,23 @@ src/namestore/plugin_namestore_flat.c
 src/namestore/plugin_namestore_postgres.c
 src/namestore/plugin_namestore_sqlite.c
 src/namestore/plugin_rest_namestore.c
+src/nat-auto/gnunet-nat-auto.c
+src/nat-auto/gnunet-nat-server.c
+src/nat-auto/gnunet-service-nat-auto.c
+src/nat-auto/nat_auto_api.c
+src/nat-auto/nat_auto_api_test.c
 src/nat/gnunet-helper-nat-client.c
 src/nat/gnunet-helper-nat-client-windows.c
 src/nat/gnunet-helper-nat-server.c
 src/nat/gnunet-helper-nat-server-windows.c
 src/nat/gnunet-nat.c
-src/nat/gnunet-nat-server.c
 src/nat/gnunet-service-nat.c
+src/nat/gnunet-service-nat_externalip.c
 src/nat/gnunet-service-nat_helper.c
 src/nat/gnunet-service-nat_mini.c
 src/nat/gnunet-service-nat_stun.c
 src/nat/nat_api.c
 src/nat/nat_api_stun.c
-src/nat/nat_api_test.c
 src/nat/nat_auto.c
 src/nat/nat.c
 src/nat/nat_mini.c
index 6925788d54a71d1c49d0b6c43f67e180dbbd01ac..d04cba9dd0a6c229ea54e092a38f962623292beb 100644 (file)
@@ -85,6 +85,7 @@ SUBDIRS = \
   template \
   ats \
   nat \
+  nat-auto \
   fragmentation \
   transport \
   ats-tool \
index f27fd6e36a01a6c08b892ffe30beb0062bd005f7..639d3bfd78f03074331a23f836c0728e3bba881f 100644 (file)
@@ -79,6 +79,7 @@ gnunetinclude_HEADERS = \
   gnunet_namestore_plugin.h \
   gnunet_namestore_service.h \
   gnunet_nat_lib.h \
+  gnunet_nat_auto_service.h \
   gnunet_nat_service.h \
   gnunet_nc_lib.h \
   gnunet_network_lib.h \
diff --git a/src/include/gnunet_nat_auto_service.h b/src/include/gnunet_nat_auto_service.h
new file mode 100644 (file)
index 0000000..90115ff
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2007-2017 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.
+*/
+
+/**
+ * @author Christian Grothoff
+ * @author Milan Bouchet-Valat
+ *
+ * @file
+ * Service for testing and autoconfiguration of
+ * NAT traversal functionality
+ *
+ * @defgroup nat  NAT testing library
+ *
+ * @{
+ */
+
+#ifndef GNUNET_NAT_AUTO_SERVICE_H
+#define GNUNET_NAT_AUTO_SERVICE_H
+
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Handle to a NAT test.
+ */
+struct GNUNET_NAT_Test;
+
+
+/**
+ * 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
+ */
+typedef void
+(*GNUNET_NAT_TestCallback) (void *cls,
+                           enum GNUNET_NAT_StatusCode result);
+
+
+/**
+ * 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.
+ *
+ * @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);
+
+
+/**
+ * Stop an active NAT test.
+ *
+ * @param tst test to stop.
+ */
+void
+GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst);
+
+
+/**
+ * Handle to auto-configuration in progress.
+ */
+struct GNUNET_NAT_AutoHandle;
+
+
+/**
+ * Converts `enum GNUNET_NAT_StatusCode` to string
+ *
+ * @param err error code to resolve to a string
+ * @return point to a static string containing the error code
+ */
+const char *
+GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err);
+
+
+/**
+ * Function called with the result from the autoconfiguration.
+ *
+ * @param cls closure
+ * @param diff minimal suggested changes to the original configuration
+ *             to make it work (as best as we can)
+ * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
+ * @param type what the situation of the NAT
+ */
+typedef void
+(*GNUNET_NAT_AutoResultCallback)(void *cls,
+                                 const struct GNUNET_CONFIGURATION_Handle *diff,
+                                 enum GNUNET_NAT_StatusCode result,
+                                 enum GNUNET_NAT_Type type);
+
+
+/**
+ * Start auto-configuration routine.  The transport adapters should
+ * be stopped while this function is called.
+ *
+ * @param cfg initial configuration
+ * @param cb function to call with autoconfiguration result
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel operation
+ */
+struct GNUNET_NAT_AutoHandle *
+GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                            GNUNET_NAT_AutoResultCallback cb,
+                            void *cb_cls);
+
+
+/**
+ * Abort autoconfiguration.
+ *
+ * @param ah handle for operation to abort
+ */
+void
+GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah);
+
+
+#endif
+
+/** @} */  /* end of group */
+
+/* end of gnunet_nat_auto_service.h */
index 6b9650306f284ec5863a810ad3346fdddf650bbe..94f8a8555feb0cdc7f371cda91fdb5bd9a752720 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2007-2016 GNUnet e.V.
+     Copyright (C) 2007-2017 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
@@ -136,132 +136,6 @@ enum GNUNET_NAT_AddressClass
 };
 
 
-/**
- * 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
- */
-typedef void
-(*GNUNET_NAT_AddressCallback) (void *cls,
-                               int add_remove,
-                              enum GNUNET_NAT_AddressClass ac,
-                               const struct sockaddr *addr,
-                               socklen_t addrlen);
-
-
-/**
- * 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 remote_addr public IP address of the other peer
- * @param remote_addrlen actual length of the @a remote_addr
- */
-typedef void
-(*GNUNET_NAT_ReversalCallback) (void *cls,
-                               const struct sockaddr *remote_addr,
-                                socklen_t remote_addrlen);
-
-
-/**
- * Handle for active NAT registrations.
- */
-struct GNUNET_NAT_Handle;
-
-
-/**
- * Attempt to enable port redirection and detect public IP address
- * contacting UPnP or NAT-PMP routers on the local network. Use @a
- * addr to specify to which of the local host's addresses should the
- * external port be mapped. The port is taken from the corresponding
- * sockaddr_in[6] field.  The NAT module should call the given @a
- * address_callback for any 'plausible' external address.
- *
- * @param cfg configuration to use
- * @param config_section name of the configuration section for optionsx
- * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
- * @param num_addrs number of addresses in @a addrs
- * @param addrs list of local addresses packets should be redirected to
- * @param addrlens actual lengths of the addresses in @a addrs
- * @param address_callback function to call everytime the public IP address changes
- * @param reversal_callback function to call if someone wants connection reversal from us,
- *        NULL if connection reversal is not supported
- * @param callback_cls closure for callbacks
- * @return NULL on error, otherwise handle that can be used to unregister
- */
-struct GNUNET_NAT_Handle *
-GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                     const char *config_section,
-                     uint8_t proto,
-                     unsigned int num_addrs,
-                     const struct sockaddr **addrs,
-                     const socklen_t *addrlens,
-                     GNUNET_NAT_AddressCallback address_callback,
-                     GNUNET_NAT_ReversalCallback reversal_callback,
-                     void *callback_cls);
-
-
-/**
- * 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
- * has returned so far.
- *
- * @param nh the handle returned by register
- * @param addr IP address to test (IPv4 or IPv6)
- * @param addrlen number of bytes in @a addr
- * @return #GNUNET_YES if the address is plausible,
- *         #GNUNET_NO if the address is not plausible,
- *         #GNUNET_SYSERR if the address is malformed
- */
-int
-GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
-                         const void *addr,
-                         socklen_t addrlen);
-
-
-/**
- * We learned about a peer (possibly behind NAT) so run the
- * gnunet-nat-client to send dummy ICMP responses to cause
- * that peer to connect to us (connection reversal).
- *
- * @param nh handle (used for configuration)
- * @param local_sa our local address of the peer (IPv4-only)
- * @param remote_sa the remote address of the peer (IPv4-only)
- * @return #GNUNET_SYSERR on error, 
- *         #GNUNET_NO if connection reversal is unavailable,
- *         #GNUNET_OK otherwise (presumably in progress)
- */
-int
-GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
-                            const struct sockaddr_in *local_sa,
-                            const struct sockaddr_in *remote_sa);
-
-
-/**
- * Stop port redirection and public IP address detection for the given
- * handle.  This frees the handle, after having sent the needed
- * commands to close open ports.
- *
- * @param nh the handle to unregister
- */
-void
-GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh);
-
-
-/**
- * Handle to a NAT test.
- */
-struct GNUNET_NAT_Test;
-
-
 /**
  * Error Types for the NAT subsystem (which can then later be converted/resolved to a string)
  */
@@ -365,129 +239,6 @@ enum GNUNET_NAT_StatusCode
 };
 
 
-/**
- * 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
- */
-typedef void
-(*GNUNET_NAT_TestCallback) (void *cls,
-                           enum GNUNET_NAT_StatusCode result);
-
-
-/**
- * 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.
- *
- * @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);
-
-
-/**
- * Stop an active NAT test.
- *
- * @param tst test to stop.
- */
-void
-GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst);
-
-
-/**
- * Handle to auto-configuration in progress.
- */
-struct GNUNET_NAT_AutoHandle;
-
 
 /**
  * What the situation of the NAT connectivity
@@ -522,54 +273,156 @@ enum GNUNET_NAT_Type
 };
 
 
+
 /**
- * Converts `enum GNUNET_NAT_StatusCode` to string
+ * Signature of the callback passed to #GNUNET_NAT_register() for
+ * a function to call whenever our set of 'valid' addresses changes.
  *
- * @param err error code to resolve to a string
- * @return point to a static string containing the error code
+ * @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
  */
-const char *
-GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err);
+typedef void
+(*GNUNET_NAT_AddressCallback) (void *cls,
+                               int add_remove,
+                              enum GNUNET_NAT_AddressClass ac,
+                               const struct sockaddr *addr,
+                               socklen_t addrlen);
 
 
 /**
- * Function called with the result from the autoconfiguration.
+ * 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 diff minimal suggested changes to the original configuration
- *             to make it work (as best as we can)
- * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
- * @param type what the situation of the NAT
+ * @param remote_addr public IP address of the other peer
+ * @param remote_addrlen actual length of the @a remote_addr
  */
 typedef void
-(*GNUNET_NAT_AutoResultCallback)(void *cls,
-                                 const struct GNUNET_CONFIGURATION_Handle *diff,
-                                 enum GNUNET_NAT_StatusCode result,
-                                 enum GNUNET_NAT_Type type);
+(*GNUNET_NAT_ReversalCallback) (void *cls,
+                               const struct sockaddr *remote_addr,
+                                socklen_t remote_addrlen);
+
+
+/**
+ * Handle for active NAT registrations.
+ */
+struct GNUNET_NAT_Handle;
 
 
 /**
- * Start auto-configuration routine.  The transport adapters should
- * be stopped while this function is called.
+ * Attempt to enable port redirection and detect public IP address
+ * contacting UPnP or NAT-PMP routers on the local network. Use @a
+ * addr to specify to which of the local host's addresses should the
+ * external port be mapped. The port is taken from the corresponding
+ * sockaddr_in[6] field.  The NAT module should call the given @a
+ * address_callback for any 'plausible' external address.
  *
- * @param cfg initial configuration
- * @param cb function to call with autoconfiguration result
- * @param cb_cls closure for @a cb
- * @return handle to cancel operation
+ * @param cfg configuration to use
+ * @param config_section name of the configuration section for options
+ * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
+ * @param num_addrs number of addresses in @a addrs
+ * @param addrs list of local addresses packets should be redirected to
+ * @param addrlens actual lengths of the addresses in @a addrs
+ * @param address_callback function to call everytime the public IP address changes
+ * @param reversal_callback function to call if someone wants connection reversal from us,
+ *        NULL if connection reversal is not supported
+ * @param callback_cls closure for callbacks
+ * @return NULL on error, otherwise handle that can be used to unregister
  */
-struct GNUNET_NAT_AutoHandle *
-GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                            GNUNET_NAT_AutoResultCallback cb,
-                            void *cb_cls);
+struct GNUNET_NAT_Handle *
+GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                     const char *config_section,
+                     uint8_t proto,
+                     unsigned int num_addrs,
+                     const struct sockaddr **addrs,
+                     const socklen_t *addrlens,
+                     GNUNET_NAT_AddressCallback address_callback,
+                     GNUNET_NAT_ReversalCallback reversal_callback,
+                     void *callback_cls);
+
+
+/**
+ * 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
+ * has returned so far.
+ *
+ * @param nh the handle returned by register
+ * @param addr IP address to test (IPv4 or IPv6)
+ * @param addrlen number of bytes in @a addr
+ * @return #GNUNET_YES if the address is plausible,
+ *         #GNUNET_NO if the address is not plausible,
+ *         #GNUNET_SYSERR if the address is malformed
+ */
+int
+GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
+                         const void *addr,
+                         socklen_t addrlen);
 
 
 /**
- * Abort autoconfiguration.
+ * We learned about a peer (possibly behind NAT) so run the
+ * gnunet-nat-client to send dummy ICMP responses to cause
+ * that peer to connect to us (connection reversal).
  *
- * @param ah handle for operation to abort
+ * @param nh handle (used for configuration)
+ * @param local_sa our local address of the peer (IPv4-only)
+ * @param remote_sa the remote address of the peer (IPv4-only)
+ * @return #GNUNET_SYSERR on error, 
+ *         #GNUNET_NO if connection reversal is unavailable,
+ *         #GNUNET_OK otherwise (presumably in progress)
+ */
+int
+GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
+                            const struct sockaddr_in *local_sa,
+                            const struct sockaddr_in *remote_sa);
+
+
+/**
+ * Stop port redirection and public IP address detection for the given
+ * handle.  This frees the handle, after having sent the needed
+ * commands to close open ports.
+ *
+ * @param nh the handle to unregister
  */
 void
-GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah);
+GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh);
+
+
+/**
+ * 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);
 
 
 #endif
index f9b7d3cb89b0a2d9926f59f1af5f5e47ecebea0d..fdabfee18740794c139b5653256e3123bb3d6cc2 100644 (file)
@@ -2820,7 +2820,7 @@ extern "C"
 /**
  * Message to ask NAT service to request autoconfiguration.
  */
-#define GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG 1067
+#define GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG 1067
 
 /**
  * Message from NAT service with the autoconfiguration result.
diff --git a/src/nat-auto/.gitignore b/src/nat-auto/.gitignore
new file mode 100644 (file)
index 0000000..6ba53d7
--- /dev/null
@@ -0,0 +1,3 @@
+gnunet-service-nat-auto
+gnunet-nat-auto
+gnunet-nat-server
diff --git a/src/nat-auto/Makefile.am b/src/nat-auto/Makefile.am
new file mode 100644 (file)
index 0000000..dbe9103
--- /dev/null
@@ -0,0 +1,58 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+pkgcfg_DATA = \
+  nat-auto.conf
+
+bin_PROGRAMS = \
+ gnunet-nat-auto \
+ gnunet-nat-server
+
+libexec_PROGRAMS = \
+ gnunet-service-nat-auto
+
+gnunet_nat_server_SOURCES = \
+ gnunet-nat-server.c nat-auto.h
+gnunet_nat_server_LDADD = \
+  $(top_builddir)/src/nat/libgnunetnat.la \
+  $(top_builddir)/src/util/libgnunetutil.la
+
+gnunet_nat_auto_SOURCES = \
+  gnunet-nat-auto.c nat-auto.h
+gnunet_nat_auto_LDADD = \
+  libgnunetnatauto.la \
+  $(top_builddir)/src/util/libgnunetutil.la
+
+
+if USE_COVERAGE
+  AM_CFLAGS = -fprofile-arcs -ftest-coverage
+endif
+
+lib_LTLIBRARIES = \
+  libgnunetnatauto.la
+
+libgnunetnatauto_la_SOURCES = \
+  nat_auto_api.c \
+  nat_auto_api_test.c 
+libgnunetnatauto_la_LIBADD = \
+  $(top_builddir)/src/nat/libgnunetnatnew.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL) @EXT_LIBS@ 
+libgnunetnatauto_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+  -version-info 0:0:0
+
+gnunet_service_nat_auto_SOURCES = \
+ gnunet-service-nat-auto.c
+gnunet_service_nat_auto_LDADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/nat/libgnunetnatnew.la \
+  $(LIBGCRYPT_LIBS) \
+  -lgcrypt \
+  $(GN_LIBINTL)
+
diff --git a/src/nat-auto/gnunet-nat-auto.c b/src/nat-auto/gnunet-nat-auto.c
new file mode 100644 (file)
index 0000000..3b9a5fa
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2015, 2016, 2017 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 src/nat/gnunet-nat-auto.c
+ * @brief Command-line tool for testing and autoconfiguration of NAT traversal
+ * @author Christian Grothoff
+ * @author Bruno Cabral
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_nat_service.h"
+#include "gnunet_nat_auto_service.h"
+
+/**
+ * Value to return from #main().
+ */
+static int global_ret;
+
+/**
+ * Handle to ongoing autoconfiguration.
+ */
+static struct GNUNET_NAT_AutoHandle *ah;
+
+/**
+ * If we do auto-configuration, should we write the result
+ * to a file?
+ */
+static int write_cfg;
+
+/**
+ * Configuration filename.
+ */ 
+static const char *cfg_file;
+
+/**
+ * Original configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Address we are bound to (in test), or should bind to
+ * (if #do_stun is set).
+ */
+static char *bind_addr;
+
+/**
+ * External IP address and port to use for the test.
+ * If not set, use #bind_addr.
+ */
+static char *extern_addr;
+
+/**
+ * Should we run autoconfiguration?
+ */
+static unsigned int do_auto;
+
+/**
+ * Handle to a NAT test operation.
+ */
+static struct GNUNET_NAT_Test *nt;
+
+/**
+ * Flag set to 1 if we use IPPROTO_UDP.
+ */
+static int use_udp;
+
+/**
+ * Flag set to 1 if we use IPPROTO_TCP.
+ */
+static int use_tcp;
+
+/**
+ * Protocol to use.
+ */
+static uint8_t proto;
+
+/**
+ * Test if all activities have finished, and if so,
+ * terminate.
+ */
+static void
+test_finished ()
+{
+  if (NULL != ah)
+    return;
+  if (NULL != nt)
+    return;
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Function to iterate over sugested changes options
+ *
+ * @param cls closure
+ * @param section name of the section
+ * @param option name of the option
+ * @param value value of the option
+ */
+static void
+auto_conf_iter (void *cls,
+                const char *section,
+                const char *option,
+                const char *value)
+{
+  struct GNUNET_CONFIGURATION_Handle *new_cfg = cls;
+  
+  PRINTF ("%s: %s\n",
+         option,
+         value);
+  if (NULL != new_cfg)
+    GNUNET_CONFIGURATION_set_value_string (new_cfg,
+                                          section,
+                                          option,
+                                          value);
+}
+
+
+/**
+ * Function called with the result from the autoconfiguration.
+ *
+ * @param cls closure
+ * @param diff minimal suggested changes to the original configuration
+ *             to make it work (as best as we can)
+ * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
+ * @param type what the situation of the NAT
+ */
+static void
+auto_config_cb (void *cls,
+               const struct GNUNET_CONFIGURATION_Handle *diff,
+               enum GNUNET_NAT_StatusCode result,
+               enum GNUNET_NAT_Type type)
+{
+  const char *nat_type;
+  char unknown_type[64];
+  struct GNUNET_CONFIGURATION_Handle *new_cfg;
+
+  ah = NULL;
+  switch (type)
+  {
+  case GNUNET_NAT_TYPE_NO_NAT:
+    nat_type = "NO NAT";
+    break;
+  case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
+    nat_type = "NAT but we can traverse";
+    break;
+  case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
+    nat_type = "NAT but STUN is able to identify the correct information";
+    break;
+  case GNUNET_NAT_TYPE_UPNP_NAT:
+    nat_type = "NAT but UPNP opened the ports";
+    break;
+  default:
+    SPRINTF (unknown_type,
+            "NAT unknown, type %u",
+            type);
+    nat_type = unknown_type;
+    break;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+             "NAT status: %s/%s\n",
+             GNUNET_NAT_status2string (result),
+             nat_type);
+
+  /* Shortcut: if there are no changes suggested, bail out early. */
+  if (GNUNET_NO ==
+      GNUNET_CONFIGURATION_is_dirty (diff))
+  {
+    test_finished ();
+    return;
+  }
+
+  /* Apply diff to original configuration and show changes
+     to the user */
+  new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
+  
+  if (NULL != diff)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+               _("Suggested configuration changes:\n"));
+    GNUNET_CONFIGURATION_iterate_section_values (diff,
+                                                "nat",
+                                                &auto_conf_iter,
+                                                new_cfg);
+  }
+
+  /* If desired, write configuration to file; we write only the
+     changes to the defaults to keep things compact. */
+  if ( (write_cfg) &&
+       (NULL != diff) )
+  {
+    struct GNUNET_CONFIGURATION_Handle *def_cfg;
+
+    GNUNET_CONFIGURATION_set_value_string (new_cfg,
+                                          "ARM",
+                                          "CONFIG",
+                                          NULL);
+    def_cfg = GNUNET_CONFIGURATION_create ();
+    GNUNET_break (GNUNET_OK ==
+                 GNUNET_CONFIGURATION_load (def_cfg,
+                                            NULL));
+    if (GNUNET_OK !=
+       GNUNET_CONFIGURATION_write_diffs (def_cfg,
+                                         new_cfg,
+                                         cfg_file))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 _("Failed to write configuration to `%s'\n"),
+                 cfg_file);
+      global_ret = 1;
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+                 _("Wrote updated configuration to `%s'\n"),
+                 cfg_file);
+    }
+    GNUNET_CONFIGURATION_destroy (def_cfg);
+  }
+
+  if (NULL != new_cfg)
+    GNUNET_CONFIGURATION_destroy (new_cfg);
+  test_finished ();
+}
+
+
+/**
+ * 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 ();
+}
+
+
+/**
+ * Task run on shutdown.
+ *
+ * @param cls NULL
+ */
+static void
+do_shutdown (void *cls)
+{
+  if (NULL != ah)
+  {
+    GNUNET_NAT_autoconfig_cancel (ah);
+    ah = NULL;
+  }
+  if (NULL != nt)
+  {
+    GNUNET_NAT_test_stop (nt);
+    nt = NULL;
+  }
+}
+
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  struct sockaddr_in bind_sa;
+  struct sockaddr_in extern_sa;
+
+  cfg_file = cfgfile;
+  cfg = c;
+  
+  GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
+                                NULL);
+
+  if (do_auto)
+  {
+    ah = GNUNET_NAT_autoconfig_start (c,
+                                     &auto_config_cb,
+                                     NULL);
+  }
+
+  if (use_tcp && use_udp)
+  {
+    if (do_auto)
+      return;
+    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+               "Cannot use TCP and UDP\n");
+    global_ret = 1;
+    return;
+  }
+  proto = 0;
+  if (use_tcp)
+    proto = IPPROTO_TCP;
+  if (use_udp)
+    proto = IPPROTO_UDP;
+
+  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 != 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);
+  }
+  test_finished ();
+}
+
+
+/**
+ * Main function of gnunet-nat
+ *
+ * @param argc number of command-line arguments
+ * @param argv command line
+ * @return 0 on success, -1 on error
+ */
+int
+main (int argc,
+      char *const argv[])
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    {'a', "auto", NULL,
+     gettext_noop ("run autoconfiguration"),
+     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 },
+    {'e', "external", "ADDRESS",
+     gettext_noop ("which external IP and port should be used to test"),
+     GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr },
+    {'t', "tcp", NULL,
+     gettext_noop ("use TCP"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp },
+    {'u', "udp", NULL,
+     gettext_noop ("use UDP"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
+    {'w', "write", NULL,
+     gettext_noop ("write configuration file (for autoconfiguration)"),
+     GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg },
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_get_utf8_args (argc, argv,
+                                   &argc, &argv))
+    return 2;
+  if (GNUNET_OK !=
+      GNUNET_PROGRAM_run (argc, argv,
+                         "gnunet-nat-auto [options]",
+                          _("GNUnet NAT traversal autoconfiguration"),
+                         options,
+                          &run,
+                         NULL))
+  {
+    global_ret = 1;
+  }
+  GNUNET_free ((void*) argv);
+  return global_ret;
+}
+
+
+/* end of gnunet-nat-auto.c */
diff --git a/src/nat-auto/gnunet-nat-server.c b/src/nat-auto/gnunet-nat-server.c
new file mode 100644 (file)
index 0000000..93352f5
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2011 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 src/nat/gnunet-nat-server.c
+ * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_nat_lib.h"
+#include "gnunet_protocols.h"
+#include "nat-auto.h"
+
+
+/**
+ * Our server.
+ */
+static struct GNUNET_SERVER_Handle *server;
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+
+/**
+ * Try contacting the peer using autonomous NAT traveral method.
+ *
+ * @param dst_ipv4 IPv4 address to send the fake ICMP message
+ * @param dport destination port to include in ICMP message
+ * @param is_tcp mark for TCP (#GNUNET_YES)  or UDP (#GNUNET_NO)
+ */
+static void
+try_anat (uint32_t dst_ipv4,
+          uint16_t dport,
+          int is_tcp)
+{
+  struct GNUNET_NAT_Handle *h;
+  struct sockaddr_in sa;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Asking for connection reversal with %x and code %u\n",
+              (unsigned int) dst_ipv4,
+              (unsigned int) dport);
+  h = GNUNET_NAT_register (cfg,
+                           is_tcp,
+                           dport,
+                           0,
+                           NULL, NULL, NULL, NULL, NULL, NULL);
+  memset (&sa, 0, sizeof (sa));
+  sa.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+  sa.sin_addr.s_addr = dst_ipv4;
+  GNUNET_NAT_run_client (h, &sa);
+  GNUNET_NAT_unregister (h);
+}
+
+
+/**
+ * Closure for #tcp_send.
+ */
+struct TcpContext
+{
+  /**
+   * TCP  socket.
+   */
+  struct GNUNET_NETWORK_Handle *s;
+
+  /**
+   * Data to transmit.
+   */
+  uint16_t data;
+};
+
+
+/**
+ * Task called by the scheduler once we can do the TCP send
+ * (or once we failed to connect...).
+ *
+ * @param cls the `struct TcpContext`
+ */
+static void
+tcp_send (void *cls)
+{
+  struct TcpContext *ctx = cls;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
+
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  if ((NULL != tc->write_ready) &&
+      (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
+  {
+    if (-1 ==
+        GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
+    }
+    GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
+  }
+  GNUNET_NETWORK_socket_close (ctx->s);
+  GNUNET_free (ctx);
+}
+
+
+/**
+ * Try to send @a data to the
+ * IP @a dst_ipv4' at port @a dport via TCP.
+ *
+ * @param dst_ipv4 target IP
+ * @param dport target port
+ * @param data data to send
+ */
+static void
+try_send_tcp (uint32_t dst_ipv4,
+              uint16_t dport,
+              uint16_t data)
+{
+  struct GNUNET_NETWORK_Handle *s;
+  struct sockaddr_in sa;
+  struct TcpContext *ctx;
+
+  s = GNUNET_NETWORK_socket_create (AF_INET,
+                                    SOCK_STREAM,
+                                    0);
+  if (NULL == s)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "socket");
+    return;
+  }
+  memset (&sa, 0, sizeof (sa));
+  sa.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+  sa.sin_addr.s_addr = dst_ipv4;
+  sa.sin_port = htons (dport);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending TCP message to `%s'\n",
+              GNUNET_a2s ((struct sockaddr *) &sa,
+                          sizeof (sa)));
+  if ( (GNUNET_OK !=
+        GNUNET_NETWORK_socket_connect (s,
+                                       (const struct sockaddr *) &sa,
+                                       sizeof (sa))) &&
+       (errno != EINPROGRESS) )
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "connect");
+    GNUNET_NETWORK_socket_close (s);
+    return;
+  }
+  ctx = GNUNET_new (struct TcpContext);
+  ctx->s = s;
+  ctx->data = data;
+  GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
+                                  s,
+                                  &tcp_send,
+                                  ctx);
+}
+
+
+/**
+ * Try to send @a data to the
+ * IP @a dst_ipv4 at port @a dport via UDP.
+ *
+ * @param dst_ipv4 target IP
+ * @param dport target port
+ * @param data data to send
+ */
+static void
+try_send_udp (uint32_t dst_ipv4,
+              uint16_t dport,
+              uint16_t data)
+{
+  struct GNUNET_NETWORK_Handle *s;
+  struct sockaddr_in sa;
+
+  s = GNUNET_NETWORK_socket_create (AF_INET,
+                                    SOCK_DGRAM,
+                                    0);
+  if (NULL == s)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "socket");
+    return;
+  }
+  memset (&sa, 0, sizeof (sa));
+  sa.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+  sa.sin_addr.s_addr = dst_ipv4;
+  sa.sin_port = htons (dport);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending UDP packet to `%s'\n",
+              GNUNET_a2s ((struct sockaddr *) &sa,
+                          sizeof (sa)));
+  if (-1 ==
+      GNUNET_NETWORK_socket_sendto (s,
+                                    &data,
+                                    sizeof (data),
+                                    (const struct sockaddr *) &sa,
+                                    sizeof (sa)))
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                         "sendto");
+  GNUNET_NETWORK_socket_close (s);
+}
+
+
+/**
+ * We've received a request to probe a NAT
+ * traversal. Do it.
+ *
+ * @param cls unused
+ * @param client handle to client (we always close)
+ * @param msg message with details about what to test
+ */
+static void
+test (void *cls,
+      struct GNUNET_SERVER_Client *client,
+      const struct GNUNET_MessageHeader *msg)
+{
+  const struct GNUNET_NAT_TestMessage *tm;
+  uint16_t dport;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received test request\n");
+  tm = (const struct GNUNET_NAT_TestMessage *) msg;
+  dport = ntohs (tm->dport);
+  if (0 == dport)
+    try_anat (tm->dst_ipv4,
+              ntohs (tm->data),
+              (int) ntohl (tm->is_tcp));
+  else if (GNUNET_YES == ntohl (tm->is_tcp))
+    try_send_tcp (tm->dst_ipv4,
+                  dport,
+                  tm->data);
+  else
+    try_send_udp (tm->dst_ipv4,
+                  dport,
+                  tm->data);
+  GNUNET_SERVER_receive_done (client,
+                              GNUNET_NO);
+}
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ */
+static void
+shutdown_task (void *cls)
+{
+  GNUNET_SERVER_destroy (server);
+  server = NULL;
+}
+
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+    {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
+     sizeof (struct GNUNET_NAT_TestMessage)},
+    {NULL, NULL, 0, 0}
+  };
+  unsigned int port;
+  struct sockaddr_in in4;
+  struct sockaddr_in6 in6;
+
+  socklen_t slen[] = {
+    sizeof (in4),
+    sizeof (in6),
+    0
+  };
+  struct sockaddr *sa[] = {
+    (struct sockaddr *) &in4,
+    (struct sockaddr *) &in6,
+    NULL
+  };
+
+  cfg = c;
+  if ( (NULL == args[0]) ||
+       (1 != SSCANF (args[0], "%u", &port)) ||
+       (0 == port) ||
+       (65536 <= port) )
+  {
+    FPRINTF (stderr,
+             _("Please pass valid port number as the first argument! (got `%s')\n"),
+             args[0]);
+    return;
+  }
+  memset (&in4, 0, sizeof (in4));
+  memset (&in6, 0, sizeof (in6));
+  in4.sin_family = AF_INET;
+  in4.sin_port = htons ((uint16_t) port);
+  in6.sin6_family = AF_INET6;
+  in6.sin6_port = htons ((uint16_t) port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  in4.sin_len = sizeof (in4);
+  in6.sin6_len = sizeof (in6);
+#endif
+  server = GNUNET_SERVER_create (NULL,
+                                NULL,
+                                (struct sockaddr * const *) sa,
+                                slen,
+                                GNUNET_TIME_UNIT_SECONDS,
+                                GNUNET_YES);
+  GNUNET_SERVER_add_handlers (server,
+                             handlers);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                NULL);
+}
+
+
+/**
+ * Main function of gnunet-nat-server.
+ *
+ * @param argc number of command-line arguments
+ * @param argv command line
+ * @return 0 on success, -1 on error
+ */
+int
+main (int argc, char *const argv[])
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_get_utf8_args (argc, argv,
+                                   &argc, &argv))
+    return 2;
+
+  if (GNUNET_OK !=
+      GNUNET_PROGRAM_run (argc,
+                         argv,
+                         "gnunet-nat-server [options] PORT",
+                          _("GNUnet NAT traversal test helper daemon"),
+                         options,
+                          &run,
+                         NULL))
+  {
+    GNUNET_free ((void*) argv);
+    return 1;
+  }
+  GNUNET_free ((void*) argv);
+  return 0;
+}
+
+
+/* end of gnunet-nat-server.c */
diff --git a/src/nat-auto/gnunet-service-nat-auto.c b/src/nat-auto/gnunet-service-nat-auto.c
new file mode 100644 (file)
index 0000000..897d6fe
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+  This file is part of GNUnet.
+  Copyright (C) 2016, 2017 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-auto/gnunet-service-nat-auto.c
+ * @brief NAT autoconfiguration service
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - merge client handle and autoconfig context
+ * - implement "more" autoconfig:
+ *   + re-work gnunet-nat-server & integrate!
+ *   + test manually punched NAT (how?)
+ */
+#include "platform.h"
+#include <math.h>
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_signatures.h"
+#include "gnunet_nat_service.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_resolver_service.h"
+#include "nat-auto.h"
+#include <gcrypt.h>
+
+
+/**
+ * How long do we wait until we forcefully terminate autoconfiguration?
+ */
+#define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+
+/**
+ * Internal data structure we track for each of our clients.
+ */
+struct ClientHandle
+{
+
+  /**
+   * Kept in a DLL.
+   */
+  struct ClientHandle *next;
+  
+  /**
+   * Kept in a DLL.
+   */
+  struct ClientHandle *prev;
+
+  /**
+   * Underlying handle for this client with the service.
+   */ 
+  struct GNUNET_SERVICE_Client *client;
+
+  /**
+   * Message queue for communicating with the client.
+   */
+  struct GNUNET_MQ_Handle *mq;
+};
+
+
+/**
+ * Context for autoconfiguration operations.
+ */
+struct AutoconfigContext
+{
+  /**
+   * Kept in a DLL.
+   */
+  struct AutoconfigContext *prev;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct AutoconfigContext *next;
+
+  /**
+   * Which client asked the question.
+   */
+  struct ClientHandle *ch;
+
+  /**
+   * Configuration we are creating.
+   */ 
+  struct GNUNET_CONFIGURATION_Handle *c;
+
+  /**
+   * Original configuration (for diffing).
+   */ 
+  struct GNUNET_CONFIGURATION_Handle *orig;
+
+  /**
+   * Timeout task to force termination.
+   */
+  struct GNUNET_SCHEDULER_Task *timeout_task;
+
+  /**
+   * #GNUNET_YES if upnpc should be used,
+   * #GNUNET_NO if upnpc should not be used,
+   * #GNUNET_SYSERR if we should simply not change the option.
+   */
+  int enable_upnpc;
+
+  /**
+   * Status code to return to the client.
+   */
+  enum GNUNET_NAT_StatusCode status_code;
+
+  /**
+   * NAT type to return to the client.
+   */
+  enum GNUNET_NAT_Type type;
+};
+
+
+/**
+ * Head of client DLL.
+ */
+static struct ClientHandle *ch_head;
+  
+/**
+ * Tail of client DLL.
+ */
+static struct ClientHandle *ch_tail;
+
+/**
+ * DLL of our autoconfiguration operations.
+ */
+static struct AutoconfigContext *ac_head;
+
+/**
+ * DLL of our autoconfiguration operations.
+ */
+static struct AutoconfigContext *ac_tail;
+
+/**
+ * Handle to our current configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to the statistics service.
+ */
+static struct GNUNET_STATISTICS_Handle *stats;
+
+
+/**
+ * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
+ * from client.
+ *
+ * @param cls client who sent the message
+ * @param message the message received
+ * @return #GNUNET_OK if message is well-formed
+ */
+static int
+check_autoconfig_request (void *cls,
+                         const struct GNUNET_NAT_AutoconfigRequestMessage *message)
+{
+  return GNUNET_OK;  /* checked later */
+}
+
+
+/**
+ * Stop all pending activities with respect to the @a ac
+ *
+ * @param ac autoconfiguration to terminate activities for
+ */
+static void
+terminate_ac_activities (struct AutoconfigContext *ac)
+{
+  if (NULL != ac->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (ac->timeout_task);
+    ac->timeout_task = NULL;
+  }
+}
+
+
+/**
+ * Finish handling the autoconfiguration request and send
+ * the response to the client.
+ *
+ * @param cls the `struct AutoconfigContext` to conclude
+ */
+static void
+conclude_autoconfig_request (void *cls)
+{
+  struct AutoconfigContext *ac = cls;
+  struct ClientHandle *ch = ac->ch;
+  struct GNUNET_NAT_AutoconfigResultMessage *arm;
+  struct GNUNET_MQ_Envelope *env;
+  size_t c_size;
+  char *buf;
+  struct GNUNET_CONFIGURATION_Handle *diff;
+  
+  ac->timeout_task = NULL;
+  terminate_ac_activities (ac);
+
+  /* Send back response */
+  diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
+                                       ac->c);
+  buf = GNUNET_CONFIGURATION_serialize (diff,
+                                       &c_size);
+  GNUNET_CONFIGURATION_destroy (diff);
+  env = GNUNET_MQ_msg_extra (arm,
+                            c_size,
+                            GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
+  arm->status_code = htonl ((uint32_t) ac->status_code);
+  arm->type = htonl ((uint32_t) ac->type);
+  GNUNET_memcpy (&arm[1],
+                buf,
+                c_size);
+  GNUNET_free (buf);
+  GNUNET_MQ_send (ch->mq,
+                 env);
+
+  /* clean up */
+  GNUNET_CONFIGURATION_destroy (ac->orig);
+  GNUNET_CONFIGURATION_destroy (ac->c);
+  GNUNET_CONTAINER_DLL_remove (ac_head,
+                              ac_tail,
+                              ac);
+  GNUNET_free (ac);
+  GNUNET_SERVICE_client_continue (ch->client);
+}
+
+
+/**
+ * Check if all autoconfiguration operations have concluded,
+ * and if they have, send the result back to the client.
+ *
+ * @param ac autoconfiguation context to check
+ */
+static void
+check_autoconfig_finished (struct AutoconfigContext *ac)
+{
+  GNUNET_SCHEDULER_cancel (ac->timeout_task);
+  ac->timeout_task
+    = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
+                               ac);
+}
+
+
+/**
+ * Update ENABLE_UPNPC configuration option.
+ *
+ * @param ac autoconfiguration to update
+ */
+static void
+update_enable_upnpc_option (struct AutoconfigContext *ac)
+{
+  switch (ac->enable_upnpc)
+  {
+  case GNUNET_YES:
+    GNUNET_CONFIGURATION_set_value_string (ac->c,
+                                          "NAT",
+                                          "ENABLE_UPNP",
+                                          "YES");
+    break;
+  case GNUNET_NO:
+    GNUNET_CONFIGURATION_set_value_string (ac->c,
+                                          "NAT",
+                                          "ENABLE_UPNP",
+                                          "NO");
+    break;
+  case GNUNET_SYSERR:
+    /* We are unsure, do not change option */
+    break;
+  }
+}
+
+
+/**
+ * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
+ * client.
+ *
+ * @param cls client who sent the message
+ * @param message the message received
+ */
+static void
+handle_autoconfig_request (void *cls,
+                          const struct GNUNET_NAT_AutoconfigRequestMessage *message)
+{
+  struct ClientHandle *ch = cls;
+  size_t left = ntohs (message->header.size) - sizeof (*message);
+  struct AutoconfigContext *ac;
+
+  ac = GNUNET_new (struct AutoconfigContext);
+  ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
+  ac->ch = ch;
+  ac->c = GNUNET_CONFIGURATION_create ();
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_deserialize (ac->c,
+                                       (const char *) &message[1],
+                                       left,
+                                       GNUNET_NO))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (ch->client);
+    GNUNET_CONFIGURATION_destroy (ac->c);
+    GNUNET_free (ac);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received REQUEST_AUTO_CONFIG message from client\n");
+
+  GNUNET_CONTAINER_DLL_insert (ac_head,
+                              ac_tail,
+                              ac);
+  ac->orig
+    = GNUNET_CONFIGURATION_dup (ac->c);
+  ac->timeout_task
+    = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
+                                   &conclude_autoconfig_request,
+                                   ac);
+  ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
+  
+  /* Probe for upnpc */
+  if (GNUNET_SYSERR ==
+      GNUNET_OS_check_helper_binary ("upnpc",
+                                    GNUNET_NO,
+                                    NULL))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+               _("UPnP client `upnpc` command not found, disabling UPnP\n"));
+    ac->enable_upnpc = GNUNET_NO;
+  }
+  else
+  {
+    /* We might at some point be behind NAT, try upnpc */
+    ac->enable_upnpc = GNUNET_YES;
+  }
+  update_enable_upnpc_option (ac);
+
+  /* Finally, check if we are already done */  
+  check_autoconfig_finished (ac);
+}
+
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ */
+static void
+shutdown_task (void *cls)
+{
+  struct AutoconfigContext *ac;
+
+  while (NULL != (ac = ac_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (ac_head,
+                                ac_tail,
+                                ac);
+    terminate_ac_activities (ac);
+    GNUNET_free (ac);
+  }
+  if (NULL != stats)
+  {
+    GNUNET_STATISTICS_destroy (stats,
+                              GNUNET_NO);
+    stats = NULL;
+  }
+}
+
+
+/**
+ * Setup NAT service.
+ *
+ * @param cls closure
+ * @param c configuration to use
+ * @param service the initialized service
+ */
+static void
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *c,
+     struct GNUNET_SERVICE_Handle *service)
+{
+  cfg = c;
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                NULL);
+  stats = GNUNET_STATISTICS_create ("nat-auto",
+                                   cfg);
+}
+
+
+/**
+ * Callback called when a client connects to the service.
+ *
+ * @param cls closure for the service
+ * @param c the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return a `struct ClientHandle`
+ */
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *c,
+                  struct GNUNET_MQ_Handle *mq)
+{
+  struct ClientHandle *ch;
+
+  ch = GNUNET_new (struct ClientHandle);
+  ch->mq = mq;
+  ch->client = c;
+  GNUNET_CONTAINER_DLL_insert (ch_head,
+                              ch_tail,
+                              ch);
+  return ch;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param c the client that disconnected
+ * @param internal_cls a `struct ClientHandle *`
+ */
+static void
+client_disconnect_cb (void *cls,
+                     struct GNUNET_SERVICE_Client *c,
+                     void *internal_cls)
+{
+  struct ClientHandle *ch = internal_cls;
+
+  GNUNET_CONTAINER_DLL_remove (ch_head,
+                              ch_tail,
+                              ch);
+  GNUNET_free (ch);
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("nat",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_var_size (autoconfig_request,
+                       GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG,
+                       struct GNUNET_NAT_AutoconfigRequestMessage,
+                       NULL),
+ GNUNET_MQ_handler_end ());
+
+
+#if defined(LINUX) && defined(__GLIBC__)
+#include <malloc.h>
+
+/**
+ * MINIMIZE heap size (way below 128k) since this process doesn't need much.
+ */
+void __attribute__ ((constructor))
+GNUNET_ARM_memory_init ()
+{
+  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
+  mallopt (M_TOP_PAD, 1 * 1024);
+  malloc_trim (0);
+}
+#endif
+
+/* end of gnunet-service-nat.c */
diff --git a/src/nat-auto/nat-auto.conf.in b/src/nat-auto/nat-auto.conf.in
new file mode 100644 (file)
index 0000000..daa3e38
--- /dev/null
@@ -0,0 +1,15 @@
+[nat]
+AUTOSTART = @AUTOSTART@
+@UNIXONLY@ PORT = 2124
+HOSTNAME = localhost
+BINARY = gnunet-service-nat-auto
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-nat-auto.sock
+UNIX_MATCH_UID = YES
+UNIX_MATCH_GID = YES
+
+[gnunet-nat-server]
+HOSTNAME = gnunet.org
+PORT = 5724
+NOARMBIND = YES
diff --git a/src/nat-auto/nat-auto.h b/src/nat-auto/nat-auto.h
new file mode 100644 (file)
index 0000000..150dc32
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2011, 2016, 2017 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 src/nat-auto/nat-auto.h
+ * @brief Messages for interaction with gnunet-nat-auto-service
+ * @author Christian Grothoff
+ *
+ */
+#ifndef NAT_AUTO_H
+#define NAT_AUTO_H
+#include "gnunet_util_lib.h"
+
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Request to test NAT traversal, sent to the gnunet-nat-server
+ * (not the service!).
+ */
+struct GNUNET_NAT_TestMessage
+{
+  /**
+   * Header with type #GNUNET_MESSAGE_TYPE_NAT_TEST
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * IPv4 target IP address
+   */
+  uint32_t dst_ipv4;
+
+  /**
+   * Port to use, 0 to send dummy ICMP response.
+   */
+  uint16_t dport;
+
+  /**
+   * Data to send OR advertised-port (in NBO) to use for dummy ICMP.
+   */
+  uint16_t data;
+
+  /**
+   * #GNUNET_YES for TCP, #GNUNET_NO for UDP.
+   */
+  int32_t is_tcp;
+
+};
+
+
+/**
+ * Client requesting automatic configuration.
+ */
+struct GNUNET_NAT_AutoconfigRequestMessage
+{
+  /**
+   * Header with type #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG
+   */
+  struct GNUNET_MessageHeader header;
+
+  /* Followed by configuration (diff, serialized, compressed) */
+  
+};
+
+
+/**
+ * Service responding with proposed configuration.
+ */
+struct GNUNET_NAT_AutoconfigResultMessage
+{
+  /**
+   * Header with type #GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT
+   */
+  struct GNUNET_MessageHeader header;
+  
+  /**
+   * An `enum GNUNET_NAT_StatusCode` in NBO.
+   */
+  int32_t status_code GNUNET_PACKED;
+
+  /**
+   * An `enum GNUNET_NAT_Type` in NBO.
+   */
+  int32_t type GNUNET_PACKED;
+
+  /* Followed by configuration (diff, serialized, compressed) */
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+#endif
diff --git a/src/nat-auto/nat_auto_api.c b/src/nat-auto/nat_auto_api.c
new file mode 100644 (file)
index 0000000..e6b0512
--- /dev/null
@@ -0,0 +1,274 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2007-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.
+*/
+
+/**
+ * @author Christian Grothoff
+ * @author Milan Bouchet-Valat
+ *
+ * @file nat/nat_auto_api.c
+ * Routines for NAT auto configuration.
+ */
+#include "platform.h"
+#include "gnunet_nat_service.h"
+#include "gnunet_nat_auto_service.h"
+#include "nat-auto.h"
+
+
+
+/**
+ * Handle to auto-configuration in progress.
+ */
+struct GNUNET_NAT_AutoHandle
+{
+
+  /**
+   * Configuration we use.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+  
+  /**
+   * Message queue for communicating with the NAT service.
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Function called with the result from the autoconfiguration.
+   */
+  GNUNET_NAT_AutoResultCallback arc;
+
+  /**
+   * Closure for @e arc.
+   */
+  void *arc_cls;
+
+};
+
+
+/**
+ * Converts `enum GNUNET_NAT_StatusCode` to string
+ *
+ * @param err error code to resolve to a string
+ * @return point to a static string containing the error code
+ */
+const char *
+GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err)
+{
+  switch (err)
+  {
+  case GNUNET_NAT_ERROR_SUCCESS:
+    return _ ("Operation Successful");
+  case GNUNET_NAT_ERROR_IPC_FAILURE:
+    return _ ("IPC failure");
+  case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR:
+    return _ ("Failure in network subsystem, check permissions.");
+  case GNUNET_NAT_ERROR_TIMEOUT:
+    return _ ("Encountered timeout while performing operation");
+  case GNUNET_NAT_ERROR_NOT_ONLINE:
+    return _ ("detected that we are offline");
+  case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
+    return _ ("`upnpc` command not found");
+  case GNUNET_NAT_ERROR_UPNPC_FAILED:
+    return _ ("Failed to run `upnpc` command");
+  case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
+    return _ ("`upnpc' command took too long, process killed");
+  case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
+    return _ ("`upnpc' command failed to establish port mapping");
+  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
+    return _ ("`external-ip' command not found");
+  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
+    return _ ("Failed to run `external-ip` command");
+  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
+    return _ ("`external-ip' command output invalid");
+  case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
+    return _ ("no valid address was returned by `external-ip'");
+  case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO:
+    return _ ("Could not determine interface with internal/local network address");
+  case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND:
+    return _ ("No functioning gnunet-helper-nat-server installation found");
+  case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED:
+    return _ ("NAT test could not be initialized");
+  case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT:
+    return _ ("NAT test timeout reached");
+  case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED:
+    return _ ("could not register NAT");
+  case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND:
+    return _ ("No working gnunet-helper-nat-client installation found");
+  default:
+    return "unknown status code";
+  }
+}
+
+
+/**
+ * Check result from autoconfiguration attempt.
+ *
+ * @param cls the `struct GNUNET_NAT_AutoHandle`
+ * @param res the result
+ * @return #GNUNET_OK if @a res is well-formed (always for now)
+ */
+static int
+check_auto_result (void *cls,
+                  const struct GNUNET_NAT_AutoconfigResultMessage *res)
+{
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle result from autoconfiguration attempt.
+ *
+ * @param cls the `struct GNUNET_NAT_AutoHandle`
+ * @param res the result
+ */
+static void
+handle_auto_result (void *cls,
+                   const struct GNUNET_NAT_AutoconfigResultMessage *res)
+{
+  struct GNUNET_NAT_AutoHandle *ah = cls;
+  size_t left;
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+  enum GNUNET_NAT_Type type
+    = (enum GNUNET_NAT_Type) ntohl (res->type);
+  enum GNUNET_NAT_StatusCode status
+    = (enum GNUNET_NAT_StatusCode) ntohl (res->status_code);
+
+  left = ntohs (res->header.size) - sizeof (*res);
+  cfg = GNUNET_CONFIGURATION_create ();
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_deserialize (cfg,
+                                       (const char *) &res[1],
+                                       left,
+                                       GNUNET_NO))
+  {
+    GNUNET_break (0);
+    ah->arc (ah->arc_cls,
+            NULL,
+            GNUNET_NAT_ERROR_IPC_FAILURE,
+            type);
+  }
+  else
+  {
+    ah->arc (ah->arc_cls,
+            cfg,
+            status,
+            type);
+  }
+  GNUNET_CONFIGURATION_destroy (cfg);
+  GNUNET_NAT_autoconfig_cancel (ah);
+}
+
+
+/**
+ * Handle queue errors by reporting autoconfiguration failure.
+ *
+ * @param cls the `struct GNUNET_NAT_AutoHandle *`
+ * @param error details about the error
+ */
+static void
+ah_error_handler (void *cls,
+                 enum GNUNET_MQ_Error error)
+{
+  struct GNUNET_NAT_AutoHandle *ah = cls;
+
+  ah->arc (ah->arc_cls,
+          NULL,
+          GNUNET_NAT_ERROR_IPC_FAILURE,
+          GNUNET_NAT_TYPE_UNKNOWN);
+  GNUNET_NAT_autoconfig_cancel (ah);
+}
+
+
+/**
+ * Start auto-configuration routine.  The transport adapters should
+ * be stopped while this function is called.
+ *
+ * @param cfg initial configuration
+ * @param cb function to call with autoconfiguration result
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel operation
+ */
+struct GNUNET_NAT_AutoHandle *
+GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                            GNUNET_NAT_AutoResultCallback cb,
+                            void *cb_cls)
+{
+  struct GNUNET_NAT_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AutoHandle);
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (auto_result,
+                          GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT,
+                          struct GNUNET_NAT_AutoconfigResultMessage,
+                          ah),
+    GNUNET_MQ_handler_end ()
+  };
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_NAT_AutoconfigRequestMessage *req;
+  char *buf;
+  size_t size;
+
+  buf = GNUNET_CONFIGURATION_serialize (cfg,
+                                       &size);
+  if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req))
+  {
+    GNUNET_break (0);
+    GNUNET_free (buf);
+    GNUNET_free (ah);
+    return NULL;
+  }
+  ah->arc = cb;
+  ah->arc_cls = cb_cls;
+  ah->mq = GNUNET_CLIENT_connecT (cfg,
+                                 "nat",
+                                 handlers,
+                                 &ah_error_handler,
+                                 ah);
+  if (NULL == ah->mq)
+  {
+    GNUNET_break (0);
+    GNUNET_free (buf);
+    GNUNET_free (ah);
+    return NULL;
+  }
+  env = GNUNET_MQ_msg_extra (req,
+                            size,
+                            GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG);
+  GNUNET_memcpy (&req[1],
+                buf,
+                size);
+  GNUNET_free (buf);
+  GNUNET_MQ_send (ah->mq,
+                 env);
+  return ah;
+}
+
+
+/**
+ * Abort autoconfiguration.
+ *
+ * @param ah handle for operation to abort
+ */
+void
+GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah)
+{
+  GNUNET_MQ_destroy (ah->mq);
+  GNUNET_free (ah);
+}
+
+/* end of nat_api_auto.c */
diff --git a/src/nat-auto/nat_auto_api_test.c b/src/nat-auto/nat_auto_api_test.c
new file mode 100644 (file)
index 0000000..056d2a2
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 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/nat_auto_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
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_nat_lib.h"
+#include "nat-auto.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
+
+#define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+
+/**
+ * Entry we keep for each incoming connection.
+ */
+struct NatActivity
+{
+  /**
+   * This is a doubly-linked list.
+   */
+  struct NatActivity *next;
+
+  /**
+   * This is a doubly-linked list.
+   */
+  struct NatActivity *prev;
+
+  /**
+   * Socket of the incoming connection.
+   */
+  struct GNUNET_NETWORK_Handle *sock;
+
+  /**
+   * Handle of the master context.
+   */
+  struct GNUNET_NAT_Test *h;
+
+  /**
+   * Task reading from the incoming connection.
+   */
+  struct GNUNET_SCHEDULER_Task *rtask;
+};
+
+
+/**
+ * Entry we keep for each connection to the gnunet-nat-service.
+ */
+struct ClientActivity
+{
+  /**
+   * This is a doubly-linked list.
+   */
+  struct ClientActivity *next;
+
+  /**
+   * This is a doubly-linked list.
+   */
+  struct ClientActivity *prev;
+
+  /**
+   * Socket of the incoming connection.
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Handle to overall NAT test.
+   */
+  struct GNUNET_NAT_Test *h;
+
+};
+
+
+/**
+ * Handle to a NAT test.
+ */
+struct GNUNET_NAT_Test
+{
+
+  /**
+   * Configuration used
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Function to call with success report
+   */
+  GNUNET_NAT_TestCallback report;
+
+  /**
+   * Closure for @e report.
+   */
+  void *report_cls;
+
+  /**
+   * Handle to NAT traversal in use
+   */
+  struct GNUNET_NAT_Handle *nat;
+
+  /**
+   * Handle to listen socket, or NULL
+   */
+  struct GNUNET_NETWORK_Handle *lsock;
+
+  /**
+   * Head of list of nat activities.
+   */
+  struct NatActivity *na_head;
+
+  /**
+   * Tail of list of nat activities.
+   */
+  struct NatActivity *na_tail;
+
+  /**
+   * Head of list of client activities.
+   */
+  struct ClientActivity *ca_head;
+
+  /**
+   * Tail of list of client activities.
+   */
+  struct ClientActivity *ca_tail;
+
+  /**
+   * Identity of task for the listen socket (if any)
+   */
+  struct GNUNET_SCHEDULER_Task *ltask;
+
+  /**
+   * Task identifier for the timeout (if any)
+   */
+  struct GNUNET_SCHEDULER_Task *ttask;
+
+  /**
+   * #GNUNET_YES if we're testing TCP
+   */
+  int is_tcp;
+
+  /**
+   * Data that should be transmitted or source-port.
+   */
+  uint16_t data;
+
+  /**
+   * Advertised port to the other peer.
+   */
+  uint16_t adv_port;
+
+  /**
+   * Status code to be reported to the timeout/status call
+   */
+  enum GNUNET_NAT_StatusCode status;
+};
+
+
+/**
+ * Function called from #GNUNET_NAT_register whenever someone asks us
+ * to do connection reversal.
+ *
+ * @param cls closure, our `struct GNUNET_NAT_Handle`
+ * @param addr public IP address of the other peer
+ * @param addrlen actual lenght of the @a addr
+ */
+static void
+reversal_cb (void *cls,
+             const struct sockaddr *addr,
+             socklen_t addrlen)
+{
+  struct GNUNET_NAT_Test *h = cls;
+  const struct sockaddr_in *sa;
+
+  if (sizeof (struct sockaddr_in) != addrlen)
+    return;
+  sa = (const struct sockaddr_in *) addr;
+  if (h->data != sa->sin_port)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received connection reversal request for wrong port\n");
+    return;                     /* wrong port */
+  }
+  /* report success */
+  h->report (h->report_cls,
+             GNUNET_NAT_ERROR_SUCCESS);
+}
+
+
+/**
+ * Activity on our incoming socket.  Read data from the
+ * incoming connection.
+ *
+ * @param cls the `struct GNUNET_NAT_Test`
+ */
+static void
+do_udp_read (void *cls)
+{
+  struct GNUNET_NAT_Test *tst = cls;
+  uint16_t data;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
+
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  tst->ltask =
+      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                     tst->lsock,
+                                     &do_udp_read,
+                                     tst);
+  if ((NULL != tc->write_ready) &&
+      (GNUNET_NETWORK_fdset_isset (tc->read_ready,
+                                   tst->lsock)) &&
+      (sizeof (data) ==
+       GNUNET_NETWORK_socket_recv (tst->lsock,
+                                   &data,
+                                   sizeof (data))))
+  {
+    if (data == tst->data)
+      tst->report (tst->report_cls,
+                   GNUNET_NAT_ERROR_SUCCESS);
+    else
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Received data mismatches expected value\n");
+  }
+  else
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to receive data from inbound connection\n");
+}
+
+
+/**
+ * Activity on our incoming socket.  Read data from the
+ * incoming connection.
+ *
+ * @param cls the `struct NatActivity`
+ */
+static void
+do_read (void *cls)
+{
+  struct NatActivity *na = cls;
+  struct GNUNET_NAT_Test *tst;
+  uint16_t data;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
+
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  na->rtask = NULL;
+  tst = na->h;
+  GNUNET_CONTAINER_DLL_remove (tst->na_head,
+                              tst->na_tail,
+                              na);
+  if ((NULL != tc->write_ready) &&
+      (GNUNET_NETWORK_fdset_isset (tc->read_ready,
+                                   na->sock)) &&
+      (sizeof (data) ==
+       GNUNET_NETWORK_socket_recv (na->sock,
+                                   &data,
+                                   sizeof (data))))
+  {
+    if (data == tst->data)
+      tst->report (tst->report_cls,
+                   GNUNET_NAT_ERROR_SUCCESS);
+    else
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Received data does not match expected value\n");
+  }
+  else
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to receive data from inbound connection\n");
+  GNUNET_NETWORK_socket_close (na->sock);
+  GNUNET_free (na);
+}
+
+
+/**
+ * Activity on our listen socket. Accept the
+ * incoming connection.
+ *
+ * @param cls the `struct GNUNET_NAT_Test`
+ */
+static void
+do_accept (void *cls)
+{
+  struct GNUNET_NAT_Test *tst = cls;
+  struct GNUNET_NETWORK_Handle *s;
+  struct NatActivity *wl;
+
+  tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                              tst->lsock,
+                                              &do_accept,
+                                              tst);
+  s = GNUNET_NETWORK_socket_accept (tst->lsock,
+                                    NULL,
+                                    NULL);
+  if (NULL == s)
+  {
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
+                         "accept");
+    return;                     /* odd error */
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got an inbound connection, waiting for data\n");
+  wl = GNUNET_new (struct NatActivity);
+  wl->sock = s;
+  wl->h = tst;
+  wl->rtask =
+    GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                   wl->sock,
+                                   &do_read,
+                                   wl);
+  GNUNET_CONTAINER_DLL_insert (tst->na_head,
+                              tst->na_tail,
+                              wl);
+}
+
+
+/**
+ * We got disconnected from the NAT server.  Stop
+ * waiting for a reply.
+ *
+ * @param cls the `struct ClientActivity`
+ * @param error error code
+ */
+static void
+mq_error_handler (void *cls,
+                  enum GNUNET_MQ_Error error)
+{
+  struct ClientActivity *ca = cls;
+  struct GNUNET_NAT_Test *tst = ca->h;
+
+  GNUNET_CONTAINER_DLL_remove (tst->ca_head,
+                               tst->ca_tail,
+                               ca);
+  GNUNET_MQ_destroy (ca->mq);
+  GNUNET_free (ca);
+}
+
+
+/**
+ * Address-callback, used to send message to gnunet-nat-server.
+ *
+ * @param cls closure
+ * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
+ *     the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual length of the @a addr
+ */
+static void
+addr_cb (void *cls,
+         int add_remove,
+         const struct sockaddr *addr,
+         socklen_t addrlen)
+{
+  struct GNUNET_NAT_Test *h = cls;
+  struct ClientActivity *ca;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_NAT_TestMessage *msg;
+  const struct sockaddr_in *sa;
+
+  if (GNUNET_YES != add_remove)
+    return;
+  if (addrlen != sizeof (struct sockaddr_in))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "NAT test ignores IPv6 address `%s' returned from NAT library\n",
+        GNUNET_a2s (addr,
+                     addrlen));
+    return;                     /* ignore IPv6 here */
+  }
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Asking gnunet-nat-server to connect to `%s'\n",
+       GNUNET_a2s (addr,
+                   addrlen));
+
+  ca = GNUNET_new (struct ClientActivity);
+  ca->h = h;
+  ca->mq = GNUNET_CLIENT_connecT (h->cfg,
+                                  "gnunet-nat-server",
+                                  NULL,
+                                  &mq_error_handler,
+                                  ca);
+  if (NULL == ca->mq)
+  {
+    GNUNET_free (ca);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Failed to connect to `gnunet-nat-server'\n"));
+    return;
+  }
+  GNUNET_CONTAINER_DLL_insert (h->ca_head,
+                               h->ca_tail,
+                               ca);
+  sa = (const struct sockaddr_in *) addr;
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_NAT_TEST);
+  msg->dst_ipv4 = sa->sin_addr.s_addr;
+  msg->dport = sa->sin_port;
+  msg->data = h->data;
+  msg->is_tcp = htonl ((uint32_t) h->is_tcp);
+  GNUNET_MQ_send (ca->mq,
+                  env);
+}
+
+
+/**
+ * Timeout task for a nat test.
+ * Calls the report-callback with a timeout return value
+ *
+ * Destroys the nat handle after the callback has been processed.
+ *
+ * @param cls handle to the timed out NAT test
+ */
+static void
+do_timeout (void *cls)
+{
+  struct GNUNET_NAT_Test *nh = cls;
+
+  nh->ttask = NULL;
+  nh->report (nh->report_cls,
+              (GNUNET_NAT_ERROR_SUCCESS == nh->status)
+              ? GNUNET_NAT_ERROR_TIMEOUT
+              : nh->status);
+}
+
+
+/**
+ * Start testing if NAT traversal works using the
+ * given configuration (IPv4-only).
+ *
+ * ALL failures are reported directly to the report callback
+ *
+ * @param cfg configuration for the NAT traversal
+ * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP
+ * @param bnd_port port to bind to, 0 for connection reversal
+ * @param adv_port externally advertised port to use
+ * @param timeout delay after which the test should be aborted
+ * @param report function to call with the result of the test
+ * @param report_cls closure for @a report
+ * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback
+ */
+struct GNUNET_NAT_Test *
+GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                       int is_tcp,
+                       uint16_t bnd_port,
+                       uint16_t adv_port,
+                       struct GNUNET_TIME_Relative timeout,
+                       GNUNET_NAT_TestCallback report,
+                       void *report_cls)
+{
+  struct GNUNET_NAT_Test *nh;
+  struct sockaddr_in sa;
+  const struct sockaddr *addrs[] = {
+    (const struct sockaddr *) &sa
+  };
+  const socklen_t addrlens[] = {
+    sizeof (sa)
+  };
+
+  memset (&sa, 0, sizeof (sa));
+  sa.sin_family = AF_INET;
+  sa.sin_port = htons (bnd_port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+
+  nh = GNUNET_new (struct GNUNET_NAT_Test);
+  nh->cfg = cfg;
+  nh->is_tcp = is_tcp;
+  nh->data = bnd_port;
+  nh->adv_port = adv_port;
+  nh->report = report;
+  nh->report_cls = report_cls;
+  nh->status = GNUNET_NAT_ERROR_SUCCESS;
+  if (0 == bnd_port)
+  {
+    nh->nat
+      = GNUNET_NAT_register (cfg,
+                             is_tcp,
+                             0,
+                             0,
+                            NULL,
+                             NULL,
+                            &addr_cb,
+                             &reversal_cb,
+                             nh,
+                             NULL);
+  }
+  else
+  {
+    nh->lsock =
+        GNUNET_NETWORK_socket_create (AF_INET,
+                                      (is_tcp ==
+                                       GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM,
+                                      0);
+    if ((nh->lsock == NULL) ||
+        (GNUNET_OK !=
+         GNUNET_NETWORK_socket_bind (nh->lsock,
+                                     (const struct sockaddr *) &sa,
+                                     sizeof (sa))))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  _("Failed to create listen socket bound to `%s' for NAT test: %s\n"),
+                  GNUNET_a2s ((const struct sockaddr *) &sa,
+                              sizeof (sa)),
+                  STRERROR (errno));
+      if (NULL != nh->lsock)
+      {
+        GNUNET_NETWORK_socket_close (nh->lsock);
+        nh->lsock = NULL;
+      }
+      nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR;
+      nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
+                                            nh);
+      return nh;
+    }
+    if (GNUNET_YES == is_tcp)
+    {
+      GNUNET_break (GNUNET_OK ==
+                    GNUNET_NETWORK_socket_listen (nh->lsock,
+                                                  5));
+      nh->ltask =
+          GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                         nh->lsock,
+                                        &do_accept,
+                                         nh);
+    }
+    else
+    {
+      nh->ltask =
+          GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                         nh->lsock,
+                                        &do_udp_read,
+                                         nh);
+    }
+    LOG (GNUNET_ERROR_TYPE_INFO,
+        "NAT test listens on port %u (%s)\n",
+        bnd_port,
+        (GNUNET_YES == is_tcp) ? "tcp" : "udp");
+    nh->nat = GNUNET_NAT_register (cfg,
+                                   is_tcp,
+                                   adv_port,
+                                   1,
+                                   addrs,
+                                   addrlens,
+                                   &addr_cb,
+                                   NULL,
+                                   nh,
+                                   NULL);
+    if (NULL == nh->nat)
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO,
+          _("NAT test failed to start NAT library\n"));
+      if (NULL != nh->ltask)
+      {
+        GNUNET_SCHEDULER_cancel (nh->ltask);
+        nh->ltask = NULL;
+      }
+      if (NULL != nh->lsock)
+      {
+        GNUNET_NETWORK_socket_close (nh->lsock);
+        nh->lsock = NULL;
+      }
+      nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED;
+      nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
+                                            nh);
+      return nh;
+    }
+  }
+  nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout,
+                                           &do_timeout,
+                                           nh);
+  return nh;
+}
+
+
+/**
+ * Stop an active NAT test.
+ *
+ * @param tst test to stop.
+ */
+void
+GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
+{
+  struct NatActivity *pos;
+  struct ClientActivity *cpos;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Stopping NAT test\n");
+  while (NULL != (cpos = tst->ca_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (tst->ca_head,
+                                tst->ca_tail,
+                                cpos);
+    GNUNET_MQ_destroy (cpos->mq);
+    GNUNET_free (cpos);
+  }
+  while (NULL != (pos = tst->na_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (tst->na_head,
+                                tst->na_tail,
+                                pos);
+    GNUNET_SCHEDULER_cancel (pos->rtask);
+    GNUNET_NETWORK_socket_close (pos->sock);
+    GNUNET_free (pos);
+  }
+  if (NULL != tst->ttask)
+  {
+    GNUNET_SCHEDULER_cancel (tst->ttask);
+    tst->ttask = NULL;
+  }
+  if (NULL != tst->ltask)
+  {
+    GNUNET_SCHEDULER_cancel (tst->ltask);
+    tst->ltask = NULL;
+  }
+  if (NULL != tst->lsock)
+  {
+    GNUNET_NETWORK_socket_close (tst->lsock);
+    tst->lsock = NULL;
+  }
+  if (NULL != tst->nat)
+  {
+    GNUNET_NAT_unregister (tst->nat);
+    tst->nat = NULL;
+  }
+  GNUNET_free (tst);
+}
+
+/* end of nat_test.c */
index b2b9c4f50e0078df27b851f7b20d0b99ea67daa0..456ddfb62cf6f82b9ac2b26186ec64aa2e7535e1 100644 (file)
@@ -34,7 +34,6 @@ install-exec-hook:
 endif
 
 bin_PROGRAMS = \
- gnunet-nat-server \
  gnunet-nat
 
 libexec_PROGRAMS = \
@@ -42,12 +41,6 @@ libexec_PROGRAMS = \
  gnunet-service-nat
 
 
-gnunet_nat_server_SOURCES = \
- gnunet-nat-server.c nat.h
-gnunet_nat_server_LDADD = \
-  libgnunetnat.la \
-  $(top_builddir)/src/util/libgnunetutil.la
-
 gnunet_helper_nat_server_SOURCES = \
  $(NATSERVER)
 
@@ -85,9 +78,7 @@ libgnunetnat_la_LDFLAGS = \
 
 libgnunetnatnew_la_SOURCES = \
   nat_api.c \
-  nat_api_auto.c \
   nat_api_stun.c nat_stun.h \
-  nat_api_test.c \
   nat.h
 libgnunetnatnew_la_LIBADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
diff --git a/src/nat/gnunet-nat-server.c b/src/nat/gnunet-nat-server.c
deleted file mode 100644 (file)
index 1692a8e..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011 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 src/nat/gnunet-nat-server.c
- * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_nat_lib.h"
-#include "gnunet_protocols.h"
-#include "nat.h"
-
-
-/**
- * Our server.
- */
-static struct GNUNET_SERVER_Handle *server;
-
-/**
- * Our configuration.
- */
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-/**
- * Try contacting the peer using autonomous NAT traveral method.
- *
- * @param dst_ipv4 IPv4 address to send the fake ICMP message
- * @param dport destination port to include in ICMP message
- * @param is_tcp mark for TCP (#GNUNET_YES)  or UDP (#GNUNET_NO)
- */
-static void
-try_anat (uint32_t dst_ipv4,
-          uint16_t dport,
-          int is_tcp)
-{
-  struct GNUNET_NAT_Handle *h;
-  struct sockaddr_in sa;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Asking for connection reversal with %x and code %u\n",
-              (unsigned int) dst_ipv4,
-              (unsigned int) dport);
-  h = GNUNET_NAT_register (cfg,
-                           is_tcp,
-                           dport,
-                           0,
-                           NULL, NULL, NULL, NULL, NULL, NULL);
-  memset (&sa, 0, sizeof (sa));
-  sa.sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_addr.s_addr = dst_ipv4;
-  GNUNET_NAT_run_client (h, &sa);
-  GNUNET_NAT_unregister (h);
-}
-
-
-/**
- * Closure for #tcp_send.
- */
-struct TcpContext
-{
-  /**
-   * TCP  socket.
-   */
-  struct GNUNET_NETWORK_Handle *s;
-
-  /**
-   * Data to transmit.
-   */
-  uint16_t data;
-};
-
-
-/**
- * Task called by the scheduler once we can do the TCP send
- * (or once we failed to connect...).
- *
- * @param cls the `struct TcpContext`
- */
-static void
-tcp_send (void *cls)
-{
-  struct TcpContext *ctx = cls;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
-
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  if ((NULL != tc->write_ready) &&
-      (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s)))
-  {
-    if (-1 ==
-        GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data)))
-    {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
-    }
-    GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR);
-  }
-  GNUNET_NETWORK_socket_close (ctx->s);
-  GNUNET_free (ctx);
-}
-
-
-/**
- * Try to send @a data to the
- * IP @a dst_ipv4' at port @a dport via TCP.
- *
- * @param dst_ipv4 target IP
- * @param dport target port
- * @param data data to send
- */
-static void
-try_send_tcp (uint32_t dst_ipv4,
-              uint16_t dport,
-              uint16_t data)
-{
-  struct GNUNET_NETWORK_Handle *s;
-  struct sockaddr_in sa;
-  struct TcpContext *ctx;
-
-  s = GNUNET_NETWORK_socket_create (AF_INET,
-                                    SOCK_STREAM,
-                                    0);
-  if (NULL == s)
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
-                         "socket");
-    return;
-  }
-  memset (&sa, 0, sizeof (sa));
-  sa.sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_addr.s_addr = dst_ipv4;
-  sa.sin_port = htons (dport);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending TCP message to `%s'\n",
-              GNUNET_a2s ((struct sockaddr *) &sa,
-                          sizeof (sa)));
-  if ( (GNUNET_OK !=
-        GNUNET_NETWORK_socket_connect (s,
-                                       (const struct sockaddr *) &sa,
-                                       sizeof (sa))) &&
-       (errno != EINPROGRESS) )
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
-                         "connect");
-    GNUNET_NETWORK_socket_close (s);
-    return;
-  }
-  ctx = GNUNET_new (struct TcpContext);
-  ctx->s = s;
-  ctx->data = data;
-  GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS,
-                                  s,
-                                  &tcp_send,
-                                  ctx);
-}
-
-
-/**
- * Try to send @a data to the
- * IP @a dst_ipv4 at port @a dport via UDP.
- *
- * @param dst_ipv4 target IP
- * @param dport target port
- * @param data data to send
- */
-static void
-try_send_udp (uint32_t dst_ipv4,
-              uint16_t dport,
-              uint16_t data)
-{
-  struct GNUNET_NETWORK_Handle *s;
-  struct sockaddr_in sa;
-
-  s = GNUNET_NETWORK_socket_create (AF_INET,
-                                    SOCK_DGRAM,
-                                    0);
-  if (NULL == s)
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
-                         "socket");
-    return;
-  }
-  memset (&sa, 0, sizeof (sa));
-  sa.sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_addr.s_addr = dst_ipv4;
-  sa.sin_port = htons (dport);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending UDP packet to `%s'\n",
-              GNUNET_a2s ((struct sockaddr *) &sa,
-                          sizeof (sa)));
-  if (-1 ==
-      GNUNET_NETWORK_socket_sendto (s,
-                                    &data,
-                                    sizeof (data),
-                                    (const struct sockaddr *) &sa,
-                                    sizeof (sa)))
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
-                         "sendto");
-  GNUNET_NETWORK_socket_close (s);
-}
-
-
-/**
- * We've received a request to probe a NAT
- * traversal. Do it.
- *
- * @param cls unused
- * @param client handle to client (we always close)
- * @param msg message with details about what to test
- */
-static void
-test (void *cls,
-      struct GNUNET_SERVER_Client *client,
-      const struct GNUNET_MessageHeader *msg)
-{
-  const struct GNUNET_NAT_TestMessage *tm;
-  uint16_t dport;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received test request\n");
-  tm = (const struct GNUNET_NAT_TestMessage *) msg;
-  dport = ntohs (tm->dport);
-  if (0 == dport)
-    try_anat (tm->dst_ipv4,
-              ntohs (tm->data),
-              (int) ntohl (tm->is_tcp));
-  else if (GNUNET_YES == ntohl (tm->is_tcp))
-    try_send_tcp (tm->dst_ipv4,
-                  dport,
-                  tm->data);
-  else
-    try_send_udp (tm->dst_ipv4,
-                  dport,
-                  tm->data);
-  GNUNET_SERVER_receive_done (client,
-                              GNUNET_NO);
-}
-
-
-/**
- * Task run during shutdown.
- *
- * @param cls unused
- */
-static void
-shutdown_task (void *cls)
-{
-  GNUNET_SERVER_destroy (server);
-  server = NULL;
-}
-
-
-/**
- * Main function that will be run.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
- */
-static void
-run (void *cls,
-     char *const *args,
-     const char *cfgfile,
-     const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
-    {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
-     sizeof (struct GNUNET_NAT_TestMessage)},
-    {NULL, NULL, 0, 0}
-  };
-  unsigned int port;
-  struct sockaddr_in in4;
-  struct sockaddr_in6 in6;
-
-  socklen_t slen[] = {
-    sizeof (in4),
-    sizeof (in6),
-    0
-  };
-  struct sockaddr *sa[] = {
-    (struct sockaddr *) &in4,
-    (struct sockaddr *) &in6,
-    NULL
-  };
-
-  cfg = c;
-  if ( (NULL == args[0]) ||
-       (1 != SSCANF (args[0], "%u", &port)) ||
-       (0 == port) ||
-       (65536 <= port) )
-  {
-    FPRINTF (stderr,
-             _("Please pass valid port number as the first argument! (got `%s')\n"),
-             args[0]);
-    return;
-  }
-  memset (&in4, 0, sizeof (in4));
-  memset (&in6, 0, sizeof (in6));
-  in4.sin_family = AF_INET;
-  in4.sin_port = htons ((uint16_t) port);
-  in6.sin6_family = AF_INET6;
-  in6.sin6_port = htons ((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  in4.sin_len = sizeof (in4);
-  in6.sin6_len = sizeof (in6);
-#endif
-  server = GNUNET_SERVER_create (NULL,
-                                NULL,
-                                (struct sockaddr * const *) sa,
-                                slen,
-                                GNUNET_TIME_UNIT_SECONDS,
-                                GNUNET_YES);
-  GNUNET_SERVER_add_handlers (server,
-                             handlers);
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
-                                NULL);
-}
-
-
-/**
- * Main function of gnunet-nat-server.
- *
- * @param argc number of command-line arguments
- * @param argv command line
- * @return 0 on success, -1 on error
- */
-int
-main (int argc, char *const argv[])
-{
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    GNUNET_GETOPT_OPTION_END
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_STRINGS_get_utf8_args (argc, argv,
-                                   &argc, &argv))
-    return 2;
-
-  if (GNUNET_OK !=
-      GNUNET_PROGRAM_run (argc,
-                         argv,
-                         "gnunet-nat-server [options] PORT",
-                          _("GNUnet NAT traversal test helper daemon"),
-                         options,
-                          &run,
-                         NULL))
-  {
-    GNUNET_free ((void*) argv);
-    return 1;
-  }
-  GNUNET_free ((void*) argv);
-  return 0;
-}
-
-
-/* end of gnunet-nat-server.c */
index 4171babf941347db90378806e72d674143f70f41..02d68d787e071ed5c7cc671be5b4a54e192e0779 100644 (file)
  */
 static int global_ret;
 
-/**
- * Handle to ongoing autoconfiguration.
- */
-static struct GNUNET_NAT_AutoHandle *ah;
-
 /**
  * Name of section in configuration file to use for 
  * additional options.
@@ -59,39 +54,11 @@ static int listen_reversal;
  */
 static int use_tcp;
 
-/**
- * If we do auto-configuration, should we write the result
- * to a file?
- */
-static int write_cfg;
-
-/**
- * Configuration filename.
- */ 
-static const char *cfg_file;
-
-/**
- * Original configuration.
- */
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
-
 /**
  * Protocol to use.
  */
 static uint8_t proto;
 
-/**
- * Address we are bound to (in test), or should bind to
- * (if #do_stun is set).
- */
-static char *bind_addr;
-
-/**
- * External IP address and port to use for the test.
- * If not set, use #bind_addr.
- */
-static char *extern_addr;
-
 /**
  * Local address to use for connection reversal request.
  */
@@ -107,16 +74,6 @@ static char *remote_addr;
  */
 static unsigned int do_stun;
 
-/**
- * Should we run autoconfiguration?
- */
-static unsigned int do_auto;
-
-/**
- * Handle to a NAT test operation.
- */
-static struct GNUNET_NAT_Test *nt;
-
 /**
  * Handle to NAT operation.
  */
@@ -140,10 +97,6 @@ static struct GNUNET_SCHEDULER_Task *rtask;
 static void
 test_finished ()
 {
-  if (NULL != ah)
-    return;
-  if (NULL != nt)
-    return;
   if (NULL != nh)
     return;
   if (NULL != rtask)
@@ -152,160 +105,6 @@ test_finished ()
 }
 
 
-/**
- * Function to iterate over sugested changes options
- *
- * @param cls closure
- * @param section name of the section
- * @param option name of the option
- * @param value value of the option
- */
-static void
-auto_conf_iter (void *cls,
-                const char *section,
-                const char *option,
-                const char *value)
-{
-  struct GNUNET_CONFIGURATION_Handle *new_cfg = cls;
-  
-  PRINTF ("%s: %s\n",
-         option,
-         value);
-  if (NULL != new_cfg)
-    GNUNET_CONFIGURATION_set_value_string (new_cfg,
-                                          section,
-                                          option,
-                                          value);
-}
-
-
-/**
- * Function called with the result from the autoconfiguration.
- *
- * @param cls closure
- * @param diff minimal suggested changes to the original configuration
- *             to make it work (as best as we can)
- * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
- * @param type what the situation of the NAT
- */
-static void
-auto_config_cb (void *cls,
-               const struct GNUNET_CONFIGURATION_Handle *diff,
-               enum GNUNET_NAT_StatusCode result,
-               enum GNUNET_NAT_Type type)
-{
-  const char *nat_type;
-  char unknown_type[64];
-  struct GNUNET_CONFIGURATION_Handle *new_cfg;
-
-  ah = NULL;
-  switch (type)
-  {
-  case GNUNET_NAT_TYPE_NO_NAT:
-    nat_type = "NO NAT";
-    break;
-  case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
-    nat_type = "NAT but we can traverse";
-    break;
-  case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
-    nat_type = "NAT but STUN is able to identify the correct information";
-    break;
-  case GNUNET_NAT_TYPE_UPNP_NAT:
-    nat_type = "NAT but UPNP opened the ports";
-    break;
-  default:
-    SPRINTF (unknown_type,
-            "NAT unknown, type %u",
-            type);
-    nat_type = unknown_type;
-    break;
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-             "NAT status: %s/%s\n",
-             GNUNET_NAT_status2string (result),
-             nat_type);
-
-  /* Shortcut: if there are no changes suggested, bail out early. */
-  if (GNUNET_NO ==
-      GNUNET_CONFIGURATION_is_dirty (diff))
-  {
-    test_finished ();
-    return;
-  }
-
-  /* Apply diff to original configuration and show changes
-     to the user */
-  new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
-  
-  if (NULL != diff)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-               _("Suggested configuration changes:\n"));
-    GNUNET_CONFIGURATION_iterate_section_values (diff,
-                                                "nat",
-                                                &auto_conf_iter,
-                                                new_cfg);
-  }
-
-  /* If desired, write configuration to file; we write only the
-     changes to the defaults to keep things compact. */
-  if ( (write_cfg) &&
-       (NULL != diff) )
-  {
-    struct GNUNET_CONFIGURATION_Handle *def_cfg;
-
-    GNUNET_CONFIGURATION_set_value_string (new_cfg,
-                                          "ARM",
-                                          "CONFIG",
-                                          NULL);
-    def_cfg = GNUNET_CONFIGURATION_create ();
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_CONFIGURATION_load (def_cfg,
-                                            NULL));
-    if (GNUNET_OK !=
-       GNUNET_CONFIGURATION_write_diffs (def_cfg,
-                                         new_cfg,
-                                         cfg_file))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-                 _("Failed to write configuration to `%s'\n"),
-                 cfg_file);
-      global_ret = 1;
-    }
-    else
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-                 _("Wrote updated configuration to `%s'\n"),
-                 cfg_file);
-    }
-    GNUNET_CONFIGURATION_destroy (def_cfg);
-  }
-
-  if (NULL != new_cfg)
-    GNUNET_CONFIGURATION_destroy (new_cfg);
-  test_finished ();
-}
-
-
-/**
- * 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.
@@ -362,16 +161,6 @@ reversal_cb (void *cls,
 static void
 do_shutdown (void *cls)
 {
-  if (NULL != ah)
-  {
-    GNUNET_NAT_autoconfig_cancel (ah);
-    ah = NULL;
-  }
-  if (NULL != nt)
-  {
-    GNUNET_NAT_test_stop (nt);
-    nt = NULL;
-  }
   if (NULL != nh)
   {
     GNUNET_NAT_unregister (nh);
@@ -452,16 +241,11 @@ run (void *cls,
      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;
   socklen_t local_len;
   size_t remote_len;
 
-  cfg_file = cfgfile;
-  cfg = c;
-  
   if (use_tcp && use_udp)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
@@ -478,50 +262,13 @@ run (void *cls,
   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
                                 NULL);
 
-  if (do_auto)
-  {
-    ah = GNUNET_NAT_autoconfig_start (c,
-                                     &auto_config_cb,
-                                     NULL);
-  }
-
   if (0 == proto)
   {
-    if (do_auto)
-      return; /* all good, we just run auto config */
     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
                "Must specify either TCP or UDP\n");
     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 = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr,
@@ -551,20 +298,6 @@ run (void *cls,
     }
   }
 
-  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,
@@ -683,15 +416,6 @@ main (int argc,
       char *const argv[])
 {
   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "auto", NULL,
-     gettext_noop ("run autoconfiguration"),
-     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 },
-    {'e', "external", "ADDRESS",
-     gettext_noop ("which external IP and port should be used to test"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr },
     {'i', "in", "ADDRESS",
      gettext_noop ("which IP and port are we locally using to bind/listen to"),
      GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr },
@@ -710,9 +434,6 @@ main (int argc,
     {'u', "udp", NULL,
      gettext_noop ("use UDP"),
      GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
-    {'w', "write", NULL,
-     gettext_noop ("write configuration file (for autoconfiguration)"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg },
     {'W', "watch", NULL,
      gettext_noop ("watch for connection reversal requests"),
      GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal },
index 79f806f271417bb2a22b58d82ccd07530deaaa00..2cb2b30ffd578d91756d4826465cb2bd94d7fcce 100644 (file)
@@ -283,80 +283,6 @@ struct StunExternalIP
 };
 
 
-/**
- * Context for autoconfiguration operations.
- */
-struct AutoconfigContext
-{
-  /**
-   * Kept in a DLL.
-   */
-  struct AutoconfigContext *prev;
-
-  /**
-   * Kept in a DLL.
-   */
-  struct AutoconfigContext *next;
-
-  /**
-   * Which client asked the question.
-   */
-  struct ClientHandle *ch;
-
-  /**
-   * Configuration we are creating.
-   */ 
-  struct GNUNET_CONFIGURATION_Handle *c;
-
-  /**
-   * Original configuration (for diffing).
-   */ 
-  struct GNUNET_CONFIGURATION_Handle *orig;
-
-  /**
-   * Timeout task to force termination.
-   */
-  struct GNUNET_SCHEDULER_Task *timeout_task;
-
-  /**
-   * What type of system are we on?
-   */
-  char *system_type;
-
-  /**
-   * Handle to activity to probe for our external IP.
-   */
-  struct GNUNET_NAT_ExternalHandle *probe_external;
-
-  /**
-   * #GNUNET_YES if upnpc should be used,
-   * #GNUNET_NO if upnpc should not be used,
-   * #GNUNET_SYSERR if we should simply not change the option.
-   */
-  int enable_upnpc;
-
-  /**
-   * Status code to return to the client.
-   */
-  enum GNUNET_NAT_StatusCode status_code;
-
-  /**
-   * NAT type to return to the client.
-   */
-  enum GNUNET_NAT_Type type;
-};
-
-
-/**
- * DLL of our autoconfiguration operations.
- */
-static struct AutoconfigContext *ac_head;
-
-/**
- * DLL of our autoconfiguration operations.
- */
-static struct AutoconfigContext *ac_tail;
-
 /**
  * Timeout to use when STUN data is considered stale.
  */
@@ -1919,274 +1845,6 @@ handle_request_connection_reversal (void *cls,
 }
 
 
-/**
- * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
- * from client.
- *
- * @param cls client who sent the message
- * @param message the message received
- * @return #GNUNET_OK if message is well-formed
- */
-static int
-check_autoconfig_request (void *cls,
-                         const struct GNUNET_NAT_AutoconfigRequestMessage *message)
-{
-  return GNUNET_OK;  /* checked later */
-}
-
-
-/**
- * Stop all pending activities with respect to the @a ac
- *
- * @param ac autoconfiguration to terminate activities for
- */
-static void
-terminate_ac_activities (struct AutoconfigContext *ac)
-{
-  if (NULL != ac->probe_external)
-  {
-    GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
-    ac->probe_external = NULL;
-  }
-  if (NULL != ac->timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (ac->timeout_task);
-    ac->timeout_task = NULL;
-  }
-}
-
-
-/**
- * Finish handling the autoconfiguration request and send
- * the response to the client.
- *
- * @param cls the `struct AutoconfigContext` to conclude
- */
-static void
-conclude_autoconfig_request (void *cls)
-{
-  struct AutoconfigContext *ac = cls;
-  struct ClientHandle *ch = ac->ch;
-  struct GNUNET_NAT_AutoconfigResultMessage *arm;
-  struct GNUNET_MQ_Envelope *env;
-  size_t c_size;
-  char *buf;
-  struct GNUNET_CONFIGURATION_Handle *diff;
-  
-  ac->timeout_task = NULL;
-  terminate_ac_activities (ac);
-
-  /* Send back response */
-  diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
-                                       ac->c);
-  buf = GNUNET_CONFIGURATION_serialize (diff,
-                                       &c_size);
-  GNUNET_CONFIGURATION_destroy (diff);
-  env = GNUNET_MQ_msg_extra (arm,
-                            c_size,
-                            GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
-  arm->status_code = htonl ((uint32_t) ac->status_code);
-  arm->type = htonl ((uint32_t) ac->type);
-  GNUNET_memcpy (&arm[1],
-                buf,
-                c_size);
-  GNUNET_free (buf);
-  GNUNET_MQ_send (ch->mq,
-                 env);
-
-  /* clean up */
-  GNUNET_free (ac->system_type);
-  GNUNET_CONFIGURATION_destroy (ac->orig);
-  GNUNET_CONFIGURATION_destroy (ac->c);
-  GNUNET_CONTAINER_DLL_remove (ac_head,
-                              ac_tail,
-                              ac);
-  GNUNET_free (ac);
-  GNUNET_SERVICE_client_continue (ch->client);
-}
-
-
-/**
- * Check if all autoconfiguration operations have concluded,
- * and if they have, send the result back to the client.
- *
- * @param ac autoconfiguation context to check
- */
-static void
-check_autoconfig_finished (struct AutoconfigContext *ac)
-{
-  if (NULL != ac->probe_external)
-    return;
-  GNUNET_SCHEDULER_cancel (ac->timeout_task);
-  ac->timeout_task
-    = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
-                               ac);
-}
-
-
-/**
- * Update ENABLE_UPNPC configuration option.
- *
- * @param ac autoconfiguration to update
- */
-static void
-update_enable_upnpc_option (struct AutoconfigContext *ac)
-{
-  switch (ac->enable_upnpc)
-  {
-  case GNUNET_YES:
-    GNUNET_CONFIGURATION_set_value_string (ac->c,
-                                          "NAT",
-                                          "ENABLE_UPNP",
-                                          "YES");
-    break;
-  case GNUNET_NO:
-    GNUNET_CONFIGURATION_set_value_string (ac->c,
-                                          "NAT",
-                                          "ENABLE_UPNP",
-                                          "NO");
-    break;
-  case GNUNET_SYSERR:
-    /* We are unsure, do not change option */
-    break;
-  }
-}
-
-
-/**
- * Handle result from external IP address probe during
- * autoconfiguration.
- *
- * @param cls our `struct AutoconfigContext`
- * @param addr the address, NULL on errors
- * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
- */
-static void
-auto_external_result_cb (void *cls,
-                        const struct in_addr *addr,
-                        enum GNUNET_NAT_StatusCode result)
-{
-  struct AutoconfigContext *ac = cls;
-
-  ac->probe_external = NULL;
-  switch (result)
-  {
-  case GNUNET_NAT_ERROR_SUCCESS:
-    ac->enable_upnpc = GNUNET_YES;
-    break;
-  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
-  case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
-  case GNUNET_NAT_ERROR_IPC_FAILURE:
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-               "Disabling UPNPC: %d\n",
-               (int) result);
-    ac->enable_upnpc = GNUNET_NO; /* did not work */
-    break;
-  default:
-    GNUNET_break (0); /* unexpected */
-    ac->enable_upnpc = GNUNET_SYSERR;
-    break;    
-  }
-  update_enable_upnpc_option (ac);
-  check_autoconfig_finished (ac);
-}
-
-
-/**
- * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
- * client.
- *
- * @param cls client who sent the message
- * @param message the message received
- */
-static void
-handle_autoconfig_request (void *cls,
-                          const struct GNUNET_NAT_AutoconfigRequestMessage *message)
-{
-  struct ClientHandle *ch = cls;
-  size_t left = ntohs (message->header.size) - sizeof (*message);
-  struct LocalAddressList *lal;
-  struct AutoconfigContext *ac;
-
-  ac = GNUNET_new (struct AutoconfigContext);
-  ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
-  ac->ch = ch;
-  ac->c = GNUNET_CONFIGURATION_create ();
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_deserialize (ac->c,
-                                       (const char *) &message[1],
-                                       left,
-                                       GNUNET_NO))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (ch->client);
-    GNUNET_CONFIGURATION_destroy (ac->c);
-    GNUNET_free (ac);
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Received REQUEST_AUTO_CONFIG message from client\n");
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_string (ac->c,
-                                            "PEER",
-                                            "SYSTEM_TYPE",
-                                            &ac->system_type))
-    ac->system_type = GNUNET_strdup ("UNKNOWN");
-
-  GNUNET_CONTAINER_DLL_insert (ac_head,
-                              ac_tail,
-                              ac);
-  ac->orig
-    = GNUNET_CONFIGURATION_dup (ac->c);
-  ac->timeout_task
-    = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
-                                   &conclude_autoconfig_request,
-                                   ac);
-  ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
-  
-  /* Probe for upnpc */
-  if (GNUNET_SYSERR ==
-      GNUNET_OS_check_helper_binary ("upnpc",
-                                    GNUNET_NO,
-                                    NULL))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-               _("UPnP client `upnpc` command not found, disabling UPnP\n"));
-    ac->enable_upnpc = GNUNET_NO;
-  }
-  else
-  {
-    for (lal = lal_head; NULL != lal; lal = lal->next)
-      if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
-       /* we are behind NAT, useful to try upnpc */
-       ac->enable_upnpc = GNUNET_YES;
-  }
-  if (GNUNET_YES == ac->enable_upnpc)
-  {
-    /* If we are a mobile device, always leave it on as the network
-       may change to one that supports UPnP anytime.  If we are
-       stationary, check if our network actually supports UPnP, and if
-       not, disable it. */
-    if ( (0 == strcasecmp (ac->system_type,
-                          "INFRASTRUCTURE")) ||
-        (0 == strcasecmp (ac->system_type,
-                          "DESKTOP")) )
-    {
-      /* Check if upnpc gives us an external IP */
-      ac->probe_external
-       = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
-                                             ac);
-    }
-  }
-  if (NULL == ac->probe_external)
-    update_enable_upnpc_option (ac);
-
-  /* Finally, check if we are already done */  
-  check_autoconfig_finished (ac);
-}
-
-
 /**
  * Task run during shutdown.
  *
@@ -2196,16 +1854,7 @@ static void
 shutdown_task (void *cls)
 {
   struct StunExternalIP *se;
-  struct AutoconfigContext *ac;
 
-  while (NULL != (ac = ac_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (ac_head,
-                                ac_tail,
-                                ac);
-    terminate_ac_activities (ac);
-    GNUNET_free (ac);
-  }
   while (NULL != (se = se_head))
   {
     GNUNET_CONTAINER_DLL_remove (se_head,
@@ -2386,10 +2035,6 @@ GNUNET_SERVICE_MAIN
                        GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
                        struct GNUNET_NAT_RequestConnectionReversalMessage,
                        NULL),
- GNUNET_MQ_hd_var_size (autoconfig_request,
-                       GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
-                       struct GNUNET_NAT_AutoconfigRequestMessage,
-                       NULL),
  GNUNET_MQ_handler_end ());
 
 
index 304db3c15318db1d7b60ac9c366af037e59ded54..88975c4244de96728340b69bdcd58fd951c5d205 100644 (file)
@@ -67,8 +67,3 @@ STUN_SERVERS = stun.gnunet.org stun.services.mozilla.com:3478 stun.ekiga.net:347
 # After how long do we consider STUN data stale?
 STUN_STALE = 60 min
 
-
-[gnunet-nat-server]
-HOSTNAME = gnunet.org
-PORT = 5724
-NOARMBIND = YES
index 02bae71e90fc4512e2d763641db2e0ce5550111e..d34900bd191fdf729fffb79b526fdb6e8e1c473f 100644 (file)
@@ -224,45 +224,6 @@ struct GNUNET_NAT_AddressChangeNotificationMessage
 };
 
 
-/**
- * Client requesting automatic configuration.
- */
-struct GNUNET_NAT_AutoconfigRequestMessage
-{
-  /**
-   * Header with type #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG
-   */
-  struct GNUNET_MessageHeader header;
-
-  /* Followed by configuration (diff, serialized, compressed) */
-  
-};
-
-
-/**
- * Service responding with proposed configuration.
- */
-struct GNUNET_NAT_AutoconfigResultMessage
-{
-  /**
-   * Header with type #GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT
-   */
-  struct GNUNET_MessageHeader header;
-  
-  /**
-   * An `enum GNUNET_NAT_StatusCode` in NBO.
-   */
-  int32_t status_code GNUNET_PACKED;
-
-  /**
-   * An `enum GNUNET_NAT_Type` in NBO.
-   */
-  int32_t type GNUNET_PACKED;
-
-  /* Followed by configuration (diff, serialized, compressed) */
-};
-
-
 GNUNET_NETWORK_STRUCT_END
 
 #endif
diff --git a/src/nat/nat_api_auto.c b/src/nat/nat_api_auto.c
deleted file mode 100644 (file)
index c5c5fa6..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2007-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.
-*/
-
-/**
- * @author Christian Grothoff
- * @author Milan Bouchet-Valat
- *
- * @file nat/nat_api_auto.c
- * Routines for NAT auto configuration.
- */
-#include "platform.h"
-#include "gnunet_nat_service.h"
-#include "nat.h"
-#include "nat_stun.h"
-
-
-
-/**
- * Handle to auto-configuration in progress.
- */
-struct GNUNET_NAT_AutoHandle
-{
-
-  /**
-   * Configuration we use.
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-  
-  /**
-   * Message queue for communicating with the NAT service.
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Function called with the result from the autoconfiguration.
-   */
-  GNUNET_NAT_AutoResultCallback arc;
-
-  /**
-   * Closure for @e arc.
-   */
-  void *arc_cls;
-
-};
-
-
-/**
- * Converts `enum GNUNET_NAT_StatusCode` to string
- *
- * @param err error code to resolve to a string
- * @return point to a static string containing the error code
- */
-const char *
-GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err)
-{
-  switch (err)
-  {
-  case GNUNET_NAT_ERROR_SUCCESS:
-    return _ ("Operation Successful");
-  case GNUNET_NAT_ERROR_IPC_FAILURE:
-    return _ ("IPC failure");
-  case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR:
-    return _ ("Failure in network subsystem, check permissions.");
-  case GNUNET_NAT_ERROR_TIMEOUT:
-    return _ ("Encountered timeout while performing operation");
-  case GNUNET_NAT_ERROR_NOT_ONLINE:
-    return _ ("detected that we are offline");
-  case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
-    return _ ("`upnpc` command not found");
-  case GNUNET_NAT_ERROR_UPNPC_FAILED:
-    return _ ("Failed to run `upnpc` command");
-  case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
-    return _ ("`upnpc' command took too long, process killed");
-  case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
-    return _ ("`upnpc' command failed to establish port mapping");
-  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
-    return _ ("`external-ip' command not found");
-  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
-    return _ ("Failed to run `external-ip` command");
-  case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
-    return _ ("`external-ip' command output invalid");
-  case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
-    return _ ("no valid address was returned by `external-ip'");
-  case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO:
-    return _ ("Could not determine interface with internal/local network address");
-  case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND:
-    return _ ("No functioning gnunet-helper-nat-server installation found");
-  case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED:
-    return _ ("NAT test could not be initialized");
-  case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT:
-    return _ ("NAT test timeout reached");
-  case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED:
-    return _ ("could not register NAT");
-  case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND:
-    return _ ("No working gnunet-helper-nat-client installation found");
-  default:
-    return "unknown status code";
-  }
-}
-
-
-/**
- * Check result from autoconfiguration attempt.
- *
- * @param cls the `struct GNUNET_NAT_AutoHandle`
- * @param res the result
- * @return #GNUNET_OK if @a res is well-formed (always for now)
- */
-static int
-check_auto_result (void *cls,
-                  const struct GNUNET_NAT_AutoconfigResultMessage *res)
-{
-  return GNUNET_OK;
-}
-
-
-/**
- * Handle result from autoconfiguration attempt.
- *
- * @param cls the `struct GNUNET_NAT_AutoHandle`
- * @param res the result
- */
-static void
-handle_auto_result (void *cls,
-                   const struct GNUNET_NAT_AutoconfigResultMessage *res)
-{
-  struct GNUNET_NAT_AutoHandle *ah = cls;
-  size_t left;
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  enum GNUNET_NAT_Type type
-    = (enum GNUNET_NAT_Type) ntohl (res->type);
-  enum GNUNET_NAT_StatusCode status
-    = (enum GNUNET_NAT_StatusCode) ntohl (res->status_code);
-
-  left = ntohs (res->header.size) - sizeof (*res);
-  cfg = GNUNET_CONFIGURATION_create ();
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_deserialize (cfg,
-                                       (const char *) &res[1],
-                                       left,
-                                       GNUNET_NO))
-  {
-    GNUNET_break (0);
-    ah->arc (ah->arc_cls,
-            NULL,
-            GNUNET_NAT_ERROR_IPC_FAILURE,
-            type);
-  }
-  else
-  {
-    ah->arc (ah->arc_cls,
-            cfg,
-            status,
-            type);
-  }
-  GNUNET_CONFIGURATION_destroy (cfg);
-  GNUNET_NAT_autoconfig_cancel (ah);
-}
-
-
-/**
- * Handle queue errors by reporting autoconfiguration failure.
- *
- * @param cls the `struct GNUNET_NAT_AutoHandle *`
- * @param error details about the error
- */
-static void
-ah_error_handler (void *cls,
-                 enum GNUNET_MQ_Error error)
-{
-  struct GNUNET_NAT_AutoHandle *ah = cls;
-
-  ah->arc (ah->arc_cls,
-          NULL,
-          GNUNET_NAT_ERROR_IPC_FAILURE,
-          GNUNET_NAT_TYPE_UNKNOWN);
-  GNUNET_NAT_autoconfig_cancel (ah);
-}
-
-
-/**
- * Start auto-configuration routine.  The transport adapters should
- * be stopped while this function is called.
- *
- * @param cfg initial configuration
- * @param cb function to call with autoconfiguration result
- * @param cb_cls closure for @a cb
- * @return handle to cancel operation
- */
-struct GNUNET_NAT_AutoHandle *
-GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                            GNUNET_NAT_AutoResultCallback cb,
-                            void *cb_cls)
-{
-  struct GNUNET_NAT_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AutoHandle);
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (auto_result,
-                          GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT,
-                          struct GNUNET_NAT_AutoconfigResultMessage,
-                          ah),
-    GNUNET_MQ_handler_end ()
-  };
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_NAT_AutoconfigRequestMessage *req;
-  char *buf;
-  size_t size;
-
-  buf = GNUNET_CONFIGURATION_serialize (cfg,
-                                       &size);
-  if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req))
-  {
-    GNUNET_break (0);
-    GNUNET_free (buf);
-    GNUNET_free (ah);
-    return NULL;
-  }
-  ah->arc = cb;
-  ah->arc_cls = cb_cls;
-  ah->mq = GNUNET_CLIENT_connecT (cfg,
-                                 "nat",
-                                 handlers,
-                                 &ah_error_handler,
-                                 ah);
-  if (NULL == ah->mq)
-  {
-    GNUNET_break (0);
-    GNUNET_free (buf);
-    GNUNET_free (ah);
-    return NULL;
-  }
-  env = GNUNET_MQ_msg_extra (req,
-                            size,
-                            GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG);
-  GNUNET_memcpy (&req[1],
-                buf,
-                size);
-  GNUNET_free (buf);
-  GNUNET_MQ_send (ah->mq,
-                 env);
-  return ah;
-}
-
-
-/**
- * Abort autoconfiguration.
- *
- * @param ah handle for operation to abort
- */
-void
-GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah)
-{
-  GNUNET_MQ_destroy (ah->mq);
-  GNUNET_free (ah);
-}
-
-/* end of nat_api_auto.c */
diff --git a/src/nat/nat_api_test.c b/src/nat/nat_api_test.c
deleted file mode 100644 (file)
index d47c140..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 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/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
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_nat_lib.h"
-#include "nat.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
-
-#define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
-
-/**
- * Entry we keep for each incoming connection.
- */
-struct NatActivity
-{
-  /**
-   * This is a doubly-linked list.
-   */
-  struct NatActivity *next;
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct NatActivity *prev;
-
-  /**
-   * Socket of the incoming connection.
-   */
-  struct GNUNET_NETWORK_Handle *sock;
-
-  /**
-   * Handle of the master context.
-   */
-  struct GNUNET_NAT_Test *h;
-
-  /**
-   * Task reading from the incoming connection.
-   */
-  struct GNUNET_SCHEDULER_Task *rtask;
-};
-
-
-/**
- * Entry we keep for each connection to the gnunet-nat-service.
- */
-struct ClientActivity
-{
-  /**
-   * This is a doubly-linked list.
-   */
-  struct ClientActivity *next;
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct ClientActivity *prev;
-
-  /**
-   * Socket of the incoming connection.
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Handle to overall NAT test.
-   */
-  struct GNUNET_NAT_Test *h;
-
-};
-
-
-/**
- * Handle to a NAT test.
- */
-struct GNUNET_NAT_Test
-{
-
-  /**
-   * Configuration used
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Function to call with success report
-   */
-  GNUNET_NAT_TestCallback report;
-
-  /**
-   * Closure for @e report.
-   */
-  void *report_cls;
-
-  /**
-   * Handle to NAT traversal in use
-   */
-  struct GNUNET_NAT_Handle *nat;
-
-  /**
-   * Handle to listen socket, or NULL
-   */
-  struct GNUNET_NETWORK_Handle *lsock;
-
-  /**
-   * Head of list of nat activities.
-   */
-  struct NatActivity *na_head;
-
-  /**
-   * Tail of list of nat activities.
-   */
-  struct NatActivity *na_tail;
-
-  /**
-   * Head of list of client activities.
-   */
-  struct ClientActivity *ca_head;
-
-  /**
-   * Tail of list of client activities.
-   */
-  struct ClientActivity *ca_tail;
-
-  /**
-   * Identity of task for the listen socket (if any)
-   */
-  struct GNUNET_SCHEDULER_Task *ltask;
-
-  /**
-   * Task identifier for the timeout (if any)
-   */
-  struct GNUNET_SCHEDULER_Task *ttask;
-
-  /**
-   * #GNUNET_YES if we're testing TCP
-   */
-  int is_tcp;
-
-  /**
-   * Data that should be transmitted or source-port.
-   */
-  uint16_t data;
-
-  /**
-   * Advertised port to the other peer.
-   */
-  uint16_t adv_port;
-
-  /**
-   * Status code to be reported to the timeout/status call
-   */
-  enum GNUNET_NAT_StatusCode status;
-};
-
-
-/**
- * Function called from #GNUNET_NAT_register whenever someone asks us
- * to do connection reversal.
- *
- * @param cls closure, our `struct GNUNET_NAT_Handle`
- * @param addr public IP address of the other peer
- * @param addrlen actual lenght of the @a addr
- */
-static void
-reversal_cb (void *cls,
-             const struct sockaddr *addr,
-             socklen_t addrlen)
-{
-  struct GNUNET_NAT_Test *h = cls;
-  const struct sockaddr_in *sa;
-
-  if (sizeof (struct sockaddr_in) != addrlen)
-    return;
-  sa = (const struct sockaddr_in *) addr;
-  if (h->data != sa->sin_port)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received connection reversal request for wrong port\n");
-    return;                     /* wrong port */
-  }
-  /* report success */
-  h->report (h->report_cls,
-             GNUNET_NAT_ERROR_SUCCESS);
-}
-
-
-/**
- * Activity on our incoming socket.  Read data from the
- * incoming connection.
- *
- * @param cls the `struct GNUNET_NAT_Test`
- */
-static void
-do_udp_read (void *cls)
-{
-  struct GNUNET_NAT_Test *tst = cls;
-  uint16_t data;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
-
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  tst->ltask =
-      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                     tst->lsock,
-                                     &do_udp_read,
-                                     tst);
-  if ((NULL != tc->write_ready) &&
-      (GNUNET_NETWORK_fdset_isset (tc->read_ready,
-                                   tst->lsock)) &&
-      (sizeof (data) ==
-       GNUNET_NETWORK_socket_recv (tst->lsock,
-                                   &data,
-                                   sizeof (data))))
-  {
-    if (data == tst->data)
-      tst->report (tst->report_cls,
-                   GNUNET_NAT_ERROR_SUCCESS);
-    else
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Received data mismatches expected value\n");
-  }
-  else
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to receive data from inbound connection\n");
-}
-
-
-/**
- * Activity on our incoming socket.  Read data from the
- * incoming connection.
- *
- * @param cls the `struct NatActivity`
- */
-static void
-do_read (void *cls)
-{
-  struct NatActivity *na = cls;
-  struct GNUNET_NAT_Test *tst;
-  uint16_t data;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
-
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  na->rtask = NULL;
-  tst = na->h;
-  GNUNET_CONTAINER_DLL_remove (tst->na_head,
-                              tst->na_tail,
-                              na);
-  if ((NULL != tc->write_ready) &&
-      (GNUNET_NETWORK_fdset_isset (tc->read_ready,
-                                   na->sock)) &&
-      (sizeof (data) ==
-       GNUNET_NETWORK_socket_recv (na->sock,
-                                   &data,
-                                   sizeof (data))))
-  {
-    if (data == tst->data)
-      tst->report (tst->report_cls,
-                   GNUNET_NAT_ERROR_SUCCESS);
-    else
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Received data does not match expected value\n");
-  }
-  else
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to receive data from inbound connection\n");
-  GNUNET_NETWORK_socket_close (na->sock);
-  GNUNET_free (na);
-}
-
-
-/**
- * Activity on our listen socket. Accept the
- * incoming connection.
- *
- * @param cls the `struct GNUNET_NAT_Test`
- */
-static void
-do_accept (void *cls)
-{
-  struct GNUNET_NAT_Test *tst = cls;
-  struct GNUNET_NETWORK_Handle *s;
-  struct NatActivity *wl;
-
-  tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                              tst->lsock,
-                                              &do_accept,
-                                              tst);
-  s = GNUNET_NETWORK_socket_accept (tst->lsock,
-                                    NULL,
-                                    NULL);
-  if (NULL == s)
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
-                         "accept");
-    return;                     /* odd error */
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got an inbound connection, waiting for data\n");
-  wl = GNUNET_new (struct NatActivity);
-  wl->sock = s;
-  wl->h = tst;
-  wl->rtask =
-    GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                   wl->sock,
-                                   &do_read,
-                                   wl);
-  GNUNET_CONTAINER_DLL_insert (tst->na_head,
-                              tst->na_tail,
-                              wl);
-}
-
-
-/**
- * We got disconnected from the NAT server.  Stop
- * waiting for a reply.
- *
- * @param cls the `struct ClientActivity`
- * @param error error code
- */
-static void
-mq_error_handler (void *cls,
-                  enum GNUNET_MQ_Error error)
-{
-  struct ClientActivity *ca = cls;
-  struct GNUNET_NAT_Test *tst = ca->h;
-
-  GNUNET_CONTAINER_DLL_remove (tst->ca_head,
-                               tst->ca_tail,
-                               ca);
-  GNUNET_MQ_destroy (ca->mq);
-  GNUNET_free (ca);
-}
-
-
-/**
- * Address-callback, used to send message to gnunet-nat-server.
- *
- * @param cls closure
- * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
- *     the previous (now invalid) one
- * @param addr either the previous or the new public IP address
- * @param addrlen actual length of the @a addr
- */
-static void
-addr_cb (void *cls,
-         int add_remove,
-         const struct sockaddr *addr,
-         socklen_t addrlen)
-{
-  struct GNUNET_NAT_Test *h = cls;
-  struct ClientActivity *ca;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_NAT_TestMessage *msg;
-  const struct sockaddr_in *sa;
-
-  if (GNUNET_YES != add_remove)
-    return;
-  if (addrlen != sizeof (struct sockaddr_in))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        "NAT test ignores IPv6 address `%s' returned from NAT library\n",
-        GNUNET_a2s (addr,
-                     addrlen));
-    return;                     /* ignore IPv6 here */
-  }
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Asking gnunet-nat-server to connect to `%s'\n",
-       GNUNET_a2s (addr,
-                   addrlen));
-
-  ca = GNUNET_new (struct ClientActivity);
-  ca->h = h;
-  ca->mq = GNUNET_CLIENT_connecT (h->cfg,
-                                  "gnunet-nat-server",
-                                  NULL,
-                                  &mq_error_handler,
-                                  ca);
-  if (NULL == ca->mq)
-  {
-    GNUNET_free (ca);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Failed to connect to `gnunet-nat-server'\n"));
-    return;
-  }
-  GNUNET_CONTAINER_DLL_insert (h->ca_head,
-                               h->ca_tail,
-                               ca);
-  sa = (const struct sockaddr_in *) addr;
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_NAT_TEST);
-  msg->dst_ipv4 = sa->sin_addr.s_addr;
-  msg->dport = sa->sin_port;
-  msg->data = h->data;
-  msg->is_tcp = htonl ((uint32_t) h->is_tcp);
-  GNUNET_MQ_send (ca->mq,
-                  env);
-}
-
-
-/**
- * Timeout task for a nat test.
- * Calls the report-callback with a timeout return value
- *
- * Destroys the nat handle after the callback has been processed.
- *
- * @param cls handle to the timed out NAT test
- */
-static void
-do_timeout (void *cls)
-{
-  struct GNUNET_NAT_Test *nh = cls;
-
-  nh->ttask = NULL;
-  nh->report (nh->report_cls,
-              (GNUNET_NAT_ERROR_SUCCESS == nh->status)
-              ? GNUNET_NAT_ERROR_TIMEOUT
-              : nh->status);
-}
-
-
-/**
- * Start testing if NAT traversal works using the
- * given configuration (IPv4-only).
- *
- * ALL failures are reported directly to the report callback
- *
- * @param cfg configuration for the NAT traversal
- * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP
- * @param bnd_port port to bind to, 0 for connection reversal
- * @param adv_port externally advertised port to use
- * @param timeout delay after which the test should be aborted
- * @param report function to call with the result of the test
- * @param report_cls closure for @a report
- * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback
- */
-struct GNUNET_NAT_Test *
-GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                       int is_tcp,
-                       uint16_t bnd_port,
-                       uint16_t adv_port,
-                       struct GNUNET_TIME_Relative timeout,
-                       GNUNET_NAT_TestCallback report,
-                       void *report_cls)
-{
-  struct GNUNET_NAT_Test *nh;
-  struct sockaddr_in sa;
-  const struct sockaddr *addrs[] = {
-    (const struct sockaddr *) &sa
-  };
-  const socklen_t addrlens[] = {
-    sizeof (sa)
-  };
-
-  memset (&sa, 0, sizeof (sa));
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (bnd_port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-
-  nh = GNUNET_new (struct GNUNET_NAT_Test);
-  nh->cfg = cfg;
-  nh->is_tcp = is_tcp;
-  nh->data = bnd_port;
-  nh->adv_port = adv_port;
-  nh->report = report;
-  nh->report_cls = report_cls;
-  nh->status = GNUNET_NAT_ERROR_SUCCESS;
-  if (0 == bnd_port)
-  {
-    nh->nat
-      = GNUNET_NAT_register (cfg,
-                             is_tcp,
-                             0,
-                             0,
-                            NULL,
-                             NULL,
-                            &addr_cb,
-                             &reversal_cb,
-                             nh,
-                             NULL);
-  }
-  else
-  {
-    nh->lsock =
-        GNUNET_NETWORK_socket_create (AF_INET,
-                                      (is_tcp ==
-                                       GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM,
-                                      0);
-    if ((nh->lsock == NULL) ||
-        (GNUNET_OK !=
-         GNUNET_NETWORK_socket_bind (nh->lsock,
-                                     (const struct sockaddr *) &sa,
-                                     sizeof (sa))))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Failed to create listen socket bound to `%s' for NAT test: %s\n"),
-                  GNUNET_a2s ((const struct sockaddr *) &sa,
-                              sizeof (sa)),
-                  STRERROR (errno));
-      if (NULL != nh->lsock)
-      {
-        GNUNET_NETWORK_socket_close (nh->lsock);
-        nh->lsock = NULL;
-      }
-      nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR;
-      nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
-                                            nh);
-      return nh;
-    }
-    if (GNUNET_YES == is_tcp)
-    {
-      GNUNET_break (GNUNET_OK ==
-                    GNUNET_NETWORK_socket_listen (nh->lsock,
-                                                  5));
-      nh->ltask =
-          GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                         nh->lsock,
-                                        &do_accept,
-                                         nh);
-    }
-    else
-    {
-      nh->ltask =
-          GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                         nh->lsock,
-                                        &do_udp_read,
-                                         nh);
-    }
-    LOG (GNUNET_ERROR_TYPE_INFO,
-        "NAT test listens on port %u (%s)\n",
-        bnd_port,
-        (GNUNET_YES == is_tcp) ? "tcp" : "udp");
-    nh->nat = GNUNET_NAT_register (cfg,
-                                   is_tcp,
-                                   adv_port,
-                                   1,
-                                   addrs,
-                                   addrlens,
-                                   &addr_cb,
-                                   NULL,
-                                   nh,
-                                   NULL);
-    if (NULL == nh->nat)
-    {
-      LOG (GNUNET_ERROR_TYPE_INFO,
-          _("NAT test failed to start NAT library\n"));
-      if (NULL != nh->ltask)
-      {
-        GNUNET_SCHEDULER_cancel (nh->ltask);
-        nh->ltask = NULL;
-      }
-      if (NULL != nh->lsock)
-      {
-        GNUNET_NETWORK_socket_close (nh->lsock);
-        nh->lsock = NULL;
-      }
-      nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED;
-      nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
-                                            nh);
-      return nh;
-    }
-  }
-  nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout,
-                                           &do_timeout,
-                                           nh);
-  return nh;
-}
-
-
-/**
- * Stop an active NAT test.
- *
- * @param tst test to stop.
- */
-void
-GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
-{
-  struct NatActivity *pos;
-  struct ClientActivity *cpos;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Stopping NAT test\n");
-  while (NULL != (cpos = tst->ca_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (tst->ca_head,
-                                tst->ca_tail,
-                                cpos);
-    GNUNET_MQ_destroy (cpos->mq);
-    GNUNET_free (cpos);
-  }
-  while (NULL != (pos = tst->na_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (tst->na_head,
-                                tst->na_tail,
-                                pos);
-    GNUNET_SCHEDULER_cancel (pos->rtask);
-    GNUNET_NETWORK_socket_close (pos->sock);
-    GNUNET_free (pos);
-  }
-  if (NULL != tst->ttask)
-  {
-    GNUNET_SCHEDULER_cancel (tst->ttask);
-    tst->ttask = NULL;
-  }
-  if (NULL != tst->ltask)
-  {
-    GNUNET_SCHEDULER_cancel (tst->ltask);
-    tst->ltask = NULL;
-  }
-  if (NULL != tst->lsock)
-  {
-    GNUNET_NETWORK_socket_close (tst->lsock);
-    tst->lsock = NULL;
-  }
-  if (NULL != tst->nat)
-  {
-    GNUNET_NAT_unregister (tst->nat);
-    tst->nat = NULL;
-  }
-  GNUNET_free (tst);
-}
-
-/* end of nat_test.c */