tcpmux.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package basic
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "github.com/onsi/ginkgo/v2"
  8. httppkg "github.com/fatedier/frp/pkg/util/http"
  9. "github.com/fatedier/frp/test/e2e/framework"
  10. "github.com/fatedier/frp/test/e2e/framework/consts"
  11. "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
  12. "github.com/fatedier/frp/test/e2e/pkg/request"
  13. "github.com/fatedier/frp/test/e2e/pkg/rpc"
  14. )
  15. var _ = ginkgo.Describe("[Feature: TCPMUX httpconnect]", func() {
  16. f := framework.NewDefaultFramework()
  17. getDefaultServerConf := func(httpconnectPort int) string {
  18. conf := consts.LegacyDefaultServerConfig + `
  19. tcpmux_httpconnect_port = %d
  20. `
  21. return fmt.Sprintf(conf, httpconnectPort)
  22. }
  23. newServer := func(port int, respContent string) *streamserver.Server {
  24. return streamserver.New(
  25. streamserver.TCP,
  26. streamserver.WithBindPort(port),
  27. streamserver.WithRespContent([]byte(respContent)),
  28. )
  29. }
  30. proxyURLWithAuth := func(username, password string, port int) string {
  31. if username == "" {
  32. return fmt.Sprintf("http://127.0.0.1:%d", port)
  33. }
  34. return fmt.Sprintf("http://%s:%s@127.0.0.1:%d", username, password, port)
  35. }
  36. ginkgo.It("Route by HTTP user", func() {
  37. vhostPort := f.AllocPort()
  38. serverConf := getDefaultServerConf(vhostPort)
  39. fooPort := f.AllocPort()
  40. f.RunServer("", newServer(fooPort, "foo"))
  41. barPort := f.AllocPort()
  42. f.RunServer("", newServer(barPort, "bar"))
  43. otherPort := f.AllocPort()
  44. f.RunServer("", newServer(otherPort, "other"))
  45. clientConf := consts.LegacyDefaultClientConfig
  46. clientConf += fmt.Sprintf(`
  47. [foo]
  48. type = tcpmux
  49. multiplexer = httpconnect
  50. local_port = %d
  51. custom_domains = normal.example.com
  52. route_by_http_user = user1
  53. [bar]
  54. type = tcpmux
  55. multiplexer = httpconnect
  56. local_port = %d
  57. custom_domains = normal.example.com
  58. route_by_http_user = user2
  59. [catchAll]
  60. type = tcpmux
  61. multiplexer = httpconnect
  62. local_port = %d
  63. custom_domains = normal.example.com
  64. `, fooPort, barPort, otherPort)
  65. f.RunProcesses([]string{serverConf}, []string{clientConf})
  66. // user1
  67. framework.NewRequestExpect(f).Explain("user1").
  68. RequestModify(func(r *request.Request) {
  69. r.Addr("normal.example.com").Proxy(proxyURLWithAuth("user1", "", vhostPort))
  70. }).
  71. ExpectResp([]byte("foo")).
  72. Ensure()
  73. // user2
  74. framework.NewRequestExpect(f).Explain("user2").
  75. RequestModify(func(r *request.Request) {
  76. r.Addr("normal.example.com").Proxy(proxyURLWithAuth("user2", "", vhostPort))
  77. }).
  78. ExpectResp([]byte("bar")).
  79. Ensure()
  80. // other user
  81. framework.NewRequestExpect(f).Explain("other user").
  82. RequestModify(func(r *request.Request) {
  83. r.Addr("normal.example.com").Proxy(proxyURLWithAuth("user3", "", vhostPort))
  84. }).
  85. ExpectResp([]byte("other")).
  86. Ensure()
  87. })
  88. ginkgo.It("Proxy auth", func() {
  89. vhostPort := f.AllocPort()
  90. serverConf := getDefaultServerConf(vhostPort)
  91. fooPort := f.AllocPort()
  92. f.RunServer("", newServer(fooPort, "foo"))
  93. clientConf := consts.LegacyDefaultClientConfig
  94. clientConf += fmt.Sprintf(`
  95. [test]
  96. type = tcpmux
  97. multiplexer = httpconnect
  98. local_port = %d
  99. custom_domains = normal.example.com
  100. http_user = test
  101. http_pwd = test
  102. `, fooPort)
  103. f.RunProcesses([]string{serverConf}, []string{clientConf})
  104. // not set auth header
  105. framework.NewRequestExpect(f).Explain("no auth").
  106. RequestModify(func(r *request.Request) {
  107. r.Addr("normal.example.com").Proxy(proxyURLWithAuth("", "", vhostPort))
  108. }).
  109. ExpectError(true).
  110. Ensure()
  111. // set incorrect auth header
  112. framework.NewRequestExpect(f).Explain("incorrect auth").
  113. RequestModify(func(r *request.Request) {
  114. r.Addr("normal.example.com").Proxy(proxyURLWithAuth("test", "invalid", vhostPort))
  115. }).
  116. ExpectError(true).
  117. Ensure()
  118. // set correct auth header
  119. framework.NewRequestExpect(f).Explain("correct auth").
  120. RequestModify(func(r *request.Request) {
  121. r.Addr("normal.example.com").Proxy(proxyURLWithAuth("test", "test", vhostPort))
  122. }).
  123. ExpectResp([]byte("foo")).
  124. Ensure()
  125. })
  126. ginkgo.It("TCPMux Passthrough", func() {
  127. vhostPort := f.AllocPort()
  128. serverConf := getDefaultServerConf(vhostPort)
  129. serverConf += `
  130. tcpmux_passthrough = true
  131. `
  132. var (
  133. respErr error
  134. connectRequestHost string
  135. )
  136. newServer := func(port int) *streamserver.Server {
  137. return streamserver.New(
  138. streamserver.TCP,
  139. streamserver.WithBindPort(port),
  140. streamserver.WithCustomHandler(func(conn net.Conn) {
  141. defer conn.Close()
  142. // read HTTP CONNECT request
  143. bufioReader := bufio.NewReader(conn)
  144. req, err := http.ReadRequest(bufioReader)
  145. if err != nil {
  146. respErr = err
  147. return
  148. }
  149. connectRequestHost = req.Host
  150. // return ok response
  151. res := httppkg.OkResponse()
  152. if res.Body != nil {
  153. defer res.Body.Close()
  154. }
  155. _ = res.Write(conn)
  156. buf, err := rpc.ReadBytes(conn)
  157. if err != nil {
  158. respErr = err
  159. return
  160. }
  161. _, _ = rpc.WriteBytes(conn, buf)
  162. }),
  163. )
  164. }
  165. localPort := f.AllocPort()
  166. f.RunServer("", newServer(localPort))
  167. clientConf := consts.LegacyDefaultClientConfig
  168. clientConf += fmt.Sprintf(`
  169. [test]
  170. type = tcpmux
  171. multiplexer = httpconnect
  172. local_port = %d
  173. custom_domains = normal.example.com
  174. `, localPort)
  175. f.RunProcesses([]string{serverConf}, []string{clientConf})
  176. framework.NewRequestExpect(f).
  177. RequestModify(func(r *request.Request) {
  178. r.Addr("normal.example.com").Proxy(proxyURLWithAuth("", "", vhostPort)).Body([]byte("frp"))
  179. }).
  180. ExpectResp([]byte("frp")).
  181. Ensure()
  182. framework.ExpectNoError(respErr)
  183. framework.ExpectEqualValues(connectRequestHost, "normal.example.com")
  184. })
  185. })