From: Yu Watanabe Date: Fri, 1 Oct 2021 11:57:59 +0000 (+0900) Subject: network: address-generation: always start DAD counter from zero X-Git-Tag: v250-rc1~552^2~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=98692ff3b8a1f03309c34ed7eaff739ebb174dc3;p=thirdparty%2Fsystemd.git network: address-generation: always start DAD counter from zero The token is stored in Network, and the .network file may be applied to multiple links. --- diff --git a/src/network/networkd-address-generation.c b/src/network/networkd-address-generation.c index a4f53436e31..b0c9a95a01e 100644 --- a/src/network/networkd-address-generation.c +++ b/src/network/networkd-address-generation.c @@ -32,8 +32,6 @@ typedef enum IPv6TokenAddressGeneration { typedef struct IPv6Token { IPv6TokenAddressGeneration address_generation_type; - - uint8_t dad_counter; struct in6_addr prefix; } IPv6Token; @@ -79,47 +77,78 @@ static bool stable_private_address_is_valid(const struct in6_addr *addr) { return true; } -static int make_stable_private_address(Link *link, const struct in6_addr *prefix, uint8_t dad_counter, struct in6_addr **ret) { - _cleanup_free_ struct in6_addr *addr = NULL; - sd_id128_t secret_key; +static void generate_stable_private_address_one( + Link *link, + const sd_id128_t *secret_key, + const struct in6_addr *prefix, + uint8_t dad_counter, + struct in6_addr *ret) { + struct siphash state; uint64_t rid; - int r; - /* According to rfc7217 section 5.1 - * RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */ + assert(link); + assert(secret_key); + assert(prefix); + assert(ret); - r = sd_id128_get_machine_app_specific(NDISC_APP_ID, &secret_key); - if (r < 0) - return log_link_warning_errno(link, r, "Failed to generate key for IPv6 stable private address: %m"); + /* According to RFC7217 section 5.1 + * RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */ - siphash24_init(&state, secret_key.bytes); + siphash24_init(&state, secret_key->bytes); siphash24_compress(prefix, 8, &state); siphash24_compress_string(link->ifname, &state); - /* Only last 8 bytes of IB MAC are stable */ if (link->iftype == ARPHRD_INFINIBAND) - siphash24_compress(&link->hw_addr.infiniband[12], 8, &state); + /* Only last 8 bytes of IB MAC are stable */ + siphash24_compress(&link->hw_addr.infiniband[INFINIBAND_ALEN - 8], 8, &state); else siphash24_compress(link->hw_addr.bytes, link->hw_addr.length, &state); siphash24_compress(&dad_counter, sizeof(uint8_t), &state); rid = htole64(siphash24_finalize(&state)); - addr = new(struct in6_addr, 1); - if (!addr) - return log_oom(); + memcpy(ret->s6_addr, prefix->s6_addr, 8); + memcpy(ret->s6_addr + 8, &rid, 8); +} - memcpy(addr->s6_addr, prefix->s6_addr, 8); - memcpy(addr->s6_addr + 8, &rid, 8); +static int generate_stable_private_address( + Link *link, + const sd_id128_t *app_id, + const struct in6_addr *prefix, + struct in6_addr *ret) { - if (!stable_private_address_is_valid(addr)) { - *ret = NULL; - return 0; + struct in6_addr addr; + sd_id128_t secret_key; + uint8_t i; + int r; + + assert(link); + assert(app_id); + assert(prefix); + assert(ret); + + r = sd_id128_get_machine_app_specific(*app_id, &secret_key); + if (r < 0) + return log_link_debug_errno(link, r, "Failed to generate secret key for IPv6 stable private address: %m"); + + /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop does + * not actually attempt Duplicate Address Detection; the counter will be incremented only when + * the address generation algorithm produces an invalid address, and the loop may exit with an + * address which ends up being unusable due to duplication on the link. */ + for (i = 0; i < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; i++) { + generate_stable_private_address_one(link, &secret_key, prefix, i, &addr); + + if (stable_private_address_is_valid(&addr)) + break; } + if (i >= DAD_CONFLICTS_IDGEN_RETRIES_RFC7217) + /* propagate recognizable errors. */ + return log_link_debug_errno(link, SYNTHETIC_ERRNO(ENOANO), + "Failed to generate stable private address."); - *ret = TAKE_PTR(addr); - return 1; + *ret = addr; + return 0; } int ndisc_router_generate_addresses(Link *link, struct in6_addr *address, uint8_t prefixlen, Set **ret) { @@ -140,17 +169,15 @@ int ndisc_router_generate_addresses(Link *link, struct in6_addr *address, uint8_ if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE && (in6_addr_is_null(&j->prefix) || in6_addr_equal(&j->prefix, address))) { - /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop - * does not actually attempt Duplicate Address Detection; the counter will be incremented - * only when the address generation algorithm produces an invalid address, and the loop - * may exit with an address which ends up being unusable due to duplication on the link. */ - for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) { - r = make_stable_private_address(link, address, j->dad_counter, &new_address); - if (r < 0) - return r; - if (r > 0) - break; - } + struct in6_addr addr; + + if (generate_stable_private_address(link, &NDISC_APP_ID, address, &addr) < 0) + continue; + + new_address = newdup(struct in6_addr, &addr, 1); + if (!new_address) + return log_oom(); + } else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC) { new_address = new(struct in6_addr, 1); if (!new_address)