diff --git a/testing/scenarios/command_test.go b/testing/scenarios/command_test.go index 27165a36..f27b4923 100644 --- a/testing/scenarios/command_test.go +++ b/testing/scenarios/command_test.go @@ -3,8 +3,11 @@ package scenarios import ( "context" "fmt" + "io" "testing" + "v2ray.com/core/app/policy" + "google.golang.org/grpc" "v2ray.com/core" "v2ray.com/core/app/commander" @@ -12,9 +15,14 @@ import ( "v2ray.com/core/app/proxyman/command" "v2ray.com/core/app/router" "v2ray.com/core/common/net" + "v2ray.com/core/common/protocol" "v2ray.com/core/common/serial" + "v2ray.com/core/common/uuid" "v2ray.com/core/proxy/dokodemo" "v2ray.com/core/proxy/freedom" + "v2ray.com/core/proxy/vmess" + "v2ray.com/core/proxy/vmess/inbound" + "v2ray.com/core/proxy/vmess/outbound" "v2ray.com/core/testing/servers/tcp" . "v2ray.com/ext/assert" ) @@ -128,3 +136,211 @@ func TestCommanderRemoveHandler(t *testing.T) { CloseAllServers(servers) } + +func TestCommanderAddRemoveUser(t *testing.T) { + assert := With(t) + + tcpServer := tcp.Server{ + MsgProcessor: xor, + } + dest, err := tcpServer.Start() + assert(err, IsNil) + defer tcpServer.Close() + + u1 := protocol.NewID(uuid.New()) + u2 := protocol.NewID(uuid.New()) + + cmdPort := pickPort() + serverPort := pickPort() + serverConfig := &core.Config{ + App: []*serial.TypedMessage{ + serial.ToTypedMessage(&commander.Config{ + Tag: "api", + Service: []*serial.TypedMessage{ + serial.ToTypedMessage(&command.Config{}), + }, + }), + serial.ToTypedMessage(&router.Config{ + Rule: []*router.RoutingRule{ + { + InboundTag: []string{"api"}, + Tag: "api", + }, + }, + }), + serial.ToTypedMessage(&policy.Config{ + Level: map[uint32]*policy.Policy{ + 0: &policy.Policy{ + Timeout: &policy.Policy_Timeout{ + UplinkOnly: &policy.Second{Value: 0}, + DownlinkOnly: &policy.Second{Value: 0}, + }, + }, + }, + }), + }, + Inbound: []*core.InboundHandlerConfig{ + { + Tag: "v", + ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ + PortRange: net.SinglePortRange(serverPort), + Listen: net.NewIPOrDomain(net.LocalHostIP), + }), + ProxySettings: serial.ToTypedMessage(&inbound.Config{ + User: []*protocol.User{ + { + Account: serial.ToTypedMessage(&vmess.Account{ + Id: u1.String(), + AlterId: 64, + }), + }, + }, + }), + }, + { + Tag: "api", + ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ + PortRange: net.SinglePortRange(cmdPort), + 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: []*core.OutboundHandlerConfig{ + { + ProxySettings: serial.ToTypedMessage(&freedom.Config{}), + }, + }, + } + + clientPort := pickPort() + clientConfig := &core.Config{ + App: []*serial.TypedMessage{ + serial.ToTypedMessage(&policy.Config{ + Level: map[uint32]*policy.Policy{ + 0: &policy.Policy{ + Timeout: &policy.Policy_Timeout{ + UplinkOnly: &policy.Second{Value: 0}, + DownlinkOnly: &policy.Second{Value: 0}, + }, + }, + }, + }), + }, + Inbound: []*core.InboundHandlerConfig{ + { + Tag: "d", + 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: []*core.OutboundHandlerConfig{ + { + ProxySettings: serial.ToTypedMessage(&outbound.Config{ + Receiver: []*protocol.ServerEndpoint{ + { + Address: net.NewIPOrDomain(net.LocalHostIP), + Port: uint32(serverPort), + User: []*protocol.User{ + { + Account: serial.ToTypedMessage(&vmess.Account{ + Id: u2.String(), + AlterId: 64, + SecuritySettings: &protocol.SecurityConfig{ + Type: protocol.SecurityType_AES128_GCM, + }, + }), + }, + }, + }, + }, + }), + }, + }, + } + + servers, err := InitializeServerConfigs(serverConfig, clientConfig) + assert(err, IsNil) + + { + conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{ + IP: []byte{127, 0, 0, 1}, + Port: int(clientPort), + }) + assert(err, IsNil) + + payload := "commander request." + nBytes, err := conn.Write([]byte(payload)) + assert(err, IsNil) + assert(nBytes, Equals, len(payload)) + + response := make([]byte, 1024) + nBytes, err = conn.Read(response) + assert(nBytes, Equals, 0) + assert(err, Equals, io.EOF) + assert(conn.Close(), IsNil) + } + + cmdConn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", cmdPort), grpc.WithInsecure()) + assert(err, IsNil) + + hsClient := command.NewHandlerServiceClient(cmdConn) + resp, err := hsClient.AlterInbound(context.Background(), &command.AlterInboundRequest{ + Tag: "v", + Operation: serial.ToTypedMessage( + &command.AddUserOperation{ + User: &protocol.User{ + Email: "test@v2ray.com", + Account: serial.ToTypedMessage(&vmess.Account{ + Id: u2.String(), + AlterId: 64, + }), + }, + }), + }) + assert(err, IsNil) + assert(resp, IsNotNil) + + { + conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{ + IP: []byte{127, 0, 0, 1}, + Port: int(clientPort), + }) + assert(err, IsNil) + + payload := "commander request." + nBytes, err := conn.Write([]byte(payload)) + assert(err, IsNil) + assert(nBytes, Equals, len(payload)) + + response := make([]byte, 1024) + nBytes, err = conn.Read(response) + assert(err, IsNil) + assert(response[:nBytes], Equals, xor([]byte(payload))) + assert(conn.Close(), IsNil) + } + + resp, err = hsClient.AlterInbound(context.Background(), &command.AlterInboundRequest{ + Tag: "v", + Operation: serial.ToTypedMessage(&command.RemoveUserOperation{Email: "test@v2ray.com"}), + }) + assert(resp, IsNotNil) + assert(err, IsNil) + + CloseAllServers(servers) +}