X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-dhcp6.c;h=f21dd29ec112a297e74e6fceed1c3c467feae443;hp=6a1083fd5c96f91b46f08df4ea9e43b704e18fdd;hb=0c816fcc7b7b1d47bc0616edada91a44f41f1c0d;hpb=397288e3eb3bfb2c48d1a666754d2f0c7ac61ca0 diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 6a1083fd5c9..f21dd29ec11 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -6,10 +6,10 @@ #include #include #include -#include "sd-radv.h" #include "sd-dhcp6-client.h" +#include "escape.h" #include "hashmap.h" #include "hostname-util.h" #include "missing_network.h" @@ -17,21 +17,22 @@ #include "networkd-dhcp6.h" #include "networkd-link.h" #include "networkd-manager.h" +#include "networkd-radv.h" #include "siphash24.h" +#include "string-table.h" #include "string-util.h" #include "radv-internal.h" +#include "web-util.h" -static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link); static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr); static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link); static int dhcp6_prefix_remove_all(Manager *m, Link *link); -static bool dhcp6_link_has_dhcpv6_prefix(Link *link); static int dhcp6_assign_delegated_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint32_t lifetime_preferred, uint32_t lifetime_valid); -static bool dhcp6_get_prefix_delegation(Link *link) { +bool dhcp6_get_prefix_delegation(Link *link) { if (!link->network) return false; @@ -53,27 +54,29 @@ static int dhcp6_get_preferred_delegated_prefix( const struct in6_addr *pd_prefix, uint8_t pd_prefix_len, struct in6_addr *ret_addr) { - int r; - union in_addr_union pd_prefix_union = { - .in6 = *pd_prefix, - }; - int64_t subnet_id = link->network->router_prefix_subnet_id; - - assert(pd_prefix_len <= 64); + int64_t subnet_id = link->network->router_prefix_subnet_id; uint8_t prefix_bits = 64 - pd_prefix_len; uint64_t n_prefixes = UINT64_C(1) << prefix_bits; _cleanup_free_ char *assigned_buf = NULL; - + union in_addr_union pd_prefix_union = { + .in6 = *pd_prefix, + }; /* We start off with the original PD prefix we have been assigned and * iterate from there */ union in_addr_union prefix = { .in6 = *pd_prefix, }; + int r; + + assert(pd_prefix_len <= 64); + assert(manager); + assert(link); + assert(link->network); if (subnet_id >= 0) { /* If the link has a preference for a particular subnet id try to allocate that */ - if ((uint64_t)subnet_id >= n_prefixes) + if ((uint64_t) subnet_id >= n_prefixes) return log_link_debug_errno(link, SYNTHETIC_ERRNO(ERANGE), "subnet id %" PRIi64 " is out of range. Only have %" PRIu64 " subnets.", @@ -107,28 +110,24 @@ static int dhcp6_get_preferred_delegated_prefix( log_link_debug(link, "The requested prefix %s is available. Using it.", strnull(assigned_buf)); return 0; - } else { - for (uint64_t n = 0; n < n_prefixes; n++) { - /* if we do not have an allocation preference just iterate - * through the address space and return the first free prefix. */ - Link* assigned_link = dhcp6_prefix_get(manager, &prefix.in6); - - if (!assigned_link || assigned_link == link) { - *ret_addr = prefix.in6; - return 0; - } + } - r = in_addr_prefix_next(AF_INET6, &prefix, 64); - if (r < 0) - return log_link_error_errno(link, - r, - "Can't allocate another prefix. Out of address space?"); + for (uint64_t n = 0; n < n_prefixes; n++) { + /* if we do not have an allocation preference just iterate + * through the address space and return the first free prefix. */ + Link* assigned_link = dhcp6_prefix_get(manager, &prefix.in6); + + if (!assigned_link || assigned_link == link) { + *ret_addr = prefix.in6; + return 0; } - log_link_warning(link, "Couldn't find a suitable prefix. Ran out of address space."); + r = in_addr_prefix_next(AF_INET6, &prefix, 64); + if (r < 0) + return log_link_error_errno(link, r, "Can't allocate another prefix. Out of address space?: %m"); } - return -ERANGE; + return log_link_warning_errno(link, SYNTHETIC_ERRNO(ERANGE), "Couldn't find a suitable prefix. Ran out of address space."); } static bool dhcp6_enable_prefix_delegation(Link *dhcp6_link) { @@ -154,8 +153,7 @@ static bool dhcp6_enable_prefix_delegation(Link *dhcp6_link) { return false; } -static int dhcp6_lease_information_acquired(sd_dhcp6_client *client, - Link *link) { +static int dhcp6_lease_information_acquired(sd_dhcp6_client *client, Link *link) { return 0; } @@ -163,45 +161,21 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix, uint8_t prefix_len, uint32_t lifetime_preferred, uint32_t lifetime_valid) { - sd_radv *radv = link->radv; int r; - _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL; - - r = sd_radv_prefix_new(&p); - if (r < 0) - return r; - - r = sd_radv_prefix_set_prefix(p, prefix, prefix_len); - if (r < 0) - return r; - - r = sd_radv_prefix_set_preferred_lifetime(p, lifetime_preferred); - if (r < 0) - return r; - r = sd_radv_prefix_set_valid_lifetime(p, lifetime_valid); + r = radv_add_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid); if (r < 0) return r; - r = sd_radv_stop(radv); + r = dhcp6_prefix_add(link->manager, prefix, link); if (r < 0) return r; - r = sd_radv_add_prefix(radv, p, true); - if (r < 0 && r != -EEXIST) - return r; - - r = dhcp6_prefix_add(link->manager, prefix, link); + r = dhcp6_assign_delegated_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid); if (r < 0) return r; - if (link->network->dhcp6_pd_assign_prefix) { - r = dhcp6_assign_delegated_prefix(link, prefix, prefix_len, lifetime_preferred, lifetime_valid); - if (r < 0) - return r; - } - - return sd_radv_start(radv); + return 0; } static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) { @@ -220,11 +194,11 @@ static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Lin } int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) { - int r; - sd_dhcp6_lease *lease; + uint32_t lifetime_preferred, lifetime_valid; union in_addr_union pd_prefix; uint8_t pd_prefix_len; - uint32_t lifetime_preferred, lifetime_valid; + sd_dhcp6_lease *lease; + int r; r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) @@ -273,17 +247,17 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, uint32_t lifetime_preferred, uint32_t lifetime_valid, bool assign_preferred_subnet_id) { - Iterator i; - Link *link; + + _cleanup_free_ char *assigned_buf = NULL, *buf = NULL; Manager *manager = dhcp6_link->manager; union in_addr_union prefix = { .in6 = *pd_prefix, }; + bool pool_depleted = false; uint64_t n_prefixes; - _cleanup_free_ char *buf = NULL; - _cleanup_free_ char *assigned_buf = NULL; + Iterator i; + Link *link; int r; - bool pool_depleted = false; assert(manager); assert(pd_prefix_len <= 64); @@ -307,14 +281,11 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, if (!dhcp6_get_prefix_delegation(link)) continue; - if (dhcp6_link_has_dhcpv6_prefix(link)) - continue; - if (assign_preferred_subnet_id != dhcp6_has_preferred_subnet_id(link)) continue; r = dhcp6_get_preferred_delegated_prefix(manager, link, &prefix.in6, pd_prefix_len, - &assigned_prefix.in6); + &assigned_prefix.in6); if (assign_preferred_subnet_id && r == -EAGAIN) { /* A link has a preferred subnet_id but that one is @@ -350,23 +321,37 @@ static int dhcp6_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link int r; assert(link); + assert(link->dhcp6_route_messages > 0); + + link->dhcp6_route_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; r = sd_netlink_message_get_errno(m); - if (r < 0 && r != -EEXIST) - log_link_message_warning_errno(link, m, r, "Received error when adding unreachable route for DHCPv6 delegated subnet"); + if (r < 0 && r != -EEXIST) { + log_link_message_warning_errno(link, m, r, "Failed to add unreachable route for DHCPv6 delegated subnet"); + link_enter_failed(link); + return 1; + } + + if (link->dhcp6_route_messages == 0) { + log_link_debug(link, "Unreachable routes for DHCPv6 delegated subnets set"); + link->dhcp6_route_configured = true; + link_check_ready(link); + } return 1; } static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { - int r; - sd_dhcp6_lease *lease; + uint32_t lifetime_preferred, lifetime_valid; union in_addr_union pd_prefix; + sd_dhcp6_lease *lease; uint8_t pd_prefix_len; - uint32_t lifetime_preferred, lifetime_valid; + int r; + + link->dhcp6_route_configured = false; r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) @@ -412,6 +397,8 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { pd_prefix_len); continue; } + if (r > 0) + link->dhcp6_route_messages++; log_link_debug(link, "Configuring unreachable route for %s/%u", strnull(buf), pd_prefix_len); @@ -461,6 +448,14 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) { * fulfill those with the next available pd delegated prefix. */ } + if (link->dhcp6_route_messages == 0) { + link->dhcp6_route_configured = true; + link_check_ready(link); + } else { + log_link_debug(link, "Setting unreachable routes for DHCPv6 delegated subnets"); + link_set_state(link, LINK_STATE_CONFIGURING); + } + return 0; } @@ -487,14 +482,14 @@ int dhcp6_request_prefix_delegation(Link *link) { r = sd_dhcp6_client_get_prefix_delegation(l->dhcp6_client, &enabled); if (r < 0) { - log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link"); + log_link_warning_errno(l, r, "Cannot get prefix delegation when adding new link: %m"); continue; } if (enabled == 0) { r = sd_dhcp6_client_set_prefix_delegation(l->dhcp6_client, 1); if (r < 0) { - log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link"); + log_link_warning_errno(l, r, "Cannot enable prefix delegation when adding new link: 5m"); continue; } } @@ -512,13 +507,13 @@ int dhcp6_request_prefix_delegation(Link *link) { r = sd_dhcp6_client_stop(l->dhcp6_client); if (r < 0) { - log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link"); + log_link_warning_errno(l, r, "Cannot stop DHCPv6 prefix delegation client after adding new link: %m"); continue; } r = sd_dhcp6_client_start(l->dhcp6_client); if (r < 0) { - log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link"); + log_link_warning_errno(l, r, "Cannot restart DHCPv6 prefix delegation client after adding new link: %m"); continue; } @@ -532,6 +527,9 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * int r; assert(link); + assert(link->dhcp6_address_messages > 0); + + link->dhcp6_address_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; @@ -544,10 +542,14 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * } else if (r >= 0) (void) manager_rtnl_process_address(rtnl, m, link->manager); - r = link_request_set_routes(link); - if (r < 0) { - link_enter_failed(link); - return 1; + if (link->dhcp6_address_messages == 0) { + log_link_debug(link, "DHCPv6 addresses set"); + link->dhcp6_address_configured = true; + r = link_request_set_routes(link); + if (r < 0) { + link_enter_failed(link); + return 1; + } } return 1; @@ -582,6 +584,8 @@ static int dhcp6_address_change( r = address_configure(addr, link, dhcp6_address_handler, true); if (r < 0) return log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m"); + if (r > 0) + link->dhcp6_address_messages++; return 0; } @@ -592,12 +596,13 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { struct in6_addr ip6_addr; uint32_t lifetime_preferred, lifetime_valid; + link->dhcp6_address_configured = false; + r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) return r; sd_dhcp6_lease_reset_address_iter(lease); - while (sd_dhcp6_lease_get_address(lease, &ip6_addr, &lifetime_preferred, &lifetime_valid) >= 0) { @@ -607,6 +612,19 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { return r; } + if (link->dhcp6_address_messages == 0) { + link->dhcp6_address_configured = true; + return link_request_set_routes(link); + } else { + log_link_debug(link, "Setting DHCPv6 addresses"); + /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). + * Before they are called, the related flags must be cleared. Otherwise, the link + * becomes configured state before routes are configured. */ + link->static_routes_configured = false; + link->static_nexthops_configured = false; + link_set_state(link, LINK_STATE_CONFIGURING); + } + return 0; } @@ -631,7 +649,6 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { (void) dhcp6_prefix_remove_all(link->manager, link); link_dirty(link); - link->dhcp6_configured = false; break; case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: @@ -643,7 +660,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { r = dhcp6_lease_pd_prefix_acquired(client, link); if (r < 0) - log_link_debug(link, "DHCPv6 did not receive prefixes to delegate"); + log_link_debug_errno(link, r, "DHCPv6 did not receive prefixes to delegate: %m"); _fallthrough_; case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: @@ -654,7 +671,6 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { } link_dirty(link); - link->dhcp6_configured = true; break; default: @@ -691,7 +707,7 @@ int dhcp6_request_address(Link *link, int ir) { r = sd_dhcp6_client_set_address_request(link->dhcp6_client, false); - if (r < 0 ) + if (r < 0) return r; ir = false; @@ -838,7 +854,6 @@ int dhcp6_configure(Link *link) { log_link_debug(link, "DHCP6 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option); continue; } - if (r < 0) return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set request flag for '%u': %m", option); } @@ -891,21 +906,30 @@ static Link *dhcp6_prefix_get(Manager *m, struct in6_addr *addr) { return hashmap_get(m->dhcp6_prefixes, addr); } -static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) { +static int dhcp6_pd_route_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) { int r; assert(link); + assert(link->dhcp6_pd_route_messages > 0); + + link->dhcp6_pd_route_messages--; if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_message_warning_errno(link, m, r, "Received error adding DHCPv6 Prefix Delegation route"); + log_link_message_warning_errno(link, m, r, "Failed to add DHCPv6 Prefix Delegation route"); link_enter_failed(link); return 1; } + if (link->dhcp6_pd_route_messages == 0) { + log_link_debug(link, "DHCPv6 prefix delegation routes set"); + link->dhcp6_pd_route_configured = true; + link_check_ready(link); + } + return 1; } @@ -927,9 +951,14 @@ static int dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) { route->dst.in6 = *addr; route->dst_prefixlen = 64; - r = route_configure(route, link, dhcp6_route_add_handler); + link->dhcp6_pd_route_configured = false; + link_set_state(link, LINK_STATE_CONFIGURING); + + r = route_configure(route, link, dhcp6_pd_route_handler); if (r < 0) return r; + if (r > 0) + link->dhcp6_pd_route_messages++; (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf); log_link_debug(link, "Adding prefix route %s/64", strnull(buf)); @@ -1024,18 +1053,36 @@ static int dhcp6_prefix_remove_all(Manager *m, Link *link) { return 0; } -static bool dhcp6_link_has_dhcpv6_prefix(Link *link) { - Iterator i; - Link *l; +static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + int r; assert(link); - assert(link->manager); + assert(link->dhcp6_pd_address_messages > 0); - HASHMAP_FOREACH(l, link->manager->dhcp6_prefixes, i) - if (link == l) - return true; + link->dhcp6_pd_address_messages--; - return false; + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EEXIST) { + log_link_message_warning_errno(link, m, r, "Could not set DHCPv6 delegated prefix address"); + link_enter_failed(link); + return 1; + } else if (r >= 0) + (void) manager_rtnl_process_address(rtnl, m, link->manager); + + if (link->dhcp6_pd_address_messages == 0) { + log_link_debug(link, "DHCPv6 delegated prefix addresses set"); + link->dhcp6_pd_address_configured = true; + r = link_request_set_routes(link); + if (r < 0) { + link_enter_failed(link); + return 1; + } + } + + return 1; } static int dhcp6_assign_delegated_prefix(Link *link, @@ -1043,6 +1090,7 @@ static int dhcp6_assign_delegated_prefix(Link *link, uint8_t prefix_len, uint32_t lifetime_preferred, uint32_t lifetime_valid) { + _cleanup_(address_freep) Address *address = NULL; int r; @@ -1050,30 +1098,172 @@ static int dhcp6_assign_delegated_prefix(Link *link, assert(link->network); assert(prefix); - if (!link->network->dhcp6_pd_assign_prefix) + if (!link->network->dhcp6_pd_assign_prefix) { + link->dhcp6_pd_address_configured = true; return 0; + } r = address_new(&address); if (r < 0) - return log_link_error_errno(link, r, "Could not allocate address: %m"); + return log_link_error_errno(link, r, "Failed to allocate address for DHCPv6 delegated prefix: %m"); address->in_addr.in6 = *prefix; - r = generate_ipv6_eui_64_address(link, &address->in_addr.in6); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to generate EUI64 address for DHCPv6 acquired delegated prefix: %m"); + + if (!in_addr_is_null(AF_INET6, &link->network->dhcp6_delegation_prefix_token)) + memcpy(address->in_addr.in6.s6_addr + 8, link->network->dhcp6_delegation_prefix_token.in6.s6_addr + 8, 8); + else { + r = generate_ipv6_eui_64_address(link, &address->in_addr.in6); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to generate EUI64 address for acquired DHCPv6 delegated prefix: %m"); + } address->prefixlen = prefix_len; address->family = AF_INET6; address->cinfo.ifa_prefered = lifetime_preferred; address->cinfo.ifa_valid = lifetime_valid; + /* address_handler calls link_request_set_routes() and link_request_set_nexthop(). Before they + * are called, the related flags must be cleared. Otherwise, the link becomes configured state + * before routes are configured. */ + link->static_routes_configured = false; + link->static_nexthops_configured = false; + link->dhcp6_pd_address_configured = false; link_set_state(link, LINK_STATE_CONFIGURING); - r = address_configure(address, link, address_handler, true); + r = address_configure(address, link, dhcp6_pd_address_handler, true); if (r < 0) - return log_link_warning_errno(link, r, "Could not set addresses: %m"); + return log_link_warning_errno(link, r, "Failed to set acquired DHCPv6 delegated prefix address: %m"); if (r > 0) - link->address_messages++; + link->dhcp6_pd_address_messages++; return 0; } + +int config_parse_dhcp6_pd_hint( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *network = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue); + return 0; + } + + if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length); + network->dhcp6_pd_length = 0; + return 0; + } + + return 0; +} + +int config_parse_dhcp6_mud_url( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_free_ char *unescaped = NULL; + Network *network = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + network->dhcp6_mudurl = mfree(network->dhcp6_mudurl); + return 0; + } + + r = cunescape(rvalue, 0, &unescaped); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue); + return 0; + } + + if (!http_url_is_valid(unescaped) || strlen(unescaped) > UINT8_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Failed to parse MUD URL '%s', ignoring: %m", rvalue); + + return 0; + } + + return free_and_replace(network->dhcp6_mudurl, unescaped); +} + +int config_parse_dhcp6_delegated_prefix_token( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *network = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + network->dhcp6_delegation_prefix_token = IN_ADDR_NULL; + return 0; + } + + r = in_addr_from_string(AF_INET6, rvalue, &network->dhcp6_delegation_prefix_token); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse DHCPv6 %s, ignoring: %s", lvalue, rvalue); + return 0; + } + + if (in_addr_is_null(AF_INET6, &network->dhcp6_delegation_prefix_token)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "DHCPv6 %s cannot be the ANY address, ignoring: %s", lvalue, rvalue); + return 0; + } + + return 0; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp6_client_start_mode, dhcp6_client_start_mode, DHCP6ClientStartMode, + "Failed to parse WithoutRA= setting"); + +static const char* const dhcp6_client_start_mode_table[_DHCP6_CLIENT_START_MODE_MAX] = { + [DHCP6_CLIENT_START_MODE_NO] = "no", + [DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST] = "information-request", + [DHCP6_CLIENT_START_MODE_SOLICIT] = "solicit", +}; + +DEFINE_STRING_TABLE_LOOKUP(dhcp6_client_start_mode, DHCP6ClientStartMode);