Skip to content

Commit d65b13d

Browse files
authored
Merge branch 'main' into feat-dns-account-01-core
2 parents 1c345a9 + 1bfc318 commit d65b13d

File tree

18 files changed

+195
-177
lines changed

18 files changed

+195
-177
lines changed

bdns/dns.go

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"github.com/miekg/dns"
2222
"github.com/prometheus/client_golang/prometheus"
2323

24-
"github.com/letsencrypt/boulder/features"
2524
blog "github.com/letsencrypt/boulder/log"
2625
"github.com/letsencrypt/boulder/metrics"
2726
"github.com/letsencrypt/boulder/policy"
@@ -77,30 +76,23 @@ func New(
7776
tlsConfig *tls.Config,
7877
) Client {
7978
var client exchanger
80-
if features.Get().DOH {
81-
// Clone the default transport because it comes with various settings
82-
// that we like, which are different from the zero value of an
83-
// `http.Transport`.
84-
transport := http.DefaultTransport.(*http.Transport).Clone()
85-
transport.TLSClientConfig = tlsConfig
86-
// The default transport already sets this field, but it isn't
87-
// documented that it will always be set. Set it again to be sure,
88-
// because Unbound will reject non-HTTP/2 DoH requests.
89-
transport.ForceAttemptHTTP2 = true
90-
client = &dohExchanger{
91-
clk: clk,
92-
hc: http.Client{
93-
Timeout: readTimeout,
94-
Transport: transport,
95-
},
96-
userAgent: userAgent,
97-
}
98-
} else {
99-
client = &dns.Client{
100-
// Set timeout for underlying net.Conn
101-
ReadTimeout: readTimeout,
102-
Net: "udp",
103-
}
79+
80+
// Clone the default transport because it comes with various settings
81+
// that we like, which are different from the zero value of an
82+
// `http.Transport`.
83+
transport := http.DefaultTransport.(*http.Transport).Clone()
84+
transport.TLSClientConfig = tlsConfig
85+
// The default transport already sets this field, but it isn't
86+
// documented that it will always be set. Set it again to be sure,
87+
// because Unbound will reject non-HTTP/2 DoH requests.
88+
transport.ForceAttemptHTTP2 = true
89+
client = &dohExchanger{
90+
clk: clk,
91+
hc: http.Client{
92+
Timeout: readTimeout,
93+
Transport: transport,
94+
},
95+
userAgent: userAgent,
10496
}
10597

10698
queryTime := prometheus.NewHistogramVec(
@@ -281,17 +273,10 @@ func (dnsClient *impl) exchangeOne(ctx context.Context, hostname string, qtype u
281273
case r := <-ch:
282274
if r.err != nil {
283275
var isRetryable bool
284-
if features.Get().DOH {
285-
// According to the http package documentation, retryable
286-
// errors emitted by the http package are of type *url.Error.
287-
var urlErr *url.Error
288-
isRetryable = errors.As(r.err, &urlErr) && urlErr.Temporary()
289-
} else {
290-
// According to the net package documentation, retryable
291-
// errors emitted by the net package are of type *net.OpError.
292-
var opErr *net.OpError
293-
isRetryable = errors.As(r.err, &opErr) && opErr.Temporary()
294-
}
276+
// According to the http package documentation, retryable
277+
// errors emitted by the http package are of type *url.Error.
278+
var urlErr *url.Error
279+
isRetryable = errors.As(r.err, &urlErr) && urlErr.Temporary()
295280
hasRetriesLeft := tries < dnsClient.maxTries
296281
if isRetryable && hasRetriesLeft {
297282
tries++

bdns/dns_test.go

Lines changed: 74 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ package bdns
22

33
import (
44
"context"
5+
"crypto/tls"
6+
"crypto/x509"
57
"errors"
68
"fmt"
9+
"io"
710
"log"
811
"net"
12+
"net/http"
913
"net/netip"
1014
"net/url"
1115
"os"
@@ -20,15 +24,37 @@ import (
2024
"github.com/miekg/dns"
2125
"github.com/prometheus/client_golang/prometheus"
2226

23-
"github.com/letsencrypt/boulder/features"
2427
blog "github.com/letsencrypt/boulder/log"
2528
"github.com/letsencrypt/boulder/metrics"
2629
"github.com/letsencrypt/boulder/test"
2730
)
2831

2932
const dnsLoopbackAddr = "127.0.0.1:4053"
3033

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+
3258
m := new(dns.Msg)
3359
m.SetReply(r)
3460
m.Compress = false
@@ -174,45 +200,37 @@ func mockDNSQuery(w dns.ResponseWriter, r *dns.Msg) {
174200
}
175201
}
176202

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)
178209
if err != nil {
179210
panic(err) // running tests, so panic is OK
180211
}
181212
}
182213

183214
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{
192218
Addr: dnsLoopbackAddr,
193-
Net: "udp",
219+
Handler: m,
194220
ReadTimeout: time.Second,
195221
WriteTimeout: time.Second,
196222
}
197223
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)
205227
if err != nil {
206228
fmt.Println(err)
207229
}
208230
}()
209231
go func() {
210232
<-stopChan
211-
err := tcpServer.Shutdown()
212-
if err != nil {
213-
log.Fatal(err)
214-
}
215-
err = udpServer.Shutdown()
233+
err := httpServer.Shutdown(context.Background())
216234
if err != nil {
217235
log.Fatal(err)
218236
}
@@ -240,7 +258,21 @@ func pollServer() {
240258
}
241259
}
242260

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+
243265
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+
244276
stop := make(chan bool, 1)
245277
serveLoopResolver(stop)
246278
pollServer()
@@ -253,7 +285,7 @@ func TestDNSNoServers(t *testing.T) {
253285
staticProvider, err := NewStaticProvider([]string{})
254286
test.AssertNotError(t, err, "Got error creating StaticProvider")
255287

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)
257289

258290
_, resolvers, err := obj.LookupHost(context.Background(), "letsencrypt.org")
259291
test.AssertEquals(t, len(resolvers), 0)
@@ -270,7 +302,7 @@ func TestDNSOneServer(t *testing.T) {
270302
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
271303
test.AssertNotError(t, err, "Got error creating StaticProvider")
272304

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)
274306

275307
_, resolvers, err := obj.LookupHost(context.Background(), "cps.letsencrypt.org")
276308
test.AssertEquals(t, len(resolvers), 2)
@@ -283,7 +315,7 @@ func TestDNSDuplicateServers(t *testing.T) {
283315
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr, dnsLoopbackAddr})
284316
test.AssertNotError(t, err, "Got error creating StaticProvider")
285317

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)
287319

