clash_test.go 10.0 KB

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