Replace DNSWATCHER_DOMAINS and DNSWATCHER_HOSTNAMES with a single DNSWATCHER_TARGETS env var. Names are automatically classified as apex domains or hostnames using the Public Suffix List (golang.org/x/net/publicsuffix). - ClassifyDNSName() uses EffectiveTLDPlusOne to determine type - Public suffixes themselves (e.g. co.uk) are rejected with an error - Old DOMAINS/HOSTNAMES vars removed entirely (pre-1.0, no compat needed) - README updated with pre-1.0 warning Closes #10
86 lines
2.1 KiB
Go
86 lines
2.1 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"golang.org/x/net/publicsuffix"
|
|
)
|
|
|
|
// DNSNameType indicates whether a DNS name is an apex domain or a hostname.
|
|
type DNSNameType int
|
|
|
|
const (
|
|
// DNSNameTypeDomain indicates the name is an apex (eTLD+1) domain.
|
|
DNSNameTypeDomain DNSNameType = iota
|
|
// DNSNameTypeHostname indicates the name is a subdomain/hostname.
|
|
DNSNameTypeHostname
|
|
)
|
|
|
|
// ErrEmptyDNSName is returned when an empty string is passed to ClassifyDNSName.
|
|
var ErrEmptyDNSName = errors.New("empty DNS name")
|
|
|
|
// String returns the string representation of a DNSNameType.
|
|
func (t DNSNameType) String() string {
|
|
switch t {
|
|
case DNSNameTypeDomain:
|
|
return "domain"
|
|
case DNSNameTypeHostname:
|
|
return "hostname"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
// ClassifyDNSName determines whether a DNS name is an apex domain or a
|
|
// hostname (subdomain) using the Public Suffix List. It returns an error
|
|
// if the input is empty or is itself a public suffix (e.g. "co.uk").
|
|
func ClassifyDNSName(name string) (DNSNameType, error) {
|
|
name = strings.ToLower(strings.TrimSuffix(strings.TrimSpace(name), "."))
|
|
|
|
if name == "" {
|
|
return 0, ErrEmptyDNSName
|
|
}
|
|
|
|
etld1, err := publicsuffix.EffectiveTLDPlusOne(name)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("invalid DNS name %q: %w", name, err)
|
|
}
|
|
|
|
if name == etld1 {
|
|
return DNSNameTypeDomain, nil
|
|
}
|
|
|
|
return DNSNameTypeHostname, nil
|
|
}
|
|
|
|
// ClassifyTargets splits a list of DNS names into apex domains and
|
|
// hostnames using the Public Suffix List. It returns an error if any
|
|
// name cannot be classified.
|
|
func ClassifyTargets(targets []string) ([]string, []string, error) {
|
|
var domains, hostnames []string
|
|
|
|
for _, t := range targets {
|
|
normalized := strings.ToLower(strings.TrimSuffix(strings.TrimSpace(t), "."))
|
|
|
|
if normalized == "" {
|
|
continue
|
|
}
|
|
|
|
typ, classErr := ClassifyDNSName(normalized)
|
|
if classErr != nil {
|
|
return nil, nil, classErr
|
|
}
|
|
|
|
switch typ {
|
|
case DNSNameTypeDomain:
|
|
domains = append(domains, normalized)
|
|
case DNSNameTypeHostname:
|
|
hostnames = append(hostnames, normalized)
|
|
}
|
|
}
|
|
|
|
return domains, hostnames, nil
|
|
}
|