feat(proxy): per-proxy status hosts + HTTPS interstitial permit-gate - #4050
Merged
0pcom merged 1 commit intoAug 21, 2026
Merged
Conversation
Two related features on the embedded-web-proxy surface. 1. Interstitial over HTTPS. The branded route interstitial's TLS-MITM path attempted a leaf mint for every TLS-port dial failure, including clearnet HTTPS a name-constrained CA can never cover — producing a "host does not match permitted suffix" error on every such request. Add skynetca.Permits (non-breaking optional HostPermitter interface) and gate the HTTPS-interstitial mint on it, so .skynet/.dmsg targets reliably render the interstitial over TLS while clearnet HTTPS falls through cleanly to the real error. The page gains a footer deep-link to the surface's status host. 2. Per-proxy status hosts. Each proxy serves a read-only diagnostic page at a reserved host through itself — status.dmsg (dmsg_web), status.skynet (skynet_web), status.skysocks (skysocks-client) — mirroring the in-process home.<suffix> host. New pkg/proxystatus owns the surface taxonomy, host matcher, in-process HTTP responder, the read-only Snapshot/Provider contract and HTML renderer; the visor implements Provider on existing read APIs (LogsSince for logging, RouteGroupMuxInfo for the per-leg mux view, ProcByName for running). Both resolving proxies intercept the status hosts before suffix resolution / upstream forwarding, so any surface is reachable through either proxy. status.skysocks is the full MVP (logs + live mux view); the others share the page. Route/transport events and route CONTROL are explicit, marked extension seams (disabled control section, additive Provider/Snapshot shape).
0pcom
added a commit
that referenced
this pull request
Aug 21, 2026
…ntrast (#4053) Two follow-ups to the per-proxy status pages (#4050). HTTPS without a cert warning. proxystatus was HTTP-only (in-process SOCKS splice) at bare hosts, so https://status.skysocks/ needed the self-signed skynetca CA installed. Serve the same pages through the browse-origin listener (pkg/visor/meshproxy.go), which already terminates TLS with the deployment's real wildcard cert under BrowseOrigin.Suffix — reached at a single-label host (status-<surface>.<suffix>, e.g. status-skysocks.haltingstate.net) that a single-level wildcard covers, so https:// loads clean with no CA install. meshStatusHandler intercepts these hosts on the browse-origin mux (subdomain and port modes) before the reverse proxy; every other host falls through. The plain-HTTP SOCKS path remains the fallback when browse-origin is disabled/unconfigured. Contrast. The dark status page's muted grey (#7a80a8) and the light block's greys were near/below WCAG AA. Raise --muted (dark #a2a8cc ~8:1, light #4a4f63) and darken the light-mode status colors (--ok/--warn/--standby, whose dark brights are illegible on white) plus the near-white h2/surface, so every text token clears 4.5:1 in both schemes. Accent gradient / identity unchanged. Locked by a WCAG contrast unit test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two related features on the embedded-web-proxy surface (
dmsg_web,skynet_web, and theskysocks-clienttunnel they chain to). Design + first working increment; read-only MVP with explicit seams for route control. Seedocs/proxy-status-and-interstitial.md.1. Interstitial over HTTPS
The branded "building a route over the mesh…" interstitial (
pkg/proxyinterstitial) rides a locally-terminated TLS session (TLS MITM) for HTTPS targets, since a raw-TLS tunnel can't carry an HTML page. TLS termination uses a name-constrained local CA (pkg/skynetca) that can only mint leaves for.skynet/.dmsg.The live bug: the HTTPS-interstitial path attempted a mint for every TLS-port dial failure — including clearnet HTTPS forwarded to the upstream
skysocks-client, which the CA can never cover — producing ahost does not match permitted suffixerror on every such request.Fix:
skynetca.Permits(minter, host)— a non-breaking optional interface (HostPermitter, implemented byCachedMinter) that reports whether the CA can cover a host without minting. Both resolving proxies now gate the HTTPS-interstitial mint on it:.skynet/.dmsgHTTPS → interstitial renders over TLS as intended;The interstitial page also gained a footer deep-link to the surface's status host.
2. Per-proxy status hosts
Each proxy serves a read-only diagnostic page at a reserved, well-known host through itself, mirroring the existing in-process
home.<suffix>host:http://status.dmsg/dmsgwebhttp://status.skynet/skynetwebhttp://status.skysocks/skysocks-clientNew
pkg/proxystatusowns the surface taxonomy, host matcher (Match), the in-process HTTP responder (ServeConn, same net.Pipe trick asserveHomeInProcess), the read-onlySnapshot/Providercontract, and the HTML renderer. Both resolving proxies'Dialcallbacks checkMatch(host)before suffix resolution / upstream forwarding, so any of the three hosts is reachable through either proxy.The visor implements
proxystatus.Provider(pkg/visor/embedded_proxystatus.go) entirely on existing read APIs:LogsSince(app)tails the app's log store;RouteGroupMuxInfo(app)gives the same per-leg bandwidth/RTT/retransmit telemetrycli proxy mux plotrenders, drawn as a per-leg bandwidth-share table (meta-refreshes to stay live);procManager.ProcByName(app).Implemented vs. scaffolded
status.skysocks— full MVP: logs + live per-leg mux view of the route group where multiplexing actually happens.status.dmsg/status.skynet— share the identical page; mux section is empty until their route group is tagged forRouteGroupMuxInfo.Extension seam: route control
MVP is deliberately read-only. The page renders a disabled "route control" section, and
Snapshot/Providerare shaped so control lands additively: add a mutating method toproxystatus.Provider, implement it on the existing visor mux-reshape API (AddMuxRoute/RemoveMuxRoute/SetMuxMode) + dmsg relay selection. No wire reshape, no new proxy plumbing. Interception inskysocks-clientfor the browser-points-directly-at-:1080 case is a noted future seam.Scope / testing
Contained to the embedded-web-proxy packages +
pkg/skynetca(the permit helper) + a small visor status provider;pkg/router/policy untouched.go build .,go vet,make formatclean. New unit tests forpkg/proxystatus(Match/Render/ServeConn),skynetca.Permits, and the interstitial status footer.