Fix FQDN validation and add tests

This commit is contained in:
Daniel 2020-05-15 22:44:24 +02:00
parent 75d7a91843
commit ca8b36cbc7
2 changed files with 89 additions and 2 deletions

View file

@ -2,13 +2,57 @@ package netutils
import (
"regexp"
"github.com/miekg/dns"
)
var (
cleanDomainRegex = regexp.MustCompile(`^((xn--)?[a-z0-9-_]{0,61}[a-z0-9]{1,1}\.)*(xn--)?([a-z0-9-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,}\.)$`)
cleanDomainRegex = regexp.MustCompile(
`^` + // match beginning
`(` + // start subdomain group
`(xn--)?` + // idn prefix
`[a-z0-9_-]{1,63}` + // main chunk
`\.` + // ending with a dot
`)*` + // end subdomain group, allow any number of subdomains
`(xn--)?` + // TLD idn prefix
`[a-z0-9_-]{2,63}` + // TLD main chunk with at least two characters
`\.` + // ending with a dot
`$`, // match end
)
)
// IsValidFqdn returns whether the given string is a valid fqdn.
func IsValidFqdn(fqdn string) bool {
return cleanDomainRegex.MatchString(fqdn)
// root zone
if fqdn == "." {
return true
}
// check max length
if len(fqdn) > 256 {
return false
}
// check with regex
if !cleanDomainRegex.MatchString(fqdn) {
return false
}
// check with miegk/dns
// IsFqdn checks if a domain name is fully qualified.
if !dns.IsFqdn(fqdn) {
return false
}
// IsDomainName checks if s is a valid domain name, it returns the number of
// labels and true, when a domain name is valid. Note that non fully qualified
// domain name is considered valid, in this case the last label is counted in
// the number of labels. When false is returned the number of labels is not
// defined. Also note that this function is extremely liberal; almost any
// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
// label fits in 63 characters and that the entire name will fit into the 255
// octet wire format limit.
_, ok := dns.IsDomainName(fqdn)
return ok
}

View file

@ -0,0 +1,43 @@
package netutils
import "testing"
func testDomainValidity(t *testing.T, domain string, isValid bool) {
if IsValidFqdn(domain) != isValid {
t.Errorf("domain %s failed check: was valid=%v, expected valid=%v", domain, IsValidFqdn(domain), isValid)
}
}
func TestDNSValidation(t *testing.T) {
// valid
testDomainValidity(t, ".", true)
testDomainValidity(t, "at.", true)
testDomainValidity(t, "orf.at.", true)
testDomainValidity(t, "www.orf.at.", true)
testDomainValidity(t, "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.x.y.z.example.org.", true)
testDomainValidity(t, "a_a.com.", true)
testDomainValidity(t, "a-a.com.", true)
testDomainValidity(t, "a_a.com.", true)
testDomainValidity(t, "a-a.com.", true)
testDomainValidity(t, "xn--a.com.", true)
testDomainValidity(t, "xn--asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd.com.", true)
// maybe valid
testDomainValidity(t, "-.com.", true)
testDomainValidity(t, "_.com.", true)
testDomainValidity(t, "a_.com.", true)
testDomainValidity(t, "a-.com.", true)
testDomainValidity(t, "_a.com.", true)
testDomainValidity(t, "-a.com.", true)
// invalid
testDomainValidity(t, ".com.", false)
testDomainValidity(t, ".com.", false)
testDomainValidity(t, "xn--asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf.com.", false)
testDomainValidity(t, "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf.com.", false)
testDomainValidity(t, "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf.com.", false)
testDomainValidity(t, "asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.asdf.as.com.", false)
// real world examples
testDomainValidity(t, "iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com.", true)
}