feature/featuretags: add option to turn off DNS

Saves 328 KB (2.5%) off the minimal binary.

For IoT devices that don't need MagicDNS (e.g. they don't make
outbound connections), this provides a knob to disable all the DNS
functionality.

Rather than a massive refactor today, this uses constant false values
as a deadcode sledgehammer, guided by shotizam to find the largest DNS
functions which survived deadcode.

A future refactor could make it so that the net/dns/resolver and
publicdns packages don't even show up in the import graph (along with
their imports) but really it's already pretty good looking with just
these consts, so it's not at the top of my list to refactor it more
soon.

Also do the same in a few places with the ACME (cert) functionality,
as I saw those while searching for DNS stuff.

Updates #12614

Change-Id: I8e459f595c2fde68ca16503ff61c8ab339871f97
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2025-09-29 22:10:28 -07:00 committed by Brad Fitzpatrick
parent a45473c4c5
commit bcd79b161a
16 changed files with 144 additions and 4 deletions

View File

@ -30,6 +30,7 @@ import (
"tailscale.com/control/controlknobs" "tailscale.com/control/controlknobs"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/feature" "tailscale.com/feature"
"tailscale.com/feature/buildfeatures"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/hostinfo" "tailscale.com/hostinfo"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
@ -1580,6 +1581,9 @@ func (c *Direct) setDNSNoise(ctx context.Context, req *tailcfg.SetDNSRequest) er
// SetDNS sends the SetDNSRequest request to the control plane server, // SetDNS sends the SetDNSRequest request to the control plane server,
// requesting a DNS record be created or updated. // requesting a DNS record be created or updated.
func (c *Direct) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) (err error) { func (c *Direct) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) (err error) {
if !buildfeatures.HasACME {
return feature.ErrUnavailable
}
metricSetDNS.Add(1) metricSetDNS.Add(1)
defer func() { defer func() {
if err != nil { if err != nil {

View File

@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build ts_omit_dns
package buildfeatures
// HasDNS is whether the binary was built with support for modular feature "MagicDNS and system DNS configuration support".
// Specifically, it's whether the binary was NOT built with the "ts_omit_dns" build tag.
// It's a const so it can be used for dead code elimination.
const HasDNS = false

View File

@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build !ts_omit_dns
package buildfeatures
// HasDNS is whether the binary was built with support for modular feature "MagicDNS and system DNS configuration support".
// Specifically, it's whether the binary was NOT built with the "ts_omit_dns" build tag.
// It's a const so it can be used for dead code elimination.
const HasDNS = true

View File

@ -4,7 +4,12 @@
// Package feature tracks which features are linked into the binary. // Package feature tracks which features are linked into the binary.
package feature package feature
import "reflect" import (
"errors"
"reflect"
)
var ErrUnavailable = errors.New("feature not included in this build")
var in = map[string]bool{} var in = map[string]bool{}

View File

@ -137,6 +137,10 @@ var Features = map[FeatureTag]FeatureMeta{
"portlist": {"PortList", "Optionally advertise listening service ports", nil}, "portlist": {"PortList", "Optionally advertise listening service ports", nil},
"portmapper": {"PortMapper", "NAT-PMP/PCP/UPnP port mapping support", nil}, "portmapper": {"PortMapper", "NAT-PMP/PCP/UPnP port mapping support", nil},
"posture": {"Posture", "Device posture checking support", nil}, "posture": {"Posture", "Device posture checking support", nil},
"dns": {
Sym: "DNS",
Desc: "MagicDNS and system DNS configuration support",
},
"netlog": { "netlog": {
Sym: "NetLog", Sym: "NetLog",
Desc: "Network flow logging support", Desc: "Network flow logging support",

View File

@ -729,6 +729,9 @@ func (b *LocalBackend) SetComponentDebugLogging(component string, until time.Tim
// GetDNSOSConfig returns the base OS DNS configuration, as seen by the DNS manager. // GetDNSOSConfig returns the base OS DNS configuration, as seen by the DNS manager.
func (b *LocalBackend) GetDNSOSConfig() (dns.OSConfig, error) { func (b *LocalBackend) GetDNSOSConfig() (dns.OSConfig, error) {
if !buildfeatures.HasDNS {
panic("unreachable")
}
manager, ok := b.sys.DNSManager.GetOK() manager, ok := b.sys.DNSManager.GetOK()
if !ok { if !ok {
return dns.OSConfig{}, errors.New("DNS manager not available") return dns.OSConfig{}, errors.New("DNS manager not available")
@ -740,6 +743,9 @@ func (b *LocalBackend) GetDNSOSConfig() (dns.OSConfig, error) {
// the raw DNS response and the resolvers that are were able to handle the query (the internal forwarder // the raw DNS response and the resolvers that are were able to handle the query (the internal forwarder
// may race multiple resolvers). // may race multiple resolvers).
func (b *LocalBackend) QueryDNS(name string, queryType dnsmessage.Type) (res []byte, resolvers []*dnstype.Resolver, err error) { func (b *LocalBackend) QueryDNS(name string, queryType dnsmessage.Type) (res []byte, resolvers []*dnstype.Resolver, err error) {
if !buildfeatures.HasDNS {
return nil, nil, feature.ErrUnavailable
}
manager, ok := b.sys.DNSManager.GetOK() manager, ok := b.sys.DNSManager.GetOK()
if !ok { if !ok {
return nil, nil, errors.New("DNS manager not available") return nil, nil, errors.New("DNS manager not available")
@ -6189,6 +6195,9 @@ func (b *LocalBackend) TestOnlyPublicKeys() (machineKey key.MachinePublic, nodeK
// This is the low-level interface. Other layers will provide more // This is the low-level interface. Other layers will provide more
// friendly options to get HTTPS certs. // friendly options to get HTTPS certs.
func (b *LocalBackend) SetDNS(ctx context.Context, name, value string) error { func (b *LocalBackend) SetDNS(ctx context.Context, name, value string) error {
if !buildfeatures.HasACME {
return feature.ErrUnavailable
}
req := &tailcfg.SetDNSRequest{ req := &tailcfg.SetDNSRequest{
Version: 1, // TODO(bradfitz,maisem): use tailcfg.CurrentCapabilityVersion when using the Noise transport Version: 1, // TODO(bradfitz,maisem): use tailcfg.CurrentCapabilityVersion when using the Noise transport
Type: "TXT", Type: "TXT",

View File

@ -12,6 +12,7 @@ import (
"sync/atomic" "sync/atomic"
"go4.org/netipx" "go4.org/netipx"
"tailscale.com/feature/buildfeatures"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
@ -630,6 +631,9 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, peers map[tailcfg.NodeID]tailcfg.
if nm == nil { if nm == nil {
return nil return nil
} }
if !buildfeatures.HasDNS {
return &dns.Config{}
}
// If the current node's key is expired, then we don't program any DNS // If the current node's key is expired, then we don't program any DNS
// configuration into the operating system. This ensures that if the // configuration into the operating system. This ensures that if the

View File

@ -26,6 +26,7 @@ import (
"golang.org/x/net/dns/dnsmessage" "golang.org/x/net/dns/dnsmessage"
"golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpguts"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/feature/buildfeatures"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/hostinfo" "tailscale.com/hostinfo"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
@ -636,6 +637,10 @@ func (h *peerAPIHandler) handleServeMetrics(w http.ResponseWriter, r *http.Reque
} }
func (h *peerAPIHandler) handleServeDNSFwd(w http.ResponseWriter, r *http.Request) { func (h *peerAPIHandler) handleServeDNSFwd(w http.ResponseWriter, r *http.Request) {
if !buildfeatures.HasDNS {
http.NotFound(w, r)
return
}
if !h.canDebug() { if !h.canDebug() {
http.Error(w, "denied; no debug access", http.StatusForbidden) http.Error(w, "denied; no debug access", http.StatusForbidden)
return return
@ -649,6 +654,9 @@ func (h *peerAPIHandler) handleServeDNSFwd(w http.ResponseWriter, r *http.Reques
} }
func (h *peerAPIHandler) replyToDNSQueries() bool { func (h *peerAPIHandler) replyToDNSQueries() bool {
if !buildfeatures.HasDNS {
return false
}
if h.isSelf { if h.isSelf {
// If the peer is owned by the same user, just allow it // If the peer is owned by the same user, just allow it
// without further checks. // without further checks.
@ -700,7 +708,7 @@ func (h *peerAPIHandler) replyToDNSQueries() bool {
// handleDNSQuery implements a DoH server (RFC 8484) over the peerapi. // handleDNSQuery implements a DoH server (RFC 8484) over the peerapi.
// It's not over HTTPS as the spec dictates, but rather HTTP-over-WireGuard. // It's not over HTTPS as the spec dictates, but rather HTTP-over-WireGuard.
func (h *peerAPIHandler) handleDNSQuery(w http.ResponseWriter, r *http.Request) { func (h *peerAPIHandler) handleDNSQuery(w http.ResponseWriter, r *http.Request) {
if h.ps.resolver == nil { if !buildfeatures.HasDNS || h.ps.resolver == nil {
http.Error(w, "DNS not wired up", http.StatusNotImplemented) http.Error(w, "DNS not wired up", http.StatusNotImplemented)
return return
} }

View File

@ -1916,6 +1916,10 @@ func (h *Handler) serveUpdateCheck(w http.ResponseWriter, r *http.Request) {
// serveDNSOSConfig serves the current system DNS configuration as a JSON object, if // serveDNSOSConfig serves the current system DNS configuration as a JSON object, if
// supported by the OS. // supported by the OS.
func (h *Handler) serveDNSOSConfig(w http.ResponseWriter, r *http.Request) { func (h *Handler) serveDNSOSConfig(w http.ResponseWriter, r *http.Request) {
if !buildfeatures.HasDNS {
http.NotFound(w, r)
return
}
if r.Method != httpm.GET { if r.Method != httpm.GET {
http.Error(w, "only GET allowed", http.StatusMethodNotAllowed) http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
return return
@ -1959,6 +1963,10 @@ func (h *Handler) serveDNSOSConfig(w http.ResponseWriter, r *http.Request) {
// //
// The response if successful is a DNSQueryResponse JSON object. // The response if successful is a DNSQueryResponse JSON object.
func (h *Handler) serveDNSQuery(w http.ResponseWriter, r *http.Request) { func (h *Handler) serveDNSQuery(w http.ResponseWriter, r *http.Request) {
if !buildfeatures.HasDNS {
http.NotFound(w, r)
return
}
if r.Method != httpm.GET { if r.Method != httpm.GET {
http.Error(w, "only GET allowed", http.StatusMethodNotAllowed) http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
return return

View File

@ -20,6 +20,7 @@ import (
"time" "time"
"tailscale.com/control/controlknobs" "tailscale.com/control/controlknobs"
"tailscale.com/feature/buildfeatures"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/net/dns/resolver" "tailscale.com/net/dns/resolver"
"tailscale.com/net/netmon" "tailscale.com/net/netmon"
@ -71,6 +72,9 @@ type Manager struct {
// //
// knobs may be nil. // knobs may be nil.
func NewManager(logf logger.Logf, oscfg OSConfigurator, health *health.Tracker, dialer *tsdial.Dialer, linkSel resolver.ForwardLinkSelector, knobs *controlknobs.Knobs, goos string) *Manager { func NewManager(logf logger.Logf, oscfg OSConfigurator, health *health.Tracker, dialer *tsdial.Dialer, linkSel resolver.ForwardLinkSelector, knobs *controlknobs.Knobs, goos string) *Manager {
if !buildfeatures.HasDNS {
return nil
}
if dialer == nil { if dialer == nil {
panic("nil Dialer") panic("nil Dialer")
} }
@ -97,7 +101,12 @@ func NewManager(logf logger.Logf, oscfg OSConfigurator, health *health.Tracker,
} }
// Resolver returns the Manager's DNS Resolver. // Resolver returns the Manager's DNS Resolver.
func (m *Manager) Resolver() *resolver.Resolver { return m.resolver } func (m *Manager) Resolver() *resolver.Resolver {
if !buildfeatures.HasDNS {
return nil
}
return m.resolver
}
// RecompileDNSConfig recompiles the last attempted DNS configuration, which has // RecompileDNSConfig recompiles the last attempted DNS configuration, which has
// the side effect of re-querying the OS's interface nameservers. This should be used // the side effect of re-querying the OS's interface nameservers. This should be used
@ -111,6 +120,9 @@ func (m *Manager) Resolver() *resolver.Resolver { return m.resolver }
// //
// It returns [ErrNoDNSConfig] if [Manager.Set] has never been called. // It returns [ErrNoDNSConfig] if [Manager.Set] has never been called.
func (m *Manager) RecompileDNSConfig() error { func (m *Manager) RecompileDNSConfig() error {
if !buildfeatures.HasDNS {
return nil
}
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
if m.config != nil { if m.config != nil {
@ -120,6 +132,9 @@ func (m *Manager) RecompileDNSConfig() error {
} }
func (m *Manager) Set(cfg Config) error { func (m *Manager) Set(cfg Config) error {
if !buildfeatures.HasDNS {
return nil
}
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
return m.setLocked(cfg) return m.setLocked(cfg)
@ -127,6 +142,9 @@ func (m *Manager) Set(cfg Config) error {
// GetBaseConfig returns the current base OS DNS configuration as provided by the OSConfigurator. // GetBaseConfig returns the current base OS DNS configuration as provided by the OSConfigurator.
func (m *Manager) GetBaseConfig() (OSConfig, error) { func (m *Manager) GetBaseConfig() (OSConfig, error) {
if !buildfeatures.HasDNS {
panic("unreachable")
}
return m.os.GetBaseConfig() return m.os.GetBaseConfig()
} }
@ -559,6 +577,9 @@ func (m *Manager) HandleTCPConn(conn net.Conn, srcAddr netip.AddrPort) {
} }
func (m *Manager) Down() error { func (m *Manager) Down() error {
if !buildfeatures.HasDNS {
return nil
}
m.ctxCancel() m.ctxCancel()
if err := m.os.Close(); err != nil { if err := m.os.Close(); err != nil {
return err return err
@ -568,6 +589,9 @@ func (m *Manager) Down() error {
} }
func (m *Manager) FlushCaches() error { func (m *Manager) FlushCaches() error {
if !buildfeatures.HasDNS {
return nil
}
return flushCaches() return flushCaches()
} }
@ -577,6 +601,9 @@ func (m *Manager) FlushCaches() error {
// //
// health must not be nil // health must not be nil
func CleanUp(logf logger.Logf, netMon *netmon.Monitor, health *health.Tracker, interfaceName string) { func CleanUp(logf logger.Logf, netMon *netmon.Monitor, health *health.Tracker, interfaceName string) {
if !buildfeatures.HasDNS {
return
}
oscfg, err := NewOSConfigurator(logf, health, policyclient.Get(), nil, interfaceName) oscfg, err := NewOSConfigurator(logf, health, policyclient.Get(), nil, interfaceName)
if err != nil { if err != nil {
logf("creating dns cleanup: %v", err) logf("creating dns cleanup: %v", err)

View File

@ -16,6 +16,7 @@ import (
"tailscale.com/control/controlknobs" "tailscale.com/control/controlknobs"
"tailscale.com/feature" "tailscale.com/feature"
"tailscale.com/feature/buildfeatures"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -63,7 +64,7 @@ var (
// //
// The health tracker may be nil; the knobs may be nil and are ignored on this platform. // The health tracker may be nil; the knobs may be nil and are ignored on this platform.
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, _ policyclient.Client, _ *controlknobs.Knobs, interfaceName string) (ret OSConfigurator, err error) { func NewOSConfigurator(logf logger.Logf, health *health.Tracker, _ policyclient.Client, _ *controlknobs.Knobs, interfaceName string) (ret OSConfigurator, err error) {
if distro.Get() == distro.JetKVM { if !buildfeatures.HasDNS || distro.Get() == distro.JetKVM {
return NewNoopManager() return NewNoopManager()
} }

View File

@ -11,6 +11,7 @@ import (
"slices" "slices"
"strings" "strings"
"tailscale.com/feature/buildfeatures"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
) )
@ -158,6 +159,10 @@ func (a OSConfig) Equal(b OSConfig) bool {
// Fixes https://github.com/tailscale/tailscale/issues/5669 // Fixes https://github.com/tailscale/tailscale/issues/5669
func (a OSConfig) Format(f fmt.State, verb rune) { func (a OSConfig) Format(f fmt.State, verb rune) {
logger.ArgWriter(func(w *bufio.Writer) { logger.ArgWriter(func(w *bufio.Writer) {
if !buildfeatures.HasDNS {
w.WriteString(`{DNS-unlinked}`)
return
}
w.WriteString(`{Nameservers:[`) w.WriteString(`{Nameservers:[`)
for i, ns := range a.Nameservers { for i, ns := range a.Nameservers {
if i != 0 { if i != 0 {

View File

@ -17,6 +17,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"tailscale.com/feature/buildfeatures"
) )
// dohOfIP maps from public DNS IPs to their DoH base URL. // dohOfIP maps from public DNS IPs to their DoH base URL.
@ -163,6 +165,9 @@ const (
// populate is called once to initialize the knownDoH and dohIPsOfBase maps. // populate is called once to initialize the knownDoH and dohIPsOfBase maps.
func populate() { func populate() {
if !buildfeatures.HasDNS {
return
}
// Cloudflare // Cloudflare
// https://developers.cloudflare.com/1.1.1.1/ip-addresses/ // https://developers.cloudflare.com/1.1.1.1/ip-addresses/
addDoH("1.1.1.1", "https://cloudflare-dns.com/dns-query") addDoH("1.1.1.1", "https://cloudflare-dns.com/dns-query")

View File

@ -12,10 +12,14 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"tailscale.com/feature/buildfeatures"
"tailscale.com/health" "tailscale.com/health"
) )
func init() { func init() {
if !buildfeatures.HasDNS {
return
}
health.RegisterDebugHandler("dnsfwd", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { health.RegisterDebugHandler("dnsfwd", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
n, _ := strconv.Atoi(r.FormValue("n")) n, _ := strconv.Atoi(r.FormValue("n"))
if n <= 0 { if n <= 0 {

View File

@ -27,6 +27,7 @@ import (
dns "golang.org/x/net/dns/dnsmessage" dns "golang.org/x/net/dns/dnsmessage"
"tailscale.com/control/controlknobs" "tailscale.com/control/controlknobs"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/feature/buildfeatures"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/net/dns/publicdns" "tailscale.com/net/dns/publicdns"
"tailscale.com/net/dnscache" "tailscale.com/net/dnscache"
@ -249,6 +250,9 @@ type forwarder struct {
} }
func newForwarder(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, health *health.Tracker, knobs *controlknobs.Knobs) *forwarder { func newForwarder(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, health *health.Tracker, knobs *controlknobs.Knobs) *forwarder {
if !buildfeatures.HasDNS {
return nil
}
if netMon == nil { if netMon == nil {
panic("nil netMon") panic("nil netMon")
} }
@ -750,6 +754,9 @@ var optDNSForwardUseRoutes = envknob.RegisterOptBool("TS_DEBUG_DNS_FORWARD_USE_R
// //
// See tailscale/tailscale#12027. // See tailscale/tailscale#12027.
func ShouldUseRoutes(knobs *controlknobs.Knobs) bool { func ShouldUseRoutes(knobs *controlknobs.Knobs) bool {
if !buildfeatures.HasDNS {
return false
}
switch runtime.GOOS { switch runtime.GOOS {
case "android", "ios": case "android", "ios":
// On mobile platforms with lower memory limits (e.g., 50MB on iOS), // On mobile platforms with lower memory limits (e.g., 50MB on iOS),

View File

@ -25,6 +25,8 @@ import (
dns "golang.org/x/net/dns/dnsmessage" dns "golang.org/x/net/dns/dnsmessage"
"tailscale.com/control/controlknobs" "tailscale.com/control/controlknobs"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/feature"
"tailscale.com/feature/buildfeatures"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/net/dns/resolvconffile" "tailscale.com/net/dns/resolvconffile"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
@ -254,6 +256,9 @@ func New(logf logger.Logf, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, h
func (r *Resolver) TestOnlySetHook(hook func(Config)) { r.saveConfigForTests = hook } func (r *Resolver) TestOnlySetHook(hook func(Config)) { r.saveConfigForTests = hook }
func (r *Resolver) SetConfig(cfg Config) error { func (r *Resolver) SetConfig(cfg Config) error {
if !buildfeatures.HasDNS {
return nil
}
if r.saveConfigForTests != nil { if r.saveConfigForTests != nil {
r.saveConfigForTests(cfg) r.saveConfigForTests(cfg)
} }
@ -279,6 +284,9 @@ func (r *Resolver) SetConfig(cfg Config) error {
// Close shuts down the resolver and ensures poll goroutines have exited. // Close shuts down the resolver and ensures poll goroutines have exited.
// The Resolver cannot be used again after Close is called. // The Resolver cannot be used again after Close is called.
func (r *Resolver) Close() { func (r *Resolver) Close() {
if !buildfeatures.HasDNS {
return
}
select { select {
case <-r.closed: case <-r.closed:
return return
@ -296,6 +304,9 @@ func (r *Resolver) Close() {
const dnsQueryTimeout = 10 * time.Second const dnsQueryTimeout = 10 * time.Second
func (r *Resolver) Query(ctx context.Context, bs []byte, family string, from netip.AddrPort) ([]byte, error) { func (r *Resolver) Query(ctx context.Context, bs []byte, family string, from netip.AddrPort) ([]byte, error) {
if !buildfeatures.HasDNS {
return nil, feature.ErrUnavailable
}
metricDNSQueryLocal.Add(1) metricDNSQueryLocal.Add(1)
select { select {
case <-r.closed: case <-r.closed:
@ -323,6 +334,9 @@ func (r *Resolver) Query(ctx context.Context, bs []byte, family string, from net
// GetUpstreamResolvers returns the resolvers that would be used to resolve // GetUpstreamResolvers returns the resolvers that would be used to resolve
// the given FQDN. // the given FQDN.
func (r *Resolver) GetUpstreamResolvers(name dnsname.FQDN) []*dnstype.Resolver { func (r *Resolver) GetUpstreamResolvers(name dnsname.FQDN) []*dnstype.Resolver {
if !buildfeatures.HasDNS {
return nil
}
return r.forwarder.GetUpstreamResolvers(name) return r.forwarder.GetUpstreamResolvers(name)
} }
@ -351,6 +365,9 @@ func parseExitNodeQuery(q []byte) *response {
// and a nil error. // and a nil error.
// TODO: figure out if we even need an error result. // TODO: figure out if we even need an error result.
func (r *Resolver) HandlePeerDNSQuery(ctx context.Context, q []byte, from netip.AddrPort, allowName func(name string) bool) (res []byte, err error) { func (r *Resolver) HandlePeerDNSQuery(ctx context.Context, q []byte, from netip.AddrPort, allowName func(name string) bool) (res []byte, err error) {
if !buildfeatures.HasDNS {
return nil, feature.ErrUnavailable
}
metricDNSExitProxyQuery.Add(1) metricDNSExitProxyQuery.Add(1)
ch := make(chan packet, 1) ch := make(chan packet, 1)
@ -427,6 +444,9 @@ var debugExitNodeDNSNetPkg = envknob.RegisterBool("TS_DEBUG_EXIT_NODE_DNS_NET_PK
// response contains the pre-serialized response, which notably // response contains the pre-serialized response, which notably
// includes the original question and its header. // includes the original question and its header.
func handleExitNodeDNSQueryWithNetPkg(ctx context.Context, logf logger.Logf, resolver *net.Resolver, resp *response) (res []byte, err error) { func handleExitNodeDNSQueryWithNetPkg(ctx context.Context, logf logger.Logf, resolver *net.Resolver, resp *response) (res []byte, err error) {
if !buildfeatures.HasDNS {
return nil, feature.ErrUnavailable
}
logf = logger.WithPrefix(logf, "exitNodeDNSQueryWithNetPkg: ") logf = logger.WithPrefix(logf, "exitNodeDNSQueryWithNetPkg: ")
if resp.Question.Class != dns.ClassINET { if resp.Question.Class != dns.ClassINET {
return nil, errors.New("unsupported class") return nil, errors.New("unsupported class")
@ -1247,6 +1267,9 @@ func (r *Resolver) respondReverse(query []byte, name dnsname.FQDN, resp *respons
// respond returns a DNS response to query if it can be resolved locally. // respond returns a DNS response to query if it can be resolved locally.
// Otherwise, it returns errNotOurName. // Otherwise, it returns errNotOurName.
func (r *Resolver) respond(query []byte) ([]byte, error) { func (r *Resolver) respond(query []byte) ([]byte, error) {
if !buildfeatures.HasDNS {
return nil, feature.ErrUnavailable
}
parser := dnsParserPool.Get().(*dnsParser) parser := dnsParserPool.Get().(*dnsParser)
defer dnsParserPool.Put(parser) defer dnsParserPool.Put(parser)