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