]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network/netdev: verify specified MAC address 21535/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 8 Nov 2021 03:41:47 +0000 (12:41 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 26 Nov 2021 21:39:04 +0000 (06:39 +0900)
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
src/network/netdev/netdev.h
src/network/netdev/veth.c
test/test-network/systemd-networkd-tests.py

index 9d17ef9ee54ef561b55dad48694108f3f7be8e67..2fd2659ddbb1355dfbdfe2ede0d84f4151fb585a 100644 (file)
@@ -2,9 +2,11 @@
 
 #include <net/if.h>
 #include <netinet/in.h>
+#include <linux/if_arp.h>
 #include <unistd.h>
 
 #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)
index 5de2d630a6d859b78ae2ab6e12673340337c90f9..d480d125a69bdbfed026425e12cba02dc41ed746 100644 (file)
@@ -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);
index e615ddfab54c77fe006e955a456e3af02af3b3bc..f1c05c6205204a2f21e9d7bfddd9f5be401ed2f8 100644 (file)
@@ -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;
 }
index 943582afeade148672606a08af812166bea68652..cf8e445b37e225751e3712210677f9ad3d979c48 100755 (executable)
@@ -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')