RoamSwitch Sensor Operations Manual
The setup and operations guide for RoamSwitch Sensor — a network sensor that, once placed on your LAN, detects new devices and spoofing on the same segment, and runs active vulnerability audits against any endpoint already running RoamSwitch (Mac / Linux Client / Server Edition). Distributed via apt / dnf packages.
1. Overview & Positioning
RoamSwitch (Mac / Linux Client / Server Edition) is, in every case, a host-resident agent. That form factor has two structural blind spots.
- A single host's self-diagnosis has a fundamental blind spot: lateral-movement risk — "closed to the outside, but wide open to another device on the same LAN" — can never be detected by a host that only ever looks at itself.
- Some devices can never run RoamSwitch: IoT devices (network cameras, smart plugs, multifunction printers), guest/BYOD devices, network equipment itself, embedded devices, and more.
RoamSwitch Sensor is a dedicated node placed on the LAN, aiming to close both gaps. What is actually implemented and verified today is limited to two things: active vulnerability audits against RoamSwitch-equipped endpoints on the same LAN, and passive detection of new-device appearance and spoofing, driven by Sensor's own ARP table (as noted in §6, this is not a feature that actively scans and visualizes every device on the LAN). It is designed not as an EDR, but as a lightweight NDR (Network Detection & Response) combined with an in-house, proof-based vulnerability scanner.
Self-defense is intentionally not implemented (a deliberate design decision). If you need to protect the Sensor host itself from attack, we recommend separately installing RoamSwitch for Linux Server Edition on the same machine. The two run as fully independent processes and coexist without conflict.
2. Current Verification Environment
- Supported OS: Debian 12 (bookworm)+ / Ubuntu 22.04+ (apt), Fedora / RHEL family (dnf).
x86_64(amd64) only —arm64is not yet supported. - Target hardware (future plan): for real-world operation we envision a low-power, always-on-friendly device such as a fanless N100/N150-class mini PC, but no dedicated build or delivery targeting this is provided today.
- Network placement: must be physically or logically connected to the LAN segment being monitored (
roamswitch-sensor.serviceruns on the host network — required to directly observe the ARP table). It must also run at a fixed IP address (a static assignment, or a DHCP reservation) so endpoints can reach it to pair and request audits. It listens on TCP port50543. - Resource usage: resident memory of a few tens of MB; idle CPU load is extremely light.
- Optional:
nmap(used for supplementary NSE diagnostics; every other feature works normally without it).
3. Installation & Startup
Install the roamswitch-sensor package from the official, signed package repository. After installation, roamswitch-sensor.service (systemd) is automatically enabled and started.
3.1 APT (Ubuntu / Debian)
# 1. Register the repository signing key
curl -fsSL https://lafine.net/apt/roamswitch-archive-keyring.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/roamswitch-archive-keyring.gpg
# 2. Add the repository
echo "deb [signed-by=/usr/share/keyrings/roamswitch-archive-keyring.gpg] https://lafine.net/apt stable main" \
| sudo tee /etc/apt/sources.list.d/roamswitch.list
# 3. Install
sudo apt update && sudo apt install roamswitch-sensor
3.2 DNF / RPM (Fedora / RHEL)
# 1. Import the GPG key
sudo rpm --import https://lafine.net/rpm/RPM-GPG-KEY-roamswitch
# 2. Add the repository config file
sudo curl -fsSL -o /etc/yum.repos.d/roamswitch.repo https://lafine.net/rpm/fedora/roamswitch.repo
# 3. Install
sudo dnf install roamswitch-sensor
3.3 Verifying It Started
systemctl status roamswitch-sensor.service
sudo roamswitch-sensor status
3.4 Running the CLI / TUI
The CLI (roamswitch-sensor) and the interactive TUI (roamswitch-sensor-tui) can be run directly after installation.
sudo roamswitch-sensor status
sudo roamswitch-sensor-tui
ROAMSWITCH_SENSOR_PASSIVE_CAPTURE_IFACE environment variable (set via systemctl edit roamswitch-sensor.service) to observe Ethernet/IPv4 headers on that interface and detect new devices or contact with known-malicious IPs (see §6.1). Off by default.4. Pairing (Pairing-Code Method)
Out of the box, Sensor trusts nothing. Pairing is done with a single-use pairing code the Sensor operator issues. The trust relationship — “Sensor may run active vulnerability audits against this endpoint” — is established in both directions at once, in a single pairing step (there is no such thing as one-directional trust).
Prerequisite: run Sensor at a fixed IP address (a static assignment, or a DHCP reservation). After pairing, the endpoint always connects directly to the IP address it saw at pairing time (there is no automatic discovery via mDNS or anything else), so if Sensor’s IP later changes you’ll need to re-pair. The endpoint side can keep a dynamic IP.
4.1 Issuing a pairing code (Sensor side)
# Run on the Sensor side (or press c in the TUI)
sudo roamswitch-sensor issue-code
An 8-character, single-use code is issued (uppercase letters and digits, excluding the easily-confused 0/O/1/I/L). It expires 10 minutes after issuance and can only be redeemed once, so pass it to the endpoint’s operator promptly over any out-of-band channel (verbally, chat, etc.).
4.2 Pairing with the code (endpoint side)
# Endpoint side (roamswitch-linux)
sudo roamswitch sensor pair --addr <Sensor fixed IP address> --code <pairing code>
On the Mac edition, the same operation is available from the GUI via “🔍 RoamSwitch Sensor Pairing…” in the menu bar, where you enter the Sensor’s IP address and pairing code.
Once pairing succeeds, every subsequent active vulnerability audit and audit-result retrieval is authenticated with an Ed25519 signature. Both sides — the endpoint that knew the code, and the Sensor that issued it — trust each other from that moment on.
issue-code.4.3 Manual pairing (registering a known public key directly)
If the Sensor operator already knows an endpoint’s public key and address out-of-band, it can be registered directly on the Sensor side without exchanging a pairing code (normally, use the code-based method in §4.2 and let the endpoint pair itself instead). You can look up your own public key and address with the following commands.
# Check your own public key/address on the endpoint side
sudo roamswitch sensor key
# Check the Sensor's own public key/address/MAC address
sudo roamswitch-sensor status
# Sensor side
sudo roamswitch-sensor pair <full public key> --addr <IP address> --confirm
5. Active Vulnerability Audit
Sensor runs non-destructive, proof-based vulnerability diagnostics against paired endpoints. It never performs destructive operations (writing or deleting data, stopping services).
sudo roamswitch-sensor scan <public key or its prefix>
The audit consists of four phases.
- Full port scan: exhaustively detects every open TCP port on the target host.
- Known-signature diagnostics: non-destructive, proof-based checks against known vulnerability patterns — unauthenticated exposure of Redis / dockerd / Memcached / MongoDB / Elasticsearch / CouchDB / Jenkins / VNC, SMTP open-relay diagnostics (a safe method that sends only
MAIL FROM/RCPT TO, neverDATA), and dev-server CORS misconfiguration, path traversal, and open-redirect diagnostics, among others. - Generic banner grab: for open ports not covered by the signatures above, retrieves the banner string by connecting only — no data is sent.
- Supplementary nmap NSE diagnostics: broad, wide-protocol supplementary diagnostics via
nmap --script safe. Runs automatically whenevernmapis installed on the host (a no-op otherwise).
Every audit run is recorded to /var/lib/roamswitch-sensor/scan_history.json — regardless of whether anything was found, since a clean result at that point in time also has record value — and can be viewed from the CLI or TUI.
roamswitch-sensor history
sudo roamswitch-sensor report <public key or its prefix> --out /tmp/report.md
5.1 Requesting an audit from the client side (pull model)
A paired endpoint can also actively request an audit from Sensor. On the Mac edition, use “Request Audit from Sensor” in the menu bar; on Linux, use the following command.
sudo roamswitch sensor request-audit
After Sensor runs the audit, the endpoint polls for the result starting 5 minutes after the request, then every 5 minutes for up to 5 attempts (so up to 25 minutes total). Whatever result is retrieved is also saved locally on the endpoint.
roamswitch sensor results
On the Mac edition, results also appear in the settings window’s “Audit Results” list, or can be read through the MCP tool get_sensor_audit_results as input for an AI agent planning a remediation. Result retrieval can also be explicitly rejected — for example, if the pairing was revoked on the Sensor’s side (see §10 Q6).
6. Passive ARP Monitoring & LAN Visibility
Sensor periodically snapshots its own ARP table (equivalent to /proc/net/arp) and, by diffing it against the previous snapshot, detects two kinds of events: a new IP/MAC never seen before, and a MAC-address change for an already-known IP (a sign of, e.g., gateway spoofing). It never sends any active packets, and only covers devices that Sensor has somehow already communicated with (it is not a feature that actively discovers and enumerates every device on the LAN). It has no ability to classify device type (e.g. whether something is an IoT device) — it only ever detects an IP/MAC change.
roamswitch-sensor arp-events
Detected events can also be listed from the TUI's “ARP Events” tab, which distinguishes between two kinds: “new device appeared” and “known IP's MAC address changed (suspected spoofing).”
6.1 Passive LAN Visibility Extension (Opt-in)
While the ARP monitoring above only covers devices Sensor has itself communicated with, setting the ROAMSWITCH_SENSOR_PASSIVE_CAPTURE_IFACE environment variable to a target interface observes Ethernet/IPv4 headers on it (no payload inspection) to detect the following.
- Passive observation of new devices: devices Sensor has never directly communicated with, not covered by ARP monitoring alone. Learned from broadcast/multicast traffic.
- Detecting contact with known-malicious IPs: flags traffic whose destination IP matches the local threat feed (same format as RoamSwitch proper's Egress Guard) — detection only, never blocked.
sudo systemctl edit roamswitch-sensor.service
# [Service]
# Environment=ROAMSWITCH_SENSOR_PASSIVE_CAPTURE_IFACE=eth0
sudo systemctl restart roamswitch-sensor.service
roamswitch-sensor passive-events
7. CLI Command Reference
| Command | Description |
|---|---|
roamswitch-sensor status |
Displays Sensor's own public key, IP address, MAC address, and the paired/ARP-event/pending-audit-request counts |
roamswitch-sensor issue-code |
Issues a single-use pairing code (valid for 10 minutes) |
roamswitch-sensor list |
Lists all paired endpoints |
roamswitch-sensor pair <public-key> [--addr <IP>] [--name <name>] --confirm |
Manually pairs an endpoint by specifying its public key and address directly (normally, use issue-code and let the endpoint pair itself instead — it’s simpler) |
roamswitch-sensor unpair <public-key> |
Removes a pairing |
roamswitch-sensor scan <public-key> |
Runs an active vulnerability audit against a paired endpoint |
roamswitch-sensor history [public-key] |
Shows audit history (omit the public key to see all endpoints) |
roamswitch-sensor report <public-key> [--out <file>] |
Outputs the most recent audit result as a Markdown report |
roamswitch-sensor arp-events |
Shows detected ARP events (new devices, suspected spoofing) |
roamswitch-sensor config [show | set <key> <value>] |
Show or change settings (scheduled audits, notifications, retention, collector; no daemon restart needed) |
roamswitch-sensor diff [public key] |
Show what changed since the previous audit (new findings, resolved ones, newly open ports, suspected unreachable) |
roamswitch-sensor export <scans|inventory|audit-log|all> … |
Write audit evidence as CSV / JSON / printable HTML |
roamswitch-sensor audit-log [verify] |
Show the operation and approval log; verify detects tampering with the hash chain |
roamswitch-sensor notify-test |
Send a test notification to the configured destinations (webhook / syslog) to verify connectivity |
The CLI supports only Japanese and English (it follows the LANG environment variable).
8. TUI Operation Guide
The interactive TUI (roamswitch-sensor-tui) supports 10 languages. Switch between its six tabs with the Tab key (Shift+Tab goes back): Trusted (the latest audit state of each endpoint) / Devices (every device on the LAN, with notes) / ARP Events / Scan History / Changes (what changed since the previous audit — new findings in red, resolved in green, suspected-unreachable in yellow) / Audit log (who approved or ran what, and when; the hash-chain verification result is shown at the top).
| Key | Action |
|---|---|
Tab | Switches tabs |
↑↓ / j k | Selects an item |
c | Issue a pairing code (valid for 10 minutes). The screen also shows the command to run on the endpoint, sudo roamswitch sensor pair --addr <this Sensor's IP> --code <code>, already filled in with the real values |
u | Removes a pairing |
s | Runs an active vulnerability audit against the selected endpoint |
n | (Network tab) Add a note — name, purpose, location — to the selected device; a device with a note counts as accounted for |
r | Re-scan the LAN now (ARP sweep; it otherwise runs automatically every hour) |
e | Export audit evidence (CSV of audit results, device inventory or the operation log; an HTML report; JSON). Written as a new owner-only file in /tmp, and the export itself is recorded in the operation log |
Enter | Show details for the selected row (audit history, changes, ARP events, devices, audit log) |
w | (while viewing details) exports the content to a file |
L | Selects the display language |
q | Quits |
9. Trust Model & Security Design
- TOFU (Trust On First Use): the pairing code itself is not a cryptographic proof of ownership — it is confirmed by the operator’s own judgment, having received the code the Sensor operator issued over an out-of-band channel (verbally, chat, etc.), similar to the explicit mutual confirmation of Bluetooth pairing. From the moment pairing succeeds, the legitimacy of every subsequent probe or request is verified against the public key exchanged at that time.
- Designed to find holes that would allow destructive actions, without ever performing a destructive action itself: every active vulnerability audit is non-destructive (it never writes or deletes data, or stops a service). What it does detect are the misconfigurations themselves — things like “writable without authentication” or “functions as an open relay” — that, if exploited, would allow a destructive action.
- False-positive mitigation (self-audit exclusion): a source-IP match exclusion is built in so that a paired Sensor's own full-port audit is not mistaken for reconnaissance by the incoming-port-scan-detection guard (a RoamSwitch-side feature). The IP is used only for this match, purely to avoid an automatic block — it is never used for trust determination itself.
- Nothing is sent unless you configure it: discovered device information, audit results and ARP events are stored, by default, only in the Sensor's own local storage, and are never sent to Lafine or any third-party server. The notifications (webhook / syslog) and central-collector push described in §11 go only to destinations your organization has configured.
10. Troubleshooting & FAQ
Q1. Entering a pairing code gets rejected.
Three likely causes: (1) more than 10 minutes have passed since it was issued and it has expired — ask the Sensor’s operator to issue a new one with issue-code; (2) a typo in the code (the easily-confused characters 0/O/1/I/L are excluded at issuance, so a code never actually contains them); (3) the IP address given with --addr doesn’t match Sensor’s current fixed IP address.
Q2. The NSE supplementary diagnostic result is empty.
One of two causes: (1) nmap is not installed in the container; (2) it did run, but the safe scripts applicable to the target ports genuinely produced no output. nmap NSE supplementary diagnostics run automatically whenever nmap is installed on the host.
Q3. How long does an audit take to complete?
A full port scan alone takes roughly tens of seconds, but when nmap is installed on the host, its supplementary NSE diagnostics run automatically and add to that, taking up to about 2 minutes depending on how many open ports the target has. The TUI keeps showing the elapsed seconds while it runs, so you can watch progress as you wait.
Q4. I paired, but I still can't run an audit.
Likely causes: (1) sensor_pairing_enabled: true isn’t set on the endpoint side (off by default); (2) Sensor’s fixed IP address changed after pairing, so the endpoint is trying to reach a stale address (re-pair to fix this); (3) the pairing was removed on the Sensor side with unpair. Check with roamswitch sensor list (endpoint side) and roamswitch-sensor list (Sensor side) that each recognizes the other.
Q5. Can Sensor itself be used alongside RoamSwitch proper (Client/Server Edition)?
Yes. Because Sensor is designed without self-defense features, we recommend running RoamSwitch for Linux Server Edition alongside it on the same machine. The two operate as completely independent processes and data stores, with no conflicts.
Q6. roamswitch sensor results says the pairing was revoked.
This endpoint’s pairing was removed on the Sensor side with unpair. Ask the Sensor’s operator to issue a new pairing code, then pair again with roamswitch sensor pair --addr <ip> --code <code>.
11. Organization-Scale Audit Features (Opt-In)
A set of features for security teams in large organizations who need audit evidence and a clear picture of what changed. Every one of them is off by default, and nothing is ever sent to Lafine or any third party — every notification or aggregation destination is one your organization configures. Settings are changed with sudo roamswitch-sensor config set <key> <value> (no daemon restart needed; each change is recorded in the operation log); config show prints the current values.
11.1 Scheduled Audits and Change Detection
Setting schedule.enabled to true audits every paired endpoint automatically (every 24 hours by default: schedule.interval_hours; the local-time window in which audits may start: schedule.window_start_hour / window_end_hour, which may wrap past midnight; concurrency: schedule.max_parallel). Each audit is compared with the previous one, and roamswitch-sensor diff shows new findings (regressions), resolved ones and newly open ports. If every port that used to be open is suddenly not visible, that is reported as suspected unreachable, not as "resolved" — a host that is switched off cannot be told apart from one that closed every port.
Unattended audits never break the guarantee that only consenting endpoints are audited. An endpoint's IP can be handed to a different device by DHCP, so the Sensor stores the MAC address the endpoint had when it last authenticated (pairing, or a signed audit request) and confirms with a live ARP request from nmap — before and after each scheduled audit — that the same MAC still answers at that IP. If it does not, the audit is skipped (or its result discarded) and a notification is raised. A manual scan is also refused when there is evidence the address now belongs to another device. This check requires nmap; endpoints paired before this feature existed are not scheduled until they re-pair or send a signed audit request; and only endpoints on the same L2 segment are covered.
11.2 Notifications (Webhook and syslog)
Regressions, new devices, ARP spoofing, suspicious traffic and more are sent to notify.webhook_urls (Slack, Discord or Teams incoming webhooks, or any generic JSON endpoint) and to notify.syslog.host / port / protocol (RFC 5424 over UDP or TCP). Narrow them with notify.min_severity (info / medium / high / critical) and notify.cooldown_minutes (minimum interval before the same event is sent again). roamswitch-sensor notify-test checks each destination.
11.3 Exporting Audit Evidence
roamswitch-sensor export <scans|inventory|audit-log|all> --format csv|json|html [--out file] [--endpoint key-prefix] [--since date]. The html output is a single self-contained file: open it in a browser and choose "Save as PDF" to get a PDF you can hand to auditors. CSV output is protected against spreadsheet formula injection. The device inventory export includes a column showing whether each device is under RoamSwitch management (paired). Output files are readable by their owner only (0600), and the export itself is recorded in the operation log.
11.4 Operation and Approval Log (Tamper-Evident)
Pairing, unpairing, audit start and completion, configuration changes and rejected access attempts are recorded with who did it (UID / endpoint public key / source IP). Each line contains the SHA-256 of the previous one, so any edit or deletion is detected by roamswitch-sensor audit-log verify (exit code 2 when something is wrong). List entries with roamswitch-sensor audit-log [--limit N]. Webhook URLs often embed a token, so configuration-change entries never contain their values. A hash chain alone cannot reveal that the newest entries were cut off, so the chain head (sequence number and hash) is also sent to the collector (§11.6).
11.5 Retention
Set retention.scan_history_days, retention.audit_log_days and retention.inventory_stale_days to have old audit history, operation-log entries and long-unseen devices deleted automatically (0 = never delete by age, the default). Devices that have a note are never removed from the inventory.
11.6 Aggregating Several Sensors (Central Collector, Optional)
When several Sensors run at several sites, run roamswitch-sensor-collector (shipped in the package, disabled by default) on a separate host to collect signed summaries from each of them.
# On the collector host (a separate host from the Sensor is recommended)
sudo systemctl enable --now roamswitch-sensor-collector # listens on 127.0.0.1:8443 by default
sudo roamswitch-sensor-collector token # read token for the dashboard
sudo roamswitch-sensor-collector enroll <Sensor public key> --name Tokyo --site Tokyo
# On each Sensor
sudo roamswitch-sensor config set collector.url https://collector.example.org:8443
sudo roamswitch-sensor config set collector.enabled true
- Only signed requests from Sensors you have enrolled (
enroll) are accepted, using their Ed25519 identity; the timestamp also rejects replays. - TLS is required whenever it is reachable from outside the LAN. Put
--bind 0.0.0.0:8443 --tls-cert … --tls-key …inCOLLECTOR_ARGSin/etc/default/roamswitch-sensor-collector, or use--allow-plain-httpbehind a TLS-terminating reverse proxy. Listening on anything other than 127.0.0.1 without TLS is refused at startup. - The dashboard is protected by a token and offers per-site filtering, events by severity and CSV export. It highlights Sensors that have gone silent and Sensors whose audit log looks truncated, rewound or forked (clear it with
clear-anomaly <public-key>once investigated).