| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | package kubernetes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							|  |  |  | 	"github.com/coredns/coredns/middleware/pkg/dnsutil"
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | 	"github.com/coredns/coredns/request"
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type recordRequest struct {
 | 
					
						
							|  |  |  | 	// The named port from the kubernetes DNS spec, this is the service part (think _https) from a well formed
 | 
					
						
							|  |  |  | 	// SRV record.
 | 
					
						
							|  |  |  | 	port string
 | 
					
						
							|  |  |  | 	// The protocol is usually _udp or _tcp (if set), and comes from the protocol part of a well formed
 | 
					
						
							|  |  |  | 	// SRV record.
 | 
					
						
							|  |  |  | 	protocol  string
 | 
					
						
							|  |  |  | 	endpoint  string
 | 
					
						
							|  |  |  | 	service   string
 | 
					
						
							|  |  |  | 	namespace string
 | 
					
						
							|  |  |  | 	// A each name can be for a pod or a service, here we track what we've seen. This value is true for
 | 
					
						
							|  |  |  | 	// pods and false for services. If we ever need to extend this well use a typed value.
 | 
					
						
							|  |  |  | 	podOrSvc   string
 | 
					
						
							|  |  |  | 	zone       string
 | 
					
						
							|  |  |  | 	federation string
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | // parseRequest parses the qname to find all the elements we need for querying k8s.
 | 
					
						
							|  |  |  | func (k *Kubernetes) parseRequest(state request.Request) (r recordRequest, err error) {
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 	// 3 Possible cases
 | 
					
						
							|  |  |  | 	//   SRV Request: _port._protocol.service.namespace.[federation.]type.zone
 | 
					
						
							|  |  |  | 	//   A Request (endpoint): endpoint.service.namespace.[federation.]type.zone
 | 
					
						
							|  |  |  | 	//   A Request (service): service.namespace.[federation.]type.zone
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | 	base, _ := dnsutil.TrimZone(state.Name(), state.Zone)
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 	segs := dns.SplitDomainName(base)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | 	r.zone = state.Zone
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 	r.federation, segs = k.stripFederation(segs)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | 	if state.QType() == dns.TypeNS {
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 		return r, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | 	if state.QType() == dns.TypeA && isDefaultNS(state.Name(), r) {
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 		return r, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	offset := 0
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | 	if state.QType() == dns.TypeSRV {
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 		// The kubernetes peer-finder expects queries with empty port and service to resolve
 | 
					
						
							|  |  |  | 		// If neither is specified, treat it as a wildcard
 | 
					
						
							|  |  |  | 		if len(segs) == 3 {
 | 
					
						
							|  |  |  | 			r.port = "*"
 | 
					
						
							|  |  |  | 			r.service = "*"
 | 
					
						
							|  |  |  | 			offset = 0
 | 
					
						
							|  |  |  | 		} else {
 | 
					
						
							|  |  |  | 			if len(segs) != 5 {
 | 
					
						
							|  |  |  | 				return r, errInvalidRequest
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			// This is a SRV style request, get first two elements as port and
 | 
					
						
							|  |  |  | 			// protocol, stripping leading underscores if present.
 | 
					
						
							|  |  |  | 			if segs[0][0] == '_' {
 | 
					
						
							|  |  |  | 				r.port = segs[0][1:]
 | 
					
						
							|  |  |  | 			} else {
 | 
					
						
							|  |  |  | 				r.port = segs[0]
 | 
					
						
							|  |  |  | 				if !wildcard(r.port) {
 | 
					
						
							|  |  |  | 					return r, errInvalidRequest
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			if segs[1][0] == '_' {
 | 
					
						
							|  |  |  | 				r.protocol = segs[1][1:]
 | 
					
						
							|  |  |  | 				if r.protocol != "tcp" && r.protocol != "udp" {
 | 
					
						
							|  |  |  | 					return r, errInvalidRequest
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			} else {
 | 
					
						
							|  |  |  | 				r.protocol = segs[1]
 | 
					
						
							|  |  |  | 				if !wildcard(r.protocol) {
 | 
					
						
							|  |  |  | 					return r, errInvalidRequest
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			if r.port == "" || r.protocol == "" {
 | 
					
						
							|  |  |  | 				return r, errInvalidRequest
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 			offset = 2
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2017-08-11 12:12:21 +01:00
										 |  |  | 	if (state.QType() == dns.TypeA || state.QType() == dns.TypeAAAA) && len(segs) == 4 {
 | 
					
						
							| 
									
										
										
										
											2017-08-10 01:08:58 -07:00
										 |  |  | 		// This is an endpoint A/AAAA record request. Get first element as endpoint.
 | 
					
						
							|  |  |  | 		r.endpoint = segs[0]
 | 
					
						
							|  |  |  | 		offset = 1
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(segs) == (offset + 3) {
 | 
					
						
							|  |  |  | 		r.service = segs[offset]
 | 
					
						
							|  |  |  | 		r.namespace = segs[offset+1]
 | 
					
						
							|  |  |  | 		r.podOrSvc = segs[offset+2]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return r, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return r, errInvalidRequest
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String return a string representation of r, it just returns all
 | 
					
						
							|  |  |  | // fields concatenated with dots.
 | 
					
						
							|  |  |  | // This is mostly used in tests.
 | 
					
						
							|  |  |  | func (r recordRequest) String() string {
 | 
					
						
							|  |  |  | 	s := r.port
 | 
					
						
							|  |  |  | 	s += "." + r.protocol
 | 
					
						
							|  |  |  | 	s += "." + r.endpoint
 | 
					
						
							|  |  |  | 	s += "." + r.service
 | 
					
						
							|  |  |  | 	s += "." + r.namespace
 | 
					
						
							|  |  |  | 	s += "." + r.podOrSvc
 | 
					
						
							|  |  |  | 	s += "." + r.zone
 | 
					
						
							|  |  |  | 	s += "." + r.federation
 | 
					
						
							|  |  |  | 	return s
 | 
					
						
							|  |  |  | }
 |