2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2021-07-15 16:11:12 +00:00
|
|
|
|
|
|
|
package resolver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"flag"
|
|
|
|
"net/http"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"golang.org/x/net/dns/dnsmessage"
|
2022-04-14 21:15:54 +00:00
|
|
|
"tailscale.com/net/dns/publicdns"
|
2021-07-15 16:11:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var testDoH = flag.Bool("test-doh", false, "do real DoH tests against the network")
|
|
|
|
|
|
|
|
const someDNSID = 123 // something non-zero as a test; in violation of spec's SHOULD of 0
|
|
|
|
|
|
|
|
func someDNSQuestion(t testing.TB) []byte {
|
|
|
|
b := dnsmessage.NewBuilder(nil, dnsmessage.Header{
|
|
|
|
OpCode: 0, // query
|
|
|
|
RecursionDesired: true,
|
|
|
|
ID: someDNSID,
|
|
|
|
})
|
|
|
|
b.StartQuestions() // err
|
|
|
|
b.Question(dnsmessage.Question{
|
|
|
|
Name: dnsmessage.MustNewName("tailscale.com."),
|
|
|
|
Type: dnsmessage.TypeA,
|
|
|
|
Class: dnsmessage.ClassINET,
|
|
|
|
})
|
|
|
|
msg, err := b.Finish()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
return msg
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDoH(t *testing.T) {
|
|
|
|
if !*testDoH {
|
|
|
|
t.Skip("skipping manual test without --test-doh flag")
|
|
|
|
}
|
2022-09-06 18:15:30 +00:00
|
|
|
prefixes := publicdns.KnownDoHPrefixes()
|
|
|
|
if len(prefixes) == 0 {
|
2021-07-15 16:11:12 +00:00
|
|
|
t.Fatal("no known DoH")
|
|
|
|
}
|
|
|
|
|
2023-02-04 00:47:51 +00:00
|
|
|
f := &forwarder{}
|
2021-07-15 16:11:12 +00:00
|
|
|
|
2022-09-06 18:15:30 +00:00
|
|
|
for _, urlBase := range prefixes {
|
2022-04-19 04:58:00 +00:00
|
|
|
t.Run(urlBase, func(t *testing.T) {
|
|
|
|
c, ok := f.getKnownDoHClientForProvider(urlBase)
|
2021-07-15 16:11:12 +00:00
|
|
|
if !ok {
|
|
|
|
t.Fatal("expected DoH")
|
|
|
|
}
|
|
|
|
res, err := f.sendDoH(context.Background(), urlBase, c, someDNSQuestion(t))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
c.Transport.(*http.Transport).CloseIdleConnections()
|
|
|
|
|
|
|
|
var p dnsmessage.Parser
|
|
|
|
h, err := p.Start(res)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if h.ID != someDNSID {
|
|
|
|
t.Errorf("response DNS ID = %v; want %v", h.ID, someDNSID)
|
|
|
|
}
|
|
|
|
|
|
|
|
p.SkipAllQuestions()
|
|
|
|
aa, err := p.AllAnswers()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if len(aa) == 0 {
|
|
|
|
t.Fatal("no answers")
|
|
|
|
}
|
|
|
|
for _, r := range aa {
|
|
|
|
t.Logf("got: %v", r.GoString())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-07-21 19:43:06 +00:00
|
|
|
|
|
|
|
func TestDoHV6Fallback(t *testing.T) {
|
2022-09-06 18:15:30 +00:00
|
|
|
for _, base := range publicdns.KnownDoHPrefixes() {
|
|
|
|
for _, ip := range publicdns.DoHIPsOfBase(base) {
|
|
|
|
if ip.Is4() {
|
|
|
|
ip6, ok := publicdns.DoHV6(base)
|
|
|
|
if !ok {
|
|
|
|
t.Errorf("no v6 DoH known for %v", ip)
|
|
|
|
} else if !ip6.Is6() {
|
|
|
|
t.Errorf("dohV6(%q) returned non-v6 address %v", base, ip6)
|
|
|
|
}
|
2021-07-21 19:43:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|