Skip to content

Commit

Permalink
dhcpv6: Do not fail when no keyfile saved
Browse files Browse the repository at this point in the history
During a DHCPv6 transaction, a DUID field was requested from storage by
calling connman_service_load_service, which tried to open the keyfile on
drive. If the service was not a newly created one, its data would get
written to the keyfile and DHCPv6 solicitation would proceed, even if
the keyfile would not contain the DUID value - a new one would be
generated with the set_duid function.

However, since the function connman_service_load_service fails when the
file is not present, and does not create a new one, the rest of the
set_duid function was not executed, and the DHCPv6 solicitation packet
failed to be sent, rendering IPv6 on the interface as non-working.

Also, the previous behaviour interferes badly with keyfile storage.
A potential service save operation may overwrite the previously written
duid value.

This change adds a struct connman_ipconfig member, dhcpv6_duid, provides
a getter and setter functions for it, and modifies
__connman_ipconfig_load and __connman_ipconfig_save functions to load
and store the value along with the connman_ipconfig structure.
Initialization did not need to be modified, since the structure is
allocated with g_try_new0, which zeros the dhcpv6_duid pointer. The
memory is freed in __connman_ipconfig_unref_debug.
  • Loading branch information
ballock committed Apr 21, 2021
1 parent 520a395 commit cec70c1
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 23 deletions.
3 changes: 3 additions & 0 deletions connman/src/connman.h
Expand Up @@ -520,6 +520,9 @@ char *__connman_ipconfig_get_dhcp_address(struct connman_ipconfig *ipconfig);
void __connman_ipconfig_set_dhcpv6_prefixes(struct connman_ipconfig *ipconfig,
char **prefixes);
char **__connman_ipconfig_get_dhcpv6_prefixes(struct connman_ipconfig *ipconfig);
void __connman_ipconfig_set_dhcpv6_duid(struct connman_ipconfig *ipconfig,
const char *dhcpv6_duid);
char *__connman_ipconfig_get_dhcpv6_duid(struct connman_ipconfig *ipconfig);

void __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
GKeyFile *keyfile, const char *identifier, const char *prefix);
Expand Down
37 changes: 14 additions & 23 deletions connman/src/dhcpv6.c
Expand Up @@ -191,30 +191,23 @@ static int set_duid(struct connman_service *service,
struct connman_network *network,
GDHCPClient *dhcp_client, int index)
{
GKeyFile *keyfile;
const char *ident;
char *hex_duid;
unsigned char *duid;
int duid_len;
struct connman_ipconfig *ip6config;

ident = connman_service_get_identifier(service);

keyfile = connman_storage_load_service(ident);
if (!keyfile)
ip6config = __connman_service_get_ip6config(service);
if (!ip6config)
return -EINVAL;

hex_duid = g_key_file_get_string(keyfile, ident, "IPv6.DHCP.DUID",
NULL);
hex_duid = __connman_ipconfig_get_dhcpv6_duid(ip6config);
if (hex_duid) {
unsigned int i, j = 0, hex;
size_t hex_duid_len = strlen(hex_duid);

duid = g_try_malloc0(hex_duid_len / 2);
if (!duid) {
g_key_file_unref(keyfile);
g_free(hex_duid);
if (!duid)
return -ENOMEM;
}

for (i = 0; i < hex_duid_len; i += 2) {
sscanf(hex_duid + i, "%02x", &hex);
Expand All @@ -228,26 +221,18 @@ static int set_duid(struct connman_service *service,

ret = g_dhcpv6_create_duid(G_DHCPV6_DUID_LLT, index, type,
&duid, &duid_len);
if (ret < 0) {
g_key_file_unref(keyfile);
if (ret < 0)
return ret;
}

hex_duid = convert_to_hex(duid, duid_len);
if (!hex_duid) {
g_free(duid);
g_key_file_unref(keyfile);
return -ENOMEM;
}

g_key_file_set_string(keyfile, ident, "IPv6.DHCP.DUID",
hex_duid);

__connman_storage_save_service(keyfile, ident);
__connman_ipconfig_set_dhcpv6_duid(ip6config, hex_duid);
g_free(hex_duid);
}
g_free(hex_duid);

g_key_file_unref(keyfile);

g_dhcpv6_client_set_duid(dhcp_client, duid, duid_len);

Expand Down Expand Up @@ -405,6 +390,8 @@ static int dhcpv6_info_request(struct connman_dhcpv6 *dhcp)

ret = set_duid(service, dhcp->network, dhcp_client, index);
if (ret < 0) {
DBG("dhcp %p failed to set dhcpv6 duid for service %p",
dhcp, service);
clear_timer(dhcp);
g_dhcp_client_unref(dhcp_client);
return ret;
Expand Down Expand Up @@ -1759,6 +1746,8 @@ static int dhcpv6_solicitation(struct connman_dhcpv6 *dhcp)

ret = set_duid(service, dhcp->network, dhcp_client, index);
if (ret < 0) {
DBG("dhcp %p failed to set dhcpv6 duid for service %p",
dhcp, service);
clear_timer(dhcp);
g_dhcp_client_unref(dhcp_client);
return ret;
Expand Down Expand Up @@ -2077,6 +2066,8 @@ static GDHCPClient *create_pd_client(struct connman_dhcpv6 *dhcp, int *err)

ret = set_duid(service, dhcp->network, dhcp_client, index);
if (ret < 0) {
DBG("dhcp %p failed to set dhcpv6 duid for service %p",
dhcp, service);
g_dhcp_client_unref(dhcp_client);
*err = ret;
return NULL;
Expand Down
24 changes: 24 additions & 0 deletions connman/src/ipconfig.c
Expand Up @@ -57,6 +57,7 @@ struct connman_ipconfig {
int ipv6_autoconf_config;
char *last_dhcp_address;
char **last_dhcpv6_prefixes;
char *dhcpv6_duid;

bool ipv6_force_disabled;
};
Expand Down Expand Up @@ -1446,6 +1447,7 @@ void __connman_ipconfig_unref_debug(struct connman_ipconfig *ipconfig,
connman_ipaddress_free(ipconfig->address);
g_free(ipconfig->last_dhcp_address);
g_strfreev(ipconfig->last_dhcpv6_prefixes);
g_free(ipconfig->dhcpv6_duid);
g_free(ipconfig);
}

Expand Down Expand Up @@ -1685,6 +1687,24 @@ char **__connman_ipconfig_get_dhcpv6_prefixes(struct connman_ipconfig *ipconfig)
return ipconfig->last_dhcpv6_prefixes;
}

void __connman_ipconfig_set_dhcpv6_duid(struct connman_ipconfig *ipconfig,
const char *dhcpv6_duid)
{
if (!ipconfig)
return;

g_free(ipconfig->dhcpv6_duid);
ipconfig->dhcpv6_duid = g_strdup(dhcpv6_duid);
}

char *__connman_ipconfig_get_dhcpv6_duid(struct connman_ipconfig *ipconfig)
{
if (!ipconfig)
return NULL;

return ipconfig->dhcpv6_duid;
}

static int disable_ipv6(struct connman_ipconfig *ipconfig, bool forced)
{
struct connman_ipdevice *ipdevice;
Expand Down Expand Up @@ -2472,6 +2492,8 @@ void __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
g_strfreev(ipconfig->last_dhcpv6_prefixes);
ipconfig->last_dhcpv6_prefixes =
store_get_strs(&is, "DHCP.LastPrefixes");

ipconfig->dhcpv6_duid = store_get_str(&is, "DHCP.DUID");
}


Expand Down Expand Up @@ -2548,6 +2570,8 @@ void __connman_ipconfig_save(struct connman_ipconfig *ipconfig,

store_set_strs(&is, "DHCP.LastPrefixes",
ipconfig->last_dhcpv6_prefixes);

store_set_str(&is, "DHCP.DUID", ipconfig->dhcpv6_duid);
}

switch (ipconfig->method) {
Expand Down

0 comments on commit cec70c1

Please sign in to comment.