diff --git a/toxcore/Makefile.inc b/toxcore/Makefile.inc index db3123d8..37ef20e8 100644 --- a/toxcore/Makefile.inc +++ b/toxcore/Makefile.inc @@ -8,6 +8,8 @@ libtoxcore_la_includedir = $(includedir)/tox libtoxcore_la_SOURCES = ../toxcore/DHT.h \ ../toxcore/DHT.c \ + ../toxcore/nat_traversal.h \ + ../toxcore/nat_traversal.c \ ../toxcore/network.h \ ../toxcore/network.c \ ../toxcore/crypto_core.h \ diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c index e2b5a682..be2b7acf 100644 --- a/toxcore/Messenger.c +++ b/toxcore/Messenger.c @@ -1814,7 +1814,7 @@ Messenger *new_messenger(Messenger_Options *options, unsigned int *error) } if (options->tcp_server_port) { - m->tcp_server = new_TCP_server(options->ipv6enabled, 1, &options->tcp_server_port, m->dht->self_secret_key, m->onion); + m->tcp_server = new_TCP_server_nat(options->ipv6enabled, 1, &options->tcp_server_port, options->traversal_type, m->dht->self_secret_key, m->onion); if (m->tcp_server == NULL) { kill_friend_connections(m->fr_c); diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c index d4944aed..c1c34835 100644 --- a/toxcore/TCP_server.c +++ b/toxcore/TCP_server.c @@ -30,7 +30,9 @@ #include #endif +#include #include "util.h" +#include "nat_traversal.h" /* return 1 on success * return 0 on failure @@ -939,8 +941,17 @@ static sock_t new_listening_TCP_socket(int family, uint16_t port) return sock; } +/** + * Added for reverse compatibility with old new_TCP_server calls. + */ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key, Onion *onion) +{ + return new_TCP_server_nat(ipv6_enabled,num_sockets,ports,TOX_TRAVERSAL_TYPE_NONE,secret_key,onion); +} + +TCP_Server *new_TCP_server_nat(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, TOX_TRAVERSAL_TYPE traversal_type, + const uint8_t *secret_key, Onion *onion) { if (num_sockets == 0 || ports == NULL) return NULL; @@ -999,6 +1010,16 @@ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uin #endif +#ifdef HAVE_LIBMINIUPNPC + if ((traversal_type == TOX_TRAVERSAL_TYPE_UPNP) || (traversal_type == TOX_TRAVERSAL_TYPE_ALL)) + upnp_map_port(NAT_TRAVERSAL_TCP,ntohs(ports[i])); +#endif + +#ifdef HAVE_LIBNATPMP + if ((traversal_type == TOX_TRAVERSAL_TYPE_NATPMP) || (traversal_type == TOX_TRAVERSAL_TYPE_ALL)) + natpmp_map_port(NAT_TRAVERSAL_TCP,ntohs(ports[i])); +#endif + temp->socks_listening[temp->num_listening_socks] = sock; ++temp->num_listening_socks; } diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h index 3f6b18ae..394444ed 100644 --- a/toxcore/TCP_server.h +++ b/toxcore/TCP_server.h @@ -23,6 +23,7 @@ #ifndef TCP_SERVER_H #define TCP_SERVER_H +#include "tox.h" #include "crypto_core.h" #include "onion.h" #include "list.h" @@ -142,10 +143,16 @@ typedef struct { } TCP_Server; /* Create new TCP server instance. + * Added for reverse compatibility with old new_TCP_server calls. */ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key, Onion *onion); +/* Create new TCP server instance. + */ +TCP_Server *new_TCP_server_nat(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, TOX_TRAVERSAL_TYPE traversal_type, + const uint8_t *secret_key, Onion *onion); + /* Run the TCP_server */ void do_TCP_server(TCP_Server *TCP_server); diff --git a/toxcore/nat_traversal.c b/toxcore/nat_traversal.c new file mode 100644 index 00000000..63d52262 --- /dev/null +++ b/toxcore/nat_traversal.c @@ -0,0 +1,140 @@ +/* nat_traversal.c -- Functions to traverse a NAT (UPnP, NAT-PMP). + * + * Copyright (C) 2014 Tox project All Rights Reserved. + * + * This file is part of Tox. + * Tox 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 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see . + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_LIBMINIUPNPC +#include +#include +#include +#include +#endif + +#ifdef HAVE_LIBNATPMP +#include +#endif + +#include "nat_traversal.h" +#include "logger.h" + +#ifdef HAVE_LIBMINIUPNPC +/* Setup port forwarding using UPnP */ +void upnp_map_port(NAT_TRAVERSAL_PROTO proto, uint16_t port) +{ + LOGGER_DEBUG("Attempting to set up UPnP port forwarding"); + + int error = 0; + struct UPNPDev *devlist = NULL; + +#if MINIUPNPC_API_VERSION < 14 + devlist = upnpDiscover(1000, NULL, NULL, 0, 0, &error); +#else + devlist = upnpDiscover(1000, NULL, NULL, 0, 0, 2, &error); +#endif + + if (error) { + LOGGER_WARNING("UPnP discovery failed (error = %d)", error); + return; + } + + struct UPNPUrls urls; + struct IGDdatas data; + char lanaddr[64]; + + error = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); + freeUPNPDevlist(devlist); + if (error) { + if (error == 1) { + LOGGER_INFO("A valid IGD has been found."); + + char portstr[10]; + snprintf(portstr, sizeof(portstr), "%d", port); + + if (proto == NAT_TRAVERSAL_UDP) + error = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, portstr, portstr, lanaddr, "Tox", "UDP", 0, "0"); + else if (proto == NAT_TRAVERSAL_TCP) + error = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, portstr, portstr, lanaddr, "Tox", "TCP", 0, "0"); + else + LOGGER_WARNING("UPnP port mapping failed (unknown NAT_TRAVERSAL_PROTO)"); + + if (error) + LOGGER_WARNING("UPnP port mapping failed (error = %d)", error); + else + LOGGER_INFO("UPnP mapped port %d", port); + } else if (error == 2) + LOGGER_WARNING("IGD was found but reported as not connected."); + else if (error == 3) + LOGGER_WARNING("UPnP device was found but not recoginzed as IGD."); + else + LOGGER_WARNING("Unknown error finding IGD: %d", error); + + FreeUPNPUrls(&urls); + } else + LOGGER_WARNING("No IGD was found."); +} +#endif + + +#ifdef HAVE_LIBNATPMP +/* Setup port forwarding using NAT-PMP */ +void natpmp_map_port(NAT_TRAVERSAL_PROTO proto, 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; + } + + if (proto == NAT_TRAVERSAL_UDP) + error = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, port, port, 3600); + else if (proto == NAT_TRAVERSAL_TCP) + error = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, port, port, 3600); + else { + LOGGER_WARNING("NAT-PMP port mapping failed (unknown NAT_TRAVERSAL_PROTO)"); + closenatpmp(&natpmp); + return; + } + + 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 diff --git a/toxcore/nat_traversal.h b/toxcore/nat_traversal.h new file mode 100644 index 00000000..e622088f --- /dev/null +++ b/toxcore/nat_traversal.h @@ -0,0 +1,53 @@ +/* nat_traversal.h -- Functions to traverse a NAT (UPnP, NAT-PMP). + * + * Copyright (C) 2014 Tox project All Rights Reserved. + * + * This file is part of Tox. + * Tox 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 of the License, or + * (at your option) any later version. + * + * Tox 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 Tox. If not, see . + * + */ + +#ifndef NAT_TRAVERSAL_H +#define NAT_TRAVERSAL_H + +#include + + +/** + * The protocol that will be used by the nat traversal. + */ +#if defined(HAVE_LIBMINIUPNPC) || defined(HAVE_LIBNATPMP) +typedef enum NAT_TRAVERSAL_PROTO { + + /* UDP */ + NAT_TRAVERSAL_UDP, + + /* TCP */ + NAT_TRAVERSAL_TCP, + +} NAT_TRAVERSAL_PROTO; +#endif + + +#ifdef HAVE_LIBMINIUPNPC +/* Setup port forwarding using UPnP */ +void upnp_map_port(NAT_TRAVERSAL_PROTO proto, uint16_t port); +#endif + +#ifdef HAVE_LIBNATPMP +/* Setup port forwarding using NAT-PMP */ +void natpmp_map_port(NAT_TRAVERSAL_PROTO proto, uint16_t port); +#endif + +#endif diff --git a/toxcore/network.c b/toxcore/network.c index 5623e5b5..9139c767 100644 --- a/toxcore/network.c +++ b/toxcore/network.c @@ -42,17 +42,7 @@ #include "network.h" #include "util.h" - -#ifdef HAVE_LIBMINIUPNPC -#include -#include -#include -#include -#endif - -#ifdef HAVE_LIBNATPMP -#include -#endif +#include "nat_traversal.h" #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) @@ -122,96 +112,6 @@ static int inet_pton(sa_family_t family, const char *addrString, void *addrbuf) #endif -#ifdef HAVE_LIBMINIUPNPC -/* Setup port forwarding using UPnP */ -static void upnp_map_port(uint16_t port) -{ - LOGGER_DEBUG("Attempting to set up UPnP port forwarding"); - - int error = 0; - struct UPNPDev *devlist = NULL; - -#if MINIUPNPC_API_VERSION < 14 - devlist = upnpDiscover(1000, NULL, NULL, 0, 0, &error); -#else - devlist = upnpDiscover(1000, NULL, NULL, 0, 0, 2, &error); -#endif - - if (error) { - LOGGER_WARNING("UPnP discovery failed (error = %d)", error); - return; - } - - struct UPNPUrls urls; - struct IGDdatas data; - char lanaddr[64]; - - error = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); - freeUPNPDevlist(devlist); - if (error) { - if (error == 1) { - LOGGER_INFO("A valid IGD has been found."); - - char portstr[10]; - snprintf(portstr, sizeof(portstr), "%d", port); - - error = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, portstr, portstr, lanaddr, "Tox", "UDP", 0, "0"); - if (error) { - LOGGER_WARNING("UPnP port mapping failed (error = %d)", error); - } else { - LOGGER_INFO("UPnP mapped port %d", port); - } - } else if (error == 2) { - LOGGER_WARNING("IGD was found but reported as not connected."); - } else if (error == 3) { - LOGGER_WARNING("UPnP device was found but not recoginzed as IGD."); - } else { - LOGGER_WARNING("Unknown error finding IGD: %d", error); - } - - FreeUPNPUrls(&urls); - } else { - LOGGER_WARNING("No IGD was found."); - } -} -#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 @@ -785,12 +685,12 @@ Networking_Core *new_networking_nat(IP ip, uint16_t port_from, uint16_t port_to, #ifdef HAVE_LIBMINIUPNPC if ((traversal_type == TOX_TRAVERSAL_TYPE_UPNP) || (traversal_type == TOX_TRAVERSAL_TYPE_ALL)) - upnp_map_port(ntohs(temp->port)); + upnp_map_port(NAT_TRAVERSAL_UDP,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)); + natpmp_map_port(NAT_TRAVERSAL_UDP,ntohs(temp->port)); #endif return temp;