Merged with guus/1.1
This commit is contained in:
commit
2ec9f1124d
13 changed files with 323 additions and 7 deletions
|
|
@ -186,6 +186,7 @@ sptps_speed_SOURCES = \
|
|||
|
||||
tincd_LDADD = libtincd.la libed25519.la libchacha_poly1305.la libtincconf.la
|
||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS) libtincd.la libtincconf.la libed25519.la libchacha_poly1305.la
|
||||
|
||||
sptps_speed_LDADD = libtincd.la libed25519.la libtincconf.la libchacha_poly1305.la libchacha_poly1305.la
|
||||
sptps_test_LDADD = libtincd.la libed25519.la libtincconf.la libchacha_poly1305.la libchacha_poly1305.la
|
||||
sptps_keypair_LDADD = libed25519.la libtincconf.la libchacha_poly1305.la libtincd.la libchacha_poly1305.la
|
||||
|
|
@ -198,6 +199,15 @@ sptps_keypair_LDADD += -lrt
|
|||
endif
|
||||
endif
|
||||
|
||||
if MINIUPNPC
|
||||
tincd_SOURCES += upnp.h upnp.c
|
||||
tincd_LDADD += $(MINIUPNPC_LIBS)
|
||||
tincd_LDFLAGS = ${tincd_LDFLAGS} -pthread
|
||||
endif
|
||||
|
||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||
sptps_speed_LDADD = -lrt
|
||||
|
||||
LIBS = @LIBS@ -lm
|
||||
|
||||
if TUNEMU
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifdef HAVE_MINIUPNPC
|
||||
#include "upnp.h"
|
||||
#endif
|
||||
|
||||
char *myport;
|
||||
static char *myname;
|
||||
|
|
@ -1083,6 +1086,25 @@ static bool setup_myself(void) {
|
|||
xasprintf(&myself->hostname, "MYSELF port %s", myport);
|
||||
myself->connection->hostname = xstrdup(myself->hostname);
|
||||
|
||||
char *upnp = NULL;
|
||||
get_config_string(lookup_config(config_tree, "UPnP"), &upnp);
|
||||
bool upnp_tcp = false;
|
||||
bool upnp_udp = false;
|
||||
if (upnp) {
|
||||
if (!strcasecmp(upnp, "yes"))
|
||||
upnp_tcp = upnp_udp = true;
|
||||
else if (!strcasecmp(upnp, "udponly"))
|
||||
upnp_udp = true;
|
||||
free(upnp);
|
||||
}
|
||||
if (upnp_tcp || upnp_udp) {
|
||||
#ifdef HAVE_MINIUPNPC
|
||||
upnp_init(upnp_tcp, upnp_udp);
|
||||
#else
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "UPnP was requested, but tinc isn't built with miniupnpc support!");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Done. */
|
||||
|
||||
last_config_check = now.tv_sec;
|
||||
|
|
|
|||
|
|
@ -604,9 +604,12 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
|
|||
|
||||
if(n && n->connection) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name);
|
||||
|
||||
n->connection->outgoing = outgoing;
|
||||
return;
|
||||
if(!n->connection->outgoing) {
|
||||
n->connection->outgoing = outgoing;
|
||||
return;
|
||||
} else {
|
||||
goto remove;
|
||||
}
|
||||
}
|
||||
|
||||
if (!outgoing->config_tree) {
|
||||
|
|
@ -620,11 +623,16 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
|
|||
outgoing->aip = outgoing->ai = get_known_addresses(n);
|
||||
if(!outgoing->ai) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name);
|
||||
return;
|
||||
goto remove;
|
||||
}
|
||||
}
|
||||
|
||||
do_outgoing_connection(outgoing);
|
||||
return;
|
||||
|
||||
remove:
|
||||
list_delete(outgoing_list, outgoing);
|
||||
free(outgoing);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ bool ans_key_h(connection_t *c, const char *request) {
|
|||
cipher_close(from->outcipher);
|
||||
digest_close(from->outdigest);
|
||||
#endif
|
||||
from->status.validkey = false;
|
||||
if (!from->status.sptps) from->status.validkey = false;
|
||||
|
||||
if(compression < 0 || compression > 11) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
|
||||
|
|
|
|||
|
|
@ -1487,6 +1487,9 @@ const var_t variables[] = {
|
|||
{"UDPInfoInterval", VAR_SERVER},
|
||||
{"UDPRcvBuf", VAR_SERVER},
|
||||
{"UDPSndBuf", VAR_SERVER},
|
||||
{"UPnP", VAR_SERVER},
|
||||
{"UPnPDiscoverWait", VAR_SERVER},
|
||||
{"UPnPRefreshPeriod", VAR_SERVER},
|
||||
{"VDEGroup", VAR_SERVER},
|
||||
{"VDEPort", VAR_SERVER},
|
||||
/* Host configuration */
|
||||
|
|
|
|||
164
src/upnp.c
Normal file
164
src/upnp.c
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
upnp.c -- UPnP-IGD client
|
||||
Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "upnp.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "miniupnpc/miniupnpc.h"
|
||||
#include "miniupnpc/upnpcommands.h"
|
||||
#include "miniupnpc/upnperrors.h"
|
||||
|
||||
#include "system.h"
|
||||
#include "logger.h"
|
||||
#include "names.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "utils.h"
|
||||
|
||||
static bool upnp_tcp;
|
||||
static bool upnp_udp;
|
||||
static int upnp_discover_wait = 5;
|
||||
static int upnp_refresh_period = 60;
|
||||
|
||||
// Unfortunately, libminiupnpc devs don't seem to care about API compatibility,
|
||||
// and there are slight changes to function signatures between library versions.
|
||||
// Well, at least they publish a "MINIUPNPC_API_VERSION" constant, so we got that going for us, which is nice.
|
||||
// Differences between API versions are documented in "apiversions.txt" in the libminiupnpc distribution.
|
||||
|
||||
#ifndef MINIUPNPC_API_VERSION
|
||||
#define MINIUPNPC_API_VERSION 0
|
||||
#endif
|
||||
|
||||
static struct UPNPDev *upnp_discover(int delay, int *error) {
|
||||
#if MINIUPNPC_API_VERSION <= 13
|
||||
|
||||
#if MINIUPNPC_API_VERSION < 8
|
||||
#warning "The version of libminiupnpc you're building against seems to be too old. Expect trouble."
|
||||
#endif
|
||||
|
||||
return upnpDiscover(delay, NULL, NULL, false, false, error);
|
||||
|
||||
#elif MINIUPNPC_API_VERSION <= 14
|
||||
|
||||
return upnpDiscover(delay, NULL NULL, false, false, 2, error);
|
||||
|
||||
#else
|
||||
|
||||
#if MINIUPNPC_API_VERSION > 15
|
||||
#warning "The version of libminiupnpc you're building against seems to be too recent. Expect trouble."
|
||||
#endif
|
||||
|
||||
return upnpDiscover(delay, NULL, NULL, UPNP_LOCAL_PORT_ANY, false, 2, error);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void upnp_add_mapping(struct UPNPUrls *urls, struct IGDdatas *data, const char *myaddr, int socket, const char *proto) {
|
||||
// Extract the port from the listening socket.
|
||||
// Note that we can't simply use listen_socket[].sa because this won't have the port
|
||||
// if we're running with Port=0 (dynamically assigned port).
|
||||
sockaddr_t sa;
|
||||
socklen_t salen = sizeof sa;
|
||||
if (getsockname(socket, &sa.sa, &salen)) {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket address: [%d] %s", sockerrno, sockstrerror(sockerrno));
|
||||
return;
|
||||
}
|
||||
char *port;
|
||||
sockaddr2str(&sa, NULL, &port);
|
||||
if (!port) {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket port");
|
||||
return;
|
||||
}
|
||||
|
||||
// Use a lease twice as long as the refresh period so that the mapping won't expire before we refresh.
|
||||
char lease_duration[16];
|
||||
snprintf(lease_duration, sizeof lease_duration, "%d", upnp_refresh_period * 2);
|
||||
|
||||
int error = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, port, port, myaddr, identname, proto, NULL, lease_duration);
|
||||
if (error == 0) {
|
||||
logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Successfully set port mapping (%s:%s %s for %s seconds)", myaddr, port, proto, lease_duration);
|
||||
} else {
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Failed to set port mapping (%s:%s %s for %s seconds): [%d] %s", myaddr, port, proto, lease_duration, error, strupnperror(error));
|
||||
}
|
||||
|
||||
free(port);
|
||||
}
|
||||
|
||||
static void upnp_refresh() {
|
||||
logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Discovering IGD devices");
|
||||
|
||||
int error;
|
||||
struct UPNPDev *devices = upnp_discover(upnp_discover_wait * 1000, &error);
|
||||
if (!devices) {
|
||||
logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] Unable to find IGD devices: [%d] %s", error, strupnperror(error));
|
||||
freeUPNPDevlist(devices);
|
||||
return;
|
||||
}
|
||||
|
||||
struct UPNPUrls urls;
|
||||
struct IGDdatas data;
|
||||
char myaddr[64];
|
||||
int result = UPNP_GetValidIGD(devices, &urls, &data, myaddr, sizeof myaddr);
|
||||
if (result <= 0) {
|
||||
logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] No IGD found");
|
||||
freeUPNPDevlist(devices);
|
||||
return;
|
||||
}
|
||||
logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] IGD found: [%d] %s (local address: %s, service type: %s)", result, urls.controlURL, myaddr, data.first.servicetype);
|
||||
|
||||
for (int i = 0; i < listen_sockets; i++) {
|
||||
if (upnp_tcp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].tcp.fd, "TCP");
|
||||
if (upnp_udp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].udp.fd, "UDP");
|
||||
}
|
||||
|
||||
FreeUPNPUrls(&urls);
|
||||
freeUPNPDevlist(devices);
|
||||
}
|
||||
|
||||
static void *upnp_thread(void *data) {
|
||||
while (true) {
|
||||
time_t start = time(NULL);
|
||||
upnp_refresh();
|
||||
|
||||
// Make sure we'll stick to the refresh period no matter how long upnp_refresh() takes.
|
||||
time_t refresh_time = start + upnp_refresh_period;
|
||||
time_t now = time(NULL);
|
||||
if (now < refresh_time) sleep(refresh_time - now);
|
||||
}
|
||||
|
||||
// TODO: we don't have a clean thread shutdown procedure, so we can't remove the mapping.
|
||||
// this is probably not a concern as long as the UPnP device honors the lease duration,
|
||||
// but considering how bug-riddled these devices often are, that's a big "if".
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void upnp_init(bool tcp, bool udp) {
|
||||
upnp_tcp = tcp;
|
||||
upnp_udp = udp;
|
||||
|
||||
get_config_int(lookup_config(config_tree, "UPnPDiscoverWait"), &upnp_discover_wait);
|
||||
get_config_int(lookup_config(config_tree, "UPnPRefreshPeriod"), &upnp_refresh_period);
|
||||
|
||||
pthread_t thread;
|
||||
int error = pthread_create(&thread, NULL, upnp_thread, NULL);
|
||||
if (error) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to start UPnP-IGD client thread: [%d] %s", error, strerror(error));
|
||||
}
|
||||
}
|
||||
27
src/upnp.h
Normal file
27
src/upnp.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
upnp.h -- UPnP-IGD client
|
||||
Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program 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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __UPNP_H__
|
||||
#define __UPNP_H__
|
||||
|
||||
#include "system.h"
|
||||
|
||||
extern void upnp_init(bool, bool);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue