mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
util/dnsname: make ToFQDN take exactly 0 or 1 allocs for everything.
name old time/op new time/op delta ToFQDN/www.tailscale.com.-32 9.55ns ± 2% 12.13ns ± 3% +27.03% (p=0.000 n=10+10) ToFQDN/www.tailscale.com-32 86.3ns ± 1% 40.7ns ± 1% -52.86% (p=0.000 n=10+9) ToFQDN/.www.tailscale.com-32 86.5ns ± 1% 40.4ns ± 1% -53.29% (p=0.000 n=10+9) ToFQDN/_ssh._tcp.www.tailscale.com.-32 12.8ns ± 2% 14.7ns ± 2% +14.24% (p=0.000 n=9+10) ToFQDN/_ssh._tcp.www.tailscale.com-32 104ns ± 1% 45ns ± 0% -57.16% (p=0.000 n=10+9) name old alloc/op new alloc/op delta ToFQDN/www.tailscale.com.-32 0.00B 0.00B ~ (all equal) ToFQDN/www.tailscale.com-32 72.0B ± 0% 24.0B ± 0% -66.67% (p=0.000 n=10+10) ToFQDN/.www.tailscale.com-32 72.0B ± 0% 24.0B ± 0% -66.67% (p=0.000 n=10+10) ToFQDN/_ssh._tcp.www.tailscale.com.-32 0.00B 0.00B ~ (all equal) ToFQDN/_ssh._tcp.www.tailscale.com-32 112B ± 0% 32B ± 0% -71.43% (p=0.000 n=10+10) name old allocs/op new allocs/op delta ToFQDN/www.tailscale.com.-32 0.00 0.00 ~ (all equal) ToFQDN/www.tailscale.com-32 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) ToFQDN/.www.tailscale.com-32 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) ToFQDN/_ssh._tcp.www.tailscale.com.-32 0.00 0.00 ~ (all equal) ToFQDN/_ssh._tcp.www.tailscale.com-32 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10) Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
parent
d7f6ef3a79
commit
c54cc24e87
@ -21,31 +21,48 @@
|
|||||||
type FQDN string
|
type FQDN string
|
||||||
|
|
||||||
func ToFQDN(s string) (FQDN, error) {
|
func ToFQDN(s string) (FQDN, error) {
|
||||||
if isValidFQDN(s) {
|
|
||||||
return FQDN(s), nil
|
|
||||||
}
|
|
||||||
if len(s) == 0 || s == "." {
|
if len(s) == 0 || s == "." {
|
||||||
return FQDN("."), nil
|
return FQDN("."), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if s[len(s)-1] == '.' {
|
|
||||||
s = s[:len(s)-1]
|
|
||||||
}
|
|
||||||
if s[0] == '.' {
|
if s[0] == '.' {
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
}
|
}
|
||||||
if len(s) > maxNameLength {
|
raw := s
|
||||||
|
totalLen := len(s)
|
||||||
|
if s[len(s)-1] == '.' {
|
||||||
|
s = s[:len(s)-1]
|
||||||
|
} else {
|
||||||
|
totalLen += 1 // account for missing dot
|
||||||
|
}
|
||||||
|
if totalLen > maxNameLength {
|
||||||
return "", fmt.Errorf("%q is too long to be a DNS name", s)
|
return "", fmt.Errorf("%q is too long to be a DNS name", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fs := strings.Split(s, ".")
|
st := 0
|
||||||
for _, f := range fs {
|
for i := 0; i < len(s); i++ {
|
||||||
if !validLabel(f) {
|
if s[i] != '.' {
|
||||||
return "", fmt.Errorf("%q is not a valid DNS label", f)
|
continue
|
||||||
}
|
}
|
||||||
|
label := s[st:i]
|
||||||
|
// You might be tempted to do further validation of the
|
||||||
|
// contents of labels here, based on the hostname rules in RFC
|
||||||
|
// 1123. However, DNS labels are not always subject to
|
||||||
|
// hostname rules. In general, they can contain any non-zero
|
||||||
|
// byte sequence, even though in practice a more restricted
|
||||||
|
// set is used.
|
||||||
|
//
|
||||||
|
// See https://github.com/tailscale/tailscale/issues/2024 for more.
|
||||||
|
if len(label) == 0 || len(label) > maxLabelLength {
|
||||||
|
return "", fmt.Errorf("%q is not a valid DNS label", label)
|
||||||
|
}
|
||||||
|
st = i + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return FQDN(s + "."), nil
|
if raw[len(raw)-1] != '.' {
|
||||||
|
raw = raw + "."
|
||||||
|
}
|
||||||
|
return FQDN(raw), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTrailingDot returns f as a string, with a trailing dot.
|
// WithTrailingDot returns f as a string, with a trailing dot.
|
||||||
@ -77,58 +94,6 @@ func (f FQDN) Contains(other FQDN) bool {
|
|||||||
return strings.HasSuffix(other.WithTrailingDot(), cmp)
|
return strings.HasSuffix(other.WithTrailingDot(), cmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidFQDN reports whether s is already a valid FQDN, without
|
|
||||||
// allocating.
|
|
||||||
func isValidFQDN(s string) bool {
|
|
||||||
if len(s) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(s) > maxNameLength {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// DNS root name.
|
|
||||||
if s == "." {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Missing trailing dot.
|
|
||||||
if s[len(s)-1] != '.' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Leading dots not allowed.
|
|
||||||
if s[0] == '.' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
st := 0
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
if s[i] != '.' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
label := s[st:i]
|
|
||||||
if !validLabel(label) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
st = i + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func validLabel(s string) bool {
|
|
||||||
// You might be tempted to do further validation of the
|
|
||||||
// contents of labels here, based on the hostname rules in RFC
|
|
||||||
// 1123. However, DNS labels are not always subject to
|
|
||||||
// hostname rules. In general, they can contain any non-zero
|
|
||||||
// byte sequence, even though in practice a more restricted
|
|
||||||
// set is used.
|
|
||||||
//
|
|
||||||
// See https://github.com/tailscale/tailscale/issues/2024 for more.
|
|
||||||
if len(s) == 0 || len(s) > maxLabelLength {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// SanitizeLabel takes a string intended to be a DNS name label
|
// SanitizeLabel takes a string intended to be a DNS name label
|
||||||
// and turns it into a valid name label according to RFC 1035.
|
// and turns it into a valid name label according to RFC 1035.
|
||||||
func SanitizeLabel(label string) string {
|
func SanitizeLabel(label string) string {
|
||||||
|
Loading…
Reference in New Issue
Block a user