| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | /* | 
					
						
							|  |  |  | Package external implements external names for kubernetes clusters. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This plugin only handles three qtypes (except the apex queries, because those are handled | 
					
						
							|  |  |  | differently). We support A, AAAA and SRV request, for all other types we return NODATA or | 
					
						
							|  |  |  | NXDOMAIN depending on the state of the cluster. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A plugin willing to provide these services must implement the Externaler interface, although it | 
					
						
							|  |  |  | likely only makes sense for the *kubernetes* plugin. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | package external | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/plugin" | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/plugin/etcd/msg" | 
					
						
							| 
									
										
										
										
											2023-03-24 20:52:44 +08:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/fall" | 
					
						
							| 
									
										
										
										
											2020-05-29 10:04:23 -07:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/upstream" | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 	"github.com/coredns/coredns/request" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Externaler defines the interface that a plugin should implement in order to be used by External. | 
					
						
							|  |  |  | type Externaler interface { | 
					
						
							|  |  |  | 	// External returns a slice of msg.Services that are looked up in the backend and match | 
					
						
							|  |  |  | 	// the request. | 
					
						
							| 
									
										
										
										
											2022-08-30 20:59:27 +02:00
										 |  |  | 	External(request.Request, bool) ([]msg.Service, int) | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 	// ExternalAddress should return a string slice of addresses for the nameserving endpoint. | 
					
						
							| 
									
										
										
										
											2022-08-30 20:59:27 +02:00
										 |  |  | 	ExternalAddress(state request.Request, headless bool) []dns.RR | 
					
						
							|  |  |  | 	// ExternalServices returns all services in the given zone as a slice of msg.Service and if enabled, headless services as a map of services. | 
					
						
							|  |  |  | 	ExternalServices(zone string, headless bool) ([]msg.Service, map[string][]msg.Service) | 
					
						
							| 
									
										
										
										
											2022-03-07 12:16:24 -05:00
										 |  |  | 	// ExternalSerial gets the current serial. | 
					
						
							|  |  |  | 	ExternalSerial(string) uint32 | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-07 12:16:24 -05:00
										 |  |  | // External serves records for External IPs and Loadbalance IPs of Services in Kubernetes clusters. | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | type External struct { | 
					
						
							|  |  |  | 	Next  plugin.Handler | 
					
						
							|  |  |  | 	Zones []string | 
					
						
							| 
									
										
										
										
											2023-03-24 20:52:44 +08:00
										 |  |  | 	Fall  fall.F | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-05 10:29:36 +00:00
										 |  |  | 	hostmaster string | 
					
						
							|  |  |  | 	apex       string | 
					
						
							|  |  |  | 	ttl        uint32 | 
					
						
							|  |  |  | 	headless   bool | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-29 10:04:23 -07:00
										 |  |  | 	upstream *upstream.Upstream | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-30 20:59:27 +02:00
										 |  |  | 	externalFunc         func(request.Request, bool) ([]msg.Service, int) | 
					
						
							|  |  |  | 	externalAddrFunc     func(request.Request, bool) []dns.RR | 
					
						
							| 
									
										
										
										
											2022-03-07 12:16:24 -05:00
										 |  |  | 	externalSerialFunc   func(string) uint32 | 
					
						
							| 
									
										
										
										
											2022-08-30 20:59:27 +02:00
										 |  |  | 	externalServicesFunc func(string, bool) ([]msg.Service, map[string][]msg.Service) | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // New returns a new and initialized *External. | 
					
						
							|  |  |  | func New() *External { | 
					
						
							|  |  |  | 	e := &External{hostmaster: "hostmaster", ttl: 5, apex: "dns"} | 
					
						
							|  |  |  | 	return e | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ServeDNS implements the plugin.Handle interface. | 
					
						
							|  |  |  | func (e *External) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { | 
					
						
							|  |  |  | 	state := request.Request{W: w, Req: r} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	zone := plugin.Zones(e.Zones).Matches(state.Name()) | 
					
						
							|  |  |  | 	if zone == "" { | 
					
						
							|  |  |  | 		return plugin.NextOrFailure(e.Name(), e.Next, ctx, w, r) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	state.Zone = zone | 
					
						
							|  |  |  | 	for _, z := range e.Zones { | 
					
						
							|  |  |  | 		// TODO(miek): save this in the External struct. | 
					
						
							|  |  |  | 		if state.Name() == z { // apex query | 
					
						
							|  |  |  | 			ret, err := e.serveApex(state) | 
					
						
							|  |  |  | 			return ret, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if dns.IsSubDomain(e.apex+"."+z, state.Name()) { | 
					
						
							|  |  |  | 			// dns subdomain test for ns. and dns. queries | 
					
						
							|  |  |  | 			ret, err := e.serveSubApex(state) | 
					
						
							|  |  |  | 			return ret, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-30 20:59:27 +02:00
										 |  |  | 	svc, rcode := e.externalFunc(state, e.headless) | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	m := new(dns.Msg) | 
					
						
							|  |  |  | 	m.SetReply(state.Req) | 
					
						
							| 
									
										
										
										
											2022-04-12 11:01:15 -04:00
										 |  |  | 	m.Authoritative = true | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if len(svc) == 0 { | 
					
						
							| 
									
										
										
										
											2023-03-24 20:52:44 +08:00
										 |  |  | 		if e.Fall.Through(state.Name()) && rcode == dns.RcodeNameError { | 
					
						
							|  |  |  | 			return plugin.NextOrFailure(e.Name(), e.Next, ctx, w, r) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 		m.Rcode = rcode | 
					
						
							|  |  |  | 		m.Ns = []dns.RR{e.soa(state)} | 
					
						
							|  |  |  | 		w.WriteMsg(m) | 
					
						
							|  |  |  | 		return 0, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch state.QType() { | 
					
						
							|  |  |  | 	case dns.TypeA: | 
					
						
							| 
									
										
										
										
											2022-03-25 13:50:23 -04:00
										 |  |  | 		m.Answer, m.Truncated = e.a(ctx, svc, state) | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 	case dns.TypeAAAA: | 
					
						
							| 
									
										
										
										
											2022-03-25 13:50:23 -04:00
										 |  |  | 		m.Answer, m.Truncated = e.aaaa(ctx, svc, state) | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 	case dns.TypeSRV: | 
					
						
							| 
									
										
										
										
											2021-10-27 16:59:21 +03:00
										 |  |  | 		m.Answer, m.Extra = e.srv(ctx, svc, state) | 
					
						
							| 
									
										
										
										
											2022-07-06 13:55:15 -04:00
										 |  |  | 	case dns.TypePTR: | 
					
						
							|  |  |  | 		m.Answer = e.ptr(svc, state) | 
					
						
							| 
									
										
										
										
											2018-12-14 09:41:51 +00:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		m.Ns = []dns.RR{e.soa(state)} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If we did have records, but queried for the wrong qtype return a nodata response. | 
					
						
							|  |  |  | 	if len(m.Answer) == 0 { | 
					
						
							|  |  |  | 		m.Ns = []dns.RR{e.soa(state)} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.WriteMsg(m) | 
					
						
							|  |  |  | 	return 0, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Name implements the Handler interface. | 
					
						
							|  |  |  | func (e *External) Name() string { return "k8s_external" } |