Skip to content

fix(net): GOAWAY local check decodes every IPv4 spelling the dial accepts - #8327

Merged
kixelated merged 2 commits into
mainfrom
quest/m0/goaway-loopback
Nov 9, 2026
Merged

kixelated merged 2 commits into
mainfrom
quest/m0/goaway-loopback

Conversation

@kixelated

@kixelated kixelated commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A GOAWAY from a non-local relay could steer a redirect: "follow" Rust client to loopback by spelling the address as shorthand or numeric IPv4 (moqt://127.1, 0x7f000001, 2130706433, 0177.0.0.1). A non-special scheme keeps its host opaque, str::parse::<IpAddr> refused those spellings, and the native dial still reached 127.0.0.1.

  • rs/moq-net/src/reconnect/redirect.rs: is_local reads a Host::Domain back through an https:// URL (WHATWG host parser), as js/net's endpoint.ts has done since moq-dev/moq#8222, and strips a trailing dot before the localhost check.
  • rs/moq-net/fixtures/endpoints.json: one corpus of spellings and verdicts, replayed by the Rust unit test and js/net/src/connection/endpoint.test.ts, so the classifiers cannot drift.
  • The quest is rewritten to what remains: the release backport, which CONTRIBUTING.md says lands only after the main fix.

Hostnames that resolve to local addresses stay out of scope (documented on Redirect::Follow).

Impact

Public API: none. Wire: none. Behavior: such redirects are refused.

Caused by

  • moq-dev/moq#8222 - fixed js/net but left Rust's is_local on str::parse::<IpAddr>.

Choices made without asking

  • Backport left for after merge (quest rewritten to it) rather than opened now, per CONTRIBUTING.md's "land on main first".
  • Fixture placed in rs/moq-net/fixtures/, beside lite.json.

Follow-ups

None.

Models

Size: S
Implementer: Claude Code, Opus 5.5, unknown effort

(Written by Opus 5.5)

Review

Rewritten by quest review after each round.

  • Reviewer: Codex, gpt-6.1-sol, medium effort
  • Session: 01a1bd10-1c75-75c3-9efe-d489d2031f55, round 1
  • Head: 2e2f754
  • Base: origin/main at cb86f86
  • Score: 9/10, The change is focused and covered by targeted cases, with no actionable defects found in source review, though builds and tests were not run as instructed.
  • Findings: none

kixelated and others added 2 commits November 8, 2026 13:05
…epts

Rust's is_local reads a non-special scheme's host back through https, as
js/net does, so moqt://127.1 and friends count as loopback, and treats
localhost. as localhost. Both sides replay rs/moq-net/fixtures/endpoints.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title GOAWAY redirects to loopback are refused in every spelling, on main and release fix(net): GOAWAY local check decodes every IPv4 spelling the dial accepts Nov 8, 2026
@kixelated
kixelated marked this pull request as ready for review November 8, 2026 21:29
@coderabbitai

coderabbitai Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4a658f0f-aa0e-4e66-a2de-572dce354dad
Commits

Reviewing files that changed from the base of the PR and between f7926f8 and 2e2f754.

Files selected for processing: 4

  • js/net/src/connection/endpoint.test.ts
  • quest/m0/goaway-loopback.md
  • rs/moq-net/fixtures/endpoints.json
  • rs/moq-net/src/reconnect/redirect.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed 2e2f754. No actionable findings.

The Rust classifier now normalizes opaque hosts through the special-scheme parser before checking local IPv4 forms and trailing-dot localhost names. Checked the existing IPv6/mapped-address handling, redirect policy ordering, shared Rust/JS fixture paths, and public-to-local refusal regression. DNS-resolved destinations remain outside this literal-address check, as documented. The release backport remains explicitly tracked.

Verification limits: GitHub-only static review; Rust/JS tests and native DNS/dial behavior were not executed.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Rust classifier decodes opaque hosts: is_local in rs/moq-net/src/reconnect/redirect.rs now re-reads a Host::Domain through the WHATWG special-scheme host parser (https://{host}/), classifies the resulting Ipv4/Ipv6/Domain, and strips a trailing dot before the localhost check, so moqt://127.1, hex/octal/decimal IPv4, LOCALHOST, localhost., and 0 are refused like their dotted-quad spellings. The old literal logic remains as the fallback when the reparse fails.
  • Shared corpus: rs/moq-net/fixtures/endpoints.json holds 30 spellings and verdicts, replayed by the Rust unit test (include_str!) and js/net/src/connection/endpoint.test.ts (Bun.file), so the Rust and JS classifiers cannot drift.
  • Redirect behaviour test: adds a Redirect::Follow refusal case for moqt://127.1 against a non-local current target.
  • Quest re-scope: quest/m0/goaway-loopback.md is rewritten to cover only the release backport.

Verification: the JS suite and tsc --noEmit pass, and the fixture file lints clean. The crate test could not run here (target/ was locked by another session), so I compiled a verbatim copy of is_local/is_local_ip/is_local_v4 against the checkout's url 2.5.8 rlib: all 30 cases classify as the fixture expects. I also probed glibc getaddrinfo for the shorthand/hex/octal spellings the native dial sees — each resolves to the same address the WHATWG parser yields, and invalid-octal forms (08, 019) fail both, so no dial-accepted literal spelling is left unclassified.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏

@kixelated
kixelated added this pull request to the merge queue Nov 9, 2026
Merged via the queue into main with commit f1eaf9c Nov 9, 2026
14 checks passed
@kixelated
kixelated deleted the quest/m0/goaway-loopback branch November 9, 2026 01:24
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