Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Generate systemd nspawn interface MAC aadresses based on the host id and container name https://wiki.wut.ee/sysadmin/systemd-nspawn_containers
#!/usr/bin/env python3
"""
This script implements systemd-nspawn MAC aadress generation algorithm
"""
import sys
import struct
from subprocess import run
import siphashc # https://pypi.org/project/siphashc/
# from src/nspawn/nspawn-network.c
# -n,--network-veth
# host side of vb-/ve- interface
HOST_HASH_KEY = bytes.fromhex("1a376fc746ec450bada3d53106605db1")
# container side of vb-/ve- interface
CONTAINER_HASH_KEY = bytes.fromhex("c3c4f919b557b21ce6cf1427039ceea2")
# --network-veth-extra
VETH_EXTRA_HOST_HASH_KEY = bytes.fromhex("48c7f6b7ea9d4c9eb728d4de91d5bf66")
VETH_EXTRA_CONTAINER_HASH_KEY = bytes.fromhex("af501761cef94d35840d2b2054bece59")
# --network-macvlan
MACVLAN_HASH_KEY = bytes.fromhex("00136dbc66834481bb0cf9511f24a66f")
# used when interface name is too long
SHORTEN_IFNAME_HASH_KEY = bytes.fromhex("e190a404a8ef4b518cccc33a9f11fca2")
# Based on systemd src/nspawn/nspawn-network.c
def generate_mac(machine_id, machine_name, hash_key, idx=0):
if type(machine_name) == str:
machine_name = machine_name.encode()
if idx > 0:
v = machine_id + struct.pack('<Q', idx) + machine_name
else:
v = machine_id + machine_name
result = siphashc.siphash(hash_key, v).to_bytes(8, byteorder='little')
mac = bytearray(result[:6])
mac[0] &= 0xfe; # clear multicast bit
mac[0] |= 0x02; # set local assignment bit (IEEE802)
return bytes(mac)
def format_mac(mac):
if type(mac) == bytes:
mac = mac.hex()
l = []
for idx in range(0, len(mac), 2):
l.append(mac[idx:idx+2])
return ":".join(l)
if __name__ == "__main__":
if len(sys.argv) == 3:
machine_id = bytes.fromhex(sys.argv[1])
machine_name = sys.argv[2]
elif len(sys.argv) == 2:
machine_name = sys.argv[1]
machine_id_proc = run(["systemd-id128", "machine-id"], capture_output=True, text=True)
machine_id = bytes.fromhex(machine_id_proc.stdout.strip())
else:
print("Usage: {} [machine-id] machine-name".format(sys.argv[0]), file=sys.stderr)
sys.exit(1)
mac = generate_mac(machine_id, machine_name, CONTAINER_HASH_KEY)
print(format_mac(mac))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.