osint-dashboard/app/masscan_config.py

66 lines
3 KiB
Python
Raw Permalink Normal View History

"""Active camera-discovery configuration (masscan-based, env-driven).
All knobs read from the environment with safe defaults. The scanner targets
open TCP port 554 (RTSP the typical IP-camera port) across a configured
range and feeds results into the same `cameras` table as the passive scraper
(discovery_source='masscan'), deduped by URL hash.
ETHICS / SCOPE (mirrors camera_scraper.py):
* Detection only a SYN port scan for OPEN hosts. No credential guessing,
no login attempts, no banner grabbing, and no access to camera feeds.
* Private / reserved ranges are excluded via MASSCAN_EXCLUDEFILE so the
scanner never probes RFC1918, loopback, link-local, multicast, or the
bogons. Fail closed if the excludefile is missing.
TIMING REALITY: at the residential-safe default of 200 pps a full IPv4
sweep (0.0.0.0/0, ~4.29B addresses) takes ~8 months. This is therefore a
CONTINUOUS ROLLING SWEEP, not a "finish in a day" job: masscan streams
open hosts to stdout and the runner ingests them incrementally, then
restarts the sweep when a pass completes. New cameras are detected as they
appear on each pass. 1k/10k pps saturated a home uplink do not raise the
rate unless you are on a VPS / unmetered link.
"""
from __future__ import annotations
import os
# Path to the masscan binary (installed on the Pi host).
MASSCAN_BIN = os.getenv("MASSCAN_BIN", "masscan")
# CIDR(s) to sweep. Default = the whole public IPv4 space.
MASSCAN_RANGE = os.getenv("MASSCAN_RANGE", "0.0.0.0/0")
# Port(s) to probe. Default 554 = RTSP, the typical IP-camera port.
MASSCAN_PORTS = os.getenv("MASSCAN_PORTS", "554")
# Packets/sec. 200 is the residential-safe default — 1k/10k pps saturated
# a home uplink. Raise only on a VPS / unmetered link.
MASSCAN_RATE = int(os.getenv("MASSCAN_RATE", "200"))
# Retransmission count. 1 maximizes unique-host coverage at low rate; the
# default (10) spends most of the budget re-probing the same hosts.
MASSCAN_RETRIES = int(os.getenv("MASSCAN_RETRIES", "1"))
# Seconds to keep listening for straggler responses after the last probe.
# 0 avoids a 10s tail per pass; tiny loss of the very last hosts is fine
# since the sweep repeats.
MASSCAN_WAIT = int(os.getenv("MASSCAN_WAIT", "0"))
# Excludefile path on the Pi host. Must contain RFC1918/loopback/link-local/
# multicast/bogons so the scanner never probes private ranges. Fail closed if
# the file is absent (the runner refuses to start rather than scan wide).
MASSCAN_EXCLUDEFILE = os.getenv(
"MASSCAN_EXCLUDEFILE", "/etc/osint-dashboard/masscan-excludes.txt"
)
# Ingest batch size — flush this many newly-seen hosts to the DB per round.
MASSCAN_FLUSH_EVERY = int(os.getenv("MASSCAN_FLUSH_EVERY", "250"))
# NATS subject newly-found cameras are published on (same feed as the
# passive scraper so the shared ingester persists them).
MASSCAN_NATS_SUBJECT = os.getenv("MASSCAN_NATS_SUBJECT", "events.camera")
# discovery_source tag written into the cameras table.
MASSCAN_DISCOVERY_SOURCE = os.getenv("MASSCAN_DISCOVERY_SOURCE", "masscan")