Fix MTR failing under systemd: grant CAP_NET_RAW via ambient capabilities

mtr ran fine as the mtr-backend user in a shell but failed under the
systemd service with:
  mtr-packet: Failure to open IPv4 sockets: Permission denied

Cause: the unit sets NoNewPrivileges=yes, which strips file capabilities,
and AmbientCapabilities/CapabilityBoundingSet were empty — so mtr-packet
(the helper that opens the raw ICMP socket) had no CAP_NET_RAW. Interactive
runs worked because they had no NoNewPrivileges.

- Grant CAP_NET_RAW the systemd-native way (AmbientCapabilities +
  CapabilityBoundingSet), which survives NoNewPrivileges. Fixed in both
  the full installer and the patch service unit.
- setcap now also targets mtr-packet, not just mtr.
- Add proxy_intercept_errors off to the diag /api/mtr location: the
  server-level "proxy_intercept_errors on" was rewriting a backend 500 into
  an HTML 404, which broke the frontend's response.json() and left the
  client IP stuck on "detecting…".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ivan Razin
2026-07-06 10:25:01 +03:00
co-authored by Claude Opus 4.8
parent fb68047c02
commit 906822b42b
2 changed files with 26 additions and 4 deletions
+13 -1
View File
@@ -488,6 +488,10 @@ server {
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
# Let the backend's JSON error bodies through; the server-level
# "proxy_intercept_errors on" would otherwise rewrite a 500 into an HTML
# 404 and break the frontend's response.json() parse.
proxy_intercept_errors off;
}
location ^~ ${diag_path}api/st/up {
if (\$diag_auth = 0) { return 404; }
@@ -614,7 +618,9 @@ id mtr-backend &>/dev/null || \
useradd --system --no-create-home --shell /usr/sbin/nologin mtr-backend
if command -v setcap &>/dev/null; then
setcap cap_net_raw+ep "$(command -v mtr)" 2>/dev/null || true
# mtr-packet is the helper that actually opens the raw socket
setcap cap_net_raw+ep "$(command -v mtr)" 2>/dev/null || true
setcap cap_net_raw+ep "$(command -v mtr-packet)" 2>/dev/null || true
fi
cat > /etc/systemd/system/mtr-backend.service <<EOF
@@ -633,6 +639,12 @@ NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/tmp
# mtr-packet opens raw ICMP sockets. NoNewPrivileges=yes strips the file
# capability off the mtr binary, so grant CAP_NET_RAW the systemd-native way
# (ambient caps survive NoNewPrivileges). Without this mtr fails with
# "Failure to open IPv4 sockets: Permission denied".
AmbientCapabilities=CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_RAW
[Install]
WantedBy=multi-user.target