clash_test.go 9.4 KB

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