diff --git a/service/intel/entity.go b/service/intel/entity.go index 986ca1401..56e0b6a59 100644 --- a/service/intel/entity.go +++ b/service/intel/entity.go @@ -397,28 +397,32 @@ func (e *Entity) getDomainLists(ctx context.Context) { } func splitDomain(domain string) []string { - domain = strings.Trim(domain, ".") - suffix, _ := publicsuffix.PublicSuffix(domain) - if suffix == domain { + // Get suffix. + d := strings.TrimSuffix(domain, ".") + suffix, icann := publicsuffix.PublicSuffix(d) + if suffix == d { return []string{domain} } - domainWithoutSuffix := domain[:len(domain)-len(suffix)] - domainWithoutSuffix = strings.Trim(domainWithoutSuffix, ".") - - splitted := strings.FieldsFunc(domainWithoutSuffix, func(r rune) bool { + // Split all subdomain into labels. + labels := strings.FieldsFunc(d[:len(d)-len(suffix)], func(r rune) bool { return r == '.' }) - domains := make([]string, 0, len(splitted)) - for idx := range splitted { + // Build list of all domains up to the public suffix. + domains := make([]string, 0, len(labels)+1) + for idx := range labels { + domains = append( + domains, + strings.Join(labels[idx:], ".")+"."+suffix+".", + ) + } - d := strings.Join(splitted[idx:], ".") + "." + suffix - if d[len(d)-1] != '.' { - d += "." - } - domains = append(domains, d) + // If the suffix is not a real TLD, but a public suffix, add it to the list. + if !icann { + domains = append(domains, suffix+".") } + return domains } diff --git a/service/intel/entity_test.go b/service/intel/entity_test.go new file mode 100644 index 000000000..83a8fd7bc --- /dev/null +++ b/service/intel/entity_test.go @@ -0,0 +1,33 @@ +package intel + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var splitDomainTestCases = [][]string{ + // Regular registered domains and subdomains. + {"example.com."}, + {"www.example.com.", "example.com."}, + {"sub.domain.example.com.", "domain.example.com.", "example.com."}, + {"example.co.uk."}, + {"www.example.co.uk.", "example.co.uk."}, + + // TLD or public suffix: Return as is. + {"com."}, + {"googleapis.com."}, + + // Public suffix domains: Return including public suffix. + {"test.googleapis.com.", "googleapis.com."}, + {"sub.domain.googleapis.com.", "domain.googleapis.com.", "googleapis.com."}, +} + +func TestSplitDomain(t *testing.T) { + t.Parallel() + + for _, testCase := range splitDomainTestCases { + splitted := splitDomain(testCase[0]) + assert.Equal(t, testCase, splitted, "result must match") + } +}