Skip to content

Fix WPA/RSN detection in the WiFi bridge, and add the missing pkt_sniff.py - #12

Open
willryker wants to merge 1 commit into
LOCOSP:mainfrom
willryker:ac1200-bridge-fixes
Open

Fix WPA/RSN detection in the WiFi bridge, and add the missing pkt_sniff.py#12
willryker wants to merge 1 commit into
LOCOSP:mainfrom
willryker:ac1200-bridge-fixes

Conversation

@willryker

Copy link
Copy Markdown

Fix WPA/RSN detection in the WiFi bridge, and add the missing pkt_sniff.py

Two independent fixes plus one new file, all in the Linux host-radio bridge path
(wdg_wifi_bridge.py). Tested on a uConsole (CM5, Debian trixie) driving a
MediaTek MT7921AU adapter in place of an ESP32.

1. _auth_from_iw() reports almost every network as OPEN

iw scan never prints the literal strings WPA2 or WPA3. It reports modern
security as an RSN: information element, and _auth_from_iw() only matched
the literal version strings — so every WPA2/WPA3 network fell through to OPEN.

On a live scan here that was 31 of 37 access points misclassified.

This is not cosmetic. The value feeds loot_manager._AUTH_MAP and is uploaded to
WiGLE, so any bridge user wardriving is publishing secured networks as open
and quietly polluting a public dataset.

The fix maps RSNWPA2, RSN+SAEWPA3, RSN+PSK+SAE
WPA2/WPA3, and RSN+WPAWPA/WPA2. scan_wifi() now also collects
Authentication suites lines, because the AKM suite is the only way to tell WPA3
from WPA2. Only tokens loot_manager._AUTH_MAP already knows are emitted.

Verified after the change: an eero mesh reads WPA2/WPA3, a Spectrum gateway
reads WPA2, and a genuinely open speaker setup AP still reads OPEN.

2. pkt_sniff.py did not exist

_start_pkt() dispatches pkt_sniff.py on start_sniffer / start_pkt_sniff,
but the file is not in the repo, so the Pkt Sniffer menu item has always failed
with sniffer error: pkt_sniff.py not found.

This adds it, matching hs_capture.py's conventions and the contract the bridge
already expects (--iface, --loot-dir, streamed stdout, SIGTERM shutdown):

  • scapy monitor-mode sniffer with 2.4/5 GHz channel hopping, dropping channels
    the regulatory domain rejects rather than retrying them every pass
  • live [SNF] AP / [SNF] STA / [SNF] DEAUTH lines, periodic summaries in the
    "<ssid>, CH<n>: <count>" shape network_manager.parse_sniffer_results()
    documents, and pcap + text output into the loot directory
  • print(..., flush=True) throughout — the bridge reads stdout as a pipe, so
    block buffering would leave the game with no output until the process exits
  • filters group (multicast) addresses by the I/G bit. Without this, every
    mDNS/SSDP frame an AP forwards is counted as an associated station and the
    per-AP client counts are meaningless
  • ranks the summary by client count before packet count, so the AP clients are
    actually associated to is not crowded out by beacon-heavy neighbours

3. Handshake capture and the packet sniffer can destroy each other

hs_capture.py and pkt_sniff.py both take the --sniffer-iface radio. Run
together they fight over channel hopping, and whichever exits first drops the
interface back to managed mode, killing the other mid-capture. This is guaranteed
to bite on a single-adapter setup, where --iface and --sniffer-iface are the
same device.

The bridge now refuses to start either while the other is active, and
pkt_sniff.py only restores managed mode if it was the one that set monitor.

Note the refusal strings deliberately read "hs capture" / "pkt sniffer": emitting
handshake ... captur or packet sniffer would trip app.py's
_handle_serial_line() state detection and flip the game into a mode nothing is
actually running.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DZnaedMVnFLztkCsmWGVfv

wdg_wifi_bridge.py:
- _auth_from_iw() only matched the literal strings "WPA2"/"WPA3", which
  `iw scan` never prints -- it reports modern security as an "RSN:"
  information element. 31 of 37 APs in a live scan were therefore
  classified OPEN. This is not cosmetic: the value feeds
  loot_manager._AUTH_MAP and is uploaded to WiGLE, so secured networks
  would be published as open. Map RSN->WPA2, RSN+SAE->WPA3,
  RSN+PSK+SAE->WPA2/WPA3, and also collect "Authentication suites" lines,
  since the AKM suite is the only way to tell WPA3 from WPA2.
- Refuse to start the packet sniffer while a handshake capture is running,
  and vice versa. With a single capture radio the two fight over channel
  hopping, and whichever exits first drops the interface back to managed
  mode and kills the other mid-capture. The refusal strings deliberately
  read "hs capture"/"pkt sniffer": "handshake ... captur" or "packet
  sniffer" in bridge output would trip app.py's state detection and flip
  the game into a mode nothing is actually running.

pkt_sniff.py (new):
- The bridge dispatches this on start_sniffer/start_pkt_sniff, but it does
  not exist upstream, so the Pkt Sniffer menu item has always errored.
  Implements the contract the bridge expects: a scapy monitor-mode sniffer
  with 2.4/5GHz channel hopping, live AP/client/deauth lines, periodic
  summaries in parse_sniffer_results() format, and pcap + text loot output.
- Prints with flush=True throughout; the bridge reads stdout as a pipe, so
  block buffering would leave the game with no output until exit.
- Only restores managed mode if it was the one that set monitor, so it
  cannot knock the radio out from under a handshake capture already using it.
- Filters group (multicast) addresses by the I/G bit. Without it every
  mDNS/SSDP frame an AP forwards was counted as a connected station, making
  the per-AP client counts meaningless.
- Ranks the summary by client count before packet count, so the AP clients
  are actually associated to is not crowded out by beacon-heavy neighbours.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZnaedMVnFLztkCsmWGVfv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant