diff options
Diffstat (limited to 'options.c')
-rw-r--r-- | options.c | 187 |
1 files changed, 187 insertions, 0 deletions
@@ -172,6 +172,8 @@ static const char usage_message[] = " addresses outside of the subnets used by either peer.\n" " TAP: configure device to use IP address l as a local\n" " endpoint and rn as a subnet mask.\n" + "--ifconfig-ipv6 l r : configure device to use IPv6 address l as local\n" + " endpoint (as a /64) and r as remote endpoint\n" "--ifconfig-noexec : Don't actually execute ifconfig/netsh command, instead\n" " pass --ifconfig parms by environment to scripts.\n" "--ifconfig-nowarn : Don't warn if the --ifconfig option on this side of the\n" @@ -182,6 +184,10 @@ static const char usage_message[] = " netmask default: 255.255.255.255\n" " gateway default: taken from --route-gateway or --ifconfig\n" " Specify default by leaving blank or setting to \"nil\".\n" + "--route-ipv6 network/bits [gateway] [metric] :\n" + " Add IPv6 route to routing table after connection\n" + " is established. Multiple routes can be specified.\n" + " gateway default: taken from --route-ipv6-gateway or --ifconfig\n" "--max-routes n : Specify the maximum number of routes that may be defined\n" " or pulled from a server.\n" "--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n" @@ -370,6 +376,7 @@ static const char usage_message[] = "\n" "Multi-Client Server options (when --mode server is used):\n" "--server network netmask : Helper option to easily configure server mode.\n" + "--server-ipv6 network/bits : Configure IPv6 server mode.\n" "--server-bridge [IP netmask pool-start-IP pool-end-IP] : Helper option to\n" " easily configure ethernet bridging server mode.\n" "--push \"option\" : Push a config file option back to the peer for remote\n" @@ -383,10 +390,13 @@ static const char usage_message[] = "--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n" " data to file, at seconds intervals (default=600).\n" " If seconds=0, file will be treated as read-only.\n" + "--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n" + " to be dynamically allocated to connecting clients.\n" "--ifconfig-push local remote-netmask : Push an ifconfig option to remote,\n" " overrides --ifconfig-pool dynamic allocation.\n" " Only valid in a client-specific config file.\n" "--iroute network [netmask] : Route subnet to client.\n" + "--iroute-ipv6 network/bits : Route IPv6 subnet to client.\n" " Sets up internal routes only.\n" " Only valid in a client-specific config file.\n" "--disable : Client is disabled.\n" @@ -871,6 +881,58 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error) return ret; } +/* parse a text string containing an IPv6 address + netbits + * in "standard format" (2001:dba::/32) + * return true if parsing succeeded, modify *network and *netbits + */ +bool +get_ipv6_addr( const char * prefix_str, struct in6_addr *network, + unsigned int * netbits, int msglevel ) +{ + int rc; + char * sep, * endp; + int bits; + + sep = strchr( prefix_str, '/' ); + if ( sep == NULL ) + { + msg (msglevel, "IPv6 prefix '%s': missing '/'", prefix_str); + return false; + } + + bits = strtol( sep+1, &endp, 10 ); + if ( *endp != '\0' || bits < 0 || bits > 128 ) + { + msg (msglevel, "IPv6 prefix '%s': invalid '/bits' spec", prefix_str); + return false; + } + + /* temporary replace '/' in caller-provided string with '\0', otherwise + * inet_pton() will refuse prefix string + * (alternative would be to strncpy() the prefix to temporary buffer) + */ + + *sep = '\0'; + rc = inet_pton( AF_INET6, prefix_str, network ); + *sep = '/'; + + if ( rc != 1 ) + { + msg (msglevel, "IPv6 prefix '%s': invalid network part", prefix_str); + return false; + } + *netbits = bits; + return true; /* parsing OK, values set */ +} + +static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec ) +{ + struct in6_addr t_addr; + unsigned int t_bits; + + return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, M_WARN ); +} + static char * string_substitute (const char *src, int from, int to, struct gc_arena *gc) { @@ -989,6 +1051,8 @@ show_p2mp_parms (const struct options *o) #if P2MP_SERVER msg (D_SHOW_PARMS, " server_network = %s", print_in_addr_t (o->server_network, 0, &gc)); msg (D_SHOW_PARMS, " server_netmask = %s", print_in_addr_t (o->server_netmask, 0, &gc)); + msg (D_SHOW_PARMS, " server_network_ipv6 = %s", print_in6_addr (o->server_network_ipv6, 0, &gc) ); + SHOW_INT (server_netbits_ipv6); msg (D_SHOW_PARMS, " server_bridge_ip = %s", print_in_addr_t (o->server_bridge_ip, 0, &gc)); msg (D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t (o->server_bridge_netmask, 0, &gc)); msg (D_SHOW_PARMS, " server_bridge_pool_start = %s", print_in_addr_t (o->server_bridge_pool_start, 0, &gc)); @@ -1009,6 +1073,8 @@ show_p2mp_parms (const struct options *o) msg (D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t (o->ifconfig_pool_netmask, 0, &gc)); SHOW_STR (ifconfig_pool_persist_filename); SHOW_INT (ifconfig_pool_persist_refresh_freq); + msg (D_SHOW_PARMS, " ifconfig_ipv6_pool_base = %s", print_in6_addr (o->ifconfig_ipv6_pool_base, 0, &gc)); + SHOW_INT (ifconfig_ipv6_pool_netbits); SHOW_INT (n_bcast_buf); SHOW_INT (tcp_queue_limit); SHOW_INT (real_hash_size); @@ -1076,6 +1142,25 @@ option_iroute (struct options *o, o->iroutes = ir; } +static void +option_iroute_ipv6 (struct options *o, + const char *prefix_str, + int msglevel) +{ + struct iroute_ipv6 *ir; + + ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc); + + if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, msglevel ) < 0 ) + { + msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification", + prefix_str); + return; + } + + ir->next = o->iroutes_ipv6; + o->iroutes_ipv6 = ir; +} #endif /* P2MP_SERVER */ #endif /* P2MP */ @@ -1113,6 +1198,13 @@ rol_check_alloc (struct options *options) options->routes = new_route_option_list (options->max_routes, &options->gc); } +void +rol6_check_alloc (struct options *options) +{ + if (!options->routes_ipv6) + options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc); +} + #ifdef ENABLE_DEBUG static void show_connection_entry (const struct connection_entry *o) @@ -1203,6 +1295,8 @@ show_settings (const struct options *o) SHOW_STR (ifconfig_remote_netmask); SHOW_BOOL (ifconfig_noexec); SHOW_BOOL (ifconfig_nowarn); + SHOW_STR (ifconfig_ipv6_local); + SHOW_STR (ifconfig_ipv6_remote); #ifdef HAVE_GETTIMEOFDAY SHOW_INT (shaper); @@ -1863,8 +1957,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if (options->connection_list) msg (M_USAGE, "<connection> cannot be used with --mode server"); #endif +#if 0 if (options->tun_ipv6) msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server"); +#endif if (options->shaper) msg (M_USAGE, "--shaper cannot be used with --mode server"); if (options->inetd) @@ -2461,6 +2557,8 @@ options_string (const struct options *o, o->topology, o->ifconfig_local, o->ifconfig_remote_netmask, + o->ifconfig_ipv6_local, + o->ifconfig_ipv6_remote, (in_addr_t)0, (in_addr_t)0, false, @@ -3794,6 +3892,21 @@ add_option (struct options *options, goto err; } } + else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] ) + { + VERIFY_PERMISSION (OPT_P_UP); + /* TODO: should we accept address + netbits (2001:db8::1/64) here? */ + if ( ipv6_addr_safe( p[1] ) && ipv6_addr_safe( p[2] ) ) + { + options->ifconfig_ipv6_local = p[1]; + options->ifconfig_ipv6_remote = p[2]; + } + else + { + msg (msglevel, "ifconfig-ipv6 parms '%s' and '%s' must be valid addresses", p[1], p[2]); + goto err; + } + } else if (streq (p[0], "ifconfig-noexec")) { VERIFY_PERMISSION (OPT_P_UP); @@ -4594,6 +4707,26 @@ add_option (struct options *options, } add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]); } + else if (streq (p[0], "route-ipv6") && p[1]) + { + VERIFY_PERMISSION (OPT_P_ROUTE); + rol6_check_alloc (options); + if (pull_mode) + { + if (!ipv6_addr_safe_hexplusbits (p[1])) + { + msg (msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]); + goto err; + } + if (p[2] && !ipv6_addr_safe (p[2])) + { + msg (msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]); + goto err; + } + /* p[3] is metric, if present */ + } + add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]); + } else if (streq (p[0], "max-routes") && p[1]) { int max_routes; @@ -4805,6 +4938,33 @@ add_option (struct options *options, } } } + else if (streq (p[0], "server-ipv6") && p[1] ) + { + const int lev = M_WARN; + struct in6_addr network; + unsigned int netbits = 0; + + VERIFY_PERMISSION (OPT_P_GENERAL); + if ( ! get_ipv6_addr (p[1], &network, &netbits, lev) ) + { + msg (msglevel, "error parsing --server-ipv6 parameter"); + goto err; + } + if ( netbits != 64 ) + { + msg( msglevel, "--server-ipv6 settings: only /64 supported right now (not /%d)", netbits ); + goto err; + } + options->server_ipv6_defined = true; + options->server_network_ipv6 = network; + options->server_netbits_ipv6 = netbits; + + if (p[2]) /* no "nopool" options or similar for IPv6 */ + { + msg (msglevel, "error parsing --server: %s is not a recognized flag", p[3]); + goto err; + } + } else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4]) { const int lev = M_WARN; @@ -4889,6 +5049,28 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->topology = TOP_P2P; } + else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] ) + { + const int lev = M_WARN; + struct in6_addr network; + unsigned int netbits = 0; + + VERIFY_PERMISSION (OPT_P_GENERAL); + if ( ! get_ipv6_addr (p[1], &network, &netbits, lev ) ) + { + msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters"); + goto err; + } + if ( netbits != 64 ) + { + msg( msglevel, "--ifconfig-ipv6-pool settings: only /64 supported right now (not /%d)", netbits ); + goto err; + } + + options->ifconfig_ipv6_pool_defined = true; + options->ifconfig_ipv6_pool_base = network; + options->ifconfig_ipv6_pool_netbits = netbits; + } else if (streq (p[0], "hash-size") && p[1] && p[2]) { int real, virtual; @@ -5084,6 +5266,11 @@ add_option (struct options *options, } option_iroute (options, p[1], netmask, msglevel); } + else if (streq (p[0], "iroute-ipv6") && p[1]) + { + VERIFY_PERMISSION (OPT_P_INSTANCE); + option_iroute_ipv6 (options, p[1], msglevel); + } else if (streq (p[0], "ifconfig-push") && p[1] && p[2]) { in_addr_t local, remote_netmask; |