Craton Shield

vs-ble-monitor

BLE connection intrusion detection for Craton Shield.

Overview

Monitors Bluetooth Low Energy connections for security anomalies on IoT devices. Tracks per-peer state for RSSI, pairing, and GATT operation monitoring. All state is stack-allocated with fixed-size arrays.

Detection Mechanisms

MechanismDescriptionDefault
MAC filteringExact MAC address allowlist/blocklist.Allow all
Connection stormSliding window detection of excessive connections (any peer).10 per 30s
RSSI anomalySudden RSSI jump between connections indicates relay/MITM attack.30 dBm threshold
Pairing brute-forceConsecutive pairing failures per peer. Resets on success.3 failures
Global pairing stormDistributed pairing failures across many MACs in a window.10 per 60s
Pairing request floodPer-peer pairing-request rate (separate from failures).100 per 60s
Pairing-method downgradeLE Secure Connections to Legacy, or authenticated method to JustWorks.Always on
GATT abusePer-peer read/write operation count in a 60-second window.100 ops/min
GATT permission violationRead/write on a policy-protected handle without the required auth/authz flags.Per registered policy
MTU downgradeNegotiated ATT MTU shrinks below a previously observed baseline.Always on
Random address floodSurge of random BLE addresses (incl. random-private-non-resolvable detected via the IEEE 802 locally-administered bit).50 per 60s
Advertisement floodAggregate advertisement rate across all peers.1000 per 60s
Advertisement replayDuplicate (peer_addr, rssi, conn_handle) digest within a short window.5s window
Short connectionDisconnect within 1 second of connect (probe behaviour).1s threshold
Timestamp anomalyNon-monotonic or out-of-range event timestamps.Always on
Invalid MACZero or broadcast peer addresses.Always on

Configuration

use vs_ble_monitor::{BleMonitor, MacAction};

let mut monitor = BleMonitor::new();             // allow-by-default
// let mut monitor = BleMonitor::new_deny_default(); // deny-by-default (allowlist only)

// MAC filters.
monitor.add_mac_filter([0xAA, 0xBB, 0xCC, 0x01, 0x02, 0x03], MacAction::Allow).unwrap();
monitor.add_mac_filter([0xDD, 0xEE, 0xFF, 0x04, 0x05, 0x06], MacAction::Block).unwrap();

// Tuning.
monitor.set_conn_storm_params(10, 30_000_000);    // 10 connections per 30 seconds
monitor.set_pairing_fail_threshold(3);             // 3 failures triggers alert
monitor.set_gatt_rate_threshold(100);              // 100 ops per 60-second window

Inspection

use vs_types_embedded::{BleEvent, BleEventType};

let result = monitor.inspect(&event);
// result.allowed     — whether the event should be processed
// result.alert_count — number of alerts (0-4)

Alert Source IDs

IDMeaningSeverity
1MAC filter blockMedium
2Connection stormHigh
3RSSI anomaly (relay attack)High
4Peer slot exhaustionLow
5Pairing failure lockoutHigh
6Global pairing stormHigh
7GATT abuseMedium
8Timestamp anomalyMedium
9Random address floodMedium
10Pairing request floodMedium
11Short connectionLow
12Advertisement floodMedium
13Unknown BLE eventLow
14Invalid MAC (zero / broadcast)High
15ATT MTU downgradeMedium
16GATT permission violationHigh
17Pairing-method downgradeHigh
18Advertisement replayMedium

Limits

  • 16 MAC filter entries
  • 16 tracked peers (RSSI, pairing, GATT)
  • 32 connection timestamps for storm detection
  • 32 GATT handle permission policies
  • 16 advertisement-replay digest ring slots

Tracked-peer and MAC-filter capacities (MAX_TRACKED_PEERS, MAX_MAC_FILTERS) are re-exported from vs-types-embedded and scale with the crate's capacity feature flags:

  • default — values shown above.
  • capacity-large — larger fixed-size tables suited for gateway-class devices.
  • capacity-xl — largest tables; intended for aggregator nodes.

See core/docs/feature-flags.md for the exact constants per profile.

Errors

  • VsError::ResourceExhausted — MAC filter capacity full

Changelog

See the workspace CHANGELOG for version history.

Feature Flags

See core/docs/feature-flags.md for the full workspace feature reference.

License

Apache-2.0. See LICENSE.