Fix SNI check failing when one IP family is undetectable#557
Merged
Conversation
runSNICheck wired each family's getIP failure through a shared context.WithCancelCause, so a single family's detection failure (for example tcp6 on an IPv4-only-egress server) made the whole check return an error even when the other family was detected and matched. Both callers treat that error as fatal, so a server that is fine on IPv4 failed the SNI check outright -- the exact audience of #529. Mirror the graceful per-family handling access.go already uses: discard the per-family getIP error and report an undetectable family through an empty OurIP4/OurIP6, which both callers already surface via their "cannot detect public IP address" branch. The error return is now reserved for genuine DNS-resolution failure. Removing the shared cancel also makes the two families independent, so a fast-failing family can no longer abort the other family's in-flight detection. Add a regression test that drives the real runSNICheck over a loopback DNS fake and an IPv4-only-egress network fake.
Collaborator
Author
|
CI note: the two red checks are pre-existing / environmental, not from this change —
Locally on the touched package: |
9seconds
approved these changes
Jun 5, 2026
Owner
|
I'll merge them now. Will make vulnerabilities verification optional in a separate PR |
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.
Follow-up to the review on #542 — the per-family error-poisoning in
runSNICheckyou OK'd fixing. Opening it as a PR into the branch so CI runs on it; merge, rework, or close as you see fit — your call on the shape, the regression test is the part that matters and it passes against any correct fix.The bug
On a dual-stack secret host (A + AAAA) running on an IPv4-only-egress server, the
tcp6getIPfails and callscancelCause(err)on the shared context, sorunSNICheckreturns a non-nil error even thoughtcp4detection succeeded and matched. Both callers treat that as fatal — a server that is actually fine on IPv4 fails the SNI check outright (the exact audience of #529).The fix
Mirror the graceful per-family handling
access.goalready uses (ip, _ = getIP(...)): discard the per-familygetIPerror and report an undetectable family through an emptyOurIP4/OurIP6. Both callers already surface that via their existingcannot detect public IP addressbranch, so:err != nil→cannot resolve DNS namebranch stays accurate);cannot detect public IP addressinstead of misreporting a DNS failure (the misleading-message point from the review, fixed for free);One deliberate trade-off: the per-family
getIPerror is dropped, so on a both-families-fail server the user no longer sees the per-service dial errors, justcannot detect public IP address. That matchesaccess.go's existing behavior and the merged 4-service error string was noisy, but flagging it in case you'd rather log it at debug.Test
internal/cli/sni_check_test.godrives the realrunSNICheck/getIPover a loopback UDP DNS fake (dual-stack) and an IPv4-only-egressmtglib.Networkfake — no network, no new deps (x/net/dns/dnsmessageis already direct). It fails on the branch as-is (cannot resolve tcp6 address …) and passes with the fix. It's the first*_test.goininternal/cliand uses plainfunc Test…+require(matching the dcprobe/network style); happy to convert to a testify suite if you prefer.Local checks green:
go test -race,go vet,go build ./...,gofmt/gofumpt,golangci-lint(repo config).