github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/infra/conf/xray_test.go (about) 1 package conf_test 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "testing" 7 8 "github.com/google/go-cmp/cmp" 9 "github.com/xtls/xray-core/app/dispatcher" 10 "github.com/xtls/xray-core/app/log" 11 "github.com/xtls/xray-core/app/proxyman" 12 "github.com/xtls/xray-core/app/router" 13 "github.com/xtls/xray-core/common" 14 clog "github.com/xtls/xray-core/common/log" 15 "github.com/xtls/xray-core/common/net" 16 "github.com/xtls/xray-core/common/protocol" 17 "github.com/xtls/xray-core/common/serial" 18 core "github.com/xtls/xray-core/core" 19 . "github.com/xtls/xray-core/infra/conf" 20 "github.com/xtls/xray-core/proxy/blackhole" 21 dns_proxy "github.com/xtls/xray-core/proxy/dns" 22 "github.com/xtls/xray-core/proxy/freedom" 23 "github.com/xtls/xray-core/proxy/vmess" 24 "github.com/xtls/xray-core/proxy/vmess/inbound" 25 "github.com/xtls/xray-core/transport/internet" 26 "github.com/xtls/xray-core/transport/internet/http" 27 "github.com/xtls/xray-core/transport/internet/tls" 28 "github.com/xtls/xray-core/transport/internet/websocket" 29 "google.golang.org/protobuf/proto" 30 ) 31 32 func TestXrayConfig(t *testing.T) { 33 createParser := func() func(string) (proto.Message, error) { 34 return func(s string) (proto.Message, error) { 35 config := new(Config) 36 if err := json.Unmarshal([]byte(s), config); err != nil { 37 return nil, err 38 } 39 return config.Build() 40 } 41 } 42 43 runMultiTestCase(t, []TestCase{ 44 { 45 Input: `{ 46 "outbound": { 47 "protocol": "freedom", 48 "settings": {} 49 }, 50 "log": { 51 "access": "/var/log/xray/access.log", 52 "loglevel": "error", 53 "error": "/var/log/xray/error.log" 54 }, 55 "inbound": { 56 "streamSettings": { 57 "network": "ws", 58 "wsSettings": { 59 "headers": { 60 "host": "example.domain" 61 }, 62 "path": "" 63 }, 64 "tlsSettings": { 65 "alpn": "h2" 66 }, 67 "security": "tls" 68 }, 69 "protocol": "vmess", 70 "port": 443, 71 "settings": { 72 "clients": [ 73 { 74 "security": "aes-128-gcm", 75 "id": "0cdf8a45-303d-4fed-9780-29aa7f54175e" 76 } 77 ] 78 } 79 }, 80 "inbounds": [{ 81 "streamSettings": { 82 "network": "ws", 83 "wsSettings": { 84 "headers": { 85 "host": "example.domain" 86 }, 87 "path": "" 88 }, 89 "tlsSettings": { 90 "alpn": "h2" 91 }, 92 "security": "tls" 93 }, 94 "protocol": "vmess", 95 "port": "443-500", 96 "allocate": { 97 "strategy": "random", 98 "concurrency": 3 99 }, 100 "settings": { 101 "clients": [ 102 { 103 "security": "aes-128-gcm", 104 "id": "0cdf8a45-303d-4fed-9780-29aa7f54175e" 105 } 106 ] 107 } 108 }], 109 "outboundDetour": [ 110 { 111 "tag": "blocked", 112 "protocol": "blackhole" 113 }, 114 { 115 "protocol": "dns" 116 } 117 ], 118 "routing": { 119 "strategy": "rules", 120 "settings": { 121 "rules": [ 122 { 123 "ip": [ 124 "10.0.0.0/8" 125 ], 126 "type": "field", 127 "outboundTag": "blocked" 128 } 129 ] 130 } 131 }, 132 "transport": { 133 "httpSettings": { 134 "path": "/test" 135 } 136 } 137 }`, 138 Parser: createParser(), 139 Output: &core.Config{ 140 App: []*serial.TypedMessage{ 141 serial.ToTypedMessage(&log.Config{ 142 ErrorLogType: log.LogType_File, 143 ErrorLogPath: "/var/log/xray/error.log", 144 ErrorLogLevel: clog.Severity_Error, 145 AccessLogType: log.LogType_File, 146 AccessLogPath: "/var/log/xray/access.log", 147 }), 148 serial.ToTypedMessage(&dispatcher.Config{}), 149 serial.ToTypedMessage(&proxyman.InboundConfig{}), 150 serial.ToTypedMessage(&proxyman.OutboundConfig{}), 151 serial.ToTypedMessage(&router.Config{ 152 DomainStrategy: router.Config_AsIs, 153 Rule: []*router.RoutingRule{ 154 { 155 Geoip: []*router.GeoIP{ 156 { 157 Cidr: []*router.CIDR{ 158 { 159 Ip: []byte{10, 0, 0, 0}, 160 Prefix: 8, 161 }, 162 }, 163 }, 164 }, 165 TargetTag: &router.RoutingRule_Tag{ 166 Tag: "blocked", 167 }, 168 }, 169 }, 170 }), 171 }, 172 Outbound: []*core.OutboundHandlerConfig{ 173 { 174 SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{ 175 StreamSettings: &internet.StreamConfig{ 176 ProtocolName: "tcp", 177 TransportSettings: []*internet.TransportConfig{ 178 { 179 ProtocolName: "http", 180 Settings: serial.ToTypedMessage(&http.Config{ 181 Path: "/test", 182 }), 183 }, 184 }, 185 }, 186 }), 187 ProxySettings: serial.ToTypedMessage(&freedom.Config{ 188 DomainStrategy: freedom.Config_AS_IS, 189 UserLevel: 0, 190 }), 191 }, 192 { 193 Tag: "blocked", 194 SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{ 195 StreamSettings: &internet.StreamConfig{ 196 ProtocolName: "tcp", 197 TransportSettings: []*internet.TransportConfig{ 198 { 199 ProtocolName: "http", 200 Settings: serial.ToTypedMessage(&http.Config{ 201 Path: "/test", 202 }), 203 }, 204 }, 205 }, 206 }), 207 ProxySettings: serial.ToTypedMessage(&blackhole.Config{}), 208 }, 209 { 210 SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{ 211 StreamSettings: &internet.StreamConfig{ 212 ProtocolName: "tcp", 213 TransportSettings: []*internet.TransportConfig{ 214 { 215 ProtocolName: "http", 216 Settings: serial.ToTypedMessage(&http.Config{ 217 Path: "/test", 218 }), 219 }, 220 }, 221 }, 222 }), 223 ProxySettings: serial.ToTypedMessage(&dns_proxy.Config{ 224 Server: &net.Endpoint{}, 225 Non_IPQuery: "drop", 226 }), 227 }, 228 }, 229 Inbound: []*core.InboundHandlerConfig{ 230 { 231 ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ 232 PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(443)}}, 233 StreamSettings: &internet.StreamConfig{ 234 ProtocolName: "websocket", 235 TransportSettings: []*internet.TransportConfig{ 236 { 237 ProtocolName: "websocket", 238 Settings: serial.ToTypedMessage(&websocket.Config{ 239 Host: "example.domain", 240 Header: map[string]string{ 241 "host": "example.domain", 242 }, 243 }), 244 }, 245 { 246 ProtocolName: "http", 247 Settings: serial.ToTypedMessage(&http.Config{ 248 Path: "/test", 249 }), 250 }, 251 }, 252 SecurityType: "xray.transport.internet.tls.Config", 253 SecuritySettings: []*serial.TypedMessage{ 254 serial.ToTypedMessage(&tls.Config{ 255 NextProtocol: []string{"h2"}, 256 }), 257 }, 258 }, 259 }), 260 ProxySettings: serial.ToTypedMessage(&inbound.Config{ 261 User: []*protocol.User{ 262 { 263 Level: 0, 264 Account: serial.ToTypedMessage(&vmess.Account{ 265 Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e", 266 SecuritySettings: &protocol.SecurityConfig{ 267 Type: protocol.SecurityType_AES128_GCM, 268 }, 269 }), 270 }, 271 }, 272 }), 273 }, 274 { 275 ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ 276 PortList: &net.PortList{Range: []*net.PortRange{{ 277 From: 443, 278 To: 500, 279 }}}, 280 AllocationStrategy: &proxyman.AllocationStrategy{ 281 Type: proxyman.AllocationStrategy_Random, 282 Concurrency: &proxyman.AllocationStrategy_AllocationStrategyConcurrency{ 283 Value: 3, 284 }, 285 }, 286 StreamSettings: &internet.StreamConfig{ 287 ProtocolName: "websocket", 288 TransportSettings: []*internet.TransportConfig{ 289 { 290 ProtocolName: "websocket", 291 Settings: serial.ToTypedMessage(&websocket.Config{ 292 Host: "example.domain", 293 Header: map[string]string{ 294 "host": "example.domain", 295 }, 296 }), 297 }, 298 { 299 ProtocolName: "http", 300 Settings: serial.ToTypedMessage(&http.Config{ 301 Path: "/test", 302 }), 303 }, 304 }, 305 SecurityType: "xray.transport.internet.tls.Config", 306 SecuritySettings: []*serial.TypedMessage{ 307 serial.ToTypedMessage(&tls.Config{ 308 NextProtocol: []string{"h2"}, 309 }), 310 }, 311 }, 312 }), 313 ProxySettings: serial.ToTypedMessage(&inbound.Config{ 314 User: []*protocol.User{ 315 { 316 Level: 0, 317 Account: serial.ToTypedMessage(&vmess.Account{ 318 Id: "0cdf8a45-303d-4fed-9780-29aa7f54175e", 319 SecuritySettings: &protocol.SecurityConfig{ 320 Type: protocol.SecurityType_AES128_GCM, 321 }, 322 }), 323 }, 324 }, 325 }), 326 }, 327 }, 328 }, 329 }, 330 }) 331 } 332 333 func TestMuxConfig_Build(t *testing.T) { 334 tests := []struct { 335 name string 336 fields string 337 want *proxyman.MultiplexingConfig 338 }{ 339 {"default", `{"enabled": true, "concurrency": 16}`, &proxyman.MultiplexingConfig{ 340 Enabled: true, 341 Concurrency: 16, 342 XudpConcurrency: 0, 343 XudpProxyUDP443: "reject", 344 }}, 345 {"empty def", `{}`, &proxyman.MultiplexingConfig{ 346 Enabled: false, 347 Concurrency: 0, 348 XudpConcurrency: 0, 349 XudpProxyUDP443: "reject", 350 }}, 351 {"not enable", `{"enabled": false, "concurrency": 4}`, &proxyman.MultiplexingConfig{ 352 Enabled: false, 353 Concurrency: 4, 354 XudpConcurrency: 0, 355 XudpProxyUDP443: "reject", 356 }}, 357 {"forbidden", `{"enabled": false, "concurrency": -1}`, &proxyman.MultiplexingConfig{ 358 Enabled: false, 359 Concurrency: -1, 360 XudpConcurrency: 0, 361 XudpProxyUDP443: "reject", 362 }}, 363 } 364 for _, tt := range tests { 365 t.Run(tt.name, func(t *testing.T) { 366 m := &MuxConfig{} 367 common.Must(json.Unmarshal([]byte(tt.fields), m)) 368 if got, _ := m.Build(); !reflect.DeepEqual(got, tt.want) { 369 t.Errorf("MuxConfig.Build() = %v, want %v", got, tt.want) 370 } 371 }) 372 } 373 } 374 375 func TestConfig_Override(t *testing.T) { 376 tests := []struct { 377 name string 378 orig *Config 379 over *Config 380 fn string 381 want *Config 382 }{ 383 { 384 "combine/empty", 385 &Config{}, 386 &Config{ 387 LogConfig: &LogConfig{}, 388 RouterConfig: &RouterConfig{}, 389 DNSConfig: &DNSConfig{}, 390 Transport: &TransportConfig{}, 391 Policy: &PolicyConfig{}, 392 API: &APIConfig{}, 393 Stats: &StatsConfig{}, 394 Reverse: &ReverseConfig{}, 395 }, 396 "", 397 &Config{ 398 LogConfig: &LogConfig{}, 399 RouterConfig: &RouterConfig{}, 400 DNSConfig: &DNSConfig{}, 401 Transport: &TransportConfig{}, 402 Policy: &PolicyConfig{}, 403 API: &APIConfig{}, 404 Stats: &StatsConfig{}, 405 Reverse: &ReverseConfig{}, 406 }, 407 }, 408 { 409 "combine/newattr", 410 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "old"}}}, 411 &Config{LogConfig: &LogConfig{}}, "", 412 &Config{LogConfig: &LogConfig{}, InboundConfigs: []InboundDetourConfig{{Tag: "old"}}}, 413 }, 414 { 415 "replace/inbounds", 416 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}}, 417 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}}}, 418 "", 419 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos0"}, {Tag: "pos1", Protocol: "kcp"}}}, 420 }, 421 { 422 "replace/inbounds-replaceall", 423 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}}, 424 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}, {Tag: "pos2", Protocol: "kcp"}}}, 425 "", 426 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos0"}, {Tag: "pos1", Protocol: "kcp"}, {Tag: "pos2", Protocol: "kcp"}}}, 427 }, 428 { 429 "replace/notag-append", 430 &Config{InboundConfigs: []InboundDetourConfig{{}, {Protocol: "vmess"}}}, 431 &Config{InboundConfigs: []InboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}}}, 432 "", 433 &Config{InboundConfigs: []InboundDetourConfig{{}, {Protocol: "vmess"}, {Tag: "pos1", Protocol: "kcp"}}}, 434 }, 435 { 436 "replace/outbounds", 437 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}}, 438 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}}}, 439 "", 440 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Tag: "pos1", Protocol: "kcp"}}}, 441 }, 442 { 443 "replace/outbounds-prepend", 444 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}, {Tag: "pos3"}}}, 445 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos1", Protocol: "kcp"}, {Tag: "pos2", Protocol: "kcp"}, {Tag: "pos4", Protocol: "kcp"}}}, 446 "config.json", 447 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos2", Protocol: "kcp"}, {Tag: "pos4", Protocol: "kcp"}, {Tag: "pos0"}, {Tag: "pos1", Protocol: "kcp"}, {Tag: "pos3"}}}, 448 }, 449 { 450 "replace/outbounds-append", 451 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}}}, 452 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos2", Protocol: "kcp"}}}, 453 "config_tail.json", 454 &Config{OutboundConfigs: []OutboundDetourConfig{{Tag: "pos0"}, {Protocol: "vmess", Tag: "pos1"}, {Tag: "pos2", Protocol: "kcp"}}}, 455 }, 456 } 457 for _, tt := range tests { 458 t.Run(tt.name, func(t *testing.T) { 459 tt.orig.Override(tt.over, tt.fn) 460 if r := cmp.Diff(tt.orig, tt.want); r != "" { 461 t.Error(r) 462 } 463 }) 464 } 465 }