Skip to content

Commit 5933266

Browse files
authored
Merge pull request #1 from libp2p/implementation
DoH resolver implementation
2 parents c48ccfd + 92051b3 commit 5933266

File tree

5 files changed

+338
-0
lines changed

5 files changed

+338
-0
lines changed

go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module github.com/libp2p/go-doh-resolver
2+
3+
go 1.15
4+
5+
require (
6+
github.com/ipfs/go-log/v2 v2.1.3
7+
github.com/miekg/dns v1.1.41
8+
github.com/multiformats/go-multiaddr-dns v0.3.0
9+
golang.org/x/tools v0.0.0-20210106214847-113979e3529a // indirect
10+
)

go.sum

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2+
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
6+
github.com/ipfs/go-log/v2 v2.1.3 h1:1iS3IU7aXRlbgUpN8yTTpJ53NXYjAe37vcI5+5nYrzk=
7+
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
8+
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
9+
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
10+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
11+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
12+
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
13+
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
14+
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
15+
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo=
16+
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
17+
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
18+
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
19+
github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5a9qECv/J90=
20+
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
21+
github.com/multiformats/go-multiaddr-dns v0.3.0 h1:CUSbj29Qw/grGQdQ4ttsGJcVvo9AvEEMyAIeI/YwQs0=
22+
github.com/multiformats/go-multiaddr-dns v0.3.0/go.mod h1:mNzQ4eTGDg0ll1N9jKPOUogZPoJ30W8a7zk66FQPpdQ=
23+
github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRHGVoUugWvXg=
24+
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
25+
github.com/multiformats/go-varint v0.0.1 h1:TR/0rdQtnNxuN2IhiB639xC3tWM4IUi7DkTBVTdGW/M=
26+
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
27+
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
28+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
29+
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
30+
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
31+
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
32+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
33+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
34+
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
35+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
36+
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
37+
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
38+
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
39+
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
40+
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
41+
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
42+
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
43+
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
44+
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
45+
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
46+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
47+
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
48+
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
49+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
50+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
51+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
52+
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
53+
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
54+
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
55+
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
56+
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
57+
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
58+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
59+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
60+
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
61+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
62+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
63+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
64+
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
65+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
66+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
67+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
68+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
69+
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
70+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
71+
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 h1:cEhElsAv9LUt9ZUUocxzWe05oFLVd+AA2nstydTeI8g=
72+
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
73+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
74+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
75+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
76+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
77+
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
78+
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
79+
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
80+
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
81+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
82+
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
83+
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
84+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
85+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
86+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
87+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
88+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
89+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
90+
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
91+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
92+
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
93+
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

request.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package doh
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"io"
8+
"net"
9+
"net/http"
10+
11+
"github.com/miekg/dns"
12+
13+
logging "github.com/ipfs/go-log/v2"
14+
)
15+
16+
const (
17+
dohMimeType = "application/dns-message"
18+
)
19+
20+
var log = logging.Logger("doh")
21+
22+
func doRequest(ctx context.Context, url string, m *dns.Msg) (*dns.Msg, error) {
23+
data, err := m.Pack()
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data))
29+
if err != nil {
30+
return nil, err
31+
}
32+
33+
req.Header.Set("Content-Type", dohMimeType)
34+
req.Header.Set("Accept", dohMimeType)
35+
36+
req = req.WithContext(ctx)
37+
38+
resp, err := http.DefaultClient.Do(req)
39+
if err != nil {
40+
return nil, err
41+
}
42+
defer resp.Body.Close()
43+
44+
if resp.StatusCode != http.StatusOK {
45+
return nil, fmt.Errorf("HTTP error: %q [%d]", resp.Status, resp.StatusCode)
46+
}
47+
48+
if ct := resp.Header.Get("Content-Type"); ct != dohMimeType {
49+
return nil, fmt.Errorf("unexpected Content-Type %q", ct)
50+
}
51+
52+
body, err := io.ReadAll(resp.Body)
53+
if err != nil {
54+
return nil, err
55+
}
56+
57+
r := new(dns.Msg)
58+
if err := r.Unpack(body); err != nil {
59+
return nil, err
60+
}
61+
62+
return r, nil
63+
}
64+
65+
func doRequestA(ctx context.Context, url string, domain string) ([]net.IPAddr, error) {
66+
fqdn := dns.Fqdn(domain)
67+
68+
m := new(dns.Msg)
69+
m.SetQuestion(fqdn, dns.TypeA)
70+
71+
r, err := doRequest(ctx, url, m)
72+
if err != nil {
73+
return nil, err
74+
}
75+
76+
result := make([]net.IPAddr, 0, len(r.Answer))
77+
for _, rr := range r.Answer {
78+
switch v := rr.(type) {
79+
case *dns.A:
80+
result = append(result, net.IPAddr{IP: v.A})
81+
default:
82+
log.Warnf("unexpected DNS resource record %+v", rr)
83+
}
84+
}
85+
86+
return result, nil
87+
}
88+
89+
func doRequestAAAA(ctx context.Context, url string, domain string) ([]net.IPAddr, error) {
90+
fqdn := dns.Fqdn(domain)
91+
92+
m := new(dns.Msg)
93+
m.SetQuestion(fqdn, dns.TypeAAAA)
94+
95+
r, err := doRequest(ctx, url, m)
96+
if err != nil {
97+
return nil, err
98+
}
99+
100+
result := make([]net.IPAddr, 0, len(r.Answer))
101+
for _, rr := range r.Answer {
102+
switch v := rr.(type) {
103+
case *dns.AAAA:
104+
result = append(result, net.IPAddr{IP: v.AAAA})
105+
default:
106+
log.Warnf("unexpected DNS resource record %+v", rr)
107+
}
108+
}
109+
110+
return result, nil
111+
}
112+
113+
func doRequestTXT(ctx context.Context, url string, domain string) ([]string, error) {
114+
fqdn := dns.Fqdn(domain)
115+
116+
m := new(dns.Msg)
117+
m.SetQuestion(fqdn, dns.TypeTXT)
118+
119+
r, err := doRequest(ctx, url, m)
120+
if err != nil {
121+
return nil, err
122+
}
123+
124+
var result []string
125+
for _, rr := range r.Answer {
126+
switch v := rr.(type) {
127+
case *dns.TXT:
128+
result = append(result, v.Txt...)
129+
default:
130+
log.Warnf("unexpected DNS resource record %+v", rr)
131+
}
132+
}
133+
134+
return result, nil
135+
}

