diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-04 15:54:05 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-04 15:54:05 +0200 |
| commit | 7ff675fdc0866ca40bdb703bc95c0cc60e3edd87 (patch) | |
| tree | 46a3cd561a876dfea9aa511b3410b5224a032613 /packaging | |
| parent | 74941aae5451c03a296413710fe888b1924e8c27 (diff) | |
| download | meshbay-7ff675fdc0866ca40bdb703bc95c0cc60e3edd87.tar.gz | |
feat(packaging): cover LAN casting in the Windows firewall step, too
firewall.ps1 only handled WebRTC. The cast HTTP relay (src/cast-relay.js,
fixed TCP 19550-19553) and Chromecast/Smart TV mDNS discovery
(src/cast-chromecast.js, bonjour-service, UDP 5353) are a separate surface
on the client and were still hitting Windows' own "Allow access" dialog.
Now four named rules: MeshBay / MeshBay Node stay program-scoped with no
port restriction (there is no fixed WebRTC port to name -- the Windows
equivalent of the broad 1024-65535/udp range the Linux packaging needs,
since netfilter has no program scoping); MeshBay Cast / MeshBay Cast
Discovery add the program AND the fixed port, matching
packaging/firewall/*/meshbay-cast.xml exactly.
test_packaging_win.py cross-checks the port numbers against cast-relay.js's
own constants and the Linux firewalld definition, so the three descriptions
of one port range can't quietly drift apart.
Verified: rebuilt MeshBay-Setup-0.1.0.exe; the deployed firewall.ps1 carries
all four rules. Node suite 836 pass / 25 skip.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'packaging')
| -rw-r--r-- | packaging/win/README.md | 41 | ||||
| -rw-r--r-- | packaging/win/firewall.ps1 | 62 |
2 files changed, 71 insertions, 32 deletions
diff --git a/packaging/win/README.md b/packaging/win/README.md index 7bd7f67..5130e60 100644 --- a/packaging/win/README.md +++ b/packaging/win/README.md @@ -89,18 +89,35 @@ publish their host candidate as an unresolvable `<uuid>.local` mDNS name that `aioice` discards — the browser always dials the node, never the reverse. So the node has to accept unsolicited inbound UDP from its peers. -**Windows Defender Firewall.** The setup wizard offers to add the inbound rules -for `MeshBay.exe` and `meshbay-node.exe` in one step — it needs one admin -confirmation (`build/installer.nsh` runs `firewall.ps1` via NSIS `ExecShellWait -"runas"`; the per-user install itself never elevates). Say yes and both -prompts you'd otherwise hit mid-use are gone; say no, or the UAC prompt is -dismissed, and Windows falls back to its own **"Allow access"** dialog the -first time each process binds a socket — tick **both Private and Public** then -(a libvirt/VM adapter, and sometimes a plain Ethernet one, registers as -Public; a Private-only rule silently drops every peer). Missed both? Add it by -hand: *Windows Defender Firewall → Advanced → Inbound Rules → New Rule → -Program →* the bundled `…\resources\node-runtime\meshbay-node.exe` *→ Allow → -all profiles*. `firewall.ps1` is idempotent and re-runnable +**Windows Defender Firewall.** The setup wizard offers to add four inbound +rules in one step — it needs one admin confirmation (`build/installer.nsh` +runs `firewall.ps1` via NSIS `ExecShellWait "runas"`; the per-user install +itself never elevates): + +| Rule | Program | Protocol / port | For | +|---|---|---|---| +| `MeshBay` | `MeshBay.exe` | UDP, any port | WebRTC (ICE checks touch the client too) | +| `MeshBay Node` | `meshbay-node.exe` | UDP, any port | WebRTC (the node — unsolicited inbound, see above) | +| `MeshBay Cast` | `MeshBay.exe` | TCP 19550–19553 | LAN cast HTTP relay (`src/cast-relay.js`) | +| `MeshBay Cast Discovery` | `MeshBay.exe` | UDP 5353 | Chromecast/Smart TV mDNS discovery (`bonjour-service`) | + +The WebRTC rules have no port restriction because there is no fixed port to +name — aiortc binds a fresh one per connection — so they are scoped by +*program* instead, which is the Windows-native answer to the same problem the +Linux packaging solves with a broad `1024-65535/udp` range +(`packaging/firewall/`). The cast rules are scoped by program *and* port, +since those two are fixed and known — matching +`packaging/firewall/*/meshbay-cast.xml` exactly. + +Say yes and every prompt you'd otherwise hit mid-use — connecting, or the +first cast — is gone. Say no, or the UAC prompt is dismissed, and Windows +falls back to its own **"Allow access"** dialog the first time each +program/port combination is used — tick **both Private and Public** then (a +libvirt/VM adapter, and sometimes a plain Ethernet one, registers as Public; a +Private-only rule silently drops every peer). Missed one? Add it by hand: +*Windows Defender Firewall → Advanced → Inbound Rules → New Rule → Program →* +the exe *→ Allow → all profiles*, restricting to the port above if it is a +cast rule. `firewall.ps1` is idempotent and re-runnable (`powershell -File resources\firewall.ps1 add`, elevated); it logs to `%TEMP%\meshbay-firewall.log`. diff --git a/packaging/win/firewall.ps1 b/packaging/win/firewall.ps1 index abed109..bf1b32b 100644 --- a/packaging/win/firewall.ps1 +++ b/packaging/win/firewall.ps1 @@ -3,19 +3,33 @@ Add (or remove) the inbound Windows Firewall rules MeshBay needs. .DESCRIPTION - WebRTC binds an ephemeral UDP port per connection and the browser always - dials the node (aioice cannot resolve the peer's mDNS `.local` candidate), - so the node must accept unsolicited inbound UDP. Without a rule, Windows - pops an "Allow access" dialog the first time each of MeshBay.exe and - meshbay-node.exe binds a socket. + Two independent things need an inbound allow, and Windows prompts + "Allow access" for each the first time it happens if there is no rule: + + 1. WebRTC (MeshBay.exe and meshbay-node.exe). It binds an ephemeral UDP + port per connection, and the browser always dials the node -- aioice + cannot resolve the peer's mDNS `.local` candidate to call back -- so the + node (and, during ICE connectivity checks, the client) must accept + unsolicited inbound UDP. There is no fixed port, so these rules are + scoped by PROGRAM with no LocalPort restriction, which is the Windows- + native way to say "this binary, any port it happens to bind" -- the + Linux packaging (packaging/firewall/) has to approximate the same thing + with a broad 1024-65535/udp port range because netfilter has no + equivalent program scoping. + 2. LAN casting (MeshBay.exe only): the HTTP relay to a Chromecast/Smart TV + (src/cast-relay.js, fixed TCP 19550-19553) and mDNS device discovery + (src/cast-chromecast.js via bonjour-service, UDP 5353). Both scoped by + program AND port -- narrower than the WebRTC rules, since these ports + are fixed and known. Matches packaging/firewall/*/meshbay-cast.xml. The installer runs this once, elevated, so the user answers one UAC prompt - instead of two firewall dialogs later. Declining the installer's offer is - fine -- the dialogs are the fallback. + instead of up to four dialogs spread across first use of chat, downloads + and casting. Declining the installer's offer is fine -- the dialogs are + the fallback, one per program/port combination as each is first used. Shipped as an extraResource at <install>\resources\firewall.ps1, so it - locates the two executables from its own path and takes no arguments beyond - the action. Runs elevated and windowless, so it leaves a trace at + locates the two executables from its own path and takes no arguments + beyond the action. Runs elevated and windowless, so it leaves a trace at %TEMP%\meshbay-firewall.log. .PARAMETER Action @@ -37,28 +51,36 @@ $resources = $PSScriptRoot $install = Split-Path -Parent $resources $GROUP = "MeshBay" -$targets = @( - @{ Name = "MeshBay"; Path = Join-Path $install "MeshBay.exe" } - @{ Name = "MeshBay Node"; Path = Join-Path $resources "node-runtime\meshbay-node.exe" } +$client = Join-Path $install "MeshBay.exe" +$node = Join-Path $resources "node-runtime\meshbay-node.exe" + +# Program-scoped, any port: the ephemeral-UDP-port problem WebRTC always has. +# Port-scoped as well: the two fixed, known ports LAN casting actually uses. +$rules = @( + @{ Name = "MeshBay"; Path = $client; Protocol = "UDP"; LocalPort = "Any" } + @{ Name = "MeshBay Node"; Path = $node; Protocol = "UDP"; LocalPort = "Any" } + @{ Name = "MeshBay Cast"; Path = $client; Protocol = "TCP"; LocalPort = "19550-19553" } + @{ Name = "MeshBay Cast Discovery"; Path = $client; Protocol = "UDP"; LocalPort = "5353" } ) try { - foreach ($t in $targets) { + foreach ($r in $rules) { # Idempotent: clear any existing rule of this name first. - Remove-NetFirewallRule -DisplayName $t.Name -ErrorAction SilentlyContinue + Remove-NetFirewallRule -DisplayName $r.Name -ErrorAction SilentlyContinue if ($Action -eq "add") { - if (-not (Test-Path $t.Path)) { - " skip $($t.Name): $($t.Path) not found" | Add-Content $log + if (-not (Test-Path $r.Path)) { + " skip $($r.Name): $($r.Path) not found" | Add-Content $log continue } - New-NetFirewallRule -DisplayName $t.Name -Group $GROUP ` + New-NetFirewallRule -DisplayName $r.Name -Group $GROUP ` -Direction Inbound -Action Allow ` - -Program $t.Path -Protocol UDP -Profile Any | Out-Null - " allowed $($t.Name) ($($t.Path))" | Add-Content $log + -Program $r.Path -Protocol $r.Protocol -LocalPort $r.LocalPort ` + -Profile Any | Out-Null + " allowed $($r.Name) ($($r.Protocol) $($r.LocalPort), $($r.Path))" | Add-Content $log } else { - " removed $($t.Name)" | Add-Content $log + " removed $($r.Name)" | Add-Content $log } } } |