diff --git a/testing/scenarios/shadowsocks_test.go b/testing/scenarios/shadowsocks_test.go index fb444c5c..7f53a6c1 100644 --- a/testing/scenarios/shadowsocks_test.go +++ b/testing/scenarios/shadowsocks_test.go @@ -2,6 +2,7 @@ package scenarios import ( "crypto/rand" + "fmt" "sync" "testing" "time" @@ -18,6 +19,8 @@ import ( "v2ray.com/core/testing/servers/tcp" "v2ray.com/core/testing/servers/udp" . "v2ray.com/ext/assert" + + ss "github.com/shadowsocks/go-shadowsocks2/core" ) func TestShadowsocksAES256TCP(t *testing.T) { @@ -374,3 +377,316 @@ func TestShadowsocksChacha20TCP(t *testing.T) { CloseAllServers(servers) } + +func TestShadowsocksAES256GCMTCP(t *testing.T) { + assert := With(t) + + tcpServer := tcp.Server{ + MsgProcessor: xor, + } + dest, err := tcpServer.Start() + assert(err, IsNil) + defer tcpServer.Close() + + account := serial.ToTypedMessage(&shadowsocks.Account{ + Password: "shadowsocks-password", + CipherType: shadowsocks.CipherType_AES_256_GCM, + }) + + serverPort := pickPort() + serverConfig := &core.Config{ + App: []*serial.TypedMessage{ + serial.ToTypedMessage(&log.Config{ + ErrorLogLevel: log.LogLevel_Debug, + ErrorLogType: log.LogType_Console, + }), + }, + Inbound: []*proxyman.InboundHandlerConfig{ + { + ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ + PortRange: net.SinglePortRange(serverPort), + Listen: net.NewIPOrDomain(net.LocalHostIP), + }), + ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ + User: &protocol.User{ + Account: account, + Level: 1, + }, + }), + }, + }, + Outbound: []*proxyman.OutboundHandlerConfig{ + { + ProxySettings: serial.ToTypedMessage(&freedom.Config{}), + }, + }, + } + + clientPort := pickPort() + clientConfig := &core.Config{ + App: []*serial.TypedMessage{ + serial.ToTypedMessage(&log.Config{ + ErrorLogLevel: log.LogLevel_Debug, + ErrorLogType: log.LogType_Console, + }), + }, + Inbound: []*proxyman.InboundHandlerConfig{ + { + ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ + PortRange: net.SinglePortRange(clientPort), + Listen: net.NewIPOrDomain(net.LocalHostIP), + }), + ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ + Address: net.NewIPOrDomain(dest.Address), + Port: uint32(dest.Port), + NetworkList: &net.NetworkList{ + Network: []net.Network{net.Network_TCP}, + }, + }), + }, + }, + Outbound: []*proxyman.OutboundHandlerConfig{ + { + ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{ + Server: []*protocol.ServerEndpoint{ + { + Address: net.NewIPOrDomain(net.LocalHostIP), + Port: uint32(serverPort), + User: []*protocol.User{ + { + Account: account, + }, + }, + }, + }, + }), + }, + }, + } + + servers, err := InitializeServerConfigs(serverConfig, clientConfig) + assert(err, IsNil) + + var wg sync.WaitGroup + wg.Add(10) + for i := 0; i < 10; i++ { + go func() { + conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{ + IP: []byte{127, 0, 0, 1}, + Port: int(clientPort), + }) + assert(err, IsNil) + + payload := make([]byte, 10240*1024) + rand.Read(payload) + + nBytes, err := conn.Write([]byte(payload)) + assert(err, IsNil) + assert(nBytes, Equals, len(payload)) + + response := readFrom(conn, time.Second*20, 10240*1024) + assert(response, Equals, xor([]byte(payload))) + assert(conn.Close(), IsNil) + wg.Done() + }() + } + wg.Wait() + + CloseAllServers(servers) +} + +func TestShadowsocksAES128GCMUDP(t *testing.T) { + assert := With(t) + + udpServer := udp.Server{ + MsgProcessor: xor, + } + dest, err := udpServer.Start() + assert(err, IsNil) + defer udpServer.Close() + + account := serial.ToTypedMessage(&shadowsocks.Account{ + Password: "shadowsocks-password", + CipherType: shadowsocks.CipherType_AES_128_GCM, + }) + + serverPort := pickPort() + serverConfig := &core.Config{ + App: []*serial.TypedMessage{ + serial.ToTypedMessage(&log.Config{ + ErrorLogLevel: log.LogLevel_Debug, + ErrorLogType: log.LogType_Console, + }), + }, + Inbound: []*proxyman.InboundHandlerConfig{ + { + ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ + PortRange: net.SinglePortRange(serverPort), + Listen: net.NewIPOrDomain(net.LocalHostIP), + }), + ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ + UdpEnabled: true, + User: &protocol.User{ + Account: account, + Level: 1, + }, + }), + }, + }, + Outbound: []*proxyman.OutboundHandlerConfig{ + { + ProxySettings: serial.ToTypedMessage(&freedom.Config{}), + }, + }, + } + + clientPort := pickPort() + clientConfig := &core.Config{ + App: []*serial.TypedMessage{ + serial.ToTypedMessage(&log.Config{ + ErrorLogLevel: log.LogLevel_Debug, + ErrorLogType: log.LogType_Console, + }), + }, + Inbound: []*proxyman.InboundHandlerConfig{ + { + ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ + PortRange: net.SinglePortRange(clientPort), + Listen: net.NewIPOrDomain(net.LocalHostIP), + }), + ProxySettings: serial.ToTypedMessage(&dokodemo.Config{ + Address: net.NewIPOrDomain(dest.Address), + Port: uint32(dest.Port), + NetworkList: &net.NetworkList{ + Network: []net.Network{net.Network_UDP}, + }, + }), + }, + }, + Outbound: []*proxyman.OutboundHandlerConfig{ + { + ProxySettings: serial.ToTypedMessage(&shadowsocks.ClientConfig{ + Server: []*protocol.ServerEndpoint{ + { + Address: net.NewIPOrDomain(net.LocalHostIP), + Port: uint32(serverPort), + User: []*protocol.User{ + { + Account: account, + }, + }, + }, + }, + }), + }, + }, + } + + servers, err := InitializeServerConfigs(serverConfig, clientConfig) + assert(err, IsNil) + + var wg sync.WaitGroup + wg.Add(10) + for i := 0; i < 10; i++ { + go func() { + conn, err := net.DialUDP("udp", nil, &net.UDPAddr{ + IP: []byte{127, 0, 0, 1}, + Port: int(clientPort), + }) + assert(err, IsNil) + + payload := make([]byte, 1024) + rand.Read(payload) + + nBytes, err := conn.Write([]byte(payload)) + assert(err, IsNil) + assert(nBytes, Equals, len(payload)) + + response := readFrom(conn, time.Second*5, 1024) + assert(response, Equals, xor([]byte(payload))) + assert(conn.Close(), IsNil) + wg.Done() + }() + } + wg.Wait() + + CloseAllServers(servers) +} + +func TestShadowsocksAES256GCMConformance(t *testing.T) { + assert := With(t) + + tcpServer := tcp.Server{ + MsgProcessor: xor, + } + dest, err := tcpServer.Start() + assert(err, IsNil) + defer tcpServer.Close() + + account := serial.ToTypedMessage(&shadowsocks.Account{ + Password: "ss-password", + CipherType: shadowsocks.CipherType_AES_256_GCM, + }) + + serverPort := pickPort() + serverConfig := &core.Config{ + App: []*serial.TypedMessage{ + serial.ToTypedMessage(&log.Config{ + ErrorLogLevel: log.LogLevel_Debug, + ErrorLogType: log.LogType_Console, + }), + }, + Inbound: []*proxyman.InboundHandlerConfig{ + { + ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ + PortRange: net.SinglePortRange(serverPort), + Listen: net.NewIPOrDomain(net.LocalHostIP), + }), + ProxySettings: serial.ToTypedMessage(&shadowsocks.ServerConfig{ + User: &protocol.User{ + Account: account, + Level: 1, + }, + }), + }, + }, + Outbound: []*proxyman.OutboundHandlerConfig{ + { + ProxySettings: serial.ToTypedMessage(&freedom.Config{}), + }, + }, + } + + servers, err := InitializeServerConfigs(serverConfig) + assert(err, IsNil) + + var wg sync.WaitGroup + wg.Add(10) + for i := 0; i < 10; i++ { + go func() { + cipher, err := ss.PickCipher("AES-256-GCM", nil, "ss-password") + assert(err, IsNil) + conn, err := ss.Dial("tcp", fmt.Sprintf(":%d", serverPort), cipher) + assert(err, IsNil) + _, err = conn.Write([]byte{1, 127, 0, 0, 1}) + assert(err, IsNil) + _, err = conn.Write(serial.Uint16ToBytes(dest.Port.Value(), nil)) + assert(err, IsNil) + + payload := make([]byte, 10240*1024) + rand.Read(payload) + + nBytes, err := conn.Write([]byte(payload)) + assert(err, IsNil) + assert(nBytes, Equals, len(payload)) + + response := readFrom(conn, time.Second*30, 10240*1024) + assert(response, Equals, xor([]byte(payload))) + assert(conn.Close(), IsNil) + wg.Done() + }() + } + wg.Wait() + + CloseAllServers(servers) +}