client.go 9.2 KB

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