rf_sentinel / how-it-works
How it works
From radio packet to alert. Every rule and threshold here is in the public source; file names point at the Kotlin classes.
1. Scanning (receive only)
- Bluetooth LE (
service/BleScanEngine.kt): continuousBluetoothLeScannerscan, no batching, aggressive match mode, legacy + BT5 extended advertising and LE Coded PHY when the chip supports them. Scan mode: low latency (default), balanced or low power. - Screen off: Android suspends unfiltered scans, so a second, hardware-filtered scan runs on the identifiers that matter (vendor company IDs, Remote ID, tracker and glasses service data and UUIDs, watchlisted exact addresses).
- WiFi:
WifiManagerscans every 30 s by default (Android allows about 4 per 2 minutes), including raw information elements on Android 11+. - Cell:
getAllCellInfo()every 15 s for fake-tower signs. - External: OUI-Spy / GhostESP ESP32 boards over USB or Bluetooth.
Nothing is ever transmitted to, connected to or paired with a scanned device.
2. Signatures
detect/SignatureEngine.kt matches payload tags (BWCDEVICE), Bluetooth SIG company IDs, 16 and 128-bit service UUIDs, service data, names and SSIDs. The watchlist matches exact addresses, IEEE MA-L / MA-M / MA-S prefixes and name / vendor rules, seeded by regional presets (assets/oui_presets/: Global, Canada, US). Every prefix used in code is checked against its IEEE registrant by tools/gen_assets.py, which fails the build data if one changes.
| Tier | Confidence | Meaning |
|---|---|---|
| Weak | < 50 | Shared identifier; amber, silent by default |
| Probable | 50-79 | Vendor-specific identifier; alerts at the default threshold |
| Strong | 80+ | Payload tag or vendor-assigned network name |
Rejected on purpose: bare 10-digit BLE names, the -FALCON SSID suffix, Liteon module blocks, Motorola Mobility blocks (consumer phones), Sierra Wireless / Cradlepoint blocks as standalone matches, and company ID 0x058E alone.
3. Evidence fusion
detect/EvidenceFusion.kt, every 2 s per device. Different rules of the same category combine by noisy-OR with each supporting hit at half weight:
fused = 1 - (1 - top) × Π (1 - 0.5 × support_i) support_i ≥ 30, result ≤ 90
Example: watchlisted address 70 + Zebra serial name 50 → 78. The patrol-vehicle hit is never fused, because it is derived from the device's own matches.
4. Patrol-vehicle grouping
detect/PatrolCluster.kt. Each device gets a role (body camera, plate reader, two-way radio, vehicle cellular router, mobile printer, in-car computer, rugged laptop, police camera) from its matches or IEEE registrant. Two or more different roles form a vehicle when their RSSI correlates (Pearson r ≥ 0.6 over ≥ 8 aligned seconds) or both are parked (flat) and appeared within 30 s of each other. Score: 24 + 12 × roles, +10 if moving together, cap 88. A device's own match is held 2 minutes after its evidence was last seen.
5. Address-rotation linking
detect/AdvertFingerprint.kt. Fingerprint = names, service UUIDs, service-data and company-ID payload sizes, TX power, connectable flag. A new private address with the same fingerprint as exactly one device that went silent 1.5-30 s earlier inherits its matches (−5), follow history (time with you, GPS path) and ignore state. Apple-Continuity-only adverts are never linked.
6. Follow detection
A tracker or flagged device heard continuously (gaps under 3 minutes) for at least 10 minutes while you moved at least 800 m raises may be following you, once per device. Both thresholds are adjustable.
7. Identifying ordinary devices
- Decoded vendor protocols (Apple Continuity incl. exact AirPods / Beats model, iBeacon, Eddystone, Fast Pair, Remote ID)
- GAP appearance
- Standard SIG services (heart rate, HID, LE Audio, medical...)
- Name patterns
- Member-service owner
- IEEE registrant
- Company ID
8. WiFi fingerprinting
detect/WifiFingerprint.kt: WPS element (manufacturer 0x1021, model name 0x1023, model number 0x1024, device name 0x1011, primary device type 0x1054), Cisco CCX AP name (IE 133, bytes 10-25), BSSID registrant (unless chipset-only), vendor IE owners split into equipment and chipset makers. BSSIDs are the same AP when octets 2-5 match, the last octet is within 16 and the first is equal or locally administered.
9. Known cameras
alpr/: OpenStreetMap elements tagged surveillance:type=ALPR, speed and red-light cameras, fetched via Overpass (overpass-api.de, with overpass.kumi.systems and overpass.private.coffee as fallbacks) and DeFlock's region snapshots, cached privately, refreshed weekly. Warnings when a camera is ~20 s ahead (150-600 m) and getting closer.
Sources
- all-cameras-are-beacons signature reference (Apache-2.0): confidence ladder and field-validated values
- opendroneid-core-c (Apache-2.0): Remote ID message layout
- IEEE Registration Authority (via Wireshark's weekly copy) and Bluetooth SIG assigned numbers
- Community prefix lists cross-checked: Flock You, OUI-Spy, nite-oui-collection, Wardrive Go, Flock-You-Android, Fieldwatch
Full tables: docs/SIGNATURES.md.