github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/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/xtls/xray-core/app/dispatcher"
    12  	"github.com/xtls/xray-core/app/proxyman"
    13  	"github.com/xtls/xray-core/app/stats"
    14  	"github.com/xtls/xray-core/common/net"
    15  	"github.com/xtls/xray-core/common/serial"
    16  	core "github.com/xtls/xray-core/core"
    17  	"github.com/xtls/xray-core/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  }