v2ray_ws_test.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
  74. TLS: &option.InboundTLSOptions{
  75. Enabled: true,
  76. ServerName: "example.org",
  77. CertificatePath: certPem,
  78. KeyPath: keyPem,
  79. },
  80. },
  81. Transport: &option.V2RayTransportOptions{
  82. Type: C.V2RayTransportTypeWebsocket,
  83. WebsocketOptions: option.V2RayWebsocketOptions{
  84. MaxEarlyData: maxEarlyData,
  85. EarlyDataHeaderName: earlyDataHeaderName,
  86. },
  87. },
  88. },
  89. },
  90. },
  91. })
  92. content, err := os.ReadFile("config/vmess-ws-client.json")
  93. require.NoError(t, err)
  94. config, err := ajson.Unmarshal(content)
  95. require.NoError(t, err)
  96. config.MustKey("inbounds").MustIndex(0).MustKey("port").SetNumeric(float64(clientPort))
  97. outbound := config.MustKey("outbounds").MustIndex(0)
  98. settings := outbound.MustKey("settings").MustKey("vnext").MustIndex(0)
  99. settings.MustKey("port").SetNumeric(float64(serverPort))
  100. user := settings.MustKey("users").MustIndex(0)
  101. user.MustKey("id").SetString(userId.String())
  102. wsSettings := outbound.MustKey("streamSettings").MustKey("wsSettings")
  103. wsSettings.MustKey("maxEarlyData").SetNumeric(float64(maxEarlyData))
  104. wsSettings.MustKey("earlyDataHeaderName").SetString(earlyDataHeaderName)
  105. content, err = ajson.Marshal(config)
  106. require.NoError(t, err)
  107. startDockerContainer(t, DockerOptions{
  108. Image: ImageV2RayCore,
  109. Ports: []uint16{serverPort, testPort},
  110. EntryPoint: "v2ray",
  111. Cmd: []string{"run"},
  112. Stdin: content,
  113. Bind: map[string]string{
  114. certPem: "/path/to/certificate.crt",
  115. keyPem: "/path/to/private.key",
  116. },
  117. })
  118. testSuitSimple(t, clientPort, testPort)
  119. }
  120. func testV2RayWebsocketOutbound(t *testing.T, maxEarlyData uint32, earlyDataHeaderName string) {
  121. userId, err := uuid.DefaultGenerator.NewV4()
  122. require.NoError(t, err)
  123. _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
  124. content, err := os.ReadFile("config/vmess-ws-server.json")
  125. require.NoError(t, err)
  126. config, err := ajson.Unmarshal(content)
  127. require.NoError(t, err)
  128. inbound := config.MustKey("inbounds").MustIndex(0)
  129. inbound.MustKey("port").SetNumeric(float64(serverPort))
  130. inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(userId.String())
  131. wsSettings := inbound.MustKey("streamSettings").MustKey("wsSettings")
  132. wsSettings.MustKey("maxEarlyData").SetNumeric(float64(maxEarlyData))
  133. wsSettings.MustKey("earlyDataHeaderName").SetString(earlyDataHeaderName)
  134. content, err = ajson.Marshal(config)
  135. require.NoError(t, err)
  136. startDockerContainer(t, DockerOptions{
  137. Image: ImageV2RayCore,
  138. Ports: []uint16{serverPort, testPort},
  139. EntryPoint: "v2ray",
  140. Cmd: []string{"run"},
  141. Stdin: content,
  142. Env: []string{"V2RAY_VMESS_AEAD_FORCED=false"},
  143. Bind: map[string]string{
  144. certPem: "/path/to/certificate.crt",
  145. keyPem: "/path/to/private.key",
  146. },
  147. })
  148. startInstance(t, option.Options{
  149. Inbounds: []option.Inbound{
  150. {
  151. Type: C.TypeMixed,
  152. Tag: "mixed-in",
  153. MixedOptions: option.HTTPMixedInboundOptions{
  154. ListenOptions: option.ListenOptions{
  155. Listen: option.NewListenAddress(netip.IPv4Unspecified()),
  156. ListenPort: clientPort,
  157. },
  158. },
  159. },
  160. },
  161. Outbounds: []option.Outbound{
  162. {
  163. Type: C.TypeVMess,
  164. Tag: "vmess-out",
  165. VMessOptions: option.VMessOutboundOptions{
  166. ServerOptions: option.ServerOptions{
  167. Server: "127.0.0.1",
  168. ServerPort: serverPort,
  169. },
  170. UUID: userId.String(),
  171. Security: "zero",
  172. OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
  173. TLS: &option.OutboundTLSOptions{
  174. Enabled: true,
  175. ServerName: "example.org",
  176. CertificatePath: certPem,
  177. },
  178. },
  179. Transport: &option.V2RayTransportOptions{
  180. Type: C.V2RayTransportTypeWebsocket,
  181. WebsocketOptions: option.V2RayWebsocketOptions{
  182. MaxEarlyData: maxEarlyData,
  183. EarlyDataHeaderName: earlyDataHeaderName,
  184. },
  185. },
  186. },
  187. },
  188. },
  189. })
  190. testSuit(t, clientPort, testPort)
  191. }