net/dns/resolver: add Windows ExitDNS service support, using net package

Updates #1713
Updates #835

Change-Id: Ia71e96d0632c2d617b401695ad68301b07c1c2ec
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-12-09 12:01:19 -08:00
committed by Brad Fitzpatrick
parent cab5c46481
commit cced414c7d
4 changed files with 775 additions and 9 deletions

View File

@ -6,6 +6,7 @@ package resolver
import (
"fmt"
"net"
"strings"
"testing"
@ -179,6 +180,129 @@ var resolveToNXDOMAIN = dns.HandlerFunc(func(w dns.ResponseWriter, req *dns.Msg)
w.WriteMsg(m)
})
// weirdoGoCNAMEHandler returns a DNS handler that satisfies
// Go's weird Resolver.LookupCNAME (read its godoc carefully!).
//
// This doesn't even return a CNAME record, because that's not
// what Go looks for.
func weirdoGoCNAMEHandler(target string) dns.HandlerFunc {
return func(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg)
m.SetReply(req)
question := req.Question[0]
switch question.Qtype {
case dns.TypeA:
m.Answer = append(m.Answer, &dns.CNAME{
Hdr: dns.RR_Header{
Name: target,
Rrtype: dns.TypeCNAME,
Class: dns.ClassINET,
Ttl: 600,
},
Target: target,
})
case dns.TypeAAAA:
m.Answer = append(m.Answer, &dns.AAAA{
Hdr: dns.RR_Header{
Name: target,
Rrtype: dns.TypeAAAA,
Class: dns.ClassINET,
Ttl: 600,
},
AAAA: net.ParseIP("1::2"),
})
}
w.WriteMsg(m)
}
}
// dnsHandler returns a handler that replies with the answers/options
// provided.
//
// Types supported: netaddr.IP.
func dnsHandler(answers ...interface{}) dns.HandlerFunc {
return func(w dns.ResponseWriter, req *dns.Msg) {
m := new(dns.Msg)
m.SetReply(req)
if len(req.Question) != 1 {
panic("not a single-question request")
}
m.RecursionAvailable = true // to stop net package's errLameReferral on empty replies
question := req.Question[0]
for _, a := range answers {
switch a := a.(type) {
default:
panic(fmt.Sprintf("unsupported dnsHandler arg %T", a))
case netaddr.IP:
ip := a
if ip.Is4() {
m.Answer = append(m.Answer, &dns.A{
Hdr: dns.RR_Header{
Name: question.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
},
A: ip.IPAddr().IP,
})
} else if ip.Is6() {
m.Answer = append(m.Answer, &dns.AAAA{
Hdr: dns.RR_Header{
Name: question.Name,
Rrtype: dns.TypeAAAA,
Class: dns.ClassINET,
},
AAAA: ip.IPAddr().IP,
})
}
case dns.PTR:
ptr := a
ptr.Hdr = dns.RR_Header{
Name: question.Name,
Rrtype: dns.TypePTR,
Class: dns.ClassINET,
}
m.Answer = append(m.Answer, &ptr)
case dns.CNAME:
c := a
c.Hdr = dns.RR_Header{
Name: question.Name,
Rrtype: dns.TypeCNAME,
Class: dns.ClassINET,
Ttl: 600,
}
m.Answer = append(m.Answer, &c)
case dns.TXT:
txt := a
txt.Hdr = dns.RR_Header{
Name: question.Name,
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
}
m.Answer = append(m.Answer, &txt)
case dns.SRV:
srv := a
srv.Hdr = dns.RR_Header{
Name: question.Name,
Rrtype: dns.TypeSRV,
Class: dns.ClassINET,
}
m.Answer = append(m.Answer, &srv)
case dns.NS:
rr := a
rr.Hdr = dns.RR_Header{
Name: question.Name,
Rrtype: dns.TypeNS,
Class: dns.ClassINET,
}
m.Answer = append(m.Answer, &rr)
}
}
w.WriteMsg(m)
}
}
func serveDNS(tb testing.TB, addr string, records ...interface{}) *dns.Server {
if len(records)%2 != 0 {
panic("must have an even number of record values")