@@ -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
@@ -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));
+ 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;
+ }
- l_free(l_steal_ptr(netconfig->v4_domain));
+ 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 int validate_dns_list(int family, char **dns_list)
+static bool netconfig_load_gateway(struct netconfig *netconfig,
+ const struct l_settings *active_settings,
+ const char *group_name, uint8_t family)
{
- 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;
- }
+ _auto_(l_free) char *gateway_str = NULL;
+
+ if (!l_settings_has_key(active_settings, group_name, "Gateway"))
+ return true;
- l_error("netconfig: Invalid DNS address '%s'.", *p);
- return -EINVAL;
+ 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;
}
- return n_valid;
+ 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;
- }
+ _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;
- if (r == 0)
- l_error("netconfig: Empty IPv4.DNS entry, skipping...");
- }
+ netconfig_free_settings(netconfig);
- dns6_overrides = l_settings_get_string_list(active_settings,
- "IPv6", "DNS", ' ');
+ /*
+ * 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 (dns6_overrides) {
- int r = validate_dns_list(AF_INET6, dns6_overrides);
+ 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);
- if (unlikely(r <= 0)) {
- l_strfreev(dns6_overrides);
- dns6_overrides = NULL;
+ if (unlikely(!addr)) {
+ success = false;
+ goto ipv6_addr;
+ }
- if (r < 0)
- return false;
+ 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;
}
- if (r == 0)
- l_error("netconfig: Empty IPv6.DNS entry, skipping...");
+ static_ipv4 = true;
}
- if (!l_settings_get_bool(active_settings,
- "IPv4", "SendHostname", &send_hostname))
- send_hostname = false;
+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 (send_hostname) {
- if (gethostname(hostname, sizeof(hostname)) != 0) {
- l_warn("netconfig: Unable to get hostname. "
- "Error %d: %s", errno, strerror(errno));
- send_hostname = false;
+ 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;
}
- mdns = l_settings_get_string(active_settings,
- "Network", "MulticastDNS");
+gateway:
+ if (!netconfig_load_gateway(netconfig, active_settings,
+ "IPv4", AF_INET))
+ success = false;
- if (l_settings_has_key(active_settings, "IPv4", "Address")) {
- v4_address = netconfig_get_static4_address(active_settings);
+ if (!netconfig_load_gateway(netconfig, active_settings,
+ "IPv6", AF_INET6))
+ success = false;
- if (unlikely(!v4_address)) {
- l_error("netconfig: Can't parse IPv4 address");
- return 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_settings_get_bool(active_settings, "IPv6",
- "Enabled", &v6_enabled))
- v6_enabled = ipv6_enabled;
+ 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;
+ }
- if (l_settings_has_key(active_settings, "IPv6", "Address")) {
- v6_address = netconfig_get_static6_address(active_settings);
+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 (unlikely(!v6_address)) {
- l_error("netconfig: Can't parse IPv6 address");
- return false;
- }
+ 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;
}
- /* No more validation steps for now, commit new values */
- netconfig->rtm_protocol = v4_address ? RTPROT_STATIC : RTPROT_DHCP;
+ if (send_hostname &&
+ !l_netconfig_set_hostname(netconfig->nc, hostname)) {
+ l_error("netconfig: l_netconfig_set_hostname() failed");
+ success = false;
+ goto mdns;
+ }
- 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;
+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;
+ }
- netconfig_free_settings(netconfig);
+ if (mdns && !L_IN_STRSET(mdns, "true", "false", "resolve")) {
+ l_error("netconfig: Bad Network.MulticastDNS value '%s'", mdns);
+ success = false;
+ }
- if (netconfig->rtm_protocol == RTPROT_STATIC)
- netconfig->v4_address = l_steal_ptr(v4_address);
+ if (!l_netconfig_check_config(netconfig->nc)) {
+ l_error("netconfig: Invalid configuration");
+ success = false;
+ }
- if (netconfig->rtm_v6_protocol == RTPROT_STATIC)
- netconfig->v6_address = l_steal_ptr(v6_address);
+ 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;
+ }
- 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;
+ 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;
}