From 80e1315b56f559db60499f5373e90c293c5ab065 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 6 Jan 2017 13:26:38 +0100 Subject: [PATCH] separate service for autoconfiguration from NAT traversal --- configure.ac | 2 + doc/man/Makefile.am | 1 + doc/man/gnunet-nat-auto.1 | 59 +++ doc/man/gnunet-nat.1 | 13 - po/POTFILES.in | 8 +- src/Makefile.am | 1 + src/include/Makefile.am | 1 + src/include/gnunet_nat_auto_service.h | 224 ++++++++ src/include/gnunet_nat_service.h | 407 +++++---------- src/include/gnunet_protocols.h | 2 +- src/nat-auto/.gitignore | 3 + src/nat-auto/Makefile.am | 58 +++ src/nat-auto/gnunet-nat-auto.c | 428 ++++++++++++++++ src/{nat => nat-auto}/gnunet-nat-server.c | 2 +- src/nat-auto/gnunet-service-nat-auto.c | 481 ++++++++++++++++++ src/nat-auto/nat-auto.conf.in | 15 + src/nat-auto/nat-auto.h | 110 ++++ .../nat_auto_api.c} | 8 +- .../nat_auto_api_test.c} | 4 +- src/nat/Makefile.am | 9 - src/nat/gnunet-nat.c | 279 ---------- src/nat/gnunet-service-nat.c | 355 ------------- src/nat/nat.conf.in | 5 - src/nat/nat.h | 39 -- 24 files changed, 1527 insertions(+), 987 deletions(-) create mode 100644 doc/man/gnunet-nat-auto.1 create mode 100644 src/include/gnunet_nat_auto_service.h create mode 100644 src/nat-auto/.gitignore create mode 100644 src/nat-auto/Makefile.am create mode 100644 src/nat-auto/gnunet-nat-auto.c rename src/{nat => nat-auto}/gnunet-nat-server.c (99%) create mode 100644 src/nat-auto/gnunet-service-nat-auto.c create mode 100644 src/nat-auto/nat-auto.conf.in create mode 100644 src/nat-auto/nat-auto.h rename src/{nat/nat_api_auto.c => nat-auto/nat_auto_api.c} (98%) rename src/{nat/nat_api_test.c => nat-auto/nat_auto_api_test.c} (99%) diff --git a/configure.ac b/configure.ac index c41bcc4b5..dade7d211 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index ff1e462b7..c40363b59 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -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 index 000000000..310f14d43 --- /dev/null +++ b/doc/man/gnunet-nat-auto.1 @@ -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 or by sending electronic mail to + +.SH SEE ALSO +gnunet\-transport(1) gnunet\-nat(1) + diff --git a/doc/man/gnunet-nat.1 b/doc/man/gnunet-nat.1 index 01e0267a4..a8a82883b 100644 --- a/doc/man/gnunet-nat.1 +++ b/doc/man/gnunet-nat.1 @@ -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 or by sending electronic mail to diff --git a/po/POTFILES.in b/po/POTFILES.in index 56af200ff..e1c3ec697 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 6925788d5..d04cba9dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -85,6 +85,7 @@ SUBDIRS = \ template \ ats \ nat \ + nat-auto \ fragmentation \ transport \ ats-tool \ diff --git a/src/include/Makefile.am b/src/include/Makefile.am index f27fd6e36..639d3bfd7 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -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 index 000000000..90115ff8c --- /dev/null +++ b/src/include/gnunet_nat_auto_service.h @@ -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 */ diff --git a/src/include/gnunet_nat_service.h b/src/include/gnunet_nat_service.h index 6b9650306..94f8a8555 100644 --- a/src/include/gnunet_nat_service.h +++ b/src/include/gnunet_nat_service.h @@ -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 diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index f9b7d3cb8..fdabfee18 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -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 index 000000000..6ba53d72f --- /dev/null +++ b/src/nat-auto/.gitignore @@ -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 index 000000000..dbe910306 --- /dev/null +++ b/src/nat-auto/Makefile.am @@ -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 index 000000000..3b9a5fa94 --- /dev/null +++ b/src/nat-auto/gnunet-nat-auto.c @@ -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/gnunet-nat-server.c b/src/nat-auto/gnunet-nat-server.c similarity index 99% rename from src/nat/gnunet-nat-server.c rename to src/nat-auto/gnunet-nat-server.c index 1692a8ef1..93352f5f0 100644 --- a/src/nat/gnunet-nat-server.c +++ b/src/nat-auto/gnunet-nat-server.c @@ -27,7 +27,7 @@ #include "gnunet_util_lib.h" #include "gnunet_nat_lib.h" #include "gnunet_protocols.h" -#include "nat.h" +#include "nat-auto.h" /** diff --git a/src/nat-auto/gnunet-service-nat-auto.c b/src/nat-auto/gnunet-service-nat-auto.c new file mode 100644 index 000000000..897d6feb2 --- /dev/null +++ b/src/nat-auto/gnunet-service-nat-auto.c @@ -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 +#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 + + +/** + * 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 + +/** + * 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 index 000000000..daa3e389d --- /dev/null +++ b/src/nat-auto/nat-auto.conf.in @@ -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 index 000000000..150dc32c2 --- /dev/null +++ b/src/nat-auto/nat-auto.h @@ -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/nat_api_auto.c b/src/nat-auto/nat_auto_api.c similarity index 98% rename from src/nat/nat_api_auto.c rename to src/nat-auto/nat_auto_api.c index c5c5fa67a..e6b0512c6 100644 --- a/src/nat/nat_api_auto.c +++ b/src/nat-auto/nat_auto_api.c @@ -23,13 +23,13 @@ * @author Christian Grothoff * @author Milan Bouchet-Valat * - * @file nat/nat_api_auto.c + * @file nat/nat_auto_api.c * Routines for NAT auto configuration. */ #include "platform.h" #include "gnunet_nat_service.h" -#include "nat.h" -#include "nat_stun.h" +#include "gnunet_nat_auto_service.h" +#include "nat-auto.h" @@ -248,7 +248,7 @@ GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg, } env = GNUNET_MQ_msg_extra (req, size, - GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG); + GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG); GNUNET_memcpy (&req[1], buf, size); diff --git a/src/nat/nat_api_test.c b/src/nat-auto/nat_auto_api_test.c similarity index 99% rename from src/nat/nat_api_test.c rename to src/nat-auto/nat_auto_api_test.c index d47c14094..056d2a2bf 100644 --- a/src/nat/nat_api_test.c +++ b/src/nat-auto/nat_auto_api_test.c @@ -18,14 +18,14 @@ Boston, MA 02110-1301, USA. */ /** - * @file nat/nat_api_test.c + * @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.h" +#include "nat-auto.h" #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am index b2b9c4f50..456ddfb62 100644 --- a/src/nat/Makefile.am +++ b/src/nat/Makefile.am @@ -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.c b/src/nat/gnunet-nat.c index 4171babf9..02d68d787 100644 --- a/src/nat/gnunet-nat.c +++ b/src/nat/gnunet-nat.c @@ -33,11 +33,6 @@ */ 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 }, diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index 79f806f27..2cb2b30ff 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c @@ -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 ()); diff --git a/src/nat/nat.conf.in b/src/nat/nat.conf.in index 304db3c15..88975c424 100644 --- a/src/nat/nat.conf.in +++ b/src/nat/nat.conf.in @@ -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 diff --git a/src/nat/nat.h b/src/nat/nat.h index 02bae71e9..d34900bd1 100644 --- a/src/nat/nat.h +++ b/src/nat/nat.h @@ -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 -- 2.25.1