123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- package basic
- import (
- "crypto/tls"
- "fmt"
- "strings"
- "time"
- "github.com/onsi/ginkgo/v2"
- "github.com/fatedier/frp/pkg/transport"
- "github.com/fatedier/frp/test/e2e/framework"
- "github.com/fatedier/frp/test/e2e/framework/consts"
- "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
- "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
- "github.com/fatedier/frp/test/e2e/pkg/port"
- "github.com/fatedier/frp/test/e2e/pkg/request"
- )
- var _ = ginkgo.Describe("[Feature: Basic]", func() {
- f := framework.NewDefaultFramework()
- ginkgo.Describe("TCP && UDP", func() {
- types := []string{"tcp", "udp"}
- for _, t := range types {
- proxyType := t
- ginkgo.It(fmt.Sprintf("Expose a %s echo server", strings.ToUpper(proxyType)), func() {
- serverConf := consts.LegacyDefaultServerConfig
- clientConf := consts.LegacyDefaultClientConfig
- localPortName := ""
- protocol := "tcp"
- switch proxyType {
- case "tcp":
- localPortName = framework.TCPEchoServerPort
- protocol = "tcp"
- case "udp":
- localPortName = framework.UDPEchoServerPort
- protocol = "udp"
- }
- getProxyConf := func(proxyName string, portName string, extra string) string {
- return fmt.Sprintf(`
- [%s]
- type = %s
- local_port = {{ .%s }}
- remote_port = {{ .%s }}
- `+extra, proxyName, proxyType, localPortName, portName)
- }
- tests := []struct {
- proxyName string
- portName string
- extraConfig string
- }{
- {
- proxyName: "normal",
- portName: port.GenName("Normal"),
- },
- {
- proxyName: "with-encryption",
- portName: port.GenName("WithEncryption"),
- extraConfig: "use_encryption = true",
- },
- {
- proxyName: "with-compression",
- portName: port.GenName("WithCompression"),
- extraConfig: "use_compression = true",
- },
- {
- proxyName: "with-encryption-and-compression",
- portName: port.GenName("WithEncryptionAndCompression"),
- extraConfig: `
- use_encryption = true
- use_compression = true
- `,
- },
- }
- // build all client config
- for _, test := range tests {
- clientConf += getProxyConf(test.proxyName, test.portName, test.extraConfig) + "\n"
- }
- // run frps and frpc
- f.RunProcesses([]string{serverConf}, []string{clientConf})
- for _, test := range tests {
- framework.NewRequestExpect(f).
- Protocol(protocol).
- PortName(test.portName).
- Explain(test.proxyName).
- Ensure()
- }
- })
- }
- })
- ginkgo.Describe("HTTP", func() {
- ginkgo.It("proxy to HTTP server", func() {
- serverConf := consts.LegacyDefaultServerConfig
- vhostHTTPPort := f.AllocPort()
- serverConf += fmt.Sprintf(`
- vhost_http_port = %d
- `, vhostHTTPPort)
- clientConf := consts.LegacyDefaultClientConfig
- getProxyConf := func(proxyName string, customDomains string, extra string) string {
- return fmt.Sprintf(`
- [%s]
- type = http
- local_port = {{ .%s }}
- custom_domains = %s
- `+extra, proxyName, framework.HTTPSimpleServerPort, customDomains)
- }
- tests := []struct {
- proxyName string
- customDomains string
- extraConfig string
- }{
- {
- proxyName: "normal",
- },
- {
- proxyName: "with-encryption",
- extraConfig: "use_encryption = true",
- },
- {
- proxyName: "with-compression",
- extraConfig: "use_compression = true",
- },
- {
- proxyName: "with-encryption-and-compression",
- extraConfig: `
- use_encryption = true
- use_compression = true
- `,
- },
- {
- proxyName: "multiple-custom-domains",
- customDomains: "a.example.com, b.example.com",
- },
- }
- // build all client config
- for i, test := range tests {
- if tests[i].customDomains == "" {
- tests[i].customDomains = test.proxyName + ".example.com"
- }
- clientConf += getProxyConf(test.proxyName, tests[i].customDomains, test.extraConfig) + "\n"
- }
- // run frps and frpc
- f.RunProcesses([]string{serverConf}, []string{clientConf})
- for _, test := range tests {
- for _, domain := range strings.Split(test.customDomains, ",") {
- domain = strings.TrimSpace(domain)
- framework.NewRequestExpect(f).
- Explain(test.proxyName + "-" + domain).
- Port(vhostHTTPPort).
- RequestModify(func(r *request.Request) {
- r.HTTP().HTTPHost(domain)
- }).
- Ensure()
- }
- }
- // not exist host
- framework.NewRequestExpect(f).
- Explain("not exist host").
- Port(vhostHTTPPort).
- RequestModify(func(r *request.Request) {
- r.HTTP().HTTPHost("not-exist.example.com")
- }).
- Ensure(framework.ExpectResponseCode(404))
- })
- })
- ginkgo.Describe("HTTPS", func() {
- ginkgo.It("proxy to HTTPS server", func() {
- serverConf := consts.LegacyDefaultServerConfig
- vhostHTTPSPort := f.AllocPort()
- serverConf += fmt.Sprintf(`
- vhost_https_port = %d
- `, vhostHTTPSPort)
- localPort := f.AllocPort()
- clientConf := consts.LegacyDefaultClientConfig
- getProxyConf := func(proxyName string, customDomains string, extra string) string {
- return fmt.Sprintf(`
- [%s]
- type = https
- local_port = %d
- custom_domains = %s
- `+extra, proxyName, localPort, customDomains)
- }
- tests := []struct {
- proxyName string
- customDomains string
- extraConfig string
- }{
- {
- proxyName: "normal",
- },
- {
- proxyName: "with-encryption",
- extraConfig: "use_encryption = true",
- },
- {
- proxyName: "with-compression",
- extraConfig: "use_compression = true",
- },
- {
- proxyName: "with-encryption-and-compression",
- extraConfig: `
- use_encryption = true
- use_compression = true
- `,
- },
- {
- proxyName: "multiple-custom-domains",
- customDomains: "a.example.com, b.example.com",
- },
- }
- // build all client config
- for i, test := range tests {
- if tests[i].customDomains == "" {
- tests[i].customDomains = test.proxyName + ".example.com"
- }
- clientConf += getProxyConf(test.proxyName, tests[i].customDomains, test.extraConfig) + "\n"
- }
- // run frps and frpc
- f.RunProcesses([]string{serverConf}, []string{clientConf})
- tlsConfig, err := transport.NewServerTLSConfig("", "", "")
- framework.ExpectNoError(err)
- localServer := httpserver.New(
- httpserver.WithBindPort(localPort),
- httpserver.WithTLSConfig(tlsConfig),
- httpserver.WithResponse([]byte("test")),
- )
- f.RunServer("", localServer)
- for _, test := range tests {
- for _, domain := range strings.Split(test.customDomains, ",") {
- domain = strings.TrimSpace(domain)
- framework.NewRequestExpect(f).
- Explain(test.proxyName + "-" + domain).
- Port(vhostHTTPSPort).
- RequestModify(func(r *request.Request) {
- r.HTTPS().HTTPHost(domain).TLSConfig(&tls.Config{
- ServerName: domain,
- InsecureSkipVerify: true,
- })
- }).
- ExpectResp([]byte("test")).
- Ensure()
- }
- }
- // not exist host
- notExistDomain := "not-exist.example.com"
- framework.NewRequestExpect(f).
- Explain("not exist host").
- Port(vhostHTTPSPort).
- RequestModify(func(r *request.Request) {
- r.HTTPS().HTTPHost(notExistDomain).TLSConfig(&tls.Config{
- ServerName: notExistDomain,
- InsecureSkipVerify: true,
- })
- }).
- ExpectError(true).
- Ensure()
- })
- })
- ginkgo.Describe("STCP && SUDP && XTCP", func() {
- types := []string{"stcp", "sudp", "xtcp"}
- for _, t := range types {
- proxyType := t
- ginkgo.It(fmt.Sprintf("Expose echo server with %s", strings.ToUpper(proxyType)), func() {
- serverConf := consts.LegacyDefaultServerConfig
- clientServerConf := consts.LegacyDefaultClientConfig + "\nuser = user1"
- clientVisitorConf := consts.LegacyDefaultClientConfig + "\nuser = user1"
- clientUser2VisitorConf := consts.LegacyDefaultClientConfig + "\nuser = user2"
- localPortName := ""
- protocol := "tcp"
- switch proxyType {
- case "stcp":
- localPortName = framework.TCPEchoServerPort
- protocol = "tcp"
- case "sudp":
- localPortName = framework.UDPEchoServerPort
- protocol = "udp"
- case "xtcp":
- localPortName = framework.TCPEchoServerPort
- protocol = "tcp"
- ginkgo.Skip("stun server is not stable")
- }
- correctSK := "abc"
- wrongSK := "123"
- getProxyServerConf := func(proxyName string, extra string) string {
- return fmt.Sprintf(`
- [%s]
- type = %s
- role = server
- sk = %s
- local_port = {{ .%s }}
- `+extra, proxyName, proxyType, correctSK, localPortName)
- }
- getProxyVisitorConf := func(proxyName string, portName, visitorSK, extra string) string {
- return fmt.Sprintf(`
- [%s]
- type = %s
- role = visitor
- server_name = %s
- sk = %s
- bind_port = {{ .%s }}
- `+extra, proxyName, proxyType, proxyName, visitorSK, portName)
- }
- tests := []struct {
- proxyName string
- bindPortName string
- visitorSK string
- commonExtraConfig string
- proxyExtraConfig string
- visitorExtraConfig string
- expectError bool
- deployUser2Client bool
- // skipXTCP is used to skip xtcp test case
- skipXTCP bool
- }{
- {
- proxyName: "normal",
- bindPortName: port.GenName("Normal"),
- visitorSK: correctSK,
- skipXTCP: true,
- },
- {
- proxyName: "with-encryption",
- bindPortName: port.GenName("WithEncryption"),
- visitorSK: correctSK,
- commonExtraConfig: "use_encryption = true",
- skipXTCP: true,
- },
- {
- proxyName: "with-compression",
- bindPortName: port.GenName("WithCompression"),
- visitorSK: correctSK,
- commonExtraConfig: "use_compression = true",
- skipXTCP: true,
- },
- {
- proxyName: "with-encryption-and-compression",
- bindPortName: port.GenName("WithEncryptionAndCompression"),
- visitorSK: correctSK,
- commonExtraConfig: `
- use_encryption = true
- use_compression = true
- `,
- skipXTCP: true,
- },
- {
- proxyName: "with-error-sk",
- bindPortName: port.GenName("WithErrorSK"),
- visitorSK: wrongSK,
- expectError: true,
- },
- {
- proxyName: "allowed-user",
- bindPortName: port.GenName("AllowedUser"),
- visitorSK: correctSK,
- proxyExtraConfig: "allow_users = another, user2",
- visitorExtraConfig: "server_user = user1",
- deployUser2Client: true,
- },
- {
- proxyName: "not-allowed-user",
- bindPortName: port.GenName("NotAllowedUser"),
- visitorSK: correctSK,
- proxyExtraConfig: "allow_users = invalid",
- visitorExtraConfig: "server_user = user1",
- expectError: true,
- },
- {
- proxyName: "allow-all",
- bindPortName: port.GenName("AllowAll"),
- visitorSK: correctSK,
- proxyExtraConfig: "allow_users = *",
- visitorExtraConfig: "server_user = user1",
- deployUser2Client: true,
- },
- }
- // build all client config
- for _, test := range tests {
- clientServerConf += getProxyServerConf(test.proxyName, test.commonExtraConfig+"\n"+test.proxyExtraConfig) + "\n"
- }
- for _, test := range tests {
- config := getProxyVisitorConf(
- test.proxyName, test.bindPortName, test.visitorSK, test.commonExtraConfig+"\n"+test.visitorExtraConfig,
- ) + "\n"
- if test.deployUser2Client {
- clientUser2VisitorConf += config
- } else {
- clientVisitorConf += config
- }
- }
- // run frps and frpc
- f.RunProcesses([]string{serverConf}, []string{clientServerConf, clientVisitorConf, clientUser2VisitorConf})
- for _, test := range tests {
- timeout := time.Second
- if t == "xtcp" {
- if test.skipXTCP {
- continue
- }
- timeout = 10 * time.Second
- }
- framework.NewRequestExpect(f).
- RequestModify(func(r *request.Request) {
- r.Timeout(timeout)
- }).
- Protocol(protocol).
- PortName(test.bindPortName).
- Explain(test.proxyName).
- ExpectError(test.expectError).
- Ensure()
- }
- })
- }
- })
- ginkgo.Describe("TCPMUX", func() {
- ginkgo.It("Type tcpmux", func() {
- serverConf := consts.LegacyDefaultServerConfig
- clientConf := consts.LegacyDefaultClientConfig
- tcpmuxHTTPConnectPortName := port.GenName("TCPMUX")
- serverConf += fmt.Sprintf(`
- tcpmux_httpconnect_port = {{ .%s }}
- `, tcpmuxHTTPConnectPortName)
- getProxyConf := func(proxyName string, extra string) string {
- return fmt.Sprintf(`
- [%s]
- type = tcpmux
- multiplexer = httpconnect
- local_port = {{ .%s }}
- custom_domains = %s
- `+extra, proxyName, port.GenName(proxyName), proxyName)
- }
- tests := []struct {
- proxyName string
- extraConfig string
- }{
- {
- proxyName: "normal",
- },
- {
- proxyName: "with-encryption",
- extraConfig: "use_encryption = true",
- },
- {
- proxyName: "with-compression",
- extraConfig: "use_compression = true",
- },
- {
- proxyName: "with-encryption-and-compression",
- extraConfig: `
- use_encryption = true
- use_compression = true
- `,
- },
- }
- // build all client config
- for _, test := range tests {
- clientConf += getProxyConf(test.proxyName, test.extraConfig) + "\n"
- localServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(f.AllocPort()), streamserver.WithRespContent([]byte(test.proxyName)))
- f.RunServer(port.GenName(test.proxyName), localServer)
- }
- // run frps and frpc
- f.RunProcesses([]string{serverConf}, []string{clientConf})
- // Request without HTTP connect should get error
- framework.NewRequestExpect(f).
- PortName(tcpmuxHTTPConnectPortName).
- ExpectError(true).
- Explain("request without HTTP connect expect error").
- Ensure()
- proxyURL := fmt.Sprintf("http://127.0.0.1:%d", f.PortByName(tcpmuxHTTPConnectPortName))
- // Request with incorrect connect hostname
- framework.NewRequestExpect(f).RequestModify(func(r *request.Request) {
- r.Addr("invalid").Proxy(proxyURL)
- }).ExpectError(true).Explain("request without HTTP connect expect error").Ensure()
- // Request with correct connect hostname
- for _, test := range tests {
- framework.NewRequestExpect(f).RequestModify(func(r *request.Request) {
- r.Addr(test.proxyName).Proxy(proxyURL)
- }).ExpectResp([]byte(test.proxyName)).Explain(test.proxyName).Ensure()
- }
- })
- })
- })
|