aboutsummaryrefslogtreecommitdiff
path: root/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'options.c')
-rw-r--r--options.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/options.c b/options.c
index d20578f..09b4293 100644
--- a/options.c
+++ b/options.c
@@ -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;