ss_test.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. package main
  2. import (
  3. "crypto/rand"
  4. "encoding/base64"
  5. "fmt"
  6. "net"
  7. "testing"
  8. "time"
  9. "github.com/docker/docker/api/types/container"
  10. "github.com/metacubex/mihomo/adapter/outbound"
  11. C "github.com/metacubex/mihomo/constant"
  12. "github.com/stretchr/testify/require"
  13. )
  14. func TestMihomo_Shadowsocks(t *testing.T) {
  15. for _, method := range []string{
  16. "aes-128-ctr",
  17. "aes-192-ctr",
  18. "aes-256-ctr",
  19. "aes-128-cfb",
  20. "aes-192-cfb",
  21. "aes-256-cfb",
  22. "rc4-md5",
  23. "chacha20-ietf",
  24. "aes-128-gcm",
  25. "aes-256-gcm",
  26. "chacha20-ietf-poly1305",
  27. "xchacha20-ietf-poly1305",
  28. } {
  29. t.Run(method, func(t *testing.T) {
  30. testMihomo_Shadowsocks(t, method, "FzcLbKs2dY9mhL")
  31. })
  32. }
  33. for _, method := range []string{
  34. "aes-128-gcm",
  35. "aes-256-gcm",
  36. "chacha20-ietf-poly1305",
  37. } {
  38. t.Run(method, func(t *testing.T) {
  39. testMihomo_ShadowsocksRust(t, method, "FzcLbKs2dY9mhL")
  40. })
  41. }
  42. }
  43. func TestMihomo_Shadowsocks2022(t *testing.T) {
  44. for _, method := range []string{
  45. "2022-blake3-aes-128-gcm",
  46. } {
  47. t.Run(method, func(t *testing.T) {
  48. testMihomo_ShadowsocksRust(t, method, mkKey(16))
  49. })
  50. }
  51. for _, method := range []string{
  52. "2022-blake3-aes-256-gcm",
  53. "2022-blake3-chacha20-poly1305",
  54. } {
  55. t.Run(method, func(t *testing.T) {
  56. testMihomo_ShadowsocksRust(t, method, mkKey(32))
  57. })
  58. }
  59. }
  60. func mkKey(bits int) string {
  61. k := make([]byte, bits)
  62. rand.Read(k)
  63. return base64.StdEncoding.EncodeToString(k)
  64. }
  65. func testMihomo_Shadowsocks(t *testing.T, method string, password string) {
  66. cfg := &container.Config{
  67. Image: ImageShadowsocks,
  68. Env: []string{
  69. "SS_MODULE=ss-server",
  70. "SS_CONFIG=-s 0.0.0.0 -u -p 10002 -m " + method + " -k " + password,
  71. },
  72. ExposedPorts: defaultExposedPorts,
  73. }
  74. hostCfg := &container.HostConfig{
  75. PortBindings: defaultPortBindings,
  76. }
  77. id, err := startContainer(cfg, hostCfg, "ss")
  78. require.NoError(t, err)
  79. t.Cleanup(func() {
  80. cleanContainer(id)
  81. })
  82. proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
  83. Name: "ss",
  84. Server: localIP.String(),
  85. Port: 10002,
  86. Password: password,
  87. Cipher: method,
  88. UDP: true,
  89. })
  90. require.NoError(t, err)
  91. time.Sleep(waitTime)
  92. testSuit(t, proxy)
  93. }
  94. func testMihomo_ShadowsocksRust(t *testing.T, method string, password string) {
  95. cfg := &container.Config{
  96. Image: ImageShadowsocksRust,
  97. Entrypoint: []string{"ssserver"},
  98. Cmd: []string{"-s", "0.0.0.0:10002", "-m", method, "-k", password, "-U", "-v"},
  99. ExposedPorts: defaultExposedPorts,
  100. }
  101. hostCfg := &container.HostConfig{
  102. PortBindings: defaultPortBindings,
  103. }
  104. id, err := startContainer(cfg, hostCfg, "ss-rust")
  105. require.NoError(t, err)
  106. t.Cleanup(func() {
  107. cleanContainer(id)
  108. })
  109. proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
  110. Name: "ss",
  111. Server: localIP.String(),
  112. Port: 10002,
  113. Password: password,
  114. Cipher: method,
  115. UDP: true,
  116. })
  117. require.NoError(t, err)
  118. time.Sleep(waitTime)
  119. testSuit(t, proxy)
  120. }
  121. func TestMihomo_ShadowsocksObfsHTTP(t *testing.T) {
  122. cfg := &container.Config{
  123. Image: ImageShadowsocks,
  124. Env: []string{
  125. "SS_MODULE=ss-server",
  126. "SS_CONFIG=-s 0.0.0.0 -u -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL --plugin obfs-server --plugin-opts obfs=http",
  127. },
  128. ExposedPorts: defaultExposedPorts,
  129. }
  130. hostCfg := &container.HostConfig{
  131. PortBindings: defaultPortBindings,
  132. }
  133. id, err := startContainer(cfg, hostCfg, "ss-obfs-http")
  134. require.NoError(t, err)
  135. t.Cleanup(func() {
  136. cleanContainer(id)
  137. })
  138. proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
  139. Name: "ss",
  140. Server: localIP.String(),
  141. Port: 10002,
  142. Password: "FzcLbKs2dY9mhL",
  143. Cipher: "chacha20-ietf-poly1305",
  144. UDP: true,
  145. Plugin: "obfs",
  146. PluginOpts: map[string]any{
  147. "mode": "http",
  148. },
  149. })
  150. require.NoError(t, err)
  151. time.Sleep(waitTime)
  152. testSuit(t, proxy)
  153. }
  154. func TestMihomo_ShadowsocksObfsTLS(t *testing.T) {
  155. cfg := &container.Config{
  156. Image: ImageShadowsocks,
  157. Env: []string{
  158. "SS_MODULE=ss-server",
  159. "SS_CONFIG=-s 0.0.0.0 -u -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL --plugin obfs-server --plugin-opts obfs=tls",
  160. },
  161. ExposedPorts: defaultExposedPorts,
  162. }
  163. hostCfg := &container.HostConfig{
  164. PortBindings: defaultPortBindings,
  165. }
  166. id, err := startContainer(cfg, hostCfg, "ss-obfs-tls")
  167. require.NoError(t, err)
  168. t.Cleanup(func() {
  169. cleanContainer(id)
  170. })
  171. proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
  172. Name: "ss",
  173. Server: localIP.String(),
  174. Port: 10002,
  175. Password: "FzcLbKs2dY9mhL",
  176. Cipher: "chacha20-ietf-poly1305",
  177. UDP: true,
  178. Plugin: "obfs",
  179. PluginOpts: map[string]any{
  180. "mode": "tls",
  181. },
  182. })
  183. require.NoError(t, err)
  184. time.Sleep(waitTime)
  185. testSuit(t, proxy)
  186. }
  187. func TestMihomo_ShadowsocksV2RayPlugin(t *testing.T) {
  188. cfg := &container.Config{
  189. Image: ImageShadowsocks,
  190. Env: []string{
  191. "SS_MODULE=ss-server",
  192. "SS_CONFIG=-s 0.0.0.0 -u -p 10002 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL --plugin v2ray-plugin --plugin-opts=server",
  193. },
  194. ExposedPorts: defaultExposedPorts,
  195. }
  196. hostCfg := &container.HostConfig{
  197. PortBindings: defaultPortBindings,
  198. }
  199. id, err := startContainer(cfg, hostCfg, "ss-v2ray-plugin")
  200. require.NoError(t, err)
  201. t.Cleanup(func() {
  202. cleanContainer(id)
  203. })
  204. proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
  205. Name: "ss",
  206. Server: localIP.String(),
  207. Port: 10002,
  208. Password: "FzcLbKs2dY9mhL",
  209. Cipher: "chacha20-ietf-poly1305",
  210. UDP: true,
  211. Plugin: "v2ray-plugin",
  212. PluginOpts: map[string]any{
  213. "mode": "websocket",
  214. },
  215. })
  216. require.NoError(t, err)
  217. time.Sleep(waitTime)
  218. testSuit(t, proxy)
  219. }
  220. func Benchmark_Shadowsocks(b *testing.B) {
  221. cfg := &container.Config{
  222. Image: ImageShadowsocksRust,
  223. Entrypoint: []string{"ssserver"},
  224. Cmd: []string{"-s", "0.0.0.0:10002", "-m", "aes-256-gcm", "-k", "FzcLbKs2dY9mhL", "-U"},
  225. ExposedPorts: defaultExposedPorts,
  226. }
  227. hostCfg := &container.HostConfig{
  228. PortBindings: defaultPortBindings,
  229. }
  230. id, err := startContainer(cfg, hostCfg, "ss-bench")
  231. require.NoError(b, err)
  232. b.Cleanup(func() {
  233. cleanContainer(id)
  234. })
  235. proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
  236. Name: "ss",
  237. Server: localIP.String(),
  238. Port: 10002,
  239. Password: "FzcLbKs2dY9mhL",
  240. Cipher: "aes-256-gcm",
  241. UDP: true,
  242. })
  243. require.NoError(b, err)
  244. require.True(b, TCPing(net.JoinHostPort(localIP.String(), "10002")))
  245. benchmarkProxy(b, proxy)
  246. }
  247. func TestMihomo_ShadowsocksUoT(t *testing.T) {
  248. configPath := C.Path.Resolve("xray-shadowsocks.json")
  249. cfg := &container.Config{
  250. Image: ImageVless,
  251. ExposedPorts: defaultExposedPorts,
  252. }
  253. hostCfg := &container.HostConfig{
  254. PortBindings: defaultPortBindings,
  255. Binds: []string{fmt.Sprintf("%s:/etc/xray/config.json", configPath)},
  256. }
  257. id, err := startContainer(cfg, hostCfg, "xray-ss")
  258. require.NoError(t, err)
  259. t.Cleanup(func() {
  260. cleanContainer(id)
  261. })
  262. proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
  263. Name: "ss",
  264. Server: localIP.String(),
  265. Port: 10002,
  266. Password: "FzcLbKs2dY9mhL",
  267. Cipher: "aes-128-gcm",
  268. UDP: true,
  269. UDPOverTCP: true,
  270. })
  271. require.NoError(t, err)
  272. time.Sleep(waitTime)
  273. testSuit(t, proxy)
  274. }