feat(relay): unauthenticated internal listener over qmux (tcp:// + unix://)#1810
Conversation
…ix://) Add a second relay listener for trusted same-host workers that want qmux without the overhead of TLS and UDP. Every accepted connection is granted unrestricted, internal-tier access (full publish/subscribe under the empty root), with no JWT or client certificate. This is the local-worker analogue of an mTLS cluster peer dialing "/". A single `--internal-listen` value picks the transport: a `host:port` binds a plain-TCP listener, a filesystem path (optionally `unix:`-prefixed) binds a Unix socket. TCP carries no peer identity, so a non-loopback bind logs a warning (operator firewalls it). A Unix socket can additionally restrict callers by kernel-reported credentials via `[internal.allow]` (uid/gid/pid; empty = no check, AND across fields, OR within), which is how you ensure only a specific worker user connects rather than any local process. moq-native gains `tcp://` and `unix://` schemes (qmux over a raw stream) plus server `Listener`s; both are always-on for native via default features and drop out of `--no-default-features` (wasm) builds. The application protocol is negotiated in-band (qmux 0.2 transport parameter), so the exact moq version is agreed up front instead of falling back to a SETUP default. Adopts the breaking qmux 0.0.8 -> 0.2.0 bump: the tcp/uds/ws builder API replaces the old free functions, `ws::Bare` becomes `ws::Upgraded`, and the removed `qmux::PREFIXES` is reconstructed locally via `Version::prefix()` in the WebSocket subprotocol builders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The peer-credential allowlist only applies to Unix sockets, so a single `listen` field (TCP-or-Unix) with a sibling `allow` was awkward: `allow` was silently ignored for TCP. Split into `[internal.tcp]` and `[internal.uds]`, each with its own `listen`, and move `allow` inside `[internal.uds]` where it belongs. Drops the `InternalListen` enum (and its custom FromStr/Display/serde): the TCP listener is a plain `Option<SocketAddr>` and the Unix listener a plain `Option<PathBuf>`, both parsed natively. The Unix flag is now `--internal-uds-listen` (`MOQ_INTERNAL_UDS_LISTEN`); `--internal-listen` stays the TCP one. Both listeners can run concurrently. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`uds` implies `tcp`, so it was covered transitively, but add it explicitly to the `Client::new`/`connect` cfg(any) feature lists (and the NoBackend messages) so the gates stay correct if uds ever stops implying tcp. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
moq-transport-18 requires the qmux-01 wire format, so pairing it with qmux-00 is illegal. The qmux 0.0.8 -> 0.2.0 bump introduced qmux-01, so the WebSocket subprotocol cross-product started emitting `qmux-00.moqt-18`. Exclude it in both the relay's `supported_subprotocols` and moq-native's `websocket_subprotocols`, matching the policy already on `dev` (and js/net's connect.ts). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThe pull request bumps the 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches✨ Simplify code
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (1)
rs/moq-relay/src/internal.rs (1)
1-8: ⚡ Quick winAdd module-level
//!docs for theinternalmodule.This file exports public API, but there is no module-root
//!documentation block.
As per coding guidelines: “Document every exported Rust symbol with doc comments (///), including everypubitem and module-level docs (//!block at module root)”.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rs/moq-relay/src/internal.rs` around lines 1 - 8, Add a module-level documentation block at the very beginning of the internal.rs file before the use statements and imports. Insert a `//!` comment block that describes the purpose and contents of the internal module, following Rust documentation conventions. This documentation should explain what this module does and what public API it exports.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@doc/bin/relay/auth.md`:
- Around line 259-262: The sentence "any local process of any user can connect"
in the TCP authentication section understates the actual exposure when the relay
is bound to non-loopback addresses. Revise this wording to clarify that while
loopback restricts access to local processes only, non-loopback binds allow
remote hosts on reachable networks to connect as well. This will help operators
correctly understand the true security exposure of their configuration choices.
In `@doc/bin/relay/config.md`:
- Around line 101-103: The opening description of the `[internal]` section
currently describes the listeners as being for "trusted local workers," which is
narrower than the actual behavior. When `internal.tcp.listen` is configured with
a non-loopback address, connections are accepted from any trusted workers on
reachable networks, not just local ones. Update the intro text in the
`[internal]` section (around lines 101-103) to use broader wording such as
"trusted workers on trusted reachable networks" to accurately reflect the actual
access behavior and risk model. Also apply the same terminology update to the
corresponding description at lines 121-122.
In `@rs/moq-native/src/error.rs`:
- Around line 75-81: The Error enum is currently externally exhaustive, which
breaks forward compatibility as new variants like Tcp and Unix are being added.
Add the #[non_exhaustive] attribute to the Error enum declaration to signal to
external consumers that additional variants may be introduced in future
releases, preventing breaking changes when the enum grows.
In `@rs/moq-native/src/lib.rs`:
- Around line 30-34: The newly exported public modules tcp and unix lack
item-level documentation comments. Add a /// doc comment block above each of the
pub mod tcp; and pub mod unix; declarations to document their purpose and
functionality according to the coding guidelines that require every exported
Rust symbol to have doc comments. Ensure the doc comments clearly describe what
each module provides to users of the library.
In `@rs/moq-native/src/unix.rs`:
- Around line 106-108: The code unconditionally removes socket files at two
locations without verifying ownership, risking deletion of active listeners or
files recreated by other processes. First, in the fs::symlink_metadata match
block around line 107, before calling fs::remove_file on a socket path, add
verification that the socket is not actively in use or owned by another process.
Second, in the Drop implementation around lines 170-174, before unconditionally
removing the socket file, add a check to verify that the current path still
refers to the socket this listener created (such as by comparing inode numbers
or other identifying metadata), and only remove it if ownership can be proven.
This ensures bind-time preemptive unlink and drop-time cleanup only delete
sockets that are definitely safe to remove.
In `@rs/moq-relay/src/config.rs`:
- Around line 343-346: The test isolation in the unsafe block is incomplete as
it only clears MOQ_INTERNAL_LISTEN and MOQ_INTERNAL_UDS_LISTEN environment
variables. To prevent test environment-dependency and ensure proper isolation,
add three additional std::env::remove_var calls within the same unsafe block to
clear MOQ_INTERNAL_ALLOW_UID, MOQ_INTERNAL_ALLOW_GID, and MOQ_INTERNAL_ALLOW_PID
environment variables alongside the existing removal calls.
In `@rs/moq-relay/src/internal.rs`:
- Around line 190-195: The error message in the run_uds function currently
doesn't distinguish between two different failure scenarios: running on a
non-Unix target versus running on Unix without the uds feature enabled. Split
the run_uds function into two separate implementations using distinct cfg
attributes: one for non-Unix targets (cfg(not(unix))) with an error message
indicating Unix socket support is only available on Unix platforms, and another
for Unix systems without the uds feature (cfg(all(unix, not(feature = "uds"))))
with an error message indicating the relay was built without the uds feature.
This way, operators will see the correct error message for their specific
situation during debugging.
In `@rs/moq-relay/tests/smoke.rs`:
- Around line 364-365: The spawn_internal_unix_relay() function is gated only on
the unix platform with #[cfg(unix)], but it should also be gated on the uds
feature since the test path relies on internal.uds.listen support. Update the
conditional compilation attribute to gate the function on both unix and the uds
feature (using #[cfg(all(unix, feature = "uds"))]). Apply the same fix to the
other related test function mentioned in the also applies to section around
lines 399-401.
---
Nitpick comments:
In `@rs/moq-relay/src/internal.rs`:
- Around line 1-8: Add a module-level documentation block at the very beginning
of the internal.rs file before the use statements and imports. Insert a `//!`
comment block that describes the purpose and contents of the internal module,
following Rust documentation conventions. This documentation should explain what
this module does and what public API it exports.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0fb8e893-f3f6-48e0-beff-b88dab60fc3e
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (17)
Cargo.tomldoc/bin/relay/auth.mddoc/bin/relay/config.mdrs/moq-native/Cargo.tomlrs/moq-native/src/client.rsrs/moq-native/src/error.rsrs/moq-native/src/lib.rsrs/moq-native/src/tcp.rsrs/moq-native/src/unix.rsrs/moq-native/src/websocket.rsrs/moq-relay/Cargo.tomlrs/moq-relay/src/config.rsrs/moq-relay/src/internal.rsrs/moq-relay/src/lib.rsrs/moq-relay/src/main.rsrs/moq-relay/src/websocket.rsrs/moq-relay/tests/smoke.rs
| TCP carries no peer identity, so **any local process of any user** can connect. | ||
| Loopback is the safest bind; a private VPC interface is also valid. The relay | ||
| logs a warning when `listen` is not a loopback address but does not refuse to | ||
| start, so firewalling the port is your responsibility. |
There was a problem hiding this comment.
Clarify TCP reachability wording to include non-local clients.
This section currently says “any local process,” but non-loopback binds can also be reached by remote hosts on reachable networks. Please tighten the wording so operators don’t underestimate exposure.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@doc/bin/relay/auth.md` around lines 259 - 262, The sentence "any local
process of any user can connect" in the TCP authentication section understates
the actual exposure when the relay is bound to non-loopback addresses. Revise
this wording to clarify that while loopback restricts access to local processes
only, non-loopback binds allow remote hosts on reachable networks to connect as
well. This will help operators correctly understand the true security exposure
of their configuration choices.
| Unauthenticated qmux listeners (no TLS) for trusted local workers. Every | ||
| connection is granted full, unrestricted access. A TCP and a Unix-socket | ||
| listener can each be enabled independently; both default to disabled. |
There was a problem hiding this comment.
Align [internal] intro wording with non-loopback behavior.
The opening “trusted local workers” phrasing is narrower than actual behavior when internal.tcp.listen is non-loopback. Consider “trusted workers on trusted reachable networks” (or equivalent) to match the risk model.
Also applies to: 121-122
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@doc/bin/relay/config.md` around lines 101 - 103, The opening description of
the `[internal]` section currently describes the listeners as being for "trusted
local workers," which is narrower than the actual behavior. When
`internal.tcp.listen` is configured with a non-loopback address, connections are
accepted from any trusted workers on reachable networks, not just local ones.
Update the intro text in the `[internal]` section (around lines 101-103) to use
broader wording such as "trusted workers on trusted reachable networks" to
accurately reflect the actual access behavior and risk model. Also apply the
same terminology update to the corresponding description at lines 121-122.
| #[cfg(feature = "tcp")] | ||
| #[error(transparent)] | ||
| Tcp(Arc<crate::tcp::Error>), | ||
|
|
||
| #[cfg(all(feature = "uds", unix))] | ||
| #[error(transparent)] | ||
| Unix(Arc<crate::unix::Error>), |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Make Error forward-compatible before adding more variants.
This enum is still externally exhaustive while continuing to grow (new Tcp/Unix variants). Add #[non_exhaustive] on the enum declaration.
Suggested change
+#[non_exhaustive]
pub enum Error {As per coding guidelines: "Add #[non_exhaustive] to public enums that may gain variants in the future."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@rs/moq-native/src/error.rs` around lines 75 - 81, The Error enum is currently
externally exhaustive, which breaks forward compatibility as new variants like
Tcp and Unix are being added. Add the #[non_exhaustive] attribute to the Error
enum declaration to signal to external consumers that additional variants may be
introduced in future releases, preventing breaking changes when the enum grows.
Source: Coding guidelines
| #[cfg(feature = "tcp")] | ||
| pub mod tcp; | ||
| pub mod tls; | ||
| #[cfg(all(feature = "uds", unix))] | ||
| pub mod unix; |
There was a problem hiding this comment.
Add item docs for newly exported modules.
pub mod tcp; and pub mod unix; are new public exports but currently have no /// item-level docs.
As per coding guidelines: "Document every exported Rust symbol with doc comments (///), including every pub item and module-level docs."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@rs/moq-native/src/lib.rs` around lines 30 - 34, The newly exported public
modules tcp and unix lack item-level documentation comments. Add a /// doc
comment block above each of the pub mod tcp; and pub mod unix; declarations to
document their purpose and functionality according to the coding guidelines that
require every exported Rust symbol to have doc comments. Ensure the doc comments
clearly describe what each module provides to users of the library.
Source: Coding guidelines
| match fs::symlink_metadata(&path) { | ||
| Ok(meta) if meta.file_type().is_socket() => fs::remove_file(&path)?, | ||
| Ok(_) => return Err(Error::NotASocket(path)), |
There was a problem hiding this comment.
Avoid unconditional socket-path deletion; it can clobber active or replaced files.
On Line 107, bind-time preemptive unlink of any socket path can replace a live listener. On Lines 170-174, unconditional remove_file during Drop can delete a path that was recreated by another process.
Safer approach
- match fs::symlink_metadata(&path) {
- Ok(meta) if meta.file_type().is_socket() => fs::remove_file(&path)?,
- Ok(_) => return Err(Error::NotASocket(path)),
- Err(err) if err.kind() == io::ErrorKind::NotFound => {}
- Err(err) => return Err(err.into()),
- }
- let listener = tokio::net::UnixListener::bind(&path)?;
+ let listener = match tokio::net::UnixListener::bind(&path) {
+ Ok(l) => l,
+ Err(err) if err.kind() == io::ErrorKind::AddrInUse => {
+ // only reclaim after confirming stale socket, then retry bind
+ // (e.g., connect probe fails with ECONNREFUSED / ENOENT)
+ // ...
+ }
+ Err(err) => return Err(err.into()),
+ };Also guard drop cleanup by verifying the current path still refers to the socket this listener created (or skip cleanup unless ownership can be proven).
Also applies to: 170-174
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@rs/moq-native/src/unix.rs` around lines 106 - 108, The code unconditionally
removes socket files at two locations without verifying ownership, risking
deletion of active listeners or files recreated by other processes. First, in
the fs::symlink_metadata match block around line 107, before calling
fs::remove_file on a socket path, add verification that the socket is not
actively in use or owned by another process. Second, in the Drop implementation
around lines 170-174, before unconditionally removing the socket file, add a
check to verify that the current path still refers to the socket this listener
created (such as by comparing inode numbers or other identifying metadata), and
only remove it if ownership can be proven. This ensures bind-time preemptive
unlink and drop-time cleanup only delete sockets that are definitely safe to
remove.
| unsafe { | ||
| std::env::remove_var("MOQ_INTERNAL_LISTEN"); | ||
| std::env::remove_var("MOQ_INTERNAL_UDS_LISTEN"); | ||
| } |
There was a problem hiding this comment.
Harden test isolation by clearing internal allowlist env vars too.
The test currently clears only MOQ_INTERNAL_LISTEN and MOQ_INTERNAL_UDS_LISTEN. If MOQ_INTERNAL_ALLOW_UID/GID/PID is set in the host environment, this test can become environment-dependent.
Suggested patch
unsafe {
std::env::remove_var("MOQ_INTERNAL_LISTEN");
std::env::remove_var("MOQ_INTERNAL_UDS_LISTEN");
+ std::env::remove_var("MOQ_INTERNAL_ALLOW_UID");
+ std::env::remove_var("MOQ_INTERNAL_ALLOW_GID");
+ std::env::remove_var("MOQ_INTERNAL_ALLOW_PID");
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| unsafe { | |
| std::env::remove_var("MOQ_INTERNAL_LISTEN"); | |
| std::env::remove_var("MOQ_INTERNAL_UDS_LISTEN"); | |
| } | |
| unsafe { | |
| std::env::remove_var("MOQ_INTERNAL_LISTEN"); | |
| std::env::remove_var("MOQ_INTERNAL_UDS_LISTEN"); | |
| std::env::remove_var("MOQ_INTERNAL_ALLOW_UID"); | |
| std::env::remove_var("MOQ_INTERNAL_ALLOW_GID"); | |
| std::env::remove_var("MOQ_INTERNAL_ALLOW_PID"); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@rs/moq-relay/src/config.rs` around lines 343 - 346, The test isolation in the
unsafe block is incomplete as it only clears MOQ_INTERNAL_LISTEN and
MOQ_INTERNAL_UDS_LISTEN environment variables. To prevent test
environment-dependency and ensure proper isolation, add three additional
std::env::remove_var calls within the same unsafe block to clear
MOQ_INTERNAL_ALLOW_UID, MOQ_INTERNAL_ALLOW_GID, and MOQ_INTERNAL_ALLOW_PID
environment variables alongside the existing removal calls.
| #[cfg(not(all(feature = "uds", unix)))] | ||
| async fn run_uds(path: PathBuf, _allow: InternalAllow, _cluster: Cluster) -> anyhow::Result<()> { | ||
| anyhow::bail!( | ||
| "internal.uds.listen requests a Unix socket ({}) but this relay was built without the `uds` feature", | ||
| path.display() | ||
| ) |
There was a problem hiding this comment.
Differentiate non-Unix vs missing-uds in the fallback error message.
Line 193 currently always says “built without the uds feature”, but this branch also covers non-Unix targets. That can mislead operators during debugging.
Suggested patch
#[cfg(not(all(feature = "uds", unix)))]
async fn run_uds(path: PathBuf, _allow: InternalAllow, _cluster: Cluster) -> anyhow::Result<()> {
- anyhow::bail!(
- "internal.uds.listen requests a Unix socket ({}) but this relay was built without the `uds` feature",
- path.display()
- )
+ if !cfg!(unix) {
+ anyhow::bail!(
+ "internal.uds.listen requests a Unix socket ({}) but this target is not Unix",
+ path.display()
+ );
+ }
+ anyhow::bail!(
+ "internal.uds.listen requests a Unix socket ({}) but this relay was built without the `uds` feature",
+ path.display()
+ )
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@rs/moq-relay/src/internal.rs` around lines 190 - 195, The error message in
the run_uds function currently doesn't distinguish between two different failure
scenarios: running on a non-Unix target versus running on Unix without the uds
feature enabled. Split the run_uds function into two separate implementations
using distinct cfg attributes: one for non-Unix targets (cfg(not(unix))) with an
error message indicating Unix socket support is only available on Unix
platforms, and another for Unix systems without the uds feature (cfg(all(unix,
not(feature = "uds")))) with an error message indicating the relay was built
without the uds feature. This way, operators will see the correct error message
for their specific situation during debugging.
| #[cfg(unix)] | ||
| async fn spawn_internal_unix_relay() -> (std::path::PathBuf, tokio::task::JoinHandle<()>) { |
There was a problem hiding this comment.
Gate the Unix internal smoke test on uds feature too.
On Unix builds without uds, run_internal rejects internal.uds.listen, so this test path can fail by timeout instead of being skipped.
Suggested patch
-#[cfg(unix)]
+#[cfg(all(unix, feature = "uds"))]
async fn spawn_internal_unix_relay() -> (std::path::PathBuf, tokio::task::JoinHandle<()>) {
@@
-#[cfg(unix)]
+#[cfg(all(unix, feature = "uds"))]
#[tokio::test]
async fn internal_unix_round_trip() {Also applies to: 399-401
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@rs/moq-relay/tests/smoke.rs` around lines 364 - 365, The
spawn_internal_unix_relay() function is gated only on the unix platform with
#[cfg(unix)], but it should also be gated on the uds feature since the test path
relies on internal.uds.listen support. Update the conditional compilation
attribute to gate the function on both unix and the uds feature (using
#[cfg(all(unix, feature = "uds"))]). Apply the same fix to the other related
test function mentioned in the also applies to section around lines 399-401.
`qmux::Session::protocol` is a trait method (not inherent), and qmux isn't re-exported, so rustdoc's `-D broken-intra-doc-links` rejected the `[`...`]` link in the tcp module doc. Make it plain inline code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Why
We want to run localhost (and trusted same-host / private-VPC) workers against the relay over qmux without paying for TLS and UDP. They should be treated as fully privileged (
internal), with no JWT or certificate ceremony.This adds dedicated, opt-in listeners for exactly that. They're isolated from the public QUIC/HTTPS paths, so the privilege can't leak: the only thing that grants unrestricted access is connecting to one of these sockets.
What changed
Relay (
rs/moq-relay)[internal]config with two independent, opt-in listeners:[internal.tcp] listen = "host:port"→ plain-TCP qmux (tcp://), flag--internal-listen/MOQ_INTERNAL_LISTEN.[internal.uds] listen = "/path"→ Unix-socket qmux (unix://), flag--internal-uds-listen/MOQ_INTERNAL_UDS_LISTEN.AuthToken::unrestricted("")on the internal tier (full publish/subscribe under the empty root) — the local-worker analogue of an mTLS cluster peer dialing/.[internal.uds.allow]withuid/gid/pidlists, checked against kernel-reported peer credentials (SO_PEERCRED/LOCAL_PEERCRED) at accept. Empty = no check; AND across fields, OR within a field; a requiredpidfails closed if the platform doesn't report one. This is how you restrict access to a specific worker user rather than any local process (loopback TCP can't do that). The allowlist lives inside[internal.uds]because it's Unix-only.moq-native (
rs/moq-native)tcp://andunix://schemes (qmux directly over a raw stream — no TLS, no WebSocket framing) with clientconnect+ serverListeners. The UnixListenersurfacesPeerCredand sets socket perms.defaultfeatures and drop out of--no-default-features(wasm) builds.udsis unix-only.qmux 0.0.8 → 0.2.0 (breaking dep bump)
ws::Bare→ws::Upgraded.qmux::PREFIXESwas removed; the WebSocket subprotocol builders now reconstruct the{prefix}{alpn}cross-product fromqmux::Version::prefix(). The existing WS negotiation regression test was updated and still passes.Docs
doc/bin/relay/auth.md(new "Internal Listener" section) anddoc/bin/relay/config.md([internal.tcp]/[internal.uds]).Reviewer notes
moq_native::{tcp, unix}modules (Listener,PeerCred,Error) andmoq_relay::{InternalConfig, InternalTcp, InternalUds, InternalAllow, run_internal}. No existing public signatures changed; qmux is not re-exported, so its major bump isn't a breaking change to moq-native's surface. Hence targetingmain.allowpeercred check. Root on the host can always bypass either (it can read the socket / ptrace the worker) — the threat model is other non-root users on a shared host.tcp:///unix://are native-only (browsers can't open raw TCP/Unix sockets); the JS client is unaffected.moq-clidoesn't yet expose thetcp/udsfeatures, so themoq publish tcp://…doc examples assume a CLI built with them. Happy to add that wiring in a follow-up if wanted.Test plan
cargo check --workspace --all-targets(qmux 0.2 bump clean across all crates)cargo fmt --check+clippy -D warnings(moq-native, moq-relay)internal_tcp_round_tripandinternal_unix_round_tripround-trip a frame end-to-end and assert the newest moq-lite version is negotiated in-bandmoq-native --no-default-features(wasm-style) build is clean with tcp/uds compiled out🤖 Generated with Claude Code
(Written by Claude)