clash_test.go 9.3 KB

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