Fix zone detection for cross-zone cnames (#449)

* Fix zone detection for cross-zone cnames

CNAMEs cannot co-exist with SOA records so responses with
a CNAME should be skipped.

The `cross-zone-example.assets.sh.` is currently hosted by
me (@fd) and will continue to exist for as long as the assets.sh
domain exists. (The assets.sh domain is used as a CDN and is unlikely
to go away.)

See #330

* Extracted CNAME checking to simplify the FindZoneByFqdn control flow.
This commit is contained in:
Simon Menke 2017-11-15 11:03:00 +01:00 committed by xenolf
parent 922235d33e
commit b929aa5aab
2 changed files with 21 additions and 3 deletions

View file

@ -255,6 +255,13 @@ func FindZoneByFqdn(fqdn string, nameservers []string) (string, error) {
// Check if we got a SOA RR in the answer section // Check if we got a SOA RR in the answer section
if in.Rcode == dns.RcodeSuccess { if in.Rcode == dns.RcodeSuccess {
// CNAME records cannot/should not exist at the root of a zone.
// So we skip a domain when a CNAME is found.
if dnsMsgContainsCNAME(in) {
continue
}
for _, ans := range in.Answer { for _, ans := range in.Answer {
if soa, ok := ans.(*dns.SOA); ok { if soa, ok := ans.(*dns.SOA); ok {
zone := soa.Hdr.Name zone := soa.Hdr.Name
@ -268,6 +275,16 @@ func FindZoneByFqdn(fqdn string, nameservers []string) (string, error) {
return "", fmt.Errorf("Could not find the start of authority") return "", fmt.Errorf("Could not find the start of authority")
} }
// dnsMsgContainsCNAME checks for a CNAME answer in msg
func dnsMsgContainsCNAME(msg *dns.Msg) bool {
for _, ans := range msg.Answer {
if _, ok := ans.(*dns.CNAME); ok {
return true
}
}
return false
}
// ClearFqdnCache clears the cache of fqdn to zone mappings. Primarily used in testing. // ClearFqdnCache clears the cache of fqdn to zone mappings. Primarily used in testing.
func ClearFqdnCache() { func ClearFqdnCache() {
fqdnToZone = map[string]string{} fqdnToZone = map[string]string{}

View file

@ -46,6 +46,7 @@ var findZoneByFqdnTests = []struct {
{"mail.google.com.", "google.com."}, // domain is a CNAME {"mail.google.com.", "google.com."}, // domain is a CNAME
{"foo.google.com.", "google.com."}, // domain is a non-existent subdomain {"foo.google.com.", "google.com."}, // domain is a non-existent subdomain
{"example.com.ac.", "ac."}, // domain is a eTLD {"example.com.ac.", "ac."}, // domain is a eTLD
{"cross-zone-example.assets.sh.", "assets.sh."}, // domain is a cross-zone CNAME
} }
var checkAuthoritativeNssTests = []struct { var checkAuthoritativeNssTests = []struct {