Updated README/architecture/security/limitations/testing/api/CHANGELOG and the LaTeX user guide (now 14pp) with the Certificates and HTTP Explorer screens. 0 called Go vulns, npm audit clean.
77 lines
7.0 KiB
Markdown
77 lines
7.0 KiB
Markdown
# Testing
|
|
|
|
## Automated
|
|
|
|
| Command | What it covers | Needs |
|
|
|---|---|---|
|
|
| `make test` | Config validation, nft/dnsmasq/NM rendering, Argon2id, TOTP (RFC 6238 vector), throttling, helper parsers, pcap/pcapng reader incl. malformed input, API auth flow (setup token, authorised-use, CSRF, source allow-list, lock-out detection, logout, throttling), TypeScript typecheck | Go, Node |
|
|
| `make test-docker` | Everything above that needs tshark/dumpcap (import → index → filter → PDML with verified byte ranges → filtered export re-read by tshark → hash verify; live capture with segment rotation, counts agreement, per-segment validity), **plus** the netns suite below | Docker |
|
|
|
|
The netns suite (`tests/integration/run.sh`) builds an upstream/Pi/client topology from
|
|
veth pairs and runs the real `pilens` binary plus the configuration rendered by `pilens-helper`:
|
|
DHCP lease and options, DNS override, NAT to a public address, blocking of RFC 1918 /
|
|
management / IPv6 / inbound / Pi-SSH, management reachable only from the allowed subnet (not
|
|
from AP clients, not even via the uplink address), first-admin creation, capture on the AP
|
|
interface through the API, display filter, packet detail, export opened by tshark, integrity
|
|
check, CSRF rejection, deny mode, and survival of an unrelated nft table.
|
|
|
|
Not covered by automation: NetworkManager AP activation and its rollback (needs a real radio;
|
|
`mac80211_hwsim` is not available in containers), systemd unit behaviour, installer.
|
|
|
|
## Hardware acceptance checklist (Raspberry Pi)
|
|
|
|
Record date, Pi model, OS, PiLens version and the result for each item.
|
|
|
|
| # | Test | Expected |
|
|
|---|---|---|
|
|
| H1 | Fresh install on Pi OS Lite via SSH over Ethernet | Installer completes. Prints URL, fingerprint, token. Existing connections unchanged. |
|
|
| H2 | Wizard: create admin, apply AP | Steps all ✓. SSID visible. Ethernet SSH session not interrupted. |
|
|
| H3 | Phone joins the AP | Lease in the pool, Pi as DNS, internet works |
|
|
| H4 | Phone → LAN host (e.g. router admin page) | Blocked |
|
|
| H5 | Phone → `https://<pi-ap-ip>:8443` and SSH to the Pi | Blocked |
|
|
| H6 | Capture on wlan0 while browsing | Packets live in the UI. Export opens in desktop Wireshark. Verify = ok. |
|
|
| H7 | Cold boot | AP returns. Firewall table loaded before the AP (`journalctl -b -u pilens-firewall -u NetworkManager`). Forwarding works. |
|
|
| H8 | Power loss during capture | Session marked interrupted. Segment hashed. Earlier segments verify. |
|
|
| H9 | Unplug Ethernet for 1 min, replug | Dashboard shows no default route, then recovers. Clients keep their leases. |
|
|
| H10 | Client disconnects and reconnects | Device list updates. Same lease. |
|
|
| H11 | `kill -9` of pilens during a capture | systemd restarts it. Session interrupted. Forwarding unaffected. |
|
|
| H12 | Storage exhaustion (small quota) | Oldest unpreserved session deleted, or capture stops with an error. Preserved session intact. |
|
|
| H13 | Apply an invalid AP config (e.g. WPA3 on a radio without SAE) | Rolled back, previous AP restored, error shown |
|
|
| H14 | `uninstall.sh` then `install.sh` | Captures kept. Old Wi-Fi client profile works again after uninstall. |
|
|
| H15 | `repair.sh` after `setcap -r /usr/bin/dumpcap` | Capabilities restored |
|
|
| H16 | Throughput: iperf3 through the AP while capturing | Record Mbit/s, dumpcap drops, ingest lag |
|
|
| H17 | Import a 500 MB pcapng | Indexing time recorded. UI responsive. |
|
|
|
|
TLS-interception hardware tests belong to phase 4.
|
|
|
|
## Results log
|
|
|
|
Only tests that were actually run are listed.
|
|
|
|
### 2026-10-09 · Raspberry Pi 5 Model B Rev 1.0 (4 GB, NVMe) · Debian 13 trixie · kernel 6.18.34+rpt-rpi-2712 · NM 1.52.1 · tshark 4.4 · PiLens 0.1.0 → 0.1.3
|
|
|
|
| # | Result | Evidence / notes |
|
|
|---|---|---|
|
|
| H1 | **pass** | Installed over SSH via eth0. Existing connections untouched. Found a false "no AP mode" warning (check ran before `iw` was installed): fixed in 0.1.1/0.1.2. |
|
|
| H2 | **pass** (via API, not the browser wizard) | Apply: all 9 steps ✓. AP `PiLens-Lab` on ch 11 (auto), regdomain GB. Management SSH on eth0 never interrupted. |
|
|
| H3 | **pass** | iPhone and Apple Watch associated, leases .101 / .168 from the pool, both shown with randomised-MAC badges |
|
|
| H4 | not run | Needs a client to try a LAN address. Netns suite covers the rule. |
|
|
| H5 | partial | nft counter: 24 client→Pi packets dropped (mDNS etc.). No explicit SSH/8443 attempt from the phone. |
|
|
| H6 | **pass** (tshark), desktop Wireshark not tried | 1,654 packets, 0 drops. Export (1,272 packets at the time) read by tshark 4.4. Verify = ok. Fields from decrypted QUIC Initial CRYPTO frames were correctly marked unverifiable (50/181 verified). |
|
|
| H7 | **pass** | Reboot: `pilens-firewall` finished 18:20:33.7, NM started `pilens-ap` 18:20:38.9. All services active, forwarding on. |
|
|
| Upgrade with a running capture | **pass after fix** | 0.1.0→0.1.1 left the session marked *failed* (systemd SIGTERMed dumpcap directly). `KillMode=mixed` in 0.1.2 means a reboot now finalises the capture as *stopped* with dumpcap's drop report. Hashes ok. |
|
|
| H8 | not run (no hard power cut) | Covered partially by H11 |
|
|
| H11 | **pass** | `kill -9` of pilens during a capture: restarted by systemd, no stray dumpcap, segment recovered (4,562 packets), hashed, verify ok, marked *interrupted*. The session packet counter showed 0: fixed in 0.1.3 (reindex on recovery). |
|
|
| H12 | **pass** | Quota 64 MiB: the two unpreserved sessions were deleted oldest first (audited), the preserved session was kept, and the capture stopped with "storage limit reached … no unpreserved sessions remain". |
|
|
| H13 | **pass** | 5 GHz ch 165 in GB: NM activation failed, rolled back in 26 s, AP back on ch 11 with DHCP active. The error message was made actionable in 0.1.3. |
|
|
| H15 | **pass** | `setcap -r dumpcap` → `repair.sh` restored `cap_net_admin,cap_net_raw=eip`, all services ✓ |
|
|
| H16 | **partial** | Loopback worst-case: 108 MB/s / 4,000 pkt/s with 14.7% drops honestly reported. Real Wi-Fi iperf3 not run. See [benchmarks.md](benchmarks.md). |
|
|
| H17 | **pass** | 263 MB import indexed in 3.2 s (~3,200 pkt/s); filters ~1.2 s; UI responsive. |
|
|
| Interception (Mode B) | **pass** | On the Pi 5: CA generated + downloaded (public only, 0 key lines). Toggle on → proxy active on 8081, nft redirect + `ct status dnat` accept present. A CA-trusting client (curl `--cacert`) decrypted https://example.com and api.github.com (TLS 1.3); an untrusting client was refused and logged as a TLS failure. HTTP Explorer showed all three. Toggle off → redirect removed, proxy stopped, masquerade intact. Full device trust (phone) is the operator's manual step. |
|
|
| Findings | **pass** | On the iPhone capture: 18 retransmissions/7 flows, 1 SYN retry, 7 resets, 17 dup-ACKs, 3 NXDOMAIN, 1 ICMP unreachable — each linking to evidence packets. |
|
|
| H9, H10, H14 | not run | Need physical cable/client actions. |
|
|
|
|
The Raspberry Pi firmware throttle flags (`vcgencmd`) cannot be read by the service user on this
|
|
OS (`/dev/vcio` is 0600 root). PiLens reports the world-readable `rpi_volt` under-voltage alarm
|
|
instead.
|