From c46a5d7c8485e2262b60d68397f7c8918444af7b Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 18 Nov 2020 09:58:28 -0600 Subject: [PATCH] netconfig: Install DNS addresses obtained from DHCPv6 This also changes the resolve API a little bit to act as a 'set' API instead of an incremental 'add' API. This is actually easier to manage in the resolve module since both systemd and resolvconf want changes wholesale and not incrementally. --- src/netconfig.c | 250 +++++++++++++++++++++++++----------------------- src/resolve.c | 56 ++++------- src/resolve.h | 2 +- 3 files changed, 153 insertions(+), 155 deletions(-) diff --git a/src/netconfig.c b/src/netconfig.c index 81f3f3c9..13e68dbf 100644 --- a/src/netconfig.c +++ b/src/netconfig.c @@ -55,6 +55,8 @@ struct netconfig { struct l_queue *ifaddr_list; uint8_t rtm_protocol; uint8_t rtm_v6_protocol; + char **dns4_overrides; + char **dns6_overrides; const struct l_settings *active_settings; @@ -159,6 +161,67 @@ static struct netconfig *netconfig_find(uint32_t ifindex) return NULL; } +#define APPEND_STRDUPV(dest, index, src) \ + do { \ + char **p; \ + for (p = src; p && *p; p++) \ + dest[index++] = l_strdup(*p); \ + } while (0) \ + +#define APPENDV(dest, index, src) \ + do { \ + char **p; \ + for (p = src; p && *p; p++) \ + dest[index++] = *p; \ + } while (0) \ + +static int netconfig_set_dns(struct netconfig *netconfig) +{ + char **dns6_list = NULL; + char **dns4_list = NULL; + unsigned int n_entries = 0; + char **dns_list; + + if (!netconfig->dns4_overrides && + netconfig->rtm_protocol == RTPROT_DHCP) { + const struct l_dhcp_lease *lease = + l_dhcp_client_get_lease(netconfig->dhcp_client); + + if (lease) + dns4_list = l_dhcp_lease_get_dns(lease); + } + + if (!netconfig->dns6_overrides && + netconfig->rtm_v6_protocol == RTPROT_DHCP) { + const struct l_dhcp6_lease *lease = + l_dhcp6_client_get_lease(netconfig->dhcp6_client); + + if (lease) + dns6_list = l_dhcp6_lease_get_dns(lease); + } + + n_entries += l_strv_length(netconfig->dns4_overrides); + n_entries += l_strv_length(netconfig->dns6_overrides); + n_entries += l_strv_length(dns4_list); + n_entries += l_strv_length(dns6_list); + + dns_list = l_new(char *, n_entries + 1); + n_entries = 0; + + APPEND_STRDUPV(dns_list, n_entries, netconfig->dns4_overrides); + APPENDV(dns_list, n_entries, dns4_list); + /* Contents now belong to ret, so not l_strfreev */ + l_free(dns4_list); + APPEND_STRDUPV(dns_list, n_entries, netconfig->dns6_overrides); + APPENDV(dns_list, n_entries, dns6_list); + /* Contents now belong to ret, so not l_strfreev */ + l_free(dns6_list); + + resolve_set_dns(netconfig->resolve, dns_list); + l_strv_free(dns_list); + return 0; +} + static struct netconfig_ifaddr *netconfig_ipv4_get_ifaddr( struct netconfig *netconfig, uint8_t proto) @@ -270,56 +333,6 @@ static char *netconfig_ipv4_get_gateway(struct netconfig *netconfig) return NULL; } -static char **netconfig_ipv4_get_dns(struct netconfig *netconfig, uint8_t proto) -{ - const struct l_dhcp_lease *lease; - struct in_addr in_addr; - char **dns_list; - - dns_list = l_settings_get_string_list(netconfig->active_settings, - "IPv4", "DNS", ' '); - if (!dns_list) - dns_list = l_settings_get_string_list( - netconfig->active_settings, - "IPv4", "dns", ' '); - - if (dns_list && *dns_list) { - char **p; - - for (p = dns_list; *p; p++) { - if (inet_pton(AF_INET, *p, &in_addr) == 1) - continue; - - l_error("netconfig: Invalid IPv4 DNS address '%s' is " - "provided in network configuration file.", *p); - - l_strv_free(dns_list); - - return NULL; - } - - /* Allow to override the DHCP DNSs with static addressing. */ - return dns_list; - } else if (dns_list) { - l_error("netconfig: No IPv4 DNS address is provided in network " - "configuration file."); - - l_strv_free(dns_list); - - return NULL; - } - - if (proto == RTPROT_DHCP) { - lease = l_dhcp_client_get_lease(netconfig->dhcp_client); - if (!lease) - return NULL; - - return l_dhcp_lease_get_dns(lease); - } - - return NULL; -} - static char *netconfig_ipv4_get_domain_name(struct netconfig *netconfig, uint8_t proto) { @@ -442,54 +455,6 @@ static char *netconfig_ipv6_get_gateway(struct netconfig *netconfig) return NULL; } -static char **netconfig_ipv6_get_dns(struct netconfig *netconfig, uint8_t proto) -{ - struct in6_addr in6_addr; - char **dns_list; - - dns_list = l_settings_get_string_list(netconfig->active_settings, - "IPv6", "DNS", ' '); - - if (!dns_list) - dns_list = l_settings_get_string_list( - netconfig->active_settings, - "IPv6", "dns", ' '); - - if (dns_list && *dns_list) { - char **p; - - for (p = dns_list; *p; p++) { - if (inet_pton(AF_INET6, *p, &in6_addr) == 1) - continue; - - l_error("netconfig: Invalid IPv6 DNS address '%s' is " - "provided in network configuration file.", *p); - - l_strv_free(dns_list); - - return NULL; - } - - /* Allow to override the DHCP DNSs with static addressing. */ - return dns_list; - } else if (dns_list) { - l_error("netconfig: No IPv6 DNS address is provided in network " - "configuration file."); - - l_strv_free(dns_list); - - return NULL; - } - - if (proto == RTPROT_DHCP) { - /* TODO */ - - return NULL; - } - - return NULL; -} - static bool netconfig_ifaddr_match(const void *a, const void *b) { const struct netconfig_ifaddr *entry = a; @@ -810,7 +775,6 @@ static void netconfig_ipv4_ifaddr_add_cmd_cb(int error, uint16_t type, { struct netconfig *netconfig = user_data; struct netconfig_ifaddr *ifaddr; - char **dns; char *domain_name; if (error && error != -EEXIST) { @@ -833,16 +797,8 @@ static void netconfig_ipv4_ifaddr_add_cmd_cb(int error, uint16_t type, goto done; } - dns = netconfig_ipv4_get_dns(netconfig, netconfig->rtm_protocol); - if (!dns) { - l_error("netconfig: Failed to obtain DNS addresses."); - goto domain_name; - } + netconfig_set_dns(netconfig); - resolve_add_dns(netconfig->resolve, ifaddr->family, dns); - l_strv_free(dns); - -domain_name: domain_name = netconfig_ipv4_get_domain_name(netconfig, netconfig->rtm_protocol); if (!domain_name) @@ -887,7 +843,6 @@ static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t type, void *user_data) { struct netconfig *netconfig = user_data; - char **dns; if (error && error != -EEXIST) { l_error("netconfig: Failed to add IPv6 address. " @@ -901,16 +856,7 @@ static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t type, return; } - dns = netconfig_ipv6_get_dns(netconfig, netconfig->rtm_v6_protocol); - if (!dns) { - l_error("netconfig: Failed to obtain the DNS addresses from " - "%s.", netconfig->rtm_v6_protocol == RTPROT_STATIC ? - "setting file" : "DHCPv6 lease"); - return; - } - - resolve_add_dns(netconfig->resolve, AF_INET6, dns); - l_strv_free(dns); + netconfig_set_dns(netconfig); } static void netconfig_install_address(struct netconfig *netconfig, @@ -1069,9 +1015,11 @@ static void netconfig_dhcp6_event_handler(struct l_dhcp6_client *client, case L_DHCP6_CLIENT_EVENT_IP_CHANGED: case L_DHCP6_CLIENT_EVENT_LEASE_OBTAINED: case L_DHCP6_CLIENT_EVENT_LEASE_RENEWED: + netconfig_set_dns(netconfig); break; case L_DHCP6_CLIENT_EVENT_LEASE_EXPIRED: l_debug("Lease for interface %u expired", netconfig->ifindex); + netconfig_set_dns(netconfig); break; case L_DHCP6_CLIENT_EVENT_NO_LEASE: l_error("netconfig: Failed to obtain DHCPv6 lease " @@ -1173,11 +1121,70 @@ static void netconfig_ipv6_select_and_uninstall(struct netconfig *netconfig) l_free(gateway); } +static int validate_dns_list(int family, char **dns_list) +{ + unsigned int n_valid = 0; + struct in_addr in_addr; + struct in6_addr in6_addr; + char **p; + + for (p = dns_list; *p; p++) { + int r; + + if (family == AF_INET) + r = inet_pton(AF_INET, *p, &in_addr); + else if (family == AF_INET6) + r = inet_pton(AF_INET6, *p, &in6_addr); + else + r = -EAFNOSUPPORT; + + if (r > 0) { + n_valid += 1; + continue; + } + + l_error("netconfig: Invalid DNS address '%s'.", *p); + return -EINVAL; + } + + return n_valid; +} + bool netconfig_configure(struct netconfig *netconfig, const struct l_settings *active_settings, const uint8_t *mac_address, netconfig_notify_func_t notify, void *user_data) { + netconfig->dns4_overrides = l_settings_get_string_list(active_settings, + "IPv4", "DNS", ' '); + + if (netconfig->dns4_overrides) { + int r = validate_dns_list(AF_INET, netconfig->dns4_overrides); + + if (r <= 0) { + l_strfreev(netconfig->dns4_overrides); + netconfig->dns4_overrides = NULL; + } + + if (r == 0) + l_error("netconfig: Empty IPv4.DNS entry, skipping..."); + } + + netconfig->dns6_overrides = l_settings_get_string_list(active_settings, + "IPv6", "DNS", ' '); + + if (netconfig->dns6_overrides) { + int r = validate_dns_list(AF_INET6, netconfig->dns6_overrides); + + if (r <= 0) { + l_strfreev(netconfig->dns6_overrides); + netconfig->dns6_overrides = NULL; + } + + if (r == 0) + l_error("netconfig: Empty IPv6.DNS entry, skipping..."); + } + netconfig->active_settings = active_settings; netconfig->notify = notify; netconfig->user_data = user_data; @@ -1219,6 +1226,11 @@ bool netconfig_reset(struct netconfig *netconfig) resolve_revert(netconfig->resolve); + l_strfreev(netconfig->dns4_overrides); + netconfig->dns4_overrides = NULL; + l_strfreev(netconfig->dns6_overrides); + netconfig->dns6_overrides = NULL; + sysfs_write_ipv6_setting(netdev_get_name(netdev), "disable_ipv6", "1"); return true; diff --git a/src/resolve.c b/src/resolve.c index 066e4c87..8e36caad 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -38,8 +38,7 @@ #include "src/resolve.h" struct resolve_ops { - void (*add_dns)(struct resolve *resolve, - uint8_t type, char **dns_list); + void (*set_dns)(struct resolve *resolve, char **dns_list); void (*add_domain_name)(struct resolve *resolve, const char *domain_name); void (*revert)(struct resolve *resolve); @@ -58,15 +57,15 @@ static inline void _resolve_init(struct resolve *resolve, uint32_t ifindex, resolve->ops = ops; } -void resolve_add_dns(struct resolve *resolve, uint8_t type, char **dns_list) +void resolve_set_dns(struct resolve *resolve, char **dns_list) { if (!dns_list || !*dns_list) return; - if (!resolve->ops->add_dns) + if (!resolve->ops->set_dns) return; - resolve->ops->add_dns(resolve, type, dns_list); + resolve->ops->set_dns(resolve, dns_list); } void resolve_add_domain_name(struct resolve *resolve, const char *domain_name) @@ -130,37 +129,27 @@ static void systemd_link_dns_reply(struct l_dbus_message *message, } static bool systemd_builder_add_dns(struct l_dbus_message_builder *builder, - uint8_t type, const char *dns) + const char *dns) { uint8_t buf[16]; uint8_t buf_size; uint8_t i; - int t = (int) type; + int t; - l_debug("installing DNS: %s %u", dns, type); + l_debug("installing DNS: %s", dns); + + if (inet_pton(AF_INET, dns, buf) == 1) { + t = AF_INET; + buf_size = 4; + } else if (inet_pton(AF_INET6, dns, buf) == 1) { + t = AF_INET6; + buf_size = 16; + } else + return false; l_dbus_message_builder_append_basic(builder, 'i', &t); l_dbus_message_builder_enter_array(builder, "y"); - switch (type) { - case AF_INET: - if (inet_pton(AF_INET, dns, buf) < 1) - return false; - - buf_size = 4; - - break; - case AF_INET6: - if (inet_pton(AF_INET6, dns, buf) < 1) - return false; - - buf_size = 16; - - break; - default: - return false; - } - for (i = 0; i < buf_size; i++) l_dbus_message_builder_append_basic(builder, 'y', &buf[i]); @@ -169,8 +158,7 @@ static bool systemd_builder_add_dns(struct l_dbus_message_builder *builder, return true; } -static void resolve_systemd_add_dns(struct resolve *resolve, - uint8_t type, char **dns_list) +static void resolve_systemd_set_dns(struct resolve *resolve, char **dns_list) { struct l_dbus_message_builder *builder; struct l_dbus_message *message; @@ -202,9 +190,8 @@ static void resolve_systemd_add_dns(struct resolve *resolve, for (; *dns_list; dns_list++) { l_dbus_message_builder_enter_struct(builder, "iay"); - if (systemd_builder_add_dns(builder, type, *dns_list)) { + if (systemd_builder_add_dns(builder, *dns_list)) { l_dbus_message_builder_leave_struct(builder); - continue; } @@ -294,7 +281,7 @@ static void resolve_systemd_destroy(struct resolve *resolve) } static const struct resolve_ops systemd_ops = { - .add_dns = resolve_systemd_add_dns, + .set_dns = resolve_systemd_set_dns, .add_domain_name = resolve_systemd_add_domain_name, .revert = resolve_systemd_revert, .destroy = resolve_systemd_destroy, @@ -390,8 +377,7 @@ struct resolvconf { char *ifname; }; -static void resolve_resolvconf_add_dns(struct resolve *resolve, - uint8_t type, char **dns_list) +static void resolve_resolvconf_set_dns(struct resolve *resolve, char **dns_list) { struct resolvconf *rc = l_container_of(resolve, struct resolvconf, super); @@ -453,7 +439,7 @@ static void resolve_resolvconf_destroy(struct resolve *resolve) } static struct resolve_ops resolvconf_ops = { - .add_dns = resolve_resolvconf_add_dns, + .set_dns = resolve_resolvconf_set_dns, .add_domain_name = resolve_resolvconf_add_domain_name, .revert = resolve_resolvconf_revert, .destroy = resolve_resolvconf_destroy, diff --git a/src/resolve.h b/src/resolve.h index 108d2704..84beb15b 100644 --- a/src/resolve.h +++ b/src/resolve.h @@ -21,7 +21,7 @@ */ struct resolve *resolve_new(uint32_t ifindex); -void resolve_add_dns(struct resolve *resolve, uint8_t type, char **dns_list); +void resolve_set_dns(struct resolve *resolve, char **dns_list); void resolve_add_domain_name(struct resolve *resolve, const char *domain_name); void resolve_revert(struct resolve *resolve); void resolve_free(struct resolve *resolve);