| commit 2a236f9fc0ff8fb2152032551436fde74da7217a |
| Author: Yu Watanabe <watanabe.yu+github@gmail.com> |
| Date: Thu Dec 3 10:19:35 2020 +0900 |
| |
| network: ignore broadcast address for /31 or /32 addresses |
| |
| As they do not have broadcast address. |
| See https://tools.ietf.org/html/rfc3021 |
| |
| diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c |
| index 0eb47f6e65..0c32ab8ff3 100644 |
| --- a/src/network/networkd-address.c |
| +++ b/src/network/networkd-address.c |
| @@ -144,29 +144,35 @@ Address *address_free(Address *address) { |
| return mfree(address); |
| } |
| |
| +static bool address_may_have_broadcast(const Address *a) { |
| + assert(a); |
| + |
| + /* A /31 or /32 IPv4 address does not have a broadcast address. |
| + * See https://tools.ietf.org/html/rfc3021 */ |
| + |
| + return a->family == AF_INET && in4_addr_is_null(&a->in_addr_peer.in) && a->prefixlen <= 30; |
| +} |
| + |
| void address_hash_func(const Address *a, struct siphash *state) { |
| assert(a); |
| |
| siphash24_compress(&a->family, sizeof(a->family), state); |
| |
| - switch (a->family) { |
| - case AF_INET: |
| - siphash24_compress(&a->broadcast, sizeof(a->broadcast), state); |
| + if (!IN_SET(a->family, AF_INET, AF_INET6)) |
| + /* treat non-IPv4 or IPv6 address family as AF_UNSPEC */ |
| + return; |
| + |
| + if (a->family == AF_INET) |
| siphash24_compress_string(a->label, state); |
| |
| - _fallthrough_; |
| - case AF_INET6: |
| - siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state); |
| - /* local address */ |
| - siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state); |
| - /* peer address */ |
| - siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state); |
| + siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state); |
| + /* local address */ |
| + siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state); |
| + /* peer address */ |
| + siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state); |
| |
| - break; |
| - default: |
| - /* treat any other address family as AF_UNSPEC */ |
| - break; |
| - } |
| + if (address_may_have_broadcast(a)) |
| + siphash24_compress(&a->broadcast, sizeof(a->broadcast), state); |
| } |
| |
| int address_compare_func(const Address *a1, const Address *a2) { |
| @@ -176,32 +182,32 @@ int address_compare_func(const Address *a1, const Address *a2) { |
| if (r != 0) |
| return r; |
| |
| - switch (a1->family) { |
| - /* use the same notion of equality as the kernel does */ |
| - case AF_INET: |
| - r = CMP(a1->broadcast.s_addr, a2->broadcast.s_addr); |
| - if (r != 0) |
| - return r; |
| + if (!IN_SET(a1->family, AF_INET, AF_INET6)) |
| + /* treat non-IPv4 or IPv6 address family as AF_UNSPEC */ |
| + return 0; |
| |
| + if (a1->family == AF_INET) { |
| r = strcmp_ptr(a1->label, a2->label); |
| if (r != 0) |
| return r; |
| + } |
| |
| - _fallthrough_; |
| - case AF_INET6: |
| - r = CMP(a1->prefixlen, a2->prefixlen); |
| - if (r != 0) |
| - return r; |
| + r = CMP(a1->prefixlen, a2->prefixlen); |
| + if (r != 0) |
| + return r; |
| |
| - r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family)); |
| - if (r != 0) |
| - return r; |
| + r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family)); |
| + if (r != 0) |
| + return r; |
| |
| - return memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family)); |
| - default: |
| - /* treat any other address family as AF_UNSPEC */ |
| - return 0; |
| - } |
| + r = memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family)); |
| + if (r != 0) |
| + return r; |
| + |
| + if (address_may_have_broadcast(a1)) |
| + return CMP(a1->broadcast.s_addr, a2->broadcast.s_addr); |
| + |
| + return 0; |
| } |
| |
| DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free); |
| @@ -222,18 +228,21 @@ static int address_copy(Address *dest, const Address *src) { |
| assert(dest); |
| assert(src); |
| |
| - r = free_and_strdup(&dest->label, src->label); |
| - if (r < 0) |
| - return r; |
| + if (src->family == AF_INET) { |
| + r = free_and_strdup(&dest->label, src->label); |
| + if (r < 0) |
| + return r; |
| + } |
| |
| dest->family = src->family; |
| dest->prefixlen = src->prefixlen; |
| dest->scope = src->scope; |
| dest->flags = src->flags; |
| - dest->broadcast = src->broadcast; |
| dest->cinfo = src->cinfo; |
| dest->in_addr = src->in_addr; |
| dest->in_addr_peer = src->in_addr_peer; |
| + if (address_may_have_broadcast(src)) |
| + dest->broadcast = src->broadcast; |
| dest->duplicate_address_detection = src->duplicate_address_detection; |
| |
| return 0; |
| @@ -840,13 +849,13 @@ int address_configure( |
| r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer); |
| if (r < 0) |
| return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m"); |
| - } else if (address->family == AF_INET && address->prefixlen <= 30) { |
| + } else if (address_may_have_broadcast(address)) { |
| r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); |
| if (r < 0) |
| return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m"); |
| } |
| |
| - if (address->label) { |
| + if (address->family == AF_INET && address->label) { |
| r = sd_netlink_message_append_string(req, IFA_LABEL, address->label); |
| if (r < 0) |
| return log_link_error_errno(link, r, "Could not append IFA_LABEL attribute: %m"); |
| @@ -1809,9 +1818,7 @@ static int address_section_verify(Address *address) { |
| address->section->filename, address->section->line); |
| } |
| |
| - if (address->family == AF_INET && |
| - in_addr_is_null(address->family, &address->in_addr_peer) && |
| - address->prefixlen <= 30) { |
| + if (address_may_have_broadcast(address)) { |
| if (address->broadcast.s_addr == 0) |
| address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen); |
| } else if (address->broadcast.s_addr != 0) { |