@@ -2,14 +2,133 @@ package dns01
2
2
3
3
import (
4
4
"errors"
5
+ "net"
5
6
"sort"
7
+ "sync"
6
8
"testing"
7
9
8
10
"github.com/miekg/dns"
9
11
"github.com/stretchr/testify/assert"
10
12
"github.com/stretchr/testify/require"
11
13
)
12
14
15
+ func testDNSHandler (writer dns.ResponseWriter , reply * dns.Msg ) {
16
+ msg := dns.Msg {}
17
+ msg .SetReply (reply )
18
+
19
+ if reply .Question [0 ].Qtype == dns .TypeA {
20
+ msg .Authoritative = true
21
+ domain := msg .Question [0 ].Name
22
+ msg .Answer = append (
23
+ msg .Answer ,
24
+ & dns.A {
25
+ Hdr : dns.RR_Header {
26
+ Name : domain ,
27
+ Rrtype : dns .TypeA ,
28
+ Class : dns .ClassINET ,
29
+ Ttl : 60 ,
30
+ },
31
+ A : net .IPv4 (127 , 0 , 0 , 1 ),
32
+ },
33
+ )
34
+ }
35
+
36
+ _ = writer .WriteMsg (& msg )
37
+ }
38
+
39
+ // getTestNameserver constructs a new DNS server on a local address, or set
40
+ // of addresses, that responds to an `A` query for `example.com`.
41
+ func getTestNameserver (t * testing.T , network string ) * dns.Server {
42
+ t .Helper ()
43
+ server := & dns.Server {
44
+ Handler : dns .HandlerFunc (testDNSHandler ),
45
+ Net : network ,
46
+ }
47
+ switch network {
48
+ case "tcp" , "udp" :
49
+ server .Addr = "0.0.0.0:0"
50
+ case "tcp4" , "udp4" :
51
+ server .Addr = "127.0.0.1:0"
52
+ case "tcp6" , "udp6" :
53
+ server .Addr = "[::1]:0"
54
+ }
55
+
56
+ waitLock := sync.Mutex {}
57
+ waitLock .Lock ()
58
+ server .NotifyStartedFunc = waitLock .Unlock
59
+
60
+ go func () { _ = server .ListenAndServe () }()
61
+
62
+ waitLock .Lock ()
63
+ return server
64
+ }
65
+
66
+ func startTestNameserver (t * testing.T , stack networkStack , proto string ) (shutdown func (), addr string ) {
67
+ t .Helper ()
68
+ currentNetworkStack = stack
69
+ srv := getTestNameserver (t , currentNetworkStack .Network (proto ))
70
+
71
+ shutdown = func () { _ = srv .Shutdown () }
72
+ if proto == "tcp" {
73
+ addr = srv .Listener .Addr ().String ()
74
+ } else {
75
+ addr = srv .PacketConn .LocalAddr ().String ()
76
+ }
77
+ return
78
+ }
79
+
80
+ func TestSendDNSQuery (t * testing.T ) {
81
+ currentNameservers := recursiveNameservers
82
+
83
+ t .Cleanup (func () {
84
+ recursiveNameservers = currentNameservers
85
+ currentNetworkStack = dualStack
86
+ })
87
+
88
+ t .Run ("does udp4 only" , func (t * testing.T ) {
89
+ stop , addr := startTestNameserver (t , ipv4only , "udp" )
90
+ defer stop ()
91
+
92
+ recursiveNameservers = ParseNameservers ([]string {addr })
93
+ msg := createDNSMsg ("example.com." , dns .TypeA , true )
94
+ result , queryError := sendDNSQuery (msg , addr )
95
+ require .NoError (t , queryError )
96
+ assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
97
+ })
98
+
99
+ t .Run ("does udp6 only" , func (t * testing.T ) {
100
+ stop , addr := startTestNameserver (t , ipv6only , "udp" )
101
+ defer stop ()
102
+
103
+ recursiveNameservers = ParseNameservers ([]string {addr })
104
+ msg := createDNSMsg ("example.com." , dns .TypeA , true )
105
+ result , queryError := sendDNSQuery (msg , addr )
106
+ require .NoError (t , queryError )
107
+ assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
108
+ })
109
+
110
+ t .Run ("does tcp4 and tcp6" , func (t * testing.T ) {
111
+ stop , addr := startTestNameserver (t , dualStack , "tcp" )
112
+ host , port , _ := net .SplitHostPort (addr )
113
+ defer stop ()
114
+ t .Logf ("### port: %s" , port )
115
+
116
+ addr6 := net .JoinHostPort (host , port )
117
+ recursiveNameservers = ParseNameservers ([]string {addr6 })
118
+ msg := createDNSMsg ("example.com." , dns .TypeA , true )
119
+ result , queryError := sendDNSQuery (msg , addr6 )
120
+ require .NoError (t , queryError )
121
+ assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
122
+
123
+ addr4 := net .JoinHostPort ("127.0.0.1" , port )
124
+ recursiveNameservers = ParseNameservers ([]string {addr4 })
125
+ msg = createDNSMsg ("example.com." , dns .TypeA , true )
126
+ result , queryError = sendDNSQuery (msg , addr4 )
127
+ require .NoError (t , queryError )
128
+ assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
129
+ })
130
+ }
131
+
13
132
func TestLookupNameserversOK (t * testing.T ) {
14
133
testCases := []struct {
15
134
fqdn string
@@ -125,8 +244,10 @@ var findXByFqdnTestCases = []struct {
125
244
fqdn : "mail.google.com." ,
126
245
zone : "google.com." ,
127
246
nameservers : []string {":7053" , ":8053" , ":9053" },
128
- // use only the start of the message because the port changes with each call: 127.0.0.1:XXXXX->127.0.0.1:7053.
129
- expectedError : "[fqdn=mail.google.com.] could not find the start of authority for 'mail.google.com.': DNS call error: read udp " ,
247
+ // NOTE: On Windows, net.DialContext finds a way down to the ContectEx syscall.
248
+ // There a fault is marked as "connectex", not "connect", see
249
+ // https://cs.opensource.google/go/go/+/refs/tags/go1.19.5:src/net/fd_windows.go;l=112
250
+ expectedError : "could not find the start of authority for 'mail.google.com.':" ,
130
251
},
131
252
{
132
253
desc : "no nameservers" ,
0 commit comments