Skip to content

Commit 83c494a

Browse files
committed
fix(dns): preserve canonical names during search resolution
Return NXDOMAIN for search-expanded external candidates so libc reaches the absolute query instead of accepting a synthesized search name. Restore mapped answer owners for direct service rewrites and cover wildcard, multi-answer, CNAME, and TCP fallback paths.
1 parent af7fd5b commit 83c494a

2 files changed

Lines changed: 428 additions & 34 deletions

File tree

pkg/dns/handler.go

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,20 @@ func (q *Question) String() string {
4141
// DNSHandler type
4242
type DNSHandler struct {
4343
requestChannel chan DNSOperationData
44-
resolver *Resolver
44+
resolver dnsResolver
4545
active bool
4646
muActive sync.RWMutex
4747
}
4848

49+
type dnsResolver interface {
50+
Lookup(net string, req *dns.Msg, timeout int, interval int, nameServers []string) (*dns.Msg, error)
51+
}
52+
53+
type questionNameRewrite struct {
54+
original string
55+
forwarded string
56+
}
57+
4958
// DNSOperationData type
5059
type DNSOperationData struct {
5160
Net string
@@ -55,13 +64,10 @@ type DNSOperationData struct {
5564

5665
// NewHandler returns a new DNSHandler
5766
func NewHandler(config *Config) *DNSHandler {
58-
var (
59-
clientConfig *dns.ClientConfig
60-
resolver *Resolver
61-
)
62-
63-
resolver = &Resolver{clientConfig}
67+
return newHandler(config, &Resolver{})
68+
}
6469

70+
func newHandler(config *Config, resolver dnsResolver) *DNSHandler {
6571
handler := &DNSHandler{
6672
requestChannel: make(chan DNSOperationData),
6773
resolver: resolver,
@@ -92,28 +98,39 @@ func (h *DNSHandler) getTrustDomainSearches(trustDomain, namespace string) []str
9298
return searches
9399
}
94100

95-
func (h *DNSHandler) getRawQName(qname, trustDomain string) (string, string) {
101+
func (h *DNSHandler) isClusterServiceQName(qname, trustDomain string) bool {
102+
prefix, found := strings.CutSuffix(qname, fmt.Sprintf(`.svc.%s.`, trustDomain))
103+
if !found {
104+
return false
105+
}
106+
sections := strings.Split(prefix, `.`)
107+
return len(sections) == 2 && k8sClient.GetK8sNamespace(sections[1]) != nil
108+
}
109+
110+
func (h *DNSHandler) getRawQName(qname, trustDomain string) (string, string, bool) {
96111
fromNamespace := `default`
112+
hadSearchSuffix := false
97113
suffixDomains := h.getSuffixDomains(trustDomain)
98114
for _, suffixDomain := range suffixDomains {
99-
if strings.HasSuffix(qname, suffixDomain) {
100-
qname = strings.TrimSuffix(qname, suffixDomain)
115+
if trimmedQName, found := strings.CutSuffix(qname, suffixDomain); found {
116+
hadSearchSuffix = true
117+
qname = trimmedQName
101118
sections := strings.Split(qname, `.`)
102119
ndots := len(sections)
103120
if ndots > 1 {
104121
fromNamespace = sections[len(sections)-1]
105122
searches := h.getTrustDomainSearches(trustDomain, fromNamespace)
106123
for _, search := range searches {
107-
if strings.HasSuffix(qname, search) {
108-
qname = strings.TrimSuffix(qname, search)
124+
if trimmedQName, found := strings.CutSuffix(qname, search); found {
125+
qname = trimmedQName
109126
break
110127
}
111128
}
112129
}
113130
break
114131
}
115132
}
116-
return strings.TrimSuffix(qname, `.`), fromNamespace
133+
return strings.TrimSuffix(qname, `.`), fromNamespace, hadSearchSuffix
117134
}
118135

119136
func (h *DNSHandler) do(cfg *Config) {
@@ -135,11 +152,15 @@ func (h *DNSHandler) do(cfg *Config) {
135152
remote = w.RemoteAddr().(*net.UDPAddr).IP
136153
}
137154

138-
var origQuestions []dns.Question
155+
var (
156+
origQuestions []dns.Question
157+
nameRewrites []questionNameRewrite
158+
continueDNSSearch bool
159+
)
139160

140161
for index, q := range req.Question {
141162
origQuestions = append(origQuestions, q)
142-
qname, fromNamespace := h.getRawQName(q.Name, trustDomain)
163+
qname, fromNamespace, hadSearchSuffix := h.getRawQName(q.Name, trustDomain)
143164
log.Debug().Msgf("%s lookup q.Name:%s qname:%s namespace:%s trustDomain:%s", remote, q.Name, qname, fromNamespace, trustDomain)
144165

145166
segs := strings.Split(qname, `.`)
@@ -155,6 +176,21 @@ func (h *DNSHandler) do(cfg *Config) {
155176
req.Question[index].Name = fmt.Sprintf(`%s.`, qname)
156177
}
157178
}
179+
nameRewrites = append(nameRewrites, questionNameRewrite{
180+
original: q.Name,
181+
forwarded: req.Question[index].Name,
182+
})
183+
if hadSearchSuffix && !h.isClusterServiceQName(q.Name, trustDomain) {
184+
continueDNSSearch = true
185+
}
186+
}
187+
188+
if continueDNSSearch {
189+
m := new(dns.Msg)
190+
m.SetRcode(req, dns.RcodeNameError)
191+
m.Question = origQuestions
192+
h.WriteReplyMsg(w, m)
193+
return
158194
}
159195

160196
q := req.Question[0]
@@ -179,8 +215,6 @@ func (h *DNSHandler) do(cfg *Config) {
179215
h.HandleFailed(w, req)
180216
return
181217
}
182-
resp.Question = origQuestions
183-
184218
if resp.Truncated && Net == "udp" {
185219
resp, err = h.resolver.Lookup("tcp", req, cfg.GetTimeout(), cfg.GetInterval(), cfg.GetNameservers())
186220
if err != nil {
@@ -194,25 +228,12 @@ func (h *DNSHandler) do(cfg *Config) {
194228

195229
if resp.Rcode == dns.RcodeNameError && cfg.IsWildcard() {
196230
req.Question = origQuestions
197-
h.HandleWildcard(req, cfg, ipQuery, &q, w)
231+
h.HandleWildcard(req, cfg, ipQuery, w)
198232
return
199233
}
200234

201-
if len(origQuestions) > 0 && len(origQuestions) >= len(resp.Answer) {
202-
for idx, rr := range resp.Answer {
203-
header := rr.Header()
204-
switch header.Rrtype {
205-
case dns.TypeA:
206-
a := rr.(*dns.A)
207-
a.Hdr.Name = origQuestions[idx].Name
208-
resp.Answer[idx] = a
209-
case dns.TypeAAAA:
210-
aaaa := rr.(*dns.AAAA)
211-
aaaa.Hdr.Name = origQuestions[idx].Name
212-
resp.Answer[idx] = aaaa
213-
}
214-
}
215-
}
235+
resp.Question = origQuestions
236+
restoreAnswerNames(resp.Answer, nameRewrites)
216237

217238
if dbs := cfg.GetWildcardResolveDB(); cfg.IsWildcard() && len(dbs) > 0 {
218239
los := cfg.GetLoopbackResolveDB()
@@ -282,9 +303,10 @@ func (h *DNSHandler) HandleFailed(w dns.ResponseWriter, req *dns.Msg) {
282303
h.WriteReplyMsg(w, m)
283304
}
284305

285-
func (h *DNSHandler) HandleWildcard(req *dns.Msg, cfg *Config, ipQuery int, q *dns.Question, w dns.ResponseWriter) {
306+
func (h *DNSHandler) HandleWildcard(req *dns.Msg, cfg *Config, ipQuery int, w dns.ResponseWriter) {
286307
m := new(dns.Msg)
287308
m.SetReply(req)
309+
q := req.Question[0]
288310

289311
if cfg.GetNXDomain() {
290312
m.SetRcode(req, dns.RcodeNameError)
@@ -326,6 +348,17 @@ func (h *DNSHandler) HandleWildcard(req *dns.Msg, cfg *Config, ipQuery int, q *d
326348
h.WriteReplyMsg(w, m)
327349
}
328350

351+
func restoreAnswerNames(answers []dns.RR, rewrites []questionNameRewrite) {
352+
for _, rr := range answers {
353+
for _, rewrite := range rewrites {
354+
if strings.EqualFold(rr.Header().Name, rewrite.forwarded) {
355+
rr.Header().Name = rewrite.original
356+
break
357+
}
358+
}
359+
}
360+
}
361+
329362
// WriteReplyMsg writes the dns reply
330363
func (h *DNSHandler) WriteReplyMsg(w dns.ResponseWriter, message *dns.Msg) {
331364
defer func() {

0 commit comments

Comments
 (0)