diff options
Diffstat (limited to 'plugin/k8s_external/transfer.go')
-rw-r--r-- | plugin/k8s_external/transfer.go | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/plugin/k8s_external/transfer.go b/plugin/k8s_external/transfer.go new file mode 100644 index 000000000..9c2c231f9 --- /dev/null +++ b/plugin/k8s_external/transfer.go @@ -0,0 +1,97 @@ +package external + +import ( + "context" + + "github.com/coredns/coredns/plugin" + "github.com/coredns/coredns/plugin/etcd/msg" + "github.com/coredns/coredns/plugin/transfer" + "github.com/coredns/coredns/request" + + "github.com/miekg/dns" +) + +// Transfer implements transfer.Transferer +func (e *External) Transfer(zone string, serial uint32) (<-chan []dns.RR, error) { + z := plugin.Zones(e.Zones).Matches(zone) + if z != zone { + return nil, transfer.ErrNotAuthoritative + } + + ctx := context.Background() + ch := make(chan []dns.RR, 2) + if zone == "." { + zone = "" + } + state := request.Request{Zone: zone} + + // SOA + soa := e.soa(state) + ch <- []dns.RR{soa} + if serial != 0 && serial >= soa.Serial { + close(ch) + return ch, nil + } + + go func() { + // Add NS + nsName := "ns1." + e.apex + "." + zone + nsHdr := dns.RR_Header{Name: zone, Rrtype: dns.TypeNS, Ttl: e.ttl, Class: dns.ClassINET} + ch <- []dns.RR{&dns.NS{Hdr: nsHdr, Ns: nsName}} + + // Add Nameserver A/AAAA records + nsRecords := e.externalAddrFunc(state) + for i := range nsRecords { + // externalAddrFunc returns incomplete header names, correct here + nsRecords[i].Header().Name = nsName + nsRecords[i].Header().Ttl = e.ttl + ch <- []dns.RR{nsRecords[i]} + } + + svcs := e.externalServicesFunc(zone) + srvSeen := make(map[string]struct{}) + for i := range svcs { + name := msg.Domain(svcs[i].Key) + if svcs[i].TargetStrip == 0 { + // Add Service A/AAAA records + s := request.Request{Req: &dns.Msg{Question: []dns.Question{{Name: name}}}} + as := e.a(ctx, []msg.Service{svcs[i]}, s) + if len(as) > 0 { + ch <- as + } + aaaas := e.aaaa(ctx, []msg.Service{svcs[i]}, s) + if len(aaaas) > 0 { + ch <- aaaas + } + // Add bare SRV record, ensuring uniqueness + recs, _ := e.srv(ctx, []msg.Service{svcs[i]}, s) + for _, srv := range recs { + if !nameSeen(srvSeen, srv) { + ch <- []dns.RR{srv} + } + } + continue + } + // Add full SRV record, ensuring uniqueness + s := request.Request{Req: &dns.Msg{Question: []dns.Question{{Name: name}}}} + recs, _ := e.srv(ctx, []msg.Service{svcs[i]}, s) + for _, srv := range recs { + if !nameSeen(srvSeen, srv) { + ch <- []dns.RR{srv} + } + } + } + ch <- []dns.RR{soa} + close(ch) + }() + + return ch, nil +} + +func nameSeen(namesSeen map[string]struct{}, rr dns.RR) bool { + if _, duplicate := namesSeen[rr.Header().Name]; duplicate { + return true + } + namesSeen[rr.Header().Name] = struct{}{} + return false +} |