{"record":{"id":"2950954bdd9cec45","repo":"AdguardTeam/AdGuardHome","slug":"no-valid-parts","errorCode":null,"errorMessage":"no valid parts","messagePattern":"no valid parts","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/dhcpd/v4_unix.go","lineNumber":92,"sourceCode":"func (s *v4Server) WriteDiskConfig6(c *V6ServerConf) {\n}\n\n// normalizeHostname normalizes a hostname sent by the client.  If err is not\n// nil, norm is an empty string.\nfunc normalizeHostname(hostname string) (norm string, err error) {\n\tdefer func() { err = errors.Annotate(err, \"normalizing %q: %w\", hostname) }()\n\n\tif hostname == \"\" {\n\t\treturn \"\", nil\n\t}\n\n\tnorm = strings.ToLower(hostname)\n\tparts := strings.FieldsFunc(norm, func(c rune) (ok bool) {\n\t\treturn c != '.' && !netutil.IsValidHostOuterRune(c)\n\t})\n\n\tif len(parts) == 0 {\n\t\treturn \"\", fmt.Errorf(\"no valid parts\")\n\t}\n\n\tnorm = strings.Join(parts, \"-\")\n\tnorm = strings.TrimSuffix(norm, \"-\")\n\n\treturn norm, nil\n}\n\n// validHostnameForClient accepts the hostname sent by the client and its IP and\n// returns either a normalized version of that hostname, or a new hostname\n// generated from the IP address, or an empty string.\nfunc (s *v4Server) validHostnameForClient(cliHostname string, ip netip.Addr) (hostname string) {\n\thostname, err := normalizeHostname(cliHostname)\n\tif err != nil {\n\t\tlog.Info(\"dhcpv4: %s\", err)\n\t}\n\n\tif hostname == \"\" {","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/dhcpd/v4_unix.go#L74-L110","documentation":"normalizeHostname lowercases the client-supplied hostname and splits it into parts consisting only of valid hostname runes (separating on '.' and invalid characters). If no valid parts remain, the entire hostname is invalid and the error is returned. This is a client-input validation error for DHCP hostname sanitization.","triggerScenarios":"A DHCP client sends a hostname composed entirely of invalid characters (e.g. \"...\", \"***\", non-ASCII garbage), so strings.FieldsFunc yields zero parts when AddStaticLease/validHostnameForClient normalizes it.","commonSituations":"IoT devices or misconfigured clients sending junk hostnames; malicious clients probing the DHCP server; static lease configuration with a hostname containing only punctuation.","solutions":["Fix the client's hostname to contain valid DNS label characters (letters, digits, hyphen)","If configuring a static lease, remove or correct the hostname field","Reject/log the offending client MAC to identify the misbehaving device","Treat as non-fatal for dynamic leases: log and fall back to serving the lease without a hostname"],"exampleFix":"// before\nhostname := \"***\"\n\n// after\nhostname := \"printer-1\"","handlingStrategy":"validation","validationCode":"func hasValidHostnameParts(h string) bool {\n    norm := strings.ToLower(h)\n    parts := strings.FieldsFunc(norm, func(c rune) bool {\n        return c != '.' && !netutil.IsValidHostOuterRune(c)\n    })\n    return len(parts) > 0\n}","typeGuard":null,"tryCatchPattern":"if norm, err := normalizeHostname(h); err != nil {\n    // serve lease without hostname rather than failing\n    h = \"\"\n} else { h = norm }","preventionTips":["Sanitize client hostnames before storing; drop invalid ones","For static leases, pre-validate hostname strings in config","Log offending MACs to identify misbehaving clients"],"tags":["dhcp","hostname","validation","client-input"],"backgroundTag":"hostname-validation-failed","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}