From 6c04fccb1db16e1a3140c01a536bff4ed342f8ed Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 04:35:56 +0900 Subject: [PATCH 01/10] util: make siphash24_compress_boolean() inline This also changes the stored type from int to uint8_t in order to make hash value endianness independent. --- src/basic/siphash24.c | 6 ------ src/basic/siphash24.h | 7 ++++++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 666431aa31f..61180819b1b 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -151,12 +151,6 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { } } -void siphash24_compress_boolean(bool in, struct siphash *state) { - int i = in; - - siphash24_compress(&i, sizeof i, state); -} - uint64_t siphash24_finalize(struct siphash *state) { uint64_t b; diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index 1937fea2985..d29058e51dd 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -17,9 +17,14 @@ struct siphash { void siphash24_init(struct siphash *state, const uint8_t k[static 16]); void siphash24_compress(const void *in, size_t inlen, struct siphash *state); -void siphash24_compress_boolean(bool in, struct siphash *state); #define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) +static inline void siphash24_compress_boolean(bool in, struct siphash *state) { + uint8_t i = in; + + siphash24_compress(&i, sizeof i, state); +} + uint64_t siphash24_finalize(struct siphash *state); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]); From 1c568d65ac285d2771f20429bbab4944c6dfd69b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 04:42:11 +0900 Subject: [PATCH 02/10] util: introduce siphash24_compress_string() --- src/basic/siphash24.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index d29058e51dd..7f799ede3d1 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -25,6 +25,13 @@ static inline void siphash24_compress_boolean(bool in, struct siphash *state) { siphash24_compress(&i, sizeof i, state); } +static inline void siphash24_compress_string(const char *in, struct siphash *state) { + if (!in) + return; + + siphash24_compress(in, strlen(in), state); +} + uint64_t siphash24_finalize(struct siphash *state); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]); From f281fc1e95ff2e39c3cc4a90444434339ae24c04 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 04:54:37 +0900 Subject: [PATCH 03/10] tree-wide: use siphash24_compress_string() where it is applicable --- src/journal/catalog.c | 2 +- src/network/networkd-ndisc.c | 4 ++-- src/network/networkd-routing-policy-rule.c | 7 ++----- src/network/networkd-util.c | 2 +- src/resolve/resolved-dns-server.c | 3 +-- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/journal/catalog.c b/src/journal/catalog.c index 70b2c8b46c4..b2589271cac 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -55,7 +55,7 @@ typedef struct CatalogItem { static void catalog_hash_func(const CatalogItem *i, struct siphash *state) { siphash24_compress(&i->id, sizeof(i->id), state); - siphash24_compress(i->language, strlen(i->language), state); + siphash24_compress_string(i->language, state); } static int catalog_compare_func(const CatalogItem *a, const CatalogItem *b) { diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 409db8c3c5a..fb7fa98b2bd 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -70,7 +70,7 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, l = MAX(DIV_ROUND_UP(prefix_len, 8), 8); siphash24_compress(prefix, l, &state); - siphash24_compress(link->ifname, strlen(link->ifname), &state); + siphash24_compress_string(link->ifname, &state); siphash24_compress(&link->mac, sizeof(struct ether_addr), &state); siphash24_compress(&dad_counter, sizeof(uint8_t), &state); @@ -577,7 +577,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { } static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) { - siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state); + siphash24_compress_string(NDISC_DNSSL_DOMAIN(x), state); } static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) { diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index 9777e020ed2..e06d4b070a1 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -132,11 +132,8 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash24_compress(&rule->dport, sizeof(rule->dport), state); siphash24_compress(&rule->uid_range, sizeof(rule->uid_range), state); - if (rule->iif) - siphash24_compress(rule->iif, strlen(rule->iif), state); - - if (rule->oif) - siphash24_compress(rule->oif, strlen(rule->oif), state); + siphash24_compress_string(rule->iif, state); + siphash24_compress_string(rule->oif, state); break; default: diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index 43507d8c635..ce9319d942a 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -117,7 +117,7 @@ int kernel_route_expiration_supported(void) { } static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) { - siphash24_compress(c->filename, strlen(c->filename), state); + siphash24_compress_string(c->filename, state); siphash24_compress(&c->line, sizeof(c->line), state); } diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index c87026f434e..9c221e1989b 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -627,8 +627,7 @@ static void dns_server_hash_func(const DnsServer *s, struct siphash *state) { siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state); siphash24_compress(&s->port, sizeof(s->port), state); siphash24_compress(&s->ifindex, sizeof(s->ifindex), state); - if (s->server_name) - siphash24_compress(s->server_name, strlen(s->server_name), state); + siphash24_compress_string(s->server_name, state); } static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) { From c2a6595014c33592a541654b396c8c3f2f36284e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 05:21:28 +0900 Subject: [PATCH 04/10] network: introduce link_save_and_clean() --- src/network/networkd-link-bus.c | 3 +-- src/network/networkd-link.c | 11 +++++++++++ src/network/networkd-link.h | 1 + src/network/networkd-manager.c | 5 ++--- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index be196715053..ad114e1173d 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -629,10 +629,9 @@ int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_ return r; link_set_state(l, LINK_STATE_INITIALIZED); - r = link_save(l); + r = link_save_and_clean(l); if (r < 0) return r; - link_clean(l); return sd_bus_reply_method_return(message, NULL); } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1d73a3c34fe..092d130a44d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -4525,6 +4525,17 @@ void link_clean(Link *link) { link_unref(set_remove(link->manager->dirty_links, link)); } +int link_save_and_clean(Link *link) { + int r; + + r = link_save(link); + if (r < 0) + return r; + + link_clean(link); + return 0; +} + static const char* const link_state_table[_LINK_STATE_MAX] = { [LINK_STATE_PENDING] = "pending", [LINK_STATE_INITIALIZED] = "initialized", diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index e7369705030..45341801288 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -208,6 +208,7 @@ int link_update(Link *link, sd_netlink_message *message); void link_dirty(Link *link); void link_clean(Link *link); int link_save(Link *link); +int link_save_and_clean(Link *link); int link_carrier_reset(Link *link); bool link_has_carrier(Link *link); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index c287367d29a..59ec0de8d34 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1727,8 +1727,7 @@ static int manager_dirty_handler(sd_event_source *s, void *userdata) { manager_save(m); SET_FOREACH(link, m->dirty_links, i) - if (link_save(link) >= 0) - link_clean(link); + (void) link_save_and_clean(link); return 1; } @@ -1899,7 +1898,7 @@ int manager_start(Manager *m) { manager_save(m); HASHMAP_FOREACH(link, m->links, i) - link_save(link); + (void) link_save(link); return 0; } From 1b1422212458d85af6358465637f1a09eb554914 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 05:26:06 +0900 Subject: [PATCH 05/10] network: make bus methods sync link state file --- src/network/networkd-link-bus.c | 62 +++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index ad114e1173d..f623a9b4a1a 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -110,7 +110,10 @@ int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_ strv_free_and_replace(l->ntp, ntp); - (void) link_dirty(l); + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; return sd_bus_reply_method_return(message, NULL); } @@ -150,7 +153,10 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi free_and_replace(l->dns, dns); l->n_dns = n; - (void) link_dirty(l); + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; return sd_bus_reply_method_return(message, NULL); @@ -240,7 +246,10 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ l->search_domains = TAKE_PTR(search_domains); l->route_domains = TAKE_PTR(route_domains); - (void) link_dirty(l); + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; return sd_bus_reply_method_return(message, NULL); } @@ -271,7 +280,11 @@ int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, s if (l->dns_default_route != b) { l->dns_default_route = b; - (void) link_dirty(l); + + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; } return sd_bus_reply_method_return(message, NULL); @@ -313,7 +326,11 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er if (l->llmnr != mode) { l->llmnr = mode; - (void) link_dirty(l); + + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; } return sd_bus_reply_method_return(message, NULL); @@ -355,7 +372,11 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err if (l->mdns != mode) { l->mdns = mode; - (void) link_dirty(l); + + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; } return sd_bus_reply_method_return(message, NULL); @@ -397,7 +418,11 @@ int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd if (l->dns_over_tls_mode != mode) { l->dns_over_tls_mode = mode; - (void) link_dirty(l); + + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; } return sd_bus_reply_method_return(message, NULL); @@ -439,7 +464,11 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e if (l->dnssec_mode != mode) { l->dnssec_mode = mode; - (void) link_dirty(l); + + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; } return sd_bus_reply_method_return(message, NULL); @@ -493,7 +522,10 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v set_free_free(l->dnssec_negative_trust_anchors); l->dnssec_negative_trust_anchors = TAKE_PTR(ns); - (void) link_dirty(l); + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; return sd_bus_reply_method_return(message, NULL); } @@ -519,7 +551,11 @@ int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_e return 1; /* Polkit will call us back */ link_ntp_settings_clear(l); - (void) link_dirty(l); + + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; return sd_bus_reply_method_return(message, NULL); } @@ -545,7 +581,11 @@ int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_e return 1; /* Polkit will call us back */ link_dns_settings_clear(l); - (void) link_dirty(l); + + link_dirty(l); + r = link_save_and_clean(l); + if (r < 0) + return r; return sd_bus_reply_method_return(message, NULL); } From f91b2340770da0cbefefb865396897da99441eda Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 05:50:15 +0900 Subject: [PATCH 06/10] test-network: drop unnecessary sleep() in NetworkdStateFileTests.test_state_file --- test/test-network/systemd-networkd-tests.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 677e39765e1..efd3db8f44e 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2592,7 +2592,9 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): path = os.path.join('/run/systemd/netif/links/', ifindex) self.assertTrue(os.path.exists(path)) - time.sleep(2) + + # make link state file updated + check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env) with open(path) as f: data = f.read() @@ -2616,7 +2618,6 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): check_output(*resolvectl_cmd, 'mdns', 'dummy98', 'no', env=env) check_output(*resolvectl_cmd, 'dnssec', 'dummy98', 'yes', env=env) check_output(*timedatectl_cmd, 'ntp-servers', 'dummy98', '2.fedora.pool.ntp.org', '3.fedora.pool.ntp.org', env=env) - time.sleep(2) with open(path) as f: data = f.read() @@ -2629,7 +2630,6 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): self.assertRegex(data, r'DNSSEC=yes') check_output(*timedatectl_cmd, 'revert', 'dummy98', env=env) - time.sleep(2) with open(path) as f: data = f.read() @@ -2642,7 +2642,6 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): self.assertRegex(data, r'DNSSEC=yes') check_output(*resolvectl_cmd, 'revert', 'dummy98', env=env) - time.sleep(2) with open(path) as f: data = f.read() From 3dbd8a15d5e43520e53f482a5a17190c8543f919 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 09:08:48 +0900 Subject: [PATCH 07/10] util: use IN6_ARE_ADDR_EQUAL() macro --- src/basic/in-addr-util.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 828ea118166..ea50e26197f 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -108,11 +108,7 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_ return in4_addr_equal(&a->in, &b->in); if (family == AF_INET6) - return - a->in6.s6_addr32[0] == b->in6.s6_addr32[0] && - a->in6.s6_addr32[1] == b->in6.s6_addr32[1] && - a->in6.s6_addr32[2] == b->in6.s6_addr32[2] && - a->in6.s6_addr32[3] == b->in6.s6_addr32[3]; + return IN6_ARE_ADDR_EQUAL(&a->in6, &b->in6); return -EAFNOSUPPORT; } From 92ee90af471c49c2c17739413f7b9e572d02be91 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 09:09:08 +0900 Subject: [PATCH 08/10] network: ndisc: do not store duplicated data in Set The Address objects in the set generated by ndisc_router_generate_addresses() have the equivalent prefixlen, flags, prefered lifetime. This commit makes ndisc_router_generate_addresses() return Set of in6_addr. --- src/network/networkd-ndisc.c | 201 ++++++++++++++++++----------------- 1 file changed, 102 insertions(+), 99 deletions(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index fb7fa98b2bd..914da0c2fd3 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -35,53 +35,6 @@ #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e) -static bool stableprivate_address_is_valid(const struct in6_addr *addr) { - assert(addr); - - /* According to rfc4291, generated address should not be in the following ranges. */ - - if (memcmp(addr, &SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291, SUBNET_ROUTER_ANYCAST_PREFIXLEN) == 0) - return false; - - if (memcmp(addr, &RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291, RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN) == 0) - return false; - - if (memcmp(addr, &RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291, RESERVED_SUBNET_ANYCAST_PREFIXLEN) == 0) - return false; - - return true; -} - -static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr *addr) { - sd_id128_t secret_key; - struct siphash state; - uint64_t rid; - size_t l; - int r; - - /* 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_error_errno(r, "Failed to generate key: %m"); - - siphash24_init(&state, secret_key.bytes); - - l = MAX(DIV_ROUND_UP(prefix_len, 8), 8); - siphash24_compress(prefix, l, &state); - siphash24_compress_string(link->ifname, &state); - siphash24_compress(&link->mac, sizeof(struct ether_addr), &state); - siphash24_compress(&dad_counter, sizeof(uint8_t), &state); - - rid = htole64(siphash24_finalize(&state)); - - memcpy(addr->s6_addr, prefix->s6_addr, l); - memcpy(addr->s6_addr + l, &rid, 16 - l); - - return 0; -} - static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -228,9 +181,66 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { return 0; } -static int ndisc_router_generate_addresses(Link *link, unsigned prefixlen, uint32_t lifetime_preferred, Address *address, Set **ret) { +static bool stableprivate_address_is_valid(const struct in6_addr *addr) { + assert(addr); + + /* According to rfc4291, generated address should not be in the following ranges. */ + + if (memcmp(addr, &SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291, SUBNET_ROUTER_ANYCAST_PREFIXLEN) == 0) + return false; + + if (memcmp(addr, &RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291, RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN) == 0) + return false; + + if (memcmp(addr, &RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291, RESERVED_SUBNET_ANYCAST_PREFIXLEN) == 0) + return false; + + return true; +} + +static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, uint8_t prefix_len, uint8_t dad_counter, struct in6_addr **ret) { + _cleanup_free_ struct in6_addr *addr = NULL; + sd_id128_t secret_key; + struct siphash state; + uint64_t rid; + size_t l; + int r; + + /* 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_error_errno(r, "Failed to generate key: %m"); + + siphash24_init(&state, secret_key.bytes); + + l = MAX(DIV_ROUND_UP(prefix_len, 8), 8); + siphash24_compress(prefix, l, &state); + siphash24_compress_string(link->ifname, &state); + siphash24_compress(&link->mac, sizeof(struct ether_addr), &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(addr->s6_addr, prefix->s6_addr, l); + memcpy(addr->s6_addr + l, &rid, 16 - l); + + if (!stableprivate_address_is_valid(addr)) { + *ret = NULL; + return 0; + } + + *ret = TAKE_PTR(addr); + return 1; +} + +static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address, uint8_t prefixlen, Set **ret) { _cleanup_set_free_free_ Set *addresses = NULL; - struct in6_addr addr; IPv6Token *j; Iterator i; int r; @@ -239,76 +249,63 @@ static int ndisc_router_generate_addresses(Link *link, unsigned prefixlen, uint3 assert(address); assert(ret); - addresses = set_new(&address_hash_ops); + addresses = set_new(&in6_addr_hash_ops); if (!addresses) return log_oom(); - addr = address->in_addr.in6; ORDERED_HASHMAP_FOREACH(j, link->network->ipv6_tokens, i) { - bool have_address = false; - _cleanup_(address_freep) Address *new_address = NULL; - - r = address_new(&new_address); - if (r < 0) - return log_oom(); - - *new_address = *address; + _cleanup_free_ struct in6_addr *new_address = NULL; if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE - && memcmp(&j->prefix, &addr, FAMILY_ADDRESS_SIZE(address->family)) == 0) { + && IN6_ARE_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_stableprivate_address(link, &j->prefix, prefixlen, j->dad_counter, &new_address->in_addr.in6); + r = make_stableprivate_address(link, &j->prefix, prefixlen, j->dad_counter, &new_address); if (r < 0) + return r; + if (r > 0) break; - - if (stableprivate_address_is_valid(&new_address->in_addr.in6)) { - have_address = true; - break; - } } } else if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_STATIC) { - memcpy(new_address->in_addr.in6.s6_addr + 8, j->prefix.s6_addr + 8, 8); - have_address = true; + new_address = new(struct in6_addr, 1); + if (!new_address) + return log_oom(); + + memcpy(new_address->s6_addr, address->s6_addr, 8); + memcpy(new_address->s6_addr + 8, j->prefix.s6_addr + 8, 8); } - if (have_address) { - new_address->prefixlen = prefixlen; - new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR; - new_address->cinfo.ifa_prefered = lifetime_preferred; - + if (new_address) { r = set_put(addresses, new_address); if (r < 0) return log_link_error_errno(link, r, "Failed to store SLAAC address: %m"); - TAKE_PTR(new_address); + else if (r == 0) + log_link_debug_errno(link, r, "Generated SLAAC address is duplicated, ignoring."); + else + TAKE_PTR(new_address); } } /* fall back to EUI-64 if no tokens provided addresses */ if (set_isempty(addresses)) { - _cleanup_(address_freep) Address *new_address = NULL; + _cleanup_free_ struct in6_addr *new_address = NULL; - r = address_new(&new_address); - if (r < 0) + new_address = newdup(struct in6_addr, address, 1); + if (!new_address) return log_oom(); - *new_address = *address; - - r = generate_ipv6_eui_64_address(link, &new_address->in_addr.in6); + r = generate_ipv6_eui_64_address(link, new_address); if (r < 0) return log_link_error_errno(link, r, "Failed to generate EUI64 address: %m"); - new_address->prefixlen = prefixlen; - new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR; - new_address->cinfo.ifa_prefered = lifetime_preferred; - r = set_put(addresses, new_address); if (r < 0) return log_link_error_errno(link, r, "Failed to store SLAAC address: %m"); + TAKE_PTR(new_address); } @@ -321,9 +318,9 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining; _cleanup_set_free_free_ Set *addresses = NULL; _cleanup_(address_freep) Address *address = NULL; + struct in6_addr addr, *a; unsigned prefixlen; usec_t time_now; - Address *a; Iterator i; int r; @@ -350,41 +347,47 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r if (lifetime_preferred > lifetime_valid) return 0; + r = sd_ndisc_router_prefix_get_address(rt, &addr); + if (r < 0) + return log_link_error_errno(link, r, "Failed to get prefix address: %m"); + + r = ndisc_router_generate_addresses(link, &addr, prefixlen, &addresses); + if (r < 0) + return r; + r = address_new(&address); if (r < 0) return log_oom(); address->family = AF_INET6; - r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6); - if (r < 0) - return log_link_error_errno(link, r, "Failed to get prefix address: %m"); - - r = ndisc_router_generate_addresses(link, prefixlen, lifetime_preferred, address, &addresses); - if (r < 0) - return r; + address->prefixlen = prefixlen; + address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR; + address->cinfo.ifa_prefered = lifetime_preferred; SET_FOREACH(a, addresses, i) { Address *existing_address; /* see RFC4862 section 5.5.3.e */ - r = address_get(link, a->family, &a->in_addr, a->prefixlen, &existing_address); + r = address_get(link, AF_INET6, (union in_addr_union *) a, prefixlen, &existing_address); if (r > 0) { lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC; if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining) - a->cinfo.ifa_valid = lifetime_valid; + address->cinfo.ifa_valid = lifetime_valid; else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN) - a->cinfo.ifa_valid = lifetime_remaining; + address->cinfo.ifa_valid = lifetime_remaining; else - a->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; + address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; } else if (lifetime_valid > 0) - a->cinfo.ifa_valid = lifetime_valid; + address->cinfo.ifa_valid = lifetime_valid; else continue; /* see RFC4862 section 5.5.3.d */ - if (a->cinfo.ifa_valid == 0) + if (address->cinfo.ifa_valid == 0) continue; - r = address_configure(a, link, ndisc_address_handler, true); + address->in_addr.in6 = *a; + + r = address_configure(address, link, ndisc_address_handler, true); if (r < 0) return log_link_error_errno(link, r, "Could not set SLAAC address: %m"); if (r > 0) From 2c621495096da421c380d8b3eda21421033876e0 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 09:42:30 +0900 Subject: [PATCH 09/10] network: ndisc: ignore duplicated IPv6Token= --- src/network/networkd-ndisc.c | 43 +++++++++++++++++++++++----------- src/network/networkd-network.c | 2 +- src/network/networkd-network.h | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 914da0c2fd3..a91c0999967 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -253,7 +253,7 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address, if (!addresses) return log_oom(); - ORDERED_HASHMAP_FOREACH(j, link->network->ipv6_tokens, i) { + ORDERED_SET_FOREACH(j, link->network->ipv6_tokens, i) { _cleanup_free_ struct in6_addr *new_address = NULL; if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE @@ -907,12 +907,26 @@ int ipv6token_new(IPv6Token **ret) { return 0; } -DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( +static void ipv6_token_hash_func(const IPv6Token *p, struct siphash *state) { + siphash24_compress(&p->address_generation_type, sizeof(p->address_generation_type), state); + siphash24_compress(&p->prefix, sizeof(p->prefix), state); +} + +static int ipv6_token_compare_func(const IPv6Token *a, const IPv6Token *b) { + int r; + + r = CMP(a->address_generation_type, b->address_generation_type); + if (r != 0) + return r; + + return memcmp(&a->prefix, &b->prefix, sizeof(struct in6_addr)); +} + +DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( ipv6_token_hash_ops, - void, - trivial_hash_func, - trivial_compare_func, IPv6Token, + ipv6_token_hash_func, + ipv6_token_compare_func, free); int config_parse_ndisc_deny_listed_prefix( @@ -1002,7 +1016,7 @@ int config_parse_address_generation_type( assert(data); if (isempty(rvalue)) { - network->ipv6_tokens = ordered_hashmap_free(network->ipv6_tokens); + network->ipv6_tokens = ordered_set_free(network->ipv6_tokens); return 0; } @@ -1034,18 +1048,19 @@ int config_parse_address_generation_type( token->prefix = buffer.in6; - r = ordered_hashmap_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops); + r = ordered_set_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops); if (r < 0) return log_oom(); - r = ordered_hashmap_put(network->ipv6_tokens, &token->prefix, token); - if (r < 0) { + r = ordered_set_put(network->ipv6_tokens, token); + if (r == -EEXIST) + log_syntax(unit, LOG_DEBUG, filename, line, r, + "IPv6 token '%s' is duplicated, ignoring: %m", rvalue); + else if (r < 0) log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to store IPv6 token '%s'", rvalue); - return 0; - } - - TAKE_PTR(token); + "Failed to store IPv6 token '%s', ignoring: %m", rvalue); + else + TAKE_PTR(token); return 0; } diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 94a1a6100fe..591d63c6b2c 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -763,7 +763,7 @@ static Network *network_free(Network *network) { ordered_hashmap_free(network->dhcp_client_send_vendor_options); ordered_hashmap_free(network->dhcp_server_send_options); ordered_hashmap_free(network->dhcp_server_send_vendor_options); - ordered_hashmap_free(network->ipv6_tokens); + ordered_set_free(network->ipv6_tokens); ordered_hashmap_free(network->dhcp6_client_send_options); ordered_hashmap_free(network->dhcp6_client_send_vendor_options); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 17109d139cf..4c3c2bdd743 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -255,7 +255,7 @@ struct Network { IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client; uint32_t ipv6_accept_ra_route_table; Set *ndisc_deny_listed_prefix; - OrderedHashmap *ipv6_tokens; + OrderedSet *ipv6_tokens; IPv6PrivacyExtensions ipv6_privacy_extensions; From 7f8c1e95a54ab5af5a766325ead56abff88ed13e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 21 Jul 2020 09:45:11 +0900 Subject: [PATCH 10/10] test-network: add test for duplicated IPv6Token= --- .../conf/ipv6-prefix-veth-token-static-multiple.network | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-network/conf/ipv6-prefix-veth-token-static-multiple.network b/test/test-network/conf/ipv6-prefix-veth-token-static-multiple.network index 49c6f31e77e..18fecb88028 100644 --- a/test/test-network/conf/ipv6-prefix-veth-token-static-multiple.network +++ b/test/test-network/conf/ipv6-prefix-veth-token-static-multiple.network @@ -4,4 +4,6 @@ Name=veth99 [Network] IPv6AcceptRA=true IPv6Token=::1a:2b:3c:4d +IPv6Token=::1a:2b:3c:4d +IPv6Token=::1a:2b:3c:4d IPv6Token=::fa:de:ca:fe