Skip to content

Allow AF_NETLINK in the systemd unit so the MAC-derived client id is detected - #53

Merged
chrisuthe merged 1 commit into
mainfrom
chrisuthe/task/allow-af-netlink-in-the-systemd-unit-so-the-mac
Sep 14, 2026
Merged

chrisuthe merged 1 commit into
mainfrom
chrisuthe/task/allow-af-netlink-in-the-systemd-unit-so-the-mac

Conversation

@chrisuthe

Copy link
Copy Markdown
Member

Under the shipped systemd unit a player with no id is never taken by Music Assistant. Reported on 0.1.6 on a Raspberry Pi 4 (installed with scripts/get_started_linux.sh, MA 2.10.2). Running sendspin-cli by hand works.

  • Client journal: W sendspin.network_info: getifaddrs failed; cannot auto-detect MAC address
  • MA log: Exception in task ... SendspinProvider._handle_client_added ...: No key provided

Cause

RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 blocks netlink. glibc's getifaddrs() reads the interface list over netlink and has no fallback. sendspin-cpp v0.7.2 derives the default client_id from the interface MAC while building client/hello, so when detection fails the hello goes out with an empty client_id, and MA's cache asserts on the empty key.

The unit comment, ROADMAP and a CI comment all said netlink was unneeded because glibc falls back. That was checked for mDNS browse and resolve, the A-record lookup and dialing, but never for MAC detection.

Changes

  • Unit: AF_NETLINK added to RestrictAddressFamilies=, with the comment rewritten to say why it is needed and what the family admits. rtnetlink refuses changes without CAP_NET_ADMIN, which the empty bounding set rules out. The family also admits other netlink protocols, and no directive narrows it to NETLINK_ROUTE.
  • CI (hardening step, every systemd: true leg, not only avahi):
    • A stdlib python3 WebSocket handshake to the unit's port. It requires the first message to be client/hello with a non-empty client_id. An inbound connection is sent its hello right after the upgrade, which is where detection runs, so nothing else in the step reaches it.
    • A journal gate scoped to the current invocation that fails on getifaddrs failed. It requires the invocation's startup line first, so an empty or unreadable journal fails instead of passing.
    • The two gates cover each other: the first survives reworded log text, the second survives a library that answers a failed detection with some other non-empty id.
  • Docs: ROADMAP and Running-as-a-Service corrected. Troubleshooting has a new entry with the symptom and a drop-in workaround for existing installs ([Service] / RestrictAddressFamilies=AF_NETLINK), plus the id = alternative and its identity caveat.

No C++ changes.

How the check was shown to fail under the old directive

This was a local run, not CI. I built the CLI at this branch against sendspin-cpp v0.7.2 in an ubuntu:24.04 container and ran it with no --id. I then ran the exact python check from build.yml against it:

  • With socket(AF_NETLINK) refused with EAFNOSUPPORT by a seccomp profile (the same denial RestrictAddressFamilies= applies), the check exits 1 with client/hello carried an empty client_id, and the player logs W sendspin.network_info: getifaddrs failed; cannot auto-detect MAC address.
  • With netlink allowed, it exits 0, the client_id is a MAC, and there is no getifaddrs line.

Seccomp stands in for systemd there. CI on this PR is the first run under the real unit. systemd-analyze verify passes on the new unit (systemd 255).

Not in this PR

  • The library sending a hello with an empty client_id belongs in sendspin-cpp. The fix goes there, and the library bump gets its own PR.
  • MA's unguarded assert on an empty client id is a Music Assistant server issue.
  • Release notes are written in the version-bump PR.

…detected

glibc's getifaddrs() reads the interface list over netlink and has no
fallback, so under RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 MAC
detection fails and a player with no id says client/hello with an empty
client_id, which Music Assistant refuses with "No key provided".

The hardening step in CI now opens a WebSocket to the unit and requires the
hello it is sent to carry a non-empty client_id, and fails if the
invocation's journal logs "getifaddrs failed". ROADMAP and the wiki drop the
claim that netlink was unneeded, and Troubleshooting gives existing installs
a drop-in workaround.
@chrisuthe
chrisuthe marked this pull request as ready for review September 14, 2026 15:46
@chrisuthe
chrisuthe merged commit c33c0e0 into main Sep 14, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant