github.com/EagleQL/Xray-core@v1.4.3/testing/scenarios/command_test.go (about)

     1  package scenarios
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/google/go-cmp/cmp"
    12  	"github.com/google/go-cmp/cmp/cmpopts"
    13  	"google.golang.org/grpc"
    14  
    15  	"github.com/xtls/xray-core/app/commander"
    16  	"github.com/xtls/xray-core/app/policy"
    17  	"github.com/xtls/xray-core/app/proxyman"
    18  	"github.com/xtls/xray-core/app/proxyman/command"
    19  	"github.com/xtls/xray-core/app/router"
    20  	"github.com/xtls/xray-core/app/stats"
    21  	statscmd "github.com/xtls/xray-core/app/stats/command"
    22  	"github.com/xtls/xray-core/common"
    23  	"github.com/xtls/xray-core/common/net"
    24  	"github.com/xtls/xray-core/common/protocol"
    25  	"github.com/xtls/xray-core/common/serial"
    26  	"github.com/xtls/xray-core/common/uuid"
    27  	core "github.com/xtls/xray-core/core"
    28  	"github.com/xtls/xray-core/proxy/dokodemo"
    29  	"github.com/xtls/xray-core/proxy/freedom"
    30  	"github.com/xtls/xray-core/proxy/vmess"
    31  	"github.com/xtls/xray-core/proxy/vmess/inbound"
    32  	"github.com/xtls/xray-core/proxy/vmess/outbound"
    33  	"github.com/xtls/xray-core/testing/servers/tcp"
    34  )
    35  
    36  func TestCommanderRemoveHandler(t *testing.T) {
    37  	tcpServer := tcp.Server{
    38  		MsgProcessor: xor,
    39  	}
    40  	dest, err := tcpServer.Start()
    41  	common.Must(err)
    42  	defer tcpServer.Close()
    43  
    44  	clientPort := tcp.PickPort()
    45  	cmdPort := tcp.PickPort()
    46  	clientConfig := &core.Config{
    47  		App: []*serial.TypedMessage{
    48  			serial.ToTypedMessage(&commander.Config{
    49  				Tag: "api",
    50  				Service: []*serial.TypedMessage{
    51  					serial.ToTypedMessage(&command.Config{}),
    52  				},
    53  			}),
    54  			serial.ToTypedMessage(&router.Config{
    55  				Rule: []*router.RoutingRule{
    56  					{
    57  						InboundTag: []string{"api"},
    58  						TargetTag: &router.RoutingRule_Tag{
    59  							Tag: "api",
    60  						},
    61  					},
    62  				},
    63  			}),
    64  		},
    65  		Inbound: []*core.InboundHandlerConfig{
    66  			{
    67  				Tag: "d",
    68  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
    69  					PortRange: net.SinglePortRange(clientPort),
    70  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
    71  				}),
    72  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
    73  					Address:  net.NewIPOrDomain(dest.Address),
    74  					Port:     uint32(dest.Port),
    75  					Networks: []net.Network{net.Network_TCP},
    76  				}),
    77  			},
    78  			{
    79  				Tag: "api",
    80  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
    81  					PortRange: net.SinglePortRange(cmdPort),
    82  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
    83  				}),
    84  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
    85  					Address:  net.NewIPOrDomain(dest.Address),
    86  					Port:     uint32(dest.Port),
    87  					Networks: []net.Network{net.Network_TCP},
    88  				}),
    89  			},
    90  		},
    91  		Outbound: []*core.OutboundHandlerConfig{
    92  			{
    93  				Tag:           "default-outbound",
    94  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
    95  			},
    96  		},
    97  	}
    98  
    99  	servers, err := InitializeServerConfigs(clientConfig)
   100  	common.Must(err)
   101  	defer CloseAllServers(servers)
   102  
   103  	if err := testTCPConn(clientPort, 1024, time.Second*5)(); err != nil {
   104  		t.Fatal(err)
   105  	}
   106  
   107  	cmdConn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", cmdPort), grpc.WithInsecure(), grpc.WithBlock())
   108  	common.Must(err)
   109  	defer cmdConn.Close()
   110  
   111  	hsClient := command.NewHandlerServiceClient(cmdConn)
   112  	resp, err := hsClient.RemoveInbound(context.Background(), &command.RemoveInboundRequest{
   113  		Tag: "d",
   114  	})
   115  	common.Must(err)
   116  	if resp == nil {
   117  		t.Error("unexpected nil response")
   118  	}
   119  
   120  	{
   121  		_, err := net.DialTCP("tcp", nil, &net.TCPAddr{
   122  			IP:   []byte{127, 0, 0, 1},
   123  			Port: int(clientPort),
   124  		})
   125  		if err == nil {
   126  			t.Error("unexpected nil error")
   127  		}
   128  	}
   129  }
   130  
   131  func TestCommanderAddRemoveUser(t *testing.T) {
   132  	tcpServer := tcp.Server{
   133  		MsgProcessor: xor,
   134  	}
   135  	dest, err := tcpServer.Start()
   136  	common.Must(err)
   137  	defer tcpServer.Close()
   138  
   139  	u1 := protocol.NewID(uuid.New())
   140  	u2 := protocol.NewID(uuid.New())
   141  
   142  	cmdPort := tcp.PickPort()
   143  	serverPort := tcp.PickPort()
   144  	serverConfig := &core.Config{
   145  		App: []*serial.TypedMessage{
   146  			serial.ToTypedMessage(&commander.Config{
   147  				Tag: "api",
   148  				Service: []*serial.TypedMessage{
   149  					serial.ToTypedMessage(&command.Config{}),
   150  				},
   151  			}),
   152  			serial.ToTypedMessage(&router.Config{
   153  				Rule: []*router.RoutingRule{
   154  					{
   155  						InboundTag: []string{"api"},
   156  						TargetTag: &router.RoutingRule_Tag{
   157  							Tag: "api",
   158  						},
   159  					},
   160  				},
   161  			}),
   162  			serial.ToTypedMessage(&policy.Config{
   163  				Level: map[uint32]*policy.Policy{
   164  					0: {
   165  						Timeout: &policy.Policy_Timeout{
   166  							UplinkOnly:   &policy.Second{Value: 0},
   167  							DownlinkOnly: &policy.Second{Value: 0},
   168  						},
   169  					},
   170  				},
   171  			}),
   172  		},
   173  		Inbound: []*core.InboundHandlerConfig{
   174  			{
   175  				Tag: "v",
   176  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   177  					PortRange: net.SinglePortRange(serverPort),
   178  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   179  				}),
   180  				ProxySettings: serial.ToTypedMessage(&inbound.Config{
   181  					User: []*protocol.User{
   182  						{
   183  							Account: serial.ToTypedMessage(&vmess.Account{
   184  								Id:      u1.String(),
   185  								AlterId: 64,
   186  							}),
   187  						},
   188  					},
   189  				}),
   190  			},
   191  			{
   192  				Tag: "api",
   193  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   194  					PortRange: net.SinglePortRange(cmdPort),
   195  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   196  				}),
   197  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
   198  					Address:  net.NewIPOrDomain(dest.Address),
   199  					Port:     uint32(dest.Port),
   200  					Networks: []net.Network{net.Network_TCP},
   201  				}),
   202  			},
   203  		},
   204  		Outbound: []*core.OutboundHandlerConfig{
   205  			{
   206  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   207  			},
   208  		},
   209  	}
   210  
   211  	clientPort := tcp.PickPort()
   212  	clientConfig := &core.Config{
   213  		App: []*serial.TypedMessage{
   214  			serial.ToTypedMessage(&policy.Config{
   215  				Level: map[uint32]*policy.Policy{
   216  					0: {
   217  						Timeout: &policy.Policy_Timeout{
   218  							UplinkOnly:   &policy.Second{Value: 0},
   219  							DownlinkOnly: &policy.Second{Value: 0},
   220  						},
   221  					},
   222  				},
   223  			}),
   224  		},
   225  		Inbound: []*core.InboundHandlerConfig{
   226  			{
   227  				Tag: "d",
   228  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   229  					PortRange: net.SinglePortRange(clientPort),
   230  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   231  				}),
   232  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
   233  					Address: net.NewIPOrDomain(dest.Address),
   234  					Port:    uint32(dest.Port),
   235  					NetworkList: &net.NetworkList{
   236  						Network: []net.Network{net.Network_TCP},
   237  					},
   238  				}),
   239  			},
   240  		},
   241  		Outbound: []*core.OutboundHandlerConfig{
   242  			{
   243  				ProxySettings: serial.ToTypedMessage(&outbound.Config{
   244  					Receiver: []*protocol.ServerEndpoint{
   245  						{
   246  							Address: net.NewIPOrDomain(net.LocalHostIP),
   247  							Port:    uint32(serverPort),
   248  							User: []*protocol.User{
   249  								{
   250  									Account: serial.ToTypedMessage(&vmess.Account{
   251  										Id:      u2.String(),
   252  										AlterId: 64,
   253  										SecuritySettings: &protocol.SecurityConfig{
   254  											Type: protocol.SecurityType_AES128_GCM,
   255  										},
   256  									}),
   257  								},
   258  							},
   259  						},
   260  					},
   261  				}),
   262  			},
   263  		},
   264  	}
   265  
   266  	servers, err := InitializeServerConfigs(serverConfig, clientConfig)
   267  	common.Must(err)
   268  	defer CloseAllServers(servers)
   269  
   270  	if err := testTCPConn(clientPort, 1024, time.Second*5)(); err != io.EOF &&
   271  		/*We might wish to drain the connection*/
   272  		(err != nil && !strings.HasSuffix(err.Error(), "i/o timeout")) {
   273  		t.Fatal("expected error: ", err)
   274  	}
   275  
   276  	cmdConn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", cmdPort), grpc.WithInsecure(), grpc.WithBlock())
   277  	common.Must(err)
   278  	defer cmdConn.Close()
   279  
   280  	hsClient := command.NewHandlerServiceClient(cmdConn)
   281  	resp, err := hsClient.AlterInbound(context.Background(), &command.AlterInboundRequest{
   282  		Tag: "v",
   283  		Operation: serial.ToTypedMessage(
   284  			&command.AddUserOperation{
   285  				User: &protocol.User{
   286  					Email: "test@example.com",
   287  					Account: serial.ToTypedMessage(&vmess.Account{
   288  						Id:      u2.String(),
   289  						AlterId: 64,
   290  					}),
   291  				},
   292  			}),
   293  	})
   294  	common.Must(err)
   295  	if resp == nil {
   296  		t.Fatal("nil response")
   297  	}
   298  
   299  	if err := testTCPConn(clientPort, 1024, time.Second*5)(); err != nil {
   300  		t.Fatal(err)
   301  	}
   302  
   303  	resp, err = hsClient.AlterInbound(context.Background(), &command.AlterInboundRequest{
   304  		Tag:       "v",
   305  		Operation: serial.ToTypedMessage(&command.RemoveUserOperation{Email: "test@example.com"}),
   306  	})
   307  	common.Must(err)
   308  	if resp == nil {
   309  		t.Fatal("nil response")
   310  	}
   311  }
   312  
   313  func TestCommanderStats(t *testing.T) {
   314  	tcpServer := tcp.Server{
   315  		MsgProcessor: xor,
   316  	}
   317  	dest, err := tcpServer.Start()
   318  	common.Must(err)
   319  	defer tcpServer.Close()
   320  
   321  	userID := protocol.NewID(uuid.New())
   322  	serverPort := tcp.PickPort()
   323  	cmdPort := tcp.PickPort()
   324  
   325  	serverConfig := &core.Config{
   326  		App: []*serial.TypedMessage{
   327  			serial.ToTypedMessage(&stats.Config{}),
   328  			serial.ToTypedMessage(&commander.Config{
   329  				Tag: "api",
   330  				Service: []*serial.TypedMessage{
   331  					serial.ToTypedMessage(&statscmd.Config{}),
   332  				},
   333  			}),
   334  			serial.ToTypedMessage(&router.Config{
   335  				Rule: []*router.RoutingRule{
   336  					{
   337  						InboundTag: []string{"api"},
   338  						TargetTag: &router.RoutingRule_Tag{
   339  							Tag: "api",
   340  						},
   341  					},
   342  				},
   343  			}),
   344  			serial.ToTypedMessage(&policy.Config{
   345  				Level: map[uint32]*policy.Policy{
   346  					0: {
   347  						Timeout: &policy.Policy_Timeout{
   348  							UplinkOnly:   &policy.Second{Value: 0},
   349  							DownlinkOnly: &policy.Second{Value: 0},
   350  						},
   351  					},
   352  					1: {
   353  						Stats: &policy.Policy_Stats{
   354  							UserUplink:   true,
   355  							UserDownlink: true,
   356  						},
   357  					},
   358  				},
   359  				System: &policy.SystemPolicy{
   360  					Stats: &policy.SystemPolicy_Stats{
   361  						InboundUplink: true,
   362  					},
   363  				},
   364  			}),
   365  		},
   366  		Inbound: []*core.InboundHandlerConfig{
   367  			{
   368  				Tag: "vmess",
   369  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   370  					PortRange: net.SinglePortRange(serverPort),
   371  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   372  				}),
   373  				ProxySettings: serial.ToTypedMessage(&inbound.Config{
   374  					User: []*protocol.User{
   375  						{
   376  							Level: 1,
   377  							Email: "test",
   378  							Account: serial.ToTypedMessage(&vmess.Account{
   379  								Id:      userID.String(),
   380  								AlterId: 64,
   381  							}),
   382  						},
   383  					},
   384  				}),
   385  			},
   386  			{
   387  				Tag: "api",
   388  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   389  					PortRange: net.SinglePortRange(cmdPort),
   390  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   391  				}),
   392  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
   393  					Address: net.NewIPOrDomain(dest.Address),
   394  					Port:    uint32(dest.Port),
   395  					NetworkList: &net.NetworkList{
   396  						Network: []net.Network{net.Network_TCP},
   397  					},
   398  				}),
   399  			},
   400  		},
   401  		Outbound: []*core.OutboundHandlerConfig{
   402  			{
   403  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   404  			},
   405  		},
   406  	}
   407  
   408  	clientPort := tcp.PickPort()
   409  	clientConfig := &core.Config{
   410  		Inbound: []*core.InboundHandlerConfig{
   411  			{
   412  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   413  					PortRange: net.SinglePortRange(clientPort),
   414  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   415  				}),
   416  				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
   417  					Address: net.NewIPOrDomain(dest.Address),
   418  					Port:    uint32(dest.Port),
   419  					NetworkList: &net.NetworkList{
   420  						Network: []net.Network{net.Network_TCP},
   421  					},
   422  				}),
   423  			},
   424  		},
   425  		Outbound: []*core.OutboundHandlerConfig{
   426  			{
   427  				ProxySettings: serial.ToTypedMessage(&outbound.Config{
   428  					Receiver: []*protocol.ServerEndpoint{
   429  						{
   430  							Address: net.NewIPOrDomain(net.LocalHostIP),
   431  							Port:    uint32(serverPort),
   432  							User: []*protocol.User{
   433  								{
   434  									Account: serial.ToTypedMessage(&vmess.Account{
   435  										Id:      userID.String(),
   436  										AlterId: 64,
   437  										SecuritySettings: &protocol.SecurityConfig{
   438  											Type: protocol.SecurityType_AES128_GCM,
   439  										},
   440  									}),
   441  								},
   442  							},
   443  						},
   444  					},
   445  				}),
   446  			},
   447  		},
   448  	}
   449  
   450  	servers, err := InitializeServerConfigs(serverConfig, clientConfig)
   451  	if err != nil {
   452  		t.Fatal("Failed to create all servers", err)
   453  	}
   454  	defer CloseAllServers(servers)
   455  
   456  	if err := testTCPConn(clientPort, 10240*1024, time.Second*20)(); err != nil {
   457  		t.Fatal(err)
   458  	}
   459  
   460  	cmdConn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", cmdPort), grpc.WithInsecure(), grpc.WithBlock())
   461  	common.Must(err)
   462  	defer cmdConn.Close()
   463  
   464  	const name = "user>>>test>>>traffic>>>uplink"
   465  	sClient := statscmd.NewStatsServiceClient(cmdConn)
   466  
   467  	sresp, err := sClient.GetStats(context.Background(), &statscmd.GetStatsRequest{
   468  		Name:   name,
   469  		Reset_: true,
   470  	})
   471  	common.Must(err)
   472  	if r := cmp.Diff(sresp.Stat, &statscmd.Stat{
   473  		Name:  name,
   474  		Value: 10240 * 1024,
   475  	}, cmpopts.IgnoreUnexported(statscmd.Stat{})); r != "" {
   476  		t.Error(r)
   477  	}
   478  
   479  	sresp, err = sClient.GetStats(context.Background(), &statscmd.GetStatsRequest{
   480  		Name: name,
   481  	})
   482  	common.Must(err)
   483  	if r := cmp.Diff(sresp.Stat, &statscmd.Stat{
   484  		Name:  name,
   485  		Value: 0,
   486  	}, cmpopts.IgnoreUnexported(statscmd.Stat{})); r != "" {
   487  		t.Error(r)
   488  	}
   489  
   490  	sresp, err = sClient.GetStats(context.Background(), &statscmd.GetStatsRequest{
   491  		Name:   "inbound>>>vmess>>>traffic>>>uplink",
   492  		Reset_: true,
   493  	})
   494  	common.Must(err)
   495  	if sresp.Stat.Value <= 10240*1024 {
   496  		t.Error("value < 10240*1024: ", sresp.Stat.Value)
   497  	}
   498  }