diff --git a/Makefile.am b/Makefile.am index ed93d000..31b7e24b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -62,7 +62,8 @@ ell_headers = ell/util.h \ ell/icmp6.h \ ell/dhcp6.h \ ell/acd.h \ - ell/cleanup.h + ell/cleanup.h \ + ell/netconfig.h ell_sources = ell/private.h \ ell/missing.h \ @@ -141,7 +142,8 @@ ell_sources = ell/private.h \ ell/icmp6-private.h \ ell/dhcp6-lease.c \ ell/dhcp6-transport.c \ - ell/acd.c + ell/acd.c \ + ell/netconfig.c ell_shared = ell/useful.h ell/asn1-private.h diff --git a/src/netconfig.c b/src/netconfig.c index ea9846f6..98764346 100644 --- a/src/netconfig.c +++ b/src/netconfig.c @@ -53,21 +53,15 @@ #include "src/sysfs.h" struct netconfig { + struct l_netconfig *nc; uint32_t ifindex; - uint8_t rtm_protocol; - uint8_t rtm_v6_protocol; - struct l_rtnl_address *v4_address; - struct l_rtnl_address *v6_address; - char **dns4_overrides; - char **dns6_overrides; - char **dns4_list; - char **dns6_list; + char *mdns; struct ie_fils_ip_addr_response_info *fils_override; - char *v4_gateway_str; - char *v6_gateway_str; - char *v4_domain; - char **v6_domains; + bool enabled[2]; + bool static_config[2]; + bool gateway_overridden[2]; + bool dns_overridden[2]; const struct l_settings *active_settings; @@ -77,6 +71,9 @@ struct netconfig { struct resolve *resolve; }; +/* 0 for AF_INET, 1 for AF_INET6 */ +#define INDEX_FOR_AF(af) ((af) != AF_INET) + static struct l_netlink *rtnl; /* @@ -95,31 +92,36 @@ static void do_debug(const char *str, void *user_data) static void netconfig_free_settings(struct netconfig *netconfig) { - l_rtnl_address_free(netconfig->v4_address); - netconfig->v4_address = NULL; - l_rtnl_address_free(netconfig->v6_address); - netconfig->v6_address = NULL; - - l_strfreev(netconfig->dns4_overrides); - netconfig->dns4_overrides = NULL; - l_strfreev(netconfig->dns6_overrides); - netconfig->dns6_overrides = NULL; + netconfig->enabled[0] = true; + netconfig->enabled[1] = false; + netconfig->static_config[0] = false; + netconfig->static_config[1] = false; + netconfig->gateway_overridden[0] = false; + netconfig->gateway_overridden[1] = false; + netconfig->dns_overridden[0] = false; + netconfig->dns_overridden[1] = false; + l_netconfig_reset_config(netconfig->nc); l_free(netconfig->mdns); netconfig->mdns = NULL; + + l_free(l_steal_ptr(netconfig->fils_override)); } static void netconfig_free(void *data) { struct netconfig *netconfig = data; + l_netconfig_destroy(netconfig->nc); l_free(netconfig); } static bool netconfig_use_fils_addr(struct netconfig *netconfig, int af) { - if ((af == AF_INET ? netconfig->rtm_protocol : - netconfig->rtm_v6_protocol) != RTPROT_DHCP) + if (!netconfig->enabled[INDEX_FOR_AF(af)]) + return false; + + if (netconfig->static_config[INDEX_FOR_AF(af)]) return false; if (!netconfig->fils_override) @@ -229,7 +231,7 @@ no_prefix_len: static void netconfig_gateway_to_arp(struct netconfig *netconfig) { - struct l_dhcp_client *dhcp = NULL; /* TODO */ + struct l_dhcp_client *dhcp = l_netconfig_get_dhcp_client(netconfig->nc); const struct l_dhcp_lease *lease; _auto_(l_free) char *server_id = NULL; _auto_(l_free) char *gw = NULL; @@ -237,7 +239,8 @@ static void netconfig_gateway_to_arp(struct netconfig *netconfig) struct in_addr in_gw; /* Can only do this for DHCP in certain network setups */ - if (netconfig->rtm_protocol != RTPROT_DHCP) + if (netconfig->static_config[INDEX_FOR_AF(AF_INET)] || + netconfig->fils_override) return; lease = l_dhcp_client_get_lease(dhcp); @@ -261,167 +264,207 @@ static void netconfig_gateway_to_arp(struct netconfig *netconfig) l_debug("l_rtnl_neighbor_set_hwaddr failed"); } -static void netconfig_remove_v4_address(struct netconfig *netconfig) +static bool netconfig_load_dns(struct netconfig *netconfig, + const struct l_settings *active_settings, + const char *group_name, uint8_t family) { - if (!netconfig->v4_address) - return; + _auto_(l_strv_free) char **dns_str_list = NULL; - l_rtnl_address_free(netconfig->v4_address); - netconfig->v4_address = NULL; -} + if (!l_settings_has_key(active_settings, group_name, "DNS")) + return true; -static void netconfig_reset_v4(struct netconfig *netconfig) -{ - if (netconfig->rtm_protocol) { - netconfig_remove_v4_address(netconfig); - - l_strv_free(l_steal_ptr(netconfig->dns4_overrides)); - l_strv_free(l_steal_ptr(netconfig->dns4_list)); - - netconfig->rtm_protocol = 0; - - l_free(l_steal_ptr(netconfig->v4_gateway_str)); - - l_free(l_steal_ptr(netconfig->v4_domain)); - } -} - -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; + dns_str_list = l_settings_get_string_list(active_settings, + group_name, "DNS", ' '); + if (unlikely(!dns_str_list)) { + l_error("netconfig: Can't load [%s].DNS", group_name); + return false; } - return n_valid; + if (unlikely(!l_netconfig_set_dns_override(netconfig->nc, family, + dns_str_list))) { + l_error("netconfig: l_netconfig_set_dns_override(%s) failed", + family == AF_INET ? "AF_INET" : "AF_INET6"); + return false; + } + + netconfig->dns_overridden[INDEX_FOR_AF(family)] = true; + return true; +} + +static bool netconfig_load_gateway(struct netconfig *netconfig, + const struct l_settings *active_settings, + const char *group_name, uint8_t family) +{ + _auto_(l_free) char *gateway_str = NULL; + + if (!l_settings_has_key(active_settings, group_name, "Gateway")) + return true; + + gateway_str = l_settings_get_string(active_settings, group_name, + "Gateway"); + if (unlikely(!gateway_str)) { + l_error("netconfig: Can't load [%s].Gateway", group_name); + return false; + } + + if (unlikely(!l_netconfig_set_gateway_override(netconfig->nc, family, + gateway_str))) { + l_error("netconfig: l_netconfig_set_gateway_override(%s) " + "failed", family == AF_INET ? "AF_INET" : "AF_INET6"); + return false; + } + + netconfig->gateway_overridden[INDEX_FOR_AF(family)] = true; + return true; } bool netconfig_load_settings(struct netconfig *netconfig, const struct l_settings *active_settings) { - _auto_(l_free) char *mdns = NULL; - bool send_hostname; - bool v6_enabled; + bool send_hostname = false; char hostname[HOST_NAME_MAX + 1]; - _auto_(l_strv_free) char **dns4_overrides = NULL; - _auto_(l_strv_free) char **dns6_overrides = NULL; - _auto_(l_rtnl_address_free) struct l_rtnl_address *v4_address = NULL; - _auto_(l_rtnl_address_free) struct l_rtnl_address *v6_address = NULL; - - dns4_overrides = l_settings_get_string_list(active_settings, - "IPv4", "DNS", ' '); - if (dns4_overrides) { - int r = validate_dns_list(AF_INET, dns4_overrides); - - if (unlikely(r <= 0)) { - l_strfreev(dns4_overrides); - dns4_overrides = NULL; - - if (r < 0) - return false; - } - - if (r == 0) - l_error("netconfig: Empty IPv4.DNS entry, skipping..."); - } - - dns6_overrides = l_settings_get_string_list(active_settings, - "IPv6", "DNS", ' '); - - if (dns6_overrides) { - int r = validate_dns_list(AF_INET6, dns6_overrides); - - if (unlikely(r <= 0)) { - l_strfreev(dns6_overrides); - dns6_overrides = NULL; - - if (r < 0) - return false; - } - - if (r == 0) - l_error("netconfig: Empty IPv6.DNS entry, skipping..."); - } - - if (!l_settings_get_bool(active_settings, - "IPv4", "SendHostname", &send_hostname)) - send_hostname = false; - - if (send_hostname) { - if (gethostname(hostname, sizeof(hostname)) != 0) { - l_warn("netconfig: Unable to get hostname. " - "Error %d: %s", errno, strerror(errno)); - send_hostname = false; - } - } - - mdns = l_settings_get_string(active_settings, - "Network", "MulticastDNS"); - - if (l_settings_has_key(active_settings, "IPv4", "Address")) { - v4_address = netconfig_get_static4_address(active_settings); - - if (unlikely(!v4_address)) { - l_error("netconfig: Can't parse IPv4 address"); - return false; - } - } - - if (!l_settings_get_bool(active_settings, "IPv6", - "Enabled", &v6_enabled)) - v6_enabled = ipv6_enabled; - - if (l_settings_has_key(active_settings, "IPv6", "Address")) { - v6_address = netconfig_get_static6_address(active_settings); - - if (unlikely(!v6_address)) { - l_error("netconfig: Can't parse IPv6 address"); - return false; - } - } - - /* No more validation steps for now, commit new values */ - netconfig->rtm_protocol = v4_address ? RTPROT_STATIC : RTPROT_DHCP; - - if (!v6_enabled) - netconfig->rtm_v6_protocol = RTPROT_UNSPEC; - else if (v6_address) - netconfig->rtm_v6_protocol = RTPROT_STATIC; - else - netconfig->rtm_v6_protocol = RTPROT_DHCP; + _auto_(l_free) char *mdns = NULL; + bool success = true; + bool static_ipv4 = false; + bool static_ipv6 = false; + bool enable_ipv4 = true; + bool enable_ipv6 = ipv6_enabled; netconfig_free_settings(netconfig); - if (netconfig->rtm_protocol == RTPROT_STATIC) - netconfig->v4_address = l_steal_ptr(v4_address); + /* + * Note we try to print errors and continue validating the + * configuration until we've gone through all the settings so + * as to make fixing the settings more efficient for the user. + */ - if (netconfig->rtm_v6_protocol == RTPROT_STATIC) - netconfig->v6_address = l_steal_ptr(v6_address); + if (l_settings_has_key(active_settings, "IPv4", "Address")) { + _auto_(l_rtnl_address_free) struct l_rtnl_address *addr = + netconfig_get_static4_address(active_settings); - netconfig->active_settings = active_settings; - netconfig->dns4_overrides = l_steal_ptr(dns4_overrides); - netconfig->dns6_overrides = l_steal_ptr(dns6_overrides); - netconfig->mdns = l_steal_ptr(mdns); - return true; + if (unlikely(!addr)) { + success = false; + goto ipv6_addr; + } + + if (!l_netconfig_set_static_addr(netconfig->nc, AF_INET, + addr)) { + l_error("netconfig: l_netconfig_set_static_addr(" + "AF_INET) failed"); + success = false; + goto ipv6_addr; + } + + static_ipv4 = true; + } + +ipv6_addr: + if (l_settings_has_key(active_settings, "IPv6", "Address")) { + _auto_(l_rtnl_address_free) struct l_rtnl_address *addr = + netconfig_get_static6_address(active_settings); + + if (unlikely(!addr)) { + success = false; + goto gateway; + } + + if (!l_netconfig_set_static_addr(netconfig->nc, AF_INET6, + addr)) { + l_error("netconfig: l_netconfig_set_static_addr(" + "AF_INET6) failed"); + success = false; + goto gateway; + } + + static_ipv6 = true; + } + +gateway: + if (!netconfig_load_gateway(netconfig, active_settings, + "IPv4", AF_INET)) + success = false; + + if (!netconfig_load_gateway(netconfig, active_settings, + "IPv6", AF_INET6)) + success = false; + + if (!netconfig_load_dns(netconfig, active_settings, "IPv4", AF_INET)) + success = false; + + if (!netconfig_load_dns(netconfig, active_settings, "IPv6", AF_INET6)) + success = false; + + if (l_settings_has_key(active_settings, "IPv6", "Enabled") && + !l_settings_get_bool(active_settings, "IPv6", "Enabled", + &enable_ipv6)) { + l_error("netconfig: Can't load IPv6.Enabled"); + success = false; + goto send_hostname; + } + + if (!l_netconfig_set_family_enabled(netconfig->nc, AF_INET, + enable_ipv4) || + !l_netconfig_set_family_enabled(netconfig->nc, AF_INET6, + enable_ipv6)) { + l_error("netconfig: l_netconfig_set_family_enabled() failed"); + success = false; + } + +send_hostname: + if (l_settings_has_key(active_settings, "IPv4", "SendHostname") && + !l_settings_get_bool(active_settings, "IPv4", + "SendHostname", + &send_hostname)) { + l_error("netconfig: Can't load [IPv4].SendHostname"); + success = false; + goto mdns; + } + + if (send_hostname && gethostname(hostname, sizeof(hostname)) != 0) { + /* Warning only */ + l_warn("netconfig: Unable to get hostname. " + "Error %d: %s", errno, strerror(errno)); + goto mdns; + } + + if (send_hostname && + !l_netconfig_set_hostname(netconfig->nc, hostname)) { + l_error("netconfig: l_netconfig_set_hostname() failed"); + success = false; + goto mdns; + } + +mdns: + if (l_settings_has_key(active_settings, "Network", "MulticastDNS") && + !(mdns = l_settings_get_string(active_settings, + "Network", + "MulticastDNS"))) { + l_error("netconfig: Can't load Network.MulticastDNS"); + success = false; + } + + if (mdns && !L_IN_STRSET(mdns, "true", "false", "resolve")) { + l_error("netconfig: Bad Network.MulticastDNS value '%s'", mdns); + success = false; + } + + if (!l_netconfig_check_config(netconfig->nc)) { + l_error("netconfig: Invalid configuration"); + success = false; + } + + if (success) { + netconfig->active_settings = active_settings; + netconfig->static_config[INDEX_FOR_AF(AF_INET)] = static_ipv4; + netconfig->static_config[INDEX_FOR_AF(AF_INET6)] = static_ipv6; + netconfig->enabled[INDEX_FOR_AF(AF_INET)] = enable_ipv4; + netconfig->enabled[INDEX_FOR_AF(AF_INET6)] = enable_ipv6; + netconfig->mdns = l_steal_ptr(mdns); + return true; + } + + l_netconfig_reset_config(netconfig->nc); + return false; } bool netconfig_configure(struct netconfig *netconfig, @@ -449,11 +492,11 @@ bool netconfig_reconfigure(struct netconfig *netconfig, bool set_arp_gw) if (set_arp_gw) netconfig_gateway_to_arp(netconfig); - if (netconfig->rtm_protocol == RTPROT_DHCP) { + if (!netconfig->static_config[INDEX_FOR_AF(AF_INET)]) { /* TODO l_dhcp_client sending a DHCP inform request */ } - if (netconfig->rtm_v6_protocol == RTPROT_DHCP) { + if (!netconfig->static_config[INDEX_FOR_AF(AF_INET6)]) { /* TODO l_dhcp_v6_client sending a DHCP inform request */ } @@ -462,32 +505,22 @@ bool netconfig_reconfigure(struct netconfig *netconfig, bool set_arp_gw) bool netconfig_reset(struct netconfig *netconfig) { - netconfig_reset_v4(netconfig); - - if (netconfig->rtm_v6_protocol) { - l_rtnl_address_free(netconfig->v6_address); - netconfig->v6_address = NULL; - - l_strv_free(l_steal_ptr(netconfig->dns6_overrides)); - l_strv_free(l_steal_ptr(netconfig->dns6_list)); - - netconfig->rtm_v6_protocol = 0; - - l_free(l_steal_ptr(netconfig->v6_gateway_str)); - - l_strv_free(l_steal_ptr(netconfig->v6_domains)); - } - - l_free(l_steal_ptr(netconfig->fils_override)); + l_netconfig_unconfigure(netconfig->nc); + l_netconfig_stop(netconfig->nc); + netconfig_free_settings(netconfig); return true; } char *netconfig_get_dhcp_server_ipv4(struct netconfig *netconfig) { - struct l_dhcp_client *client = NULL; /* TODO */ + struct l_dhcp_client *client = + l_netconfig_get_dhcp_client(netconfig->nc); const struct l_dhcp_lease *lease; + if (!client) + return NULL; + lease = l_dhcp_client_get_lease(client); if (!lease) return NULL; @@ -504,15 +537,16 @@ bool netconfig_get_fils_ip_req(struct netconfig *netconfig, * configuration (usually DHCP). If we're configured with static * values return false to mean the IE should not be sent. */ - if (netconfig->rtm_protocol != RTPROT_DHCP && - netconfig->rtm_v6_protocol != RTPROT_DHCP) + if (netconfig->static_config[0] && netconfig->static_config[1]) return false; memset(info, 0, sizeof(*info)); - info->ipv4 = (netconfig->rtm_protocol == RTPROT_DHCP); - info->ipv6 = (netconfig->rtm_v6_protocol == RTPROT_DHCP); - info->dns = (info->ipv4 && !netconfig->dns4_overrides) || - (info->ipv6 && !netconfig->dns6_overrides); + info->ipv4 = !netconfig->static_config[INDEX_FOR_AF(AF_INET)]; + info->ipv6 = !netconfig->static_config[INDEX_FOR_AF(AF_INET6)]; + info->dns = (info->ipv4 && + !netconfig->dns_overridden[INDEX_FOR_AF(AF_INET)]) || + (info->ipv6 && + !netconfig->dns_overridden[INDEX_FOR_AF(AF_INET)]); return true; } @@ -530,12 +564,12 @@ struct netconfig *netconfig_new(uint32_t ifindex) struct netconfig *netconfig; const char *debug_level = NULL; int dhcp_priority = L_LOG_INFO; - struct l_dhcp_client *dhcp = NULL; /* TODO */ - struct l_dhcp6_client *dhcp6 = NULL; /* TODO */ + struct l_dhcp6_client *dhcp6; - l_debug("Starting netconfig for interface: %d", ifindex); + l_debug("Creating netconfig for interface: %d", ifindex); netconfig = l_new(struct netconfig, 1); + netconfig->nc = l_netconfig_new(ifindex); netconfig->ifindex = ifindex; netconfig->resolve = resolve_new(ifindex); @@ -553,15 +587,18 @@ struct netconfig *netconfig_new(uint32_t ifindex) dhcp_priority = L_LOG_DEBUG; } - l_dhcp_client_set_debug(dhcp, do_debug, "[DHCPv4] ", NULL, - dhcp_priority); + l_dhcp_client_set_debug(l_netconfig_get_dhcp_client(netconfig->nc), + do_debug, "[DHCPv4] ", NULL, dhcp_priority); + dhcp6 = l_netconfig_get_dhcp6_client(netconfig->nc); l_dhcp6_client_set_lla_randomized(dhcp6, true); l_dhcp6_client_set_nodelay(dhcp6, true); - if (getenv("IWD_DHCP_DEBUG")) + if (debug_level) l_dhcp6_client_set_debug(dhcp6, do_debug, "[DHCPv6] ", NULL); + l_netconfig_set_route_priority(netconfig->nc, ROUTE_PRIORITY_OFFSET); + return netconfig; }