From: Yu Watanabe Date: Sat, 6 Nov 2021 01:55:21 +0000 (+0900) Subject: netif-util: introduce net_verify_hardware_address() X-Git-Tag: v250-rc1~149^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=37593b7c488f7b957936500158f200af16534c6b;p=thirdparty%2Fsystemd.git netif-util: introduce net_verify_hardware_address() --- diff --git a/src/shared/netif-util.c b/src/shared/netif-util.c index 85b6ad45c8b..8d3d4473fa6 100644 --- a/src/shared/netif-util.c +++ b/src/shared/netif-util.c @@ -1,7 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include + #include "arphrd-util.h" #include "device-util.h" +#include "log-link.h" +#include "memory-util.h" #include "netif-util.h" #include "siphash24.h" #include "sparse-endian.h" @@ -99,3 +103,91 @@ int net_get_unique_predictable_data_from_name( *ret = htole64(siphash24(v, sz, key->bytes)); return 0; } + +typedef struct Link { + const char *ifname; +} Link; + +int net_verify_hardware_address( + const char *ifname, + bool warn_invalid, + uint16_t iftype, + const struct hw_addr_data *ib_hw_addr, /* current or parent HW address */ + struct hw_addr_data *new_hw_addr) { + + Link link = { .ifname = ifname }; + + assert(new_hw_addr); + + if (new_hw_addr->length == 0) + return 0; + + if (new_hw_addr->length != arphrd_to_hw_addr_len(iftype)) { + if (warn_invalid) + log_link_warning(&link, + "Specified MAC address with invalid length (%zu, expected %zu), refusing.", + new_hw_addr->length, arphrd_to_hw_addr_len(iftype)); + return -EINVAL; + } + + switch (iftype) { + case ARPHRD_ETHER: + /* see eth_random_addr() in the kernel */ + + if (ether_addr_is_null(&new_hw_addr->ether)) { + if (warn_invalid) + log_link_warning(&link, "Specified MAC address is null, refusing."); + return -EINVAL; + } + + if (ether_addr_is_broadcast(&new_hw_addr->ether)) { + if (warn_invalid) + log_link_warning(&link, "Specified MAC address is broadcast, refusing."); + return -EINVAL; + } + + if (ether_addr_is_multicast(&new_hw_addr->ether)) { + if (warn_invalid) + log_link_warning(&link, "Specified MAC address has multicast bit set, clearing the bit."); + + new_hw_addr->bytes[0] &= 0xfe; + } + + if (!ether_addr_is_local(&new_hw_addr->ether)) { + if (warn_invalid) + log_link_warning(&link, "Specified MAC address has not local assignment bit set, setting the bit."); + + new_hw_addr->bytes[0] |= 0x02; + } + + break; + + case ARPHRD_INFINIBAND: + /* see ipoib_check_lladdr() in the kernel */ + + assert(ib_hw_addr); + assert(ib_hw_addr->length == INFINIBAND_ALEN); + + if (warn_invalid && + (!memeqzero(new_hw_addr->bytes, INFINIBAND_ALEN - 8) || + memcmp(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8) != 0)) + log_link_warning(&link, "Only the last 8 bytes of the InifniBand MAC address can be changed, ignoring the first 12 bytes."); + + if (memeqzero(new_hw_addr->bytes + INFINIBAND_ALEN - 8, 8)) { + if (warn_invalid) + log_link_warning(&link, "The last 8 bytes of the InfiniBand MAC address cannot be null, refusing."); + return -EINVAL; + } + + memcpy(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8); + break; + + default: + if (warn_invalid) + log_link_warning(&link, "Unsupported interface type %s%u to set MAC address, refusing.", + strna(arphrd_to_name(iftype)), iftype); + return -EINVAL; + } + + return 0; +} diff --git a/src/shared/netif-util.h b/src/shared/netif-util.h index f239f042b58..09776811538 100644 --- a/src/shared/netif-util.h +++ b/src/shared/netif-util.h @@ -7,7 +7,15 @@ #include "sd-device.h" #include "sd-id128.h" +#include "ether-addr-util.h" + int net_get_type_string(sd_device *device, uint16_t iftype, char **ret); const char *net_get_persistent_name(sd_device *device); int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *ret); int net_get_unique_predictable_data_from_name(const char *name, const sd_id128_t *key, uint64_t *ret); +int net_verify_hardware_address( + const char *ifname, + bool warn_invalid, + uint16_t iftype, + const struct hw_addr_data *ib_hw_addr, + struct hw_addr_data *new_hw_addr);