From 007899f43e9f897ef7f3324768423ce04465d205 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 8 Nov 2021 12:41:47 +0900 Subject: [PATCH] network/netdev: verify specified MAC address Drop multicast bit and set local bit of the specified MAC address. This also makes failure in generating persistent MAC address non-critical. --- src/network/netdev/netdev.c | 74 ++++++++++++--------- src/network/netdev/netdev.h | 2 +- src/network/netdev/veth.c | 10 +-- test/test-network/systemd-networkd-tests.py | 3 +- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 9d17ef9ee54..2fd2659ddbb 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -2,9 +2,11 @@ #include #include +#include #include #include "alloc-util.h" +#include "arphrd-util.h" #include "bareudp.h" #include "batadv.h" #include "bond.h" @@ -23,6 +25,7 @@ #include "macvlan.h" #include "netdev.h" #include "netdevsim.h" +#include "netif-util.h" #include "netlink-util.h" #include "networkd-manager.h" #include "networkd-queue.h" @@ -423,40 +426,52 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) { #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48) -int netdev_generate_hw_addr(const char *name, struct hw_addr_data *ret) { - uint64_t result; - size_t l, sz; - uint8_t *v; +int netdev_generate_hw_addr(NetDev *netdev, const char *name, struct hw_addr_data *hw_addr) { + bool warn_invalid = false; + struct hw_addr_data a; int r; - assert(ifname); - assert(ret); + assert(netdev); + assert(name); + assert(hw_addr); - l = strlen(ifname); - sz = sizeof(sd_id128_t) + l; - v = newa(uint8_t, sz); + if (hw_addr->length == 0) { + uint64_t result; - /* fetch some persistent data unique to the machine */ - r = sd_id128_get_machine((sd_id128_t*) v); - if (r < 0) - return r; + /* HardwareAddress= is not specified. */ - /* combine with some data unique (on this machine) to this - * netdev */ - memcpy(v + sizeof(sd_id128_t), ifname, l); + if (!NETDEV_VTABLE(netdev)->generate_mac) + return 0; + + if (NETDEV_VTABLE(netdev)->iftype != ARPHRD_ETHER) + return 0; + + r = net_get_unique_predictable_data_from_name(name, &HASH_KEY, &result); + if (r < 0) { + log_netdev_warning_errno(netdev, r, + "Failed to generate persistent MAC address, ignoring: %m"); + return 0; + } - /* Let's hash the host machine ID plus the container name. We - * use a fixed, but originally randomly created hash key here. */ - result = siphash24(v, sz, HASH_KEY.bytes); + a.length = arphrd_to_hw_addr_len(NETDEV_VTABLE(netdev)->iftype); + assert(a.length <= sizeof(result)); + memcpy(a.bytes, &result, a.length); - assert_cc(ETH_ALEN <= sizeof(result)); - ret->length = ETH_ALEN; - memcpy(ret->bytes, &result, ETH_ALEN); + if (ether_addr_is_null(&a.ether) || ether_addr_is_broadcast(&a.ether)) { + log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), + "Failed to generate persistent MAC address, ignoring: %m"); + return 0; + } + } else { + a = *hw_addr; + warn_invalid = true; + } - /* see eth_random_addr in the kernel */ - ret->ether.ether_addr_octet[0] &= 0xfe; /* clear multicast bit */ - ret->ether.ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */ + r = net_verify_hardware_address(name, warn_invalid, NETDEV_VTABLE(netdev)->iftype, NULL, &a); + if (r < 0) + return r; + *hw_addr = a; return 0; } @@ -806,12 +821,9 @@ int netdev_load_one(Manager *manager, const char *filename) { if (!netdev->filename) return log_oom(); - if (netdev->hw_addr.length == 0 && NETDEV_VTABLE(netdev)->generate_mac) { - r = netdev_generate_hw_addr(netdev->ifname, &netdev->hw_addr); - if (r < 0) - return log_netdev_error_errno(netdev, r, - "Failed to generate predictable MAC address: %m"); - } + r = netdev_generate_hw_addr(netdev, netdev->ifname, &netdev->hw_addr); + if (r < 0) + return r; r = hashmap_ensure_put(&netdev->manager->netdevs, &string_hash_ops, netdev->ifname, netdev); if (r == -ENOMEM) diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index 5de2d630a6d..d480d125a69 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -198,7 +198,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref); bool netdev_is_managed(NetDev *netdev); int netdev_get(Manager *manager, const char *name, NetDev **ret); int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink); -int netdev_generate_hw_addr(const char *name, struct hw_addr_data *ret); +int netdev_generate_hw_addr(NetDev *netdev, const char *name, struct hw_addr_data *hw_addr); int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb); int request_process_stacked_netdev(Request *req); diff --git a/src/network/netdev/veth.c b/src/network/netdev/veth.c index e615ddfab54..f1c05c62052 100644 --- a/src/network/netdev/veth.c +++ b/src/network/netdev/veth.c @@ -66,13 +66,9 @@ static int netdev_veth_verify(NetDev *netdev, const char *filename) { "Veth NetDev without peer name configured in %s. Ignoring", filename); - if (v->hw_addr_peer.length == 0) { - r = netdev_generate_hw_addr(v->ifname_peer, &v->hw_addr_peer); - if (r < 0) - return log_netdev_warning_errno(netdev, r, - "Failed to generate persistent hardware address for peer '%s': %m", - v->ifname_peer); - } + r = netdev_generate_hw_addr(netdev, v->ifname_peer, &v->hw_addr_peer); + if (r < 0) + return r; return 0; } diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 943582afead..cf8e445b37e 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -1082,7 +1082,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): output = check_output('ip link show dropin-test') print(output) - self.assertRegex(output, '00:50:56:c0:00:28') + # 00:50:56:c0:00:28 was requested, and the local bit is set by networkd. + self.assertRegex(output, '02:50:56:c0:00:28') def test_match_udev_property(self): copy_unit_to_networkd_unit_path('12-dummy.netdev', '13-not-match-udev-property.network', '14-match-udev-property.network') -- 2.47.3