Let miners reach the pool over IPv6, behind a config gate - #73
Merged
Conversation
A pool whose hostname publishes an AAAA record looks healthy over IPv6 while stratum, bound IPv4-only, refuses the connection. A miner whose client prefers AAAA -- the RFC 6724 default -- never starts mining, and unlike a browser most mining firmware has no Happy Eyeballs fallback to recover with. The failure is invisible from the pool side: a refused connection never reaches the process. listen_addr now selects the address family: "" or "0.0.0.0" -> IPv4 only, exactly as before "::" -> dual-stack, IPv6 and IPv4 both reach the pool IPv4 literal -> that IPv4 address only IPv6 literal -> that IPv6 address only "0.0.0.0" deliberately does NOT become dual-stack, even though overloading it would deliver the fix to every existing deployment for free. Installing a new binary must not change listening behaviour nobody asked it to change. Setting listen_addr = :: turns it on and the revert is one config line, no rebuild. IPV6_V6ONLY is set explicitly in both directions rather than inherited from net.ipv6.bindv6only, so the pool's listening behaviour does not depend on a host sysctl nobody records alongside the deployment. accept() now writes into a sockaddr_storage. It was a sockaddr_in, which cannot hold the sockaddr_in6 an IPv6 listener produces -- the kernel would truncate the address silently, and since the connection is still accepted nothing would ever look wrong. Three tests over real sockets, because connections made through the test helpers never go through accept() at all: an IPv6 client is accepted on a dual-stack listener, an IPv4 client still is, and 0.0.0.0 still refuses IPv6. That last one is the gate -- without it, two accepted-everywhere results would be equally consistent with the config check being ignored and every deployment silently becoming dual-stack. Mutation-checked: disabling the dual-stack branch fails the suite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
A pool whose hostname publishes an AAAA record looks healthy over IPv6 while stratum, bound IPv4-only, refuses the connection. A miner whose client prefers AAAA — the RFC 6724 default — never starts mining, and unlike a browser most mining firmware has no Happy Eyeballs fallback to recover with. It is invisible from the pool side: a refused connection never reaches the process.
listen_addrnow selects the family:0.0.0.0deliberately does not become dual-stack, even though overloading it would deliver the fix to every existing deployment for free. Installing a new binary shouldn't change listening behaviour nobody asked it to change. Setlisten_addr = ::to turn it on; the revert is one config line, no rebuild.IPV6_V6ONLYis set explicitly in both directions rather than inherited fromnet.ipv6.bindv6only, so listening behaviour doesn't depend on a host sysctl nobody records with the deployment.accept()now writes into asockaddr_storage. It was asockaddr_in, which can't hold thesockaddr_in6an IPv6 listener produces — the kernel truncates silently, and since the connection is still accepted nothing would ever look wrong.Three tests over real sockets, because connections made through the test helpers never go through
accept(): an IPv6 client is accepted on a dual-stack listener, an IPv4 client still is, and0.0.0.0still refuses IPv6. That last one is the gate — without it, two accepted-everywhere results would be equally consistent with the config check being ignored and every deployment silently becoming dual-stack. Mutation-checked: disabling the dual-stack branch fails the suite.