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