288320
_, resolvers, err := obj.LookupHost(context.Background(), "cps.letsencrypt.org")
289321
test.AssertEquals(t, len(resolvers), 2)
@@ -296,7 +328,7 @@ func TestDNSServFail(t *testing.T) {
296328
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
297329
test.AssertNotError(t, err, "Got error creating StaticProvider")
298330

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)
300332
bad := "servfail.com"
301333

302334
_, _, err = obj.LookupTXT(context.Background(), bad)
@@ -314,7 +346,7 @@ func TestDNSLookupTXT(t *testing.T) {
314346
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
315347
test.AssertNotError(t, err, "Got error creating StaticProvider")
316348

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)
318350

319351
a, _, err := obj.LookupTXT(context.Background(), "letsencrypt.org")
320352
t.Logf("A: %v", a)
@@ -332,7 +364,7 @@ func TestDNSLookupHost(t *testing.T) {
332364
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
333365
test.AssertNotError(t, err, "Got error creating StaticProvider")
334366

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)
336368

337369
ip, resolvers, err := obj.LookupHost(context.Background(), "servfail.com")
338370
t.Logf("servfail.com - IP: %s, Err: %s", ip, err)
@@ -418,7 +450,7 @@ func TestDNSNXDOMAIN(t *testing.T) {
418450
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
419451
test.AssertNotError(t, err, "Got error creating StaticProvider")
420452

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)
422454

