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