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