aboutsummaryrefslogtreecommitdiff
path: root/middleware/kubernetes/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'middleware/kubernetes/parse.go')
-rw-r--r--middleware/kubernetes/parse.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/middleware/kubernetes/parse.go b/middleware/kubernetes/parse.go
new file mode 100644
index 000000000..790060896
--- /dev/null
+++ b/middleware/kubernetes/parse.go
@@ -0,0 +1,120 @@
+package kubernetes
+
+import (
+ "github.com/coredns/coredns/middleware/pkg/dnsutil"
+
+ "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
+}
+
+// TODO(miek): make it use request.Request.
+func (k *Kubernetes) parseRequest(lowerCasedName string, qtype uint16, zone ...string) (r recordRequest, err error) {
+ // 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
+
+ if len(zone) == 0 {
+ panic("parseRequest must be called with a zone")
+ }
+
+ base, _ := dnsutil.TrimZone(lowerCasedName, zone[0])
+ segs := dns.SplitDomainName(base)
+
+ r.zone = zone[0]
+ r.federation, segs = k.stripFederation(segs)
+
+ if qtype == dns.TypeNS {
+ return r, nil
+ }
+
+ if qtype == dns.TypeA && isDefaultNS(lowerCasedName, r) {
+ return r, nil
+ }
+
+ offset := 0
+ if qtype == dns.TypeSRV {
+ // 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
+ }
+ }
+ if (qtype == dns.TypeA || qtype == dns.TypeAAAA) && len(segs) == 4 {
+ // 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
+}