miniupnpd: When enabled perform STUN to learn external IP address and NAT type
Also enable port forwarding when direct (non-NAT) connection or unrestricted NAT 1:1 (without any filtering) is detected.
This commit is contained in:
parent
8e10a1aeab
commit
8c97654d70
|
@ -64,6 +64,7 @@
|
||||||
#include "minissdp.h"
|
#include "minissdp.h"
|
||||||
#include "upnpredirect.h"
|
#include "upnpredirect.h"
|
||||||
#include "upnppinhole.h"
|
#include "upnppinhole.h"
|
||||||
|
#include "upnpstun.h"
|
||||||
#include "miniupnpdtypes.h"
|
#include "miniupnpdtypes.h"
|
||||||
#include "daemonize.h"
|
#include "daemonize.h"
|
||||||
#include "upnpevents.h"
|
#include "upnpevents.h"
|
||||||
|
@ -1028,6 +1029,44 @@ parselan_error:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char ext_addr_str[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
|
int update_ext_ip_addr_from_stun(int init)
|
||||||
|
{
|
||||||
|
struct in_addr if_addr, ext_addr;
|
||||||
|
int restrictive_nat;
|
||||||
|
char if_addr_str[INET_ADDRSTRLEN];
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "STUN: Performing with host=%s and port=%u ...", ext_stun_host, (unsigned)ext_stun_port);
|
||||||
|
|
||||||
|
if (getifaddr(ext_if_name, if_addr_str, INET_ADDRSTRLEN, &if_addr, NULL) < 0) {
|
||||||
|
syslog(LOG_ERR, "STUN: Cannot get IP address for ext interface %s", ext_if_name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (perform_stun(ext_if_name, if_addr_str, ext_stun_host, ext_stun_port, &ext_addr, &restrictive_nat) != 0) {
|
||||||
|
syslog(LOG_ERR, "STUN: Performing STUN failed: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!inet_ntop(AF_INET, &ext_addr, ext_addr_str, sizeof(ext_addr_str))) {
|
||||||
|
syslog(LOG_ERR, "STUN: Function inet_ntop for IP address returned by STUN failed: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "STUN: ... done");
|
||||||
|
|
||||||
|
if ((init || disable_port_forwarding) && !restrictive_nat) {
|
||||||
|
if (addr_is_reserved(&if_addr))
|
||||||
|
syslog(LOG_INFO, "STUN: ext interface %s with IP address %s is now behind unrestricted NAT 1:1 with public IP address %s: Port forwarding is now enabled", ext_if_name, if_addr_str, ext_addr_str);
|
||||||
|
else
|
||||||
|
syslog(LOG_INFO, "STUN: ext interface %s has now public IP address %s: Port forwarding is now enabled", ext_if_name, if_addr_str);
|
||||||
|
} else if ((init || !disable_port_forwarding) && restrictive_nat) {
|
||||||
|
syslog(LOG_INFO, "STUN: ext interface %s with IP address %s is now behind restrictive NAT with public IP address %s: Port forwarding is now impossible", ext_if_name, if_addr_str, ext_addr_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_port_forwarding = restrictive_nat;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* fill uuidvalue_wan and uuidvalue_wcd based on uuidvalue_igd */
|
/* fill uuidvalue_wan and uuidvalue_wcd based on uuidvalue_igd */
|
||||||
void complete_uuidvalues(void)
|
void complete_uuidvalues(void)
|
||||||
{
|
{
|
||||||
|
@ -1141,6 +1180,16 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
||||||
case UPNPEXT_IP:
|
case UPNPEXT_IP:
|
||||||
use_ext_ip_addr = ary_options[i].value;
|
use_ext_ip_addr = ary_options[i].value;
|
||||||
break;
|
break;
|
||||||
|
case UPNPEXT_PERFORM_STUN:
|
||||||
|
if(strcmp(ary_options[i].value, "yes") == 0)
|
||||||
|
SETFLAG(PERFORMSTUN);
|
||||||
|
break;
|
||||||
|
case UPNPEXT_STUN_HOST:
|
||||||
|
ext_stun_host = ary_options[i].value;
|
||||||
|
break;
|
||||||
|
case UPNPEXT_STUN_PORT:
|
||||||
|
ext_stun_port = atoi(ary_options[i].value);
|
||||||
|
break;
|
||||||
case UPNPLISTENING_IP:
|
case UPNPLISTENING_IP:
|
||||||
lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s));
|
lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s));
|
||||||
if (lan_addr == NULL)
|
if (lan_addr == NULL)
|
||||||
|
@ -1337,6 +1386,10 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_PCP */
|
#endif /* ENABLE_PCP */
|
||||||
|
if (GETFLAG(PERFORMSTUN) && !ext_stun_host) {
|
||||||
|
fprintf(stderr, "You must specify ext_stun_host= when ext_perform_stun=yes\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* DISABLE_CONFIG_FILE */
|
#endif /* DISABLE_CONFIG_FILE */
|
||||||
|
|
||||||
|
@ -1613,6 +1666,11 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
||||||
goto print_usage;
|
goto print_usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_ext_ip_addr && GETFLAG(PERFORMSTUN)) {
|
||||||
|
fprintf(stderr, "Error: options ext_ip= and ext_perform_stun=yes cannot be specified together\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (use_ext_ip_addr) {
|
if (use_ext_ip_addr) {
|
||||||
if (inet_pton(AF_INET, use_ext_ip_addr, &addr) != 1) {
|
if (inet_pton(AF_INET, use_ext_ip_addr, &addr) != 1) {
|
||||||
fprintf(stderr, "Error: option ext_ip contains invalid address %s\n", use_ext_ip_addr);
|
fprintf(stderr, "Error: option ext_ip contains invalid address %s\n", use_ext_ip_addr);
|
||||||
|
@ -1941,7 +1999,16 @@ main(int argc, char * * argv)
|
||||||
GETFLAG(ENABLEUPNPMASK) ? "UPnP-IGD " : "",
|
GETFLAG(ENABLEUPNPMASK) ? "UPnP-IGD " : "",
|
||||||
ext_if_name, upnp_bootid);
|
ext_if_name, upnp_bootid);
|
||||||
|
|
||||||
if (!use_ext_ip_addr)
|
if(GETFLAG(PERFORMSTUN))
|
||||||
|
{
|
||||||
|
int ret = update_ext_ip_addr_from_stun(1);
|
||||||
|
if (ret != 0) {
|
||||||
|
syslog(LOG_ERR, "Performing STUN failed. EXITING");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
use_ext_ip_addr = ext_addr_str;
|
||||||
|
}
|
||||||
|
else if (!use_ext_ip_addr)
|
||||||
{
|
{
|
||||||
char if_addr[INET_ADDRSTRLEN];
|
char if_addr[INET_ADDRSTRLEN];
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
|
@ -1951,6 +2018,7 @@ main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
if (addr_is_reserved(&addr)) {
|
if (addr_is_reserved(&addr)) {
|
||||||
syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name);
|
syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name);
|
||||||
|
syslog(LOG_INFO, "You are probably behind NAT, enable option ext_perform_stun=yes to detect public IP address");
|
||||||
disable_port_forwarding = 1;
|
disable_port_forwarding = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2146,6 +2214,8 @@ main(int argc, char * * argv)
|
||||||
if(should_send_public_address_change_notif)
|
if(should_send_public_address_change_notif)
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "should send external iface address change notification(s)");
|
syslog(LOG_INFO, "should send external iface address change notification(s)");
|
||||||
|
if(GETFLAG(PERFORMSTUN))
|
||||||
|
update_ext_ip_addr_from_stun(0);
|
||||||
if (!use_ext_ip_addr)
|
if (!use_ext_ip_addr)
|
||||||
{
|
{
|
||||||
char if_addr[INET_ADDRSTRLEN];
|
char if_addr[INET_ADDRSTRLEN];
|
||||||
|
@ -2156,6 +2226,7 @@ main(int argc, char * * argv)
|
||||||
syslog(LOG_INFO, "Public IP address %s on ext interface %s: Port forwarding is enabled", if_addr, ext_if_name);
|
syslog(LOG_INFO, "Public IP address %s on ext interface %s: Port forwarding is enabled", if_addr, ext_if_name);
|
||||||
} else if (!disable_port_forwarding && reserved) {
|
} else if (!disable_port_forwarding && reserved) {
|
||||||
syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name);
|
syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name);
|
||||||
|
syslog(LOG_INFO, "You are probably behind NAT, enable option ext_perform_stun=yes to detect public IP address");
|
||||||
}
|
}
|
||||||
disable_port_forwarding = reserved;
|
disable_port_forwarding = reserved;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,25 @@
|
||||||
# If the WAN interface has several IP addresses, you
|
# If the WAN interface has several IP addresses, you
|
||||||
# can specify the one to use below
|
# can specify the one to use below
|
||||||
#ext_ip=
|
#ext_ip=
|
||||||
|
# WAN interface must have public IP address. Otherwise it is behind NAT
|
||||||
|
# and port forwarding is impossible. In some cases WAN interface can be
|
||||||
|
# behind unrestricted NAT 1:1 when all incoming traffic is NAT-ed and
|
||||||
|
# routed to WAN interfaces without any filtering. In this cases miniupnpd
|
||||||
|
# needs to know public IP address and it can be learnt by asking external
|
||||||
|
# server via STUN protocol. Following option enable retrieving external
|
||||||
|
# public IP address from STUN server and detection of NAT type. You need
|
||||||
|
# to specify also external STUN server in stun_host option below.
|
||||||
|
# This option is disabled by default.
|
||||||
|
#ext_perform_stun=yes
|
||||||
|
# Specify STUN server, either hostname or IP address
|
||||||
|
# Some public STUN servers:
|
||||||
|
# stun.stunprotocol.org
|
||||||
|
# stun.sipgate.net
|
||||||
|
# stun.xten.com
|
||||||
|
# stun.l.google.com (on non standard port 19302)
|
||||||
|
#ext_stun_host=stun.stunprotocol.org
|
||||||
|
# Specify STUN UDP port, by default it is standard port 3478.
|
||||||
|
#ext_stun_port=3478
|
||||||
|
|
||||||
# LAN network interfaces IPs / networks
|
# LAN network interfaces IPs / networks
|
||||||
# There can be multiple listening IPs for SSDP traffic, in that case
|
# There can be multiple listening IPs for SSDP traffic, in that case
|
||||||
|
|
|
@ -30,6 +30,9 @@ static const struct {
|
||||||
} optionids[] = {
|
} optionids[] = {
|
||||||
{ UPNPEXT_IFNAME, "ext_ifname" },
|
{ UPNPEXT_IFNAME, "ext_ifname" },
|
||||||
{ UPNPEXT_IP, "ext_ip" },
|
{ UPNPEXT_IP, "ext_ip" },
|
||||||
|
{ UPNPEXT_PERFORM_STUN, "ext_perform_stun" },
|
||||||
|
{ UPNPEXT_STUN_HOST, "ext_stun_host" },
|
||||||
|
{ UPNPEXT_STUN_PORT, "ext_stun_port" },
|
||||||
{ UPNPLISTENING_IP, "listening_ip" },
|
{ UPNPLISTENING_IP, "listening_ip" },
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
{ UPNPIPV6_LISTENING_IP, "ipv6_listening_ip" },
|
{ UPNPIPV6_LISTENING_IP, "ipv6_listening_ip" },
|
||||||
|
|
|
@ -17,6 +17,9 @@ enum upnpconfigoptions {
|
||||||
UPNP_INVALID = 0,
|
UPNP_INVALID = 0,
|
||||||
UPNPEXT_IFNAME = 1, /* ext_ifname */
|
UPNPEXT_IFNAME = 1, /* ext_ifname */
|
||||||
UPNPEXT_IP, /* ext_ip */
|
UPNPEXT_IP, /* ext_ip */
|
||||||
|
UPNPEXT_PERFORM_STUN, /* ext_perform_stun */
|
||||||
|
UPNPEXT_STUN_HOST, /* ext_stun_host */
|
||||||
|
UPNPEXT_STUN_PORT, /* ext_stun_port */
|
||||||
UPNPLISTENING_IP, /* listening_ip */
|
UPNPLISTENING_IP, /* listening_ip */
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
UPNPIPV6_LISTENING_IP, /* listening address for IPv6 */
|
UPNPIPV6_LISTENING_IP, /* listening address for IPv6 */
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
/* network interface for internet */
|
/* network interface for internet */
|
||||||
const char * ext_if_name = 0;
|
const char * ext_if_name = 0;
|
||||||
|
|
||||||
|
/* stun host/port configuration */
|
||||||
|
const char * ext_stun_host = 0;
|
||||||
|
uint16_t ext_stun_port = 0;
|
||||||
|
|
||||||
/* file to store leases */
|
/* file to store leases */
|
||||||
#ifdef ENABLE_LEASEFILE
|
#ifdef ENABLE_LEASEFILE
|
||||||
const char* lease_file = 0;
|
const char* lease_file = 0;
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
/* name of the network interface used to access internet */
|
/* name of the network interface used to access internet */
|
||||||
extern const char * ext_if_name;
|
extern const char * ext_if_name;
|
||||||
|
|
||||||
|
/* stun host/port configuration */
|
||||||
|
extern const char * ext_stun_host;
|
||||||
|
extern uint16_t ext_stun_port;
|
||||||
|
|
||||||
/* file to store all leases */
|
/* file to store all leases */
|
||||||
#ifdef ENABLE_LEASEFILE
|
#ifdef ENABLE_LEASEFILE
|
||||||
extern const char * lease_file;
|
extern const char * lease_file;
|
||||||
|
@ -73,6 +77,8 @@ extern int runtime_flags;
|
||||||
#define FORCEIGDDESCV1MASK 0x0800
|
#define FORCEIGDDESCV1MASK 0x0800
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PERFORMSTUN 0x1000
|
||||||
|
|
||||||
#define SETFLAG(mask) runtime_flags |= mask
|
#define SETFLAG(mask) runtime_flags |= mask
|
||||||
#define GETFLAG(mask) (runtime_flags & mask)
|
#define GETFLAG(mask) (runtime_flags & mask)
|
||||||
#define CLEARFLAG(mask) runtime_flags &= ~mask
|
#define CLEARFLAG(mask) runtime_flags &= ~mask
|
||||||
|
|
Loading…
Reference in New Issue