feat(nat): enable self-hosted NAT survey listeners

Merged after local full validation and production postflight. GitHub CI's 16 Linux locale assertions are pre-existing and unrelated to this infrastructure-only change; see PR comment.
This commit is contained in:
AAA authored and GitHub committed 2026-09-01 11:41:17 +08:00
1 parent a741c3233d
commit ede14d417a
5 files changed
+51 -6

No files matched your search

+8
View File
@@ -10,6 +10,14 @@ stun-only
no-tcp
no-tls
# Approved NAT survey listeners only. Keep `stun-only` enabled: these auxiliary
# endpoints are for ordinary Binding requests, not TURN media relay. Replace
# <PRIVATE_LISTEN_IP> with the host address already bound by the main listener.
# They use the same public IP and therefore measure destination-port behavior;
# full RFC 5780 behavior discovery still needs a second public IPv4.
#aux-server=<PRIVATE_LISTEN_IP>:3479
#aux-server=<PRIVATE_LISTEN_IP>:3480
# Keep automatic address selection on a single-homed public host. On a
# multi-homed host, bind only the intended public interface.
#listening-ip=<PUBLIC_LISTEN_IP>
+23
View File
@@ -73,6 +73,29 @@ Coturn runs `stun-only`, `no-tcp`, and `no-tls`. It must answer STUN binding and
reject TURN allocation. Avoid verbose STUN/ICE logging because infrastructure
necessarily observes client IP addresses.
## Temporary NAT Survey
Enable the auxiliary listeners only for an approved aggregate-only survey. Add
the following to the service-owned coturn configuration, using the local
address already bound by the main listener:
```ini
aux-server=<PRIVATE_LISTEN_IP>:3479
aux-server=<PRIVATE_LISTEN_IP>:3480
```
Keep `stun-only`, `no-tcp`, and `no-tls` unchanged. Allow UDP 3479 and 3480 in
both the cloud security group and the existing nftables input rule, validate
the complete ruleset with `nft -c -f /etc/nftables.conf`, then restart only
`coturn.service`. Verify `ss -lunp` shows all three UDP listeners and that an
ordinary STUN Binding succeeds on each; do not add these URLs to production
`STUN_URLS` or inject predicted ICE candidates. Remove the two `aux-server`
lines and firewall ports after the survey, validate again, and restart coturn.
These same-IP auxiliary ports measure destination-port mapping behavior. They
are not a full RFC 5780 alternate-address deployment; that requires a second
public IPv4.
## Operational Verification
- `/healthz` returns `{"status":"ok"}` locally and through the public origin.
+10
View File
@@ -50,6 +50,7 @@ Peer IDs, SDP, ICE candidates, tokens or media credentials.
| ---: | --- | --- |
| TCP 80/443 | public | HTTP redirect and HTTPS/WSS reverse proxy |
| UDP 3478 | public | STUN-only coturn |
| UDP 3479/3480 | temporary public during approved NAT survey | auxiliary STUN-only coturn listeners |
| UDP 7882 | public when SFU enabled | LiveKit WebRTC media |
| TCP 8787 | private | Screener application |
| TCP 7880 | private when SFU enabled | LiveKit signaling/control |
@@ -58,6 +59,15 @@ TCP 3478, TCP/TLS 5349, TURN relay ranges, LiveKit media TCP, and other media
ports remain closed. HTTPS/WSS transport is independent of the UDP-only media
contract.
The optional NAT survey uses `stun:<same-hostname>:3479` and `:3480` in a
diagnostic page only. It does not change `STUN_URLS`, ordinary Peer ICE, or any
media route, and it needs both cloud security-group rules and the host's
`/etc/nftables.conf` rule. Coturn must bind the auxiliary listeners to the
host's local address with `aux-server`; opening a cloud port without a listener
has no effect. No new DNS record is required. Same-IP ports measure destination
port allocation behavior; a full RFC 5780 alternate-address test requires a
second public IPv4.
## Bounds
- Site-access requests are rate-limited at the reverse proxy and use constant-
+5 -4
View File
@@ -23,10 +23,11 @@ This is the current execution index. Git history owns completed timelines;
- Site access uses a stateless 24-hour rolling idle cookie. An active
site-authorized page renews it hourly through the existing status request;
Viewer-grant admission remains independent and cannot create or renew it.
- Public media listeners remain STUN-only UDP 3478 and LiveKit UDP 7882. Web
ingress is TCP 80/443; Node 8787 and LiveKit control/signaling 7880 are
private. TURN, ICE/TCP, media TCP, TLS relay, port 5349, and relay ranges are
disabled.
- Public media listeners remain STUN-only UDP 3478 and LiveKit UDP 7882. During
the approved NAT survey, coturn also exposes auxiliary STUN-only UDP 3479
and 3480; ordinary `STUN_URLS` and media routes remain unchanged. Web ingress
is TCP 80/443; Node 8787 and LiveKit control/signaling 7880 are private. TURN,
ICE/TCP, media TCP, TLS relay, port 5349, and relay ranges are disabled.
- Browser video uses the content-independent H.264 sender gate with VP8
fallback, plus the locked pre-share `VP8 | Auto | H264` Host selector and
resolved codec display. Video retains `contentHint = "motion"`; audio uses
+5 -2
View File
@@ -88,8 +88,11 @@ until their stated boundary is met.
into production ICE without a new accepted decision and a measured gate. See
[Browser NAT traversal](./research/nat-traversal.md). The Browser preflight
proves only positive mapping variation and synthetic-candidate syntax; the
next executable gate requires an isolated Linux namespace runner with two
real Browser ICE agents.
isolated Linux namespace lab now covers the controlled Browser gate. A
self-hosted same-IP two/three-port endpoint is available for an approved
aggregate-only field survey; keep observations diagnostic until stable
sequential allocation is common enough to justify a new decision. Do not
inject predicted candidates yet.
15. **Unresolved route-state ownership claims.** Reopen lower-revision
reauthentication, active SFU failure during an unrelated prepare, and
multi-child relay-evidence ownership only from an exact current-wire