Send connman mailing list submissions to connman@lists.01.org To subscribe or unsubscribe via email, send a message with subject or body 'help' to connman-requ...@lists.01.org
You can reach the person managing the list at connman-ow...@lists.01.org When replying, please edit your Subject line so it is more specific than "Re: Contents of connman digest..." Today's Topics: 1. [PATCH 06/11] network: Adopt to new IPv6 disabled functionality of ipconfig.c (Jussi Laakkonen) 2. [PATCH 07/11] service: Support IPv6 enable/disable for connected services (Jussi Laakkonen) 3. [PATCH 08/11] provider: Toggle IPv6 on the transport of IPv4 VPN connection (Jussi Laakkonen) 4. [PATCH 09/11] service: Change IPv6 support if split routing value changes on IPv4 VPN (Jussi Laakkonen) 5. [PATCH 10/11] doc: Add note to SingleConnectedTech on IPv4 VPN data leak prevention (Jussi Laakkonen) 6. [PATCH 11/11] TODO: Add task about IPv6 only connection with IPv4 VPN (Jussi Laakkonen) ---------------------------------------------------------------------- Date: Thu, 1 Apr 2021 17:46:13 +0300 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 06/11] network: Adopt to new IPv6 disabled functionality of ipconfig.c To: connman@lists.01.org Message-ID: <20210401144618.12936-7-jussi.laakko...@jolla.com> If a new connection comes up/is manually connected when IPv6 is internally disabled for a IPv4 VPN the IPv6 configuration for the network must be prevented. If the different IPv6 method functions do this then an error is received from ipconfig.c which will propagate to disabling of the new connection completely as network error is triggered. This way IPv6 is silently ignored and forcefully set as disabled to be re-enabled when VPN is disconnected. Disable force disabled in IPv6 ipconfig when clearing the IPv6 address in set_disconnect(). This is required when re-enabling IPv6 for kernel to clear the values in order to return the proper /proc values for the interface in case IPv6 was disabled for IPv4 VPN. Also restore the original IPv6 method before setting disconnected to make kernel know about the changes as well. Otherwise IPv6 on some occasions is not enabled on the interface when, e.g., changing to another service of same type technology. Adapt to ipconfig.c changes by reporting back potential errors. --- src/network.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/network.c b/src/network.c index 256e3b5f..388e9bbe 100644 --- a/src/network.c +++ b/src/network.c @@ -610,7 +610,9 @@ static int manual_ipv6_set(struct connman_network *network, if (!__connman_ipconfig_get_local(ipconfig_ipv6)) __connman_service_read_ip6config(service); - __connman_ipconfig_enable_ipv6(ipconfig_ipv6); + err = __connman_ipconfig_enable_ipv6(ipconfig_ipv6); + if (err) + return err; err = __connman_ipconfig_address_add(ipconfig_ipv6); if (err < 0) { @@ -898,7 +900,8 @@ static void autoconf_ipv6_set(struct connman_network *network) __connman_ipconfig_enable(ipconfig); - __connman_ipconfig_enable_ipv6(ipconfig); + if (__connman_ipconfig_enable_ipv6(ipconfig)) + return; __connman_ipconfig_address_remove(ipconfig); @@ -952,6 +955,21 @@ static void set_disconnected(struct connman_network *network) ipconfig_ipv6); ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4); + + /* + * If disconnecting a force disabled IPv6 restore the old method and + * remove force disabled to allow enabling of IPv6 for kernel to + * cleanup the addresses. This is crucial when changing to another same + * type service, e.g., WiFi in order to properly get IPv6 re-enabled + * via kernel. + */ + if (ipconfig_ipv6 && __connman_ipconfig_ipv6_get_force_disabled( + ipconfig_ipv6)) { + __connman_ipconfig_ipv6_set_force_disabled(ipconfig_ipv6, + false); + __connman_ipconfig_ipv6_method_restore(ipconfig_ipv6); + } + ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6); DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method); @@ -1915,6 +1933,25 @@ int __connman_network_enable_ipconfig(struct connman_network *network, return -ENOSYS; case CONNMAN_IPCONFIG_TYPE_IPV6: + /* + * If enabling IPv6 for new network while IPv6 support is + * disabled enforce the ipconfig to be completely disabled to + * avoid IPv6 address being set. + */ + if (!__connman_ipconfig_get_ipv6_support()) { + DBG("ipv6 not enabled, force disable %p", ipconfig); + + __connman_ipconfig_ipv6_method_save(ipconfig); + __connman_ipconfig_set_method(ipconfig, + CONNMAN_IPCONFIG_METHOD_OFF); + + __connman_ipconfig_disable_ipv6(ipconfig); + __connman_ipconfig_ipv6_set_force_disabled(ipconfig, + true); + + return 0; + } + set_configuration(network, type); method = __connman_ipconfig_get_method(ipconfig); -- 2.20.1 ------------------------------ Date: Thu, 1 Apr 2021 17:46:14 +0300 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 07/11] service: Support IPv6 enable/disable for connected services To: connman@lists.01.org Message-ID: <20210401144618.12936-8-jussi.laakko...@jolla.com> Implement support for enabling/disabling IPv6 for every connected service exluding the VPN and including the VPN transport. This is used when an IPv4 VPN is connected to avoid leaking of data to IPv6 network by disabling IPv6 for all services when connected and when disconnecting the VPN re-enable IPv6. When disabling the old IPv6 method is recorded, address is cleared, IPv6 network is disconnected, then turned to idle and notified. When enabling IPv6 method is restored and simply enabling the ipconfig is required in order to get the IPv6 connectivity to be resumed. In case the transport has been disconnected prior to VPN disconnect it is imperative to do the changes only to ipconfig to avoid changing the state of the transport. --- src/connman.h | 2 + src/service.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/src/connman.h b/src/connman.h index 0a8adbd3..598e2970 100644 --- a/src/connman.h +++ b/src/connman.h @@ -701,6 +701,8 @@ int __connman_service_compare(const struct connman_service *a, struct connman_service *__connman_service_lookup_from_index(int index); struct connman_service *__connman_service_create_from_network(struct connman_network *network); +void __connman_service_set_ipv6_for_connected(struct connman_service *vpn, + struct connman_service *transport, bool enable); struct connman_service *__connman_service_create_from_provider(struct connman_provider *provider); bool __connman_service_index_is_default(int index); void __connman_service_update_from_network(struct connman_network *network); diff --git a/src/service.c b/src/service.c index 7dfa89f2..b164de3a 100644 --- a/src/service.c +++ b/src/service.c @@ -7233,6 +7233,120 @@ struct connman_service *__connman_service_lookup_from_index(int index) return NULL; } +struct set_ipv6_data { + struct connman_service *vpn; + struct connman_service *transport; + bool enable; +}; + +static void set_ipv6_for_service(gpointer value, gpointer user_data) +{ + struct connman_service *service = value; + struct connman_ipconfig *ipconfig; + struct connman_network *network; + struct set_ipv6_data *data = user_data; + int err; + + /* + * Ignore the vpn and not connected unless it is the transport. It is + * imperative to set the IPv6 parameters on the transport even though + * it is being disconnected. This ensures that the interface it is/was + * using is set to the previous state. + */ + if ((!is_connected(service->state) || service == data->vpn) && + service != data->transport) + return; + + DBG("%s service %p/%s", data->enable ? "enable" : "disable", service, + service->identifier); + + network = service->network; + if (!network) + return; + + ipconfig = service->ipconfig_ipv6; + if (!ipconfig) + return; + + if (data->enable == __connman_ipconfig_ipv6_is_enabled(ipconfig)) { + DBG("Ignore service, IPv6 already %s", + data->enable ? "enabled" : "disabled"); + return; + } + + if (data->enable) { + /* Restore the original method before enabling. */ + __connman_ipconfig_ipv6_method_restore(ipconfig); + + /* To allow enabling remove force disabled. */ + __connman_ipconfig_ipv6_set_force_disabled(ipconfig, false); + + /* + * When changing to use another service the current service + * used as transport is disconnected first and in that case + * simply enable IPv6 via ipconfig instead of network to avoid + * state changes. + */ + if (service == data->transport && + !is_connected(service->state)) + err = __connman_ipconfig_enable_ipv6(ipconfig); + else + err = __connman_network_enable_ipconfig(network, + ipconfig); + + if (err) + connman_warn("cannot re-enable IPv6 on %s", + service->identifier); + } else { + /* Save the IPv6 method for enabling and clear network conf */ + __connman_ipconfig_ipv6_method_save(ipconfig); + __connman_network_clear_ipconfig(network, ipconfig); + __connman_ipconfig_gateway_remove(ipconfig); + + /* Disconnect and clear address */ + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV6); + __connman_ipconfig_address_remove(ipconfig); + + /* + * Disables IPv6 on ipconfig and sets the force_disabled + * as true. + */ + __connman_ipconfig_set_method(ipconfig, + CONNMAN_IPCONFIG_METHOD_OFF); + err = __connman_network_enable_ipconfig(network, ipconfig); + if (err) + connman_warn("cannot disable IPv6 on %s", + service->identifier); + + /* Set force disabled on after disabling. */ + __connman_ipconfig_ipv6_set_force_disabled(ipconfig, true); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); + } + + ipv6_configuration_changed(service); + __connman_notifier_ipconfig_changed(service, ipconfig); +} + +void __connman_service_set_ipv6_for_connected(struct connman_service *vpn, + struct connman_service *transport, bool enable) +{ + struct set_ipv6_data data = { + .vpn = vpn, + .transport = transport, + .enable = enable + }; + + DBG("%s vpn %p transport %p", enable ? "enable" : "disable", vpn, + transport); + + g_list_foreach(service_list, set_ipv6_for_service, &data); +} + const char *connman_service_get_identifier(struct connman_service *service) { return service ? service->identifier : NULL; -- 2.20.1 ------------------------------ Date: Thu, 1 Apr 2021 17:46:15 +0300 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 08/11] provider: Toggle IPv6 on the transport of IPv4 VPN connection To: connman@lists.01.org Message-ID: <20210401144618.12936-9-jussi.laakko...@jolla.com> Add support to disable/enable IPv6 on the transport of the VPN that uses IPv4. This change eliminates the data and DNS leak to IPv6 when dual-stack transport is used on a IPv4 only VPN. Otherwise with an AAAA record for a requested hostname the traffic can bypass the VPN to transport's IPv6 network if the DNS server of the VPN serves both A and AAAA requests. If multiple connection technologies (SingleConnectedTechnology omitted or false) are in use IPv6 support is changed internally as well. The value of SingleConnectedTechnology does not change run-time so there is no possibility for inconsistent state. When re-enabling IPv6 enable the internal IPv6 suppor prior to resuming IPv6 functionality on service basis. When disabling IPv6 do the internal disabling after the services are handled. This is due to the changes that were required for network.c to get new connections enabled but IPv6 disabled if IPv6 is internally disabled. Disable IPv6 when state changes to READY (also ONLINE but that is never used with VPNs) for IPv4 provider. Allow to do the change only for VPNs that are connected (READY). When provider state changes to DISCONNECT or FAILURE re-enable IPv6 the transport using the recorded method. Prevent running the function as a loop within loop. This might happen when current transport service is disconnected that in turn causes the VPN to be disconnected as well. Then while looping through the services another disconnect on the transport will get provider_indicate_state() called again. --- src/connman.h | 3 ++ src/provider.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/src/connman.h b/src/connman.h index 598e2970..58f49b5d 100644 --- a/src/connman.h +++ b/src/connman.h @@ -683,6 +683,9 @@ int __connman_provider_indicate_error(struct connman_provider *provider, int __connman_provider_connect(struct connman_provider *provider, const char *dbus_sender); int __connman_provider_remove_by_path(const char *path); +int __connman_provider_set_ipv6_for_connected( + struct connman_provider *provider, + bool enable); void __connman_provider_cleanup(void); int __connman_provider_init(void); diff --git a/src/provider.c b/src/provider.c index 51bbfdf4..ecd4a342 100644 --- a/src/provider.c +++ b/src/provider.c @@ -121,11 +121,128 @@ void connman_provider_unref_debug(struct connman_provider *provider, provider_destruct(provider); } +static bool ipv6_change_running = false; + +int __connman_provider_set_ipv6_for_connected( + struct connman_provider *provider, bool enable) +{ + struct connman_service *service; + struct connman_service *transport; + struct connman_ipconfig *ipconfig; + enum connman_service_state state; + const char *transport_ident; + bool single_connected_tech; + + if (ipv6_change_running) + return -EALREADY; + + if (!provider) + return -EINVAL; + + DBG("provider %p %s", provider, enable ? "enable" : "disable"); + + service = provider->vpn_service; + if (!service) + return -EINVAL; + + /* + * Allow only when the VPN service is in ready state, service state + * is changed to ready before provider when connecting and changed + * away from ready after provider state is changed. + */ + state = connman_service_get_state(service); + if (state != CONNMAN_SERVICE_STATE_READY) + return 0; + + /* + * If a VPN changes from non-split routed to split routed then IPv6 on + * the transport must be re-enabled. + */ + if (__connman_service_is_split_routing(service) && !enable) + return 0; + + ipconfig = __connman_service_get_ip6config(service); + if (__connman_ipconfig_ipv6_is_enabled(ipconfig)) + return 0; + + single_connected_tech = + connman_setting_get_bool("SingleConnectedTechnology"); + + /* If re-enabling IPv6 set the internal status prior to enabling IPv6 + * for connected servises to allow the IPv6 ipconfig enabled check to + * return correct value. + */ + if (enable && !single_connected_tech) + __connman_ipconfig_set_ipv6_support(enable); + + transport_ident = __connman_provider_get_transport_ident(provider); + transport = connman_service_lookup_from_identifier(transport_ident); + + /* In case a sevice of same type that the current transport is changed + * to use another, e.g., WiFi AP, then the service is first + * disconnected which in turn calls provider_indicate_state() when + * provider is being disconnected and this function gets called. In + * such case another call to provider_indicate_state() can be made + * while traversing through the services list with + * __connman_service_set_ipv6_for_connected() to disconnect this + * provider. Therefore, using this boolean can prevent a loop within + * loop from being executed. + */ + ipv6_change_running = true; + + /* Set IPv6 for connected, excluding VPN and include transport. */ + __connman_service_set_ipv6_for_connected(service, transport, enable); + + /* + * Disable internal IPv6 use after disabling IPv6 for the connected + * services to allow IPv6 enabled check to work. + */ + if (!enable && !single_connected_tech) + __connman_ipconfig_set_ipv6_support(enable); + + ipv6_change_running = false; + + return 0; +} + static int provider_indicate_state(struct connman_provider *provider, enum connman_service_state state) { + int err; + DBG("state %d", state); + switch (state) { + case CONNMAN_SERVICE_STATE_UNKNOWN: + case CONNMAN_SERVICE_STATE_IDLE: + case CONNMAN_SERVICE_STATE_ASSOCIATION: + case CONNMAN_SERVICE_STATE_CONFIGURATION: + break; + case CONNMAN_SERVICE_STATE_READY: + case CONNMAN_SERVICE_STATE_ONLINE: + if (provider->family != AF_INET) + break; + + err = __connman_provider_set_ipv6_for_connected(provider, + false); + if (err && err != -EALREADY) + DBG("cannot disable IPv6 on provider %p transport", + provider); + break; + case CONNMAN_SERVICE_STATE_DISCONNECT: + case CONNMAN_SERVICE_STATE_FAILURE: + if (provider->family != AF_INET) + break; + + err = __connman_provider_set_ipv6_for_connected(provider, + true); + if (err && err != -EALREADY) + DBG("cannot enable IPv6 on provider %p transport", + provider); + + break; + } + __connman_service_ipconfig_indicate_state(provider->vpn_service, state, CONNMAN_IPCONFIG_TYPE_IPV4); -- 2.20.1 ------------------------------ Date: Thu, 1 Apr 2021 17:46:16 +0300 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 09/11] service: Change IPv6 support if split routing value changes on IPv4 VPN To: connman@lists.01.org Message-ID: <20210401144618.12936-10-jussi.laakko...@jolla.com> Enable/disable IPv6 on VPNs transport when the split routing value is changed. This is important in both cases when a connected IPv4 VPN has the value changed as with split routing -> non-split routing IPv6 should be disabled as well as non-split-routing -> split routed IPv6 should be re-enabled. --- src/service.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/service.c b/src/service.c index b164de3a..07032e8f 100644 --- a/src/service.c +++ b/src/service.c @@ -388,12 +388,18 @@ void __connman_service_split_routing_changed(struct connman_service *service) service->identifier); } +static bool is_connected(enum connman_service_state state); + void __connman_service_set_split_routing(struct connman_service *service, bool value) { + bool change; + if (service->type != CONNMAN_SERVICE_TYPE_VPN) return; + change = service->do_split_routing != value; + service->do_split_routing = value; if (service->do_split_routing) @@ -401,6 +407,20 @@ void __connman_service_set_split_routing(struct connman_service *service, else service->order = 10; + /* + * Change IPv6 on the VPN transport when split routing value changes + * on a connected IPv4 VPN. + */ + if (connman_provider_get_family(service->provider) == AF_INET && + change && is_connected(service->state)) { + if (__connman_provider_set_ipv6_for_connected( + service->provider, + value)) + DBG("cannot %s IPv6 for VPN service %p provider %p", + value ? "enable" : "disable", + service, service->provider); + } + /* * In order to make sure the value is propagated also when loading the * VPN service signal the value regardless of the value change. -- 2.20.1 ------------------------------ Date: Thu, 1 Apr 2021 17:46:17 +0300 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 10/11] doc: Add note to SingleConnectedTech on IPv4 VPN data leak prevention To: connman@lists.01.org Message-ID: <20210401144618.12936-11-jussi.laakko...@jolla.com> Describe the behavior on having IPv4 VPN connected if IPv6 only connection is attempted to be established with SingleConnectedTech disabled. --- doc/connman.conf.5.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/connman.conf.5.in b/doc/connman.conf.5.in index 2e06b3ef..52e75962 100644 --- a/doc/connman.conf.5.in +++ b/doc/connman.conf.5.in @@ -130,6 +130,10 @@ the only one that will be kept connected. A service connected by the user will be used until going out of network coverage. With this setting enabled applications will notice more network breaks than normal. Default value is false. +NOTE that when this setting is disabled and IPv4 VPN is connected an +IPv6 only connection cannot be connected until VPN is disconnected. +This is a side-effect of preventing data leak to IPv6 when using IPv4 +VPN connections. .TP .BI TetheringTechnologies= technology\fR[,...] List of technologies that are allowed to enable tethering separated by ",". -- 2.20.1 ------------------------------ Date: Thu, 1 Apr 2021 17:46:18 +0300 From: Jussi Laakkonen <jussi.laakko...@jolla.com> Subject: [PATCH 11/11] TODO: Add task about IPv6 only connection with IPv4 VPN To: connman@lists.01.org Message-ID: <20210401144618.12936-12-jussi.laakko...@jolla.com> --- TODO | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/TODO b/TODO index c10b8ce1..8d1ff2b9 100644 --- a/TODO +++ b/TODO @@ -229,6 +229,17 @@ VPN server certificate as it is done now, otherwise indicate error to libopenconnect. +- Figure out way to allow IPv6 service to connect while IPv4 VPN is connected + + Priority: Low + Complexity: C? + + Consider adding a feature to allow IPv6 only connection to connect even when + IPv4 VPN is connected and IPv6 is internally disabled to avoid leaking of data + to IPv6 network. This is a tricky issue, would the VPN be required to disconnect + in such case or just to leave the IPv6 only connection to some pending state + until VPN disconnect happens. + Tools ===== -- 2.20.1 ------------------------------ Subject: Digest Footer _______________________________________________ connman mailing list -- connman@lists.01.org To unsubscribe send an email to connman-le...@lists.01.org ------------------------------ End of connman Digest, Vol 66, Issue 1 **************************************