mirror of
https://github.com/juanfont/headscale
synced 2026-04-25 17:15:33 +02:00
Ingest (registration and MapRequest updates) now calls dnsname.SanitizeHostname directly and lets NodeStore auto-bump on collision. Admin rename uses dnsname.ValidLabel + SetGivenName so conflicts are surfaced to the caller instead of silently mutated. Three duplicate invalidDNSRegex definitions, the old NormaliseHostname and ValidateHostname helpers, EnsureHostname, InvalidString, ApplyHostnameFromHostInfo, GivenNameHasBeenChanged, generateGivenName and EnsureUniqueGivenName are removed along with their tests. ValidateHostname's username half is retained as ValidateUsername for users.go. The SaaS-matching collision rule replaces the random "invalid-xxxxxx" fallback and the 8-character hash suffix; the empty-input fallback is the literal "node". TestUpdateHostnameFromClient now exercises the rewrite end-to-end with awkward macOS/Windows names. Fixes #3188 Fixes #2926 Fixes #2343 Fixes #2762 Fixes #2449 Updates #2177 Updates #2121 Updates #363
110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package util
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"tailscale.com/tailcfg"
|
|
)
|
|
|
|
// GenerateRandomBytes returns securely generated random bytes.
|
|
// It will return an error if the system's secure random
|
|
// number generator fails to function correctly, in which
|
|
// case the caller should not continue.
|
|
func GenerateRandomBytes(n int) ([]byte, error) {
|
|
bytes := make([]byte, n)
|
|
|
|
// Note that err == nil only if we read len(b) bytes.
|
|
if _, err := rand.Read(bytes); err != nil { //nolint:noinlineerr
|
|
return nil, err
|
|
}
|
|
|
|
return bytes, nil
|
|
}
|
|
|
|
// GenerateRandomStringURLSafe returns a URL-safe, base64 encoded
|
|
// securely generated random string.
|
|
// It will return an error if the system's secure random
|
|
// number generator fails to function correctly, in which
|
|
// case the caller should not continue.
|
|
func GenerateRandomStringURLSafe(n int) (string, error) {
|
|
b, err := GenerateRandomBytes(n)
|
|
|
|
uenc := base64.RawURLEncoding.EncodeToString(b)
|
|
|
|
return uenc[:n], err
|
|
}
|
|
|
|
// GenerateRandomStringDNSSafe returns a DNS-safe
|
|
// securely generated random string.
|
|
// It will return an error if the system's secure random
|
|
// number generator fails to function correctly, in which
|
|
// case the caller should not continue.
|
|
func GenerateRandomStringDNSSafe(size int) (string, error) {
|
|
var (
|
|
str string
|
|
err error
|
|
)
|
|
|
|
for len(str) < size {
|
|
str, err = GenerateRandomStringURLSafe(size)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
str = strings.ToLower(
|
|
strings.ReplaceAll(strings.ReplaceAll(str, "_", ""), "-", ""),
|
|
)
|
|
}
|
|
|
|
return str[:size], nil
|
|
}
|
|
|
|
func MustGenerateRandomStringDNSSafe(size int) string {
|
|
hash, err := GenerateRandomStringDNSSafe(size)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return hash
|
|
}
|
|
|
|
func TailNodesToString(nodes []*tailcfg.Node) string {
|
|
temp := make([]string, len(nodes))
|
|
|
|
for index, node := range nodes {
|
|
temp[index] = node.Name
|
|
}
|
|
|
|
return fmt.Sprintf("[ %s ](%d)", strings.Join(temp, ", "), len(temp))
|
|
}
|
|
|
|
func TailMapResponseToString(resp tailcfg.MapResponse) string {
|
|
return fmt.Sprintf(
|
|
"{ Node: %s, Peers: %s }",
|
|
resp.Node.Name,
|
|
TailNodesToString(resp.Peers),
|
|
)
|
|
}
|
|
|
|
func TailcfgFilterRulesToString(rules []tailcfg.FilterRule) string {
|
|
var sb strings.Builder
|
|
|
|
for index, rule := range rules {
|
|
fmt.Fprintf(&sb, `
|
|
{
|
|
SrcIPs: %v
|
|
DstIPs: %v
|
|
}
|
|
`, rule.SrcIPs, rule.DstPorts)
|
|
|
|
if index < len(rules)-1 {
|
|
sb.WriteString(", ")
|
|
}
|
|
}
|
|
|
|
return fmt.Sprintf("[ %s ](%d)", sb.String(), len(rules))
|
|
}
|