Skip to content

fix(bolt): replace WSL mirrored-networking with a host UDP forwarder#45

Merged
hyperpolymath merged 4 commits into
mainfrom
fix/wsl-bolt-inbound-udp-no-mirrored
May 19, 2026
Merged

fix(bolt): replace WSL mirrored-networking with a host UDP forwarder#45
hyperpolymath merged 4 commits into
mainfrom
fix/wsl-bolt-inbound-udp-no-mirrored

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Why

The WSL2 dev path for the Bolt server was incredibly unstable. Mirrored
mode (networkingMode=mirrored + dnsTunneling/autoProxy/
hostAddressLoopback), which docs/developer/wsl-mirrored-networking.adoc
instructed every contributor to enable, causes recurring Hyper-V
VmSwitch Failed to restore configuration for port … Object Name not found errors and intermittent Wsl/Service/E_UNEXPECTED catastrophic
failures (vNIC flap / VM bounce) on Windows 11 24H2 and Insider builds.

What (3 commits)

  • scripts/wsl-bolt-udp-forward.ps1 (new) — bidirectional userspace
    UDP relay on the Windows host for udp/7373 + udp/9, per-client
    ephemeral upstream with idle expiry (QUIC/ack returns work, not just
    fire-and-forget cold pokes), re-resolves the WSL NAT IP every 15s.
    -Install registers a logon scheduled task; optional -Firewall.
    netsh portproxy is TCP-only and cannot do this.
  • docs/developer/wsl-mirrored-networking.adoc — rewritten: NAT +
    forwarder recommended; bridged = wired alternative; mirrored demoted
    to last-resort with a 24H2/Insider warning. Filename kept (5 inbound
    refs incl. machine-readable state).
  • docs/decisions/0005-wsl-bolt-inbound-udp-no-mirrored.adoc (new)
    — ADR; also turns the stub docs/decisions/README.adoc into a real
    ADR index/decision log.
  • CHANGELOG.md, .machine_readable/6a2/STATE.a2ml, CLAUDE.md,
    README.adoc, router-port-forward.adoc, bolt-ddns.adoc — synced
    so human + machine docs no longer assert mirrored mode.

Verification

Script statically parse-checked (0 errors). End-to-end check is an
operator step: revert ~/.wslconfig to plain NAT, wsl --shutdown,
just server, then a test datagram to <host-lan-ip>:7373 (or
scripts/check-bolt-reachability.sh). Tracked outside this PR.

Considered and rejected

  • proven-stun NAT traversal — cold bolts target peers not in a
    session, so hole-punching is structurally impossible (recorded in
    ADR-0005).
  • proven-frame hardening of Burble.Bolt.Packet — separate, low
    priority.

🤖 Generated with Claude Code

hyperpolymath and others added 4 commits May 19, 2026 11:56
Mirrored mode (networkingMode=mirrored + dnsTunneling/autoProxy/
hostAddressLoopback) causes recurring Hyper-V VmSwitch port-restore
errors and intermittent Wsl/Service/E_UNEXPECTED catastrophic failures
(vNIC flap / VM bounce) on Windows 11 24H2 and Insider builds, making
the WSL2 dev path "incredibly unstable" for every contributor who
followed the old doc.

Replace it with a portable, hazard-free default:

* scripts/wsl-bolt-udp-forward.ps1 — bidirectional userspace UDP relay
  on the Windows host (udp/7373 + udp/9), per-client ephemeral upstream
  with idle expiry, re-resolves the WSL NAT IP every 15s; -Install
  registers a logon scheduled task, optional -Firewall rules. netsh
  portproxy is TCP-only and cannot do this.
* docs/developer/wsl-mirrored-networking.adoc — rewritten: NAT +
  forwarder is now the recommended path; bridged documented as the
  wired alternative; mirrored demoted to fallback-of-last-resort with
  an explicit 24H2/Insider instability warning. Filename kept (5
  inbound refs incl. machine-readable state).
* README.adoc / router-port-forward.adoc / bolt-ddns.adoc / CLAUDE.md —
  reference captions updated so they no longer assert mirrored mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rename the local in Resolve-WslIp to $wslArgs so it no longer shadows
PowerShell's automatic $args variable. Cosmetic; no behaviour change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs/decisions/0005-wsl-bolt-inbound-udp-no-mirrored.adoc — ADR for
  dropping mirrored networking in favour of the host UDP forwarder;
  records the proven-stun rejection rationale and the ADR-0004 link.
* docs/decisions/README.adoc — was a 17-byte stub; now the actual ADR
  index/decision log (0001-0005 with status).
* CHANGELOG.md — [Unreleased] Added/Changed entries for the forwarder
  and the rewritten WSL doc.
* .machine_readable/6a2/STATE.a2ml — corrected the now-false
  "mirrored-networking prereq" claim and appended a 2026-05-19 entry so
  machine state matches reality.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Install-Task generated `powershell -File … -Run -Ports 7373,9`. Under
-File, `7373,9` is passed as the literal string "7373,9", which cannot
bind to [int[]]$Ports, so the task aborted before binding any socket
(Task Scheduler LastTaskResult=1; nothing on udp/7373). Manual runs
worked only because they used the default ports with no -Ports arg.

Switch the generated action to `-Command "& '<self>' -Run -Ports 7373,9"`
so PowerShell parses the array argument correctly. Found by validating
the installed scheduled task end-to-end on Windows 11 (not just the
ad-hoc -Run instance).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath enabled auto-merge (squash) May 19, 2026 11:58
@hyperpolymath hyperpolymath merged commit 5286eea into main May 19, 2026
12 of 14 checks passed
@hyperpolymath hyperpolymath deleted the fix/wsl-bolt-inbound-udp-no-mirrored branch May 19, 2026 12:00
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 21 issues detected

Severity Count
🔴 Critical 4
🟠 High 6
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action ocaml/setup-ocaml@v3 needs attention",
    "type": "unpinned_action",
    "file": "affinescript-canary.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "No permissions declaration -- add permissions: read-all",
    "type": "missing_permissions",
    "file": "elixir-ci.yml",
    "action": "add_permissions",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "binary_to_term without :safe option -- deserialization attack (1 occurrences, CWE-502)",
    "type": "elixir_send_unsanitised",
    "file": "/home/runner/work/burble/burble/server/lib/burble/media/lmdb_playout.ex",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "SSL verify_none disables certificate validation -- MITM risk (1 occurrences, CWE-295)",
    "type": "elixir_no_ssl_verify",
    "file": "/home/runner/work/burble/burble/server/lib/burble/bridges/mumble.ex",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "believe_me undermines formal verification (2 occurrences, CWE-704)",
    "type": "believe_me",
    "file": "/home/runner/work/burble/burble/src/interface/abi/Foreign.idr",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "critical"
  },
  {
    "reason": "Nickel file missing SPDX-License-Identifier header (1 occurrences, CWE-1104)",
    "type": "ncl_missing_spdx",
    "file": "/home/runner/work/burble/burble/configs/config.ncl",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "Lock.unwrap() without poison handling (14 occurrences, CWE-754)",
    "type": "lock_unwrap",
    "file": "/home/runner/work/burble/burble/tools/selur-compose/crates/selur-compose-driver/src/mock.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

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