sing-box/test/clash_test.go

519 lines
9.9 KiB
Go
Raw Permalink Normal View History

2022-07-09 00:01:23 +08:00
package main
import (
"context"
"crypto/md5"
"crypto/rand"
"errors"
"io"
"net"
_ "net/http/pprof"
2022-07-09 00:01:23 +08:00
"net/netip"
"sync"
"testing"
"time"
2022-07-15 08:42:02 +08:00
"github.com/sagernet/sing-box/log"
2022-07-18 18:50:19 +08:00
"github.com/sagernet/sing/common/control"
2022-07-09 00:01:23 +08:00
F "github.com/sagernet/sing/common/format"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// kanged from clash
const (
ImageShadowsocksRustServer = "ghcr.io/shadowsocks/ssserver-rust:latest"
ImageShadowsocksRustClient = "ghcr.io/shadowsocks/sslocal-rust:latest"
2022-07-18 18:50:19 +08:00
ImageV2RayCore = "v2fly/v2fly-core:latest"
2022-08-08 08:56:04 +08:00
ImageTrojan = "trojangfw/trojan:latest"
2022-08-10 20:19:16 +08:00
ImageNaive = "pocat/naiveproxy:client"
2022-08-16 23:37:51 +08:00
ImageBoringTun = "ghcr.io/ntkme/boringtun:edge"
ImageHysteria = "tobyxdd/hysteria:latest"
2022-08-23 13:22:03 +08:00
ImageNginx = "nginx:stable"
ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest"
2022-09-12 17:30:54 +08:00
ImageShadowsocksR = "teddysun/shadowsocks-r:latest"
2022-09-12 21:59:27 +08:00
ImageXRayCore = "teddysun/xray:latest"
2022-09-25 16:16:48 +08:00
ImageShadowsocksLegacy = "mritd/shadowsocks:latest"
2022-07-09 00:01:23 +08:00
)
var allImages = []string{
ImageShadowsocksRustServer,
ImageShadowsocksRustClient,
2022-07-18 18:50:19 +08:00
ImageV2RayCore,
2022-08-08 08:56:04 +08:00
ImageTrojan,
2022-08-10 20:19:16 +08:00
ImageNaive,
2022-08-16 23:37:51 +08:00
ImageBoringTun,
ImageHysteria,
ImageNginx,
ImageShadowTLS,
2022-09-12 17:30:54 +08:00
ImageShadowsocksR,
2022-09-12 21:59:27 +08:00
ImageXRayCore,
2022-09-25 16:16:48 +08:00
ImageShadowsocksLegacy,
2022-07-09 00:01:23 +08:00
}
2022-07-24 22:54:16 +08:00
var localIP = netip.MustParseAddr("127.0.0.1")
2022-07-09 00:01:23 +08:00
func init() {
dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer dockerClient.Close()
list, err := dockerClient.ImageList(context.Background(), types.ImageListOptions{All: true})
if err != nil {
2023-02-20 13:53:06 +08:00
log.Warn(err)
return
2022-07-09 00:01:23 +08:00
}
imageExist := func(image string) bool {
for _, item := range list {
for _, tag := range item.RepoTags {
if image == tag {
return true
}
}
}
return false
}
for _, image := range allImages {
if imageExist(image) {
continue
}
2022-07-14 23:06:03 +08:00
log.Info("pulling image: ", image)
2022-07-09 00:01:23 +08:00
imageStream, err := dockerClient.ImagePull(context.Background(), image, types.ImagePullOptions{})
if err != nil {
panic(err)
}
io.Copy(io.Discard, imageStream)
}
}
func newPingPongPair() (chan []byte, chan []byte, func(t *testing.T) error) {
pingCh := make(chan []byte)
pongCh := make(chan []byte)
test := func(t *testing.T) error {
defer close(pingCh)
defer close(pongCh)
pingOpen := false
pongOpen := false
var recv []byte
for {
if pingOpen && pongOpen {
break
}
select {
case recv, pingOpen = <-pingCh:
assert.True(t, pingOpen)
assert.Equal(t, []byte("ping"), recv)
case recv, pongOpen = <-pongCh:
assert.True(t, pongOpen)
assert.Equal(t, []byte("pong"), recv)
case <-time.After(10 * time.Second):
return errors.New("timeout")
}
}
return nil
}
return pingCh, pongCh, test
}
func newLargeDataPair() (chan hashPair, chan hashPair, func(t *testing.T) error) {
pingCh := make(chan hashPair)
pongCh := make(chan hashPair)
test := func(t *testing.T) error {
defer close(pingCh)
defer close(pongCh)
pingOpen := false
pongOpen := false
var serverPair hashPair
var clientPair hashPair
for {
if pingOpen && pongOpen {
break
}
select {
case serverPair, pingOpen = <-pingCh:
assert.True(t, pingOpen)
case clientPair, pongOpen = <-pongCh:
assert.True(t, pongOpen)
case <-time.After(10 * time.Second):
return errors.New("timeout")
}
}
assert.Equal(t, serverPair.recvHash, clientPair.sendHash)
assert.Equal(t, serverPair.sendHash, clientPair.recvHash)
return nil
}
return pingCh, pongCh, test
}
2022-07-18 12:32:31 +08:00
func testPingPongWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)) error {
2022-07-09 00:01:23 +08:00
l, err := listen("tcp", ":"+F.ToString(port))
if err != nil {
return err
}
defer l.Close()
2022-07-18 12:32:31 +08:00
c, err := cc()
2022-07-09 00:01:23 +08:00
if err != nil {
return err
}
2022-09-07 15:41:19 +08:00
defer c.Close()
2022-07-09 00:01:23 +08:00
pingCh, pongCh, test := newPingPongPair()
go func() {
c, err := l.Accept()
if err != nil {
return
}
buf := make([]byte, 4)
if _, err := io.ReadFull(c, buf); err != nil {
return
}
pingCh <- buf
if _, err := c.Write([]byte("pong")); err != nil {
return
}
}()
go func() {
if _, err := c.Write([]byte("ping")); err != nil {
return
}
buf := make([]byte, 4)
if _, err := io.ReadFull(c, buf); err != nil {
return
}
pongCh <- buf
}()
return test(t)
}
2022-07-18 12:32:31 +08:00
func testPingPongWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
2022-07-09 00:01:23 +08:00
l, err := listenPacket("udp", ":"+F.ToString(port))
2022-07-18 18:50:19 +08:00
if err != nil {
return err
}
2022-07-09 00:01:23 +08:00
defer l.Close()
rAddr := &net.UDPAddr{IP: localIP.AsSlice(), Port: int(port)}
pingCh, pongCh, test := newPingPongPair()
go func() {
buf := make([]byte, 1024)
n, rAddr, err := l.ReadFrom(buf)
if err != nil {
return
}
pingCh <- buf[:n]
if _, err := l.WriteTo([]byte("pong"), rAddr); err != nil {
return
}
}()
2022-07-18 12:32:31 +08:00
pc, err := pcc()
2022-07-09 00:01:23 +08:00
if err != nil {
return err
}
2022-09-07 15:41:19 +08:00
defer pc.Close()
2022-07-09 00:01:23 +08:00
go func() {
if _, err := pc.WriteTo([]byte("ping"), rAddr); err != nil {
return
}
buf := make([]byte, 1024)
n, _, err := pc.ReadFrom(buf)
if err != nil {
return
}
pongCh <- buf[:n]
}()
return test(t)
}
type hashPair struct {
sendHash map[int][]byte
recvHash map[int][]byte
}
2022-07-18 12:32:31 +08:00
func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error)) error {
2022-07-09 00:01:23 +08:00
l, err := listen("tcp", ":"+F.ToString(port))
require.NoError(t, err)
defer l.Close()
times := 100
chunkSize := int64(64 * 1024)
pingCh, pongCh, test := newLargeDataPair()
writeRandData := func(conn net.Conn) (map[int][]byte, error) {
buf := make([]byte, chunkSize)
hashMap := map[int][]byte{}
for i := 0; i < times; i++ {
if _, err := rand.Read(buf[1:]); err != nil {
return nil, err
}
buf[0] = byte(i)
hash := md5.Sum(buf)
hashMap[i] = hash[:]
if _, err := conn.Write(buf); err != nil {
return nil, err
}
}
return hashMap, nil
}
2022-07-18 12:32:31 +08:00
c, err := cc()
2022-07-09 00:01:23 +08:00
if err != nil {
return err
}
2022-09-07 15:41:19 +08:00
defer c.Close()
2022-07-09 00:01:23 +08:00
go func() {
c, err := l.Accept()
if err != nil {
return
}
defer c.Close()
hashMap := map[int][]byte{}
buf := make([]byte, chunkSize)
for i := 0; i < times; i++ {
_, err := io.ReadFull(c, buf)
if err != nil {
t.Log(err.Error())
return
}
hash := md5.Sum(buf)
hashMap[int(buf[0])] = hash[:]
}
sendHash, err := writeRandData(c)
if err != nil {
t.Log(err.Error())
return
}
pingCh <- hashPair{
sendHash: sendHash,
recvHash: hashMap,
}
}()
go func() {
sendHash, err := writeRandData(c)
if err != nil {
t.Log(err.Error())
return
}
hashMap := map[int][]byte{}
buf := make([]byte, chunkSize)
for i := 0; i < times; i++ {
_, err := io.ReadFull(c, buf)
if err != nil {
t.Log(err.Error())
return
}
hash := md5.Sum(buf)
hashMap[int(buf[0])] = hash[:]
}
pongCh <- hashPair{
sendHash: sendHash,
recvHash: hashMap,
}
}()
return test(t)
}
2022-07-18 12:32:31 +08:00
func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
2022-07-09 00:01:23 +08:00
l, err := listenPacket("udp", ":"+F.ToString(port))
2022-07-18 18:50:19 +08:00
if err != nil {
return err
}
2022-07-09 00:01:23 +08:00
defer l.Close()
rAddr := &net.UDPAddr{IP: localIP.AsSlice(), Port: int(port)}
2022-09-13 10:41:10 +08:00
times := 50
2022-07-09 00:01:23 +08:00
chunkSize := int64(1024)
pingCh, pongCh, test := newLargeDataPair()
writeRandData := func(pc net.PacketConn, addr net.Addr) (map[int][]byte, error) {
hashMap := map[int][]byte{}
mux := sync.Mutex{}
for i := 0; i < times; i++ {
2022-09-13 10:41:10 +08:00
go func(idx int) {
buf := make([]byte, chunkSize)
if _, err := rand.Read(buf[1:]); err != nil {
t.Log(err.Error())
return
}
buf[0] = byte(idx)
2022-07-09 00:01:23 +08:00
2022-09-13 10:41:10 +08:00
hash := md5.Sum(buf)
mux.Lock()
hashMap[idx] = hash[:]
mux.Unlock()
if _, err := pc.WriteTo(buf, addr); err != nil {
t.Log(err.Error())
return
}
}(i)
2022-07-09 00:01:23 +08:00
}
return hashMap, nil
}
go func() {
var rAddr net.Addr
hashMap := map[int][]byte{}
buf := make([]byte, 64*1024)
for i := 0; i < times; i++ {
_, rAddr, err = l.ReadFrom(buf)
if err != nil {
t.Log(err.Error())
return
}
hash := md5.Sum(buf[:chunkSize])
hashMap[int(buf[0])] = hash[:]
}
sendHash, err := writeRandData(l, rAddr)
if err != nil {
t.Log(err.Error())
return
}
pingCh <- hashPair{
sendHash: sendHash,
recvHash: hashMap,
}
}()
2022-07-18 12:32:31 +08:00
pc, err := pcc()
2022-07-09 00:01:23 +08:00
if err != nil {
return err
}
2022-09-07 15:41:19 +08:00
defer pc.Close()
2022-07-09 00:01:23 +08:00
go func() {
sendHash, err := writeRandData(pc, rAddr)
if err != nil {
t.Log(err.Error())
return
}
hashMap := map[int][]byte{}
buf := make([]byte, 64*1024)
for i := 0; i < times; i++ {
_, _, err := pc.ReadFrom(buf)
if err != nil {
t.Log(err.Error())
return
}
hash := md5.Sum(buf[:chunkSize])
hashMap[int(buf[0])] = hash[:]
}
pongCh <- hashPair{
sendHash: sendHash,
recvHash: hashMap,
}
}()
return test(t)
}
2022-07-18 12:32:31 +08:00
func testPacketConnTimeout(t *testing.T, pcc func() (net.PacketConn, error)) error {
pc, err := pcc()
2022-07-09 00:01:23 +08:00
if err != nil {
return err
}
err = pc.SetReadDeadline(time.Now().Add(time.Millisecond * 300))
require.NoError(t, err)
errCh := make(chan error, 1)
go func() {
buf := make([]byte, 1024)
_, _, err := pc.ReadFrom(buf)
errCh <- err
}()
select {
case <-errCh:
return nil
case <-time.After(time.Second * 10):
return errors.New("timeout")
}
}
func listen(network, address string) (net.Listener, error) {
2022-07-18 18:50:19 +08:00
var lc net.ListenConfig
lc.Control = control.ReuseAddr()
2022-07-09 00:01:23 +08:00
var lastErr error
for i := 0; i < 5; i++ {
l, err := lc.Listen(context.Background(), network, address)
if err == nil {
return l, nil
}
lastErr = err
2022-07-18 20:40:14 +08:00
time.Sleep(5 * time.Millisecond)
2022-07-09 00:01:23 +08:00
}
return nil, lastErr
}
func listenPacket(network, address string) (net.PacketConn, error) {
2022-07-18 18:50:19 +08:00
var lc net.ListenConfig
lc.Control = control.ReuseAddr()
2022-07-09 00:01:23 +08:00
var lastErr error
for i := 0; i < 5; i++ {
2022-07-18 18:50:19 +08:00
l, err := lc.ListenPacket(context.Background(), network, address)
2022-07-09 00:01:23 +08:00
if err == nil {
return l, nil
}
lastErr = err
2022-07-18 20:40:14 +08:00
time.Sleep(5 * time.Millisecond)
2022-07-09 00:01:23 +08:00
}
return nil, lastErr
}