NAT traversal: add support for TCP relays

This commit is contained in:
Ansa89 2016-03-25 13:52:24 +01:00
parent 5f3dc97eef
commit 2e9a731ff3
7 changed files with 227 additions and 104 deletions

View File

@ -8,6 +8,8 @@ libtoxcore_la_includedir = $(includedir)/tox
libtoxcore_la_SOURCES = ../toxcore/DHT.h \ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
../toxcore/DHT.c \ ../toxcore/DHT.c \
../toxcore/nat_traversal.h \
../toxcore/nat_traversal.c \
../toxcore/network.h \ ../toxcore/network.h \
../toxcore/network.c \ ../toxcore/network.c \
../toxcore/crypto_core.h \ ../toxcore/crypto_core.h \

View File

@ -1814,7 +1814,7 @@ Messenger *new_messenger(Messenger_Options *options, unsigned int *error)
} }
if (options->tcp_server_port) { 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) { if (m->tcp_server == NULL) {
kill_friend_connections(m->fr_c); kill_friend_connections(m->fr_c);

View File

@ -30,7 +30,9 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#endif #endif
#include <arpa/inet.h>
#include "util.h" #include "util.h"
#include "nat_traversal.h"
/* return 1 on success /* return 1 on success
* return 0 on failure * return 0 on failure
@ -939,8 +941,17 @@ static sock_t new_listening_TCP_socket(int family, uint16_t port)
return sock; 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, TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key,
Onion *onion) 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) if (num_sockets == 0 || ports == NULL)
return NULL; return NULL;
@ -999,6 +1010,16 @@ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uin
#endif #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->socks_listening[temp->num_listening_socks] = sock;
++temp->num_listening_socks; ++temp->num_listening_socks;
} }

View File

@ -23,6 +23,7 @@
#ifndef TCP_SERVER_H #ifndef TCP_SERVER_H
#define TCP_SERVER_H #define TCP_SERVER_H
#include "tox.h"
#include "crypto_core.h" #include "crypto_core.h"
#include "onion.h" #include "onion.h"
#include "list.h" #include "list.h"
@ -142,10 +143,16 @@ typedef struct {
} TCP_Server; } TCP_Server;
/* Create new TCP server instance. /* 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, TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key,
Onion *onion); 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 /* Run the TCP_server
*/ */
void do_TCP_server(TCP_Server *TCP_server); void do_TCP_server(TCP_Server *TCP_server);

140
toxcore/nat_traversal.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_LIBMINIUPNPC
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/miniwget.h>
#include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h>
#endif
#ifdef HAVE_LIBNATPMP
#include <natpmp.h>
#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

53
toxcore/nat_traversal.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef NAT_TRAVERSAL_H
#define NAT_TRAVERSAL_H
#include <stdint.h>
/**
* 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

View File

@ -42,17 +42,7 @@
#include "network.h" #include "network.h"
#include "util.h" #include "util.h"
#include "nat_traversal.h"
#ifdef HAVE_LIBMINIUPNPC
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/miniwget.h>
#include <miniupnpc/upnpcommands.h>
#include <miniupnpc/upnperrors.h>
#endif
#ifdef HAVE_LIBNATPMP
#include <natpmp.h>
#endif
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) #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 #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. /* Check if socket is valid.
* *
* return 1 if 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 #ifdef HAVE_LIBMINIUPNPC
if ((traversal_type == TOX_TRAVERSAL_TYPE_UPNP) || (traversal_type == TOX_TRAVERSAL_TYPE_ALL)) 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 #endif
#ifdef HAVE_LIBNATPMP #ifdef HAVE_LIBNATPMP
if ((traversal_type == TOX_TRAVERSAL_TYPE_NATPMP) || (traversal_type == TOX_TRAVERSAL_TYPE_ALL)) 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 #endif
return temp; return temp;