mirror of
https://github.com/systemd/systemd.git
synced 2026-08-03 06:30:30 +00:00
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.
This commit is contained in:
@@ -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);
|
||||
/* HardwareAddress= is not specified. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
a.length = arphrd_to_hw_addr_len(NETDEV_VTABLE(netdev)->iftype);
|
||||
assert(a.length <= sizeof(result));
|
||||
memcpy(a.bytes, &result, a.length);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
r = net_verify_hardware_address(name, warn_invalid, NETDEV_VTABLE(netdev)->iftype, NULL, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* combine with some data unique (on this machine) to this
|
||||
* netdev */
|
||||
memcpy(v + sizeof(sd_id128_t), ifname, l);
|
||||
|
||||
/* 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);
|
||||
|
||||
assert_cc(ETH_ALEN <= sizeof(result));
|
||||
ret->length = ETH_ALEN;
|
||||
memcpy(ret->bytes, &result, ETH_ALEN);
|
||||
|
||||
/* 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) */
|
||||
|
||||
*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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user