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