mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-12 05:37:32 +00:00
tailcfg, ipn/ipnlocal, net/dns: forward exit node DNS on Unix to system DNS
Updates #1713 Change-Id: I4c073fec0992d9e01a9a4ce97087d5af0efdc68d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
d9c21936c3
commit
135580a5a8
@@ -344,3 +344,48 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllowExitNodeDNSProxyToServeName(t *testing.T) {
|
||||
b := &LocalBackend{}
|
||||
if b.allowExitNodeDNSProxyToServeName("google.com") {
|
||||
t.Fatal("unexpected true on backend with nil NetMap")
|
||||
}
|
||||
|
||||
b.netMap = &netmap.NetworkMap{
|
||||
DNS: tailcfg.DNSConfig{
|
||||
ExitNodeFilteredSet: []string{
|
||||
".ts.net",
|
||||
"some.exact.bad",
|
||||
},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
want bool
|
||||
}{
|
||||
// Allow by default:
|
||||
{"google.com", true},
|
||||
{"GOOGLE.com", true},
|
||||
|
||||
// Rejected by suffix:
|
||||
{"foo.TS.NET", false},
|
||||
{"foo.ts.net", false},
|
||||
|
||||
// Suffix doesn't match
|
||||
{"ts.net", true},
|
||||
|
||||
// Rejected by exact match:
|
||||
{"some.exact.bad", false},
|
||||
{"SOME.EXACT.BAD", false},
|
||||
|
||||
// But a prefix is okay.
|
||||
{"prefix-okay.some.exact.bad", true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := b.allowExitNodeDNSProxyToServeName(tt.name)
|
||||
if got != tt.want {
|
||||
t.Errorf("for %q = %v; want %v", tt.name, got, tt.want)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -3053,3 +3053,34 @@ func (b *LocalBackend) OfferingExitNode() bool {
|
||||
}
|
||||
return def4 && def6
|
||||
}
|
||||
|
||||
// allowExitNodeDNSProxyToServeName reports whether the Exit Node DNS
|
||||
// proxy is allowed to serve responses for the provided DNS name.
|
||||
func (b *LocalBackend) allowExitNodeDNSProxyToServeName(name string) bool {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
nm := b.netMap
|
||||
if nm == nil {
|
||||
return false
|
||||
}
|
||||
name = strings.ToLower(name)
|
||||
for _, bad := range nm.DNS.ExitNodeFilteredSet {
|
||||
if bad == "" {
|
||||
// Invalid, ignore.
|
||||
continue
|
||||
}
|
||||
if bad[0] == '.' {
|
||||
// Entries beginning with a dot are suffix matches.
|
||||
if dnsname.HasSuffix(name, bad) {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Otherwise entries are exact matches. They're
|
||||
// guaranteed to be lowercase already.
|
||||
if name == bad {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@@ -832,7 +832,7 @@ func (h *peerAPIHandler) handleDNSQuery(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
ctx, cancel := context.WithTimeout(r.Context(), arbitraryTimeout)
|
||||
defer cancel()
|
||||
res, err := h.ps.resolver.HandleExitNodeDNSQuery(ctx, q, h.remoteAddr)
|
||||
res, err := h.ps.resolver.HandleExitNodeDNSQuery(ctx, q, h.remoteAddr, h.ps.b.allowExitNodeDNSProxyToServeName)
|
||||
if err != nil {
|
||||
h.logf("handleDNS fwd error: %v", err)
|
||||
if err := ctx.Err(); err != nil {
|
||||
@@ -918,14 +918,19 @@ func writePrettyDNSReply(w io.Writer, res []byte) (err error) {
|
||||
j, _ := json.Marshal(struct {
|
||||
Error string
|
||||
}{err.Error()})
|
||||
j = append(j, '\n')
|
||||
w.Write(j)
|
||||
return
|
||||
}
|
||||
}()
|
||||
var p dnsmessage.Parser
|
||||
if _, err := p.Start(res); err != nil {
|
||||
hdr, err := p.Start(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hdr.RCode != dnsmessage.RCodeSuccess {
|
||||
return fmt.Errorf("DNS RCode = %v", hdr.RCode)
|
||||
}
|
||||
if err := p.SkipAllQuestions(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
Reference in New Issue
Block a user