@@ -2,10 +2,14 @@ package bdns
2
2
3
3
import (
4
4
"context"
5
+ "crypto/tls"
6
+ "crypto/x509"
5
7
"errors"
6
8
"fmt"
9
+ "io"
7
10
"log"
8
11
"net"
12
+ "net/http"
9
13
"net/netip"
10
14
"net/url"
11
15
"os"
@@ -20,15 +24,37 @@ import (
20
24
"github.com/miekg/dns"
21
25
"github.com/prometheus/client_golang/prometheus"
22
26
23
- "github.com/letsencrypt/boulder/features"
24
27
blog "github.com/letsencrypt/boulder/log"
25
28
"github.com/letsencrypt/boulder/metrics"
26
29
"github.com/letsencrypt/boulder/test"
27
30
)
28
31
29
32
const dnsLoopbackAddr = "127.0.0.1:4053"
30
33
31
- func mockDNSQuery (w dns.ResponseWriter , r * dns.Msg ) {
34
+ func mockDNSQuery (w http.ResponseWriter , httpReq * http.Request ) {
35
+ if httpReq .Header .Get ("Content-Type" ) != "application/dns-message" {
36
+ w .WriteHeader (http .StatusBadRequest )
37
+ fmt .Fprintf (w , "client didn't send Content-Type: application/dns-message" )
38
+ }
39
+ if httpReq .Header .Get ("Accept" ) != "application/dns-message" {
40
+ w .WriteHeader (http .StatusBadRequest )
41
+ fmt .Fprintf (w , "client didn't accept Content-Type: application/dns-message" )
42
+ }
43
+
44
+ requestBody , err := io .ReadAll (httpReq .Body )
45
+ if err != nil {
46
+ w .WriteHeader (http .StatusBadRequest )
47
+ fmt .Fprintf (w , "reading body: %s" , err )
48
+ }
49
+ httpReq .Body .Close ()
50
+
51
+ r := new (dns.Msg )
52
+ err = r .Unpack (requestBody )
53
+ if err != nil {
54
+ w .WriteHeader (http .StatusBadRequest )
55
+ fmt .Fprintf (w , "unpacking request: %s" , err )
56
+ }
57
+
32
58
m := new (dns.Msg )
33
59
m .SetReply (r )
34
60
m .Compress = false
@@ -174,45 +200,37 @@ func mockDNSQuery(w dns.ResponseWriter, r *dns.Msg) {
174
200
}
175
201
}
176
202
177
- err := w .WriteMsg (m )
203
+ body , err := m .Pack ()
204
+ if err != nil {
205
+ fmt .Fprintf (os .Stderr , "packing reply: %s\n " , err )
206
+ }
207
+ w .Header ().Set ("Content-Type" , "application/dns-message" )
208
+ _ , err = w .Write (body )
178
209
if err != nil {
179
210
panic (err ) // running tests, so panic is OK
180
211
}
181
212
}
182
213
183
214
func serveLoopResolver (stopChan chan bool ) {
184
- dns .HandleFunc ("." , mockDNSQuery )
185
- tcpServer := & dns.Server {
186
- Addr : dnsLoopbackAddr ,
187
- Net : "tcp" ,
188
- ReadTimeout : time .Second ,
189
- WriteTimeout : time .Second ,
190
- }
191
- udpServer := & dns.Server {
215
+ m := http .NewServeMux ()
216
+ m .HandleFunc ("/dns-query" , mockDNSQuery )
217
+ httpServer := & http.Server {
192
218
Addr : dnsLoopbackAddr ,
193
- Net : "udp" ,
219
+ Handler : m ,
194
220
ReadTimeout : time .Second ,
195
221
WriteTimeout : time .Second ,
196
222
}
197
223
go func () {
198
- err := tcpServer .ListenAndServe ()
199
- if err != nil {
200
- fmt .Println (err )
201
- }
202
- }()
203
- go func () {
204
- err := udpServer .ListenAndServe ()
224
+ cert := "../test/certs/ipki/localhost/cert.pem"
225
+ key := "../test/certs/ipki/localhost/key.pem"
226
+ err := httpServer .ListenAndServeTLS (cert , key )
205
227
if err != nil {
206
228
fmt .Println (err )
207
229
}
208
230
}()
209
231
go func () {
210
232
<- stopChan
211
- err := tcpServer .Shutdown ()
212
- if err != nil {
213
- log .Fatal (err )
214
- }
215
- err = udpServer .Shutdown ()
233
+ err := httpServer .Shutdown (context .Background ())
216
234
if err != nil {
217
235
log .Fatal (err )
218
236
}
@@ -240,7 +258,21 @@ func pollServer() {
240
258
}
241
259
}
242
260
261
+ // tlsConfig is used for the TLS config of client instances that talk to the
262
+ // DoH server set up in TestMain.
263
+ var tlsConfig * tls.Config
264
+
243
265
func TestMain (m * testing.M ) {
266
+ root , err := os .ReadFile ("../test/certs/ipki/minica.pem" )
267
+ if err != nil {
268
+ log .Fatal (err )
269
+ }
270
+ pool := x509 .NewCertPool ()
271
+ pool .AppendCertsFromPEM (root )
272
+ tlsConfig = & tls.Config {
273
+ RootCAs : pool ,
274
+ }
275
+
244
276
stop := make (chan bool , 1 )
245
277
serveLoopResolver (stop )
246
278
pollServer ()
@@ -253,7 +285,7 @@ func TestDNSNoServers(t *testing.T) {
253
285
staticProvider , err := NewStaticProvider ([]string {})
254
286
test .AssertNotError (t , err , "Got error creating StaticProvider" )
255
287
256
- obj := New (time .Hour , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
288
+ obj := New (time .Hour , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
257
289
258
290
_ , resolvers , err := obj .LookupHost (context .Background (), "letsencrypt.org" )
259
291
test .AssertEquals (t , len (resolvers ), 0 )
@@ -270,7 +302,7 @@ func TestDNSOneServer(t *testing.T) {
270
302
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
271
303
test .AssertNotError (t , err , "Got error creating StaticProvider" )
272
304
273
- obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
305
+ obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
274
306
275
307
_ , resolvers , err := obj .LookupHost (context .Background (), "cps.letsencrypt.org" )
276
308
test .AssertEquals (t , len (resolvers ), 2 )
@@ -283,7 +315,7 @@ func TestDNSDuplicateServers(t *testing.T) {
283
315
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr , dnsLoopbackAddr })
284
316
test .AssertNotError (t , err , "Got error creating StaticProvider" )
285
317
286
- obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
318
+ obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
287
319
288
320
_ , resolvers , err := obj .LookupHost (context .Background (), "cps.letsencrypt.org" )
289
321
test .AssertEquals (t , len (resolvers ), 2 )
@@ -296,7 +328,7 @@ func TestDNSServFail(t *testing.T) {
296
328
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
297
329
test .AssertNotError (t , err , "Got error creating StaticProvider" )
298
330
299
- obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
331
+ obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
300
332
bad := "servfail.com"
301
333
302
334
_ , _ , err = obj .LookupTXT (context .Background (), bad )
@@ -314,7 +346,7 @@ func TestDNSLookupTXT(t *testing.T) {
314
346
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
315
347
test .AssertNotError (t , err , "Got error creating StaticProvider" )
316
348
317
- obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
349
+ obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
318
350
319
351
a , _ , err := obj .LookupTXT (context .Background (), "letsencrypt.org" )
320
352
t .Logf ("A: %v" , a )
@@ -332,7 +364,7 @@ func TestDNSLookupHost(t *testing.T) {
332
364
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
333
365
test .AssertNotError (t , err , "Got error creating StaticProvider" )
334
366
335
- obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
367
+ obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
336
368
337
369
ip , resolvers , err := obj .LookupHost (context .Background (), "servfail.com" )
338
370
t .Logf ("servfail.com - IP: %s, Err: %s" , ip , err )
@@ -418,7 +450,7 @@ func TestDNSNXDOMAIN(t *testing.T) {
418
450
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
419
451
test .AssertNotError (t , err , "Got error creating StaticProvider" )
420
452
421
- obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
453
+ obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
422
454
423
455
hostname := "nxdomain.letsencrypt.org"
424
456
_ , _ , err = obj .LookupHost (context .Background (), hostname )
@@ -434,7 +466,7 @@ func TestDNSLookupCAA(t *testing.T) {
434
466
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
435
467
test .AssertNotError (t , err , "Got error creating StaticProvider" )
436
468
437
- obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), nil )
469
+ obj := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 1 , "" , blog .UseMock (), tlsConfig )
438
470
removeIDExp := regexp .MustCompile (" id: [[:digit:]]+" )
439
471
440
472
caas , resp , resolvers , err := obj .LookupCAA (context .Background (), "bracewel.net" )
@@ -513,10 +545,9 @@ func (te *testExchanger) Exchange(m *dns.Msg, a string) (*dns.Msg, time.Duration
513
545
}
514
546
515
547
func TestRetry (t * testing.T ) {
516
- isTempErr := & net. OpError {Op : "read" , Err : tempError (true )}
517
- nonTempErr := & net. OpError {Op : "read" , Err : tempError (false )}
548
+ isTempErr := & url. Error {Op : "read" , Err : tempError (true )}
549
+ nonTempErr := & url. Error {Op : "read" , Err : tempError (false )}
518
550
servFailError := errors .New ("DNS problem: server failure at resolver looking up TXT for example.com" )
519
- netError := errors .New ("DNS problem: networking error looking up TXT for example.com" )
520
551
type testCase struct {
521
552
name string
522
553
maxTries int
@@ -567,7 +598,7 @@ func TestRetry(t *testing.T) {
567
598
isTempErr ,
568
599
},
569
600
},
570
- expected : netError ,
601
+ expected : servFailError ,
571
602
expectedCount : 3 ,
572
603
metricsAllRetries : 1 ,
573
604
},
@@ -620,7 +651,7 @@ func TestRetry(t *testing.T) {
620
651
isTempErr ,
621
652
},
622
653
},
623
- expected : netError ,
654
+ expected : servFailError ,
624
655
expectedCount : 3 ,
625
656
metricsAllRetries : 1 ,
626
657
},
@@ -634,7 +665,7 @@ func TestRetry(t *testing.T) {
634
665
nonTempErr ,
635
666
},
636
667
},
637
- expected : netError ,
668
+ expected : servFailError ,
638
669
expectedCount : 2 ,
639
670
},
640
671
}
@@ -644,7 +675,7 @@ func TestRetry(t *testing.T) {
644
675
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
645
676
test .AssertNotError (t , err , "Got error creating StaticProvider" )
646
677
647
- testClient := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), tc .maxTries , "" , blog .UseMock (), nil )
678
+ testClient := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), tc .maxTries , "" , blog .UseMock (), tlsConfig )
648
679
dr := testClient .(* impl )
649
680
dr .dnsClient = tc .te
650
681
_ , _ , err = dr .LookupTXT (context .Background (), "example.com" )
@@ -675,7 +706,7 @@ func TestRetry(t *testing.T) {
675
706
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
676
707
test .AssertNotError (t , err , "Got error creating StaticProvider" )
677
708
678
- testClient := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 3 , "" , blog .UseMock (), nil )
709
+ testClient := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 3 , "" , blog .UseMock (), tlsConfig )
679
710
dr := testClient .(* impl )
680
711
dr .dnsClient = & testExchanger {errs : []error {isTempErr , isTempErr , nil }}
681
712
ctx , cancel := context .WithCancel (context .Background ())
@@ -754,7 +785,7 @@ func (e *rotateFailureExchanger) Exchange(m *dns.Msg, a string) (*dns.Msg, time.
754
785
755
786
// If its a broken server, return a retryable error
756
787
if e .brokenAddresses [a ] {
757
- isTempErr := & net. OpError {Op : "read" , Err : tempError (true )}
788
+ isTempErr := & url. Error {Op : "read" , Err : tempError (true )}
758
789
return nil , 2 * time .Millisecond , isTempErr
759
790
}
760
791
@@ -776,10 +807,9 @@ func TestRotateServerOnErr(t *testing.T) {
776
807
// working server
777
808
staticProvider , err := NewStaticProvider (dnsServers )
778
809
test .AssertNotError (t , err , "Got error creating StaticProvider" )
779
- fmt .Println (staticProvider .servers )
780
810
781
811
maxTries := 5
782
- client := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), maxTries , "" , blog .UseMock (), nil )
812
+ client := New (time .Second * 10 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), maxTries , "" , blog .UseMock (), tlsConfig )
783
813
784
814
// Configure a mock exchanger that will always return a retryable error for
785
815
// servers A and B. This will force server "[2606:4700:4700::1111]:53" to do
@@ -843,13 +873,10 @@ func (dohE *dohAlwaysRetryExchanger) Exchange(m *dns.Msg, a string) (*dns.Msg, t
843
873
}
844
874
845
875
func TestDOHMetric (t * testing.T ) {
846
- features .Set (features.Config {DOH : true })
847
- defer features .Reset ()
848
-
849
876
staticProvider , err := NewStaticProvider ([]string {dnsLoopbackAddr })
850
877
test .AssertNotError (t , err , "Got error creating StaticProvider" )
851
878
852
- testClient := New (time .Second * 11 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 0 , "" , blog .UseMock (), nil )
879
+ testClient := New (time .Second * 11 , staticProvider , metrics .NoopRegisterer , clock .NewFake (), 0 , "" , blog .UseMock (), tlsConfig )
853
880
resolver := testClient .(* impl )
854
881
resolver .dnsClient = & dohAlwaysRetryExchanger {err : & url.Error {Op : "read" , Err : tempError (true )}}
855
882
0 commit comments