v2ray_ws_test.go 6.2 KB

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