client_server.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. package basic
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. "github.com/onsi/ginkgo/v2"
  7. "github.com/fatedier/frp/test/e2e/framework"
  8. "github.com/fatedier/frp/test/e2e/framework/consts"
  9. "github.com/fatedier/frp/test/e2e/pkg/cert"
  10. "github.com/fatedier/frp/test/e2e/pkg/port"
  11. )
  12. type generalTestConfigures struct {
  13. server string
  14. client string
  15. clientPrefix string
  16. client2 string
  17. client2Prefix string
  18. testDelay time.Duration
  19. expectError bool
  20. }
  21. func renderBindPortConfig(protocol string) string {
  22. switch protocol {
  23. case "kcp":
  24. return fmt.Sprintf(`kcp_bind_port = {{ .%s }}`, consts.PortServerName)
  25. case "quic":
  26. return fmt.Sprintf(`quic_bind_port = {{ .%s }}`, consts.PortServerName)
  27. default:
  28. return ""
  29. }
  30. }
  31. func runClientServerTest(f *framework.Framework, configures *generalTestConfigures) {
  32. serverConf := consts.LegacyDefaultServerConfig
  33. clientConf := consts.LegacyDefaultClientConfig
  34. if configures.clientPrefix != "" {
  35. clientConf = configures.clientPrefix
  36. }
  37. serverConf += fmt.Sprintf(`
  38. %s
  39. `, configures.server)
  40. tcpPortName := port.GenName("TCP")
  41. udpPortName := port.GenName("UDP")
  42. clientConf += fmt.Sprintf(`
  43. %s
  44. [tcp]
  45. type = tcp
  46. local_port = {{ .%s }}
  47. remote_port = {{ .%s }}
  48. [udp]
  49. type = udp
  50. local_port = {{ .%s }}
  51. remote_port = {{ .%s }}
  52. `, configures.client,
  53. framework.TCPEchoServerPort, tcpPortName,
  54. framework.UDPEchoServerPort, udpPortName,
  55. )
  56. clientConfs := []string{clientConf}
  57. if configures.client2 != "" {
  58. client2Conf := consts.LegacyDefaultClientConfig
  59. if configures.client2Prefix != "" {
  60. client2Conf = configures.client2Prefix
  61. }
  62. client2Conf += fmt.Sprintf(`
  63. %s
  64. `, configures.client2)
  65. clientConfs = append(clientConfs, client2Conf)
  66. }
  67. f.RunProcesses([]string{serverConf}, clientConfs)
  68. if configures.testDelay > 0 {
  69. time.Sleep(configures.testDelay)
  70. }
  71. framework.NewRequestExpect(f).PortName(tcpPortName).ExpectError(configures.expectError).Explain("tcp proxy").Ensure()
  72. framework.NewRequestExpect(f).Protocol("udp").
  73. PortName(udpPortName).ExpectError(configures.expectError).Explain("udp proxy").Ensure()
  74. }
  75. // defineClientServerTest test a normal tcp and udp proxy with specified TestConfigures.
  76. func defineClientServerTest(desc string, f *framework.Framework, configures *generalTestConfigures) {
  77. ginkgo.It(desc, func() {
  78. runClientServerTest(f, configures)
  79. })
  80. }
  81. var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
  82. f := framework.NewDefaultFramework()
  83. ginkgo.Describe("Protocol", func() {
  84. supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
  85. for _, protocol := range supportProtocols {
  86. configures := &generalTestConfigures{
  87. server: fmt.Sprintf(`
  88. %s
  89. `, renderBindPortConfig(protocol)),
  90. client: "protocol = " + protocol,
  91. }
  92. defineClientServerTest(protocol, f, configures)
  93. }
  94. })
  95. // wss is special, it needs to be tested separately.
  96. // frps only supports ws, so there should be a proxy to terminate TLS before frps.
  97. ginkgo.Describe("Protocol wss", func() {
  98. wssPort := f.AllocPort()
  99. configures := &generalTestConfigures{
  100. clientPrefix: fmt.Sprintf(`
  101. [common]
  102. server_addr = 127.0.0.1
  103. server_port = %d
  104. protocol = wss
  105. log_level = trace
  106. login_fail_exit = false
  107. `, wssPort),
  108. // Due to the fact that frps cannot directly accept wss connections, we use the https2http plugin of another frpc to terminate TLS.
  109. client2: fmt.Sprintf(`
  110. [wss2ws]
  111. type = tcp
  112. remote_port = %d
  113. plugin = https2http
  114. plugin_local_addr = 127.0.0.1:{{ .%s }}
  115. `, wssPort, consts.PortServerName),
  116. testDelay: 10 * time.Second,
  117. }
  118. defineClientServerTest("wss", f, configures)
  119. })
  120. ginkgo.Describe("Authentication", func() {
  121. defineClientServerTest("Token Correct", f, &generalTestConfigures{
  122. server: "token = 123456",
  123. client: "token = 123456",
  124. })
  125. defineClientServerTest("Token Incorrect", f, &generalTestConfigures{
  126. server: "token = 123456",
  127. client: "token = invalid",
  128. expectError: true,
  129. })
  130. })
  131. ginkgo.Describe("TLS", func() {
  132. supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
  133. for _, protocol := range supportProtocols {
  134. tmp := protocol
  135. // Since v0.50.0, the default value of tls_enable has been changed to true.
  136. // Therefore, here it needs to be set as false to test the scenario of turning it off.
  137. defineClientServerTest("Disable TLS over "+strings.ToUpper(tmp), f, &generalTestConfigures{
  138. server: fmt.Sprintf(`
  139. %s
  140. `, renderBindPortConfig(protocol)),
  141. client: fmt.Sprintf(`tls_enable = false
  142. protocol = %s
  143. `, protocol),
  144. })
  145. }
  146. defineClientServerTest("enable tls_only, client with TLS", f, &generalTestConfigures{
  147. server: "tls_only = true",
  148. })
  149. defineClientServerTest("enable tls_only, client without TLS", f, &generalTestConfigures{
  150. server: "tls_only = true",
  151. client: "tls_enable = false",
  152. expectError: true,
  153. })
  154. })
  155. ginkgo.Describe("TLS with custom certificate", func() {
  156. supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
  157. var (
  158. caCrtPath string
  159. serverCrtPath, serverKeyPath string
  160. clientCrtPath, clientKeyPath string
  161. )
  162. ginkgo.JustBeforeEach(func() {
  163. generator := &cert.SelfSignedCertGenerator{}
  164. artifacts, err := generator.Generate("127.0.0.1")
  165. framework.ExpectNoError(err)
  166. caCrtPath = f.WriteTempFile("ca.crt", string(artifacts.CACert))
  167. serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert))
  168. serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key))
  169. generator.SetCA(artifacts.CACert, artifacts.CAKey)
  170. _, err = generator.Generate("127.0.0.1")
  171. framework.ExpectNoError(err)
  172. clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert))
  173. clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key))
  174. })
  175. for _, protocol := range supportProtocols {
  176. tmp := protocol
  177. ginkgo.It("one-way authentication: "+tmp, func() {
  178. runClientServerTest(f, &generalTestConfigures{
  179. server: fmt.Sprintf(`
  180. %s
  181. tls_trusted_ca_file = %s
  182. `, renderBindPortConfig(tmp), caCrtPath),
  183. client: fmt.Sprintf(`
  184. protocol = %s
  185. tls_cert_file = %s
  186. tls_key_file = %s
  187. `, tmp, clientCrtPath, clientKeyPath),
  188. })
  189. })
  190. ginkgo.It("mutual authentication: "+tmp, func() {
  191. runClientServerTest(f, &generalTestConfigures{
  192. server: fmt.Sprintf(`
  193. %s
  194. tls_cert_file = %s
  195. tls_key_file = %s
  196. tls_trusted_ca_file = %s
  197. `, renderBindPortConfig(tmp), serverCrtPath, serverKeyPath, caCrtPath),
  198. client: fmt.Sprintf(`
  199. protocol = %s
  200. tls_cert_file = %s
  201. tls_key_file = %s
  202. tls_trusted_ca_file = %s
  203. `, tmp, clientCrtPath, clientKeyPath, caCrtPath),
  204. })
  205. })
  206. }
  207. })
  208. ginkgo.Describe("TLS with custom certificate and specified server name", func() {
  209. var (
  210. caCrtPath string
  211. serverCrtPath, serverKeyPath string
  212. clientCrtPath, clientKeyPath string
  213. )
  214. ginkgo.JustBeforeEach(func() {
  215. generator := &cert.SelfSignedCertGenerator{}
  216. artifacts, err := generator.Generate("example.com")
  217. framework.ExpectNoError(err)
  218. caCrtPath = f.WriteTempFile("ca.crt", string(artifacts.CACert))
  219. serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert))
  220. serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key))
  221. generator.SetCA(artifacts.CACert, artifacts.CAKey)
  222. _, err = generator.Generate("example.com")
  223. framework.ExpectNoError(err)
  224. clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert))
  225. clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key))
  226. })
  227. ginkgo.It("mutual authentication", func() {
  228. runClientServerTest(f, &generalTestConfigures{
  229. server: fmt.Sprintf(`
  230. tls_cert_file = %s
  231. tls_key_file = %s
  232. tls_trusted_ca_file = %s
  233. `, serverCrtPath, serverKeyPath, caCrtPath),
  234. client: fmt.Sprintf(`
  235. tls_server_name = example.com
  236. tls_cert_file = %s
  237. tls_key_file = %s
  238. tls_trusted_ca_file = %s
  239. `, clientCrtPath, clientKeyPath, caCrtPath),
  240. })
  241. })
  242. ginkgo.It("mutual authentication with incorrect server name", func() {
  243. runClientServerTest(f, &generalTestConfigures{
  244. server: fmt.Sprintf(`
  245. tls_cert_file = %s
  246. tls_key_file = %s
  247. tls_trusted_ca_file = %s
  248. `, serverCrtPath, serverKeyPath, caCrtPath),
  249. client: fmt.Sprintf(`
  250. tls_server_name = invalid.com
  251. tls_cert_file = %s
  252. tls_key_file = %s
  253. tls_trusted_ca_file = %s
  254. `, clientCrtPath, clientKeyPath, caCrtPath),
  255. expectError: true,
  256. })
  257. })
  258. })
  259. ginkgo.Describe("TLS with disable_custom_tls_first_byte set to false", func() {
  260. supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
  261. for _, protocol := range supportProtocols {
  262. tmp := protocol
  263. defineClientServerTest("TLS over "+strings.ToUpper(tmp), f, &generalTestConfigures{
  264. server: fmt.Sprintf(`
  265. %s
  266. `, renderBindPortConfig(protocol)),
  267. client: fmt.Sprintf(`
  268. protocol = %s
  269. disable_custom_tls_first_byte = false
  270. `, protocol),
  271. })
  272. }
  273. })
  274. ginkgo.Describe("IPv6 bind address", func() {
  275. supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
  276. for _, protocol := range supportProtocols {
  277. tmp := protocol
  278. defineClientServerTest("IPv6 bind address: "+strings.ToUpper(tmp), f, &generalTestConfigures{
  279. server: fmt.Sprintf(`
  280. bind_addr = ::
  281. %s
  282. `, renderBindPortConfig(protocol)),
  283. client: fmt.Sprintf(`
  284. protocol = %s
  285. `, protocol),
  286. })
  287. }
  288. })
  289. })