client.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. package plugin
  2. import (
  3. "crypto/tls"
  4. "fmt"
  5. "strconv"
  6. "github.com/onsi/ginkgo/v2"
  7. "github.com/fatedier/frp/pkg/transport"
  8. "github.com/fatedier/frp/test/e2e/framework"
  9. "github.com/fatedier/frp/test/e2e/framework/consts"
  10. "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
  11. "github.com/fatedier/frp/test/e2e/pkg/cert"
  12. "github.com/fatedier/frp/test/e2e/pkg/port"
  13. "github.com/fatedier/frp/test/e2e/pkg/request"
  14. )
  15. var _ = ginkgo.Describe("[Feature: Client-Plugins]", func() {
  16. f := framework.NewDefaultFramework()
  17. ginkgo.Describe("UnixDomainSocket", func() {
  18. ginkgo.It("Expose a unix domain socket echo server", func() {
  19. serverConf := consts.DefaultServerConfig
  20. clientConf := consts.DefaultClientConfig
  21. getProxyConf := func(proxyName string, portName string, extra string) string {
  22. return fmt.Sprintf(`
  23. [[proxies]]
  24. name = "%s"
  25. type = "tcp"
  26. remotePort = {{ .%s }}
  27. [proxies.plugin]
  28. type = "unix_domain_socket"
  29. unixPath = "{{ .%s }}"
  30. `+extra, proxyName, portName, framework.UDSEchoServerAddr)
  31. }
  32. tests := []struct {
  33. proxyName string
  34. portName string
  35. extraConfig string
  36. }{
  37. {
  38. proxyName: "normal",
  39. portName: port.GenName("Normal"),
  40. },
  41. {
  42. proxyName: "with-encryption",
  43. portName: port.GenName("WithEncryption"),
  44. extraConfig: "transport.useEncryption = true",
  45. },
  46. {
  47. proxyName: "with-compression",
  48. portName: port.GenName("WithCompression"),
  49. extraConfig: "transport.useCompression = true",
  50. },
  51. {
  52. proxyName: "with-encryption-and-compression",
  53. portName: port.GenName("WithEncryptionAndCompression"),
  54. extraConfig: `
  55. transport.useEncryption = true
  56. transport.useCompression = true
  57. `,
  58. },
  59. }
  60. // build all client config
  61. for _, test := range tests {
  62. clientConf += getProxyConf(test.proxyName, test.portName, test.extraConfig) + "\n"
  63. }
  64. // run frps and frpc
  65. f.RunProcesses([]string{serverConf}, []string{clientConf})
  66. for _, test := range tests {
  67. framework.NewRequestExpect(f).Port(f.PortByName(test.portName)).Ensure()
  68. }
  69. })
  70. })
  71. ginkgo.It("http_proxy", func() {
  72. serverConf := consts.DefaultServerConfig
  73. clientConf := consts.DefaultClientConfig
  74. remotePort := f.AllocPort()
  75. clientConf += fmt.Sprintf(`
  76. [[proxies]]
  77. name = "tcp"
  78. type = "tcp"
  79. remotePort = %d
  80. [proxies.plugin]
  81. type = "http_proxy"
  82. httpUser = "abc"
  83. httpPassword = "123"
  84. `, remotePort)
  85. f.RunProcesses([]string{serverConf}, []string{clientConf})
  86. // http proxy, no auth info
  87. framework.NewRequestExpect(f).PortName(framework.HTTPSimpleServerPort).RequestModify(func(r *request.Request) {
  88. r.HTTP().Proxy("http://127.0.0.1:" + strconv.Itoa(remotePort))
  89. }).Ensure(framework.ExpectResponseCode(407))
  90. // http proxy, correct auth
  91. framework.NewRequestExpect(f).PortName(framework.HTTPSimpleServerPort).RequestModify(func(r *request.Request) {
  92. r.HTTP().Proxy("http://abc:123@127.0.0.1:" + strconv.Itoa(remotePort))
  93. }).Ensure()
  94. // connect TCP server by CONNECT method
  95. framework.NewRequestExpect(f).PortName(framework.TCPEchoServerPort).RequestModify(func(r *request.Request) {
  96. r.TCP().Proxy("http://abc:123@127.0.0.1:" + strconv.Itoa(remotePort))
  97. })
  98. })
  99. ginkgo.It("socks5 proxy", func() {
  100. serverConf := consts.DefaultServerConfig
  101. clientConf := consts.DefaultClientConfig
  102. remotePort := f.AllocPort()
  103. clientConf += fmt.Sprintf(`
  104. [[proxies]]
  105. name = "tcp"
  106. type = "tcp"
  107. remotePort = %d
  108. [proxies.plugin]
  109. type = "socks5"
  110. username = "abc"
  111. password = "123"
  112. `, remotePort)
  113. f.RunProcesses([]string{serverConf}, []string{clientConf})
  114. // http proxy, no auth info
  115. framework.NewRequestExpect(f).PortName(framework.TCPEchoServerPort).RequestModify(func(r *request.Request) {
  116. r.TCP().Proxy("socks5://127.0.0.1:" + strconv.Itoa(remotePort))
  117. }).ExpectError(true).Ensure()
  118. // http proxy, correct auth
  119. framework.NewRequestExpect(f).PortName(framework.TCPEchoServerPort).RequestModify(func(r *request.Request) {
  120. r.TCP().Proxy("socks5://abc:123@127.0.0.1:" + strconv.Itoa(remotePort))
  121. }).Ensure()
  122. })
  123. ginkgo.It("static_file", func() {
  124. vhostPort := f.AllocPort()
  125. serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
  126. vhostHTTPPort = %d
  127. `, vhostPort)
  128. clientConf := consts.DefaultClientConfig
  129. remotePort := f.AllocPort()
  130. f.WriteTempFile("test_static_file", "foo")
  131. clientConf += fmt.Sprintf(`
  132. [[proxies]]
  133. name = "tcp"
  134. type = "tcp"
  135. remotePort = %d
  136. [proxies.plugin]
  137. type = "static_file"
  138. localPath = "%s"
  139. [[proxies]]
  140. name = "http"
  141. type = "http"
  142. customDomains = ["example.com"]
  143. [proxies.plugin]
  144. type = "static_file"
  145. localPath = "%s"
  146. [[proxies]]
  147. name = "http-with-auth"
  148. type = "http"
  149. customDomains = ["other.example.com"]
  150. [proxies.plugin]
  151. type = "static_file"
  152. localPath = "%s"
  153. httpUser = "abc"
  154. httpPassword = "123"
  155. `, remotePort, f.TempDirectory, f.TempDirectory, f.TempDirectory)
  156. f.RunProcesses([]string{serverConf}, []string{clientConf})
  157. // from tcp proxy
  158. framework.NewRequestExpect(f).Request(
  159. framework.NewHTTPRequest().HTTPPath("/test_static_file").Port(remotePort),
  160. ).ExpectResp([]byte("foo")).Ensure()
  161. // from http proxy without auth
  162. framework.NewRequestExpect(f).Request(
  163. framework.NewHTTPRequest().HTTPHost("example.com").HTTPPath("/test_static_file").Port(vhostPort),
  164. ).ExpectResp([]byte("foo")).Ensure()
  165. // from http proxy with auth
  166. framework.NewRequestExpect(f).Request(
  167. framework.NewHTTPRequest().HTTPHost("other.example.com").HTTPPath("/test_static_file").Port(vhostPort).HTTPAuth("abc", "123"),
  168. ).ExpectResp([]byte("foo")).Ensure()
  169. })
  170. ginkgo.It("http2https", func() {
  171. serverConf := consts.DefaultServerConfig
  172. vhostHTTPPort := f.AllocPort()
  173. serverConf += fmt.Sprintf(`
  174. vhostHTTPPort = %d
  175. `, vhostHTTPPort)
  176. localPort := f.AllocPort()
  177. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  178. [[proxies]]
  179. name = "http2https"
  180. type = "http"
  181. customDomains = ["example.com"]
  182. [proxies.plugin]
  183. type = "http2https"
  184. localAddr = "127.0.0.1:%d"
  185. `, localPort)
  186. f.RunProcesses([]string{serverConf}, []string{clientConf})
  187. tlsConfig, err := transport.NewServerTLSConfig("", "", "")
  188. framework.ExpectNoError(err)
  189. localServer := httpserver.New(
  190. httpserver.WithBindPort(localPort),
  191. httpserver.WithTLSConfig(tlsConfig),
  192. httpserver.WithResponse([]byte("test")),
  193. )
  194. f.RunServer("", localServer)
  195. framework.NewRequestExpect(f).
  196. Port(vhostHTTPPort).
  197. RequestModify(func(r *request.Request) {
  198. r.HTTP().HTTPHost("example.com")
  199. }).
  200. ExpectResp([]byte("test")).
  201. Ensure()
  202. })
  203. ginkgo.It("https2http", func() {
  204. generator := &cert.SelfSignedCertGenerator{}
  205. artifacts, err := generator.Generate("example.com")
  206. framework.ExpectNoError(err)
  207. crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
  208. keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
  209. serverConf := consts.DefaultServerConfig
  210. vhostHTTPSPort := f.AllocPort()
  211. serverConf += fmt.Sprintf(`
  212. vhostHTTPSPort = %d
  213. `, vhostHTTPSPort)
  214. localPort := f.AllocPort()
  215. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  216. [[proxies]]
  217. name = "https2http"
  218. type = "https"
  219. customDomains = ["example.com"]
  220. [proxies.plugin]
  221. type = "https2http"
  222. localAddr = "127.0.0.1:%d"
  223. crtPath = "%s"
  224. keyPath = "%s"
  225. `, localPort, crtPath, keyPath)
  226. f.RunProcesses([]string{serverConf}, []string{clientConf})
  227. localServer := httpserver.New(
  228. httpserver.WithBindPort(localPort),
  229. httpserver.WithResponse([]byte("test")),
  230. )
  231. f.RunServer("", localServer)
  232. framework.NewRequestExpect(f).
  233. Port(vhostHTTPSPort).
  234. RequestModify(func(r *request.Request) {
  235. r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
  236. ServerName: "example.com",
  237. InsecureSkipVerify: true,
  238. })
  239. }).
  240. ExpectResp([]byte("test")).
  241. Ensure()
  242. })
  243. ginkgo.It("https2https", func() {
  244. generator := &cert.SelfSignedCertGenerator{}
  245. artifacts, err := generator.Generate("example.com")
  246. framework.ExpectNoError(err)
  247. crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
  248. keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
  249. serverConf := consts.DefaultServerConfig
  250. vhostHTTPSPort := f.AllocPort()
  251. serverConf += fmt.Sprintf(`
  252. vhostHTTPSPort = %d
  253. `, vhostHTTPSPort)
  254. localPort := f.AllocPort()
  255. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  256. [[proxies]]
  257. name = "https2https"
  258. type = "https"
  259. customDomains = ["example.com"]
  260. [proxies.plugin]
  261. type = "https2https"
  262. localAddr = "127.0.0.1:%d"
  263. crtPath = "%s"
  264. keyPath = "%s"
  265. `, localPort, crtPath, keyPath)
  266. f.RunProcesses([]string{serverConf}, []string{clientConf})
  267. tlsConfig, err := transport.NewServerTLSConfig("", "", "")
  268. framework.ExpectNoError(err)
  269. localServer := httpserver.New(
  270. httpserver.WithBindPort(localPort),
  271. httpserver.WithResponse([]byte("test")),
  272. httpserver.WithTLSConfig(tlsConfig),
  273. )
  274. f.RunServer("", localServer)
  275. framework.NewRequestExpect(f).
  276. Port(vhostHTTPSPort).
  277. RequestModify(func(r *request.Request) {
  278. r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
  279. ServerName: "example.com",
  280. InsecureSkipVerify: true,
  281. })
  282. }).
  283. ExpectResp([]byte("test")).
  284. Ensure()
  285. })
  286. })