1 // Package dnsutil contains higher-level methods useful with the dns 2 // package. While package dns implements the DNS protocols itself, 3 // these functions are related but not directly required for protocol 4 // processing. They are often useful in preparing input/output of the 5 // functions in package dns. 6 package dnsutil 7 8 import ( 9 "strings" 10 11 "github.com/miekg/dns" 12 ) 13 14 // AddOrigin adds origin to s if s is not already a FQDN. 15 // Note that the result may not be a FQDN. If origin does not end 16 // with a ".", the result won't either. 17 // This implements the zonefile convention (specified in RFC 1035, 18 // Section "5.1. Format") that "@" represents the 19 // apex (bare) domain. i.e. AddOrigin("@", "foo.com.") returns "foo.com.". 20 func AddOrigin(s, origin string) string { 21 // ("foo.", "origin.") -> "foo." (already a FQDN) 22 // ("foo", "origin.") -> "foo.origin." 23 // ("foo", "origin") -> "foo.origin" 24 // ("foo", ".") -> "foo." (Same as dns.Fqdn()) 25 // ("foo.", ".") -> "foo." (Same as dns.Fqdn()) 26 // ("@", "origin.") -> "origin." (@ represents the apex (bare) domain) 27 // ("", "origin.") -> "origin." (not obvious) 28 // ("foo", "") -> "foo" (not obvious) 29 30 if dns.IsFqdn(s) { 31 return s // s is already a FQDN, no need to mess with it. 32 } 33 if origin == "" { 34 return s // Nothing to append. 35 } 36 if s == "@" || s == "" { 37 return origin // Expand apex. 38 } 39 if origin == "." { 40 return dns.Fqdn(s) 41 } 42 43 return s + "." + origin // The simple case. 44 } 45 46 // TrimDomainName trims origin from s if s is a subdomain. 47 // This function will never return "", but returns "@" instead (@ represents the apex domain). 48 func TrimDomainName(s, origin string) string { 49 // An apex (bare) domain is always returned as "@". 50 // If the return value ends in a ".", the domain was not the suffix. 51 // origin can end in "." or not. Either way the results should be the same. 52 53 if s == "" { 54 return "@" 55 } 56 // Someone is using TrimDomainName(s, ".") to remove a dot if it exists. 57 if origin == "." { 58 return strings.TrimSuffix(s, origin) 59 } 60 61 original := s 62 s = dns.Fqdn(s) 63 origin = dns.Fqdn(origin) 64 65 if !dns.IsSubDomain(origin, s) { 66 return original 67 } 68 69 slabels := dns.Split(s) 70 olabels := dns.Split(origin) 71 m := dns.CompareDomainName(s, origin) 72 if len(olabels) == m { 73 if len(olabels) == len(slabels) { 74 return "@" // origin == s 75 } 76 if (s[0] == '.') && (len(slabels) == (len(olabels) + 1)) { 77 return "@" // TrimDomainName(".foo.", "foo.") 78 } 79 } 80 81 // Return the first (len-m) labels: 82 return s[:slabels[len(slabels)-m]-1] 83 } 84