feat: read what listens on which address, and which service it is, once for every driver #7

Merged
christianmanivong merged 1 commits from feat/listening-sockets into main 2026-10-06 16:19:23 +00:00
Owner

ListeningSocketsMixin.get_listening_sockets() — every listening TCP and bound UDP socket with the process, systemd service and container behind it, in one framed round trip (ss -lntup + /proc/<pid>/cgroup). A driver supplies only _run_listening_sockets_command(command, privileged=).

  • Root: the script goes as one sh -c argument, so a sudo -n prefix covers all of it (a plain prefix would run only the first command as root). No report back → read again unprivileged, attributed: false.
  • Old iproute2: no -H; the parser skips the header.
  • Addresses: *, 0.0.0.0, [::], :::22 (iproute2 4.9), 127.0.0.53%lo, [::ffff:127.0.0.1], [fe80::1%eth0] → address + interface.
  • cgroups: v2, nested slices, escaped template instances, v1 name=systemd; containers via docker-<id>.scope and /docker/<id> (also libpod).
  • Failures: no ss → ListeningSocketsUnavailable (not retried); cut-short report or failing ss → ValueError.
  • Raw reading: docker-proxy appears as docker.service; reachability is the consumer's decision.

New TypedDicts ListeningSocketDict / ListeningSocketsDict, README "Function classes", version 2.4.0.

Tests: tests/test_listening_sockets.py (35, incl. a real run on the test host and a sh -n syntax check). Whole suite: 347 passed.

For NetOrk/netork#658.

`ListeningSocketsMixin.get_listening_sockets()` — every listening TCP and bound UDP socket with the process, systemd service and container behind it, in one framed round trip (`ss -lntup` + `/proc/<pid>/cgroup`). A driver supplies only `_run_listening_sockets_command(command, privileged=)`. - **Root:** the script goes as one `sh -c` argument, so a `sudo -n` prefix covers all of it (a plain prefix would run only the first command as root). No report back → read again unprivileged, `attributed: false`. - **Old iproute2:** no `-H`; the parser skips the header. - **Addresses:** `*`, `0.0.0.0`, `[::]`, `:::22` (iproute2 4.9), `127.0.0.53%lo`, `[::ffff:127.0.0.1]`, `[fe80::1%eth0]` → address + interface. - **cgroups:** v2, nested slices, escaped template instances, v1 `name=systemd`; containers via `docker-<id>.scope` and `/docker/<id>` (also libpod). - **Failures:** no `ss` → `ListeningSocketsUnavailable` (not retried); cut-short report or failing `ss` → `ValueError`. - Raw reading: `docker-proxy` appears as `docker.service`; reachability is the consumer's decision. New TypedDicts `ListeningSocketDict` / `ListeningSocketsDict`, README "Function classes", version 2.4.0. Tests: `tests/test_listening_sockets.py` (35, incl. a real run on the test host and a `sh -n` syntax check). Whole suite: 347 passed. For NetOrk/netork#658.
christianmanivong added 1 commit 2026-10-06 16:19:11 +00:00
Whether a service is reachable from outside its host is decided by the
address it listens on: 0.0.0.0:5432 is, 127.0.0.1:5432 is not. Reading
that is the same on every Linux host, so the command and its parse live
here once and a driver only carries the command across
(ListeningSocketsMixin, _run_listening_sockets_command).

One framed round trip: ss -lntup for every listening TCP and bound UDP
socket, then /proc/<pid>/cgroup for each process holding one, which names
the systemd service (v2, nested slices, v1's name=systemd hierarchy) or
the container (docker-<id>.scope, /docker/<id>) it runs in.

- Root: only root sees every process. The script goes as one sh -c
  argument, so a sudo -n prefix covers all of it; when that brings no
  report back the reading runs again unprivileged and says it is not
  attributed.
- No -H: iproute2 before 4.10 fails on it, which would read as nothing
  listening. The header is skipped instead.
- A host without ss raises ListeningSocketsUnavailable; a report cut short
  or a failing ss raises ValueError.
- The reading is raw: docker-proxy shows up as docker.service, loopback as
  loopback. What counts as reachable is the consumer's call.

2.4.0. For netOrk#658.
christianmanivong merged commit f833e23422 into main 2026-10-06 16:19:23 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: NAPALM/napalm-device-types#7