Repository: kubernetes-sigs/external-dns (language: go)

Issue:
Relax protocol matching requirement between Gateway API listener and Route
**What would you like to be added**:

remove or allow to disable this check

https://github.com/kubernetes-sigs/external-dns/blob/master/source/gateway.go#L318-L321

```go
// Confirm that the Listener and Route protocols match.
if !gwProtocolMatches(rt.Protocol(), lis.Protocol) {
  continue
}
```

Or to extend `gwProtocolMatches` to include considering TLS and TCP the same:

https://github.com/kubernetes-sigs/external-dns/blob/master/source/gateway.go#L476-L486

```go
// gwProtocolMatches returns whether a and b are the same protocol,
// where HTTP and HTTPS are considered the same.
func gwProtocolMatches(a, b v1beta1.ProtocolType) bool {
	if a == v1beta1.HTTPSProtocolType {
		a = v1beta1.HTTPProtocolType
	}
	if b == v1beta1.HTTPSProtocolType {
		b = v1beta1.HTTPProtocolType
	}
	return a == b
}
```

**Why is this needed**:

When using a Gateway as a terminating proxy for TCP connections as per https://gateway-api.sigs.k8s.io/guides/tls/#clientserver-and-tls

```
TLS | Terminate | TCPRoute
```

The protocols will be mixed between the listener and route (TLS and TCP). This check seems to prevent what is otherwise considered valid usages from having DNS records generated.

```
{"level":"debug","msg":"No endpoints could be generated from TCPRoute ...","time":"..."}
{"level":"debug","msg":"Gateway ... section \"...\" does not match TCPRoute ... hostnames [\"...\" \"\"]","time":"..."}
```

Given

```
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
  name: ...
  namespace: ...
spec:
  gatewayClassName: ...
  listeners:
  - allowedRoutes:
      kinds:
      - group: gateway.networking.k8s.io
        kind: TCPRoute
      namespaces:
        from: Same
    hostname: ...
    name: ...
    port: ...
    protocol: TLS
    tls:
      certificateRefs:
      - group: ""
        kind: Secret
        name: ...
      mode: Terminate
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  labels:
    external-dns.alpha.kubernetes.io/hostname: ...
  name: ...
  namespace: ...
spec:
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: ...
    sectionName: ...
  rules:
  - backendRefs:
    - group: ""
      kind: Service
      name: ...
      port: ...
      weight: 1
```


Discussion / hints:
Faced the same problem. TLS protocol and TCPRoute combination should be supported, as it is supported in GatewayAPI.
Faced the same problem. TLS termination with TCPRoute

Fix patch:
diff --git a/source/gateway.go b/source/gateway.go
index c14ef2ad98..8f8a624a50 100644
--- a/source/gateway.go
+++ b/source/gateway.go
@@ -476,6 +476,7 @@ func uniqueTargets(targets endpoint.Targets) endpoint.Targets {
 
 // gwProtocolMatches returns whether a and b are the same protocol,
 // where HTTP and HTTPS are considered the same.
+// and TLS and TCP are considered the same.
 func gwProtocolMatches(a, b v1.ProtocolType) bool {
 	if a == v1.HTTPSProtocolType {
 		a = v1.HTTPProtocolType
@@ -483,6 +484,10 @@ func gwProtocolMatches(a, b v1.ProtocolType) bool {
 	if b == v1.HTTPSProtocolType {
 		b = v1.HTTPProtocolType
 	}
+	// if Listener is TLS and Route is TCP set Listener type to TCP as to pass true and return valid match
+	if a == v1.TCPProtocolType && b == v1.TLSProtocolType {
+		b = v1.TCPProtocolType
+	}
 	return a == b
 }
 


Test patch:
diff --git a/source/gateway_test.go b/source/gateway_test.go
index 914992511d..940622e958 100644
--- a/source/gateway_test.go
+++ b/source/gateway_test.go
@@ -19,6 +19,8 @@ package source
 import (
 	"strings"
 	"testing"
+
+	v1 "sigs.k8s.io/gateway-api/apis/v1"
 )
 
 func TestGatewayMatchingHost(t *testing.T) {
@@ -105,6 +107,60 @@ func TestGatewayMatchingHost(t *testing.T) {
 	}
 }
 
+func TestGatewayMatchingProtocol(t *testing.T) {
+	tests := []struct {
+		route, lis string
+		desc       string
+		ok         bool
+	}{
+		{
+			desc:  "protocol-matches-lis-https-route-http",
+			route: "HTTP",
+			lis:   "HTTPS",
+			ok:    true,
+		},
+		{
+			desc:  "protocol-match-invalid-list-https-route-tcp",
+			route: "TCP",
+			lis:   "HTTPS",
+			ok:    false,
+		},
+		{
+			desc:  "protocol-match-valid-lis-tls-route-tls",
+			route: "TLS",
+			lis:   "TLS",
+			ok:    true,
+		},
+		{
+			desc:  "protocol-match-valid-lis-TLS-route-TCP",
+			route: "TCP",
+			lis:   "TLS",
+			ok:    true,
+		},
+		{
+			desc:  "protocol-match-valid-lis-TLS-route-TCP",
+			route: "TLS",
+			lis:   "TCP",
+			ok:    false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.desc, func(t *testing.T) {
+			for i := 0; i < 2; i++ {
+				if ok := gwProtocolMatches(v1.ProtocolType(tt.route), v1.ProtocolType(tt.lis)); ok != tt.ok {
+					t.Errorf(
+						"gwProtocolMatches(%q, %q); got: %v; want: %v",
+						tt.route, tt.lis, ok, tt.ok,
+					)
+				}
+				//tt.a, tt.b = tt.b, tt.a
+			}
+		})
+
+	}
+}
+
 func TestIsDNS1123Domain(t *testing.T) {
 	tests := []struct {
 		desc string