coredns/plugin/k8s_external/msg_to_dns.go
2022-07-10 11:06:33 -07:00

190 lines
4.9 KiB
Go

package external
import (
"context"
"math"
"github.com/coredns/coredns/plugin/etcd/msg"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
func (e *External) a(ctx context.Context, services []msg.Service, state request.Request) (records []dns.RR, truncated bool) {
dup := make(map[string]struct{})
for _, s := range services {
what, ip := s.HostType()
switch what {
case dns.TypeCNAME:
rr := s.NewCNAME(state.QName(), s.Host)
records = append(records, rr)
if resp, err := e.upstream.Lookup(ctx, state, dns.Fqdn(s.Host), dns.TypeA); err == nil {
records = append(records, resp.Answer...)
if resp.Truncated {
truncated = true
}
}
case dns.TypeA:
if _, ok := dup[s.Host]; !ok {
dup[s.Host] = struct{}{}
rr := s.NewA(state.QName(), ip)
rr.Hdr.Ttl = e.ttl
records = append(records, rr)
}
case dns.TypeAAAA:
// nada
}
}
return records, truncated
}
func (e *External) aaaa(ctx context.Context, services []msg.Service, state request.Request) (records []dns.RR, truncated bool) {
dup := make(map[string]struct{})
for _, s := range services {
what, ip := s.HostType()
switch what {
case dns.TypeCNAME:
rr := s.NewCNAME(state.QName(), s.Host)
records = append(records, rr)
if resp, err := e.upstream.Lookup(ctx, state, dns.Fqdn(s.Host), dns.TypeAAAA); err == nil {
records = append(records, resp.Answer...)
if resp.Truncated {
truncated = true
}
}
case dns.TypeA:
// nada
case dns.TypeAAAA:
if _, ok := dup[s.Host]; !ok {
dup[s.Host] = struct{}{}
rr := s.NewAAAA(state.QName(), ip)
rr.Hdr.Ttl = e.ttl
records = append(records, rr)
}
}
}
return records, truncated
}
func (e *External) ptr(services []msg.Service, state request.Request) (records []dns.RR) {
dup := make(map[string]struct{})
for _, s := range services {
if _, ok := dup[s.Host]; !ok {
dup[s.Host] = struct{}{}
rr := s.NewPTR(state.QName(), dnsutil.Join(s.Host, e.Zones[0]))
rr.Hdr.Ttl = e.ttl
records = append(records, rr)
}
}
return records
}
func (e *External) srv(ctx context.Context, services []msg.Service, state request.Request) (records, extra []dns.RR) {
dup := make(map[item]struct{})
// Looping twice to get the right weight vs priority. This might break because we may drop duplicate SRV records latter on.
w := make(map[int]int)
for _, s := range services {
weight := 100
if s.Weight != 0 {
weight = s.Weight
}
if _, ok := w[s.Priority]; !ok {
w[s.Priority] = weight
continue
}
w[s.Priority] += weight
}
for _, s := range services {
// Don't add the entry if the port is -1 (invalid). The kubernetes plugin uses port -1 when a service/endpoint
// does not have any declared ports.
if s.Port == -1 {
continue
}
w1 := 100.0 / float64(w[s.Priority])
if s.Weight == 0 {
w1 *= 100
} else {
w1 *= float64(s.Weight)
}
weight := uint16(math.Floor(w1))
// weight should be at least 1
if weight == 0 {
weight = 1
}
what, ip := s.HostType()
switch what {
case dns.TypeCNAME:
addr := dns.Fqdn(s.Host)
srv := s.NewSRV(state.QName(), weight)
if ok := isDuplicate(dup, srv.Target, "", srv.Port); !ok {
records = append(records, srv)
}
if ok := isDuplicate(dup, srv.Target, addr, 0); !ok {
if resp, err := e.upstream.Lookup(ctx, state, addr, dns.TypeA); err == nil {
extra = append(extra, resp.Answer...)
}
if resp, err := e.upstream.Lookup(ctx, state, addr, dns.TypeAAAA); err == nil {
extra = append(extra, resp.Answer...)
}
}
case dns.TypeA, dns.TypeAAAA:
addr := s.Host
s.Host = msg.Domain(s.Key)
srv := s.NewSRV(state.QName(), weight)
if ok := isDuplicate(dup, srv.Target, "", srv.Port); !ok {
records = append(records, srv)
}
if ok := isDuplicate(dup, srv.Target, addr, 0); !ok {
hdr := dns.RR_Header{Name: srv.Target, Rrtype: what, Class: dns.ClassINET, Ttl: e.ttl}
switch what {
case dns.TypeA:
extra = append(extra, &dns.A{Hdr: hdr, A: ip})
case dns.TypeAAAA:
extra = append(extra, &dns.AAAA{Hdr: hdr, AAAA: ip})
}
}
}
}
return records, extra
}
// not sure if this is even needed.
// item holds records.
type item struct {
name string // name of the record (either owner or something else unique).
port uint16 // port of the record (used for address records, A and AAAA).
addr string // address of the record (A and AAAA).
}
// isDuplicate uses m to see if the combo (name, addr, port) already exists. If it does
// not exist already IsDuplicate will also add the record to the map.
func isDuplicate(m map[item]struct{}, name, addr string, port uint16) bool {
if addr != "" {
_, ok := m[item{name, 0, addr}]
if !ok {
m[item{name, 0, addr}] = struct{}{}
}
return ok
}
_, ok := m[item{name, port, ""}]
if !ok {
m[item{name, port, ""}] = struct{}{}
}
return ok
}