423455
hostname := "nxdomain.letsencrypt.org"
424456
_, _, err = obj.LookupHost(context.Background(), hostname)
@@ -434,7 +466,7 @@ func TestDNSLookupCAA(t *testing.T) {
434466
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
435467
test.AssertNotError(t, err, "Got error creating StaticProvider")
436468

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)
438470
removeIDExp := regexp.MustCompile(" id: [[:digit:]]+")
439471

440472
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
513545
}
514546

515547
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)}
518550
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")
520551
type testCase struct {
521552
name string
522553
maxTries int
@@ -567,7 +598,7 @@ func TestRetry(t *testing.T) {
567598
isTempErr,
568599
},
569600
},
570-
expected: netError,
601+
expected: servFailError,
571602
expectedCount: 3,
572603
metricsAllRetries: 1,
573604
},
@@ -620,7 +651,7 @@ func TestRetry(t *testing.T) {
620651
isTempErr,
621652
},
622653
},
623-
expected: netError,
654+
expected: servFailError,
624655
expectedCount: 3,
625656
metricsAllRetries: 1,
626657
},
@@ -634,7 +665,7 @@ func TestRetry(t *testing.T) {
634665
nonTempErr,
635666
},
636667
},
637-
expected: netError,
668+
expected: servFailError,
638669
expectedCount: 2,
639670
},
640671
}
@@ -644,7 +675,7 @@ func TestRetry(t *testing.T) {
644675
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
645676
test.AssertNotError(t, err, "Got error creating StaticProvider")
646677

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)
648679
dr := testClient.(*impl)
649680
dr.dnsClient = tc.te
650681
_, _, err = dr.LookupTXT(context.Background(), "example.com")
@@ -675,7 +706,7 @@ func TestRetry(t *testing.T) {
675706
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
676707
test.AssertNotError(t, err, "Got error creating StaticProvider")
677708

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)
679710
dr := testClient.(*impl)
680711
dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}}
681712
ctx, cancel := context.WithCancel(context.Background())
@@ -754,7 +785,7 @@ func (e *rotateFailureExchanger) Exchange(m *dns.Msg, a string) (*dns.Msg, time.
754785

755786
// If its a broken server, return a retryable error
756787
if e.brokenAddresses[a] {
757-
isTempErr := &net.OpError{Op: "read", Err: tempError(true)}
788+
isTempErr := &url.Error{Op: "read", Err: tempError(true)}
758789
return nil, 2 * time.Millisecond, isTempErr
759790
}
760791

@@ -776,10 +807,9 @@ func TestRotateServerOnErr(t *testing.T) {
776807
// working server
777808
staticProvider, err := NewStaticProvider(dnsServers)
778809
test.AssertNotError(t, err, "Got error creating StaticProvider")
779-
fmt.Println(staticProvider.servers)
780810

781811
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)
783813

784814
// Configure a mock exchanger that will always return a retryable error for
785815
// 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
843873
}
844874

845875
func TestDOHMetric(t *testing.T) {
846-
features.Set(features.Config{DOH: true})
847-
defer features.Reset()
848-
849876
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
850877
test.AssertNotError(t, err, "Got error creating StaticProvider")
851878

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)
853880
resolver := testClient.(*impl)
854881
resolver.dnsClient = &dohAlwaysRetryExchanger{err: &url.Error{Op: "read", Err: tempError(true)}}
855882

cmd/boulder-va/main.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,12 @@ func main() {
8282
clk := cmd.Clock()
8383

8484
var servers bdns.ServerProvider
85-
proto := "udp"
86-
if features.Get().DOH {
87-
proto = "tcp"
88-
}
8985

9086
if len(c.VA.DNSStaticResolvers) != 0 {
9187
servers, err = bdns.NewStaticProvider(c.VA.DNSStaticResolvers)
9288
cmd.FailOnError(err, "Couldn't start static DNS server resolver")
9389
} else {
94-
servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second, proto)
90+
servers, err = bdns.StartDynamicProvider(c.VA.DNSProvider, 60*time.Second, "tcp")
9591
cmd.FailOnError(err, "Couldn't start dynamic DNS server resolver")
9692
}
9793
defer servers.Stop()

0 commit comments

Comments
 (0)