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