Hint when private outbound addr detected

This commit is contained in:
Martin Pulec
2020-12-01 15:05:49 +01:00
parent 90a1543ad2
commit 95056b6ca8
3 changed files with 65 additions and 18 deletions

View File

@@ -48,16 +48,18 @@
#endif // defined HAVE_PCP
#include "debug.h"
#include "rtp/net_udp.h" // socket_error
#include "utils/color_out.h"
#include "utils/nat.h"
#include "utils/net.h"
#define ENABLE_STRNATPMPERR 1
#define STATICLIB 1
#include "ext-deps/libnatpmp-20150609/natpmp.h"
#define DEFAULT_ALLOCATION_TIMEOUT_S 1800
#define PREALLOCATE_S 5 ///< number of seconds that repeated allocation is performed before timeout
#define MOD_NAME "[NAT] "
#define PREALLOCATE_S 5 ///< number of seconds that repeated allocation is performed before timeout
struct ug_nat_traverse {
enum traverse_t {
@@ -206,10 +208,6 @@ static void print_ext_addr(pcp_flow_t* f)
}
#endif // defined HAVE_PCP
#define PCP_ASSERT_EQ(expr, val) { int rc = expr; if (rc != (val)) abort(); }
#define PCP_ASSERT_NEQ(expr, val) { int rc = expr; if (rc == (val)) abort(); }
#define PCP_WAIT_MS 500
static void done_pcp(struct ug_nat_traverse *state)
{
#ifdef HAVE_PCP
@@ -220,26 +218,40 @@ static void done_pcp(struct ug_nat_traverse *state)
#endif
}
#define PCP_WAIT_MS 500
#define NAT_ASSERT_EQ(expr, val) { int rc = expr; if (rc != (val)) { socket_error(#expr); return false; } }
#define NAT_ASSERT_NEQ(expr, val) { int rc = expr; if (rc == (val)) { socket_error(#expr); return false; } }
static bool get_outbound_ip(struct sockaddr_in *out) {
struct sockaddr_in dst = { 0 };
socklen_t src_len = sizeof *out;
dst.sin_family = AF_INET;
dst.sin_port = htons(80);
NAT_ASSERT_EQ(inet_pton(AF_INET, "93.184.216.34", &dst.sin_addr.s_addr), 1);
int fd = socket(AF_INET, SOCK_DGRAM, 0);
NAT_ASSERT_NEQ(fd, -1);
NAT_ASSERT_EQ(connect(fd, (struct sockaddr *) &dst, sizeof dst), 0);
NAT_ASSERT_EQ(getsockname(fd, (struct sockaddr *) out, &src_len), 0);
CLOSESOCKET(fd);
return true;
}
static bool setup_pcp(struct ug_nat_traverse *state, int video_rx_port, int audio_rx_port, int lifetime)
{
#ifdef HAVE_PCP
struct pcp_state *s = &state->nat_state.pcp_state;
struct sockaddr_in src = { 0 };
struct sockaddr_in dst = { 0 };
socklen_t src_len = sizeof src;
s->ctx = pcp_init(ENABLE_AUTODISCOVERY, NULL);
// handle errors
// get our outbound IP address
dst.sin_family = AF_INET;
dst.sin_port = htons(80);
PCP_ASSERT_EQ(inet_pton(AF_INET, "93.184.216.34", &dst.sin_addr.s_addr), 1);
int fd = socket(AF_INET, SOCK_DGRAM, 0);
PCP_ASSERT_NEQ(fd, -1);
PCP_ASSERT_EQ(connect(fd, (struct sockaddr *) &dst, sizeof dst), 0);
PCP_ASSERT_EQ(getsockname(fd, (struct sockaddr *) &src, &src_len), 0);
CLOSESOCKET(fd);
if (!get_outbound_ip(&src)) {
log_msg(LOG_LEVEL_ERROR, MOD_NAME "PCP - cannot get outbound address!\n");
return false;
}
bool ret = true;
if (video_rx_port) {
@@ -450,13 +462,17 @@ static void *nat_traverse_keepalive(void *state) {
* "" - enable with default arguments
* other - start with configuration
* @returns state, NULL on error (or help)
*
* @todo
* Add a hint advicing to enable NAT traversal if we are are receiver with a private address
*/
struct ug_nat_traverse *start_nat_traverse(const char *config, int video_rx_port, int audio_rx_port)
{
if (config == NULL) {
if (video_rx_port != 0 || audio_rx_port != 0) {
struct sockaddr_in out;
if (get_outbound_ip(&out) && is_addr_private((struct sockaddr *) &out)) {
log_msg(LOG_LEVEL_WARNING, MOD_NAME "Private outbound IPv4 address detected and bound to a non-dynamic port. Consider adding '-N' option for NAT traversal.\n");
}
}
return calloc(1, sizeof(struct ug_nat_traverse));
}

View File

@@ -120,6 +120,27 @@ bool is_addr_loopback(struct sockaddr *sa)
}
}
bool is_addr_private(struct sockaddr *sa)
{
switch (sa->sa_family) {
case AF_UNIX:
return true;
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
uint32_t addr = ntohl(sin->sin_addr.s_addr);
return ((addr >> 24U) == 10) || ((addr >> 20U) == 2753) || ((addr >> 16U) == 49320);
}
case AF_INET6:
{
struct sockaddr_in6 *sin = (struct sockaddr_in6 *) sa;
return (sin->sin6_addr.s6_addr[0] & 0xFEU) == 0xFCU; // ULA
}
default:
return false;
}
}
bool is_host_loopback(const char *hostname)
{
int gai_err;

View File

@@ -38,6 +38,15 @@
#ifndef UTILS_NET_H_
#define UTILS_NET_H_
#ifdef __cplusplus
#include <cstddef>
#include <cstdint>
#else
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#endif // __cplusplus
#ifdef __cplusplus
extern "C" {
#endif
@@ -45,6 +54,7 @@ extern "C" {
struct sockaddr_storage;
bool is_addr_linklocal(struct sockaddr *sa);
bool is_addr_loopback(struct sockaddr *sa);
bool is_addr_private(struct sockaddr *sa);
bool is_addr_multicast(const char *addr);
bool is_host_loopback(const char *hostname);
uint16_t socket_get_recv_port(int fd);