summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGert Doering <gert@greenie.muc.de>2010-01-14 15:53:40 +0100
committerGert Doering <gert@greenie.muc.de>2011-04-24 17:22:35 +0200
commit1840c852c2074421e2a2e0d56b47ed6154d4b198 (patch)
tree702ce20af75c5cd33536a60cc911dac982a42792
parent0b6f1912fc483734da504dfbc6a5a155008806bb (diff)
downloadopenvpn-1840c852c2074421e2a2e0d56b47ed6154d4b198.tar.gz
openvpn-1840c852c2074421e2a2e0d56b47ed6154d4b198.tar.xz
openvpn-1840c852c2074421e2a2e0d56b47ed6154d4b198.zip
new feature: "ifconfig-ipv6-push" (from ccd/ config)
affects options.h, options.c, multi.c benefit: static IPv6 address assignment from radiusplugin (etc) rewritten get_ipv6_addr() to handle IPv6 addresses with and without "/bits" affects route.c and mainly options.c benefit: ifconfig-ipv6, ifconfig-ipv6-pool can now be accept configurations with networks != /64 (the rest of the implementation is not yet completely there, but this is imporant preparation work to be able to add /bits to "push 'ifconfig-ipv6 ...'" later on without breaking clients do not try to add/delete IPv6 routes if no IPv6 on tunnel affects: route.c benefit: avoid error messages, and make IPv6 troubleshooting easier flag as "config error" if --ifconfig-ipv6-pool used without --ifconfig-ipv6 flag as "config error" if --ifconfig-ipv6-pool used without --server print warning if --ifconfig-ipv6 is used without --tun-ipv6 changes documented in more detail in ChangeLog.IPv6 * release patch set 20100114-1 (cherry picked from commit c04f774c7e9bed602818b1fe2ff4e83cf913d471)
-rw-r--r--ChangeLog.IPv642
-rw-r--r--multi.c35
-rw-r--r--options.c140
-rw-r--r--options.h8
-rw-r--r--route.c17
-rw-r--r--route.h2
6 files changed, 212 insertions, 32 deletions
diff --git a/ChangeLog.IPv6 b/ChangeLog.IPv6
index 7c39fc3..4881578 100644
--- a/ChangeLog.IPv6
+++ b/ChangeLog.IPv6
@@ -187,3 +187,45 @@ Mon Jan 4 17:46:58 CET 2010
on the Solaris side via "ndpd.conf" (see ``man ifconfig'').
* release as patch 20100104-1
+
+Fri Jan 8 10:00:50 CET 2010
+
+ * import into git repository
+
+ * options.c: add sanity checks for most typical error cases
+ (--ifconfig-ipv6-pool configured with no --ifconfig-ipv6, etc)
+
+ * options.c: modify get_ipv6_addr() to be more flexible about netbits
+ (optional now, default to /64) and to return the address-without-netbits
+ string now (-> for options that want the IPv6 address in printable
+ form, but without /nn)
+
+ * options.c: modify --ifconfig-ipv6 to optionally accept /netbits,
+ you can do now "ifconfig-ipv6 2001:df8::1/64 2001:df8::2" or just
+ "ifconfig-ipv6 2001:df8::5 2001:df8::7", defaulting to /64
+
+ * options.h: add necessary structure elements for --ifconfig-ipv6-push
+
+ * options.c: implement "parse options" side of --ifconfig-ipv6-push
+
+Tue Jan 12 22:42:09 CET 2010
+
+ * tun.c: in TARGET_NETBSD #ifdef, distinguish between "old" code
+ (IPv4 only, but unmodified read/write) and "new" code (multi-af,
+ extra 32 bit AF on read/write of the tun interface) - pre-4.0
+ NetBSD systems don't have TUNSIFHEAD, no way to have common code.
+
+ * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6 (v4+v6)
+
+ * TEST SUCCESS: NetBSD 3.1/Sparc64: client-ipv6 with route-ipv6 (v4-only)
+
+Thu Jan 14 15:41:50 CET 2010
+
+ * multi.c: if "--ifconfig-push" is used together with "--ifconfig-ipv6-pool"
+ and no "--ifconfig-ipv6-push" is seen, issue warning - the current
+ implementation of pools has IPv6 tied to IPv4, so if v4 does not use
+ the pool, it breaks for IPv6. Not a *big* problem (since there is
+ enough v6, just give those users a static v6 address as well), but needs
+ to be pointed out clearly.
+
+ * release as patch 20100114-1
diff --git a/multi.c b/multi.c
index 4ee575b..6c57423 100644
--- a/multi.c
+++ b/multi.c
@@ -1237,6 +1237,17 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
mi->context.c2.push_ifconfig_defined = true;
mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
+
+ /* the current implementation does not allow "static IPv4, pool IPv6",
+ * (see below) so issue a warning if that happens - don't break the
+ * session, though, as we don't even know if this client WANTS IPv6
+ */
+ if ( mi->context.c1.tuntap->ipv6 &&
+ mi->context.options.ifconfig_ipv6_pool_defined &&
+ ! mi->context.options.push_ifconfig_ipv6_defined )
+ {
+ msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." );
+ }
}
else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */
{
@@ -1294,6 +1305,30 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
msg (D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available");
}
}
+
+ /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the
+ * pool handling with IPv4, the combination "static IPv4, dynamic IPv6"
+ * will fail (because no pool will be allocated in this case).
+ * OTOH, this doesn't make too much sense in reality - and the other
+ * way round ("dynamic IPv4, static IPv6") or "both static" makes sense
+ * -> and so it's implemented right now
+ */
+ if ( mi->context.c1.tuntap->ipv6 &&
+ mi->context.options.push_ifconfig_ipv6_defined )
+ {
+ mi->context.c2.push_ifconfig_ipv6_local =
+ mi->context.options.push_ifconfig_ipv6_local;
+ mi->context.c2.push_ifconfig_ipv6_remote =
+ mi->context.options.push_ifconfig_ipv6_remote;
+ mi->context.c2.push_ifconfig_ipv6_netbits =
+ mi->context.options.push_ifconfig_ipv6_netbits;
+ mi->context.c2.push_ifconfig_ipv6_defined = true;
+
+ msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d",
+ print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ),
+ mi->context.c2.push_ifconfig_ipv6_netbits );
+ }
+
gc_free (&gc);
}
diff --git a/options.c b/options.c
index 09b4293..fcc2d9d 100644
--- a/options.c
+++ b/options.c
@@ -395,6 +395,10 @@ static const char usage_message[] =
"--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"
+ "--ifconfig-ipv6-push local/bits remote : Push an ifconfig-ipv6 option to\n"
+ " remote, overrides --ifconfig-ipv6-pool allocation.\n"
+ " Only valid in a client-specific config file.\n"
+ "--iroute network [netmask] : Route subnet to client.\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"
@@ -881,47 +885,67 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error)
return ret;
}
-/* parse a text string containing an IPv6 address + netbits
+/* helper: parse a text string containing an IPv6 address + netbits
* in "standard format" (2001:dba::/32)
+ * "/nn" is optional, default to /64 if missing
+ *
* return true if parsing succeeded, modify *network and *netbits
+ * return address part without "/nn" in *printable_ipv6 (if != NULL)
*/
bool
get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
- unsigned int * netbits, int msglevel )
+ unsigned int * netbits, char ** printable_ipv6, int msglevel )
{
int rc;
char * sep, * endp;
int bits;
+ struct in6_addr t_network;
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;
- }
+ {
+ bits = 64;
+ }
+ else
+ {
+ 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 ( sep != NULL ) *sep = '\0';
+
+ rc = inet_pton( AF_INET6, prefix_str, &t_network );
+
+ if ( rc == 1 && printable_ipv6 != NULL )
+ {
+ *printable_ipv6 = string_alloc( prefix_str, NULL );
+ }
+
+ if ( sep != NULL ) *sep = '/';
if ( rc != 1 )
- {
- msg (msglevel, "IPv6 prefix '%s': invalid network part", prefix_str);
- return false;
- }
- *netbits = bits;
+ {
+ msg (msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str);
+ return false;
+ }
+
+ if ( netbits != NULL )
+ {
+ *netbits = bits;
+ }
+ if ( network != NULL )
+ {
+ *network = t_network;
+ }
return true; /* parsing OK, values set */
}
@@ -930,7 +954,7 @@ 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 );
+ return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, NULL, M_WARN );
}
static char *
@@ -1073,6 +1097,7 @@ 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);
+ SHOW_BOOL (ifconfig_ipv6_pool_defined);
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);
@@ -1088,6 +1113,9 @@ show_p2mp_parms (const struct options *o)
SHOW_BOOL (push_ifconfig_defined);
msg (D_SHOW_PARMS, " push_ifconfig_local = %s", print_in_addr_t (o->push_ifconfig_local, 0, &gc));
msg (D_SHOW_PARMS, " push_ifconfig_remote_netmask = %s", print_in_addr_t (o->push_ifconfig_remote_netmask, 0, &gc));
+ SHOW_BOOL (push_ifconfig_ipv6_defined);
+ msg (D_SHOW_PARMS, " push_ifconfig_ipv6_local = %s/%d", print_in6_addr (o->push_ifconfig_ipv6_local, 0, &gc), o->push_ifconfig_ipv6_netbits );
+ msg (D_SHOW_PARMS, " push_ifconfig_ipv6_remote = %s", print_in6_addr (o->push_ifconfig_ipv6_remote, 0, &gc));
SHOW_BOOL (enable_c2c);
SHOW_BOOL (duplicate_cn);
SHOW_INT (cf_max);
@@ -1151,7 +1179,7 @@ option_iroute_ipv6 (struct options *o,
ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc);
- if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, msglevel ) < 0 )
+ if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, NULL, msglevel ) < 0 )
{
msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification",
prefix_str);
@@ -1296,6 +1324,7 @@ show_settings (const struct options *o)
SHOW_BOOL (ifconfig_noexec);
SHOW_BOOL (ifconfig_nowarn);
SHOW_STR (ifconfig_ipv6_local);
+ SHOW_INT (ifconfig_ipv6_netbits);
SHOW_STR (ifconfig_ipv6_remote);
#ifdef HAVE_GETTIMEOFDAY
@@ -1985,6 +2014,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--up-delay cannot be used with --mode server");
if (!options->ifconfig_pool_defined && options->ifconfig_pool_persist_filename)
msg (M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool");
+ if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local )
+ msg (M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6");
+ if (options->ifconfig_ipv6_local && !options->tun_ipv6 )
+ msg (M_INFO, "Warning: --ifconfig-ipv6 without --tun-ipv6 will not do IPv6");
+
if (options->auth_user_pass_file)
msg (M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)");
if (options->ccd_exclusive && !options->client_config_dir)
@@ -2016,6 +2050,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
*/
if (options->ifconfig_pool_defined || options->ifconfig_pool_persist_filename)
msg (M_USAGE, "--ifconfig-pool/--ifconfig-pool-persist requires --mode server");
+ if (options->ifconfig_ipv6_pool_defined)
+ msg (M_USAGE, "--ifconfig-ipv6-pool requires --mode server");
if (options->real_hash_size != defaults.real_hash_size
|| options->virtual_hash_size != defaults.virtual_hash_size)
msg (M_USAGE, "--hash-size requires --mode server");
@@ -3894,11 +3930,20 @@ add_option (struct options *options,
}
else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] )
{
+ unsigned int netbits;
+ char * ipv6_local;
+
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] ) )
+ if ( get_ipv6_addr( p[1], NULL, &netbits, &ipv6_local, msglevel ) &&
+ ipv6_addr_safe( p[2] ) )
{
- options->ifconfig_ipv6_local = p[1];
+ if ( netbits < 64 || netbits > 124 )
+ {
+ msg( msglevel, "ifconfig-ipv6: /netbits must be between 64 and 124, not '/%d'", netbits );
+ goto err;
+ }
+ options->ifconfig_ipv6_local = ipv6_local;
+ options->ifconfig_ipv6_netbits = netbits;
options->ifconfig_ipv6_remote = p[2];
}
else
@@ -4945,7 +4990,7 @@ add_option (struct options *options,
unsigned int netbits = 0;
VERIFY_PERMISSION (OPT_P_GENERAL);
- if ( ! get_ipv6_addr (p[1], &network, &netbits, lev) )
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev) )
{
msg (msglevel, "error parsing --server-ipv6 parameter");
goto err;
@@ -4961,7 +5006,7 @@ add_option (struct options *options,
if (p[2]) /* no "nopool" options or similar for IPv6 */
{
- msg (msglevel, "error parsing --server: %s is not a recognized flag", p[3]);
+ msg (msglevel, "error parsing --server-ipv6: %s is not a recognized flag", p[3]);
goto err;
}
}
@@ -5056,7 +5101,7 @@ add_option (struct options *options,
unsigned int netbits = 0;
VERIFY_PERMISSION (OPT_P_GENERAL);
- if ( ! get_ipv6_addr (p[1], &network, &netbits, lev ) )
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev ) )
{
msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters");
goto err;
@@ -5309,6 +5354,43 @@ add_option (struct options *options,
goto err;
}
}
+ else if (streq (p[0], "ifconfig-ipv6-push") && p[1] )
+ {
+ struct in6_addr local, remote;
+ unsigned int netbits;
+
+ VERIFY_PERMISSION (OPT_P_INSTANCE);
+
+ if ( ! get_ipv6_addr( p[1], &local, &netbits, NULL, msglevel ) )
+ {
+ msg (msglevel, "cannot parse --ifconfig-ipv6-push addresses");
+ goto err;
+ }
+
+ if ( p[2] )
+ {
+ if ( !get_ipv6_addr( p[2], &remote, NULL, NULL, msglevel ) )
+ {
+ msg( msglevel, "cannot parse --ifconfig-ipv6-push addresses");
+ goto err;
+ }
+ }
+ else
+ {
+ if ( ! options->ifconfig_ipv6_local ||
+ ! get_ipv6_addr( options->ifconfig_ipv6_local, &remote,
+ NULL, NULL, msglevel ) )
+ {
+ msg( msglevel, "second argument to --ifconfig-ipv6-push missing and no global --ifconfig-ipv6 address set");
+ goto err;
+ }
+ }
+
+ options->push_ifconfig_ipv6_defined = true;
+ options->push_ifconfig_ipv6_local = local;
+ options->push_ifconfig_ipv6_netbits = netbits;
+ options->push_ifconfig_ipv6_remote = remote;
+ }
else if (streq (p[0], "disable"))
{
VERIFY_PERMISSION (OPT_P_INSTANCE);
diff --git a/options.h b/options.h
index 7612807..120ff57 100644
--- a/options.h
+++ b/options.h
@@ -206,6 +206,7 @@ struct options
const char *ifconfig_local;
const char *ifconfig_remote_netmask;
const char *ifconfig_ipv6_local;
+ int ifconfig_ipv6_netbits;
const char *ifconfig_ipv6_remote;
bool ifconfig_noexec;
bool ifconfig_nowarn;
@@ -412,6 +413,10 @@ struct options
bool push_ifconfig_constraint_defined;
in_addr_t push_ifconfig_constraint_network;
in_addr_t push_ifconfig_constraint_netmask;
+ bool push_ifconfig_ipv6_defined; /* IPv6 */
+ struct in6_addr push_ifconfig_ipv6_local; /* IPv6 */
+ int push_ifconfig_ipv6_netbits; /* IPv6 */
+ struct in6_addr push_ifconfig_ipv6_remote; /* IPv6 */
bool enable_c2c;
bool duplicate_cn;
int cf_max;
@@ -735,7 +740,8 @@ void options_string_import (struct options *options,
struct env_set *es);
bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
- unsigned int * netbits, int msglevel );
+ unsigned int * netbits, char ** printable_ipv6,
+ int msglevel );
/*
* inline functions
diff --git a/route.c b/route.c
index 21c6553..4b8e5e4 100644
--- a/route.c
+++ b/route.c
@@ -35,6 +35,7 @@
#include "socket.h"
#include "manage.h"
#include "win32.h"
+#include "options.h"
#include "memdbg.h"
@@ -338,7 +339,7 @@ init_route_ipv6 (struct route_ipv6 *r6,
r6->option = r6o;
r6->defined = false;
- if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, M_WARN ))
+ if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, NULL, M_WARN ))
goto fail;
/* gateway */
@@ -1300,6 +1301,13 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
network = print_in6_addr( network_copy, 0, &gc);
gateway = print_in6_addr( r6->gateway, 0, &gc);
+ if ( !tt->ipv6 )
+ {
+ msg( M_INFO, "add_route_ipv6(): not adding %s/%d, no IPv6 on if %s",
+ network, r6->netbits, device );
+ return;
+ }
+
msg( M_INFO, "add_route_ipv6(%s/%d -> %s metric %d) dev %s",
network, r6->netbits, gateway, r6->metric, device );
@@ -1550,6 +1558,13 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
network = print_in6_addr( r6->network, 0, &gc);
gateway = print_in6_addr( r6->gateway, 0, &gc);
+ if ( !tt->ipv6 )
+ {
+ msg( M_INFO, "delete_route_ipv6(): not deleting %s/%d, no IPv6 on if %s",
+ network, r6->netbits, device );
+ return;
+ }
+
msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits );
#if defined(TARGET_LINUX)
diff --git a/route.h b/route.h
index aeaaf4d..739d12d 100644
--- a/route.h
+++ b/route.h
@@ -130,7 +130,7 @@ struct route_ipv6 {
bool defined;
const struct route_ipv6_option *option;
struct in6_addr network;
- int netbits;
+ unsigned int netbits;
struct in6_addr gateway;
bool metric_defined;
int metric;