Repository: traefik/traefik (language: go)

Issue:
v3 breaks TCP route HostSNI having multiple entries
### Welcome!

- [X] Yes, I've searched similar issues on [GitHub](https://github.com/traefik/traefik/issues) and didn't find any.
- [X] Yes, I've searched similar issues on the [Traefik community forum](https://community.traefik.io) and didn't find any.

### What did you do?

We configured TCP route based on HostSNI and in the past (in v2) for which we were able to pass several entries into `HostSNI()`:

```json
"Tags": [
"traefik.enable=true",
"traefik.tcp.routers.example-prod-website-https.entrypoints=websecure",
"traefik.tcp.routers.example-prod-website-https.rule=HostSNI(`example.com`,`www.example.com`)",
"traefik.tcp.routers.example-prod-website-https.service=example-prod-website-https",
"traefik.tcp.routers.example-prod-website-https.tls.passthrough=true"
],
```

This seems no longer possible, even with `--core.defaultRuleSyntax=v2`, but we haven't read anything about it the migration docs.

### What did you see instead?

```
error while adding rule Host(`example.com`,`www.example.com`): error while adding rule Host: unexpected number of parameters; got 2, expected one of [1]
```

### What version of Traefik are you using?

docker image traefik:v3.0.0

### What is your environment & configuration?

```yaml
core:
  defaultRuleSyntax: v2

providers:
  consulCatalog:
    refreshInterval: 5s
    prefix: traefik
    exposedByDefault: false
    endpoint:
      address: 127.0.0.1:8500
      scheme: http

entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
  traefik:
    address: ":8080"
```

### If applicable, please paste the log output in DEBUG level

_No response_


Discussion / hints:
Hello,

I recommend reading the migration guide: https://doc.traefik.io/traefik/migration/v2-to-v3/#router-rule-matchers

You should either enable v2 compatibility or split your rule ```HostSNI(`example.com`) || HostSNI(`www.example.com`)```
thanks @ldez but even with 

```
--core.defaultRuleSyntax=v2
```

or 
```
core:
  defaultRuleSyntax: v2
```

We still get the same behaviour and error messages. I updated the main description accordingly. 

