blob: cf6d52044c6508b2caad06fa6196e423def37814 [file] [log] [blame]
Jan Schär39f4f5c2024-10-29 09:41:50 +01001package node
2
3import (
4 "errors"
5 "fmt"
6 "regexp"
7)
8
9const (
10 // domainNameMaxLength is the maximum length of a domain name supported by DNS
11 // when represented without a trailing dot.
12 domainNameMaxLength = 253
13
14 // clusterDomainMaxLength is the maximum length of a cluster domain. Limiting
15 // this to 80 allows for constructing subdomains of the cluster domain, where
16 // the subdomain part can have length up to 172. With the joining dot, this
17 // adds up to 253.
18 clusterDomainMaxLength = 80
19)
20
21var (
22 fmtDomainNameLabel = `[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?`
23 reDomainName = regexp.MustCompile(`^` + fmtDomainNameLabel + `(\.` + fmtDomainNameLabel + `)*$`)
24 reDomainNameEndsInNumber = regexp.MustCompile(`(^|\.)([0-9]+|0x[0-9a-f]*)$`)
25
26 errDomainNameTooLong = fmt.Errorf("too long, must have length at most %d", domainNameMaxLength)
27 errDomainNameInvalid = errors.New("must consist of labels separated by '.', where each label has between 1 and 63 lowercase letters, digits or '-', and must not start or end with '-'")
28 errDomainNameEndsInNumber = errors.New("must not end in a number")
29
30 errClusterDomainTooLong = fmt.Errorf("too long, must have length at most %d", clusterDomainMaxLength)
31)
32
33// validateDomainName returns an error if the passed string is not a valid
34// domain name, according to these rules: The name must be a valid DNS name
35// without a trailing dot. Labels must only consist of lowercase letters, digits
36// or '-', and must not start or end with '-'. Additionally, the name must not
37// end in a number, so that it won't be parsed as an IPv4 address.
38func validateDomainName(d string) error {
39 if len(d) > domainNameMaxLength {
40 return errDomainNameTooLong
41 }
42 // This implements RFC 1123 domain validation. Additionally, it does not allow
43 // uppercase, so that we don't need to implement case-insensitive matching.
44 if !reDomainName.MatchString(d) {
45 return errDomainNameInvalid
46 }
47 // This implements https://url.spec.whatwg.org/#ends-in-a-number-checker
48 if reDomainNameEndsInNumber.MatchString(d) {
49 return errDomainNameEndsInNumber
50 }
51 return nil
52}
53
54// ValidateClusterDomain returns an error if the passed string is not a valid
55// cluster domain.
56func ValidateClusterDomain(d string) error {
57 if len(d) > clusterDomainMaxLength {
58 return errClusterDomainTooLong
59 }
60 return validateDomainName(d)
61}