11package  dns01
22
33import  (
4+ 	"net" 
45	"sort" 
6+ 	"sync" 
57	"testing" 
68
9+ 	"github.com/miekg/dns" 
710	"github.com/stretchr/testify/assert" 
811	"github.com/stretchr/testify/require" 
912)
1013
14+ func  testDNSHandler (writer  dns.ResponseWriter , reply  * dns.Msg ) {
15+ 	msg  :=  dns.Msg {}
16+ 	msg .SetReply (reply )
17+ 
18+ 	if  reply .Question [0 ].Qtype  ==  dns .TypeA  {
19+ 		msg .Authoritative  =  true 
20+ 		domain  :=  msg .Question [0 ].Name 
21+ 		msg .Answer  =  append (
22+ 			msg .Answer ,
23+ 			& dns.A {
24+ 				Hdr : dns.RR_Header {
25+ 					Name :   domain ,
26+ 					Rrtype : dns .TypeA ,
27+ 					Class :  dns .ClassINET ,
28+ 					Ttl :    60 ,
29+ 				},
30+ 				A : net .IPv4 (127 , 0 , 0 , 1 ),
31+ 			},
32+ 		)
33+ 	}
34+ 
35+ 	_  =  writer .WriteMsg (& msg )
36+ }
37+ 
38+ // getTestNameserver constructs a new DNS server on a local address, or set 
39+ // of addresses, that responds to an `A` query for `example.com`. 
40+ func  getTestNameserver (t  * testing.T , network  string ) * dns.Server  {
41+ 	t .Helper ()
42+ 	server  :=  & dns.Server {
43+ 		Handler : dns .HandlerFunc (testDNSHandler ),
44+ 		Net :     network ,
45+ 	}
46+ 	switch  network  {
47+ 	case  "tcp" , "udp" :
48+ 		server .Addr  =  "0.0.0.0:0" 
49+ 	case  "tcp4" , "udp4" :
50+ 		server .Addr  =  "127.0.0.1:0" 
51+ 	case  "tcp6" , "udp6" :
52+ 		server .Addr  =  "[::1]:0" 
53+ 	}
54+ 
55+ 	waitLock  :=  sync.Mutex {}
56+ 	waitLock .Lock ()
57+ 	server .NotifyStartedFunc  =  waitLock .Unlock 
58+ 
59+ 	go  func () { _  =  server .ListenAndServe () }()
60+ 
61+ 	waitLock .Lock ()
62+ 	return  server 
63+ }
64+ 
65+ func  startTestNameserver (t  * testing.T , stack  networkStack , proto  string ) (shutdown  func (), addr  string ) {
66+ 	t .Helper ()
67+ 	currentNetworkStack  =  stack 
68+ 	srv  :=  getTestNameserver (t , currentNetworkStack .Network (proto ))
69+ 
70+ 	shutdown  =  func () { _  =  srv .Shutdown () }
71+ 	if  proto  ==  "tcp"  {
72+ 		addr  =  srv .Listener .Addr ().String ()
73+ 	} else  {
74+ 		addr  =  srv .PacketConn .LocalAddr ().String ()
75+ 	}
76+ 	return 
77+ }
78+ 
79+ func  TestSendDNSQuery (t  * testing.T ) {
80+ 	currentNameservers  :=  recursiveNameservers 
81+ 
82+ 	t .Cleanup (func () {
83+ 		recursiveNameservers  =  currentNameservers 
84+ 		currentNetworkStack  =  dualStack 
85+ 	})
86+ 
87+ 	t .Run ("does udp4 only" , func (t  * testing.T ) {
88+ 		stop , addr  :=  startTestNameserver (t , ipv4only , "udp" )
89+ 		defer  stop ()
90+ 
91+ 		recursiveNameservers  =  ParseNameservers ([]string {addr })
92+ 		msg  :=  createDNSMsg ("example.com." , dns .TypeA , true )
93+ 		result , queryError  :=  sendDNSQuery (msg , addr )
94+ 		require .NoError (t , queryError )
95+ 		assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
96+ 	})
97+ 
98+ 	t .Run ("does udp6 only" , func (t  * testing.T ) {
99+ 		stop , addr  :=  startTestNameserver (t , ipv6only , "udp" )
100+ 		defer  stop ()
101+ 
102+ 		recursiveNameservers  =  ParseNameservers ([]string {addr })
103+ 		msg  :=  createDNSMsg ("example.com." , dns .TypeA , true )
104+ 		result , queryError  :=  sendDNSQuery (msg , addr )
105+ 		require .NoError (t , queryError )
106+ 		assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
107+ 	})
108+ 
109+ 	t .Run ("does tcp4 and tcp6" , func (t  * testing.T ) {
110+ 		stop , addr  :=  startTestNameserver (t , dualStack , "tcp" )
111+ 		host , port , _  :=  net .SplitHostPort (addr )
112+ 		defer  stop ()
113+ 		t .Logf ("### port: %s" , port )
114+ 
115+ 		addr6  :=  net .JoinHostPort (host , port )
116+ 		recursiveNameservers  =  ParseNameservers ([]string {addr6 })
117+ 		msg  :=  createDNSMsg ("example.com." , dns .TypeA , true )
118+ 		result , queryError  :=  sendDNSQuery (msg , addr6 )
119+ 		require .NoError (t , queryError )
120+ 		assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
121+ 
122+ 		addr4  :=  net .JoinHostPort ("127.0.0.1" , port )
123+ 		recursiveNameservers  =  ParseNameservers ([]string {addr4 })
124+ 		msg  =  createDNSMsg ("example.com." , dns .TypeA , true )
125+ 		result , queryError  =  sendDNSQuery (msg , addr4 )
126+ 		require .NoError (t , queryError )
127+ 		assert .Equal (t , result .Answer [0 ].(* dns.A ).A .String (), "127.0.0.1" )
128+ 	})
129+ }
130+ 
11131func  TestLookupNameserversOK (t  * testing.T ) {
12132	testCases  :=  []struct  {
13133		fqdn  string 
@@ -74,7 +194,7 @@ var findXByFqdnTestCases = []struct {
74194	zone           string 
75195	primaryNs      string 
76196	nameservers    []string 
77- 	expectedError  string 
197+ 	expectedError  string   // regular expression 
78198}{
79199	{
80200		desc :        "domain is a CNAME" ,
@@ -109,7 +229,7 @@ var findXByFqdnTestCases = []struct {
109229		fqdn :          "test.lego.zz." ,
110230		zone :          "lego.zz." ,
111231		nameservers :   []string {"8.8.8.8:53" },
112- 		expectedError : " could not find the start of authority for test.lego.zz.: NXDOMAIN" 
232+ 		expectedError : `^ could not find the start of authority for test\ .lego\ .zz.: NXDOMAIN` 
113233	},
114234	{
115235		desc :        "several non existent nameservers" ,
@@ -119,18 +239,21 @@ var findXByFqdnTestCases = []struct {
119239		nameservers : []string {":7053" , ":8053" , "8.8.8.8:53" },
120240	},
121241	{
122- 		desc :          "only non-existent nameservers" ,
123- 		fqdn :          "mail.google.com." ,
124- 		zone :          "google.com." ,
125- 		nameservers :   []string {":7053" , ":8053" , ":9053" },
126- 		expectedError : "could not find the start of authority for mail.google.com.: read udp" ,
242+ 		desc :        "only non-existent nameservers" ,
243+ 		fqdn :        "mail.google.com." ,
244+ 		zone :        "google.com." ,
245+ 		nameservers : []string {":7053" , ":8053" , ":9053" },
246+ 		// NOTE: On Windows, net.DialContext finds a way down to the ContectEx syscall. 
247+ 		// There a fault is marked as "connectex", not "connect", see 
248+ 		// https://cs.opensource.google/go/go/+/refs/tags/go1.19.5:src/net/fd_windows.go;l=112 
249+ 		expectedError : `^could not find the start of authority for mail\.google\.com.: dial tcp :9053: connect(ex)?:` ,
127250	},
128251	{
129252		desc :          "no nameservers" ,
130253		fqdn :          "test.ldez.com." ,
131254		zone :          "ldez.com." ,
132255		nameservers :   []string {},
133- 		expectedError : " could not find the start of authority for test.ldez.com." 
256+ 		expectedError : `^ could not find the start of authority for test\ .ldez\ .com\.` 
134257	},
135258}
136259
@@ -142,7 +265,7 @@ func TestFindZoneByFqdnCustom(t *testing.T) {
142265			zone , err  :=  FindZoneByFqdnCustom (test .fqdn , test .nameservers )
143266			if  test .expectedError  !=  ""  {
144267				require .Error (t , err )
145- 				assert .Contains (t , err .Error (),  test . expectedError )
268+ 				assert .Regexp (t , test . expectedError ,  err .Error ())
146269			} else  {
147270				require .NoError (t , err )
148271				assert .Equal (t , test .zone , zone )
@@ -159,7 +282,7 @@ func TestFindPrimaryNsByFqdnCustom(t *testing.T) {
159282			ns , err  :=  FindPrimaryNsByFqdnCustom (test .fqdn , test .nameservers )
160283			if  test .expectedError  !=  ""  {
161284				require .Error (t , err )
162- 				assert .Contains (t , err .Error (),  test . expectedError )
285+ 				assert .Regexp (t , test . expectedError ,  err .Error ())
163286			} else  {
164287				require .NoError (t , err )
165288				assert .Equal (t , test .primaryNs , ns )
0 commit comments