clash_test.go 10 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. "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. ImageBoringTun = "ghcr.io/ntkme/boringtun:edge"
  30. ImageHysteria = "tobyxdd/hysteria:v1.3.5"
  31. ImageHysteria2 = "tobyxdd/hysteria:v2"
  32. ImageNginx = "nginx:stable"
  33. ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest"
  34. ImageXRayCore = "teddysun/xray:latest"
  35. ImageShadowsocksLegacy = "mritd/shadowsocks:latest"
  36. ImageTUICServer = "kilvn/tuic-server:latest"
  37. ImageTUICClient = "kilvn/tuic-client:latest"
  38. )
  39. var allImages = []string{
  40. ImageShadowsocksRustServer,
  41. ImageShadowsocksRustClient,
  42. ImageV2RayCore,
  43. ImageTrojan,
  44. ImageNaive,
  45. ImageBoringTun,
  46. ImageHysteria,
  47. ImageHysteria2,
  48. ImageNginx,
  49. ImageShadowTLS,
  50. ImageXRayCore,
  51. ImageShadowsocksLegacy,
  52. ImageTUICServer,
  53. ImageTUICClient,
  54. }
  55. var localIP = netip.MustParseAddr("127.0.0.1")
  56. func init() {
  57. dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
  58. if err != nil {
  59. panic(err)
  60. }
  61. defer dockerClient.Close()
  62. list, err := dockerClient.ImageList(context.Background(), types.ImageListOptions{All: true})
  63. if err != nil {
  64. log.Warn(err)
  65. return
  66. }
  67. imageExist := func(image string) bool {
  68. for _, item := range list {
  69. for _, tag := range item.RepoTags {
  70. if image == tag {
  71. return true
  72. }
  73. }
  74. }
  75. return false
  76. }
  77. for _, image := range allImages {
  78. if imageExist(image) {
  79. continue
  80. }
  81. log.Info("pulling image: ", image)
  82. imageStream, err := dockerClient.ImagePull(context.Background(), image, types.ImagePullOptions{})
  83. if err != nil {
  84. panic(err)
  85. }
  86. io.Copy(io.Discard, imageStream)
  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. defer c.Close()
  157. pingCh, pongCh, test := newPingPongPair()
  158. go func() {
  159. c, err := l.Accept()
  160. if err != nil {
  161. return
  162. }
  163. buf := make([]byte, 4)
  164. if _, err := io.ReadFull(c, buf); err != nil {
  165. return
  166. }
  167. pingCh <- buf
  168. if _, err := c.Write([]byte("pong")); err != nil {
  169. return
  170. }
  171. }()
  172. go func() {
  173. if _, err := c.Write([]byte("ping")); err != nil {
  174. return
  175. }
  176. buf := make([]byte, 4)
  177. if _, err := io.ReadFull(c, buf); err != nil {
  178. return
  179. }
  180. pongCh <- buf
  181. }()
  182. return test(t)
  183. }
  184. func testPingPongWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
  185. l, err := listenPacket("udp", ":"+F.ToString(port))
  186. if err != nil {
  187. return err
  188. }
  189. defer l.Close()
  190. rAddr := &net.UDPAddr{IP: localIP.AsSlice(), Port: int(port)}
  191. pingCh, pongCh, test := newPingPongPair()
  192. go func() {
  193. buf := make([]byte, 1024)
  194. n, rAddr, err := l.ReadFrom(buf)
  195. if err != nil {
  196. return
  197. }
  198. pingCh <- buf[:n]
  199. if _, err := l.WriteTo([]byte("pong"), rAddr); err != nil {
  200. return
  201. }
  202. }()
  203. pc, err := pcc()
  204. if err != nil {
  205. return err
  206. }
  207. defer pc.Close()
  208. go func() {
  209. if _, err := pc.WriteTo([]byte("ping"), rAddr); err != nil {
  210. return
  211. }
  212. buf := make([]byte, 1024)
  213. n, _, err := pc.ReadFrom(buf)
  214. if err != nil {
  215. return
  216. }
  217. pongCh <- buf[:n]
  218. }()
  219. return test(t)
  220. }
  221. type hashPair struct {
  222. sendHash map[int][]byte
  223. recvHash map[int][]byte
  224. }
  225. func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)) error {
  226. l, err := listen("tcp", ":"+F.ToString(port))
  227. require.NoError(t, err)
  228. defer l.Close()
  229. times := 100
  230. chunkSize := int64(64 * 1024)
  231. pingCh, pongCh, test := newLargeDataPair()
  232. writeRandData := func(conn net.Conn) (map[int][]byte, error) {
  233. buf := make([]byte, chunkSize)
  234. hashMap := map[int][]byte{}
  235. for i := 0; i < times; i++ {
  236. if _, err := rand.Read(buf[1:]); err != nil {
  237. return nil, err
  238. }
  239. buf[0] = byte(i)
  240. hash := md5.Sum(buf)
  241. hashMap[i] = hash[:]
  242. if _, err := conn.Write(buf); err != nil {
  243. return nil, err
  244. }
  245. }
  246. return hashMap, nil
  247. }
  248. c, err := cc()
  249. if err != nil {
  250. return err
  251. }
  252. defer c.Close()
  253. go func() {
  254. c, err := l.Accept()
  255. if err != nil {
  256. return
  257. }
  258. defer c.Close()
  259. hashMap := map[int][]byte{}
  260. buf := make([]byte, chunkSize)
  261. for i := 0; i < times; i++ {
  262. _, err := io.ReadFull(c, buf)
  263. if err != nil {
  264. t.Log(err.Error())
  265. return
  266. }
  267. hash := md5.Sum(buf)
  268. hashMap[int(buf[0])] = hash[:]
  269. }
  270. sendHash, err := writeRandData(c)
  271. if err != nil {
  272. t.Log(err.Error())
  273. return
  274. }
  275. pingCh <- hashPair{
  276. sendHash: sendHash,
  277. recvHash: hashMap,
  278. }
  279. }()
  280. go func() {
  281. sendHash, err := writeRandData(c)
  282. if err != nil {
  283. t.Log(err.Error())
  284. return
  285. }
  286. hashMap := map[int][]byte{}
  287. buf := make([]byte, chunkSize)
  288. for i := 0; i < times; i++ {
  289. _, err := io.ReadFull(c, buf)
  290. if err != nil {
  291. t.Log(err.Error())
  292. return
  293. }
  294. hash := md5.Sum(buf)
  295. hashMap[int(buf[0])] = hash[:]
  296. }
  297. pongCh <- hashPair{
  298. sendHash: sendHash,
  299. recvHash: hashMap,
  300. }
  301. }()
  302. return test(t)
  303. }
  304. func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
  305. return testLargeDataWithPacketConnSize(t, port, 1500, pcc)
  306. }
  307. func testLargeDataWithPacketConnSize(t *testing.T, port uint16, chunkSize int, 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. pingCh, pongCh, test := newLargeDataPair()
  316. writeRandData := func(pc net.PacketConn, addr net.Addr) (map[int][]byte, error) {
  317. hashMap := map[int][]byte{}
  318. mux := sync.Mutex{}
  319. for i := 0; i < times; i++ {
  320. buf := make([]byte, chunkSize)
  321. if _, err := rand.Read(buf[1:]); err != nil {
  322. t.Log(err.Error())
  323. continue
  324. }
  325. buf[0] = byte(i)
  326. hash := md5.Sum(buf)
  327. mux.Lock()
  328. hashMap[i] = hash[:]
  329. mux.Unlock()
  330. if _, err := pc.WriteTo(buf, addr); err != nil {
  331. t.Log(err.Error())
  332. }
  333. time.Sleep(10 * time.Millisecond)
  334. }
  335. return hashMap, nil
  336. }
  337. go func() {
  338. var rAddr net.Addr
  339. hashMap := map[int][]byte{}
  340. buf := make([]byte, 64*1024)
  341. for i := 0; i < times; i++ {
  342. _, rAddr, err = l.ReadFrom(buf)
  343. if err != nil {
  344. t.Log(err.Error())
  345. return
  346. }
  347. hash := md5.Sum(buf[:chunkSize])
  348. hashMap[int(buf[0])] = hash[:]
  349. }
  350. sendHash, err := writeRandData(l, rAddr)
  351. if err != nil {
  352. t.Log(err.Error())
  353. return
  354. }
  355. pingCh <- hashPair{
  356. sendHash: sendHash,
  357. recvHash: hashMap,
  358. }
  359. }()
  360. pc, err := pcc()
  361. if err != nil {
  362. return err
  363. }
  364. defer pc.Close()
  365. go func() {
  366. sendHash, err := writeRandData(pc, rAddr)
  367. if err != nil {
  368. t.Log(err.Error())
  369. return
  370. }
  371. hashMap := map[int][]byte{}
  372. buf := make([]byte, 64*1024)
  373. for i := 0; i < times; i++ {
  374. _, _, err := pc.ReadFrom(buf)
  375. if err != nil {
  376. t.Log(err.Error())
  377. return
  378. }
  379. hash := md5.Sum(buf[:chunkSize])
  380. hashMap[int(buf[0])] = hash[:]
  381. }
  382. pongCh <- hashPair{
  383. sendHash: sendHash,
  384. recvHash: hashMap,
  385. }
  386. }()
  387. return test(t)
  388. }
  389. func testPacketConnTimeout(t *testing.T, pcc func() (net.PacketConn, error)) error {
  390. pc, err := pcc()
  391. if err != nil {
  392. return err
  393. }
  394. err = pc.SetReadDeadline(time.Now().Add(time.Millisecond * 300))
  395. require.NoError(t, err)
  396. errCh := make(chan error, 1)
  397. go func() {
  398. buf := make([]byte, 1024)
  399. _, _, err := pc.ReadFrom(buf)
  400. errCh <- err
  401. }()
  402. select {
  403. case <-errCh:
  404. return nil
  405. case <-time.After(time.Second * 10):
  406. return errors.New("timeout")
  407. }
  408. }
  409. func listen(network, address string) (net.Listener, error) {
  410. var lc net.ListenConfig
  411. lc.Control = control.ReuseAddr()
  412. var lastErr error
  413. for i := 0; i < 5; i++ {
  414. l, err := lc.Listen(context.Background(), network, address)
  415. if err == nil {
  416. return l, nil
  417. }
  418. lastErr = err
  419. time.Sleep(5 * time.Millisecond)
  420. }
  421. return nil, lastErr
  422. }
  423. func listenPacket(network, address string) (net.PacketConn, error) {
  424. var lc net.ListenConfig
  425. lc.Control = control.ReuseAddr()
  426. var lastErr error
  427. for i := 0; i < 5; i++ {
  428. l, err := lc.ListenPacket(context.Background(), network, address)
  429. if err == nil {
  430. return l, nil
  431. }
  432. lastErr = err
  433. time.Sleep(5 * time.Millisecond)
  434. }
  435. return nil, lastErr
  436. }