coredns/plugin/k8s_external/apex.go
TomasKohout 6782b7fb42
plugin/k8s_external: Resolve headless services (#5505)
*add option for resolving headless Services without external IPs in k8s_external

Signed-off-by: Tomas Kohout <tomas.kohout1995@gmail.com>
2022-08-30 14:59:27 -04:00

112 lines
2.8 KiB
Go

package external
import (
"github.com/coredns/coredns/plugin/pkg/dnsutil"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
// serveApex serves request that hit the zone' apex. A reply is written back to the client.
func (e *External) serveApex(state request.Request) (int, error) {
m := new(dns.Msg)
m.SetReply(state.Req)
m.Authoritative = true
switch state.QType() {
case dns.TypeSOA:
m.Answer = []dns.RR{e.soa(state)}
case dns.TypeNS:
m.Answer = []dns.RR{e.ns(state)}
addr := e.externalAddrFunc(state, e.headless)
for _, rr := range addr {
rr.Header().Ttl = e.ttl
rr.Header().Name = dnsutil.Join("ns1", e.apex, state.QName())
m.Extra = append(m.Extra, rr)
}
default:
m.Ns = []dns.RR{e.soa(state)}
}
state.W.WriteMsg(m)
return 0, nil
}
// serveSubApex serves requests that hit the zones fake 'dns' subdomain where our nameservers live.
func (e *External) serveSubApex(state request.Request) (int, error) {
base, _ := dnsutil.TrimZone(state.Name(), state.Zone)
m := new(dns.Msg)
m.SetReply(state.Req)
m.Authoritative = true
// base is either dns. of ns1.dns (or another name), if it's longer return nxdomain
switch labels := dns.CountLabel(base); labels {
default:
m.SetRcode(m, dns.RcodeNameError)
m.Ns = []dns.RR{e.soa(state)}
state.W.WriteMsg(m)
return 0, nil
case 2:
nl, _ := dns.NextLabel(base, 0)
ns := base[:nl]
if ns != "ns1." {
// nxdomain
m.SetRcode(m, dns.RcodeNameError)
m.Ns = []dns.RR{e.soa(state)}
state.W.WriteMsg(m)
return 0, nil
}
addr := e.externalAddrFunc(state, e.headless)
for _, rr := range addr {
rr.Header().Ttl = e.ttl
rr.Header().Name = state.QName()
switch state.QType() {
case dns.TypeA:
if rr.Header().Rrtype == dns.TypeA {
m.Answer = append(m.Answer, rr)
}
case dns.TypeAAAA:
if rr.Header().Rrtype == dns.TypeAAAA {
m.Answer = append(m.Answer, rr)
}
}
}
if len(m.Answer) == 0 {
m.Ns = []dns.RR{e.soa(state)}
}
state.W.WriteMsg(m)
return 0, nil
case 1:
// nodata for the dns empty non-terminal
m.Ns = []dns.RR{e.soa(state)}
state.W.WriteMsg(m)
return 0, nil
}
}
func (e *External) soa(state request.Request) *dns.SOA {
header := dns.RR_Header{Name: state.Zone, Rrtype: dns.TypeSOA, Ttl: e.ttl, Class: dns.ClassINET}
soa := &dns.SOA{Hdr: header,
Mbox: dnsutil.Join(e.hostmaster, e.apex, state.Zone),
Ns: dnsutil.Join("ns1", e.apex, state.Zone),
Serial: e.externalSerialFunc(state.Zone),
Refresh: 7200,
Retry: 1800,
Expire: 86400,
Minttl: e.ttl,
}
return soa
}
func (e *External) ns(state request.Request) *dns.NS {
header := dns.RR_Header{Name: state.Zone, Rrtype: dns.TypeNS, Ttl: e.ttl, Class: dns.ClassINET}
ns := &dns.NS{Hdr: header, Ns: dnsutil.Join("ns1", e.apex, state.Zone)}
return ns
}