From 93e44aa92f64f634be1c86f5b1855997bef7aaf3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 20 Apr 2021 21:12:22 +0900 Subject: [PATCH 1/4] in-addr-util: add assertions --- src/basic/in-addr-util.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index c11e6ceb90..13cdb9e5a5 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -803,6 +803,9 @@ int in_addr_prefix_from_string_auto_internal( } static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) { + assert(a); + assert(state); + siphash24_compress(&a->family, sizeof(a->family), state); siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state); } @@ -810,6 +813,9 @@ static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) { int r; + assert(x); + assert(y); + r = CMP(x->family, y->family); if (r != 0) return r; @@ -821,11 +827,15 @@ DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_fu void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) { assert(addr); + assert(state); siphash24_compress(addr, sizeof(*addr), state); } int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) { + assert(a); + assert(b); + return memcmp(a, b, sizeof(*a)); } From eccdc687717568303de1448f20863b20f7315cb4 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 20 Apr 2021 10:49:21 +0900 Subject: [PATCH 2/4] in-addr-util: introduce 'struct in_addr_prefix' and hash ops for it --- src/basic/in-addr-util.c | 29 +++++++++++++++++++++++++++++ src/basic/in-addr-util.h | 8 ++++++++ 2 files changed, 37 insertions(+) diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 13cdb9e5a5..9d7e51f8fd 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -825,6 +825,35 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func); +static void in_addr_prefix_hash_func(const struct in_addr_prefix *a, struct siphash *state) { + assert(a); + assert(state); + + siphash24_compress(&a->family, sizeof(a->family), state); + siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state); + siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state); +} + +static int in_addr_prefix_compare_func(const struct in_addr_prefix *x, const struct in_addr_prefix *y) { + int r; + + assert(x); + assert(y); + + r = CMP(x->family, y->family); + if (r != 0) + return r; + + r = CMP(x->prefixlen, y->prefixlen); + if (r != 0) + return r; + + return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family)); +} + +DEFINE_HASH_OPS(in_addr_prefix_hash_ops, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func); +DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(in_addr_prefix_hash_ops_free, struct in_addr_prefix, in_addr_prefix_hash_func, in_addr_prefix_compare_func, free); + void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) { assert(addr); assert(state); diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 519ee53b3a..d5caf662ab 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -20,6 +20,12 @@ struct in_addr_data { union in_addr_union address; }; +struct in_addr_prefix { + int family; + uint8_t prefixlen; + union in_addr_union address; +}; + bool in4_addr_is_null(const struct in_addr *a); static inline bool in4_addr_is_set(const struct in_addr *a) { return !in4_addr_is_null(a); @@ -111,4 +117,6 @@ void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state); int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b); extern const struct hash_ops in_addr_data_hash_ops; +extern const struct hash_ops in_addr_prefix_hash_ops; +extern const struct hash_ops in_addr_prefix_hash_ops_free; extern const struct hash_ops in6_addr_hash_ops; From 4b409e855b18c263b0526c826fdca16215a4cf2e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 20 Apr 2021 10:50:36 +0900 Subject: [PATCH 3/4] network: dhcp6: logs about delegated prefixes Closes #19354. --- src/network/networkd-dhcp6.c | 58 +++++++++++++++++++++++++++++------- src/network/networkd-link.c | 2 ++ src/network/networkd-link.h | 1 + 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index f5e66b9457..73987600d2 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -652,6 +652,8 @@ static void dhcp6_pd_prefix_lost(Link *dhcp6_link) { if (r < 0) link_enter_failed(link); } + + set_clear(dhcp6_link->dhcp6_pd_prefixes); } static int dhcp6_remove_old(Link *link, bool force); @@ -794,20 +796,12 @@ static int dhcp6_set_unreachable_route(Link *link, const union in_addr_union *ad (void) in_addr_prefix_to_string(AF_INET6, addr, prefixlen, &buf); - if (prefixlen > 64) { - log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s", strna(buf)); - return 0; - } - if (prefixlen == 64) { log_link_debug(link, "Not adding a blocking route for DHCPv6 delegated subnet %s since distributed prefix is 64", strna(buf)); - return 1; + return 0; } - if (prefixlen < 48) - log_link_warning(link, "PD Prefix length < 48, looks unusual: %s", strna(buf)); - r = route_new(&route); if (r < 0) return log_oom(); @@ -835,7 +829,45 @@ static int dhcp6_set_unreachable_route(Link *link, const union in_addr_union *ad (void) set_remove(link->dhcp6_routes_old, ret); - return 1; + return 0; +} + +static int dhcp6_pd_prefix_add(Link *link, const union in_addr_union *prefix, uint8_t prefixlen) { + _cleanup_free_ struct in_addr_prefix *p = NULL; + _cleanup_free_ char *buf = NULL; + int r; + + assert(link); + assert(prefix); + + p = new(struct in_addr_prefix, 1); + if (!p) + return log_oom(); + + *p = (struct in_addr_prefix) { + .family = AF_INET6, + .prefixlen = prefixlen, + .address = *prefix, + }; + + (void) in_addr_prefix_to_string(p->family, &p->address, p->prefixlen, &buf); + + log_link_full(link, + set_contains(link->dhcp6_pd_prefixes, p) ? LOG_DEBUG : + prefixlen > 64 || prefixlen < 48 ? LOG_WARNING : LOG_INFO, + "DHCP6: received PD Prefix %s%s", + strna(buf), + prefixlen > 64 ? " with prefix length > 64, ignoring." : + prefixlen < 48 ? " with prefix lenght < 48, looks unusual.": ""); + + /* Store PD prefix even if prefixlen > 64, not to make logged at warning level so frequently. */ + r = set_ensure_put(&link->dhcp6_pd_prefixes, &in_addr_prefix_hash_ops_free, p); + if (r < 0) + return log_link_error_errno(link, r, "Failed to store DHCP6 PD prefix %s: %m", strna(buf)); + if (r > 0) + TAKE_PTR(p); + + return prefixlen <= 64; } static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { @@ -864,12 +896,16 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { if (r < 0) break; - r = dhcp6_set_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len); + r = dhcp6_pd_prefix_add(dhcp6_link, &pd_prefix, pd_prefix_len); if (r < 0) return r; if (r == 0) continue; + r = dhcp6_set_unreachable_route(dhcp6_link, &pd_prefix, pd_prefix_len); + if (r < 0) + return r; + /* We are doing prefix allocation in two steps: * 1. all those links that have a preferred subnet id will be assigned their subnet * 2. all those links that remain will receive prefixes in sequential order. Prefixes diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5143502745..127780ec60 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -573,6 +573,8 @@ static Link *link_free(Link *link) { link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old); link->ndisc_addresses = set_free(link->ndisc_addresses); + link->dhcp6_pd_prefixes = set_free(link->dhcp6_pd_prefixes); + link_free_engines(link); free(link->ifname); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index a8bdd971f5..a9f6cf61eb 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -151,6 +151,7 @@ typedef struct Link { sd_dhcp6_lease *dhcp6_lease; Set *dhcp6_addresses, *dhcp6_addresses_old; Set *dhcp6_routes, *dhcp6_routes_old; + Set *dhcp6_pd_prefixes; Set *dhcp6_pd_addresses, *dhcp6_pd_addresses_old; Set *dhcp6_pd_routes, *dhcp6_pd_routes_old; unsigned dhcp6_address_messages; From baad6421b1c04e6968a69701be9a7aabbcdad989 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 20 Apr 2021 10:08:08 +0900 Subject: [PATCH 4/4] network: dhcp6: logs about generated addresses in delegated prefix --- src/network/networkd-dhcp6.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 73987600d2..899d912151 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -363,6 +363,33 @@ static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin return 1; } +static void log_dhcp6_pd_address(Link *link, const Address *address) { + char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX]; + const char *valid_str = NULL, *preferred_str = NULL; + _cleanup_free_ char *buffer = NULL; + int log_level; + + log_level = address_get(link, address, NULL) >= 0 ? LOG_DEBUG : LOG_INFO; + + if (log_level < log_get_max_level()) + return; + + (void) in_addr_prefix_to_string(address->family, &address->in_addr, address->prefixlen, &buffer); + if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME) + valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, + address->cinfo.ifa_valid * USEC_PER_SEC, + USEC_PER_SEC); + if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME) + preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX, + address->cinfo.ifa_prefered * USEC_PER_SEC, + USEC_PER_SEC); + + log_link_full(link, log_level, "DHCPv6-PD address %s (valid %s%s, preferred %s%s)", + strna(buffer), + valid_str ? "for " : "forever", strempty(valid_str), + preferred_str ? "for " : "forever", strempty(preferred_str)); +} + static int dhcp6_set_pd_address( Link *link, const union in_addr_union *prefix, @@ -400,6 +427,7 @@ static int dhcp6_set_pd_address( address->cinfo.ifa_valid = lifetime_valid; SET_FLAG(address->flags, IFA_F_MANAGETEMPADDR, link->network->dhcp6_pd_manage_temporary_address); + log_dhcp6_pd_address(link, address); r = address_configure(address, link, dhcp6_pd_address_handler, &ret); if (r < 0) return log_link_error_errno(link, r, "Failed to set DHCPv6 delegated prefix address: %m");