basic.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. package basic
  2. import (
  3. "crypto/tls"
  4. "fmt"
  5. "strings"
  6. "github.com/fatedier/frp/pkg/transport"
  7. "github.com/fatedier/frp/test/e2e/framework"
  8. "github.com/fatedier/frp/test/e2e/framework/consts"
  9. "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
  10. "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
  11. "github.com/fatedier/frp/test/e2e/pkg/port"
  12. "github.com/fatedier/frp/test/e2e/pkg/request"
  13. . "github.com/onsi/ginkgo"
  14. )
  15. var _ = Describe("[Feature: Basic]", func() {
  16. f := framework.NewDefaultFramework()
  17. Describe("TCP && UDP", func() {
  18. types := []string{"tcp", "udp"}
  19. for _, t := range types {
  20. proxyType := t
  21. It(fmt.Sprintf("Expose a %s echo server", strings.ToUpper(proxyType)), func() {
  22. serverConf := consts.DefaultServerConfig
  23. clientConf := consts.DefaultClientConfig
  24. localPortName := ""
  25. protocol := "tcp"
  26. switch proxyType {
  27. case "tcp":
  28. localPortName = framework.TCPEchoServerPort
  29. protocol = "tcp"
  30. case "udp":
  31. localPortName = framework.UDPEchoServerPort
  32. protocol = "udp"
  33. }
  34. getProxyConf := func(proxyName string, portName string, extra string) string {
  35. return fmt.Sprintf(`
  36. [%s]
  37. type = %s
  38. local_port = {{ .%s }}
  39. remote_port = {{ .%s }}
  40. `+extra, proxyName, proxyType, localPortName, portName)
  41. }
  42. tests := []struct {
  43. proxyName string
  44. portName string
  45. extraConfig string
  46. }{
  47. {
  48. proxyName: "normal",
  49. portName: port.GenName("Normal"),
  50. },
  51. {
  52. proxyName: "with-encryption",
  53. portName: port.GenName("WithEncryption"),
  54. extraConfig: "use_encryption = true",
  55. },
  56. {
  57. proxyName: "with-compression",
  58. portName: port.GenName("WithCompression"),
  59. extraConfig: "use_compression = true",
  60. },
  61. {
  62. proxyName: "with-encryption-and-compression",
  63. portName: port.GenName("WithEncryptionAndCompression"),
  64. extraConfig: `
  65. use_encryption = true
  66. use_compression = true
  67. `,
  68. },
  69. }
  70. // build all client config
  71. for _, test := range tests {
  72. clientConf += getProxyConf(test.proxyName, test.portName, test.extraConfig) + "\n"
  73. }
  74. // run frps and frpc
  75. f.RunProcesses([]string{serverConf}, []string{clientConf})
  76. for _, test := range tests {
  77. framework.NewRequestExpect(f).
  78. Protocol(protocol).
  79. PortName(test.portName).
  80. Explain(test.proxyName).
  81. Ensure()
  82. }
  83. })
  84. }
  85. })
  86. Describe("HTTP", func() {
  87. It("proxy to HTTP server", func() {
  88. serverConf := consts.DefaultServerConfig
  89. vhostHTTPPort := f.AllocPort()
  90. serverConf += fmt.Sprintf(`
  91. vhost_http_port = %d
  92. `, vhostHTTPPort)
  93. clientConf := consts.DefaultClientConfig
  94. getProxyConf := func(proxyName string, customDomains string, extra string) string {
  95. return fmt.Sprintf(`
  96. [%s]
  97. type = http
  98. local_port = {{ .%s }}
  99. custom_domains = %s
  100. `+extra, proxyName, framework.HTTPSimpleServerPort, customDomains)
  101. }
  102. tests := []struct {
  103. proxyName string
  104. customDomains string
  105. extraConfig string
  106. }{
  107. {
  108. proxyName: "normal",
  109. },
  110. {
  111. proxyName: "with-encryption",
  112. extraConfig: "use_encryption = true",
  113. },
  114. {
  115. proxyName: "with-compression",
  116. extraConfig: "use_compression = true",
  117. },
  118. {
  119. proxyName: "with-encryption-and-compression",
  120. extraConfig: `
  121. use_encryption = true
  122. use_compression = true
  123. `,
  124. },
  125. {
  126. proxyName: "multiple-custom-domains",
  127. customDomains: "a.example.com, b.example.com",
  128. },
  129. }
  130. // build all client config
  131. for i, test := range tests {
  132. if tests[i].customDomains == "" {
  133. tests[i].customDomains = test.proxyName + ".example.com"
  134. }
  135. clientConf += getProxyConf(test.proxyName, tests[i].customDomains, test.extraConfig) + "\n"
  136. }
  137. // run frps and frpc
  138. f.RunProcesses([]string{serverConf}, []string{clientConf})
  139. for _, test := range tests {
  140. for _, domain := range strings.Split(test.customDomains, ",") {
  141. domain = strings.TrimSpace(domain)
  142. framework.NewRequestExpect(f).
  143. Explain(test.proxyName + "-" + domain).
  144. Port(vhostHTTPPort).
  145. RequestModify(func(r *request.Request) {
  146. r.HTTP().HTTPHost(domain)
  147. }).
  148. Ensure()
  149. }
  150. }
  151. // not exist host
  152. framework.NewRequestExpect(f).
  153. Explain("not exist host").
  154. Port(vhostHTTPPort).
  155. RequestModify(func(r *request.Request) {
  156. r.HTTP().HTTPHost("not-exist.example.com")
  157. }).
  158. Ensure(framework.ExpectResponseCode(404))
  159. })
  160. })
  161. Describe("HTTPS", func() {
  162. It("proxy to HTTPS server", func() {
  163. serverConf := consts.DefaultServerConfig
  164. vhostHTTPSPort := f.AllocPort()
  165. serverConf += fmt.Sprintf(`
  166. vhost_https_port = %d
  167. `, vhostHTTPSPort)
  168. localPort := f.AllocPort()
  169. clientConf := consts.DefaultClientConfig
  170. getProxyConf := func(proxyName string, customDomains string, extra string) string {
  171. return fmt.Sprintf(`
  172. [%s]
  173. type = https
  174. local_port = %d
  175. custom_domains = %s
  176. `+extra, proxyName, localPort, customDomains)
  177. }
  178. tests := []struct {
  179. proxyName string
  180. customDomains string
  181. extraConfig string
  182. }{
  183. {
  184. proxyName: "normal",
  185. },
  186. {
  187. proxyName: "with-encryption",
  188. extraConfig: "use_encryption = true",
  189. },
  190. {
  191. proxyName: "with-compression",
  192. extraConfig: "use_compression = true",
  193. },
  194. {
  195. proxyName: "with-encryption-and-compression",
  196. extraConfig: `
  197. use_encryption = true
  198. use_compression = true
  199. `,
  200. },
  201. {
  202. proxyName: "multiple-custom-domains",
  203. customDomains: "a.example.com, b.example.com",
  204. },
  205. }
  206. // build all client config
  207. for i, test := range tests {
  208. if tests[i].customDomains == "" {
  209. tests[i].customDomains = test.proxyName + ".example.com"
  210. }
  211. clientConf += getProxyConf(test.proxyName, tests[i].customDomains, test.extraConfig) + "\n"
  212. }
  213. // run frps and frpc
  214. f.RunProcesses([]string{serverConf}, []string{clientConf})
  215. tlsConfig, err := transport.NewServerTLSConfig("", "", "")
  216. framework.ExpectNoError(err)
  217. localServer := httpserver.New(
  218. httpserver.WithBindPort(localPort),
  219. httpserver.WithTlsConfig(tlsConfig),
  220. httpserver.WithResponse([]byte("test")),
  221. )
  222. f.RunServer("", localServer)
  223. for _, test := range tests {
  224. for _, domain := range strings.Split(test.customDomains, ",") {
  225. domain = strings.TrimSpace(domain)
  226. framework.NewRequestExpect(f).
  227. Explain(test.proxyName + "-" + domain).
  228. Port(vhostHTTPSPort).
  229. RequestModify(func(r *request.Request) {
  230. r.HTTPS().HTTPHost(domain).TLSConfig(&tls.Config{
  231. ServerName: domain,
  232. InsecureSkipVerify: true,
  233. })
  234. }).
  235. ExpectResp([]byte("test")).
  236. Ensure()
  237. }
  238. }
  239. // not exist host
  240. notExistDomain := "not-exist.example.com"
  241. framework.NewRequestExpect(f).
  242. Explain("not exist host").
  243. Port(vhostHTTPSPort).
  244. RequestModify(func(r *request.Request) {
  245. r.HTTPS().HTTPHost(notExistDomain).TLSConfig(&tls.Config{
  246. ServerName: notExistDomain,
  247. InsecureSkipVerify: true,
  248. })
  249. }).
  250. ExpectError(true).
  251. Ensure()
  252. })
  253. })
  254. Describe("STCP && SUDP", func() {
  255. types := []string{"stcp", "sudp"}
  256. for _, t := range types {
  257. proxyType := t
  258. It(fmt.Sprintf("Expose echo server with %s", strings.ToUpper(proxyType)), func() {
  259. serverConf := consts.DefaultServerConfig
  260. clientServerConf := consts.DefaultClientConfig
  261. clientVisitorConf := consts.DefaultClientConfig
  262. localPortName := ""
  263. protocol := "tcp"
  264. switch proxyType {
  265. case "stcp":
  266. localPortName = framework.TCPEchoServerPort
  267. protocol = "tcp"
  268. case "sudp":
  269. localPortName = framework.UDPEchoServerPort
  270. protocol = "udp"
  271. }
  272. correctSK := "abc"
  273. wrongSK := "123"
  274. getProxyServerConf := func(proxyName string, extra string) string {
  275. return fmt.Sprintf(`
  276. [%s]
  277. type = %s
  278. role = server
  279. sk = %s
  280. local_port = {{ .%s }}
  281. `+extra, proxyName, proxyType, correctSK, localPortName)
  282. }
  283. getProxyVisitorConf := func(proxyName string, portName, visitorSK, extra string) string {
  284. return fmt.Sprintf(`
  285. [%s]
  286. type = %s
  287. role = visitor
  288. server_name = %s
  289. sk = %s
  290. bind_port = {{ .%s }}
  291. `+extra, proxyName, proxyType, proxyName, visitorSK, portName)
  292. }
  293. tests := []struct {
  294. proxyName string
  295. bindPortName string
  296. visitorSK string
  297. extraConfig string
  298. expectError bool
  299. }{
  300. {
  301. proxyName: "normal",
  302. bindPortName: port.GenName("Normal"),
  303. visitorSK: correctSK,
  304. },
  305. {
  306. proxyName: "with-encryption",
  307. bindPortName: port.GenName("WithEncryption"),
  308. visitorSK: correctSK,
  309. extraConfig: "use_encryption = true",
  310. },
  311. {
  312. proxyName: "with-compression",
  313. bindPortName: port.GenName("WithCompression"),
  314. visitorSK: correctSK,
  315. extraConfig: "use_compression = true",
  316. },
  317. {
  318. proxyName: "with-encryption-and-compression",
  319. bindPortName: port.GenName("WithEncryptionAndCompression"),
  320. visitorSK: correctSK,
  321. extraConfig: `
  322. use_encryption = true
  323. use_compression = true
  324. `,
  325. },
  326. {
  327. proxyName: "with-error-sk",
  328. bindPortName: port.GenName("WithErrorSK"),
  329. visitorSK: wrongSK,
  330. expectError: true,
  331. },
  332. }
  333. // build all client config
  334. for _, test := range tests {
  335. clientServerConf += getProxyServerConf(test.proxyName, test.extraConfig) + "\n"
  336. }
  337. for _, test := range tests {
  338. clientVisitorConf += getProxyVisitorConf(test.proxyName, test.bindPortName, test.visitorSK, test.extraConfig) + "\n"
  339. }
  340. // run frps and frpc
  341. f.RunProcesses([]string{serverConf}, []string{clientServerConf, clientVisitorConf})
  342. for _, test := range tests {
  343. framework.NewRequestExpect(f).
  344. Protocol(protocol).
  345. PortName(test.bindPortName).
  346. Explain(test.proxyName).
  347. ExpectError(test.expectError).
  348. Ensure()
  349. }
  350. })
  351. }
  352. })
  353. Describe("TCPMUX", func() {
  354. It("Type tcpmux", func() {
  355. serverConf := consts.DefaultServerConfig
  356. clientConf := consts.DefaultClientConfig
  357. tcpmuxHTTPConnectPortName := port.GenName("TCPMUX")
  358. serverConf += fmt.Sprintf(`
  359. tcpmux_httpconnect_port = {{ .%s }}
  360. `, tcpmuxHTTPConnectPortName)
  361. getProxyConf := func(proxyName string, extra string) string {
  362. return fmt.Sprintf(`
  363. [%s]
  364. type = tcpmux
  365. multiplexer = httpconnect
  366. local_port = {{ .%s }}
  367. custom_domains = %s
  368. `+extra, proxyName, port.GenName(proxyName), proxyName)
  369. }
  370. tests := []struct {
  371. proxyName string
  372. extraConfig string
  373. }{
  374. {
  375. proxyName: "normal",
  376. },
  377. {
  378. proxyName: "with-encryption",
  379. extraConfig: "use_encryption = true",
  380. },
  381. {
  382. proxyName: "with-compression",
  383. extraConfig: "use_compression = true",
  384. },
  385. {
  386. proxyName: "with-encryption-and-compression",
  387. extraConfig: `
  388. use_encryption = true
  389. use_compression = true
  390. `,
  391. },
  392. }
  393. // build all client config
  394. for _, test := range tests {
  395. clientConf += getProxyConf(test.proxyName, test.extraConfig) + "\n"
  396. localServer := streamserver.New(streamserver.TCP, streamserver.WithBindPort(f.AllocPort()), streamserver.WithRespContent([]byte(test.proxyName)))
  397. f.RunServer(port.GenName(test.proxyName), localServer)
  398. }
  399. // run frps and frpc
  400. f.RunProcesses([]string{serverConf}, []string{clientConf})
  401. // Request without HTTP connect should get error
  402. framework.NewRequestExpect(f).
  403. PortName(tcpmuxHTTPConnectPortName).
  404. ExpectError(true).
  405. Explain("request without HTTP connect expect error").
  406. Ensure()
  407. proxyURL := fmt.Sprintf("http://127.0.0.1:%d", f.PortByName(tcpmuxHTTPConnectPortName))
  408. // Request with incorrect connect hostname
  409. framework.NewRequestExpect(f).RequestModify(func(r *request.Request) {
  410. r.Addr("invalid").Proxy(proxyURL)
  411. }).ExpectError(true).Explain("request without HTTP connect expect error").Ensure()
  412. // Request with correct connect hostname
  413. for _, test := range tests {
  414. framework.NewRequestExpect(f).RequestModify(func(r *request.Request) {
  415. r.Addr(test.proxyName).Proxy(proxyURL)
  416. }).ExpectResp([]byte(test.proxyName)).Explain(test.proxyName).Ensure()
  417. }
  418. })
  419. })
  420. })