diff --git a/meshview/decode_payload.py b/meshview/decode_payload.py index 080a935..bba46c9 100644 --- a/meshview/decode_payload.py +++ b/meshview/decode_payload.py @@ -17,12 +17,25 @@ def text_message(payload): return payload.decode("utf-8") +# The firmware keeps at most 8 hops in each direction (none of 66,709 real traceroutes in 17 +# days of bay-area traffic had more). A longer route can only be forged, and one with +# thousands of hops makes every page that draws it slow, so treat it as undecodable. +MAX_ROUTE_HOPS = 8 + + +def route_discovery(payload): + route = RouteDiscovery.FromString(payload) + if max(len(route.route), len(route.route_back)) > MAX_ROUTE_HOPS: + return None + return route + + DECODE_MAP = { PortNum.POSITION_APP: Position.FromString, PortNum.NEIGHBORINFO_APP: NeighborInfo.FromString, PortNum.NODEINFO_APP: User.FromString, PortNum.TELEMETRY_APP: Telemetry.FromString, - PortNum.TRACEROUTE_APP: RouteDiscovery.FromString, + PortNum.TRACEROUTE_APP: route_discovery, PortNum.ROUTING_APP: Routing.FromString, PortNum.TEXT_MESSAGE_APP: text_message, PortNum.MAP_REPORT_APP: MapReport.FromString, diff --git a/meshview/store.py b/meshview/store.py index d0e0e3d..f90e265 100644 --- a/meshview/store.py +++ b/meshview/store.py @@ -152,12 +152,19 @@ async def has_packets(node_id, portnum): ) +# Every TRACEROUTE message stores a row under its packet id, so anyone who can publish can add +# thousands. Real ones have a few dozen (one per gateway that heard it; the most seen in 17 days +# of bay-area traffic was 72), so only the earliest rows are used. +MAX_TRACEROUTE_ROWS = 200 + + async def get_traceroute(packet_id): async with database.async_session() as session: result = await session.execute( select(Traceroute) .where(Traceroute.packet_id == packet_id) .order_by(Traceroute.import_time_us) + .limit(MAX_TRACEROUTE_ROWS) ) return result.scalars()