resolver.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package doh
2+
3+
import (
4+
"context"
5+
"net"
6+
"strings"
7+
8+
madns "github.com/multiformats/go-multiaddr-dns"
9+
)
10+
11+
type Resolver struct {
12+
url string
13+
}
14+
15+
func NewResolver(url string) *Resolver {
16+
if !strings.HasPrefix(url, "https://") {
17+
url = "https://" + url
18+
}
19+
20+
return &Resolver{url: url}
21+
}
22+
23+
var _ madns.BasicResolver = (*Resolver)(nil)
24+
25+
func (r *Resolver) LookupIPAddr(ctx context.Context, domain string) (result []net.IPAddr, err error) {
26+
type response struct {
27+
ips []net.IPAddr
28+
err error
29+
}
30+
31+
resch := make(chan response, 2)
32+
go func() {
33+
ip4, err := doRequestA(ctx, r.url, domain)
34+
resch <- response{ip4, err}
35+
}()
36+
37+
go func() {
38+
ip6, err := doRequestAAAA(ctx, r.url, domain)
39+
resch <- response{ip6, err}
40+
}()
41+
42+
for i := 0; i < 2; i++ {
43+
r := <-resch
44+
if r.err != nil {
45+
return nil, r.err
46+
}
47+
48+
result = append(result, r.ips...)
49+
}
50+
51+
return result, nil
52+
}
53+
54+
func (r *Resolver) LookupTXT(ctx context.Context, domain string) ([]string, error) {
55+
return doRequestTXT(ctx, r.url, domain)
56+
}

resolver_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package doh
2+
3+
import (
4+
"context"
5+
"testing"
6+
)
7+
8+
func TestLookupIPAddr(t *testing.T) {
9+
r := NewResolver("https://cloudflare-dns.com/dns-query")
10+
11+
ips, err := r.LookupIPAddr(context.Background(), "libp2p.io")
12+
if err != nil {
13+
t.Fatal(err)
14+
}
15+
if len(ips) == 0 {
16+
t.Fatal("got no IPs")
17+
}
18+
var got4, got6 bool
19+
for _, ip := range ips {
20+
if len(ip.IP.To4()) == 4 {
21+
got4 = true
22+
} else {
23+
got6 = true
24+
}
25+
}
26+
if !got4 {
27+
t.Fatal("got no IPv4 addresses")
28+
}
29+
if !got6 {
30+
t.Fatal("got no IPv6 addresses")
31+
}
32+
}
33+
34+
func TestLookupTXT(t *testing.T) {
35+
r := NewResolver("https://cloudflare-dns.com/dns-query")
36+
37+
txt, err := r.LookupTXT(context.Background(), "_dnsaddr.bootstrap.libp2p.io")
38+
if err != nil {
39+
t.Fatal(err)
40+
}
41+
if len(txt) == 0 {
42+
t.Fatal("got no TXT entries")
43+
}
44+
}

0 commit comments

Comments
 (0)