Ports doppelt nach Scan — IPv4/IPv6-Binds nicht dedupliziert (Backend-Dedup vor Persist) #35

Closed
opened 2026-06-01 22:14:15 +00:00 by chinux · 0 comments
Owner

Symptom

Nach einem Port-Scan tauchen Ports doppelt in der VM auf.

Root Cause

Dienste, die auf IPv4 und IPv6 lauschen (0.0.0.0:22 + [::]:22), liefern in ss -tulpnH zwei Zeilen → zwei Einträge mit identischem (protocol, port), nur unterschiedlicher address.

  • Agent VM-Guest-Agent/src/collect/linux.rs collect_ports pusht jede Zeile und sortiert nur nach (protocol, port)kein Dedup.
  • Backend server/routers/security_router.py _run_port_scan_persist (Z. ~173) speichert found_ports ungefiltert (scan_data=found_ports); auch _hash_ports/_diff_ports laufen auf der Roh-Liste → zusätzlich instabiler scan_hash/falsche „changed"-Diffs.

Fix (Backend — agent-agnostisch, kein Agent-Rebuild)

Dedup-Helper in security_router.py und vor diff/hash/Store anwenden:

def _dedup_ports(ports: list[dict]) -> list[dict]:
    rank = {"public": 2, "local": 1, "": 0}
    by_key: dict[tuple, dict] = {}
    for p in ports:
        key = (str(p.get("protocol", "")).lower(), int(p.get("port", 0)))
        cur = by_key.get(key)
        if cur is None:
            by_key[key] = dict(p)
        else:
            if rank.get(p.get("exposure", ""), 0) > rank.get(cur.get("exposure", ""), 0):
                cur["exposure"] = p.get("exposure")
            if not cur.get("process") and p.get("process"):
                cur["process"] = p.get("process")
    return sorted(by_key.values(), key=lambda x: (str(x.get("protocol", "")), int(x.get("port", 0))))

In _run_port_scan_persist:

found_ports = _dedup_ports(data.get("ports") or [])

→ deckt Linux/FreeBSD/Windows gleichermaßen ab, ohne Agent-Build. scan_data/scan_hash/diff werden dadurch sauber/stabil.

Optional (Quelle)

Zusätzlich in collect_ports (Linux/FreeBSD/Windows) gleich am Agent dedupen (gleicher (protocol, port)-Schlüssel, höchste Exposure gewinnt) — sauberer an der Quelle, aber Backend-Fix genügt für das Symptom.

Bezug

Komplementär zu #32: #32 merged unterschiedliche Protokolle (tcp und udp) zu einer Anzeige-Zeile; #35 entfernt echte Duplikate desselben (protocol, port) aus IPv4/IPv6-Binds in den Daten.

Akzeptanz

  • Ein auf v4+v6 lauschender Dienst erscheint nur einmal je (protocol, port).
  • scan_hash/Diff stabil (kein „changed" nur wegen v4/v6).
  • Port-Counts (Security-Overview) korrekt.

Branch

fix/port-scan-dedup

## Symptom Nach einem Port-Scan tauchen Ports doppelt in der VM auf. ## Root Cause Dienste, die auf IPv4 **und** IPv6 lauschen (`0.0.0.0:22` + `[::]:22`), liefern in `ss -tulpnH` zwei Zeilen → zwei Einträge mit identischem `(protocol, port)`, nur unterschiedlicher `address`. - Agent `VM-Guest-Agent/src/collect/linux.rs` `collect_ports` pusht **jede** Zeile und **sortiert** nur nach `(protocol, port)` — **kein Dedup**. - Backend `server/routers/security_router.py` `_run_port_scan_persist` (Z. ~173) speichert `found_ports` **ungefiltert** (`scan_data=found_ports`); auch `_hash_ports`/`_diff_ports` laufen auf der Roh-Liste → zusätzlich instabiler `scan_hash`/falsche „changed"-Diffs. ## Fix (Backend — agent-agnostisch, kein Agent-Rebuild) Dedup-Helper in `security_router.py` und vor `diff`/`hash`/Store anwenden: ```python def _dedup_ports(ports: list[dict]) -> list[dict]: rank = {"public": 2, "local": 1, "": 0} by_key: dict[tuple, dict] = {} for p in ports: key = (str(p.get("protocol", "")).lower(), int(p.get("port", 0))) cur = by_key.get(key) if cur is None: by_key[key] = dict(p) else: if rank.get(p.get("exposure", ""), 0) > rank.get(cur.get("exposure", ""), 0): cur["exposure"] = p.get("exposure") if not cur.get("process") and p.get("process"): cur["process"] = p.get("process") return sorted(by_key.values(), key=lambda x: (str(x.get("protocol", "")), int(x.get("port", 0)))) ``` In `_run_port_scan_persist`: ```python found_ports = _dedup_ports(data.get("ports") or []) ``` → deckt Linux/FreeBSD/Windows gleichermaßen ab, ohne Agent-Build. `scan_data`/`scan_hash`/`diff` werden dadurch sauber/stabil. ## Optional (Quelle) Zusätzlich in `collect_ports` (Linux/FreeBSD/Windows) gleich am Agent dedupen (gleicher `(protocol, port)`-Schlüssel, höchste Exposure gewinnt) — sauberer an der Quelle, aber Backend-Fix genügt für das Symptom. ## Bezug Komplementär zu #32: #32 merged unterschiedliche Protokolle (tcp **und** udp) zu einer Anzeige-Zeile; #35 entfernt echte Duplikate desselben `(protocol, port)` aus IPv4/IPv6-Binds in den Daten. ## Akzeptanz - Ein auf v4+v6 lauschender Dienst erscheint nur **einmal** je `(protocol, port)`. - `scan_hash`/Diff stabil (kein „changed" nur wegen v4/v6). - Port-Counts (Security-Overview) korrekt. ## Branch `fix/port-scan-dedup`
chinux changed title from Port tauchen nach Scan doppel in der VM auf to Ports doppelt nach Scan — IPv4/IPv6-Binds nicht dedupliziert (Backend-Dedup vor Persist) 2026-06-01 22:24:21 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
chinux/theProx#35
No description provided.