1
0

client_server.go 9.4 KB

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