From ce5e4812394d124b08c62f2514e9bab5a111e13f Mon Sep 17 00:00:00 2001 From: Tim Kourt Date: Tue, 1 Oct 2019 16:44:23 -0700 Subject: [PATCH] netconfig: Add IPv6 static address installation/removal The network configuration options for IPv6 are grouped under [IPv6] and include the following: ip= ADDRESS/PREFIX gateway=ADDRESS dns=ADDRESS The placeholders for DHCPv6 are placed along the way and marked as TODO items. --- src/netconfig.c | 157 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 8 deletions(-) diff --git a/src/netconfig.c b/src/netconfig.c index 7d1f5509..e1ea33e4 100644 --- a/src/netconfig.c +++ b/src/netconfig.c @@ -48,6 +48,7 @@ struct netconfig { struct l_dhcp_client *dhcp_client; struct l_queue *ifaddr_list; uint8_t rtm_protocol; + uint8_t rtm_v6_protocol; const struct l_settings *active_settings; }; @@ -224,6 +225,67 @@ static char **netconfig_ipv4_get_dns(struct netconfig *netconfig, uint8_t proto) return NULL; } +static struct netconfig_ifaddr *netconfig_ipv6_get_ifaddr( + struct netconfig *netconfig, + uint8_t proto) +{ + struct in6_addr in6_addr; + struct netconfig_ifaddr *ifaddr; + char *ip; + char *p; + + switch (proto) { + case RTPROT_STATIC: + ip = l_settings_get_string(netconfig->active_settings, "IPv6", + "ip"); + if (!ip) + return NULL; + + ifaddr = l_new(struct netconfig_ifaddr, 1); + ifaddr->ip = ip; + + p = strrchr(ifaddr->ip, '/'); + if (!p) + goto no_prefix_len; + + *p = '\0'; + + if (inet_pton(AF_INET6, ifaddr->ip, &in6_addr) < 1) { + l_error("netconfig: Invalid IPv6 address %s is " + "provided in network configuration file.", + ifaddr->ip); + + netconfig_ifaddr_destroy(ifaddr); + + return NULL; + } + + if (*++p == '\0') + goto no_prefix_len; + + ifaddr->prefix_len = strtoul(p, NULL, 10); + + if (!unlikely(errno == EINVAL || errno == ERANGE || + !ifaddr->prefix_len || + ifaddr->prefix_len > 128)) + goto proceed; + +no_prefix_len: + ifaddr->prefix_len = 128; +proceed: + ifaddr->family = AF_INET6; + + return ifaddr; + + case RTPROT_DHCP: + /* TODO */ + + return NULL; + } + + return NULL; +} + static bool netconfig_ifaddr_match(const void *a, const void *b) { const struct netconfig_ifaddr *entry = a; @@ -541,6 +603,19 @@ done: netconfig_ifaddr_destroy(ifaddr); } +static void netconfig_ipv6_ifaddr_add_cmd_cb(int error, uint16_t type, + const void *data, uint32_t len, + void *user_data) +{ + if (error && error != -EEXIST) { + l_error("netconfig: Failed to add IPv6 address. " + "Error %d: %s", error, strerror(-error)); + return; + } + + /* TODO Install routes and DNS */ +} + static void netconfig_install_address(struct netconfig *netconfig, struct netconfig_ifaddr *ifaddr) { @@ -560,6 +635,16 @@ static void netconfig_install_address(struct netconfig *netconfig, l_error("netconfig: Failed to set IP %s/%u.", ifaddr->ip, ifaddr->prefix_len); break; + case AF_INET6: + if (rtnl_ifaddr_ipv6_add(rtnl, netconfig->ifindex, + ifaddr->prefix_len, ifaddr->ip, + netconfig_ipv6_ifaddr_add_cmd_cb, + netconfig, NULL)) + return; + + l_error("netconfig: Failed to set IPv6 address %s/%u.", + ifaddr->ip, ifaddr->prefix_len); + break; default: l_error("netconfig: Unsupported address family: %u", ifaddr->family); @@ -606,6 +691,16 @@ static void netconfig_uninstall_address(struct netconfig *netconfig, l_error("netconfig: Failed to delete IP %s/%u.", ifaddr->ip, ifaddr->prefix_len); break; + case AF_INET6: + if (rtnl_ifaddr_ipv6_delete(rtnl, netconfig->ifindex, + ifaddr->prefix_len, ifaddr->ip, + netconfig_ifaddr_del_cmd_cb, netconfig, + NULL)) + return; + + l_error("netconfig: Failed to delete IPv6 address %s/%u.", + ifaddr->ip, ifaddr->prefix_len); + break; default: l_error("netconfig: Unsupported address family: %u", ifaddr->family); @@ -717,6 +812,49 @@ static void netconfig_ipv4_select_and_uninstall(struct netconfig *netconfig) l_dhcp_client_stop(netconfig->dhcp_client); } +static void netconfig_ipv6_select_and_install(struct netconfig *netconfig) +{ + struct netconfig_ifaddr *ifaddr; + + ifaddr = netconfig_ipv6_get_ifaddr(netconfig, RTPROT_STATIC); + if (ifaddr) { + netconfig->rtm_v6_protocol = RTPROT_STATIC; + netconfig_install_address(netconfig, ifaddr); + netconfig_ifaddr_destroy(ifaddr); + + return; + } + + /* + * TODO + * + * netconfig->rtm_v6_protocol = RTPROT_DHCP; + * + * if (l_dhcp_v6_client_start(netconfig->l_dhcp_v6_client)) + * return; + * + * l_error("netconfig: Failed to start DHCPv6 client for " + * "interface %u", netconfig->ifindex); + */ +} + +static void netconfig_ipv6_select_and_uninstall(struct netconfig *netconfig) +{ + struct netconfig_ifaddr *ifaddr; + + ifaddr = netconfig_ipv6_get_ifaddr(netconfig, + netconfig->rtm_v6_protocol); + if (ifaddr) { + netconfig_uninstall_address(netconfig, ifaddr); + netconfig_ifaddr_destroy(ifaddr); + } + + /* + * TODO + * l_dhcp_v6_client_stop(netconfig->l_dhcp_v6_client); + */ +} + bool netconfig_configure(struct netconfig *netconfig, const struct l_settings *active_settings, const uint8_t *mac_address) @@ -728,7 +866,7 @@ bool netconfig_configure(struct netconfig *netconfig, netconfig_ipv4_select_and_install(netconfig); - /* TODO: IPv6 addressing */ + netconfig_ipv6_select_and_install(netconfig); return true; } @@ -739,7 +877,9 @@ bool netconfig_reconfigure(struct netconfig *netconfig) /* TODO l_dhcp_client sending a DHCP inform request */ } - /* TODO: IPv6 addressing */ + if (netconfig->rtm_v6_protocol == RTPROT_DHCP) { + /* TODO l_dhcp_v6_client sending a DHCP inform request */ + } return true; } @@ -747,13 +887,13 @@ bool netconfig_reconfigure(struct netconfig *netconfig) bool netconfig_reset(struct netconfig *netconfig) { netconfig_ipv4_select_and_uninstall(netconfig); + netconfig->rtm_protocol = 0; - /* TODO: IPv6 addressing */ + netconfig_ipv6_select_and_uninstall(netconfig); + netconfig->rtm_v6_protocol = 0; resolve_remove(netconfig->ifindex); - netconfig->rtm_protocol = 0; - return true; } @@ -790,13 +930,14 @@ void netconfig_destroy(struct netconfig *netconfig) l_queue_remove(netconfig_list, netconfig); - if (netconfig->rtm_protocol) { + if (netconfig->rtm_protocol) netconfig_ipv4_select_and_uninstall(netconfig); - /* TODO Uninstall IPv6 addresses. */ + if (netconfig->rtm_v6_protocol) + netconfig_ipv6_select_and_uninstall(netconfig); + if (netconfig->rtm_protocol || netconfig->rtm_v6_protocol) resolve_remove(netconfig->ifindex); - } netconfig_free(netconfig); }