From 55f0400ad4888dd039b5374ccad0fc44da30d0f5 Mon Sep 17 00:00:00 2001 From: Ansa89 Date: Sat, 5 Mar 2016 13:43:39 +0100 Subject: [PATCH] Add NAT-PMP support --- .travis.yml | 2 +- configure.ac | 90 ++++++++++++++++++++++++++++++++++++++++++++ libtoxcore.pc.in | 2 +- toxcore/Makefile.inc | 9 +++-- toxcore/Messenger.c | 2 +- toxcore/Messenger.h | 2 +- toxcore/network.c | 54 +++++++++++++++++++++++--- toxcore/network.h | 30 ++++++++++++++- toxcore/tox.c | 4 +- toxcore/tox.h | 11 ++---- 10 files changed, 182 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index f508d514..9fc3752c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ before_script: - sudo add-apt-repository ppa:avsm/ocaml42+opam12 -y - sudo apt-get update -qq - sudo apt-get install ocaml opam astyle -qq - - sudo apt-get install libconfig-dev libvpx-dev libopus-dev libminiupnpc-dev check -qq + - sudo apt-get install libconfig-dev libvpx-dev libopus-dev libminiupnpc-dev libnatpmp-dev check -qq # build apidsl - git clone https://github.com/iphydf/apidsl - cd apidsl diff --git a/configure.ac b/configure.ac index 0e7b9bea..028cb229 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,7 @@ LIBCHECK_FOUND="no" WANT_NACL="no" ADD_NACL_OBJECTS_TO_PKGCONFIG="yes" MINIUPNP="yes" +NATPMP="yes" TOXCORE_LT_LDFLAGS="-version-info $LIBTOXCORE_LT_VERSION" TOXAV_LT_LDFLAGS="-version-info $LIBTOXAV_LT_VERSION" @@ -81,6 +82,17 @@ AC_ARG_ENABLE([miniupnp], ] ) +AC_ARG_ENABLE([natpmp], + [AC_HELP_STRING([--disable-natpmp], [nat-pmp port forwarding (default: enabled)]) ], + [ + if test "x$enableval" = "xyes"; then + NATPMP="yes" + elif test "x$enableval" = "xno"; then + NATPMP="no" + fi + ] +) + AC_ARG_ENABLE([randombytes-stir], [AC_HELP_STRING([--enable-randombytes-stir], [use randombytes_stir() instead of sodium_init() for faster startup on android (default: disabled)]) ], [ @@ -241,6 +253,8 @@ NACL_SEARCH_HEADERS= NACL_SEARCH_LIBS= MINIUPNP_SEARCH_HEADERS= MINIUPNP_SEARCH_LIBS= +NATPMP_SEARCH_HEADERS= +NATPMP_SEARCH_LIBS= AC_ARG_WITH(dependency-search, AC_HELP_STRING([--with-dependency-search=DIR], @@ -312,6 +326,24 @@ AC_ARG_WITH(miniupnp-libs, ] ) +AC_ARG_WITH(natpmp-headers, + AC_HELP_STRING([--with-natpmp-headers=DIR], + [search for natpmp header files in DIR]), + [ + NATPMP_SEARCH_HEADERS="$withval" + AC_MSG_NOTICE([will search for natpmp header files in $withval]) + ] +) + +AC_ARG_WITH(natpmp-libs, + AC_HELP_STRING([--with-natpmp-libs=DIR], + [search for natpmp libraries in DIR]), + [ + NATPMP_SEARCH_LIBS="$withval" + AC_MSG_NOTICE([will search for natpmp libraries in $withval]) + ] +) + if test "x$WANT_NACL" = "xyes"; then enable_shared=no enable_static=yes @@ -459,6 +491,36 @@ if test "x$MINIUPNP" = "xyes"; then AC_SUBST(MINIUPNP_LDFLAGS) fi +if test "x$NATPMP" = "xyes"; then + NATPMP_LIBS= + NATPMP_LDFLAGS= + LDFLAGS_SAVE="$LDFLAGS" + + if test -n "$NATPMP_SEARCH_LIBS"; then + LDFLAGS="-L$NATPMP_SEARCH_LIBS $LDFLAGS" + AC_CHECK_LIB(natpmp, initnatpmp + [ + NATPMP_LDFLAGS="-L$NATPMP_SEARCH_LIBS" + NATPMP_LIBS="-lnatpmp" + ], + [ + AC_MSG_ERROR([required library libnatpmp was not found in requested location $NATPMP_SEARCH_LIBS]) + ] + ) + else + AC_CHECK_LIB(natpmp, initnatpmp, + [], + [ + AC_MSG_ERROR([required library libnatpmp was not found on your system, please check http://miniupnp.free.fr/]) + ] + ) + fi + + LDFLAGS="$LDFLAGS_SAVE" + AC_SUBST(NATPMP_LIBS) + AC_SUBST(NATPMP_LDFLAGS) +fi + # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h]) @@ -546,6 +608,34 @@ if test "x$MINIUPNP" = "xyes"; then AC_SUBST(MINIUPNP_CFLAGS) fi +if test "x$NATPMP" = "xyes"; then + NATPMP_CFLAGS= + CFLAGS_SAVE="$CFLAGS" + CPPFLAGS_SAVE="$CPPFLAGS" + if test -n "$NATPMP_SEARCH_HEADERS"; then + CFLAGS="-I$NATPMP_SEARCH_HEADERS $CFLAGS" + CPPFLAGS="-I$NATPMP_SEARCH_HEADERS $CPPFLAGS" + AC_CHECK_HEADERS(natpmp.h, + [ + NATPMP_CFLAGS="-I$NATPMP_SEARCH_HEADERS" + ], + [ + AC_MSG_ERROR([header files for required library libnatpmp were not found in requested location $NATPMP_SEARCH_HEADERS]) + ] + ) + else + AC_CHECK_HEADERS(natpmp.h, + [], + [ + AC_MSG_ERROR([header files for required library libnatpmp was not found on your system, please check http://miniupnp.free.fr/]) + ] + ) + fi + CFLAGS="$CFLAGS_SAVE" + CPPFLAGS="$CPPFLAGS_SAVE" + AC_SUBST(NATPMP_CFLAGS) +fi + # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL AC_TYPE_INT16_T diff --git a/libtoxcore.pc.in b/libtoxcore.pc.in index 6542b52c..f89cbf00 100644 --- a/libtoxcore.pc.in +++ b/libtoxcore.pc.in @@ -7,5 +7,5 @@ Name: libtoxcore Description: Tox protocol library Requires: Version: @PACKAGE_VERSION@ -Libs: @NACL_OBJECTS_PKGCONFIG@ -L${libdir} @NACL_LDFLAGS@ -ltoxdns -ltoxencryptsave -ltoxcore @NACL_LIBS@ @MINIUPNP_LIBS@ @LIBS@ @MATH_LDFLAGS@ @PTHREAD_LDFLAGS@ +Libs: @NACL_OBJECTS_PKGCONFIG@ -L${libdir} @NACL_LDFLAGS@ -ltoxdns -ltoxencryptsave -ltoxcore @NACL_LIBS@ @MINIUPNP_LIBS@ @NATPMP_LIBS@ @LIBS@ @MATH_LDFLAGS@ @PTHREAD_LDFLAGS@ Cflags: -I${includedir} diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index 42389fc3..db3123d8 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -57,14 +57,16 @@ libtoxcore_la_CFLAGS = -I$(top_srcdir) \ -I$(top_srcdir)/toxcore \ $(LIBSODIUM_CFLAGS) \ $(NACL_CFLAGS) \ - $(MINIDUMP_CFLAGS) \ + $(MINIUPNP_CFLAGS) \ + $(NATPMP_CFLAGS) \ $(PTHREAD_CFLAGS) libtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \ $(EXTRA_LT_LDFLAGS) \ $(LIBSODIUM_LDFLAGS) \ $(NACL_LDFLAGS) \ - $(MINIDUMP_LDFLAGS) \ + $(MINIUPNP_LDFLAGS) \ + $(NATPMP_LDFLAGS) \ $(MATH_LDFLAGS) \ $(RT_LIBS) \ $(WINSOCK2_LIBS) @@ -72,5 +74,6 @@ libtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \ libtoxcore_la_LIBADD = $(LIBSODIUM_LIBS) \ $(NACL_OBJECTS) \ $(NAC_LIBS) \ - $(MINIDUMP_LIBS) \ + $(MINIUPNP_LIBS) \ + $(NATPMP_LIBS) \ $(PTHREAD_LIBS) diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index 92b8ca51..e2b5a682 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -1766,7 +1766,7 @@ Messenger *new_messenger(Messenger_Options *options, unsigned int *error) } else { IP ip; ip_init(&ip, options->ipv6enabled); - m->net = new_networking_upnp(ip, options->port_range[0], options->port_range[1], options->upnp_enabled, &net_err); + m->net = new_networking_nat(ip, options->port_range[0], options->port_range[1], options->traversal_type, &net_err); } if (m->net == NULL) { diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h index 181d1446..a7e81c8c 100644 --- a/toxcore/Messenger.h +++ b/toxcore/Messenger.h @@ -68,7 +68,7 @@ enum { typedef struct { uint8_t ipv6enabled; uint8_t udp_disabled; - uint8_t upnp_enabled; + TOX_TRAVERSAL_TYPE traversal_type; TCP_Proxy_Info proxy_info; uint16_t port_range[2]; uint16_t tcp_server_port; diff --git a/toxcore/network.c b/toxcore/network.c index a14df13c..5623e5b5 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -50,6 +50,10 @@ #include #endif +#ifdef HAVE_LIBNATPMP +#include +#endif + #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) static const char *inet_ntop(sa_family_t family, void *addr, char *buf, size_t bufsize) @@ -133,7 +137,6 @@ static void upnp_map_port(uint16_t port) devlist = upnpDiscover(1000, NULL, NULL, 0, 0, 2, &error); #endif - if (error) { LOGGER_WARNING("UPnP discovery failed (error = %d)", error); return; @@ -173,6 +176,42 @@ static void upnp_map_port(uint16_t port) } #endif +#ifdef HAVE_LIBNATPMP +/* Setup port forwarding using NAT-PMP */ +static void natpmp_map_port(uint16_t port) +{ + LOGGER_DEBUG("Attempting to set up NAT-PMP port forwarding"); + + int error; + natpmp_t natpmp; + natpmpresp_t resp; + + error = initnatpmp(&natpmp, 0, 0); + if (error) { + LOGGER_WARNING("NAT-PMP initialization failed (error = %d)", error); + return; + } + + error = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, port, port, 3600); + if (error != 12) { + LOGGER_WARNING("NAT-PMP send request failed (error = %d)", error); + closenatpmp(&natpmp); + return; + } + + error = readnatpmpresponseorretry(&natpmp, &resp); + for ( ; error == NATPMP_TRYAGAIN ; error = readnatpmpresponseorretry(&natpmp, &resp) ) + sleep(1); + + if (error) + LOGGER_WARNING("NAT-PMP port mapping failed (error = %d)", error); + else + LOGGER_INFO("NAT-PMP mapped port %d", port); + + closenatpmp(&natpmp); +} +#endif + /* Check if socket is valid. * * return 1 if valid @@ -544,7 +583,7 @@ static void at_shutdown(void) */ Networking_Core *new_networking(IP ip, uint16_t port) { - return new_networking_upnp(ip, port, port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM), 1, 0); + return new_networking_nat(ip, port, port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM), TOX_TRAVERSAL_TYPE_NONE, 0); } /* Initialize networking. @@ -552,7 +591,7 @@ Networking_Core *new_networking(IP ip, uint16_t port) */ Networking_Core *new_networking_ex(IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error) { - return new_networking_upnp(ip, port_from, port_to, 1, 0); + return new_networking_nat(ip, port_from, port_to, TOX_TRAVERSAL_TYPE_NONE, 0); } /* Initialize networking. @@ -565,7 +604,7 @@ Networking_Core *new_networking_ex(IP ip, uint16_t port_from, uint16_t port_to, * * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other. */ -Networking_Core *new_networking_upnp(IP ip, uint16_t port_from, uint16_t port_to, bool upnp_enabled, unsigned int *error) +Networking_Core *new_networking_nat(IP ip, uint16_t port_from, uint16_t port_to, TOX_TRAVERSAL_TYPE traversal_type, unsigned int *error) { /* If both from and to are 0, use default port range * If one is 0 and the other is non-0, use the non-0 value as only port @@ -745,10 +784,15 @@ Networking_Core *new_networking_upnp(IP ip, uint16_t port_from, uint16_t port_to *error = 0; #ifdef HAVE_LIBMINIUPNPC - if (upnp_enabled) + if ((traversal_type == TOX_TRAVERSAL_TYPE_UPNP) || (traversal_type == TOX_TRAVERSAL_TYPE_ALL)) upnp_map_port(ntohs(temp->port)); #endif +#ifdef HAVE_LIBNATPMP + if ((traversal_type == TOX_TRAVERSAL_TYPE_NATPMP) || (traversal_type == TOX_TRAVERSAL_TYPE_ALL)) + natpmp_map_port(ntohs(temp->port)); +#endif + return temp; } diff --git a/toxcore/network.h b/toxcore/network.h index d653f450..f77fa2f2 100644 --- a/toxcore/network.h +++ b/toxcore/network.h @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -166,6 +165,33 @@ typedef struct { } IP_Port; +/** + * Type of technology used to try to traverse a NAT. + */ +typedef enum TOX_TRAVERSAL_TYPE { + + /** + * Don't use any particular technology. + */ + TOX_TRAVERSAL_TYPE_NONE, + + /** + * Use UPnP technology. + */ + TOX_TRAVERSAL_TYPE_UPNP, + + /** + * Use NAT-PMP technology. + */ + TOX_TRAVERSAL_TYPE_NATPMP, + + /** + * Use both UPnP and NAT-PMP technologies. + */ + TOX_TRAVERSAL_TYPE_ALL, + +} TOX_TRAVERSAL_TYPE; + /* Does the IP6 struct a contain an IPv4 address in an IPv6 one? */ #define IPV6_IPV4_IN_V6(a) ((a.uint64[0] == 0) && (a.uint32[2] == htonl (0xffff))) @@ -379,7 +405,7 @@ void networking_poll(Networking_Core *net); */ Networking_Core *new_networking(IP ip, uint16_t port); Networking_Core *new_networking_ex(IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error); -Networking_Core *new_networking_upnp(IP ip, uint16_t port_from, uint16_t port_to, bool upnp_enabled, unsigned int *error); +Networking_Core *new_networking_nat(IP ip, uint16_t port_from, uint16_t port_to, TOX_TRAVERSAL_TYPE traversal_type, unsigned int *error); /* Function to cleanup networking stuff (doesn't do much right now). */ void kill_networking(Networking_Core *net); diff --git a/toxcore/tox.c b/toxcore/tox.c index 88ad79f6..08824b1f 100644 --- a/toxcore/tox.c +++ b/toxcore/tox.c @@ -101,7 +101,7 @@ void tox_options_default(struct Tox_Options *options) memset(options, 0, sizeof(struct Tox_Options)); options->ipv6_enabled = 1; options->udp_enabled = 1; - options->upnp_enabled = 1; + options->traversal_type = TOX_TRAVERSAL_TYPE_NONE; options->proxy_type = TOX_PROXY_TYPE_NONE; } } @@ -167,7 +167,7 @@ Tox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error) m_options.ipv6enabled = options->ipv6_enabled; m_options.udp_disabled = !options->udp_enabled; - m_options.upnp_enabled = options->upnp_enabled; + m_options.traversal_type = options->traversal_type; m_options.port_range[0] = options->start_port; m_options.port_range[1] = options->end_port; m_options.tcp_server_port = options->tcp_port; diff --git a/toxcore/tox.h b/toxcore/tox.h index 10b0a8af..549a11b8 100644 --- a/toxcore/tox.h +++ b/toxcore/tox.h @@ -27,6 +27,7 @@ #include #include #include +#include "network.h" #ifdef __cplusplus extern "C" { @@ -412,15 +413,9 @@ struct Tox_Options { /** - * Enable the use of UPnP for port forwarding. - * - * When enabled it will automatically make a UPnP-compatible (and enabled) - * router forward port 33445 to you (or whichever port Tox decides to use). - * This should improve tox networking, especially in udp mode. - * Setting this to false will force Tox to not search/use UPnP-compatible - * devices. + * Try to traverse a NAT. */ - bool upnp_enabled; + TOX_TRAVERSAL_TYPE traversal_type; /**