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