diff --git a/backend/app/services/fingerprint.py b/backend/app/services/fingerprint.py index 51cdefb..4470776 100644 --- a/backend/app/services/fingerprint.py +++ b/backend/app/services/fingerprint.py @@ -21,7 +21,7 @@ def match_port(port: int, protocol: str, banner: str | None = None) -> dict[str, for sig in _load(): if sig["port"] != port or sig["protocol"] != protocol: continue - if sig.get("banner_regex") and banner and not re.search(sig["banner_regex"], banner, re.IGNORECASE): + if sig.get("banner_regex") and (not banner or not re.search(sig["banner_regex"], banner, re.IGNORECASE)): continue return sig return None @@ -95,7 +95,7 @@ def suggest_node_type(open_ports: list[dict[str, Any]]) -> str: sig = match_port(port, proto) if sig and sig.get("suggested_node_type"): found.add(sig["suggested_node_type"]) - elif port in _PORT_TYPE_HINTS: + if port in _PORT_TYPE_HINTS: found.add(_PORT_TYPE_HINTS[port]) for t in priority: if t in found: diff --git a/backend/tests/test_fingerprint.py b/backend/tests/test_fingerprint.py index 8aa9630..159e595 100644 --- a/backend/tests/test_fingerprint.py +++ b/backend/tests/test_fingerprint.py @@ -50,11 +50,11 @@ def test_match_port_with_banner_no_match_falls_through_to_next(): assert result["service_name"] == "Web UI" -def test_match_port_no_banner_matches_first_sig(): - # no banner → banner check is skipped entirely, first matching sig wins +def test_match_port_no_banner_skips_banner_regex_sigs(): + # no banner → banner_regex sigs are skipped, falls through to generic fallback result = match_port(8006, "tcp", banner=None) assert result is not None - assert result["service_name"] == "Proxmox API" + assert result["service_name"] == "Web UI" # ── fingerprint_ports ─────────────────────────────────────────────────────────