hostname: normalize before validation

Apply NormaliseHostname() before ValidateHostname() in ApplyHostnameFromHostInfo()
and EnsureHostname() to sanitize hostnames with minor invalid characters instead
of replacing them with generic identifiers like "invalid-abc123".

This allows hostnames like "My-PC!" to become "my-pc" rather than being rejected.

Fixes #2926
This commit is contained in:
griffer 2025-12-19 08:17:31 +01:00
parent 7be20912f5
commit 91711ec234
2 changed files with 16 additions and 8 deletions

View file

@ -585,17 +585,25 @@ func (node *Node) ApplyHostnameFromHostInfo(hostInfo *tailcfg.Hostinfo) {
return return
} }
newHostname := strings.ToLower(hostInfo.Hostname) newHostname, err := util.NormaliseHostname(hostInfo.Hostname)
if err := util.ValidateHostname(newHostname); err != nil { if err != nil {
log.Warn(). log.Warn().
Str("node.id", node.ID.String()). Str("node.id", node.ID.String()).
Str("current_hostname", node.Hostname). Str("current_hostname", node.Hostname).
Str("rejected_hostname", hostInfo.Hostname). Str("original_hostname", hostInfo.Hostname).
Err(err). Err(err).
Msg("Rejecting invalid hostname update from hostinfo") Msg("Hostname normalization failed, keeping current hostname")
return return
} }
if hostInfo.Hostname != newHostname {
log.Info().
Str("node.id", node.ID.String()).
Str("original", hostInfo.Hostname).
Str("sanitized", newHostname).
Msg("Hostname sanitized during update")
}
if node.Hostname != newHostname { if node.Hostname != newHostname {
log.Trace(). log.Trace().
Str("node.id", node.ID.String()). Str("node.id", node.ID.String()).

View file

@ -287,12 +287,12 @@ func EnsureHostname(hostinfo *tailcfg.Hostinfo, machineKey, nodeKey string) stri
return fmt.Sprintf("node-%s", keyPrefix) return fmt.Sprintf("node-%s", keyPrefix)
} }
lowercased := strings.ToLower(hostinfo.Hostname) normalized, err := NormaliseHostname(hostinfo.Hostname)
if err := ValidateHostname(lowercased); err == nil { if err != nil {
return lowercased return InvalidString()
} }
return InvalidString() return normalized
} }
// GenerateRegistrationKey generates a vanity key for tracking web authentication // GenerateRegistrationKey generates a vanity key for tracking web authentication