@@ -26,6 +26,10 @@ var defaultNameservers = []string{
2626// recursiveNameservers are used to pre-check DNS propagation.
2727var recursiveNameservers = getNameservers (defaultResolvConf , defaultNameservers )
2828
29+ // networkStack is used to define which IP stack will be used. The default is
30+ // both IPv4 and IPv6. Set to "ipv4" for IPv4 only, and "ipv6" for IPv6 only.
31+ var networkStack = "both"
32+
2933// soaCacheEntry holds a cached SOA record (only selected fields).
3034type soaCacheEntry struct {
3135 zone string // zone apex (a domain name)
@@ -67,6 +71,16 @@ func AddRecursiveNameservers(nameservers []string) ChallengeOption {
6771 }
6872}
6973
74+ // SetNetworkStack defines the IP stack that will be used for DNS queries.
75+ // Accepts "both", "ipv4", or "ipv6".
76+ func SetNetworkStack (network string ) {
77+ if network == "ipv4" || network == "ipv6" {
78+ networkStack = network
79+ } else {
80+ networkStack = "both"
81+ }
82+ }
83+
7084// getNameservers attempts to get systems nameservers before falling back to the defaults.
7185func getNameservers (path string , defaults []string ) []string {
7286 config , err := dns .ClientConfigFromFile (path )
@@ -249,12 +263,30 @@ func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
249263 return m
250264}
251265
266+ // getNetwork interprets the networkStack setting in relation to the desired
267+ // protocol. The proto value should be either "udp" or "tcp".
268+ func getNetwork (proto string ) string {
269+ // The dns client passes whatever value is set in [dns.Client.Net] to
270+ // the [net.Dialer] (https://github.com/miekg/dns/blob/fe20d5d/client.go#L119-L141).
271+ // And the [net.Dialer] accepts strings such as "udp4" or "tcp6"
272+ // (https://cs.opensource.google/go/go/+/refs/tags/go1.18.9:src/net/dial.go;l=167-182).
273+ if networkStack == "ipv4" {
274+ return proto + "4"
275+ }
276+ if networkStack == "ipv6" {
277+ return proto + "6"
278+ }
279+ return proto
280+ }
281+
252282func sendDNSQuery (m * dns.Msg , ns string ) (* dns.Msg , error ) {
253- udp := & dns.Client {Net : "udp" , Timeout : dnsTimeout }
283+ network := getNetwork ("udp" )
284+ udp := & dns.Client {Net : network , Timeout : dnsTimeout }
254285 in , _ , err := udp .Exchange (m , ns )
255286
287+ network = getNetwork ("tcp" )
256288 if in != nil && in .Truncated {
257- tcp := & dns.Client {Net : "tcp" , Timeout : dnsTimeout }
289+ tcp := & dns.Client {Net : network , Timeout : dnsTimeout }
258290 // If the TCP request succeeds, the err will reset to nil
259291 in , _ , err = tcp .Exchange (m , ns )
260292 }
0 commit comments