Skip to main content

Module lan_firewall

Module lan_firewall 

Source
Expand description

Would the OS firewall let LAN peers reach us? Pure rule logic, no OS calls.

SPEC_LAN_FIREWALL_SETUP_2026_10_01.md 4.2 and 4.3. On 2026-09-30 narko had LAN enabled, started its listeners, registered its mDNS service, logged no warning, and never saw a peer, because Windows Defender Firewall had no inbound allow rule for the active Private profile (and 606 stale per-path rules, none of them for the running binary). Nothing in AgentMux could say so.

This module decides, from a snapshot of the firewall rules and the adapters’ network categories, whether each interface is covered, and what the status bar should say. Reading the snapshot is OS-specific and lives elsewhere (lan_firewall_windows.rs); keeping the decision pure means the cases that actually bit us are unit tests that run on every platform.

Windows semantics encoded here:

  • Inbound traffic is blocked unless a matching enabled allow rule exists, and an enabled matching block rule beats any allow.
  • A rule applies per network profile (Domain, Private, Public), and each adapter’s connection has its own category.
  • A rule naming a program matches that exact path. The sidecar’s file name embeds its version (agentmux-srv-0.59.1-windows.x64.exe) and portable and dev builds sit at a new path every time, so a per-program rule stops matching on every update (spec R7). A port rule does not.

Structs§

Adapter
A network adapter and the category of the network it is connected to.
FwRule
One firewall rule, with the fields that decide whether it affects us.
LanFirewall
laninstances:firewall: what the OS firewall would do to LAN peers reaching this machine.
LanFirewallAdapter
One adapter in a LanFirewall verdict.
Need
Something the running srv must be reachable on from the LAN.
ProfileSettings
One profile’s own switches, which decide whether any rule is needed at all (ReAgent P1 on #4151: judging from rules alone reported needs-setup on a profile whose firewall is off, or whose default inbound action is Allow).
Profiles
Report
Snapshot
Everything read from the OS in one go.

Enums§

AdapterState
Applies 🔒
Does a rule apply to need on this adapter? Three answers, not two.
Category
A network’s category, as INetworkListManager reports it.
Coverage
FirewallStatus
What the status bar shows about the firewall (spec 4.3).
LocalScope
A rule’s LocalAddresses: which of OUR addresses it applies to. A rule limited to one local IP must only count for the adapter that owns it (Codex P2 on #4151); treating it as “every adapter in the profile” could make an uncovered adapter look covered, or turn an address-scoped block into a false global block.
PortSpec
A rule’s LocalPorts. Anything we cannot read exactly is Unparseable and matches nothing: claiming coverage we cannot prove is the worse error.
Proto
Remote
A rule’s RemoteAddresses, reduced to the one question that matters here: does it reach LAN peers in general?

Constants§

PROFILE_DOMAIN
NET_FW_PROFILE2_* bits.
PROFILE_PRIVATE
PROFILE_PUBLIC
WATCH_TICK 🔒
How often the firewall is read while LAN discovery is wanted. A read is cheap (about 60 ms for 1,300 rules on narko) and a changed rule or network should show promptly.

Functions§

adapter_state_with
applies_to 🔒
category_wire 🔒
coverage_with
Does category’s profile let LAN peers reach exe on every need?
lan_needs
The inbound traffic a LAN peer needs: our web and ws ports (TCP), the mDNS port (UDP 5353) and the UDP broadcast-probe responder that mobile clients use when mDNS is filtered (lan_discovery::UDP_DISCOVERY_PORT, spec 4.1 puts it in the same rule as 5353; Codex P2 on #4151).
overall
The overall status from every adapter. One covered adapter is enough for “ok”: a host also has virtual adapters (VMware, WSL, Hyper-V) that are rightly uncovered, and they must not flag a machine whose real LAN works. Otherwise the most actionable problem wins: a block, then a managed policy (no helper can help), then missing rules, then an untrusted Public network.
payload
The laninstances:firewall event body.
read_snapshot
report
rule_applies 🔒
An ALLOW counts only when every field is evaluable and says yes: counting one we cannot evaluate would claim coverage we cannot prove. A BLOCK is the opposite case, handled in coverage_with: skipping one we cannot evaluate would lean toward Covered, the very direction the unreadable-means-unknown rule forbids (ReAgent on #4151).
same_path
Compare two Windows paths: case-insensitive, / equals \, the \\?\ prefix ignored. Rules that use environment variables (%SystemRoot%) do not match: coverage is only claimed when it can be shown.
should_publish
Whether this status goes to the windows on this tick. A standing problem is re-sent every tick so a window opened later, or a reconnected WebSocket, learns of it: the frontend only learns from events and cannot ask (the same lesson as lan_mdns_health::should_publish, ReAgent P1 on #4148). Ok and Unknown go out only on change.
spawn_watcher
Watch the OS firewall while LAN discovery is wanted and tell the windows what it found, via laninstances:firewall. Only Windows can read its firewall today (macOS and Linux are later PRs): elsewhere this does nothing, so the status bar simply has no firewall verdict.
state_wire 🔒