diff --git a/src/edge.c b/src/edge.c index c9716b9..fd56e6e 100644 --- a/src/edge.c +++ b/src/edge.c @@ -124,8 +124,8 @@ static void help() { #endif /* #ifndef WIN32 */ #ifdef __linux__ "[-T ]" - "[-n cidr:gateway] " #endif + "[-n cidr:gateway] " "[-m ] " "-l \n" " " @@ -182,8 +182,8 @@ static void help() { printf("-S | Do not connect P2P. Always use the supernode.\n"); #ifdef __linux__ printf("-T | TOS for packets (e.g. 0x48 for SSH like priority)\n"); - printf("-n | Route an IPv4 network via the gw. Use 0.0.0.0/0 for the default gw. Can be set multiple times.\n"); #endif + printf("-n | Route an IPv4 network via the gw. Use 0.0.0.0/0 for the default gw. Can be set multiple times.\n"); printf("-v | Make more verbose. Repeat as required.\n"); printf("-t | Management UDP Port (for multiple edges on a machine).\n"); @@ -443,6 +443,7 @@ static int setOption(int optkey, char *optargument, n2n_tuntap_priv_config_t *ec break; } +#endif case 'n': { @@ -480,7 +481,6 @@ static int setOption(int optkey, char *optargument, n2n_tuntap_priv_config_t *ec break; } -#endif case 's': /* Subnet Mask */ { @@ -539,13 +539,13 @@ static const struct option long_options[] = static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tuntap_priv_config_t *ec) { u_char c; - while((c = getopt_long(argc, argv, - "k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z::A::H" + while ((c = getopt_long(argc, argv, + "k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z::A::Hn:" #ifdef __linux__ - "T:n:" + "T:" #endif - , - long_options, NULL)) != '?') { + , + long_options, NULL)) != '?') { if(c == 255) break; setOption(c, optarg, ec, conf); } diff --git a/src/edge_utils.c b/src/edge_utils.c index 1389ab8..9e54087 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -2288,92 +2288,137 @@ static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx) { * the TAP device is destroyed. */ static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) { #ifdef __linux__ - int i; - - for(i=0; inet_addr == 0) && (route->net_bitlen == 0)) { - /* This is a default gateway rule. We need to: - * - * 1. Add a route to the supernode via the host internet gateway - * 2. Add the new default gateway route - * - * Instead of modifying the system default gateway, we use the trick - * of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus - * covering the whole IPv4 range. Such routes in linux take precedence - * over the default gateway (0.0.0.0/0) since are more specific. - * This leaves the default gateway unchanged so that after n2n is - * stopped the cleanup is easier. - * See https://github.com/zerotier/ZeroTierOne/issues/178#issuecomment-204599227 - */ - n2n_sock_t sn; - n2n_route_t custom_route; - uint32_t *a; + return edge_init_routes_linux(eee, routes, num_routes); +#endif - if(eee->sn_route_to_clean) { - traceEvent(TRACE_ERROR, "Only one default gateway route allowed"); - return(-1); - } +#ifdef WIN32 + return edge_init_routes_win(eee, routes, num_routes); +#endif +} - if(eee->conf.sn_num != 1) { - traceEvent(TRACE_ERROR, "Only one supernode supported with routes"); - return(-1); - } +static int edge_init_routes_linux(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) { +#ifdef __linux__ + int i; + for (i = 0; inet_addr == 0) && (route->net_bitlen == 0)) { + /* This is a default gateway rule. We need to: + * + * 1. Add a route to the supernode via the host internet gateway + * 2. Add the new default gateway route + * + * Instead of modifying the system default gateway, we use the trick + * of adding a route to the networks 0.0.0.0/1 and 128.0.0.0/1, thus + * covering the whole IPv4 range. Such routes in linux take precedence + * over the default gateway (0.0.0.0/0) since are more specific. + * This leaves the default gateway unchanged so that after n2n is + * stopped the cleanup is easier. + * See https://github.com/zerotier/ZeroTierOne/issues/178#issuecomment-204599227 + */ + n2n_sock_t sn; + n2n_route_t custom_route; + uint32_t *a; + + if (eee->sn_route_to_clean) { + traceEvent(TRACE_ERROR, "Only one default gateway route allowed"); + return(-1); + } - if(supernode2addr(&sn, eee->conf.sn_ip_array[0]) < 0) - return(-1); + if (eee->conf.sn_num != 1) { + traceEvent(TRACE_ERROR, "Only one supernode supported with routes"); + return(-1); + } - if(sn.family != AF_INET) { - traceEvent(TRACE_ERROR, "Only IPv4 routes supported"); - return(-1); - } + if (supernode2addr(&sn, eee->conf.sn_ip_array[0]) < 0) + return(-1); - a = (u_int32_t*)sn.addr.v4; - custom_route.net_addr = *a; - custom_route.net_bitlen = 32; - custom_route.gateway = get_gateway_ip(); + if (sn.family != AF_INET) { + traceEvent(TRACE_ERROR, "Only IPv4 routes supported"); + return(-1); + } - if(!custom_route.gateway) { - traceEvent(TRACE_ERROR, "could not determine the gateway IP address"); - return(-1); - } + a = (u_int32_t*)sn.addr.v4; + custom_route.net_addr = *a; + custom_route.net_bitlen = 32; + custom_route.gateway = get_gateway_ip(); - /* ip route add supernode via internet_gateway */ - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0) - return(-1); + if (!custom_route.gateway) { + traceEvent(TRACE_ERROR, "could not determine the gateway IP address"); + return(-1); + } - /* Save the route to delete it when n2n is stopped */ - eee->sn_route_to_clean = calloc(1, sizeof(n2n_route_t)); + /* ip route add supernode via internet_gateway */ + if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, -1) < 0) + return(-1); - /* Store a copy of the rules into the runtime to delete it during shutdown */ - if(eee->sn_route_to_clean) - *eee->sn_route_to_clean = custom_route; + /* Save the route to delete it when n2n is stopped */ + eee->sn_route_to_clean = calloc(1, sizeof(n2n_route_t)); - /* ip route add 0.0.0.0/1 via n2n_gateway */ - custom_route.net_addr = 0; - custom_route.net_bitlen = 1; - custom_route.gateway = route->gateway; + /* Store a copy of the rules into the runtime to delete it during shutdown */ + if (eee->sn_route_to_clean) + *eee->sn_route_to_clean = custom_route; - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) - return(-1); + /* ip route add 0.0.0.0/1 via n2n_gateway */ + custom_route.net_addr = 0; + custom_route.net_bitlen = 1; + custom_route.gateway = route->gateway; - /* ip route add 128.0.0.0/1 via n2n_gateway */ - custom_route.net_addr = 128; - custom_route.net_bitlen = 1; - custom_route.gateway = route->gateway; + if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) + return(-1); - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) - return(-1); - } else { - /* ip route add net via n2n_gateway */ - if(routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0) - return(-1); + /* ip route add 128.0.0.0/1 via n2n_gateway */ + custom_route.net_addr = 128; + custom_route.net_bitlen = 1; + custom_route.gateway = route->gateway; + + if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, &custom_route, eee->device.if_idx) < 0) + return(-1); + } + else { + /* ip route add net via n2n_gateway */ + if (routectl(RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, route, eee->device.if_idx) < 0) + return(-1); + } } - } #endif - return(0); + return(0); +} + +static int edge_init_routes_win(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes) +{ +#ifdef WIN32 + int i; + struct in_addr net_addr, gateway; + char c_net_addr[32]; + char c_gateway[32]; + char cmd[256]; + + for (i = 0; i < num_routes; i++) + { + n2n_route_t *route = &routes[i]; + if ((route->net_addr == 0) && (route->net_bitlen == 0)) + { + traceEvent(TRACE_NORMAL, "Warning: The 0.0.0.0/0 route settings are not supported on Windows"); + return (-1); + } + else + { + /* ip route add net via n2n_gateway */ + memcpy(&net_addr, &(route->net_addr), sizeof(net_addr)); + memcpy(&gateway, &(route->gateway), sizeof(gateway)); + _snprintf(c_net_addr, sizeof(c_net_addr), inet_ntoa(net_addr)); + _snprintf(c_gateway, sizeof(c_gateway), inet_ntoa(gateway)); + _snprintf(cmd, sizeof(cmd), "route add %s/%d %s > nul", c_net_addr, route->net_bitlen, c_gateway); + traceEvent(TRACE_NORMAL, "ROUTE CMD = '%s'\n", cmd); + system(cmd); + } + } + +#endif // WIN32 + + return (0); } /* ************************************** */