diff --git a/include/n2n.h b/include/n2n.h index 42bb342..30e1ba0 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -223,8 +223,6 @@ char * ip_subnet_to_str (dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr); SOCKET open_socket (int local_port, in_addr_t address, int type); int sock_equal (const n2n_sock_t * a, const n2n_sock_t * b); -int detect_local_ip_address (n2n_sock_t* out_sock, - const n2n_edge_t* eee); /* Header encryption */ uint64_t time_stamp (void); diff --git a/src/edge_utils.c b/src/edge_utils.c index 85e757c..4be00bf 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -198,6 +198,53 @@ void reset_sup_attempts (n2n_edge_t *eee) { } +// detect local IP address by probing a connection to the supernode +static int detect_local_ip_address (n2n_sock_t* out_sock, const n2n_edge_t* eee) { + + struct sockaddr_in local_sock; + struct sockaddr_in sn_sock; + socklen_t sock_len = sizeof(local_sock); + SOCKET probe_sock; + int ret = 0; + + out_sock->family = AF_INVALID; + + // always 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))) + // remember the port number + out_sock->port = ntohs(local_sock.sin_port); + else + ret = -1; + + // probe for local IP address + 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; as re-connecting to AF_UNSPEC might not work to release the socket + // on non-UNIXoids, we use a temporary socket + if((int)probe_sock >= 0) { + fill_sockaddr((struct sockaddr*)&sn_sock, sizeof(sn_sock), &eee->curr_sn->sock); + if(connect(probe_sock, (struct sockaddr *)&sn_sock, sizeof(sn_sock)) == 0) { + if((getsockname(probe_sock, (struct sockaddr *)&local_sock, &sock_len) == 0) + && (local_sock.sin_family == AF_INET) + && (sock_len == sizeof(local_sock))) { + memcpy(&(out_sock->addr.v4), &(local_sock.sin_addr.s_addr), IPV4_SIZE); + } else + ret = -4; + } else + ret = -3; + closesocket(probe_sock); + } else + ret = -2; + + out_sock->family = AF_INET; + + return ret; +} + + // open socket, close it before if TCP // in case of TCP, 'connect()' is required int supernode_connect(n2n_edge_t *eee) {