diff --git a/edge.8 b/edge.8 index 6b6ea9f..2554a57 100644 --- a/edge.8 +++ b/edge.8 @@ -40,6 +40,10 @@ 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\-b \fR<\fIbind ip\fR> +binds edge to the provided local IP address only, defaults to 'any' ip address +if not provided +.TP \fB\-S1\fR ... \fB\-S2\fR do not connect p2p, always use the supernode, \-S1 = via UDP, \-S2 = via TCP diff --git a/include/n2n.h b/include/n2n.h index bf4d6ee..396c8b6 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -220,7 +220,7 @@ int memxor (uint8_t *destination, const uint8_t *source, size_t len); char* sock_to_cstr (n2n_sock_str_t out, const n2n_sock_t * sock); char * ip_subnet_to_str (dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr); -SOCKET open_socket (int local_port, int bind_any, int type); +SOCKET open_socket (int local_port, int bind_any, in_addr_t address, int type); int sock_equal (const n2n_sock_t * a, const n2n_sock_t * b); diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index 0231b6f..4863ccf 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -646,6 +646,7 @@ typedef struct n2n_edge_conf { char *encrypt_key; int register_interval; /**< Interval for supernode registration, also used for UDP NAT hole punching. */ 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) */ 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 4234cfe..7cee431 100644 --- a/src/edge.c +++ b/src/edge.c @@ -177,7 +177,7 @@ static void help (int level) { "[-H] " "[-z]" "\n " - "[-S]" + "[-b ][-S]" "\n\n tap device and " "[-a [static:|dhcp:][/]] " "\n overlay network " @@ -252,6 +252,8 @@ static void help (int level) { printf(" -D | enable PMTU discovery, it can reduce fragmentation but\n" " | causes connections to stall if not properly supported\n"); #endif + printf(" -b | bind the edge to the provided local IP address only,\n" + " | defaults to 'any' ip address if not provided\n"); printf(" -S1 ... -S2 | do not connect p2p, always use the supernode,\n" " | -S1 = via UDP" @@ -589,6 +591,20 @@ static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *e break; } + case 'b': { + if(optargument) { + conf->bind_address = inet_addr(optargument); + + if(conf->bind_address == INADDR_NONE) { + traceEvent(TRACE_WARNING, "Bad address to bind to, binding to any IP address."); + conf->bind_address = INADDR_ANY; + break; + } + } + + break; + } + case 't': { conf->mgmt_port = atoi(optargument); break; @@ -711,6 +727,7 @@ static const struct option long_options[] = { "tap-device", required_argument, NULL, 'd' }, { "euid", required_argument, NULL, 'u' }, { "egid", required_argument, NULL, 'g' }, + { "bind", required_argument, NULL, 'b' }, { "help" , no_argument, NULL, '@' }, /* special character '@' to identify long help case */ { "verbose", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } @@ -724,7 +741,7 @@ static int loadFromCLI (int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tunta u_char c; while ((c = getopt_long(argc, argv, - "k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:I:J:P:S::DL:z::A::Hn:R:" + "k:a:b:c:Eu:g:m:M:s:d:l:p:fvhrt:i:I:J:P:S::DL:z::A::Hn:R:" #ifdef __linux__ "T:" #endif diff --git a/src/edge_utils.c b/src/edge_utils.c index d03ca8a..62f8499 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -214,7 +214,8 @@ int supernode_connect(n2n_edge_t *eee) { (eee->conf.connect_tcp) ? 0 : eee->conf.local_port); eee->sock = open_socket((eee->conf.connect_tcp) ? 0 : eee->conf.local_port, - 1 /* bind ANY */, eee->conf.connect_tcp); + 2 /* bind as provided with next parameter */, eee->conf.bind_address, + eee->conf.connect_tcp); if(eee->sock < 0) { traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", @@ -3090,7 +3091,7 @@ static int edge_init_sockets (n2n_edge_t *eee) { closesocket(eee->udp_multicast_sock); #endif - eee->udp_mgmt_sock = open_socket(eee->conf.mgmt_port, 0 /* bind LOOPBACK */, 0 /* UDP */); + eee->udp_mgmt_sock = open_socket(eee->conf.mgmt_port, 0 /* bind LOOPBACK */, 0, 0 /* UDP */); if(eee->udp_mgmt_sock < 0) { traceEvent(TRACE_ERROR, "Failed to bind management UDP port %u", eee->conf.mgmt_port); return(-2); @@ -3105,7 +3106,7 @@ static int edge_init_sockets (n2n_edge_t *eee) { eee->multicast_peer.addr.v4[2] = 0; eee->multicast_peer.addr.v4[3] = 68; - eee->udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, 1 /* bind ANY */, 0 /* UDP */); + eee->udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, 1 /* bind ANY */, 0, 0 /* UDP */); if(eee->udp_multicast_sock < 0) return(-3); else { @@ -3523,6 +3524,7 @@ void edge_init_conf_defaults (n2n_edge_conf_t *conf) { memset(conf, 0, sizeof(*conf)); + conf->bind_address = INADDR_ANY; /* any address */ conf->local_port = 0 /* any port */; conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ conf->transop_id = N2N_TRANSFORM_ID_NULL; diff --git a/src/example_sn_embed.c b/src/example_sn_embed.c index 5c31741..f09d06c 100644 --- a/src/example_sn_embed.c +++ b/src/example_sn_embed.c @@ -29,12 +29,12 @@ int main () { sss_node.daemon = 0; // Whether to daemonize sss_node.lport = 1234; // Main UDP listen port - sss_node.sock = open_socket(sss_node.lport, 1, 0); + sss_node.sock = open_socket(sss_node.lport, 1, 0, 0); if(-1 == sss_node.sock) { exit(-2); } - sss_node.mgmt_sock = open_socket(5645, 0, 0); // Main UDP management port + sss_node.mgmt_sock = open_socket(5645, 0, 0, 0); // Main UDP management port if(-1 == sss_node.mgmt_sock) { exit(-2); } diff --git a/src/n2n.c b/src/n2n.c index 553bc79..81d0bc4 100644 --- a/src/n2n.c +++ b/src/n2n.c @@ -28,7 +28,7 @@ /* ************************************** */ -SOCKET open_socket (int local_port, int bind_any, int type /* 0 = UDP, TCP otherwise */) { +SOCKET open_socket (int local_port, int bind_any, in_addr_t address, int type /* 0 = UDP, TCP otherwise */) { SOCKET sock_fd; struct sockaddr_in local_address; @@ -50,7 +50,14 @@ SOCKET open_socket (int local_port, int bind_any, int type /* 0 = UDP, TCP other memset(&local_address, 0, sizeof(local_address)); local_address.sin_family = AF_INET; local_address.sin_port = htons(local_port); - local_address.sin_addr.s_addr = htonl(bind_any ? INADDR_ANY : INADDR_LOOPBACK); + if(bind_any == 2) { + // use the provided address for binding + // REVISIT: allow for multiple addresses to be provided, i.e. through several '-b' at cli, + // internally requires a list of in_addr_t addresses + local_address.sin_addr.s_addr = address; + } else { + local_address.sin_addr.s_addr = htonl(bind_any ? INADDR_ANY : INADDR_LOOPBACK); + } if(bind(sock_fd,(struct sockaddr*) &local_address, sizeof(local_address)) == -1) { traceEvent(TRACE_ERROR, "Bind error on local port %u [%s]\n", local_port, strerror(errno)); diff --git a/src/sn.c b/src/sn.c index 659a35e..86df623 100644 --- a/src/sn.c +++ b/src/sn.c @@ -577,7 +577,7 @@ int main (int argc, char * const argv[]) { traceEvent(TRACE_DEBUG, "traceLevel is %d", getTraceLevel()); - sss_node.sock = open_socket(sss_node.lport, 1 /*bind ANY*/, 0 /* UDP */); + sss_node.sock = open_socket(sss_node.lport, 1 /*bind ANY*/, 0, 0 /* UDP */); if(-1 == sss_node.sock) { traceEvent(TRACE_ERROR, "Failed to open main socket. %s", strerror(errno)); exit(-2); @@ -586,7 +586,7 @@ int main (int argc, char * const argv[]) { } #ifdef N2N_HAVE_TCP - sss_node.tcp_sock = open_socket(sss_node.lport, 1 /*bind ANY*/, 1 /* TCP */); + sss_node.tcp_sock = open_socket(sss_node.lport, 1 /*bind ANY*/, 0, 1 /* TCP */); if(-1 == sss_node.tcp_sock) { traceEvent(TRACE_ERROR, "Failed to open auxiliary TCP socket. %s", strerror(errno)); exit(-2); @@ -602,7 +602,7 @@ int main (int argc, char * const argv[]) { } #endif - sss_node.mgmt_sock = open_socket(sss_node.mport, 0 /* bind LOOPBACK */, 0 /* UDP */); + sss_node.mgmt_sock = open_socket(sss_node.mport, 0 /* bind LOOPBACK */, 0, 0 /* UDP */); if(-1 == sss_node.mgmt_sock) { traceEvent(TRACE_ERROR, "Failed to open management socket. %s", strerror(errno)); exit(-2);