You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
derphttp,magicsock,netcheck: add TLSConfigBypassesTLSDial opt-in flag
Today derphttp.Client.tlsConfig always passes the caller-supplied
TLSConfig through tlsdial.Config, which wraps it with a VerifyConnection
hook that runs system-root verification with a baked-in Let's Encrypt
fallback. tlsdial.Config also panics on base configs that already set
InsecureSkipVerify or VerifyConnection.
That contract works well when DERP is reachable directly over a publicly
trusted PKI, but it breaks for callers who legitimately need to perform
their own server verification — for example when DERP is fronted by a
reverse proxy that presents a non-publicly-trusted certificate, or when
authenticating with an mTLS framework that uses custom CAs / SPIFFE-style
identity / app-name verification (i.e. the standard Go pattern of
InsecureSkipVerify=true paired with a custom VerifyPeerCertificate).
This adds an opt-in TLSConfigBypassesTLSDial bool. When true (and
TLSConfig is non-nil), the supplied config is used as-is after a Clone +
ServerName fallback. tlsdial.Config is bypassed entirely. node-level
InsecureForTests is still honored; node.CertName (a tlsdial-specific
domain-fronting hook) is intentionally ignored on the bypass path —
callers bringing their own verifier are expected to encode any cert
pinning in their own VerifyPeerCertificate / VerifyConnection. The doc
comment explicitly warns that with bypass=true the supplied TLSConfig is
the sole source of server verification.
Plumbing:
- derphttp.Client.TLSConfigBypassesTLSDial bool.
- magicsock.Conn stores the (TLSConfig, bypass) pair as a single
atomic.Pointer[derpTLSPair] so reconnects observe a coherent pair.
Existing SetDERPTLSConfig(cfg) remains the default path and stores
(cfg, false); new SetDERPTLSConfigWithBypass(cfg, bypass) stores the
pair together for callers that need the bypass path.
- magicsock/derp.go reads the pair atomically and propagates both onto
the constructed derphttp.Client.
- netcheck.Client gains DERPTLSConfigBypassesTLSDial alongside the
existing DERPTLSConfig field, propagated to the netcheck DERP probe
client so health checks / `coder netcheck` don't panic when
DERPTLSConfig is a custom-verifier config.
Backward compatible: bypass=false (the default) preserves the existing
behavior and existing callers see no change. Existing SetDERPTLSConfig(cfg)
callers continue to work; their effective bypass state is false.
Test coverage:
- derp/derphttp/derphttp_test.go: TestTLSConfigBypassesTLSDial covers
the default path, the bypass path, ServerName behavior, the nil-config
fallback, and node.InsecureForTests under bypass.
- wgengine/magicsock/derp_tls_pair_test.go: TestSetDERPTLSConfigPair
covers the legacy setter, the combined setter, and a -race-friendly
concurrent writers/readers test that verifies the (cfg, bypass)
atomic-pair invariant.
0 commit comments