clash_test.go 10 KB

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