Skip to content

Commit d6da247

Browse files
edwardrfedw-defang
andauthored
Create a transport that use root resolver instead of normal resolver (#661)
* Create a transport that use root resolver instead of normal resolver * Use root resolver for tls https connection test * Only return cname when no IP are found when querying IP addr --------- Co-authored-by: Edward J <[email protected]>
1 parent 6c6c5ec commit d6da247

File tree

2 files changed

+74
-5
lines changed

2 files changed

+74
-5
lines changed

src/pkg/cli/cert.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"io"
8+
"math/rand"
89
"net"
910
"net/http"
1011
"slices"
@@ -23,8 +24,33 @@ type HTTPClient interface {
2324
Do(req *http.Request) (*http.Response, error)
2425
}
2526

26-
var resolver dns.Resolver = dns.RootResolver{}
27-
var httpClient HTTPClient = http.DefaultClient
27+
var (
28+
resolver dns.Resolver = dns.RootResolver{}
29+
httpClient HTTPClient = &http.Client{
30+
// Based on the default transport: https://pkg.go.dev/net/http#RoundTripper
31+
Transport: &http.Transport{
32+
Proxy: http.ProxyFromEnvironment,
33+
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
34+
host, port, err := net.SplitHostPort(addr)
35+
if err != nil {
36+
return nil, err
37+
}
38+
ips, err := resolver.LookupIPAddr(ctx, host)
39+
if err != nil {
40+
return nil, err
41+
}
42+
dialer := &net.Dialer{}
43+
rootAddr := net.JoinHostPort(ips[rand.Intn(len(ips))].String(), port)
44+
return dialer.DialContext(ctx, network, rootAddr)
45+
},
46+
ForceAttemptHTTP2: true,
47+
MaxIdleConns: 100,
48+
IdleConnTimeout: 90 * time.Second,
49+
TLSHandshakeTimeout: 10 * time.Second,
50+
ExpectContinueTimeout: 1 * time.Second,
51+
},
52+
}
53+
)
2854

2955
func GenerateLetsEncryptCert(ctx context.Context, client cliClient.Client) error {
3056
projectName, err := client.LoadProjectName(ctx)
@@ -252,7 +278,17 @@ func checkDomainDNSReady(ctx context.Context, domain string, validCNAMEs []strin
252278
}
253279

254280
func checkTLSCert(ctx context.Context, domain string) error {
255-
return getWithRetries(ctx, fmt.Sprintf("https://%v", domain), 3)
281+
url := fmt.Sprintf("https://%v", domain)
282+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
283+
if err != nil {
284+
return err
285+
}
286+
resp, err := httpClient.Do(req) // http non 200 errors are not considered as errors
287+
if err != nil {
288+
return err
289+
}
290+
defer resp.Body.Close()
291+
return nil
256292
}
257293

258294
func getWithRetries(ctx context.Context, url string, tries int) error {
@@ -267,7 +303,6 @@ func getWithRetries(ctx context.Context, url string, tries int) error {
267303
defer resp.Body.Close()
268304
var msg []byte
269305
msg, err = io.ReadAll(resp.Body)
270-
term.Debugf("Response from %v: %v", url, string(msg))
271306
if resp.StatusCode == http.StatusOK {
272307
return nil
273308
}

src/pkg/dns/resolver.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dns
22

33
import (
44
"context"
5+
"fmt"
56
"math/rand"
67
"net"
78
"slices"
@@ -36,7 +37,15 @@ var rootServers = []*net.NS{
3637
}
3738

3839
func (r RootResolver) LookupIPAddr(ctx context.Context, domain string) ([]net.IPAddr, error) {
39-
return r.getResolver(ctx, domain).LookupIPAddr(ctx, domain)
40+
ips, err := r.getResolver(ctx, domain).LookupIPAddr(ctx, domain)
41+
if err != nil {
42+
if err, ok := err.(ErrCNAMEFound); ok {
43+
return r.getResolver(ctx, err.CNAME()).LookupIPAddr(ctx, err.CNAME())
44+
} else {
45+
return nil, err
46+
}
47+
}
48+
return ips, nil
4049
}
4150

4251
func (r RootResolver) LookupCNAME(ctx context.Context, domain string) (string, error) {
@@ -83,6 +92,16 @@ var ResolverAt = DirectResolverAt
8392

8493
var ErrNoSuchHost = &net.DNSError{Err: "no such host", IsNotFound: true}
8594

95+
type ErrCNAMEFound string
96+
97+
func (e ErrCNAMEFound) Error() string {
98+
return fmt.Sprintf("CNAME found: %v", string(e))
99+
}
100+
101+
func (e ErrCNAMEFound) CNAME() string {
102+
return string(e)
103+
}
104+
86105
type DirectResolver struct {
87106
NSServer string
88107
}
@@ -100,9 +119,15 @@ func (r DirectResolver) LookupIPAddr(ctx context.Context, domain string) ([]net.
100119
}
101120

102121
var result []net.IPAddr
122+
var cname string
123+
var ansErr error
103124
for _, rr := range res.Answer {
104125
if ns, ok := rr.(*dns.A); ok {
105126
result = append(result, net.IPAddr{IP: ns.A})
127+
} else if cn, ok := rr.(*dns.CNAME); ok {
128+
cname = cn.Target
129+
} else {
130+
ansErr = fmt.Errorf("unexpected type %T [%v]", rr, rr)
106131
}
107132
}
108133

@@ -114,9 +139,18 @@ func (r DirectResolver) LookupIPAddr(ctx context.Context, domain string) ([]net.
114139
for _, rr := range res.Answer {
115140
if ns, ok := rr.(*dns.AAAA); ok {
116141
result = append(result, net.IPAddr{IP: ns.AAAA})
142+
} else if cn, ok := rr.(*dns.CNAME); ok {
143+
cname = cn.Target
144+
} else {
145+
ansErr = fmt.Errorf("unexpected type %T [%v]", rr, rr)
117146
}
118147
}
119148
if len(result) == 0 {
149+
if cname != "" {
150+
return nil, ErrCNAMEFound(cname)
151+
} else if ansErr != nil {
152+
return nil, ansErr
153+
}
120154
return nil, ErrNoSuchHost
121155
}
122156
return result, nil

0 commit comments

Comments
 (0)