clash_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. package main
  2. import (
  3. "context"
  4. "crypto/md5"
  5. "crypto/rand"
  6. "errors"
  7. "io"
  8. "net"
  9. _ "net/http/pprof"
  10. "net/netip"
  11. "sync"
  12. "testing"
  13. "time"
  14. "github.com/sagernet/sing-box/log"
  15. "github.com/sagernet/sing/common/control"
  16. F "github.com/sagernet/sing/common/format"
  17. "github.com/docker/docker/api/types"
  18. "github.com/docker/docker/client"
  19. "github.com/stretchr/testify/assert"
  20. "github.com/stretchr/testify/require"
  21. )
  22. // kanged from clash
  23. const (
  24. ImageShadowsocksRustServer = "ghcr.io/shadowsocks/ssserver-rust:latest"
  25. ImageShadowsocksRustClient = "ghcr.io/shadowsocks/sslocal-rust:latest"
  26. ImageV2RayCore = "v2fly/v2fly-core:latest"
  27. ImageTrojan = "trojangfw/trojan:latest"
  28. ImageNaive = "pocat/naiveproxy:client"
  29. ImageBoringTun = "ghcr.io/ntkme/boringtun:edge"
  30. ImageHysteria = "tobyxdd/hysteria:latest"
  31. ImageNginx = "nginx:stable"
  32. ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest"
  33. ImageShadowsocksR = "teddysun/shadowsocks-r:latest"
  34. ImageXRayCore = "teddysun/xray:latest"
  35. ImageShadowsocksLegacy = "mritd/shadowsocks:latest"
  36. )
  37. var allImages = []string{
  38. ImageShadowsocksRustServer,
  39. ImageShadowsocksRustClient,
  40. ImageV2RayCore,
  41. ImageTrojan,
  42. ImageNaive,
  43. ImageBoringTun,
  44. ImageHysteria,
  45. ImageNginx,
  46. ImageShadowTLS,
  47. ImageShadowsocksR,
  48. ImageXRayCore,
  49. ImageShadowsocksLegacy,
  50. }
  51. var localIP = netip.MustParseAddr("127.0.0.1")
  52. func init() {
  53. dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  54. if err != nil {
  55. panic(err)
  56. }
  57. defer dockerClient.Close()
  58. list, err := dockerClient.ImageList(context.Background(), types.ImageListOptions{All: true})
  59. if err != nil {
  60. log.Warn(err)
  61. return
  62. }
  63. imageExist := func(image string) bool {
  64. for _, item := range list {
  65. for _, tag := range item.RepoTags {
  66. if image == tag {
  67. return true
  68. }
  69. }
  70. }
  71. return false
  72. }
  73. for _, image := range allImages {
  74. if imageExist(image) {
  75. continue
  76. }
  77. log.Info("pulling image: ", image)
  78. imageStream, err := dockerClient.ImagePull(context.Background(), image, types.ImagePullOptions{})
  79. if err != nil {
  80. panic(err)
  81. }
  82. io.Copy(io.Discard, imageStream)
  83. }
  84. }
  85. func newPingPongPair() (chan []byte, chan []byte, func(t *testing.T) error) {
  86. pingCh := make(chan []byte)
  87. pongCh := make(chan []byte)
  88. test := func(t *testing.T) error {
  89. defer close(pingCh)
  90. defer close(pongCh)
  91. pingOpen := false
  92. pongOpen := false
  93. var recv []byte
  94. for {
  95. if pingOpen && pongOpen {
  96. break
  97. }
  98. select {
  99. case recv, pingOpen = <-pingCh:
  100. assert.True(t, pingOpen)
  101. assert.Equal(t, []byte("ping"), recv)
  102. case recv, pongOpen = <-pongCh:
  103. assert.True(t, pongOpen)
  104. assert.Equal(t, []byte("pong"), recv)
  105. case <-time.After(10 * time.Second):
  106. return errors.New("timeout")
  107. }
  108. }
  109. return nil
  110. }
  111. return pingCh, pongCh, test
  112. }
  113. func newLargeDataPair() (chan hashPair, chan hashPair, func(t *testing.T) error) {
  114. pingCh := make(chan hashPair)
  115. pongCh := make(chan hashPair)
  116. test := func(t *testing.T) error {
  117. defer close(pingCh)
  118. defer close(pongCh)
  119. pingOpen := false
  120. pongOpen := false
  121. var serverPair hashPair
  122. var clientPair hashPair
  123. for {
  124. if pingOpen && pongOpen {
  125. break
  126. }
  127. select {
  128. case serverPair, pingOpen = <-pingCh:
  129. assert.True(t, pingOpen)
  130. case clientPair, pongOpen = <-pongCh:
  131. assert.True(t, pongOpen)
  132. case <-time.After(10 * time.Second):
  133. return errors.New("timeout")
  134. }
  135. }
  136. assert.Equal(t, serverPair.recvHash, clientPair.sendHash)
  137. assert.Equal(t, serverPair.sendHash, clientPair.recvHash)
  138. return nil
  139. }
  140. return pingCh, pongCh, test
  141. }
  142. func testPingPongWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)) error {
  143. l, err := listen("tcp", ":"+F.ToString(port))
  144. if err != nil {
  145. return err
  146. }
  147. defer l.Close()
  148. c, err := cc()
  149. if err != nil {
  150. return err
  151. }
  152. defer c.Close()
  153. pingCh, pongCh, test := newPingPongPair()
  154. go func() {
  155. c, err := l.Accept()
  156. if err != nil {
  157. return
  158. }
  159. buf := make([]byte, 4)
  160. if _, err := io.ReadFull(c, buf); err != nil {
  161. return
  162. }
  163. pingCh <- buf
  164. if _, err := c.Write([]byte("pong")); err != nil {
  165. return
  166. }
  167. }()
  168. go func() {
  169. if _, err := c.Write([]byte("ping")); err != nil {
  170. return
  171. }
  172. buf := make([]byte, 4)
  173. if _, err := io.ReadFull(c, buf); err != nil {
  174. return
  175. }
  176. pongCh <- buf
  177. }()
  178. return test(t)
  179. }
  180. func testPingPongWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
  181. l, err := listenPacket("udp", ":"+F.ToString(port))
  182. if err != nil {
  183. return err
  184. }
  185. defer l.Close()
  186. rAddr := &net.UDPAddr{IP: localIP.AsSlice(), Port: int(port)}
  187. pingCh, pongCh, test := newPingPongPair()
  188. go func() {
  189. buf := make([]byte, 1024)
  190. n, rAddr, err := l.ReadFrom(buf)
  191. if err != nil {
  192. return
  193. }
  194. pingCh <- buf[:n]
  195. if _, err := l.WriteTo([]byte("pong"), rAddr); err != nil {
  196. return
  197. }
  198. }()
  199. pc, err := pcc()
  200. if err != nil {
  201. return err
  202. }
  203. defer pc.Close()
  204. go func() {
  205. if _, err := pc.WriteTo([]byte("ping"), rAddr); err != nil {
  206. return
  207. }
  208. buf := make([]byte, 1024)
  209. n, _, err := pc.ReadFrom(buf)
  210. if err != nil {
  211. return
  212. }
  213. pongCh <- buf[:n]
  214. }()
  215. return test(t)
  216. }
  217. type hashPair struct {
  218. sendHash map[int][]byte
  219. recvHash map[int][]byte
  220. }
  221. func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)) error {
  222. l, err := listen("tcp", ":"+F.ToString(port))
  223. require.NoError(t, err)
  224. defer l.Close()
  225. times := 100
  226. chunkSize := int64(64 * 1024)
  227. pingCh, pongCh, test := newLargeDataPair()
  228. writeRandData := func(conn net.Conn) (map[int][]byte, error) {
  229. buf := make([]byte, chunkSize)
  230. hashMap := map[int][]byte{}
  231. for i := 0; i < times; i++ {
  232. if _, err := rand.Read(buf[1:]); err != nil {
  233. return nil, err
  234. }
  235. buf[0] = byte(i)
  236. hash := md5.Sum(buf)
  237. hashMap[i] = hash[:]
  238. if _, err := conn.Write(buf); err != nil {
  239. return nil, err
  240. }
  241. }
  242. return hashMap, nil
  243. }
  244. c, err := cc()
  245. if err != nil {
  246. return err
  247. }
  248. defer c.Close()
  249. go func() {
  250. c, err := l.Accept()
  251. if err != nil {
  252. return
  253. }
  254. defer c.Close()
  255. hashMap := map[int][]byte{}
  256. buf := make([]byte, chunkSize)
  257. for i := 0; i < times; i++ {
  258. _, err := io.ReadFull(c, buf)
  259. if err != nil {
  260. t.Log(err.Error())
  261. return
  262. }
  263. hash := md5.Sum(buf)
  264. hashMap[int(buf[0])] = hash[:]
  265. }
  266. sendHash, err := writeRandData(c)
  267. if err != nil {
  268. t.Log(err.Error())
  269. return
  270. }
  271. pingCh <- hashPair{
  272. sendHash: sendHash,
  273. recvHash: hashMap,
  274. }
  275. }()
  276. go func() {
  277. sendHash, err := writeRandData(c)
  278. if err != nil {
  279. t.Log(err.Error())
  280. return
  281. }
  282. hashMap := map[int][]byte{}
  283. buf := make([]byte, chunkSize)
  284. for i := 0; i < times; i++ {
  285. _, err := io.ReadFull(c, buf)
  286. if err != nil {
  287. t.Log(err.Error())
  288. return
  289. }
  290. hash := md5.Sum(buf)
  291. hashMap[int(buf[0])] = hash[:]
  292. }
  293. pongCh <- hashPair{
  294. sendHash: sendHash,
  295. recvHash: hashMap,
  296. }
  297. }()
  298. return test(t)
  299. }
  300. func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
  301. l, err := listenPacket("udp", ":"+F.ToString(port))
  302. if err != nil {
  303. return err
  304. }
  305. defer l.Close()
  306. rAddr := &net.UDPAddr{IP: localIP.AsSlice(), Port: int(port)}
  307. times := 50
  308. chunkSize := int64(1024)
  309. pingCh, pongCh, test := newLargeDataPair()
  310. writeRandData := func(pc net.PacketConn, addr net.Addr) (map[int][]byte, error) {
  311. hashMap := map[int][]byte{}
  312. mux := sync.Mutex{}
  313. for i := 0; i < times; i++ {
  314. go func(idx int) {
  315. buf := make([]byte, chunkSize)
  316. if _, err := rand.Read(buf[1:]); err != nil {
  317. t.Log(err.Error())
  318. return
  319. }
  320. buf[0] = byte(idx)
  321. hash := md5.Sum(buf)
  322. mux.Lock()
  323. hashMap[idx] = hash[:]
  324. mux.Unlock()
  325. if _, err := pc.WriteTo(buf, addr); err != nil {
  326. t.Log(err.Error())
  327. return
  328. }
  329. }(i)
  330. }
  331. return hashMap, nil
  332. }
  333. go func() {
  334. var rAddr net.Addr
  335. hashMap := map[int][]byte{}
  336. buf := make([]byte, 64*1024)
  337. for i := 0; i < times; i++ {
  338. _, rAddr, err = l.ReadFrom(buf)
  339. if err != nil {
  340. t.Log(err.Error())
  341. return
  342. }
  343. hash := md5.Sum(buf[:chunkSize])
  344. hashMap[int(buf[0])] = hash[:]
  345. }
  346. sendHash, err := writeRandData(l, rAddr)
  347. if err != nil {
  348. t.Log(err.Error())
  349. return
  350. }
  351. pingCh <- hashPair{
  352. sendHash: sendHash,
  353. recvHash: hashMap,
  354. }
  355. }()
  356. pc, err := pcc()
  357. if err != nil {
  358. return err
  359. }
  360. defer pc.Close()
  361. go func() {
  362. sendHash, err := writeRandData(pc, rAddr)
  363. if err != nil {
  364. t.Log(err.Error())
  365. return
  366. }
  367. hashMap := map[int][]byte{}
  368. buf := make([]byte, 64*1024)
  369. for i := 0; i < times; i++ {
  370. _, _, err := pc.ReadFrom(buf)
  371. if err != nil {
  372. t.Log(err.Error())
  373. return
  374. }
  375. hash := md5.Sum(buf[:chunkSize])
  376. hashMap[int(buf[0])] = hash[:]
  377. }
  378. pongCh <- hashPair{
  379. sendHash: sendHash,
  380. recvHash: hashMap,
  381. }
  382. }()
  383. return test(t)
  384. }
  385. func testPacketConnTimeout(t *testing.T, pcc func() (net.PacketConn, error)) error {
  386. pc, err := pcc()
  387. if err != nil {
  388. return err
  389. }
  390. err = pc.SetReadDeadline(time.Now().Add(time.Millisecond * 300))
  391. require.NoError(t, err)
  392. errCh := make(chan error, 1)
  393. go func() {
  394. buf := make([]byte, 1024)
  395. _, _, err := pc.ReadFrom(buf)
  396. errCh <- err
  397. }()
  398. select {
  399. case <-errCh:
  400. return nil
  401. case <-time.After(time.Second * 10):
  402. return errors.New("timeout")
  403. }
  404. }
  405. func listen(network, address string) (net.Listener, error) {
  406. var lc net.ListenConfig
  407. lc.Control = control.ReuseAddr()
  408. var lastErr error
  409. for i := 0; i < 5; i++ {
  410. l, err := lc.Listen(context.Background(), network, address)
  411. if err == nil {
  412. return l, nil
  413. }
  414. lastErr = err
  415. time.Sleep(5 * time.Millisecond)
  416. }
  417. return nil, lastErr
  418. }
  419. func listenPacket(network, address string) (net.PacketConn, error) {
  420. var lc net.ListenConfig
  421. lc.Control = control.ReuseAddr()
  422. var lastErr error
  423. for i := 0; i < 5; i++ {
  424. l, err := lc.ListenPacket(context.Background(), network, address)
  425. if err == nil {
  426. return l, nil
  427. }
  428. lastErr = err
  429. time.Sleep(5 * time.Millisecond)
  430. }
  431. return nil, lastErr
  432. }