2022-07-08 16:01:23 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base64"
|
|
|
|
"net/netip"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
C "github.com/sagernet/sing-box/constant"
|
|
|
|
"github.com/sagernet/sing-box/option"
|
2022-08-11 02:36:28 +00:00
|
|
|
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
2022-07-08 16:01:23 +00:00
|
|
|
F "github.com/sagernet/sing/common/format"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2022-07-20 01:41:44 +00:00
|
|
|
const (
|
|
|
|
serverPort uint16 = 10000 + iota
|
|
|
|
clientPort
|
|
|
|
testPort
|
2022-08-23 05:22:03 +00:00
|
|
|
otherPort
|
2023-03-05 06:56:09 +00:00
|
|
|
otherClientPort
|
2022-07-20 01:41:44 +00:00
|
|
|
)
|
|
|
|
|
2022-07-08 16:01:23 +00:00
|
|
|
func TestShadowsocks(t *testing.T) {
|
2022-07-15 03:18:14 +00:00
|
|
|
for _, method := range []string{
|
|
|
|
"aes-128-gcm",
|
|
|
|
"aes-256-gcm",
|
|
|
|
"chacha20-ietf-poly1305",
|
|
|
|
} {
|
|
|
|
t.Run(method+"-inbound", func(t *testing.T) {
|
|
|
|
testShadowsocksInboundWithShadowsocksRust(t, method, mkBase64(t, 16))
|
|
|
|
})
|
|
|
|
t.Run(method+"-outbound", func(t *testing.T) {
|
|
|
|
testShadowsocksOutboundWithShadowsocksRust(t, method, mkBase64(t, 16))
|
|
|
|
})
|
|
|
|
t.Run(method+"-self", func(t *testing.T) {
|
|
|
|
testShadowsocksSelf(t, method, mkBase64(t, 16))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-05 05:06:05 +00:00
|
|
|
func TestShadowsocksNone(t *testing.T) {
|
|
|
|
testShadowsocksSelf(t, "none", "")
|
|
|
|
}
|
|
|
|
|
2022-07-15 03:18:14 +00:00
|
|
|
func TestShadowsocks2022(t *testing.T) {
|
2022-07-08 16:01:23 +00:00
|
|
|
for _, method16 := range []string{
|
|
|
|
"2022-blake3-aes-128-gcm",
|
|
|
|
} {
|
|
|
|
t.Run(method16+"-inbound", func(t *testing.T) {
|
|
|
|
testShadowsocksInboundWithShadowsocksRust(t, method16, mkBase64(t, 16))
|
|
|
|
})
|
|
|
|
t.Run(method16+"-outbound", func(t *testing.T) {
|
|
|
|
testShadowsocksOutboundWithShadowsocksRust(t, method16, mkBase64(t, 16))
|
|
|
|
})
|
|
|
|
t.Run(method16+"-self", func(t *testing.T) {
|
|
|
|
testShadowsocksSelf(t, method16, mkBase64(t, 16))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, method32 := range []string{
|
|
|
|
"2022-blake3-aes-256-gcm",
|
|
|
|
"2022-blake3-chacha20-poly1305",
|
|
|
|
} {
|
|
|
|
t.Run(method32+"-inbound", func(t *testing.T) {
|
|
|
|
testShadowsocksInboundWithShadowsocksRust(t, method32, mkBase64(t, 32))
|
|
|
|
})
|
|
|
|
t.Run(method32+"-outbound", func(t *testing.T) {
|
|
|
|
testShadowsocksOutboundWithShadowsocksRust(t, method32, mkBase64(t, 32))
|
|
|
|
})
|
|
|
|
t.Run(method32+"-self", func(t *testing.T) {
|
|
|
|
testShadowsocksSelf(t, method32, mkBase64(t, 32))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-19 04:17:06 +00:00
|
|
|
func TestShadowsocks2022EIH(t *testing.T) {
|
|
|
|
for _, method16 := range []string{
|
|
|
|
"2022-blake3-aes-128-gcm",
|
|
|
|
} {
|
|
|
|
t.Run(method16, func(t *testing.T) {
|
|
|
|
testShadowsocks2022EIH(t, method16, mkBase64(t, 16))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, method32 := range []string{
|
|
|
|
"2022-blake3-aes-256-gcm",
|
|
|
|
} {
|
|
|
|
t.Run(method32, func(t *testing.T) {
|
|
|
|
testShadowsocks2022EIH(t, method32, mkBase64(t, 32))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-08 16:01:23 +00:00
|
|
|
func testShadowsocksInboundWithShadowsocksRust(t *testing.T, method string, password string) {
|
|
|
|
startDockerContainer(t, DockerOptions{
|
|
|
|
Image: ImageShadowsocksRustClient,
|
|
|
|
EntryPoint: "sslocal",
|
|
|
|
Ports: []uint16{serverPort, clientPort},
|
|
|
|
Cmd: []string{"-s", F.ToString("127.0.0.1:", serverPort), "-b", F.ToString("0.0.0.0:", clientPort), "-m", method, "-k", password, "-U"},
|
|
|
|
})
|
|
|
|
startInstance(t, option.Options{
|
|
|
|
Inbounds: []option.Inbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
ShadowsocksOptions: option.ShadowsocksInboundOptions{
|
|
|
|
ListenOptions: option.ListenOptions{
|
2023-03-19 12:46:22 +00:00
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
2022-07-08 16:01:23 +00:00
|
|
|
ListenPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
testSuit(t, clientPort, testPort)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testShadowsocksOutboundWithShadowsocksRust(t *testing.T, method string, password string) {
|
|
|
|
startDockerContainer(t, DockerOptions{
|
|
|
|
Image: ImageShadowsocksRustServer,
|
|
|
|
EntryPoint: "ssserver",
|
|
|
|
Ports: []uint16{serverPort, testPort},
|
|
|
|
Cmd: []string{"-s", F.ToString("0.0.0.0:", serverPort), "-m", method, "-k", password, "-U"},
|
|
|
|
})
|
|
|
|
startInstance(t, option.Options{
|
|
|
|
Inbounds: []option.Inbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeMixed,
|
2022-07-14 06:04:57 +00:00
|
|
|
MixedOptions: option.HTTPMixedInboundOptions{
|
2022-07-08 16:01:23 +00:00
|
|
|
ListenOptions: option.ListenOptions{
|
2023-03-19 12:46:22 +00:00
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
2022-07-08 16:01:23 +00:00
|
|
|
ListenPort: clientPort,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Outbounds: []option.Outbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
|
|
|
ServerOptions: option.ServerOptions{
|
|
|
|
Server: "127.0.0.1",
|
|
|
|
ServerPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
testSuit(t, clientPort, testPort)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testShadowsocksSelf(t *testing.T, method string, password string) {
|
|
|
|
startInstance(t, option.Options{
|
|
|
|
Inbounds: []option.Inbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeMixed,
|
|
|
|
Tag: "mixed-in",
|
2022-07-14 06:04:57 +00:00
|
|
|
MixedOptions: option.HTTPMixedInboundOptions{
|
2022-07-08 16:01:23 +00:00
|
|
|
ListenOptions: option.ListenOptions{
|
2023-03-19 12:46:22 +00:00
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
2022-07-08 16:01:23 +00:00
|
|
|
ListenPort: clientPort,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
ShadowsocksOptions: option.ShadowsocksInboundOptions{
|
|
|
|
ListenOptions: option.ListenOptions{
|
2023-03-19 12:46:22 +00:00
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
2022-07-08 16:01:23 +00:00
|
|
|
ListenPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Outbounds: []option.Outbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeDirect,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
Tag: "ss-out",
|
|
|
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
|
|
|
ServerOptions: option.ServerOptions{
|
|
|
|
Server: "127.0.0.1",
|
|
|
|
ServerPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Route: &option.RouteOptions{
|
|
|
|
Rules: []option.Rule{
|
|
|
|
{
|
|
|
|
DefaultOptions: option.DefaultRule{
|
|
|
|
Inbound: []string{"mixed-in"},
|
|
|
|
Outbound: "ss-out",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
testSuit(t, clientPort, testPort)
|
|
|
|
}
|
|
|
|
|
2022-08-11 02:36:28 +00:00
|
|
|
func TestShadowsocksUoT(t *testing.T) {
|
|
|
|
method := shadowaead_2022.List[0]
|
|
|
|
password := mkBase64(t, 16)
|
|
|
|
startInstance(t, option.Options{
|
|
|
|
Inbounds: []option.Inbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeMixed,
|
|
|
|
Tag: "mixed-in",
|
|
|
|
MixedOptions: option.HTTPMixedInboundOptions{
|
|
|
|
ListenOptions: option.ListenOptions{
|
2023-03-19 12:46:22 +00:00
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
2022-08-11 02:36:28 +00:00
|
|
|
ListenPort: clientPort,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
ShadowsocksOptions: option.ShadowsocksInboundOptions{
|
|
|
|
ListenOptions: option.ListenOptions{
|
2023-03-19 12:46:22 +00:00
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
2022-08-11 02:36:28 +00:00
|
|
|
ListenPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Outbounds: []option.Outbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeDirect,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
Tag: "ss-out",
|
|
|
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
|
|
|
ServerOptions: option.ServerOptions{
|
|
|
|
Server: "127.0.0.1",
|
|
|
|
ServerPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password,
|
2023-11-08 04:09:22 +00:00
|
|
|
UDPOverTCP: &option.UDPOverTCPOptions{
|
2023-03-18 09:02:55 +00:00
|
|
|
Enabled: true,
|
|
|
|
},
|
2022-08-11 02:36:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Route: &option.RouteOptions{
|
|
|
|
Rules: []option.Rule{
|
|
|
|
{
|
|
|
|
DefaultOptions: option.DefaultRule{
|
|
|
|
Inbound: []string{"mixed-in"},
|
|
|
|
Outbound: "ss-out",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
testSuit(t, clientPort, testPort)
|
|
|
|
}
|
|
|
|
|
2023-11-19 04:17:06 +00:00
|
|
|
func testShadowsocks2022EIH(t *testing.T, method string, password string) {
|
|
|
|
startInstance(t, option.Options{
|
|
|
|
Inbounds: []option.Inbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeMixed,
|
|
|
|
Tag: "mixed-in",
|
|
|
|
MixedOptions: option.HTTPMixedInboundOptions{
|
|
|
|
ListenOptions: option.ListenOptions{
|
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
|
|
|
ListenPort: clientPort,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
ShadowsocksOptions: option.ShadowsocksInboundOptions{
|
|
|
|
ListenOptions: option.ListenOptions{
|
|
|
|
Listen: option.NewListenAddress(netip.IPv4Unspecified()),
|
|
|
|
ListenPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password,
|
|
|
|
Users: []option.ShadowsocksUser{
|
|
|
|
{
|
|
|
|
Password: password,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Outbounds: []option.Outbound{
|
|
|
|
{
|
|
|
|
Type: C.TypeDirect,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: C.TypeShadowsocks,
|
|
|
|
Tag: "ss-out",
|
|
|
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
|
|
|
ServerOptions: option.ServerOptions{
|
|
|
|
Server: "127.0.0.1",
|
|
|
|
ServerPort: serverPort,
|
|
|
|
},
|
|
|
|
Method: method,
|
|
|
|
Password: password + ":" + password,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Route: &option.RouteOptions{
|
|
|
|
Rules: []option.Rule{
|
|
|
|
{
|
|
|
|
DefaultOptions: option.DefaultRule{
|
|
|
|
Inbound: []string{"mixed-in"},
|
|
|
|
Outbound: "ss-out",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
testSuit(t, clientPort, testPort)
|
|
|
|
}
|
|
|
|
|
2022-07-08 16:01:23 +00:00
|
|
|
func mkBase64(t *testing.T, length int) string {
|
|
|
|
psk := make([]byte, length)
|
|
|
|
_, err := rand.Read(psk)
|
|
|
|
require.NoError(t, err)
|
|
|
|
return base64.StdEncoding.EncodeToString(psk)
|
|
|
|
}
|