vmess_test.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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"
  9. "github.com/spyzhov/ajson"
  10. "github.com/stretchr/testify/require"
  11. )
  12. func TestVMess(t *testing.T) {
  13. for _, security := range []string{
  14. "zero",
  15. } {
  16. t.Run(security, func(t *testing.T) {
  17. testVMess0(t, security)
  18. })
  19. }
  20. for _, security := range []string{
  21. "aes-128-gcm", "chacha20-poly1305", "aes-128-cfb",
  22. } {
  23. t.Run(security, func(t *testing.T) {
  24. testVMess1(t, security)
  25. })
  26. }
  27. }
  28. func testVMess0(t *testing.T, security string) {
  29. user, err := uuid.DefaultGenerator.NewV4()
  30. require.NoError(t, err)
  31. t.Run("self", func(t *testing.T) {
  32. testVMessSelf(t, security, user, false, false)
  33. })
  34. t.Run("self-padding", func(t *testing.T) {
  35. testVMessSelf(t, security, user, true, false)
  36. })
  37. t.Run("outbound", func(t *testing.T) {
  38. testVMessOutboundWithV2Ray(t, security, user, false, false, 0)
  39. })
  40. t.Run("outbound-padding", func(t *testing.T) {
  41. testVMessOutboundWithV2Ray(t, security, user, true, false, 0)
  42. })
  43. t.Run("outbound-legacy", func(t *testing.T) {
  44. testVMessOutboundWithV2Ray(t, security, user, false, false, 1)
  45. })
  46. t.Run("outbound-legacy-padding", func(t *testing.T) {
  47. testVMessOutboundWithV2Ray(t, security, user, true, false, 1)
  48. })
  49. }
  50. func testVMess1(t *testing.T, security string) {
  51. user, err := uuid.DefaultGenerator.NewV4()
  52. require.NoError(t, err)
  53. t.Run("self", func(t *testing.T) {
  54. testVMessSelf(t, security, user, false, false)
  55. })
  56. t.Run("self-padding", func(t *testing.T) {
  57. testVMessSelf(t, security, user, true, false)
  58. })
  59. t.Run("self-authid", func(t *testing.T) {
  60. testVMessSelf(t, security, user, false, true)
  61. })
  62. t.Run("self-padding-authid", func(t *testing.T) {
  63. testVMessSelf(t, security, user, true, true)
  64. })
  65. t.Run("inbound", func(t *testing.T) {
  66. testVMessInboundWithV2Ray(t, security, user, false)
  67. })
  68. t.Run("inbound-authid", func(t *testing.T) {
  69. testVMessInboundWithV2Ray(t, security, user, true)
  70. })
  71. t.Run("outbound", func(t *testing.T) {
  72. testVMessOutboundWithV2Ray(t, security, user, false, false, 0)
  73. })
  74. t.Run("outbound-padding", func(t *testing.T) {
  75. testVMessOutboundWithV2Ray(t, security, user, true, false, 0)
  76. })
  77. t.Run("outbound-authid", func(t *testing.T) {
  78. testVMessOutboundWithV2Ray(t, security, user, false, true, 0)
  79. })
  80. t.Run("outbound-padding-authid", func(t *testing.T) {
  81. testVMessOutboundWithV2Ray(t, security, user, true, true, 0)
  82. })
  83. t.Run("outbound-legacy", func(t *testing.T) {
  84. testVMessOutboundWithV2Ray(t, security, user, false, false, 1)
  85. })
  86. t.Run("outbound-legacy-padding", func(t *testing.T) {
  87. testVMessOutboundWithV2Ray(t, security, user, true, false, 1)
  88. })
  89. t.Run("outbound-legacy-authid", func(t *testing.T) {
  90. testVMessOutboundWithV2Ray(t, security, user, false, true, 1)
  91. })
  92. t.Run("outbound-legacy-padding-authid", func(t *testing.T) {
  93. testVMessOutboundWithV2Ray(t, security, user, true, true, 1)
  94. })
  95. }
  96. func testVMessInboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, authenticatedLength bool) {
  97. content, err := os.ReadFile("config/vmess-client.json")
  98. require.NoError(t, err)
  99. config, err := ajson.Unmarshal(content)
  100. require.NoError(t, err)
  101. config.MustKey("inbounds").MustIndex(0).MustKey("port").SetNumeric(float64(clientPort))
  102. outbound := config.MustKey("outbounds").MustIndex(0).MustKey("settings").MustKey("vnext").MustIndex(0)
  103. outbound.MustKey("port").SetNumeric(float64(serverPort))
  104. user := outbound.MustKey("users").MustIndex(0)
  105. user.MustKey("id").SetString(uuid.String())
  106. user.MustKey("security").SetString(security)
  107. var experiments string
  108. if authenticatedLength {
  109. experiments += "AuthenticatedLength"
  110. }
  111. user.MustKey("experiments").SetString(experiments)
  112. content, err = ajson.Marshal(config)
  113. require.NoError(t, err)
  114. startDockerContainer(t, DockerOptions{
  115. Image: ImageV2RayCore,
  116. Ports: []uint16{serverPort, testPort},
  117. EntryPoint: "v2ray",
  118. Stdin: content,
  119. Env: []string{"V2RAY_VMESS_AEAD_FORCED=false"},
  120. })
  121. startInstance(t, option.Options{
  122. Log: &option.LogOptions{
  123. Level: "error",
  124. },
  125. Inbounds: []option.Inbound{
  126. {
  127. Type: C.TypeVMess,
  128. VMessOptions: option.VMessInboundOptions{
  129. ListenOptions: option.ListenOptions{
  130. Listen: option.ListenAddress(netip.IPv4Unspecified()),
  131. ListenPort: serverPort,
  132. },
  133. Users: []option.VMessUser{
  134. {
  135. Name: "sekai",
  136. UUID: uuid.String(),
  137. },
  138. },
  139. },
  140. },
  141. },
  142. })
  143. testSuit(t, clientPort, testPort)
  144. }
  145. func testVMessOutboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, globalPadding bool, authenticatedLength bool, alterId int) {
  146. content, err := os.ReadFile("config/vmess-server.json")
  147. require.NoError(t, err)
  148. config, err := ajson.Unmarshal(content)
  149. require.NoError(t, err)
  150. inbound := config.MustKey("inbounds").MustIndex(0)
  151. inbound.MustKey("port").SetNumeric(float64(serverPort))
  152. inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(uuid.String())
  153. inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("alterId").SetNumeric(float64(alterId))
  154. content, err = ajson.Marshal(config)
  155. require.NoError(t, err)
  156. startDockerContainer(t, DockerOptions{
  157. Image: ImageV2RayCore,
  158. Ports: []uint16{serverPort, testPort},
  159. EntryPoint: "v2ray",
  160. Stdin: content,
  161. Env: []string{"V2RAY_VMESS_AEAD_FORCED=false"},
  162. })
  163. startInstance(t, option.Options{
  164. Log: &option.LogOptions{
  165. Level: "error",
  166. },
  167. Inbounds: []option.Inbound{
  168. {
  169. Type: C.TypeMixed,
  170. MixedOptions: option.HTTPMixedInboundOptions{
  171. ListenOptions: option.ListenOptions{
  172. Listen: option.ListenAddress(netip.IPv4Unspecified()),
  173. ListenPort: clientPort,
  174. },
  175. },
  176. },
  177. },
  178. Outbounds: []option.Outbound{
  179. {
  180. Type: C.TypeVMess,
  181. VMessOptions: option.VMessOutboundOptions{
  182. ServerOptions: option.ServerOptions{
  183. Server: "127.0.0.1",
  184. ServerPort: serverPort,
  185. },
  186. Security: security,
  187. UUID: uuid.String(),
  188. GlobalPadding: globalPadding,
  189. AuthenticatedLength: authenticatedLength,
  190. AlterId: alterId,
  191. },
  192. },
  193. },
  194. })
  195. testSuit(t, clientPort, testPort)
  196. }
  197. func testVMessSelf(t *testing.T, security string, uuid uuid.UUID, globalPadding bool, authenticatedLength bool) {
  198. startInstance(t, option.Options{
  199. Log: &option.LogOptions{
  200. Level: "error",
  201. },
  202. Inbounds: []option.Inbound{
  203. {
  204. Type: C.TypeMixed,
  205. Tag: "mixed-in",
  206. MixedOptions: option.HTTPMixedInboundOptions{
  207. ListenOptions: option.ListenOptions{
  208. Listen: option.ListenAddress(netip.IPv4Unspecified()),
  209. ListenPort: clientPort,
  210. },
  211. },
  212. },
  213. {
  214. Type: C.TypeVMess,
  215. VMessOptions: option.VMessInboundOptions{
  216. ListenOptions: option.ListenOptions{
  217. Listen: option.ListenAddress(netip.IPv4Unspecified()),
  218. ListenPort: serverPort,
  219. },
  220. Users: []option.VMessUser{
  221. {
  222. Name: "sekai",
  223. UUID: uuid.String(),
  224. },
  225. },
  226. },
  227. },
  228. },
  229. Outbounds: []option.Outbound{
  230. {
  231. Type: C.TypeDirect,
  232. },
  233. {
  234. Type: C.TypeVMess,
  235. Tag: "vmess-out",
  236. VMessOptions: option.VMessOutboundOptions{
  237. ServerOptions: option.ServerOptions{
  238. Server: "127.0.0.1",
  239. ServerPort: serverPort,
  240. },
  241. Security: security,
  242. UUID: uuid.String(),
  243. GlobalPadding: globalPadding,
  244. AuthenticatedLength: authenticatedLength,
  245. },
  246. },
  247. },
  248. Route: &option.RouteOptions{
  249. Rules: []option.Rule{
  250. {
  251. DefaultOptions: option.DefaultRule{
  252. Inbound: []string{"mixed-in"},
  253. Outbound: "vmess-out",
  254. },
  255. },
  256. },
  257. },
  258. })
  259. testSuit(t, clientPort, testPort)
  260. }