From d3efcd2def3b1eb4cc87404cee434b8d8d01c4d7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 15 Jul 2022 03:36:30 +0900 Subject: [PATCH] network: refuse 169.254.0.0/24 and 169.254.255.0/24 for IPv4LLStartAddress= Follow-up for #23927. --- man/systemd.network.xml | 11 +++++------ src/basic/in-addr-util.c | 14 ++++++++++++++ src/basic/in-addr-util.h | 1 + src/libsystemd-network/sd-ipv4ll.c | 11 +---------- src/network/networkd-ipv4ll.c | 5 +++-- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 67177183042..516a42e25a0 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -401,12 +401,11 @@ IPv4LLStartAddress= - Specifies the first IPv4 link-local address to try. Takes an IPv4 address - for example 169.254.1.2, from the link-local address range 169.254.0.0/16. - This setting may be useful if the device should always have the same address - as long as there is no address conflict. When unset, a random address will be automatically selected. - Defaults to unset. - + Specifies the first IPv4 link-local address to try. Takes an IPv4 address for example + 169.254.1.2, from the link-local address range: 169.254.0.0/16 except for 169.254.0.0/24 and + 169.254.255.0/24. This setting may be useful if the device should always have the same address + as long as there is no address conflict. When unset, a random address will be automatically + selected. Defaults to unset. diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index 6f8ffaf2596..fe356c6d15c 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -49,6 +49,20 @@ bool in4_addr_is_link_local(const struct in_addr *a) { return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); } +bool in4_addr_is_link_local_dynamic(const struct in_addr *a) { + assert(a); + + if (!in4_addr_is_link_local(a)) + return false; + + /* 169.254.0.0/24 and 169.254.255.0/24 must not be used for the dynamic IPv4LL assignment. + * See RFC 3927 Section 2.1: + * The IPv4 prefix 169.254/16 is registered with the IANA for this purpose. The first 256 and last + * 256 addresses in the 169.254/16 prefix are reserved for future use and MUST NOT be selected by a + * host using this dynamic configuration mechanism. */ + return !IN_SET(be32toh(a->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); +} + bool in6_addr_is_link_local(const struct in6_addr *a) { assert(a); diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index c1e7ef965da..fbc60436c79 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -44,6 +44,7 @@ static inline bool in_addr_data_is_set(const struct in_addr_data *a) { int in_addr_is_multicast(int family, const union in_addr_union *u); bool in4_addr_is_link_local(const struct in_addr *a); +bool in4_addr_is_link_local_dynamic(const struct in_addr *a); bool in6_addr_is_link_local(const struct in6_addr *a); int in_addr_is_link_local(int family, const union in_addr_union *u); bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a); diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index fe0d8361655..155c1a5de6c 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -212,21 +212,12 @@ int sd_ipv4ll_is_running(sd_ipv4ll *ll) { return sd_ipv4acd_is_running(ll->acd); } -static bool ipv4ll_address_is_valid(const struct in_addr *address) { - assert(address); - - if (!in4_addr_is_link_local(address)) - return false; - - return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); -} - int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { int r; assert_return(ll, -EINVAL); assert_return(address, -EINVAL); - assert_return(ipv4ll_address_is_valid(address), -EINVAL); + assert_return(in4_addr_is_link_local_dynamic(address), -EINVAL); r = sd_ipv4acd_set_address(ll->acd, address); if (r < 0) diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 8833bee2330..6dfa60e08bd 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -295,9 +295,10 @@ int config_parse_ipv4ll_address( "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); return 0; } - if (!in4_addr_is_link_local(&a.in)) { + if (!in4_addr_is_link_local_dynamic(&a.in)) { log_syntax(unit, LOG_WARNING, filename, line, 0, - "Not a IPv4 link local address, ignoring assignment: %s", rvalue); + "Specified address cannot be used as an IPv4 link local address, ignoring assignment: %s", + rvalue); return 0; }