mirror of
				https://github.com/traefik/traefik.git
				synced 2025-10-31 08:21:27 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			379 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			379 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package tcp
 | |
| 
 | |
| import (
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| 	"github.com/traefik/traefik/v3/pkg/tcp"
 | |
| )
 | |
| 
 | |
| func Test_HostSNICatchAll(t *testing.T) {
 | |
| 	testCases := []struct {
 | |
| 		desc       string
 | |
| 		rule       string
 | |
| 		isCatchAll bool
 | |
| 	}{
 | |
| 		{
 | |
| 			desc: "HostSNI(`example.com`) is not catchAll",
 | |
| 			rule: "HostSNI(`example.com`)",
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "HostSNI(`*`) is catchAll",
 | |
| 			rule:       "HostSNI(`*`)",
 | |
| 			isCatchAll: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "HostSNIRegexp(`^.*$`) is not catchAll",
 | |
| 			rule:       "HostSNIRegexp(`.*`)",
 | |
| 			isCatchAll: false,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, test := range testCases {
 | |
| 		t.Run(test.desc, func(t *testing.T) {
 | |
| 			t.Parallel()
 | |
| 
 | |
| 			muxer, err := NewMuxer()
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			handler, catchAll := muxer.Match(ConnData{
 | |
| 				serverName: "example.com",
 | |
| 			})
 | |
| 			require.NotNil(t, handler)
 | |
| 			assert.Equal(t, test.isCatchAll, catchAll)
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func Test_HostSNI(t *testing.T) {
 | |
| 	testCases := []struct {
 | |
| 		desc       string
 | |
| 		rule       string
 | |
| 		serverName string
 | |
| 		buildErr   bool
 | |
| 		match      bool
 | |
| 	}{
 | |
| 		{
 | |
| 			desc:     "Empty",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNI matcher (empty host)",
 | |
| 			rule:     "HostSNI(``)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNI matcher (too many parameters)",
 | |
| 			rule:     "HostSNI(`example.com`, `example.org`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNI matcher (globing sub domain)",
 | |
| 			rule:     "HostSNI(`*.com`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNI matcher (non ASCII host)",
 | |
| 			rule:     "HostSNI(`🦭.com`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Valid HostSNI matcher - puny-coded emoji",
 | |
| 			rule:       "HostSNI(`xn--9t9h.com`)",
 | |
| 			serverName: "xn--9t9h.com",
 | |
| 			match:      true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Valid HostSNI matcher - puny-coded emoji but emoji in server name",
 | |
| 			rule:       "HostSNI(`xn--9t9h.com`)",
 | |
| 			serverName: "🦭.com",
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Matching hosts",
 | |
| 			rule:       "HostSNI(`example.com`)",
 | |
| 			serverName: "example.com",
 | |
| 			match:      true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "No matching hosts",
 | |
| 			rule:       "HostSNI(`example.com`)",
 | |
| 			serverName: "example.org",
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Matching globing host `*`",
 | |
| 			rule:       "HostSNI(`*`)",
 | |
| 			serverName: "example.com",
 | |
| 			match:      true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Matching globing host `*` and empty server name",
 | |
| 			rule:       "HostSNI(`*`)",
 | |
| 			serverName: "",
 | |
| 			match:      true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Matching host with trailing dot",
 | |
| 			rule:       "HostSNI(`example.com.`)",
 | |
| 			serverName: "example.com.",
 | |
| 			match:      true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Matching host with trailing dot but not in server name",
 | |
| 			rule:       "HostSNI(`example.com.`)",
 | |
| 			serverName: "example.com",
 | |
| 			match:      true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:       "Matching hosts with subdomains",
 | |
| 			rule:       "HostSNI(`foo.example.com`)",
 | |
| 			serverName: "foo.example.com",
 | |
| 			match:      true,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, test := range testCases {
 | |
| 		t.Run(test.desc, func(t *testing.T) {
 | |
| 			t.Parallel()
 | |
| 
 | |
| 			muxer, err := NewMuxer()
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
 | |
| 			if test.buildErr {
 | |
| 				require.Error(t, err)
 | |
| 				return
 | |
| 			}
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			meta := ConnData{
 | |
| 				serverName: test.serverName,
 | |
| 			}
 | |
| 
 | |
| 			handler, _ := muxer.Match(meta)
 | |
| 			require.Equal(t, test.match, handler != nil)
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func Test_HostSNIRegexp(t *testing.T) {
 | |
| 	testCases := []struct {
 | |
| 		desc     string
 | |
| 		rule     string
 | |
| 		expected map[string]bool
 | |
| 		buildErr bool
 | |
| 		match    bool
 | |
| 	}{
 | |
| 		{
 | |
| 			desc:     "Empty",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNIRegexp matcher (empty host)",
 | |
| 			rule:     "HostSNIRegexp(``)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNIRegexp matcher (non ASCII host)",
 | |
| 			rule:     "HostSNIRegexp(`🦭.com`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNIRegexp matcher (invalid regexp)",
 | |
| 			rule:     "HostSNIRegexp(`(example.com`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid HostSNIRegexp matcher (too many parameters)",
 | |
| 			rule:     "HostSNIRegexp(`example.com`, `example.org`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc: "valid HostSNIRegexp matcher",
 | |
| 			rule: "HostSNIRegexp(`^example\\.(com|org)$`)",
 | |
| 			expected: map[string]bool{
 | |
| 				"example.com":  true,
 | |
| 				"example.com.": false,
 | |
| 				"EXAMPLE.com":  false,
 | |
| 				"example.org":  true,
 | |
| 				"exampleuorg":  false,
 | |
| 				"":             false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			desc: "valid HostSNIRegexp matcher with Traefik v2 syntax",
 | |
| 			rule: "HostSNIRegexp(`example.{tld:(com|org)}`)",
 | |
| 			expected: map[string]bool{
 | |
| 				"example.com":  false,
 | |
| 				"example.com.": false,
 | |
| 				"EXAMPLE.com":  false,
 | |
| 				"example.org":  false,
 | |
| 				"exampleuorg":  false,
 | |
| 				"":             false,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, test := range testCases {
 | |
| 		t.Run(test.desc, func(t *testing.T) {
 | |
| 			t.Parallel()
 | |
| 
 | |
| 			muxer, err := NewMuxer()
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
 | |
| 			if test.buildErr {
 | |
| 				require.Error(t, err)
 | |
| 				return
 | |
| 			}
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			for serverName, match := range test.expected {
 | |
| 				meta := ConnData{
 | |
| 					serverName: serverName,
 | |
| 				}
 | |
| 
 | |
| 				handler, _ := muxer.Match(meta)
 | |
| 				assert.Equal(t, match, handler != nil, serverName)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func Test_ClientIP(t *testing.T) {
 | |
| 	testCases := []struct {
 | |
| 		desc     string
 | |
| 		rule     string
 | |
| 		expected map[string]bool
 | |
| 		buildErr bool
 | |
| 	}{
 | |
| 		{
 | |
| 			desc:     "Empty",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid ClientIP matcher (empty host)",
 | |
| 			rule:     "ClientIP(``)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid ClientIP matcher (non ASCII host)",
 | |
| 			rule:     "ClientIP(`🦭/32`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid ClientIP matcher (too many parameters)",
 | |
| 			rule:     "ClientIP(`127.0.0.1`, `127.0.0.2`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc: "valid ClientIP matcher",
 | |
| 			rule: "ClientIP(`20.20.20.20`)",
 | |
| 			expected: map[string]bool{
 | |
| 				"20.20.20.20": true,
 | |
| 				"10.10.10.10": false,
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			desc: "valid ClientIP matcher with CIDR",
 | |
| 			rule: "ClientIP(`20.20.20.20/24`)",
 | |
| 			expected: map[string]bool{
 | |
| 				"20.20.20.20": true,
 | |
| 				"20.20.20.40": true,
 | |
| 				"10.10.10.10": false,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, test := range testCases {
 | |
| 		t.Run(test.desc, func(t *testing.T) {
 | |
| 			t.Parallel()
 | |
| 
 | |
| 			muxer, err := NewMuxer()
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
 | |
| 			if test.buildErr {
 | |
| 				require.Error(t, err)
 | |
| 				return
 | |
| 			}
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			for remoteIP, match := range test.expected {
 | |
| 				meta := ConnData{
 | |
| 					remoteIP: remoteIP,
 | |
| 				}
 | |
| 
 | |
| 				handler, _ := muxer.Match(meta)
 | |
| 				assert.Equal(t, match, handler != nil, remoteIP)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func Test_ALPN(t *testing.T) {
 | |
| 	testCases := []struct {
 | |
| 		desc     string
 | |
| 		rule     string
 | |
| 		expected map[string]bool
 | |
| 		buildErr bool
 | |
| 	}{
 | |
| 		{
 | |
| 			desc:     "Empty",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid ALPN matcher (TLS proto)",
 | |
| 			rule:     "ALPN(`acme-tls/1`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid ALPN matcher (empty parameters)",
 | |
| 			rule:     "ALPN(``)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc:     "Invalid ALPN matcher (too many parameters)",
 | |
| 			rule:     "ALPN(`h2`, `mqtt`)",
 | |
| 			buildErr: true,
 | |
| 		},
 | |
| 		{
 | |
| 			desc: "Valid ALPN matcher",
 | |
| 			rule: "ALPN(`h2`)",
 | |
| 			expected: map[string]bool{
 | |
| 				"h2":   true,
 | |
| 				"mqtt": false,
 | |
| 				"":     false,
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, test := range testCases {
 | |
| 		t.Run(test.desc, func(t *testing.T) {
 | |
| 			t.Parallel()
 | |
| 
 | |
| 			muxer, err := NewMuxer()
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			err = muxer.AddRoute(test.rule, "", 0, tcp.HandlerFunc(func(conn tcp.WriteCloser) {}))
 | |
| 			if test.buildErr {
 | |
| 				require.Error(t, err)
 | |
| 				return
 | |
| 			}
 | |
| 			require.NoError(t, err)
 | |
| 
 | |
| 			for proto, match := range test.expected {
 | |
| 				meta := ConnData{
 | |
| 					alpnProtos: []string{proto},
 | |
| 				}
 | |
| 
 | |
| 				handler, _ := muxer.Match(meta)
 | |
| 				assert.Equal(t, match, handler != nil, proto)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 |