From 9ee9408c6a6b2cab49e6894e9cd8b96682aa86d7 Mon Sep 17 00:00:00 2001 From: Hiroyuki Wada Date: Tue, 27 Feb 2018 12:46:09 +0900 Subject: [PATCH] Resolve CNAME record like Route 53 alias record --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++++-------- amazondns.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++- build.sh | 12 ++++++++--- 3 files changed, 113 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a81aa39..ac19750 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,11 @@ amazondns ZONE [ADDRESS] { ## Examples -Create your Route 53 private hostead zone with `sub.example.org` and attach your VPC. Then add A record for `test.sub.example.org` into the zone. +Setup Route 53 as below. + +* Create your Route 53 private hostead zone with `sub.example.org` and attach your VPC. +* Add A record as `test.sub.example.org` into the zone. +* Add CNAME record as `lb.sub.example.org` for your ELB into the zone. Next, boot EC2 instance and deploy CoreDNS binary, and configure CoreDNS config file as below. @@ -60,14 +64,14 @@ The `test.sub.example.org` is resolved with *AUTHORITY SECTION* and *ADDITIONAL ; EDNS: version: 0, flags:; udp: 4096 ; COOKIE: 23246de45b4a3601 (echoed) ;; QUESTION SECTION: -;test.sub.example.org. IN A +;test.sub.example.org. IN A ;; ANSWER SECTION: -test.sub.example.org. 60 IN A 10.0.0.10 +test.sub.example.org. 60 IN A 10.0.0.10 ;; AUTHORITY SECTION: -sub.example.org. 60 IN NS ns1.sub.example.org. -sub.example.org. 60 IN NS ns2.sub.example.org. +sub.example.org. 60 IN NS ns1.sub.example.org. +sub.example.org. 60 IN NS ns2.sub.example.org. ;; ADDITIONAL SECTION: ns1.sub.example.org. 60 IN A 192.168.0.1 @@ -95,11 +99,11 @@ Also it can return NS record(s) for subdomain as below. ; EDNS: version: 0, flags:; udp: 4096 ; COOKIE: c1c3332966dba8fd (echoed) ;; QUESTION SECTION: -;sub.example.org. IN NS +;sub.example.org. IN NS ;; ANSWER SECTION: -sub.example.org. 60 IN NS ns1.sub.example.org. -sub.example.org. 60 IN NS ns2.sub.example.org. +sub.example.org. 60 IN NS ns1.sub.example.org. +sub.example.org. 60 IN NS ns2.sub.example.org. ;; ADDITIONAL SECTION: ns1.sub.example.org. 60 IN A 192.168.0.1 @@ -111,3 +115,39 @@ ns2.sub.example.org. 60 IN A 192.168.0.2 ;; MSG SIZE rcvd: 125 ``` +And it works like Route 53 alias record when answering CNAME record. +Your CNAME record will be removed and A/AAAA records of the CNAME record will be replaces. + +```bash +> dig @localhost lb.sub.example.org + +; <<>> DiG 9.11.1 <<>> @localhost test.sub.example.org +norecurse +; (1 server found) +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63630 +;; flags: qr aa ra; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 3 + +;; OPT PSEUDOSECTION: +; EDNS: version: 0, flags:; udp: 4096 +; COOKIE: 89a840e16b4d3fc7 (echoed) +;; QUESTION SECTION: +;lb.sub.example.org. IN A + +;; ANSWER SECTION: +lb.sub.example.org. 54 IN A 10.0.0.16 +lb.sub.example.org. 54 IN A 10.0.0.132 + +;; AUTHORITY SECTION: +sub.example.org. 60 IN NS ns1.sub.example.org. +sub.example.org. 60 IN NS ns2.sub.example.org. + +;; ADDITIONAL SECTION: +ns1.sub.example.org. 60 IN A 192.168.0.1 +ns2.sub.example.org. 60 IN A 192.168.0.2 + +;; Query time: 11 msec +;; SERVER: 127.0.0.1#53(127.0.0.1) +;; WHEN: Tue Feb 27 11:20:08 JST 2018 +;; MSG SIZE rcvd: 174 +``` diff --git a/amazondns.go b/amazondns.go index ada9612..0bf269a 100644 --- a/amazondns.go +++ b/amazondns.go @@ -68,6 +68,9 @@ L: m.Answer = resp.Answer m.Rcode = resp.Rcode + // It's useful resolving CNAME for DNS of ELB, RDS and so on + resolveCNAME(name, m) + // Overwrite authority and additional section if len(m.Answer) > 0 { m.Ns = zone.ns @@ -96,6 +99,7 @@ L: state.SizeAndDo(m) m, _ = state.Scrub(m) + w.WriteMsg(m) return dns.RcodeSuccess, nil } @@ -124,7 +128,58 @@ func handleNotFound(zone *Zone, name string, m *dns.Msg) { m.Rcode = dns.RcodeNameError } -func (ad *AmazonDNS) fillResponse(state request.Request, m *dns.Msg) { +func resolveCNAME(reqName string, res *dns.Msg) { + ignore := map[string]struct{}{} + + for { + var name string + var cname string + var ttl uint32 + cnameIndex := -1 + + // Find CNAME record + for i, rr := range res.Answer { + if rr.Header().Rrtype == dns.TypeCNAME { + name = rr.Header().Name + + if name != reqName { + continue + } + + if _, ok := ignore[name]; ok { + continue + } + + cname = rr.(*dns.CNAME).Target + ttl = rr.Header().Ttl + + cnameIndex = i + break + } + } + + if cnameIndex == -1 { + break + } + + var replaced bool + + // Replace records belong to CNAME record + for _, rr := range res.Answer { + if rr.Header().Name == cname { + rr.Header().Name = name + rr.Header().Ttl = ttl + replaced = true + } + } + + // Remove CNAME record + if replaced { + res.Answer = append(res.Answer[:cnameIndex], res.Answer[cnameIndex+1:]...) + } else { + ignore[name] = struct{}{} + } + } } // Name implements the Handler interface. diff --git a/build.sh b/build.sh index 33dd035..59ffb80 100755 --- a/build.sh +++ b/build.sh @@ -1,18 +1,24 @@ #!/bin/sh -VERSION=0.1 -TAG=master +VERSION=0.2 +TAG=b1ce9ed6e5b6178fbfa73d3764d25a6e1f20fc82 +CADDY_TAG=37b291f82c2083a378b698577640389686b0baf4 if [ "$1" = "" ]; then docker run --rm \ -v $(pwd):/go/src/github.com/wadahiro/coredns-amazondns \ -v $(pwd)/.tmp:/go \ -w /go/src/github.com/wadahiro/coredns-amazondns \ - golang:1.9 ./build.sh $TAG + golang:1.9 ./build.sh $TAG $CADDY_TAG else echo "Building CoreDNS:$1 with amazondns..." go get github.com/coredns/coredns + + cd /go/src/github.com/mholt/caddy + + git checkout $2 + cd /go/src/github.com/coredns/coredns git reset --hard HEAD