github.com/v2fly/v2ray-core/v4@v4.45.2/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 core "github.com/v2fly/v2ray-core/v4" 16 "github.com/v2fly/v2ray-core/v4/app/commander" 17 "github.com/v2fly/v2ray-core/v4/app/policy" 18 "github.com/v2fly/v2ray-core/v4/app/proxyman" 19 "github.com/v2fly/v2ray-core/v4/app/proxyman/command" 20 "github.com/v2fly/v2ray-core/v4/app/router" 21 "github.com/v2fly/v2ray-core/v4/app/stats" 22 statscmd "github.com/v2fly/v2ray-core/v4/app/stats/command" 23 "github.com/v2fly/v2ray-core/v4/common" 24 "github.com/v2fly/v2ray-core/v4/common/net" 25 "github.com/v2fly/v2ray-core/v4/common/protocol" 26 "github.com/v2fly/v2ray-core/v4/common/serial" 27 "github.com/v2fly/v2ray-core/v4/common/uuid" 28 "github.com/v2fly/v2ray-core/v4/proxy/dokodemo" 29 "github.com/v2fly/v2ray-core/v4/proxy/freedom" 30 "github.com/v2fly/v2ray-core/v4/proxy/vmess" 31 "github.com/v2fly/v2ray-core/v4/proxy/vmess/inbound" 32 "github.com/v2fly/v2ray-core/v4/proxy/vmess/outbound" 33 "github.com/v2fly/v2ray-core/v4/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: 0, 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: 0, 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@v2fly.org", 287 Account: serial.ToTypedMessage(&vmess.Account{ 288 Id: u2.String(), 289 AlterId: 0, 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@v2fly.org"}), 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: 0, 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: 0, 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 }