Support ALPN for TCP + TLS routers
This commit is contained in:
parent
aff334ffb4
commit
4dc379c601
4 changed files with 228 additions and 34 deletions
|
@ -1,10 +1,12 @@
|
|||
package tcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge/tlsalpn01"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v2/pkg/tcp"
|
||||
|
@ -58,6 +60,7 @@ func Test_addTCPRoute(t *testing.T) {
|
|||
rule string
|
||||
serverName string
|
||||
remoteAddr string
|
||||
protos []string
|
||||
routeErr bool
|
||||
matchErr bool
|
||||
}{
|
||||
|
@ -436,6 +439,66 @@ func Test_addTCPRoute(t *testing.T) {
|
|||
serverName: "bar",
|
||||
remoteAddr: "10.0.0.1:80",
|
||||
},
|
||||
{
|
||||
desc: "Invalid ALPN rule matching ACME-TLS/1",
|
||||
rule: fmt.Sprintf("ALPN(`%s`)", tlsalpn01.ACMETLS1Protocol),
|
||||
protos: []string{"foo"},
|
||||
routeErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Valid ALPN rule matching single protocol",
|
||||
rule: "ALPN(`foo`)",
|
||||
protos: []string{"foo"},
|
||||
},
|
||||
{
|
||||
desc: "Valid ALPN rule matching ACME-TLS/1 protocol",
|
||||
rule: "ALPN(`foo`)",
|
||||
protos: []string{tlsalpn01.ACMETLS1Protocol},
|
||||
matchErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Valid ALPN rule not matching single protocol",
|
||||
rule: "ALPN(`foo`)",
|
||||
protos: []string{"bar"},
|
||||
matchErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Valid alternative case ALPN rule matching single protocol without another being supported",
|
||||
rule: "ALPN(`foo`) && !alpn(`h2`)",
|
||||
protos: []string{"foo", "bar"},
|
||||
},
|
||||
{
|
||||
desc: "Valid alternative case ALPN rule not matching single protocol because of another being supported",
|
||||
rule: "ALPN(`foo`) && !alpn(`h2`)",
|
||||
protos: []string{"foo", "h2", "bar"},
|
||||
matchErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Valid complex alternative case ALPN and HostSNI rule",
|
||||
rule: "ALPN(`foo`) && (!alpn(`h2`) || hostsni(`foo`))",
|
||||
protos: []string{"foo", "bar"},
|
||||
serverName: "foo",
|
||||
},
|
||||
{
|
||||
desc: "Valid complex alternative case ALPN and HostSNI rule not matching by SNI",
|
||||
rule: "ALPN(`foo`) && (!alpn(`h2`) || hostsni(`foo`))",
|
||||
protos: []string{"foo", "bar", "h2"},
|
||||
serverName: "bar",
|
||||
matchErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Valid complex alternative case ALPN and HostSNI rule matching by ALPN",
|
||||
rule: "ALPN(`foo`) && (!alpn(`h2`) || hostsni(`foo`))",
|
||||
protos: []string{"foo", "bar"},
|
||||
serverName: "bar",
|
||||
},
|
||||
{
|
||||
desc: "Valid complex alternative case ALPN and HostSNI rule not matching by protos",
|
||||
rule: "ALPN(`foo`) && (!alpn(`h2`) || hostsni(`foo`))",
|
||||
protos: []string{"h2", "bar"},
|
||||
serverName: "bar",
|
||||
matchErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
@ -471,7 +534,7 @@ func Test_addTCPRoute(t *testing.T) {
|
|||
remoteAddr: fakeAddr{addr: addr},
|
||||
}
|
||||
|
||||
connData, err := NewConnData(test.serverName, conn)
|
||||
connData, err := NewConnData(test.serverName, conn, test.protos)
|
||||
require.NoError(t, err)
|
||||
|
||||
matchingHandler, _ := router.Match(connData)
|
||||
|
@ -918,6 +981,75 @@ func Test_ClientIP(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_ALPN(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
ruleALPNProtos []string
|
||||
connProto string
|
||||
buildErr bool
|
||||
matchErr bool
|
||||
}{
|
||||
{
|
||||
desc: "Empty",
|
||||
buildErr: true,
|
||||
},
|
||||
{
|
||||
desc: "ACME TLS proto",
|
||||
ruleALPNProtos: []string{tlsalpn01.ACMETLS1Protocol},
|
||||
buildErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Not matching empty proto",
|
||||
ruleALPNProtos: []string{"h2"},
|
||||
matchErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Not matching ALPN",
|
||||
ruleALPNProtos: []string{"h2"},
|
||||
connProto: "mqtt",
|
||||
matchErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Matching ALPN",
|
||||
ruleALPNProtos: []string{"h2"},
|
||||
connProto: "h2",
|
||||
},
|
||||
{
|
||||
desc: "Not matching multiple ALPNs",
|
||||
ruleALPNProtos: []string{"h2", "mqtt"},
|
||||
connProto: "h2c",
|
||||
matchErr: true,
|
||||
},
|
||||
{
|
||||
desc: "Matching multiple ALPNs",
|
||||
ruleALPNProtos: []string{"h2", "h2c", "mqtt"},
|
||||
connProto: "h2c",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
matchersTree := &matchersTree{}
|
||||
err := alpn(matchersTree, test.ruleALPNProtos...)
|
||||
if test.buildErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
meta := ConnData{
|
||||
alpnProtos: []string{test.connProto},
|
||||
}
|
||||
|
||||
assert.Equal(t, test.matchErr, !matchersTree.match(meta))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Priority(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue