fix: produce valid listener names for wildcard and unusual DNS names

A DNS name like *.home.hrajfrisbee.cz put "*" into the listener name; the
API server rejected the patch, which blocked every certificate on that
Gateway.

- lowercase the DNS part, spell "*" as "wildcard", map other characters
  outside [a-z0-9] to "-"
- names over 253 chars are cut and get a hash suffix instead of a blind cut
- names that were valid before are unchanged

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 20:47:44 +02:00
co-authored by Claude Opus 5.5
parent 6698eab1d8
commit 42b53b7538
5 changed files with 137 additions and 24 deletions
+31 -7
View File
@@ -1,6 +1,8 @@
package gateway
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"sort"
"strings"
@@ -132,16 +134,38 @@ func listenerMap(listeners []gwapiv1.Listener) map[string]listenerKey {
return m
}
// maxSectionNameLen is the Gateway API limit for listener names.
const maxSectionNameLen = 253
// listenerNameFor generates a deterministic listener name from cert name and DNS name.
// Truncates to stay within Gateway API's 253-char limit for section names.
// The result is a valid Gateway API SectionName: names that would exceed the limit
// are cut and get a hash of the full name appended, so distinct long names stay distinct.
func listenerNameFor(prefix, certName, dnsName string) string {
// Replace dots with dashes for DNS names, combine with cert name.
sanitized := strings.ReplaceAll(dnsName, ".", "-")
name := fmt.Sprintf("%s%s-%s", prefix, certName, sanitized)
if len(name) > 253 {
name = name[:253]
name := strings.TrimRight(fmt.Sprintf("%s%s-%s", prefix, certName, sanitizeDNSName(dnsName)), "-.")
if len(name) <= maxSectionNameLen {
return name
}
return name
sum := sha256.Sum256([]byte(name))
suffix := "-" + hex.EncodeToString(sum[:4])
return strings.TrimRight(name[:maxSectionNameLen-len(suffix)], "-.") + suffix
}
// sanitizeDNSName maps a certificate DNS name onto the characters allowed in a
// listener name. A wildcard label is spelled out so "*.example.com" and
// "example.com" stay distinct.
func sanitizeDNSName(dnsName string) string {
var b strings.Builder
for _, r := range strings.ToLower(dnsName) {
switch {
case r >= 'a' && r <= 'z', r >= '0' && r <= '9':
b.WriteRune(r)
case r == '*':
b.WriteString("wildcard")
default:
b.WriteByte('-')
}
}
return strings.Trim(b.String(), "-")
}
func ptrTo[T any](v T) *T {