From 7f1fe9a499b3e3171acb6b19fb5d42fe96ccfd48 Mon Sep 17 00:00:00 2001 From: Logan oos Even <46396513+Logan007@users.noreply.github.com> Date: Sun, 12 Sep 2021 00:22:05 +0545 Subject: [PATCH] allowed edge to optionally auto-detetct local IP address ('-e auto') for advertising as preferred (#776) --- edge.8 | 5 +++-- include/n2n_typedefs.h | 1 + src/edge.c | 14 +++++++++++--- src/edge_utils.c | 43 +++++++++++++++++++++++++++--------------- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/edge.8 b/edge.8 index 8124933..7eb35ca 100644 --- a/edge.8 +++ b/edge.8 @@ -44,10 +44,11 @@ TOS for packets, e.g. 0x48 for SSH like priority enable PMTU discovery, it can reduce fragmentation but causes connections to stall if not properly supported .TP -\fB\-e \fR<\fIlocal ip\fR> +\fB\-e \fR<\fIlocal_ip_address\fR> advertises the provided local IP address as preferred, useful if multicast peer detection is not available, e.g. -disabled on routers +disabled on routers. \fB\-e auto\fR tries auto-detection of +local IP address. .TP \fB\-S1\fR ... \fB\-S2\fR do not connect p2p, always use the supernode, diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index 7146303..752cf3b 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -652,6 +652,7 @@ typedef struct n2n_edge_conf { int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */ in_addr_t bind_address; /**< The address to bind to if provided (-b) */ n2n_sock_t preferred_sock; /**< propagated local sock for better p2p in LAN (-e) */ + uint8_t preferred_sock_auto; /**< indicates desired auto detect for preferred sock */ int local_port; int mgmt_port; uint8_t connect_tcp; /** connection to supernode 0 = UDP; 1 = TCP */ diff --git a/src/edge.c b/src/edge.c index fb487f6..5486cd3 100644 --- a/src/edge.c +++ b/src/edge.c @@ -255,7 +255,8 @@ static void help (int level) { " | causes connections to stall if not properly supported\n"); #endif printf(" -e | advertises the provided local IP address as preferred,\n" - " | useful if multicast peer detection is not available\n"); + " | useful if multicast peer detection is not available,\n" + " | '-e auto' tries IP address auto-detection\n"); printf(" -S1 ... -S2 | do not connect p2p, always use the supernode,\n" " | -S1 = via UDP" @@ -615,8 +616,16 @@ static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *e } case 'e': { + in_addr_t address_tmp; + if(optargument) { - in_addr_t address_tmp = inet_addr(optargument); + + if(!strcmp(optargument, "auto")) { + address_tmp = INADDR_ANY; + conf->preferred_sock_auto = 1; + } else { + address_tmp = inet_addr(optargument); + } memcpy(&(conf->preferred_sock.addr.v4), &(address_tmp), IPV4_SIZE); @@ -1098,7 +1107,6 @@ int main (int argc, char* argv[]) { eee->last_sup = 0; /* if it wasn't zero yet */ eee->curr_sn = eee->conf.supernodes; supernode_connect(eee); - while(runlevel < 5) { now = time(NULL); diff --git a/src/edge_utils.c b/src/edge_utils.c index 24d1f0f..e790912 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -203,8 +203,10 @@ void reset_sup_attempts (n2n_edge_t *eee) { int supernode_connect(n2n_edge_t *eee) { int sockopt; - struct sockaddr_in sock; - int sock_len = sizeof(sock); + struct sockaddr_in sn_sock; + struct sockaddr_in local_sock; + int sock_len = sizeof(local_sock); + SOCKET probe_sock; if((eee->conf.connect_tcp) && (eee->sock >= 0)) { closesocket(eee->sock); @@ -227,18 +229,7 @@ int supernode_connect(n2n_edge_t *eee) { return -1; } - // detetct local port, even/especially if chosen by OS... - if((getsockname(eee->sock, (struct sockaddr *)&sock, &sock_len) == 0) - && (sock.sin_family == AF_INET) - && (sock_len == sizeof(sock))) { - // ... and write to local preferred socket -- no matter if used or not - eee->conf.preferred_sock.port = ntohs(sock.sin_port); - } - - // variable 'sock' gets re-used from here on (for sn) - sock.sin_family = eee->curr_sn->sock.family; - sock.sin_port = htons(eee->curr_sn->sock.port); - memcpy(&(sock.sin_addr.s_addr), &(eee->curr_sn->sock.addr.v4), IPV4_SIZE); + fill_sockaddr((struct sockaddr*)&sn_sock, sizeof(sn_sock), &eee->curr_sn->sock); // set tcp socket to O_NONBLOCK so connect does not hang // requires checking the socket for readiness before sending and receving @@ -249,7 +240,7 @@ int supernode_connect(n2n_edge_t *eee) { #else fcntl(eee->sock, F_SETFL, O_NONBLOCK); #endif - if((connect(eee->sock, (struct sockaddr*)&(sock), sizeof(struct sockaddr)) < 0) + if((connect(eee->sock, (struct sockaddr*)&(sn_sock), sizeof(struct sockaddr)) < 0) && (errno != EINPROGRESS)) { eee->sock = -1; return -1; @@ -275,6 +266,28 @@ int supernode_connect(n2n_edge_t *eee) { traceEvent(TRACE_INFO, "PMTU discovery %s", (eee->conf.disable_pmtu_discovery) ? "disabled" : "enabled"); #endif + // detetct local port even/especially if chosen by OS... + if((getsockname(eee->sock, (struct sockaddr *)&local_sock, &sock_len) == 0) + && (local_sock.sin_family == AF_INET) + && (sock_len == sizeof(local_sock))) { + // ... and write to local preferred socket -- no matter if used or not + eee->conf.preferred_sock.port = ntohs(local_sock.sin_port); + // probe for & overwrite local address only if auto-detection mode + if(eee->conf.preferred_sock_auto) { + probe_sock = socket(PF_INET, SOCK_DGRAM, 0); + // connecting the UDP socket makes getsockname read the local address it uses to connect (to the sn in this case) + // we cannot do it with the real (eee->sock) socket because socket does not accept any conenction from elsewhere then, + // e.g. from another edge instead of the supernode; hence, we use a temporary socket + connect(probe_sock, (struct sockaddr *)&sn_sock, sizeof(sn_sock)); + if((getsockname(probe_sock, (struct sockaddr *)&local_sock, &sock_len) == 0) + && (local_sock.sin_family == AF_INET) + && (sock_len == sizeof(local_sock))) { + memcpy(&(eee->conf.preferred_sock.addr.v4), &(local_sock.sin_addr.s_addr), IPV4_SIZE); + } + close(probe_sock); + } + } + if(eee->cb.sock_opened) eee->cb.sock_opened(eee); }