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.
This commit is contained in:
Yu Watanabe
2021-10-07 01:14:51 +09:00
parent ac77e0b315
commit 98692ff3b8
+62 -35
View File
@@ -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
assert(link);
assert(secret_key);
assert(prefix);
assert(ret);
/* According to RFC7217 section 5.1
* RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */
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");
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)