Add passive Flock/Raven surveillance detection for WARHOG - #56
Open
jebjarrell1974-debug wants to merge 15 commits into
Open
Add passive Flock/Raven surveillance detection for WARHOG#56jebjarrell1974-debug wants to merge 15 commits into
jebjarrell1974-debug wants to merge 15 commits into
Conversation
Confidence-scored WiFi (OUI + addr1 receiver + wildcard probe) and BLE (mfr 0x09C8, name hints, Raven service UUIDs) detection. Dual logging to WiGLE export and a separate flock.csv for deflock.me. Passive only, no TX. Signature data attributed to deflock.me / NitekryDPaul / DeFlockJoplin.
Runs detection on WARHOG active-scan results via new inspectScanResult() (BSSID OUI + SSID name hints, Medium threshold). Hits log to a session flock.csv for deflock.me while the AP still flows to the WiGLE export. Loud SIREN on a camera hit, distinct tone for Raven, via the SFX module. Renames namespace flock->flockdet to avoid colliding with the POSIX flock() declared in the ESP32 toolchain headers. Builds clean for env:m5cardputer and flashed/tested on Cardputer ADV.
|
This is great man! Note that the code in the 'janus hog' branch is newer, though. I've pulled your code into my fork off that, and it merges cleanly. |
…cal OUIs Wires flockdet::inspectWifiFrame into the promiscuous callback so sleeping cameras are detected in DO NO HAM / OINK / SPECTRUM, not just WARHOG's active scan. Hits go through a lock-free ring buffer and are drained in update() for the siren, toast and GPS-tagged flock CSV on SD. Replaces the OUI table with the canonical 31-prefix field-tested list (@NitekryDPaul + DeFlockJoplin 82:6b:f2), all FLOCK_LINKED. Drops the seven generic Espressif vendor blocks, which matched any ESP32 including the Cardputer itself. Adds an I/G group-bit guard so broadcast/multicast addr1 values can never match.
flockprox scans a flash-resident table of 2736 reported ALPR locations (OpenStreetMap surveillance:type=ALPR, ODbL) and ramps an audible tick as the nearest one closes: silent beyond 1000 ft, a tick that tightens from 1500 ms to 350 ms across 1000-300 ft, then a faster, higher tick inside 300 ft, plus a one-shot ALPR AHEAD toast on entering the zone. This is the map half of the feature and is independent of the radio, so it keeps warning while WiFi is mid-scan. An integer bounding-box prefilter drops all but a handful of points before any trig runs, and the scan is rate-limited to 2 Hz since GPS only moves at 1 Hz. fetch_flockmap.py (Overpass query) and scripts/gen_flock_map.py (CSV to header) are committed for provenance; the intermediate CSV stays gitignored.
An active scan only sees a camera that is currently beaconing. A sleeping one shows up as a receiver address in another device frames, which needs promiscuous mode -- and WARHOG previously stopped NetworkRecon outright, so it could never see one. WARHOG now runs an 8s scan slice and a 4s promiscuous slice in a loop, with live Flock detection and the siren running during the latter. NetworkRecon is parked with pause() instead of stop() for the duration of the mode, so each handover costs ~50ms rather than a full BLE-deinit and WiFi re-init. Handovers only run with no scan in flight, so the radio never changes mode mid-scan. Both slice durations are tunable constants.
DO NO HAM was silent near cameras because drainFlockHits() lived inside NetworkRecon::update(), which early-returns whenever recon is paused and is coupled to recon's lifecycle. WARHOG only ever alarmed from its own active-scan path, so the promiscuous alarm path had never actually been exercised. Move the drain into a public NetworkRecon::serviceFlockAlerts() called every frame from the global app loop, so the alarm + flock.csv log fire in every sniffing mode (DNH / OINK / SPECTRUM / WARHOG) regardless of pause state. Enqueue stays in the shared core promiscuous callback, which already covers every mode. Pipeline counters (match/enqueue/drain/alert) stay live behind FLOCK_DEBUG_COUNTERS (default off) for future bring-up. Replace the siren/beeps with pig-themed SFX: PIG_ALARM (squeal x2, camera found), PIG_RAVEN (low angry squeal, Raven), PIG_SQUEAL (close-range proximity loop) and PIG_GRUNT (gentle proximity tick). Wire detection and the proximity ramp to them.
Adds the defensive-suite container mode GUARD HOG (menu RECON > GRDHOG, or key G from idle). Passive, RX-only: it stops NetworkRecon, powers WiFi down and runs a NimBLE passive scan. TICK CHECK (defense/tracker_detect): classifies BLE personal-item trackers from raw advertisement AD structures -- Apple AirTag / Find My (mfr 0x004C, type 0x12, lost-broadcast 0x1E), Tile (0xFEED/0xFEEC), Samsung SmartTag (0xFD5A / mfr 0x0075) and best-effort Google Find My (0xFEAA, low confidence, Eddystone-shared). Framework-agnostic like flock_detect so it host-tests. Signatures attributed to the reference projects (Eye Spy / CYD AirTag scanner) as facts. TAIL WAGGER: bounded cross-waypoint persistence engine. A BLE MAC seen >=3x across >=3 distinct GPS waypoints (>=120m apart) over >=5 min is flagged !FOLLOWING with the pig alarm. Trackers also log to guardhog CSV on SD. The watch face lists nearby trackers (type / RSSI / MAC tail / LOST) and raises the !FOLLOWING banner. Full CALM/SNIFFY/SPOOKED fusion + WiFi rotation land in P5.
Adds defense/attack_detect, a lock-free per-second monitor fed from the shared promiscuous callback (so it runs in every WiFi sniffing mode, mode-independent like the flock hook). Counts deauth (subtype 0x0C), disassoc (0x0A), beacon floods (0x08 from locally-administered/random BSSIDs, the mdk4 tell) and probe floods (0x04). Thresholds are tunable. The per-second roll-up + alert run from serviceFlockAlerts() on the main loop: crossing a threshold squeals PIG_SQUEAL (rate-limited to once / 5s) and toasts the attack type + offending BSSID tail. Counters are std::atomic so onFrame() stays callback-safe. Stats exposed via NetworkRecon::getAttackStats/getLastAttack for GUARD HOG'\''s fused watch face in P5.
Adds defense/eviltwin_detect, a self-baselining rogue-AP monitor. The first BSSID seen for an SSID sets its expected security; a later BSSID for that SSID with a security mismatch (a WPA2 network suddenly beaconing OPEN elsewhere -- the classic Pineapple/karma clone) is flagged EVIL TWIN. Two BSSIDs with matching security are ordinary roaming/mesh and stay quiet, keeping false positives off enterprise and carrier networks. Fed one observation per newly-seen beacon from processBeacon via a lock-free ring (callback-safe); the SSID table and alert run on the main loop in serviceFlockAlerts(), so it works in every WiFi sniffing mode. A flag fires PIG_ALARM + a toast naming the SSID and both BSSID tails. Count exposed via NetworkRecon::getEvilTwinCount() for GUARD HOG.
SKY HOGS (defense/drone_detect): parses OpenDroneID / ASTM F3411 BLE frames -- 16-bit service data UUID 0xFFFA, application code 0x0D, message counter, then the 25-byte Remote ID message; extracts the UAS ID from a Basic ID message. UUID and app code verified against the OpenDroneID spec and Eye Spy; attributed as facts. FLIPPER FINDER (defense/flipper_detect): Flipper Zero by BLE address prefix (0C:FA:22 / 80:E1:26 / 80:E1:27) or a Flipper advertised name. Both run in GUARD HOG'\''s existing NimBLE passive scan alongside TICK CHECK. The callback now un-reverses NimBLE'\''s little-endian address to human order so prefix matching and display tails are correct. Distinct-MAC tallies drive the watch face (ticks / skyhogs / flippers); a new drone raises PIG_ALARM, a new Flipper a grunt. Framework-agnostic detectors, host-testable like the rest.
GUARD HOG now time-shares the one 2.4GHz radio (Eye-Spy rotation): a ~9s BLE passive-scan slice (trackers / drones / Flippers) alternating with a ~8s WiFi slice that runs its own PASSIVE channel-hopping promiscuous sniff feeding NetworkRecon::inspectDefenseFrame (flock cams / deauth+flood / evil-twin). NimBLE stays initialised throughout -- only the scan starts/stops -- to avoid the ESP32-S3 re-init trap. No TX in either slice (active scanning dropped to honour the passive mandate). Factored inspectDefenseFrame() out of NetworkRecon so both radios feed the same flock/attack/evil-twin monitors, and exposed getFlockAlertCount(). Fused CALM / SNIFFY / SPOOKED score: SPOOKED only when two independent signals agree -- a BLE strong signal (follower/drone) AND a WiFi one (flock/attack/twin), or two distinct WiFi signals (e.g. deauth-flood + evil-twin). Entering SPOOKED fires PIG_ALARM and turns the piglet angry. The watch face leads with the mood word, the live radio slice, and both radios'\'' tallies.
Drops the DEFENSIVE SUITE page into README section 2 verbatim (numbered 2.9 to fit, since 2.5 is PIGGY BLUES). Documents GUARD HOG / TICK CHECK / TAIL WAGGER / SQUEAL ALERT / FAKE BACON / SKY HOGS / FLIPPER FINDER and, importantly, what the pig canNOT do (no IMSI catchers, no analog cams, 2.4GHz only). Docs-only.
GUARD HOG rebooted ~4s after entry (only GUARD HOG; the detectors were fine in other modes). Two GUARD-HOG-specific defects in the BLE scan path: 1. HEAP EXHAUSTION (the ~4s crash). The passive scan set setDuplicateFilter(false) but never setMaxResults(), so NimBLE stashed every advertisement in its results vector, growing unbounded through the 9s BLE slice. On this no-PSRAM S3 that runs the heap out in a few seconds. Fix: setMaxResults(0) -- callback-only, do not store adverts. Also window(150) < interval(160) to give the radio room. 2. USE-AFTER-FREE. getAddress() returns a NimBLEAddress BY VALUE and getVal()/ getBase() point into it, so `const uint8_t* le = device->getAddress().getVal()` dangled after the statement. Bind the address to a named local so it outlives the read; null-guard it. Verified on-device: with a temporary auto-enter hook, GUARD HOG ran for 45s (>2 full BLE<->WiFi rotations) with a single clean boot and zero reboots, where the old build reboot-looped. Serial slice-transition logs kept for future diagnosis. Passive/no-TX unchanged.
Coredump (decoded via esp-coredump) showed the real fault: an abort() in the wifi task, coex_enable() -> coex_core_enable(), during wifi_hw_start(). GUARD HOG kept the BLE (NimBLE) controller initialized across the BLE->WiFi handoff, so when the WiFi slice called WiFi.mode(WIFI_STA) the ESP32-S3 coexistence layer aborted -- two radio controllers can't both be enabled the way it was sequenced. This is entry-path-independent (it fires at the handoff, ~one slice after entry), which is why the earlier maxResults/dangling-address fixes did not stop it and why a USB-CDC survival check gave a false negative (reboots hidden by the port re-enumerating). Fix: only ever have ONE radio's controller enabled at a time, using the proven coex-safe bring-up NetworkRecon already implements. At BLE->WiFi we stop the scan, NimBLEDevice::deinit(true), then NetworkRecon::start() (which owns WiFi promiscuous with correct coex and feeds flock/attack/evil-twin -- the global serviceFlockAlerts drains + alerts). At WiFi->BLE we NetworkRecon::stop(), WiFi off, then re-init NimBLE + scan. GUARD HOG no longer runs its own promiscuous callback or channel hop. The maxResults(0)/dangling-address hardening from the prior commit is retained. Verified with coredump-to-flash: erased the coredump, ran GUARD HOG through 80s (>4 full BLE<->WiFi rotations, >8 handoffs); the coredump partition stayed empty = no panic. Passive/no-TX unchanged.
Jeb's balance: idle guarding holds the pig's life ~flat; catching things fattens him up. The "life bar" is the piglet mood/happiness (-100..100), which naturally decays -1 every phraseInterval (5s) = -12/min in quiet modes -- so GUARD HOG left on the dash slowly starved. Idle break-even (named constants): - GH_ONDUTY_DECAY_DIVISOR = 3 (mood.cpp): on guard duty the -1 decay only lands every 3rd 5s cycle = -1/15s = -4.0/min. - GH_VIGILANCE_HAPPINESS = 1 (guardhog.cpp): +1 happiness per completed BLE<->WiFi rotation (~17s) = +3.53/min. - Net idle = -0.47/min -- a hair below zero, never a free gain. Detections = clear net gain, deduped per device so one camera/tracker can't spam: - XP_DEFENSE_HIT = 15 XP + GH_CATCH_HAPPINESS = 8 mood per dedup'd catch (Mood::onDefensiveCatch: fatten + excitement). Wired at each detector's existing dedup point: TICK CHECK new tracker, TAIL WAGGER !FOLLOWING flag, SKY HOGS new drone, FLIPPER FINDER new flipper (guardhog.cpp); FLOCK cam, FAKE BACON twin, SQUEAL attack (network_recon serviceFlockAlerts, so they also reward in DNH/WARHOG). Attack XP is 30s-cooldown-gated (a flood has no per-device key), flock is per-MAC, twin is per-SSID. - XP_DEFENSE_SPOOKED = 30 XP + fatten on entering SPOOKED. Watch face shows a LIFE + XP readout so the economy is visible: idle holds LIFE ~flat, a catch bumps LIFE and the XP bar. Coredump-verified no crash across 78s of rotations (mood-decay hot path touched). Passive/no-TX unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PORKCHOP goes on defense: a passive surveillance & threat-detection suite
What started as "add Flock camera detection" grew into a full passive counter-surveillance layer for the Cardputer (ADV-tested). Everything here is receive-only — no TX, no attacks — in the spirit of DO NO HAM. Detectors are framework-agnostic and host-testable. Built, flashed, and run on real Cardputer ADV hardware (flash ~59.6%, RAM ~42.7%).
It's a large set — happy to split into smaller PRs if you'd rather take it piecemeal.
Flock / Raven surveillance detection
flock.csvwhile the AP still flows to the normal WiGLE export.The Defensive Suite (src/defense/) + GUARD HOG
Piglet integration
Docs
Attribution & licensing (please read)
flock_map_data.h— flagging in case you'd prefer ODbL-derived data kept out of the MIT tree or handled separately.Notes
Happy to split, rename, or gate any of this behind a build flag — your call.
Confidence-scored WiFi (OUI + addr1 receiver + wildcard probe) and BLE (mfr 0x09C8, name hints, Raven service UUIDs) detection. Dual logging to WiGLE export and a separate flock.csv for deflock.me. Passive only, no TX. Signature data attributed to deflock.me / NitekryDPaul / DeFlockJoplin.
Adds passive Flock Safety / Raven surveillance-camera detection to WARHOG.
Passive only — no new radio mode, no TX.
and its SSID against name hints. Generic Espressif OUIs are scored weak so they
don't false-alarm (default threshold Medium).
(deflock.me-ready) while the AP still flows to the existing WiGLE export.
for a Raven gunshot-detector.
in the ESP32 toolchain headers.
Builds clean for env:m5cardputer and flashed/run on Cardputer ADV hardware.
Signature table ships the publicly-documented OUIs with the full deflock.me set
stubbed pending a license check; expanding it plus a map-based proximity alert
is the planned follow-up. Signature data attributed to deflock.me / @NitekryDPaul
/ DeFlockJoplin.