Skip to content

Accept ws and wss in X-Forwarded-Proto for the monitoring UI - #3418

Merged
jedisct1 merged 1 commit into
DNSCrypt:masterfrom
Dv2Corn:fix/monitoring-ui-forwarded-proto-ws
Nov 12, 2026
Merged

jedisct1 merged 1 commit into
DNSCrypt:masterfrom
Dv2Corn:fix/monitoring-ui-forwarded-proto-ws

Conversation

@Dv2Corn

@Dv2Corn Dv2Corn commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Since 2.1.19, the monitoring UI never gets its live connection behind a TLS-terminating reverse proxy that reports WebSocket handshakes as X-Forwarded-Proto: wss (Traefik does): every GET /api/ws is answered with 403, the log fills with WebSocket upgrade error: websocket: request origin not allowed by Upgrader.CheckOrigin, and the page falls back to polling. It can be reproduced without a proxy by sending the handshake to the UI with Host: dns.example, Origin: https://dns.example and X-Forwarded-Proto: wss.

The origin check added in b00a0fc compares the scheme of Origin with requestScheme(), which only knows http and https. Any other value falls through to r.TLS, so the request is taken for plain http and the https origin of the dashboard is refused, while Origin: http://dns.example is accepted on that same request.

ws is now read as http and wss as https. Nothing else changes: an origin is accepted exactly when it would be with the equivalent http/https value. Traefik sets these two values here.

Tested with a new table test of the origin check (the ws/wss rows fail before the change; go test and go vet pass after), and with the built proxy and a raw handshake carrying the proxy headers:

Origin X-Forwarded-Proto before after
https://dns.example https 101 101
https://dns.example wss 403 101
http://dns.example wss 101 403
https://evil.example wss 403 403

Not covered: the Forwarded header is still not read, and I did not put a real Traefik in front of it.

Discussion #3389 reports this error behind Traefik.

Some reverse proxies, such as Traefik, report WebSocket handshakes as
ws or wss. These values were ignored, so behind a TLS-terminating proxy
the scheme was assumed to be http: the origin check rejected the
https origin of the dashboard, and accepted an http one.

Map ws to http and wss to https.
@jedisct1
jedisct1 merged commit a286175 into DNSCrypt:master Nov 12, 2026
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.

2 participants