Skip to content

Instantly share code, notes, and snippets.

@artizirk
Last active April 23, 2020 11:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save artizirk/fb70ff49b9e259f32e3ed7e068838746 to your computer and use it in GitHub Desktop.
Save artizirk/fb70ff49b9e259f32e3ed7e068838746 to your computer and use it in GitHub Desktop.
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