github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/infra/conf/v4/v2ray.go (about) 1 package v4 2 3 import ( 4 "encoding/json" 5 "path/filepath" 6 "strings" 7 8 "google.golang.org/protobuf/types/known/anypb" 9 10 core "github.com/v2fly/v2ray-core/v5" 11 "github.com/v2fly/v2ray-core/v5/app/dispatcher" 12 "github.com/v2fly/v2ray-core/v5/app/proxyman" 13 "github.com/v2fly/v2ray-core/v5/app/stats" 14 "github.com/v2fly/v2ray-core/v5/common/serial" 15 "github.com/v2fly/v2ray-core/v5/features" 16 "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon" 17 "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/loader" 18 "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/muxcfg" 19 "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/proxycfg" 20 "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/sniffer" 21 "github.com/v2fly/v2ray-core/v5/infra/conf/synthetic/dns" 22 "github.com/v2fly/v2ray-core/v5/infra/conf/synthetic/log" 23 "github.com/v2fly/v2ray-core/v5/infra/conf/synthetic/router" 24 ) 25 26 var ( 27 inboundConfigLoader = loader.NewJSONConfigLoader(loader.ConfigCreatorCache{ 28 "dokodemo-door": func() interface{} { return new(DokodemoConfig) }, 29 "http": func() interface{} { return new(HTTPServerConfig) }, 30 "shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) }, 31 "socks": func() interface{} { return new(SocksServerConfig) }, 32 "vless": func() interface{} { return new(VLessInboundConfig) }, 33 "vmess": func() interface{} { return new(VMessInboundConfig) }, 34 "trojan": func() interface{} { return new(TrojanServerConfig) }, 35 }, "protocol", "settings") 36 37 outboundConfigLoader = loader.NewJSONConfigLoader(loader.ConfigCreatorCache{ 38 "blackhole": func() interface{} { return new(BlackholeConfig) }, 39 "freedom": func() interface{} { return new(FreedomConfig) }, 40 "http": func() interface{} { return new(HTTPClientConfig) }, 41 "shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) }, 42 "socks": func() interface{} { return new(SocksClientConfig) }, 43 "vless": func() interface{} { return new(VLessOutboundConfig) }, 44 "vmess": func() interface{} { return new(VMessOutboundConfig) }, 45 "trojan": func() interface{} { return new(TrojanClientConfig) }, 46 "dns": func() interface{} { return new(DNSOutboundConfig) }, 47 "loopback": func() interface{} { return new(LoopbackConfig) }, 48 }, "protocol", "settings") 49 ) 50 51 func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) { 52 kp := make([]proxyman.KnownProtocols, 0, 8) 53 for _, p := range s { 54 switch strings.ToLower(p) { 55 case "http": 56 kp = append(kp, proxyman.KnownProtocols_HTTP) 57 case "https", "tls", "ssl": 58 kp = append(kp, proxyman.KnownProtocols_TLS) 59 default: 60 return nil, newError("Unknown protocol: ", p) 61 } 62 } 63 return kp, nil 64 } 65 66 type InboundDetourAllocationConfig struct { 67 Strategy string `json:"strategy"` 68 Concurrency *uint32 `json:"concurrency"` 69 RefreshMin *uint32 `json:"refresh"` 70 } 71 72 // Build implements Buildable. 73 func (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) { 74 config := new(proxyman.AllocationStrategy) 75 switch strings.ToLower(c.Strategy) { 76 case "always": 77 config.Type = proxyman.AllocationStrategy_Always 78 case "random": 79 config.Type = proxyman.AllocationStrategy_Random 80 case "external": 81 config.Type = proxyman.AllocationStrategy_External 82 default: 83 return nil, newError("unknown allocation strategy: ", c.Strategy) 84 } 85 if c.Concurrency != nil { 86 config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{ 87 Value: *c.Concurrency, 88 } 89 } 90 91 if c.RefreshMin != nil { 92 config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{ 93 Value: *c.RefreshMin, 94 } 95 } 96 97 return config, nil 98 } 99 100 type InboundDetourConfig struct { 101 Protocol string `json:"protocol"` 102 PortRange *cfgcommon.PortRange `json:"port"` 103 ListenOn *cfgcommon.Address `json:"listen"` 104 Settings *json.RawMessage `json:"settings"` 105 Tag string `json:"tag"` 106 Allocation *InboundDetourAllocationConfig `json:"allocate"` 107 StreamSetting *StreamConfig `json:"streamSettings"` 108 DomainOverride *cfgcommon.StringList `json:"domainOverride"` 109 SniffingConfig *sniffer.SniffingConfig `json:"sniffing"` 110 } 111 112 // Build implements Buildable. 113 func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) { 114 receiverSettings := &proxyman.ReceiverConfig{} 115 116 if c.ListenOn == nil { 117 // Listen on anyip, must set PortRange 118 if c.PortRange == nil { 119 return nil, newError("Listen on AnyIP but no Port(s) set in InboundDetour.") 120 } 121 receiverSettings.PortRange = c.PortRange.Build() 122 } else { 123 // Listen on specific IP or Unix Domain Socket 124 receiverSettings.Listen = c.ListenOn.Build() 125 listenDS := c.ListenOn.Family().IsDomain() && (filepath.IsAbs(c.ListenOn.Domain()) || c.ListenOn.Domain()[0] == '@') 126 listenIP := c.ListenOn.Family().IsIP() || (c.ListenOn.Family().IsDomain() && c.ListenOn.Domain() == "localhost") 127 switch { 128 case listenIP: 129 // Listen on specific IP, must set PortRange 130 if c.PortRange == nil { 131 return nil, newError("Listen on specific ip without port in InboundDetour.") 132 } 133 // Listen on IP:Port 134 receiverSettings.PortRange = c.PortRange.Build() 135 case listenDS: 136 if c.PortRange != nil { 137 // Listen on Unix Domain Socket, PortRange should be nil 138 receiverSettings.PortRange = nil 139 } 140 default: 141 return nil, newError("unable to listen on domain address: ", c.ListenOn.Domain()) 142 } 143 } 144 145 if c.Allocation != nil { 146 concurrency := -1 147 if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" { 148 concurrency = int(*c.Allocation.Concurrency) 149 } 150 portRange := int(c.PortRange.To - c.PortRange.From + 1) 151 if concurrency >= 0 && concurrency >= portRange { 152 return nil, newError("not enough ports. concurrency = ", concurrency, " ports: ", c.PortRange.From, " - ", c.PortRange.To) 153 } 154 155 as, err := c.Allocation.Build() 156 if err != nil { 157 return nil, err 158 } 159 receiverSettings.AllocationStrategy = as 160 } 161 if c.StreamSetting != nil { 162 ss, err := c.StreamSetting.Build() 163 if err != nil { 164 return nil, err 165 } 166 receiverSettings.StreamSettings = ss 167 } 168 if c.SniffingConfig != nil { 169 s, err := c.SniffingConfig.Build() 170 if err != nil { 171 return nil, newError("failed to build sniffing config").Base(err) 172 } 173 receiverSettings.SniffingSettings = s 174 } 175 if c.DomainOverride != nil { 176 kp, err := toProtocolList(*c.DomainOverride) 177 if err != nil { 178 return nil, newError("failed to parse inbound detour config").Base(err) 179 } 180 receiverSettings.DomainOverride = kp 181 } 182 183 settings := []byte("{}") 184 if c.Settings != nil { 185 settings = ([]byte)(*c.Settings) 186 } 187 rawConfig, err := inboundConfigLoader.LoadWithID(settings, c.Protocol) 188 if err != nil { 189 return nil, newError("failed to load inbound detour config.").Base(err) 190 } 191 if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok { 192 receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect 193 } 194 ts, err := rawConfig.(cfgcommon.Buildable).Build() 195 if err != nil { 196 return nil, err 197 } 198 199 return &core.InboundHandlerConfig{ 200 Tag: c.Tag, 201 ReceiverSettings: serial.ToTypedMessage(receiverSettings), 202 ProxySettings: serial.ToTypedMessage(ts), 203 }, nil 204 } 205 206 type OutboundDetourConfig struct { 207 Protocol string `json:"protocol"` 208 SendThrough *cfgcommon.Address `json:"sendThrough"` 209 Tag string `json:"tag"` 210 Settings *json.RawMessage `json:"settings"` 211 StreamSetting *StreamConfig `json:"streamSettings"` 212 ProxySettings *proxycfg.ProxyConfig `json:"proxySettings"` 213 MuxSettings *muxcfg.MuxConfig `json:"mux"` 214 DomainStrategy string `json:"domainStrategy"` 215 } 216 217 // Build implements Buildable. 218 func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) { 219 senderSettings := &proxyman.SenderConfig{} 220 221 if c.SendThrough != nil { 222 address := c.SendThrough 223 if address.Family().IsDomain() { 224 return nil, newError("unable to send through: " + address.String()) 225 } 226 senderSettings.Via = address.Build() 227 } 228 229 if c.StreamSetting != nil { 230 ss, err := c.StreamSetting.Build() 231 if err != nil { 232 return nil, err 233 } 234 senderSettings.StreamSettings = ss 235 } 236 237 if c.ProxySettings != nil { 238 ps, err := c.ProxySettings.Build() 239 if err != nil { 240 return nil, newError("invalid outbound detour proxy settings.").Base(err) 241 } 242 senderSettings.ProxySettings = ps 243 } 244 245 if c.MuxSettings != nil { 246 senderSettings.MultiplexSettings = c.MuxSettings.Build() 247 } 248 249 senderSettings.DomainStrategy = proxyman.SenderConfig_AS_IS 250 switch strings.ToLower(c.DomainStrategy) { 251 case "useip", "use_ip", "use-ip": 252 senderSettings.DomainStrategy = proxyman.SenderConfig_USE_IP 253 case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4": 254 senderSettings.DomainStrategy = proxyman.SenderConfig_USE_IP4 255 case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6": 256 senderSettings.DomainStrategy = proxyman.SenderConfig_USE_IP6 257 } 258 259 settings := []byte("{}") 260 if c.Settings != nil { 261 settings = ([]byte)(*c.Settings) 262 } 263 rawConfig, err := outboundConfigLoader.LoadWithID(settings, c.Protocol) 264 if err != nil { 265 return nil, newError("failed to parse to outbound detour config.").Base(err) 266 } 267 ts, err := rawConfig.(cfgcommon.Buildable).Build() 268 if err != nil { 269 return nil, err 270 } 271 272 return &core.OutboundHandlerConfig{ 273 SenderSettings: serial.ToTypedMessage(senderSettings), 274 Tag: c.Tag, 275 ProxySettings: serial.ToTypedMessage(ts), 276 }, nil 277 } 278 279 type StatsConfig struct{} 280 281 // Build implements Buildable. 282 func (c *StatsConfig) Build() (*stats.Config, error) { 283 return &stats.Config{}, nil 284 } 285 286 type Config struct { 287 // Port of this Point server. 288 // Deprecated: Port exists for historical compatibility 289 // and should not be used. 290 Port uint16 `json:"port"` 291 292 // Deprecated: InboundConfig exists for historical compatibility 293 // and should not be used. 294 InboundConfig *InboundDetourConfig `json:"inbound"` 295 296 // Deprecated: OutboundConfig exists for historical compatibility 297 // and should not be used. 298 OutboundConfig *OutboundDetourConfig `json:"outbound"` 299 300 // Deprecated: InboundDetours exists for historical compatibility 301 // and should not be used. 302 InboundDetours []InboundDetourConfig `json:"inboundDetour"` 303 304 // Deprecated: OutboundDetours exists for historical compatibility 305 // and should not be used. 306 OutboundDetours []OutboundDetourConfig `json:"outboundDetour"` 307 308 LogConfig *log.LogConfig `json:"log"` 309 RouterConfig *router.RouterConfig `json:"routing"` 310 DNSConfig *dns.DNSConfig `json:"dns"` 311 InboundConfigs []InboundDetourConfig `json:"inbounds"` 312 OutboundConfigs []OutboundDetourConfig `json:"outbounds"` 313 Transport *TransportConfig `json:"transport"` 314 Policy *PolicyConfig `json:"policy"` 315 API *APIConfig `json:"api"` 316 Stats *StatsConfig `json:"stats"` 317 Reverse *ReverseConfig `json:"reverse"` 318 FakeDNS *dns.FakeDNSConfig `json:"fakeDns"` 319 BrowserForwarder *BrowserForwarderConfig `json:"browserForwarder"` 320 Observatory *ObservatoryConfig `json:"observatory"` 321 BurstObservatory *BurstObservatoryConfig `json:"burstObservatory"` 322 MultiObservatory *MultiObservatoryConfig `json:"multiObservatory"` 323 324 Services map[string]*json.RawMessage `json:"services"` 325 } 326 327 func (c *Config) findInboundTag(tag string) int { 328 found := -1 329 for idx, ib := range c.InboundConfigs { 330 if ib.Tag == tag { 331 found = idx 332 break 333 } 334 } 335 return found 336 } 337 338 func (c *Config) findOutboundTag(tag string) int { 339 found := -1 340 for idx, ob := range c.OutboundConfigs { 341 if ob.Tag == tag { 342 found = idx 343 break 344 } 345 } 346 return found 347 } 348 349 func applyTransportConfig(s *StreamConfig, t *TransportConfig) { 350 if s.TCPSettings == nil { 351 s.TCPSettings = t.TCPConfig 352 } 353 if s.KCPSettings == nil { 354 s.KCPSettings = t.KCPConfig 355 } 356 if s.WSSettings == nil { 357 s.WSSettings = t.WSConfig 358 } 359 if s.HTTPSettings == nil { 360 s.HTTPSettings = t.HTTPConfig 361 } 362 if s.DSSettings == nil { 363 s.DSSettings = t.DSConfig 364 } 365 } 366 367 // Build implements Buildable. 368 func (c *Config) Build() (*core.Config, error) { 369 if err := PostProcessConfigureFile(c); err != nil { 370 return nil, err 371 } 372 373 config := &core.Config{ 374 App: []*anypb.Any{ 375 serial.ToTypedMessage(&dispatcher.Config{}), 376 serial.ToTypedMessage(&proxyman.InboundConfig{}), 377 serial.ToTypedMessage(&proxyman.OutboundConfig{}), 378 }, 379 } 380 381 if c.API != nil { 382 apiConf, err := c.API.Build() 383 if err != nil { 384 return nil, err 385 } 386 config.App = append(config.App, serial.ToTypedMessage(apiConf)) 387 } 388 389 if c.Stats != nil { 390 statsConf, err := c.Stats.Build() 391 if err != nil { 392 return nil, err 393 } 394 config.App = append(config.App, serial.ToTypedMessage(statsConf)) 395 } 396 397 var logConfMsg *anypb.Any 398 if c.LogConfig != nil { 399 logConfMsg = serial.ToTypedMessage(c.LogConfig.Build()) 400 } else { 401 logConfMsg = serial.ToTypedMessage(log.DefaultLogConfig()) 402 } 403 // let logger module be the first App to start, 404 // so that other modules could print log during initiating 405 config.App = append([]*anypb.Any{logConfMsg}, config.App...) 406 407 if c.RouterConfig != nil { 408 routerConfig, err := c.RouterConfig.Build() 409 if err != nil { 410 return nil, err 411 } 412 config.App = append(config.App, serial.ToTypedMessage(routerConfig)) 413 } 414 415 if c.FakeDNS != nil { 416 features.PrintDeprecatedFeatureWarning("root fakedns settings") 417 if c.DNSConfig != nil { 418 c.DNSConfig.FakeDNS = c.FakeDNS 419 } else { 420 c.DNSConfig = &dns.DNSConfig{ 421 FakeDNS: c.FakeDNS, 422 } 423 } 424 } 425 426 if c.DNSConfig != nil { 427 dnsApp, err := c.DNSConfig.Build() 428 if err != nil { 429 return nil, newError("failed to parse DNS config").Base(err) 430 } 431 config.App = append(config.App, serial.ToTypedMessage(dnsApp)) 432 } 433 434 if c.Policy != nil { 435 pc, err := c.Policy.Build() 436 if err != nil { 437 return nil, err 438 } 439 config.App = append(config.App, serial.ToTypedMessage(pc)) 440 } 441 442 if c.Reverse != nil { 443 r, err := c.Reverse.Build() 444 if err != nil { 445 return nil, err 446 } 447 config.App = append(config.App, serial.ToTypedMessage(r)) 448 } 449 450 if c.BrowserForwarder != nil { 451 r, err := c.BrowserForwarder.Build() 452 if err != nil { 453 return nil, err 454 } 455 config.App = append(config.App, serial.ToTypedMessage(r)) 456 } 457 458 if c.Observatory != nil { 459 r, err := c.Observatory.Build() 460 if err != nil { 461 return nil, err 462 } 463 config.App = append(config.App, serial.ToTypedMessage(r)) 464 } 465 466 if c.BurstObservatory != nil { 467 r, err := c.BurstObservatory.Build() 468 if err != nil { 469 return nil, err 470 } 471 config.App = append(config.App, serial.ToTypedMessage(r)) 472 } 473 474 if c.MultiObservatory != nil { 475 r, err := c.MultiObservatory.Build() 476 if err != nil { 477 return nil, err 478 } 479 config.App = append(config.App, serial.ToTypedMessage(r)) 480 } 481 482 // Load Additional Services that do not have a json translator 483 484 if msg, err := c.BuildServices(c.Services); err != nil { 485 developererr := newError("Loading a V2Ray Features as a service is intended for developers only. " + 486 "This is used for developers to prototype new features or for an advanced client to use special features in V2Ray," + 487 " instead of allowing end user to enable it without special tool and knowledge.") 488 sb := strings.Builder{} 489 return nil, newError("Cannot load service").Base(developererr).Base(err).Base(newError(sb.String())) 490 } else { // nolint: revive 491 // Using a else here is required to keep msg in scope 492 config.App = append(config.App, msg...) 493 } 494 495 var inbounds []InboundDetourConfig 496 497 if c.InboundConfig != nil { 498 inbounds = append(inbounds, *c.InboundConfig) 499 } 500 501 if len(c.InboundDetours) > 0 { 502 inbounds = append(inbounds, c.InboundDetours...) 503 } 504 505 if len(c.InboundConfigs) > 0 { 506 inbounds = append(inbounds, c.InboundConfigs...) 507 } 508 509 // Backward compatibility. 510 if len(inbounds) > 0 && inbounds[0].PortRange == nil && c.Port > 0 { 511 inbounds[0].PortRange = &cfgcommon.PortRange{ 512 From: uint32(c.Port), 513 To: uint32(c.Port), 514 } 515 } 516 517 for _, rawInboundConfig := range inbounds { 518 if c.Transport != nil { 519 if rawInboundConfig.StreamSetting == nil { 520 rawInboundConfig.StreamSetting = &StreamConfig{} 521 } 522 applyTransportConfig(rawInboundConfig.StreamSetting, c.Transport) 523 } 524 ic, err := rawInboundConfig.Build() 525 if err != nil { 526 return nil, err 527 } 528 config.Inbound = append(config.Inbound, ic) 529 } 530 531 var outbounds []OutboundDetourConfig 532 533 if c.OutboundConfig != nil { 534 outbounds = append(outbounds, *c.OutboundConfig) 535 } 536 537 if len(c.OutboundDetours) > 0 { 538 outbounds = append(outbounds, c.OutboundDetours...) 539 } 540 541 if len(c.OutboundConfigs) > 0 { 542 outbounds = append(outbounds, c.OutboundConfigs...) 543 } 544 545 for _, rawOutboundConfig := range outbounds { 546 if c.Transport != nil { 547 if rawOutboundConfig.StreamSetting == nil { 548 rawOutboundConfig.StreamSetting = &StreamConfig{} 549 } 550 applyTransportConfig(rawOutboundConfig.StreamSetting, c.Transport) 551 } 552 oc, err := rawOutboundConfig.Build() 553 if err != nil { 554 return nil, err 555 } 556 config.Outbound = append(config.Outbound, oc) 557 } 558 559 return config, nil 560 }