From: Tobias Brunner Date: Fri, 25 Jan 2019 09:56:19 +0000 (+0100) Subject: charon-nm: Add IPv6 support X-Git-Tag: 5.8.0dr2~9^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=05b7f1cbfefcaf42b669cc3777da459801756a40;p=thirdparty%2Fstrongswan.git charon-nm: Add IPv6 support --- diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c index d86b89f8f4..e207ac851c 100644 --- a/src/charon-nm/nm/nm_service.c +++ b/src/charon-nm/nm/nm_service.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2017 Lubomir Rintel * - * Copyright (C) 2013 Tobias Brunner + * Copyright (C) 2013-2019 Tobias Brunner * Copyright (C) 2008-2009 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -51,21 +51,54 @@ typedef struct { NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate)) /** - * convert enumerated handler chunks to a UINT_ARRAY GValue + * Convert an address chunk to a GValue */ -static GVariant* handler_to_variant(nm_handler_t *handler, +static GVariant *addr_to_variant(chunk_t addr) +{ + GVariantBuilder builder; + int i; + + switch (addr.len) + { + case 4: + return g_variant_new_uint32 (*(uint32_t*)addr.ptr); + case 16: + g_variant_builder_init (&builder, G_VARIANT_TYPE ("ay")); + for (i = 0; i < addr.len; i++) + { + g_variant_builder_add (&builder, "y", addr.ptr[i]); + + } + return g_variant_builder_end (&builder); + default: + return NULL; + } +} + +/** + * Convert a host to a GValue + */ +static GVariant *host_to_variant(host_t *host) +{ + return addr_to_variant(host->get_address(host)); +} + +/** + * Convert enumerated handler chunks to a GValue + */ +static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type, configuration_attribute_type_t type) { GVariantBuilder builder; enumerator_t *enumerator; chunk_t *chunk; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("au")); + g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type)); enumerator = handler->create_enumerator(handler, type); while (enumerator->enumerate(enumerator, &chunk)) { - g_variant_builder_add (&builder, "u", *(uint32_t*)chunk->ptr); + g_variant_builder_add_value (&builder, addr_to_variant(*chunk)); } enumerator->destroy(enumerator); @@ -73,57 +106,132 @@ static GVariant* handler_to_variant(nm_handler_t *handler, } /** - * signal IPv4 config to NM, set connection as established + * Signal IP config to NM, set connection as established */ -static void signal_ipv4_config(NMVpnServicePlugin *plugin, - ike_sa_t *ike_sa, child_sa_t *child_sa) +static void signal_ip_config(NMVpnServicePlugin *plugin, + ike_sa_t *ike_sa, child_sa_t *child_sa) { NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); - GVariantBuilder builder; + GVariantBuilder builder, ip4builder, ip6builder; + GVariant *ip4config, *ip6config; enumerator_t *enumerator; - host_t *me, *other; + host_t *me, *other, *vip4 = NULL, *vip6 = NULL; nm_handler_t *handler; g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT); handler = priv->handler; /* NM apparently requires to know the gateway */ other = ike_sa->get_other_host(ike_sa); - g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY, - g_variant_new_uint32 (*(uint32_t*)other->get_address(other).ptr)); + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, + host_to_variant(other)); - /* NM installs this IP address on the interface above, so we use the VIP if - * we got one. - */ + /* pass the first virtual IPs we got or use the physical IP */ enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); - if (!enumerator->enumerate(enumerator, &me)) + while (enumerator->enumerate(enumerator, &me)) { - me = ike_sa->get_my_host(ike_sa); + switch (me->get_family(me)) + { + case AF_INET: + if (!vip4) + { + vip4 = me; + } + break; + case AF_INET6: + if (!vip6) + { + vip6 = me; + } + break; + } } enumerator->destroy(enumerator); - g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, - g_variant_new_uint32 (*(uint32_t*)other->get_address(me).ptr)); + if (!vip4 && !vip6) + { + me = ike_sa->get_my_host(ike_sa); + switch (me->get_family(me)) + { + case AF_INET: + vip4 = me; + break; + case AF_INET6: + vip6 = me; + break; + } + } - g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, - g_variant_new_uint32 (me->get_address(me).len * 8)); + if (vip4) + { + g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, + host_to_variant(vip4)); + g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, + g_variant_new_uint32 (vip4->get_address(vip4).len * 8)); - /* prevent NM from changing the default route. we set our own route in our - * own routing table - */ - g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, - g_variant_new_boolean (TRUE)); + /* prevent NM from changing the default route. we set our own route in our + * own routing table + */ + g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, + g_variant_new_boolean (TRUE)); + g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS, + handler_to_variant(handler, "au", INTERNAL_IP4_DNS)); - g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS, - handler_to_variant(handler, INTERNAL_IP4_DNS)); + g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS, + handler_to_variant(handler, "au", INTERNAL_IP4_NBNS)); + } + + if (vip6) + { + g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS, + host_to_variant(vip6)); + g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX, + g_variant_new_uint32 (vip6->get_address(vip6).len * 8)); + g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT, + g_variant_new_boolean (TRUE)); + g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS, + handler_to_variant(handler, "aay", INTERNAL_IP6_DNS)); + /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */ + } + + ip4config = g_variant_builder_end (&ip4builder); + if (g_variant_n_children (ip4config)) + { + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4, + g_variant_new_boolean (TRUE)); + } + else + { + g_variant_unref (ip4config); + ip4config = NULL; + } - g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS, - handler_to_variant(handler, INTERNAL_IP4_NBNS)); + ip6config = g_variant_builder_end (&ip6builder); + if (g_variant_n_children (ip6config)) + { + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6, + g_variant_new_boolean (TRUE)); + } + else + { + g_variant_unref (ip6config); + ip6config = NULL; + } handler->reset(handler); - nm_vpn_service_plugin_set_ip4_config(plugin, g_variant_builder_end (&builder)); + nm_vpn_service_plugin_set_config (plugin, g_variant_builder_end (&builder)); + if (ip4config) + { + nm_vpn_service_plugin_set_ip4_config (plugin, ip4config); + } + if (ip6config) + { + nm_vpn_service_plugin_set_ip6_config (plugin, ip6config); + } } /** @@ -184,7 +292,7 @@ static bool child_updown(listener_t *listener, ike_sa_t *ike_sa, { /* disable initiate-failure-detection hooks */ private->listener.ike_state_change = NULL; private->listener.child_state_change = NULL; - signal_ipv4_config(private->plugin, ike_sa, child_sa); + signal_ip_config(private->plugin, ike_sa, child_sa); } else {