Skip to content

Commit

Permalink
network: Prevent enabling IPv6 for network if internally disabled
Browse files Browse the repository at this point in the history
[network] Dont' enable IPv6 for network if internally disabled. JB#53542

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.

Adopt to ipconfig.c changes to remove the force value from the IPv6
enable/disable functions. Instead use the direct ipconfig.c function to
set the value for force disabled. Thus, reverting most of the changes
done in 2031f66
  • Loading branch information
LaakkonenJussi committed Apr 21, 2021
1 parent c00d00d commit 9454f93
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 19 deletions.
3 changes: 1 addition & 2 deletions connman/src/connman.h
Expand Up @@ -716,8 +716,7 @@ int __connman_network_disconnect(struct connman_network *network);
int __connman_network_clear_ipconfig(struct connman_network *network,
struct connman_ipconfig *ipconfig);
int __connman_network_enable_ipconfig(struct connman_network *network,
struct connman_ipconfig *ipconfig,
bool force);
struct connman_ipconfig *ipconfig);

const char *__connman_network_get_type(struct connman_network *network);
const char *__connman_network_get_group(struct connman_network *network);
Expand Down
66 changes: 49 additions & 17 deletions connman/src/network.c
Expand Up @@ -282,8 +282,7 @@ static int set_connected_dhcp(struct connman_network *network)
}

static int manual_ipv6_set(struct connman_network *network,
struct connman_ipconfig *ipconfig_ipv6,
bool force)
struct connman_ipconfig *ipconfig_ipv6)
{
struct connman_service *service;
int err;
Expand All @@ -297,7 +296,7 @@ static int manual_ipv6_set(struct connman_network *network,
if (!__connman_ipconfig_get_local(ipconfig_ipv6))
__connman_service_read_ip6config(service);

err = __connman_ipconfig_enable_ipv6(ipconfig_ipv6, force);
err = __connman_ipconfig_enable_ipv6(ipconfig_ipv6);
if (err)
return err;

Expand Down Expand Up @@ -377,7 +376,7 @@ static int dhcpv6_set_addresses(struct connman_network *network)
return err;
}

static void autoconf_ipv6_set(struct connman_network *network, bool force);
static void autoconf_ipv6_set(struct connman_network *network);
static void dhcpv6_callback(struct connman_network *network,
enum __connman_dhcpv6_status status, gpointer data);

Expand All @@ -399,7 +398,7 @@ static void dhcpv6_renew_callback(struct connman_network *network,
stop_dhcpv6(network);

/* restart and do solicit again. */
autoconf_ipv6_set(network, false);
autoconf_ipv6_set(network);
break;
}
}
Expand All @@ -425,7 +424,7 @@ static void dhcpv6_callback(struct connman_network *network,

} else if (status == CONNMAN_DHCPV6_STATUS_RESTART) {
stop_dhcpv6(network);
autoconf_ipv6_set(network, false);
autoconf_ipv6_set(network);
} else
stop_dhcpv6(network);
}
Expand Down Expand Up @@ -561,7 +560,7 @@ int __connman_network_refresh_rs_ipv6(struct connman_network *network,
return ret;
}

static void autoconf_ipv6_set(struct connman_network *network, bool force)
static void autoconf_ipv6_set(struct connman_network *network)
{
struct connman_service *service;
struct connman_ipconfig *ipconfig;
Expand Down Expand Up @@ -591,7 +590,7 @@ static void autoconf_ipv6_set(struct connman_network *network, bool force)

__connman_ipconfig_enable(ipconfig);

if (__connman_ipconfig_enable_ipv6(ipconfig, force))
if (__connman_ipconfig_enable_ipv6(ipconfig))
return;

__connman_ipconfig_address_remove(ipconfig);
Expand Down Expand Up @@ -626,8 +625,8 @@ static void set_connected(struct connman_network *network)
DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4,
ipconfig_ipv6);

__connman_network_enable_ipconfig(network, ipconfig_ipv4, false);
__connman_network_enable_ipconfig(network, ipconfig_ipv6, false);
__connman_network_enable_ipconfig(network, ipconfig_ipv4);
__connman_network_enable_ipconfig(network, ipconfig_ipv6);
}

static void set_disconnected(struct connman_network *network)
Expand All @@ -646,6 +645,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);
Expand Down Expand Up @@ -734,8 +748,8 @@ static void set_disconnected(struct connman_network *network)
* automagically.
*/
if (ipv6_method == CONNMAN_IPCONFIG_METHOD_AUTO) {
__connman_ipconfig_disable_ipv6(ipconfig_ipv6, false);
__connman_ipconfig_enable_ipv6(ipconfig_ipv6, false);
__connman_ipconfig_disable_ipv6(ipconfig_ipv6);
__connman_ipconfig_enable_ipv6(ipconfig_ipv6);
}
}

Expand Down Expand Up @@ -1579,7 +1593,7 @@ int __connman_network_clear_ipconfig(struct connman_network *network,
}

int __connman_network_enable_ipconfig(struct connman_network *network,
struct connman_ipconfig *ipconfig, bool force)
struct connman_ipconfig *ipconfig)
{
int r = 0;
enum connman_ipconfig_type type;
Expand All @@ -1596,6 +1610,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);
Expand All @@ -1607,20 +1640,19 @@ int __connman_network_enable_ipconfig(struct connman_network *network,
break;

case CONNMAN_IPCONFIG_METHOD_OFF:
__connman_ipconfig_disable_ipv6(ipconfig, force);
__connman_ipconfig_disable_ipv6(ipconfig);
break;

case CONNMAN_IPCONFIG_METHOD_AUTO:
autoconf_ipv6_set(network, force);
autoconf_ipv6_set(network);
break;

case CONNMAN_IPCONFIG_METHOD_FIXED:
case CONNMAN_IPCONFIG_METHOD_MANUAL:
r = manual_ipv6_set(network, ipconfig, force);
r = manual_ipv6_set(network, ipconfig);
break;

case CONNMAN_IPCONFIG_METHOD_DHCP:
__connman_ipconfig_enable_ipv6(ipconfig, force);
r = -ENOSYS;
break;
}
Expand Down

0 comments on commit 9454f93

Please sign in to comment.