client.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. package plugin
  2. import (
  3. "crypto/tls"
  4. "fmt"
  5. "net/http"
  6. "strconv"
  7. "github.com/onsi/ginkgo/v2"
  8. "github.com/fatedier/frp/pkg/transport"
  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/httpserver"
  12. "github.com/fatedier/frp/test/e2e/pkg/cert"
  13. "github.com/fatedier/frp/test/e2e/pkg/port"
  14. "github.com/fatedier/frp/test/e2e/pkg/request"
  15. )
  16. var _ = ginkgo.Describe("[Feature: Client-Plugins]", func() {
  17. f := framework.NewDefaultFramework()
  18. ginkgo.Describe("UnixDomainSocket", func() {
  19. ginkgo.It("Expose a unix domain socket echo server", func() {
  20. serverConf := consts.DefaultServerConfig
  21. clientConf := consts.DefaultClientConfig
  22. getProxyConf := func(proxyName string, portName string, extra string) string {
  23. return fmt.Sprintf(`
  24. [[proxies]]
  25. name = "%s"
  26. type = "tcp"
  27. remotePort = {{ .%s }}
  28. `+extra, proxyName, portName) + fmt.Sprintf(`
  29. [proxies.plugin]
  30. type = "unix_domain_socket"
  31. unixPath = "{{ .%s }}"
  32. `, framework.UDSEchoServerAddr)
  33. }
  34. tests := []struct {
  35. proxyName string
  36. portName string
  37. extraConfig string
  38. }{
  39. {
  40. proxyName: "normal",
  41. portName: port.GenName("Normal"),
  42. },
  43. {
  44. proxyName: "with-encryption",
  45. portName: port.GenName("WithEncryption"),
  46. extraConfig: "transport.useEncryption = true",
  47. },
  48. {
  49. proxyName: "with-compression",
  50. portName: port.GenName("WithCompression"),
  51. extraConfig: "transport.useCompression = true",
  52. },
  53. {
  54. proxyName: "with-encryption-and-compression",
  55. portName: port.GenName("WithEncryptionAndCompression"),
  56. extraConfig: `
  57. transport.useEncryption = true
  58. transport.useCompression = true
  59. `,
  60. },
  61. }
  62. // build all client config
  63. for _, test := range tests {
  64. clientConf += getProxyConf(test.proxyName, test.portName, test.extraConfig) + "\n"
  65. }
  66. // run frps and frpc
  67. f.RunProcesses([]string{serverConf}, []string{clientConf})
  68. for _, test := range tests {
  69. framework.NewRequestExpect(f).Port(f.PortByName(test.portName)).Ensure()
  70. }
  71. })
  72. })
  73. ginkgo.It("http_proxy", func() {
  74. serverConf := consts.DefaultServerConfig
  75. clientConf := consts.DefaultClientConfig
  76. remotePort := f.AllocPort()
  77. clientConf += fmt.Sprintf(`
  78. [[proxies]]
  79. name = "tcp"
  80. type = "tcp"
  81. remotePort = %d
  82. [proxies.plugin]
  83. type = "http_proxy"
  84. httpUser = "abc"
  85. httpPassword = "123"
  86. `, remotePort)
  87. f.RunProcesses([]string{serverConf}, []string{clientConf})
  88. // http proxy, no auth info
  89. framework.NewRequestExpect(f).PortName(framework.HTTPSimpleServerPort).RequestModify(func(r *request.Request) {
  90. r.HTTP().Proxy("http://127.0.0.1:" + strconv.Itoa(remotePort))
  91. }).Ensure(framework.ExpectResponseCode(407))
  92. // http proxy, correct auth
  93. framework.NewRequestExpect(f).PortName(framework.HTTPSimpleServerPort).RequestModify(func(r *request.Request) {
  94. r.HTTP().Proxy("http://abc:123@127.0.0.1:" + strconv.Itoa(remotePort))
  95. }).Ensure()
  96. // connect TCP server by CONNECT method
  97. framework.NewRequestExpect(f).PortName(framework.TCPEchoServerPort).RequestModify(func(r *request.Request) {
  98. r.TCP().Proxy("http://abc:123@127.0.0.1:" + strconv.Itoa(remotePort))
  99. })
  100. })
  101. ginkgo.It("socks5 proxy", func() {
  102. serverConf := consts.DefaultServerConfig
  103. clientConf := consts.DefaultClientConfig
  104. remotePort := f.AllocPort()
  105. clientConf += fmt.Sprintf(`
  106. [[proxies]]
  107. name = "tcp"
  108. type = "tcp"
  109. remotePort = %d
  110. [proxies.plugin]
  111. type = "socks5"
  112. username = "abc"
  113. password = "123"
  114. `, remotePort)
  115. f.RunProcesses([]string{serverConf}, []string{clientConf})
  116. // http proxy, no auth info
  117. framework.NewRequestExpect(f).PortName(framework.TCPEchoServerPort).RequestModify(func(r *request.Request) {
  118. r.TCP().Proxy("socks5://127.0.0.1:" + strconv.Itoa(remotePort))
  119. }).ExpectError(true).Ensure()
  120. // http proxy, correct auth
  121. framework.NewRequestExpect(f).PortName(framework.TCPEchoServerPort).RequestModify(func(r *request.Request) {
  122. r.TCP().Proxy("socks5://abc:123@127.0.0.1:" + strconv.Itoa(remotePort))
  123. }).Ensure()
  124. })
  125. ginkgo.It("static_file", func() {
  126. vhostPort := f.AllocPort()
  127. serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
  128. vhostHTTPPort = %d
  129. `, vhostPort)
  130. clientConf := consts.DefaultClientConfig
  131. remotePort := f.AllocPort()
  132. f.WriteTempFile("test_static_file", "foo")
  133. clientConf += fmt.Sprintf(`
  134. [[proxies]]
  135. name = "tcp"
  136. type = "tcp"
  137. remotePort = %d
  138. [proxies.plugin]
  139. type = "static_file"
  140. localPath = "%s"
  141. [[proxies]]
  142. name = "http"
  143. type = "http"
  144. customDomains = ["example.com"]
  145. [proxies.plugin]
  146. type = "static_file"
  147. localPath = "%s"
  148. [[proxies]]
  149. name = "http-with-auth"
  150. type = "http"
  151. customDomains = ["other.example.com"]
  152. [proxies.plugin]
  153. type = "static_file"
  154. localPath = "%s"
  155. httpUser = "abc"
  156. httpPassword = "123"
  157. `, remotePort, f.TempDirectory, f.TempDirectory, f.TempDirectory)
  158. f.RunProcesses([]string{serverConf}, []string{clientConf})
  159. // from tcp proxy
  160. framework.NewRequestExpect(f).Request(
  161. framework.NewHTTPRequest().HTTPPath("/test_static_file").Port(remotePort),
  162. ).ExpectResp([]byte("foo")).Ensure()
  163. // from http proxy without auth
  164. framework.NewRequestExpect(f).Request(
  165. framework.NewHTTPRequest().HTTPHost("example.com").HTTPPath("/test_static_file").Port(vhostPort),
  166. ).ExpectResp([]byte("foo")).Ensure()
  167. // from http proxy with auth
  168. framework.NewRequestExpect(f).Request(
  169. framework.NewHTTPRequest().HTTPHost("other.example.com").HTTPPath("/test_static_file").Port(vhostPort).HTTPAuth("abc", "123"),
  170. ).ExpectResp([]byte("foo")).Ensure()
  171. })
  172. ginkgo.It("http2https", func() {
  173. serverConf := consts.DefaultServerConfig
  174. vhostHTTPPort := f.AllocPort()
  175. serverConf += fmt.Sprintf(`
  176. vhostHTTPPort = %d
  177. `, vhostHTTPPort)
  178. localPort := f.AllocPort()
  179. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  180. [[proxies]]
  181. name = "http2https"
  182. type = "http"
  183. customDomains = ["example.com"]
  184. [proxies.plugin]
  185. type = "http2https"
  186. localAddr = "127.0.0.1:%d"
  187. `, localPort)
  188. f.RunProcesses([]string{serverConf}, []string{clientConf})
  189. tlsConfig, err := transport.NewServerTLSConfig("", "", "")
  190. framework.ExpectNoError(err)
  191. localServer := httpserver.New(
  192. httpserver.WithBindPort(localPort),
  193. httpserver.WithTLSConfig(tlsConfig),
  194. httpserver.WithResponse([]byte("test")),
  195. )
  196. f.RunServer("", localServer)
  197. framework.NewRequestExpect(f).
  198. Port(vhostHTTPPort).
  199. RequestModify(func(r *request.Request) {
  200. r.HTTP().HTTPHost("example.com")
  201. }).
  202. ExpectResp([]byte("test")).
  203. Ensure()
  204. })
  205. ginkgo.It("https2http", func() {
  206. generator := &cert.SelfSignedCertGenerator{}
  207. artifacts, err := generator.Generate("example.com")
  208. framework.ExpectNoError(err)
  209. crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
  210. keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
  211. serverConf := consts.DefaultServerConfig
  212. vhostHTTPSPort := f.AllocPort()
  213. serverConf += fmt.Sprintf(`
  214. vhostHTTPSPort = %d
  215. `, vhostHTTPSPort)
  216. localPort := f.AllocPort()
  217. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  218. [[proxies]]
  219. name = "https2http"
  220. type = "https"
  221. customDomains = ["example.com"]
  222. [proxies.plugin]
  223. type = "https2http"
  224. localAddr = "127.0.0.1:%d"
  225. crtPath = "%s"
  226. keyPath = "%s"
  227. `, localPort, crtPath, keyPath)
  228. f.RunProcesses([]string{serverConf}, []string{clientConf})
  229. localServer := httpserver.New(
  230. httpserver.WithBindPort(localPort),
  231. httpserver.WithResponse([]byte("test")),
  232. )
  233. f.RunServer("", localServer)
  234. framework.NewRequestExpect(f).
  235. Port(vhostHTTPSPort).
  236. RequestModify(func(r *request.Request) {
  237. r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
  238. ServerName: "example.com",
  239. InsecureSkipVerify: true,
  240. })
  241. }).
  242. ExpectResp([]byte("test")).
  243. Ensure()
  244. })
  245. ginkgo.It("https2https", func() {
  246. generator := &cert.SelfSignedCertGenerator{}
  247. artifacts, err := generator.Generate("example.com")
  248. framework.ExpectNoError(err)
  249. crtPath := f.WriteTempFile("server.crt", string(artifacts.Cert))
  250. keyPath := f.WriteTempFile("server.key", string(artifacts.Key))
  251. serverConf := consts.DefaultServerConfig
  252. vhostHTTPSPort := f.AllocPort()
  253. serverConf += fmt.Sprintf(`
  254. vhostHTTPSPort = %d
  255. `, vhostHTTPSPort)
  256. localPort := f.AllocPort()
  257. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  258. [[proxies]]
  259. name = "https2https"
  260. type = "https"
  261. customDomains = ["example.com"]
  262. [proxies.plugin]
  263. type = "https2https"
  264. localAddr = "127.0.0.1:%d"
  265. crtPath = "%s"
  266. keyPath = "%s"
  267. `, localPort, crtPath, keyPath)
  268. f.RunProcesses([]string{serverConf}, []string{clientConf})
  269. tlsConfig, err := transport.NewServerTLSConfig("", "", "")
  270. framework.ExpectNoError(err)
  271. localServer := httpserver.New(
  272. httpserver.WithBindPort(localPort),
  273. httpserver.WithResponse([]byte("test")),
  274. httpserver.WithTLSConfig(tlsConfig),
  275. )
  276. f.RunServer("", localServer)
  277. framework.NewRequestExpect(f).
  278. Port(vhostHTTPSPort).
  279. RequestModify(func(r *request.Request) {
  280. r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
  281. ServerName: "example.com",
  282. InsecureSkipVerify: true,
  283. })
  284. }).
  285. ExpectResp([]byte("test")).
  286. Ensure()
  287. })
  288. ginkgo.Describe("http2http", func() {
  289. ginkgo.It("host header rewrite", func() {
  290. serverConf := consts.DefaultServerConfig
  291. localPort := f.AllocPort()
  292. remotePort := f.AllocPort()
  293. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  294. [[proxies]]
  295. name = "http2http"
  296. type = "tcp"
  297. remotePort = %d
  298. [proxies.plugin]
  299. type = "http2http"
  300. localAddr = "127.0.0.1:%d"
  301. hostHeaderRewrite = "rewrite.test.com"
  302. `, remotePort, localPort)
  303. f.RunProcesses([]string{serverConf}, []string{clientConf})
  304. localServer := httpserver.New(
  305. httpserver.WithBindPort(localPort),
  306. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  307. _, _ = w.Write([]byte(req.Host))
  308. })),
  309. )
  310. f.RunServer("", localServer)
  311. framework.NewRequestExpect(f).
  312. Port(remotePort).
  313. RequestModify(func(r *request.Request) {
  314. r.HTTP().HTTPHost("example.com")
  315. }).
  316. ExpectResp([]byte("rewrite.test.com")).
  317. Ensure()
  318. })
  319. ginkgo.It("set request header", func() {
  320. serverConf := consts.DefaultServerConfig
  321. localPort := f.AllocPort()
  322. remotePort := f.AllocPort()
  323. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  324. [[proxies]]
  325. name = "http2http"
  326. type = "tcp"
  327. remotePort = %d
  328. [proxies.plugin]
  329. type = "http2http"
  330. localAddr = "127.0.0.1:%d"
  331. requestHeaders.set.x-from-where = "frp"
  332. `, remotePort, localPort)
  333. f.RunProcesses([]string{serverConf}, []string{clientConf})
  334. localServer := httpserver.New(
  335. httpserver.WithBindPort(localPort),
  336. httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
  337. _, _ = w.Write([]byte(req.Header.Get("x-from-where")))
  338. })),
  339. )
  340. f.RunServer("", localServer)
  341. framework.NewRequestExpect(f).
  342. Port(remotePort).
  343. RequestModify(func(r *request.Request) {
  344. r.HTTP().HTTPHost("example.com")
  345. }).
  346. ExpectResp([]byte("frp")).
  347. Ensure()
  348. })
  349. })
  350. ginkgo.It("tls2raw", func() {
  351. generator := &cert.SelfSignedCertGenerator{}
  352. artifacts, err := generator.Generate("example.com")
  353. framework.ExpectNoError(err)
  354. crtPath := f.WriteTempFile("tls2raw_server.crt", string(artifacts.Cert))
  355. keyPath := f.WriteTempFile("tls2raw_server.key", string(artifacts.Key))
  356. serverConf := consts.DefaultServerConfig
  357. vhostHTTPSPort := f.AllocPort()
  358. serverConf += fmt.Sprintf(`
  359. vhostHTTPSPort = %d
  360. `, vhostHTTPSPort)
  361. localPort := f.AllocPort()
  362. clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
  363. [[proxies]]
  364. name = "tls2raw-test"
  365. type = "https"
  366. customDomains = ["example.com"]
  367. [proxies.plugin]
  368. type = "tls2raw"
  369. localAddr = "127.0.0.1:%d"
  370. crtPath = "%s"
  371. keyPath = "%s"
  372. `, localPort, crtPath, keyPath)
  373. f.RunProcesses([]string{serverConf}, []string{clientConf})
  374. localServer := httpserver.New(
  375. httpserver.WithBindPort(localPort),
  376. httpserver.WithResponse([]byte("test")),
  377. )
  378. f.RunServer("", localServer)
  379. framework.NewRequestExpect(f).
  380. Port(vhostHTTPSPort).
  381. RequestModify(func(r *request.Request) {
  382. r.HTTPS().HTTPHost("example.com").TLSConfig(&tls.Config{
  383. ServerName: "example.com",
  384. InsecureSkipVerify: true,
  385. })
  386. }).
  387. ExpectResp([]byte("test")).
  388. Ensure()
  389. })
  390. })