diff --git a/hbd/server/udp.py b/hbd/server/udp.py index e6034a4..50a7e29 100644 --- a/hbd/server/udp.py +++ b/hbd/server/udp.py @@ -422,6 +422,12 @@ def handle_datagram(msg: dict, addr, transport, ctx: dict): except Exception as e: logger.debug(f"Failed to log message to journal: {e}") + # Only named HTB/PLG datagrams come from clients; anything else (e.g. an internet scanner's + # SIP probe) is journaled above but must not sign on a host. + if msg.get("ID") not in ("HTB", "PLG") or not msg.get("name"): + logger.debug("Ignoring non-client datagram from %s", addr) + return + cfg = ctx.get("config", {}) hbdcls = ctx.get("hbdclass") msg_to_websockets = ctx.get("msg_to_websockets") @@ -430,7 +436,7 @@ def handle_datagram(msg: dict, addr, transport, ctx: dict): # normalize addr (ip, port) ip = addr[0] if isinstance(addr, (list, tuple)) else addr - name = msg.get("name", "unknown") + name = msg["name"] from ..common.utils import shortname from . import config as config_mod diff --git a/tests/test_udp_stray_datagrams.py b/tests/test_udp_stray_datagrams.py new file mode 100644 index 0000000..2e1cc74 --- /dev/null +++ b/tests/test_udp_stray_datagrams.py @@ -0,0 +1,40 @@ +"""Datagrams that are not heartbeat traffic (internet scanners) must not create hosts.""" +from hbd.common.proto import dicttos +from hbd.server import hbdclass +from hbd.server.udp import handle_datagram, parse_message + + +class _FakeTransport: + sent = 0 + + def sendto(self, data, addr): + _FakeTransport.sent += 1 + + +def _ctx(): + return {"config": {}, "hbdclass": hbdclass, "msg_to_websockets": None, + "DEBUG": 0, "verbose": False} + + +def _handle(raw): + handle_datagram(parse_message(raw), ("192.0.2.9", 50000), _FakeTransport(), _ctx()) + + +def test_sip_invite_does_not_create_a_host(): + hbdclass.Host.hosts.pop("unknown", None) + _handle(b"INVITE sip:10000@192.0.2.1:50003 SIP/2.0\r\nTo: \r\n\r\n") + assert "unknown" not in hbdclass.Host.hosts + + +def test_nameless_heartbeat_does_not_create_a_host_or_get_acked(): + hbdclass.Host.hosts.pop("unknown", None) + _FakeTransport.sent = 0 + _handle(dicttos("HTB", {"id": 0})) + assert "unknown" not in hbdclass.Host.hosts + assert _FakeTransport.sent == 0 + + +def test_named_heartbeat_still_creates_its_host(): + hbdclass.Host.hosts.pop("stray-ok", None) + _handle(dicttos("HTB", {"name": "stray-ok", "id": 0})) + assert "stray-ok" in hbdclass.Host.hosts