Skip to content

Commit a419925

Browse files
committed
Refactor based on feedback and add an initial test
1 parent ebbbbd0 commit a419925

File tree

5 files changed

+120
-30
lines changed

5 files changed

+120
-30
lines changed

challenge/dns01/nameserver.go

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,23 @@ var defaultNameservers = []string{
2626
// recursiveNameservers are used to pre-check DNS propagation.
2727
var recursiveNameservers = getNameservers(defaultResolvConf, defaultNameservers)
2828

29-
type networkStack int
29+
// NetworkStack is used to indicate which IP stack should be used for DNS
30+
// queries. Valid values are DefaultNetworkStack, IPv4Only, and IPv6Only.
31+
type NetworkStack int
3032

3133
const (
32-
defaultNetworkStack networkStack = iota
33-
ipv4Only
34-
ipv6Only
34+
// DefaultNetworkStack indicates that both IPv4 and IPv6 should be allowed.
35+
// This setting lets the OS determine which IP stack to use.
36+
DefaultNetworkStack NetworkStack = iota
37+
// IPv4Only forces DNS queries to only happen over the IPv4 stack.
38+
IPv4Only
39+
// IPv6Only forces DNS queries to only happen over the IPv6 stack.
40+
IPv6Only
3541
)
3642

3743
// currentNetworkStack is used to define which IP stack will be used. The default is
38-
// both IPv4 and IPv6. Set to ipv4Only or ipv6Only to select either version.
39-
var currentNetworkStack = defaultNetworkStack
44+
// both IPv4 and IPv6. Set to IPv4Only or IPv6Only to select either version.
45+
var currentNetworkStack = DefaultNetworkStack
4046

4147
// soaCacheEntry holds a cached SOA record (only selected fields).
4248
type soaCacheEntry struct {
@@ -80,18 +86,8 @@ func AddRecursiveNameservers(nameservers []string) ChallengeOption {
8086
}
8187

8288
// SetNetworkStack defines the IP stack that will be used for DNS queries.
83-
// Accepts "both", "ipv4", or "ipv6".
84-
func SetNetworkStack(network string) {
85-
switch network {
86-
case "ipv4":
87-
currentNetworkStack = ipv4Only
88-
89-
case "ipv6":
90-
currentNetworkStack = ipv6Only
91-
92-
default:
93-
currentNetworkStack = defaultNetworkStack
94-
}
89+
func SetNetworkStack(network NetworkStack) {
90+
currentNetworkStack = network
9591
}
9692

9793
// getNameservers attempts to get systems nameservers before falling back to the defaults.
@@ -276,17 +272,17 @@ func createDNSMsg(fqdn string, rtype uint16, recursive bool) *dns.Msg {
276272
return m
277273
}
278274

279-
// getNetwork interprets the networkStack setting in relation to the desired
275+
// getNetwork interprets the NetworkStack setting in relation to the desired
280276
// protocol. The proto value should be either "udp" or "tcp".
281277
func getNetwork(proto string) string {
282278
// The dns client passes whatever value is set in [dns.Client.Net] to
283279
// the [net.Dialer] (https://github.com/miekg/dns/blob/fe20d5d/client.go#L119-L141).
284280
// And the [net.Dialer] accepts strings such as "udp4" or "tcp6"
285281
// (https://cs.opensource.google/go/go/+/refs/tags/go1.18.9:src/net/dial.go;l=167-182).
286-
if currentNetworkStack == ipv4Only {
282+
if currentNetworkStack == IPv4Only {
287283
return proto + "4"
288284
}
289-
if currentNetworkStack == ipv6Only {
285+
if currentNetworkStack == IPv6Only {
290286
return proto + "6"
291287
}
292288
return proto

challenge/dns01/nameserver_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,99 @@
11
package dns01
22

33
import (
4+
getport "github.com/jsumners/go-getport"
5+
"github.com/miekg/dns"
6+
"net"
47
"sort"
8+
"sync"
59
"testing"
610

711
"github.com/stretchr/testify/assert"
812
"github.com/stretchr/testify/require"
913
)
1014

15+
type testDnsHandler struct{}
16+
17+
func (handler *testDnsHandler) ServeDNS(writer dns.ResponseWriter, reply *dns.Msg) {
18+
msg := dns.Msg{}
19+
msg.SetReply(reply)
20+
21+
switch reply.Question[0].Qtype {
22+
case dns.TypeA:
23+
msg.Authoritative = true
24+
domain := msg.Question[0].Name
25+
msg.Answer = append(
26+
msg.Answer,
27+
&dns.A{
28+
Hdr: dns.RR_Header{
29+
Name: domain,
30+
Rrtype: dns.TypeA,
31+
Class: dns.ClassINET,
32+
Ttl: 60,
33+
},
34+
A: net.ParseIP("127.0.0.1"),
35+
},
36+
)
37+
}
38+
39+
writer.WriteMsg(&msg)
40+
}
41+
42+
func getTestNameserver(t *testing.T, network string) *dns.Server {
43+
server := &dns.Server{
44+
Handler: new(testDnsHandler),
45+
Net: network,
46+
}
47+
48+
var protocol getport.Protocol
49+
switch network {
50+
case "tcp":
51+
protocol = getport.TCP
52+
case "tcp4":
53+
protocol = getport.TCP4
54+
case "tcp6":
55+
protocol = getport.TCP6
56+
case "udp":
57+
protocol = getport.UDP
58+
case "udp4":
59+
protocol = getport.UDP4
60+
case "udp6":
61+
protocol = getport.UDP6
62+
}
63+
portResult, portError := getport.GetPort(protocol, "127.0.0.1")
64+
if portError != nil {
65+
t.Error(portError)
66+
return server
67+
}
68+
server.Addr = getport.PortResultToAddress(portResult)
69+
70+
waitLock := sync.Mutex{}
71+
waitLock.Lock()
72+
server.NotifyStartedFunc = waitLock.Unlock
73+
74+
fin := make(chan error, 1)
75+
go func() {
76+
fin <- server.ListenAndServe()
77+
}()
78+
79+
waitLock.Lock()
80+
return server
81+
}
82+
83+
func TestSendDNSQuery(t *testing.T) {
84+
t.Run("does udp4 only", func(t *testing.T) {
85+
SetNetworkStack(IPv4Only)
86+
nameserver := getTestNameserver(t, getNetwork("udp"))
87+
defer nameserver.Shutdown()
88+
89+
recursiveNameservers = ParseNameservers([]string{nameserver.Addr})
90+
msg := createDNSMsg("example.com.", dns.TypeA, true)
91+
result, queryError := sendDNSQuery(msg, nameserver.Addr)
92+
assert.NoError(t, queryError)
93+
assert.Equal(t, result.Answer[0].(*dns.A).A.String(), "127.0.0.1")
94+
})
95+
}
96+
1197
func TestLookupNameserversOK(t *testing.T) {
1298
testCases := []struct {
1399
fqdn string

cmd/setup_challenges.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,13 @@ func setupDNS(ctx *cli.Context, client *lego.Client) {
115115
case ctx.IsSet("ipv4only") && ctx.IsSet("ipv6only"):
116116
// If both flags are set then it's as good as not providing either flag,
117117
// so we default to the OS choice.
118-
dns01.SetNetworkStack("both")
118+
dns01.SetNetworkStack(dns01.DefaultNetworkStack)
119119

120120
case ctx.IsSet("ipv4only"):
121-
dns01.SetNetworkStack("ipv4")
121+
dns01.SetNetworkStack(dns01.IPv4Only)
122122

123123
case ctx.IsSet("ipv6only"):
124-
dns01.SetNetworkStack("ipv6")
124+
dns01.SetNetworkStack(dns01.IPv6Only)
125125
}
126126

127127
servers := ctx.StringSlice("dns.resolvers")

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ require (
5151
github.com/sacloud/iaas-api-go v1.3.2
5252
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9
5353
github.com/softlayer/softlayer-go v1.0.6
54-
github.com/stretchr/testify v1.8.0
54+
github.com/stretchr/testify v1.8.1
5555
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490
5656
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490
5757
github.com/transip/gotransip/v6 v6.17.0
@@ -71,6 +71,8 @@ require (
7171
software.sslmate.com/src/go-pkcs12 v0.2.0
7272
)
7373

74+
require github.com/jsumners/go-getport v1.0.0
75+
7476
require (
7577
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
7678
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
@@ -117,8 +119,8 @@ require (
117119
github.com/smartystreets/assertions v1.0.1 // indirect
118120
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
119121
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
120-
github.com/spf13/cast v1.3.1 // indirect
121-
github.com/stretchr/objx v0.4.0 // indirect
122+
github.com/spf13/cast v1.5.0 // indirect
123+
github.com/stretchr/objx v0.5.0 // indirect
122124
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
123125
go.opencensus.io v0.22.3 // indirect
124126
go.uber.org/ratelimit v0.2.0 // indirect

go.sum

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
132132
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
133133
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
134134
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
135+
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
135136
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
136137
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
137138
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
@@ -308,6 +309,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
308309
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
309310
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
310311
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
312+
github.com/jsumners/go-getport v1.0.0 h1:d11eDaP25dKKoJRAFeBrchCayceft735pDSTFCEdkb4=
313+
github.com/jsumners/go-getport v1.0.0/go.mod h1:KpeJgwNSkpuXuoGhJ2Hgl5QJqWbLG1m0jY2rQsYUTIE=
311314
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
312315
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
313316
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
@@ -515,8 +518,9 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
515518
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
516519
github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
517520
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
518-
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
519521
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
522+
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
523+
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
520524
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
521525
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
522526
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@@ -526,17 +530,19 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
526530
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
527531
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
528532
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
529-
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
530533
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
534+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
535+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
531536
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
532537
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
533538
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
534539
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
535540
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
536541
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
537542
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
538-
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
539543
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
544+
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
545+
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
540546
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
541547
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 h1:mmz27tVi2r70JYnm5y0Zk8w0Qzsx+vfUw3oqSyrEfP8=
542548
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=

0 commit comments

Comments
 (0)