Skip to content

Commit 03db674

Browse files
committed
Add network selection for dns01
1 parent 0122506 commit 03db674

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

challenge/dns01/nameserver.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ var defaultNameservers = []string{
2626
// recursiveNameservers are used to pre-check DNS propagation.
2727
var 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).
3034
type 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.
7185
func 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+
252282
func 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
}

cmd/flags.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ import (
88

99
func CreateFlags(defaultPath string) []cli.Flag {
1010
return []cli.Flag{
11+
&cli.BoolFlag{
12+
Name: "ipv4only",
13+
Aliases: []string{"4"},
14+
Usage: "Use IPv4 only. This flag is ignored if ipv6only is also specified.",
15+
},
16+
&cli.BoolFlag{
17+
Name: "ipv6only",
18+
Aliases: []string{"6"},
19+
Usage: "Use IPv6 only. This flag is ignored if ipv4only is also specified.",
20+
},
1121
&cli.StringSliceFlag{
1222
Name: "domains",
1323
Aliases: []string{"d"},

cmd/setup_challenges.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ func setupDNS(ctx *cli.Context, client *lego.Client) {
111111
log.Fatal(err)
112112
}
113113

114+
if ctx.IsSet("ipv4only") && ctx.IsSet("ipv6only") {
115+
// If both flags are set then it's as good as not providing either flag,
116+
// so we default to the OS choice.
117+
dns01.SetNetworkStack("both")
118+
} else if ctx.IsSet("ipv4only") {
119+
dns01.SetNetworkStack("ipv4")
120+
} else if ctx.IsSet("ipv6only") {
121+
dns01.SetNetworkStack("ipv6")
122+
}
123+
114124
servers := ctx.StringSlice("dns.resolvers")
115125
err = client.Challenge.SetDNS01Provider(provider,
116126
dns01.CondOption(len(servers) > 0,

0 commit comments

Comments
 (0)