Skip to content

Commit 8df41ca

Browse files
committed
Add OverlappingTLSConfig condition
1 parent e8083f7 commit 8df41ca

File tree

5 files changed

+368
-9
lines changed

5 files changed

+368
-9
lines changed

internal/controller/state/conditions/conditions.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ const (
2929
ListenerMessageFailedNginxReload = "The Listener is not programmed due to a failure to " +
3030
"reload nginx with the configuration"
3131

32+
// ListenerMessageOverlappingHostnames is a message used with the "OverlappingTLSConfig" condition when the
33+
// condition is true due to overlapping hostnames.
34+
ListenerMessageOverlappingHostnames = "Listener hostname overlaps with hostname(s) of other Listener(s) " +
35+
"on the same port"
36+
3237
// RouteReasonBackendRefUnsupportedValue is used with the "ResolvedRefs" condition when one of the
3338
// Route rules has a backendRef with an unsupported value.
3439
RouteReasonBackendRefUnsupportedValue v1.RouteConditionReason = "UnsupportedValue"
@@ -501,13 +506,32 @@ func NewRouteResolvedRefsInvalidFilter(msg string) Condition {
501506
}
502507

503508
// NewDefaultListenerConditions returns the default Conditions that must be present in the status of a Listener.
504-
func NewDefaultListenerConditions() []Condition {
505-
return []Condition{
509+
// If existingConditions contains conflict-related conditions (like OverlappingTLSConfig or Conflicted),
510+
// the NoConflicts condition is excluded to avoid conflicting condition states.
511+
func NewDefaultListenerConditions(existingConditions []Condition) []Condition {
512+
defaultConds := []Condition{
506513
NewListenerAccepted(),
507514
NewListenerProgrammed(),
508515
NewListenerResolvedRefs(),
509-
NewListenerNoConflicts(),
510516
}
517+
518+
// Only add NoConflicts condition if there are no existing conflict-related conditions
519+
if !hasConflictConditions(existingConditions) {
520+
defaultConds = append(defaultConds, NewListenerNoConflicts())
521+
}
522+
523+
return defaultConds
524+
}
525+
526+
// hasConflictConditions checks if the listener has any conflict-related conditions.
527+
func hasConflictConditions(conditions []Condition) bool {
528+
for _, cond := range conditions {
529+
if cond.Type == string(v1.ListenerConditionConflicted) ||
530+
cond.Type == string(v1.ListenerConditionOverlappingTLSConfig) {
531+
return true
532+
}
533+
}
534+
return false
511535
}
512536

513537
// NewListenerAccepted returns a Condition that indicates that the Listener is accepted.
@@ -681,6 +705,17 @@ func NewListenerRefNotPermitted(msg string) []Condition {
681705
}
682706
}
683707

708+
// NewListenerOverlappingTLSConfig returns a Condition that indicates overlapping TLS configuration
709+
// between Listeners on the same port.
710+
func NewListenerOverlappingTLSConfig(reason v1.ListenerConditionReason, msg string) Condition {
711+
return Condition{
712+
Type: string(v1.ListenerConditionOverlappingTLSConfig),
713+
Status: metav1.ConditionTrue,
714+
Reason: string(reason),
715+
Message: msg,
716+
}
717+
}
718+
684719
// NewGatewayClassResolvedRefs returns a Condition that indicates that the parametersRef
685720
// on the GatewayClass is resolved.
686721
func NewGatewayClassResolvedRefs() Condition {

internal/controller/state/graph/gateway_listener.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func newListenerConfiguratorFactory(
8989
protectedPorts ProtectedPorts,
9090
) *listenerConfiguratorFactory {
9191
sharedPortConflictResolver := createPortConflictResolver()
92+
sharedOverlappingTLSConfigResolver := createOverlappingTLSConfigResolver()
9293

9394
return &listenerConfiguratorFactory{
9495
unsupportedProtocol: &listenerConfigurator{
@@ -123,6 +124,7 @@ func newListenerConfiguratorFactory(
123124
},
124125
conflictResolvers: []listenerConflictResolver{
125126
sharedPortConflictResolver,
127+
sharedOverlappingTLSConfigResolver,
126128
},
127129
externalReferenceResolvers: []listenerExternalReferenceResolver{
128130
createExternalReferencesForTLSSecretsResolver(gw.Namespace, secretResolver, refGrantResolver),
@@ -137,6 +139,7 @@ func newListenerConfiguratorFactory(
137139
},
138140
conflictResolvers: []listenerConflictResolver{
139141
sharedPortConflictResolver,
142+
sharedOverlappingTLSConfigResolver,
140143
},
141144
externalReferenceResolvers: []listenerExternalReferenceResolver{},
142145
},
@@ -591,3 +594,38 @@ func haveOverlap(hostname1, hostname2 *v1.Hostname) bool {
591594
}
592595
return matchesWildcard(h1, h2)
593596
}
597+
598+
func createOverlappingTLSConfigResolver() listenerConflictResolver {
599+
listenersByPort := make(map[v1.PortNumber][]*Listener)
600+
601+
return func(l *Listener) {
602+
port := l.Source.Port
603+
604+
// Only check TLS-enabled listeners (HTTPS/TLS)
605+
if l.Source.Protocol != v1.HTTPSProtocolType && l.Source.Protocol != v1.TLSProtocolType {
606+
return
607+
}
608+
609+
// Check for overlaps with existing listeners on this port
610+
for _, existingListener := range listenersByPort[port] {
611+
// Only check against other TLS-enabled listeners
612+
if existingListener.Source.Protocol != v1.HTTPSProtocolType &&
613+
existingListener.Source.Protocol != v1.TLSProtocolType {
614+
continue
615+
}
616+
617+
// Check for hostname overlap
618+
if haveOverlap(l.Source.Hostname, existingListener.Source.Hostname) {
619+
// Set condition on both listeners
620+
cond := conditions.NewListenerOverlappingTLSConfig(
621+
v1.ListenerReasonOverlappingHostnames,
622+
conditions.ListenerMessageOverlappingHostnames,
623+
)
624+
l.Conditions = append(l.Conditions, cond)
625+
existingListener.Conditions = append(existingListener.Conditions, cond)
626+
}
627+
}
628+
629+
listenersByPort[port] = append(listenersByPort[port], l)
630+
}
631+
}

0 commit comments

Comments
 (0)