v2ray_ws_test.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package main
  2. import (
  3. "net/netip"
  4. "os"
  5. "testing"
  6. C "github.com/sagernet/sing-box/constant"
  7. "github.com/sagernet/sing-box/option"
  8. "github.com/gofrs/uuid/v5"
  9. "github.com/spyzhov/ajson"
  10. "github.com/stretchr/testify/require"
  11. )
  12. func TestV2RayWebsocket(t *testing.T) {
  13. t.Run("self", func(t *testing.T) {
  14. testV2RayTransportSelf(t, &option.V2RayTransportOptions{
  15. Type: C.V2RayTransportTypeWebsocket,
  16. })
  17. })
  18. t.Run("self-early-data", func(t *testing.T) {
  19. testV2RayTransportSelf(t, &option.V2RayTransportOptions{
  20. Type: C.V2RayTransportTypeWebsocket,
  21. WebsocketOptions: option.V2RayWebsocketOptions{
  22. MaxEarlyData: 2048,
  23. },
  24. })
  25. })
  26. t.Run("self-xray-early-data", func(t *testing.T) {
  27. testV2RayTransportSelf(t, &option.V2RayTransportOptions{
  28. Type: C.V2RayTransportTypeWebsocket,
  29. WebsocketOptions: option.V2RayWebsocketOptions{
  30. MaxEarlyData: 2048,
  31. EarlyDataHeaderName: "Sec-WebSocket-Protocol",
  32. },
  33. })
  34. })
  35. t.Run("inbound", func(t *testing.T) {
  36. testV2RayWebsocketInbound(t, 0, "")
  37. })
  38. t.Run("inbound-early-data", func(t *testing.T) {
  39. testV2RayWebsocketInbound(t, 2048, "")
  40. })
  41. t.Run("inbound-xray-early-data", func(t *testing.T) {
  42. testV2RayWebsocketInbound(t, 2048, "Sec-WebSocket-Protocol")
  43. })
  44. t.Run("outbound", func(t *testing.T) {
  45. testV2RayWebsocketOutbound(t, 0, "")
  46. })
  47. t.Run("outbound-early-data", func(t *testing.T) {
  48. testV2RayWebsocketOutbound(t, 2048, "")
  49. })
  50. t.Run("outbound-xray-early-data", func(t *testing.T) {
  51. testV2RayWebsocketOutbound(t, 2048, "Sec-WebSocket-Protocol")
  52. })
  53. }
  54. func testV2RayWebsocketInbound(t *testing.T, maxEarlyData uint32, earlyDataHeaderName string) {
  55. userId, err := uuid.DefaultGenerator.NewV4()
  56. require.NoError(t, err)
  57. _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
  58. startInstance(t, option.Options{
  59. Inbounds: []option.Inbound{
  60. {
  61. Type: C.TypeVMess,
  62. VMessOptions: option.VMessInboundOptions{
  63. ListenOptions: option.ListenOptions{
  64. Listen: option.NewListenAddress(netip.IPv4Unspecified()),
  65. ListenPort: serverPort,
  66. },
  67. Users: []option.VMessUser{
  68. {
  69. Name: "sekai",
  70. UUID: userId.String(),
  71. },
  72. },
  73. TLS: &option.InboundTLSOptions{
  74. Enabled: true,
  75. ServerName: "example.org",
  76. CertificatePath: certPem,
  77. KeyPath: keyPem,
  78. },
  79. Transport: &option.V2RayTransportOptions{
  80. Type: C.V2RayTransportTypeWebsocket,
  81. WebsocketOptions: option.V2RayWebsocketOptions{
  82. MaxEarlyData: maxEarlyData,
  83. EarlyDataHeaderName: earlyDataHeaderName,
  84. },
  85. },
  86. },
  87. },
  88. },
  89. })
  90. content, err := os.ReadFile("config/vmess-ws-client.json")
  91. require.NoError(t, err)
  92. config, err := ajson.Unmarshal(content)
  93. require.NoError(t, err)
  94. config.MustKey("inbounds").MustIndex(0).MustKey("port").SetNumeric(float64(clientPort))
  95. outbound := config.MustKey("outbounds").MustIndex(0)
  96. settings := outbound.MustKey("settings").MustKey("vnext").MustIndex(0)
  97. settings.MustKey("port").SetNumeric(float64(serverPort))
  98. user := settings.MustKey("users").MustIndex(0)
  99. user.MustKey("id").SetString(userId.String())
  100. wsSettings := outbound.MustKey("streamSettings").MustKey("wsSettings")
  101. wsSettings.MustKey("maxEarlyData").SetNumeric(float64(maxEarlyData))
  102. wsSettings.MustKey("earlyDataHeaderName").SetString(earlyDataHeaderName)
  103. content, err = ajson.Marshal(config)
  104. require.NoError(t, err)
  105. startDockerContainer(t, DockerOptions{
  106. Image: ImageV2RayCore,
  107. Ports: []uint16{serverPort, testPort},
  108. EntryPoint: "v2ray",
  109. Cmd: []string{"run"},
  110. Stdin: content,
  111. Bind: map[string]string{
  112. certPem: "/path/to/certificate.crt",
  113. keyPem: "/path/to/private.key",
  114. },
  115. })
  116. testSuitSimple(t, clientPort, testPort)
  117. }
  118. func testV2RayWebsocketOutbound(t *testing.T, maxEarlyData uint32, earlyDataHeaderName string) {
  119. userId, err := uuid.DefaultGenerator.NewV4()
  120. require.NoError(t, err)
  121. _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
  122. content, err := os.ReadFile("config/vmess-ws-server.json")
  123. require.NoError(t, err)
  124. config, err := ajson.Unmarshal(content)
  125. require.NoError(t, err)
  126. inbound := config.MustKey("inbounds").MustIndex(0)
  127. inbound.MustKey("port").SetNumeric(float64(serverPort))
  128. inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(userId.String())
  129. wsSettings := inbound.MustKey("streamSettings").MustKey("wsSettings")
  130. wsSettings.MustKey("maxEarlyData").SetNumeric(float64(maxEarlyData))
  131. wsSettings.MustKey("earlyDataHeaderName").SetString(earlyDataHeaderName)
  132. content, err = ajson.Marshal(config)
  133. require.NoError(t, err)
  134. startDockerContainer(t, DockerOptions{
  135. Image: ImageV2RayCore,
  136. Ports: []uint16{serverPort, testPort},
  137. EntryPoint: "v2ray",
  138. Cmd: []string{"run"},
  139. Stdin: content,
  140. Env: []string{"V2RAY_VMESS_AEAD_FORCED=false"},
  141. Bind: map[string]string{
  142. certPem: "/path/to/certificate.crt",
  143. keyPem: "/path/to/private.key",
  144. },
  145. })
  146. startInstance(t, option.Options{
  147. Inbounds: []option.Inbound{
  148. {
  149. Type: C.TypeMixed,
  150. Tag: "mixed-in",
  151. MixedOptions: option.HTTPMixedInboundOptions{
  152. ListenOptions: option.ListenOptions{
  153. Listen: option.NewListenAddress(netip.IPv4Unspecified()),
  154. ListenPort: clientPort,
  155. },
  156. },
  157. },
  158. },
  159. Outbounds: []option.Outbound{
  160. {
  161. Type: C.TypeVMess,
  162. Tag: "vmess-out",
  163. VMessOptions: option.VMessOutboundOptions{
  164. ServerOptions: option.ServerOptions{
  165. Server: "127.0.0.1",
  166. ServerPort: serverPort,
  167. },
  168. UUID: userId.String(),
  169. Security: "zero",
  170. TLS: &option.OutboundTLSOptions{
  171. Enabled: true,
  172. ServerName: "example.org",
  173. CertificatePath: certPem,
  174. },
  175. Transport: &option.V2RayTransportOptions{
  176. Type: C.V2RayTransportTypeWebsocket,
  177. WebsocketOptions: option.V2RayWebsocketOptions{
  178. MaxEarlyData: maxEarlyData,
  179. EarlyDataHeaderName: earlyDataHeaderName,
  180. },
  181. },
  182. },
  183. },
  184. },
  185. })
  186. testSuit(t, clientPort, testPort)
  187. }