clash_test.go 9.7 KB

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