Fix patch:
diff --git a/pkg/server/aggregator.go b/pkg/server/aggregator.go
index 75ad759cf6..f015cb43d1 100644
--- a/pkg/server/aggregator.go
+++ b/pkg/server/aggregator.go
@@ -84,6 +84,9 @@ func mergeConfiguration(configurations dynamic.Configurations, defaultEntryPoint
 			for serviceName, service := range configuration.TCP.Services {
 				conf.TCP.Services[provider.MakeQualifiedName(pvd, serviceName)] = service
 			}
+			for modelName, model := range configuration.TCP.Models {
+				conf.TCP.Models[provider.MakeQualifiedName(pvd, modelName)] = model
+			}
 			for serversTransportName, serversTransport := range configuration.TCP.ServersTransports {
 				conf.TCP.ServersTransports[provider.MakeQualifiedName(pvd, serversTransportName)] = serversTransport
 			}
@@ -146,52 +149,50 @@ func mergeConfiguration(configurations dynamic.Configurations, defaultEntryPoint
 }
 
 func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
-	if cfg.HTTP == nil || len(cfg.HTTP.Models) == 0 {
-		return cfg
-	}
-
-	rts := make(map[string]*dynamic.Router)
+	if cfg.HTTP != nil && len(cfg.HTTP.Models) > 0 {
+		rts := make(map[string]*dynamic.Router)
 
-	for name, rt := range cfg.HTTP.Routers {
-		router := rt.DeepCopy()
+		for name, rt := range cfg.HTTP.Routers {
+			router := rt.DeepCopy()
 
-		if !router.DefaultRule && router.RuleSyntax == "" {
-			for _, model := range cfg.HTTP.Models {
-				router.RuleSyntax = model.DefaultRuleSyntax
-				break
+			if !router.DefaultRule && router.RuleSyntax == "" {
+				for _, model := range cfg.HTTP.Models {
+					router.RuleSyntax = model.DefaultRuleSyntax
+					break
+				}
 			}
-		}
 
-		eps := router.EntryPoints
-		router.EntryPoints = nil
+			eps := router.EntryPoints
+			router.EntryPoints = nil
 
-		for _, epName := range eps {
-			m, ok := cfg.HTTP.Models[epName+"@internal"]
-			if ok {
-				cp := router.DeepCopy()
+			for _, epName := range eps {
+				m, ok := cfg.HTTP.Models[epName+"@internal"]
+				if ok {
+					cp := router.DeepCopy()
 
-				cp.EntryPoints = []string{epName}
+					cp.EntryPoints = []string{epName}
 
-				if cp.TLS == nil {
-					cp.TLS = m.TLS
-				}
+					if cp.TLS == nil {
+						cp.TLS = m.TLS
+					}
 
-				cp.Middlewares = append(m.Middlewares, cp.Middlewares...)
+					cp.Middlewares = append(m.Middlewares, cp.Middlewares...)
 
-				rtName := name
-				if len(eps) > 1 {
-					rtName = epName + "-" + name
-				}
-				rts[rtName] = cp
-			} else {
-				router.EntryPoints = append(router.EntryPoints, epName)
+					rtName := name
+					if len(eps) > 1 {
+						rtName = epName + "-" + name
+					}
+					rts[rtName] = cp
+				} else {
+					router.EntryPoints = append(router.EntryPoints, epName)
 
-				rts[name] = router
+					rts[name] = router
+				}
 			}
 		}
-	}
 
-	cfg.HTTP.Routers = rts
+		cfg.HTTP.Routers = rts
+	}
 
 	if cfg.TCP == nil || len(cfg.TCP.Models) == 0 {
 		return cfg
@@ -199,7 +200,7 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
 
 	tcpRouters := make(map[string]*dynamic.TCPRouter)
 
-	for _, rt := range cfg.TCP.Routers {
+	for name, rt := range cfg.TCP.Routers {
 		router := rt.DeepCopy()
 
 		if router.RuleSyntax == "" {
@@ -208,6 +209,8 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
 				break
 			}
 		}
+
+		tcpRouters[name] = router
 	}
 
 	cfg.TCP.Routers = tcpRouters


Test patch:
diff --git a/pkg/server/aggregator_test.go b/pkg/server/aggregator_test.go
index ba5fe44183..b70d261aea 100644
--- a/pkg/server/aggregator_test.go
+++ b/pkg/server/aggregator_test.go
@@ -656,6 +656,50 @@ func Test_applyModel(t *testing.T) {
 				},
 			},
 		},
+		{
+			desc: "with TCP model, two entry points",
+			input: dynamic.Configuration{
+				TCP: &dynamic.TCPConfiguration{
+					Routers: map[string]*dynamic.TCPRouter{
+						"test": {
+							EntryPoints: []string{"websecure", "web"},
+						},
+						"test2": {
+							EntryPoints: []string{"web"},
+							RuleSyntax:  "barfoo",
+						},
+					},
+					Middlewares: make(map[string]*dynamic.TCPMiddleware),
+					Services:    make(map[string]*dynamic.TCPService),
+					Models: map[string]*dynamic.TCPModel{
+						"websecure@internal": {
+							DefaultRuleSyntax: "foobar",
+						},
+					},
+				},
+			},
+			expected: dynamic.Configuration{
+				TCP: &dynamic.TCPConfiguration{
+					Routers: map[string]*dynamic.TCPRouter{
+						"test": {
+							EntryPoints: []string{"websecure", "web"},
+							RuleSyntax:  "foobar",
+						},
+						"test2": {
+							EntryPoints: []string{"web"},
+							RuleSyntax:  "barfoo",
+						},
+					},
+					Middlewares: make(map[string]*dynamic.TCPMiddleware),
+					Services:    make(map[string]*dynamic.TCPService),
+					Models: map[string]*dynamic.TCPModel{
+						"websecure@internal": {
+							DefaultRuleSyntax: "foobar",
+						},
+					},
+				},
+			},
+		},
 	}
 
 	for _, test := range testCases {