Skip to content

Commit

Permalink
provider: Toggle IPv6 on the transport of IPv4 VPN connection
Browse files Browse the repository at this point in the history
[provider] Toggle IPv6 on the transport of IPV4 VPN. JB#48769

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 on system level. The value
of SingleConnectedTechnology does not change run-time so there should
not be a possibility for inconsistent state.

To get the transport utilize the recorded transport from plugins/vpn.c.

Disable IPv6 when state changes to READY (also ONLINE but that is never
used with VPNs) for IPv4 provider. Record the old IPv6 method for
re-enabling the IPv6 on the used transport.

When provider state changes to DISCONNECT or FAILURE re-enable IPv6 the
transport using the recorded method.
  • Loading branch information
LaakkonenJussi committed Mar 17, 2021
1 parent f839c26 commit d68291d
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 0 deletions.
4 changes: 4 additions & 0 deletions connman/src/connman.h
Expand Up @@ -765,13 +765,17 @@ void __connman_provider_list(DBusMessageIter *iter, void *user_data);
bool __connman_provider_is_immutable(struct connman_provider *provider);
int __connman_provider_create_and_connect(DBusMessage *msg);
const char * __connman_provider_get_ident(struct connman_provider *provider);
const char * __connman_provider_get_transport_ident(
struct connman_provider *provider);
int __connman_provider_indicate_state(struct connman_provider *provider,
enum connman_provider_state state);
int __connman_provider_indicate_error(struct connman_provider *provider,
enum connman_provider_error error);
int __connman_provider_connect(struct connman_provider *provider,
const char *dbus_sender);
int __connman_provider_remove_by_path(const char *path);
int __connman_provider_toggle_transport_ipv6(struct connman_provider *provider,
bool disable);
void __connman_provider_cleanup(void);
int __connman_provider_init(void);

Expand Down
177 changes: 177 additions & 0 deletions connman/src/provider.c
Expand Up @@ -47,6 +47,7 @@ struct connman_provider {
int family;
struct connman_provider_driver *driver;
void *driver_data;
enum connman_ipconfig_method transport_ipv6_method;
};

void __connman_provider_append_properties(struct connman_provider *provider,
Expand Down Expand Up @@ -121,11 +122,173 @@ void connman_provider_unref_debug(struct connman_provider *provider,
provider_destruct(provider);
}

int __connman_provider_toggle_transport_ipv6(struct connman_provider *provider,
bool disable)
{
struct connman_service *service;
struct connman_service *transport;
struct connman_network *network;
struct connman_ipconfig *service_ipv6config;
struct connman_ipconfig *transport_ipv6config;
const char *transport_ident;

if (!provider)
return -EINVAL;

DBG("provider %p %s", provider, !disable ? "enable" : "disable");

service = provider->vpn_service;
if (!service)
return -EINVAL;

/*
* 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) && disable)
goto out;

service_ipv6config = __connman_service_get_ip6config(service);
if (service_ipv6config &&
__connman_ipconfig_ipv6_is_enabled(service_ipv6config))
return 0;

/*
* Set system IPv6 status if multiple connected technologies are used
* in order to avoid leaking DNS/data to any IPv6 network. That may
* happen when DNS server returns also AAAA record for a request.
*/
if (!connman_setting_get_bool("SingleConnectedTechnology")) {
if (!__connman_ipconfig_set_ipv6_support(!disable))
connman_warn("cannot disable IPv6 support for "
"provider %p", provider);
}

transport_ident = __connman_provider_get_transport_ident(provider);
transport = connman_service_lookup_from_identifier(transport_ident);
if (!transport) {
DBG("no transport for %p transport ident %s", service,
transport_ident);
return -ENODEV;
}

DBG("transport %p", transport);

network = __connman_service_get_network(transport);
if (!network) {
DBG("no network for transport %p", transport);
return -ENODEV;
}

transport_ipv6config = __connman_service_get_ip6config(transport);
if (!transport_ipv6config) {
DBG("no ipv6config on transport %p", transport);
return 0; // Not enabled?
}

if (disable) {
if (!__connman_ipconfig_ipv6_is_enabled(transport_ipv6config))
return 0;

provider->transport_ipv6_method =
__connman_ipconfig_get_method(
transport_ipv6config);
DBG("set IPv6 ipconfig %p off (old %d)", transport,
provider->transport_ipv6_method);

__connman_network_clear_ipconfig(network,
transport_ipv6config);
__connman_ipconfig_gateway_remove(transport_ipv6config);

__connman_service_ipconfig_indicate_state(transport,
CONNMAN_SERVICE_STATE_DISCONNECT,
CONNMAN_IPCONFIG_TYPE_IPV6);
__connman_ipconfig_address_unset(transport_ipv6config);

/*
* Disables IPv6 on ipconfig and sets the force_disabled
* as true.
*/
connman_network_set_ipv6_method(network,
CONNMAN_IPCONFIG_METHOD_OFF);
__connman_network_enable_ipconfig(network,
transport_ipv6config, true);

__connman_service_ipconfig_indicate_state(transport,
CONNMAN_SERVICE_STATE_IDLE,
CONNMAN_IPCONFIG_TYPE_IPV6);
} else {
if (__connman_ipconfig_ipv6_is_enabled(transport_ipv6config))
return 0;

switch (provider->transport_ipv6_method) {
case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
case CONNMAN_IPCONFIG_METHOD_OFF:
DBG("IPv6 previously disabled on %p", transport);
goto out;
case CONNMAN_IPCONFIG_METHOD_MANUAL:
case CONNMAN_IPCONFIG_METHOD_AUTO:
case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_DHCP:
break;
}

DBG("set IPv6 method %d", provider->transport_ipv6_method);

connman_network_set_ipv6_method(network,
provider->transport_ipv6_method);
__connman_network_enable_ipconfig(network,
transport_ipv6config, true);
}

__connman_service_notify_ipv6_configuration(transport);
__connman_notifier_ipconfig_changed(transport, transport_ipv6config);

out:
if (!disable)
provider->transport_ipv6_method =
CONNMAN_IPCONFIG_METHOD_UNKNOWN;

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_toggle_transport_ipv6(provider, true);
if (err)
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_toggle_transport_ipv6(provider,
false);
if (err)
DBG("cannot enable IPv6 on provider %p transport",
provider);

break;
}

__connman_service_ipconfig_indicate_state(provider->vpn_service, state,
CONNMAN_IPCONFIG_TYPE_IPV4);

Expand Down Expand Up @@ -248,6 +411,8 @@ static int set_connected(struct connman_provider *provider,
struct connman_service *service = provider->vpn_service;
struct connman_ipconfig *ipconfig;

DBG("provider %p", provider);

if (!service)
return -ENODEV;

Expand Down Expand Up @@ -446,6 +611,18 @@ const char *__connman_provider_get_ident(struct connman_provider *provider)
return provider->identifier;
}

const char * __connman_provider_get_transport_ident(
struct connman_provider *provider)
{
if (!provider)
return NULL;

if (provider->driver && provider->driver->get_property)
return provider->driver->get_property(provider, "Transport");

return NULL;
}

int connman_provider_set_string(struct connman_provider *provider,
const char *key, const char *value)
{
Expand Down

0 comments on commit d68291d

Please sign in to comment.