mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-12-23 14:09:49 +00:00
b413066012
* Fix UDP destination override * Fix code style * Fix fakedns object init Do type convertion at runtime in case if user don't use fakedns in config. Since dispatcher now depend on fakedns object, move the injection order of fakedns to top (As a temporary solution) * Amend logic for handing fakedns client A map is used by server side when client turn on fakedns Client will send domain address in the buffer.UDP.Address, server record all possible target IP addrs. When target replies, server will restore the domain and send back to client. Co-authored-by: hmol233 <82594500+hmol233@users.noreply.github.com>
712 lines
20 KiB
Go
712 lines
20 KiB
Go
package conf
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/xtls/xray-core/app/dispatcher"
|
|
"github.com/xtls/xray-core/app/proxyman"
|
|
"github.com/xtls/xray-core/app/stats"
|
|
"github.com/xtls/xray-core/common/serial"
|
|
core "github.com/xtls/xray-core/core"
|
|
"github.com/xtls/xray-core/transport/internet"
|
|
"github.com/xtls/xray-core/transport/internet/xtls"
|
|
)
|
|
|
|
var (
|
|
inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
|
"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
|
|
"http": func() interface{} { return new(HTTPServerConfig) },
|
|
"shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) },
|
|
"socks": func() interface{} { return new(SocksServerConfig) },
|
|
"vless": func() interface{} { return new(VLessInboundConfig) },
|
|
"vmess": func() interface{} { return new(VMessInboundConfig) },
|
|
"trojan": func() interface{} { return new(TrojanServerConfig) },
|
|
"mtproto": func() interface{} { return new(MTProtoServerConfig) },
|
|
}, "protocol", "settings")
|
|
|
|
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
|
|
"blackhole": func() interface{} { return new(BlackholeConfig) },
|
|
"loopback": func() interface{} { return new(LoopbackConfig) },
|
|
"freedom": func() interface{} { return new(FreedomConfig) },
|
|
"http": func() interface{} { return new(HTTPClientConfig) },
|
|
"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
|
|
"socks": func() interface{} { return new(SocksClientConfig) },
|
|
"vless": func() interface{} { return new(VLessOutboundConfig) },
|
|
"vmess": func() interface{} { return new(VMessOutboundConfig) },
|
|
"trojan": func() interface{} { return new(TrojanClientConfig) },
|
|
"mtproto": func() interface{} { return new(MTProtoClientConfig) },
|
|
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
|
}, "protocol", "settings")
|
|
|
|
ctllog = log.New(os.Stderr, "xctl> ", 0)
|
|
)
|
|
|
|
func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {
|
|
kp := make([]proxyman.KnownProtocols, 0, 8)
|
|
for _, p := range s {
|
|
switch strings.ToLower(p) {
|
|
case "http":
|
|
kp = append(kp, proxyman.KnownProtocols_HTTP)
|
|
case "https", "tls", "ssl":
|
|
kp = append(kp, proxyman.KnownProtocols_TLS)
|
|
default:
|
|
return nil, newError("Unknown protocol: ", p)
|
|
}
|
|
}
|
|
return kp, nil
|
|
}
|
|
|
|
type SniffingConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
DestOverride *StringList `json:"destOverride"`
|
|
DomainsExcluded *StringList `json:"domainsExcluded"`
|
|
MetadataOnly bool `json:"metadataOnly"`
|
|
RouteOnly bool `json:"routeOnly"`
|
|
}
|
|
|
|
// Build implements Buildable.
|
|
func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
|
var p []string
|
|
if c.DestOverride != nil {
|
|
for _, protocol := range *c.DestOverride {
|
|
switch strings.ToLower(protocol) {
|
|
case "http":
|
|
p = append(p, "http")
|
|
case "tls", "https", "ssl":
|
|
p = append(p, "tls")
|
|
case "fakedns":
|
|
p = append(p, "fakedns")
|
|
case "fakedns+others":
|
|
p = append(p, "fakedns+others")
|
|
default:
|
|
return nil, newError("unknown protocol: ", protocol)
|
|
}
|
|
}
|
|
}
|
|
|
|
var d []string
|
|
if c.DomainsExcluded != nil {
|
|
for _, domain := range *c.DomainsExcluded {
|
|
d = append(d, strings.ToLower(domain))
|
|
}
|
|
}
|
|
|
|
return &proxyman.SniffingConfig{
|
|
Enabled: c.Enabled,
|
|
DestinationOverride: p,
|
|
DomainsExcluded: d,
|
|
MetadataOnly: c.MetadataOnly,
|
|
RouteOnly: c.RouteOnly,
|
|
}, nil
|
|
}
|
|
|
|
type MuxConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
Concurrency int16 `json:"concurrency"`
|
|
}
|
|
|
|
// Build creates MultiplexingConfig, Concurrency < 0 completely disables mux.
|
|
func (m *MuxConfig) Build() *proxyman.MultiplexingConfig {
|
|
if m.Concurrency < 0 {
|
|
return nil
|
|
}
|
|
|
|
var con uint32 = 8
|
|
if m.Concurrency > 0 {
|
|
con = uint32(m.Concurrency)
|
|
}
|
|
|
|
return &proxyman.MultiplexingConfig{
|
|
Enabled: m.Enabled,
|
|
Concurrency: con,
|
|
}
|
|
}
|
|
|
|
type InboundDetourAllocationConfig struct {
|
|
Strategy string `json:"strategy"`
|
|
Concurrency *uint32 `json:"concurrency"`
|
|
RefreshMin *uint32 `json:"refresh"`
|
|
}
|
|
|
|
// Build implements Buildable.
|
|
func (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {
|
|
config := new(proxyman.AllocationStrategy)
|
|
switch strings.ToLower(c.Strategy) {
|
|
case "always":
|
|
config.Type = proxyman.AllocationStrategy_Always
|
|
case "random":
|
|
config.Type = proxyman.AllocationStrategy_Random
|
|
case "external":
|
|
config.Type = proxyman.AllocationStrategy_External
|
|
default:
|
|
return nil, newError("unknown allocation strategy: ", c.Strategy)
|
|
}
|
|
if c.Concurrency != nil {
|
|
config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
|
|
Value: *c.Concurrency,
|
|
}
|
|
}
|
|
|
|
if c.RefreshMin != nil {
|
|
config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{
|
|
Value: *c.RefreshMin,
|
|
}
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
type InboundDetourConfig struct {
|
|
Protocol string `json:"protocol"`
|
|
PortList *PortList `json:"port"`
|
|
ListenOn *Address `json:"listen"`
|
|
Settings *json.RawMessage `json:"settings"`
|
|
Tag string `json:"tag"`
|
|
Allocation *InboundDetourAllocationConfig `json:"allocate"`
|
|
StreamSetting *StreamConfig `json:"streamSettings"`
|
|
DomainOverride *StringList `json:"domainOverride"`
|
|
SniffingConfig *SniffingConfig `json:"sniffing"`
|
|
}
|
|
|
|
// Build implements Buildable.
|
|
func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
|
|
receiverSettings := &proxyman.ReceiverConfig{}
|
|
|
|
if c.ListenOn == nil {
|
|
// Listen on anyip, must set PortList
|
|
if c.PortList == nil {
|
|
return nil, newError("Listen on AnyIP but no Port(s) set in InboundDetour.")
|
|
}
|
|
receiverSettings.PortList = c.PortList.Build()
|
|
} else {
|
|
// Listen on specific IP or Unix Domain Socket
|
|
receiverSettings.Listen = c.ListenOn.Build()
|
|
listenDS := c.ListenOn.Family().IsDomain() && (c.ListenOn.Domain()[0] == '/' || c.ListenOn.Domain()[0] == '@')
|
|
listenIP := c.ListenOn.Family().IsIP() || (c.ListenOn.Family().IsDomain() && c.ListenOn.Domain() == "localhost")
|
|
if listenIP {
|
|
// Listen on specific IP, must set PortList
|
|
if c.PortList == nil {
|
|
return nil, newError("Listen on specific ip without port in InboundDetour.")
|
|
}
|
|
// Listen on IP:Port
|
|
receiverSettings.PortList = c.PortList.Build()
|
|
} else if listenDS {
|
|
if c.PortList != nil {
|
|
// Listen on Unix Domain Socket, PortList should be nil
|
|
receiverSettings.PortList = nil
|
|
}
|
|
} else {
|
|
return nil, newError("unable to listen on domain address: ", c.ListenOn.Domain())
|
|
}
|
|
}
|
|
|
|
if c.Allocation != nil {
|
|
concurrency := -1
|
|
if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" {
|
|
concurrency = int(*c.Allocation.Concurrency)
|
|
}
|
|
portRange := 0
|
|
|
|
for _, pr := range c.PortList.Range {
|
|
portRange += int(pr.To - pr.From + 1)
|
|
}
|
|
if concurrency >= 0 && concurrency >= portRange {
|
|
var ports strings.Builder
|
|
for _, pr := range c.PortList.Range {
|
|
fmt.Fprintf(&ports, "%d-%d ", pr.From, pr.To)
|
|
}
|
|
return nil, newError("not enough ports. concurrency = ", concurrency, " ports: ", ports.String())
|
|
}
|
|
|
|
as, err := c.Allocation.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
receiverSettings.AllocationStrategy = as
|
|
}
|
|
if c.StreamSetting != nil {
|
|
ss, err := c.StreamSetting.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
|
|
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
|
|
}
|
|
receiverSettings.StreamSettings = ss
|
|
}
|
|
if c.SniffingConfig != nil {
|
|
s, err := c.SniffingConfig.Build()
|
|
if err != nil {
|
|
return nil, newError("failed to build sniffing config").Base(err)
|
|
}
|
|
receiverSettings.SniffingSettings = s
|
|
}
|
|
if c.DomainOverride != nil {
|
|
kp, err := toProtocolList(*c.DomainOverride)
|
|
if err != nil {
|
|
return nil, newError("failed to parse inbound detour config").Base(err)
|
|
}
|
|
receiverSettings.DomainOverride = kp
|
|
}
|
|
|
|
settings := []byte("{}")
|
|
if c.Settings != nil {
|
|
settings = ([]byte)(*c.Settings)
|
|
}
|
|
rawConfig, err := inboundConfigLoader.LoadWithID(settings, c.Protocol)
|
|
if err != nil {
|
|
return nil, newError("failed to load inbound detour config.").Base(err)
|
|
}
|
|
if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
|
|
receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect
|
|
}
|
|
ts, err := rawConfig.(Buildable).Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &core.InboundHandlerConfig{
|
|
Tag: c.Tag,
|
|
ReceiverSettings: serial.ToTypedMessage(receiverSettings),
|
|
ProxySettings: serial.ToTypedMessage(ts),
|
|
}, nil
|
|
}
|
|
|
|
type OutboundDetourConfig struct {
|
|
Protocol string `json:"protocol"`
|
|
SendThrough *Address `json:"sendThrough"`
|
|
Tag string `json:"tag"`
|
|
Settings *json.RawMessage `json:"settings"`
|
|
StreamSetting *StreamConfig `json:"streamSettings"`
|
|
ProxySettings *ProxyConfig `json:"proxySettings"`
|
|
MuxSettings *MuxConfig `json:"mux"`
|
|
}
|
|
|
|
func (c *OutboundDetourConfig) checkChainProxyConfig() error {
|
|
if c.StreamSetting == nil || c.ProxySettings == nil || c.StreamSetting.SocketSettings == nil {
|
|
return nil
|
|
}
|
|
if len(c.ProxySettings.Tag) > 0 && len(c.StreamSetting.SocketSettings.DialerProxy) > 0 {
|
|
return newError("proxySettings.tag is conflicted with sockopt.dialerProxy").AtWarning()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Build implements Buildable.
|
|
func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
|
senderSettings := &proxyman.SenderConfig{}
|
|
if err := c.checkChainProxyConfig(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if c.SendThrough != nil {
|
|
address := c.SendThrough
|
|
if address.Family().IsDomain() {
|
|
return nil, newError("unable to send through: " + address.String())
|
|
}
|
|
senderSettings.Via = address.Build()
|
|
}
|
|
|
|
if c.StreamSetting != nil {
|
|
ss, err := c.StreamSetting.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) && !strings.EqualFold(c.Protocol, "vless") && !strings.EqualFold(c.Protocol, "trojan") {
|
|
return nil, newError("XTLS doesn't supports " + c.Protocol + " for now.")
|
|
}
|
|
senderSettings.StreamSettings = ss
|
|
}
|
|
|
|
if c.ProxySettings != nil {
|
|
ps, err := c.ProxySettings.Build()
|
|
if err != nil {
|
|
return nil, newError("invalid outbound detour proxy settings.").Base(err)
|
|
}
|
|
if ps.TransportLayerProxy {
|
|
if senderSettings.StreamSettings != nil {
|
|
if senderSettings.StreamSettings.SocketSettings != nil {
|
|
senderSettings.StreamSettings.SocketSettings.DialerProxy = ps.Tag
|
|
} else {
|
|
senderSettings.StreamSettings.SocketSettings = &internet.SocketConfig{DialerProxy: ps.Tag}
|
|
}
|
|
} else {
|
|
senderSettings.StreamSettings = &internet.StreamConfig{SocketSettings: &internet.SocketConfig{DialerProxy: ps.Tag}}
|
|
}
|
|
ps = nil
|
|
}
|
|
senderSettings.ProxySettings = ps
|
|
}
|
|
|
|
if c.MuxSettings != nil {
|
|
ms := c.MuxSettings.Build()
|
|
if ms != nil && ms.Enabled {
|
|
if ss := senderSettings.StreamSettings; ss != nil {
|
|
if ss.SecurityType == serial.GetMessageType(&xtls.Config{}) {
|
|
return nil, newError("XTLS doesn't support Mux for now.")
|
|
}
|
|
}
|
|
}
|
|
senderSettings.MultiplexSettings = ms
|
|
}
|
|
|
|
settings := []byte("{}")
|
|
if c.Settings != nil {
|
|
settings = ([]byte)(*c.Settings)
|
|
}
|
|
rawConfig, err := outboundConfigLoader.LoadWithID(settings, c.Protocol)
|
|
if err != nil {
|
|
return nil, newError("failed to parse to outbound detour config.").Base(err)
|
|
}
|
|
ts, err := rawConfig.(Buildable).Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &core.OutboundHandlerConfig{
|
|
SenderSettings: serial.ToTypedMessage(senderSettings),
|
|
Tag: c.Tag,
|
|
ProxySettings: serial.ToTypedMessage(ts),
|
|
}, nil
|
|
}
|
|
|
|
type StatsConfig struct{}
|
|
|
|
// Build implements Buildable.
|
|
func (c *StatsConfig) Build() (*stats.Config, error) {
|
|
return &stats.Config{}, nil
|
|
}
|
|
|
|
type Config struct {
|
|
// Port of this Point server.
|
|
// Deprecated: Port exists for historical compatibility
|
|
// and should not be used.
|
|
Port uint16 `json:"port"`
|
|
|
|
// Deprecated: InboundConfig exists for historical compatibility
|
|
// and should not be used.
|
|
InboundConfig *InboundDetourConfig `json:"inbound"`
|
|
|
|
// Deprecated: OutboundConfig exists for historical compatibility
|
|
// and should not be used.
|
|
OutboundConfig *OutboundDetourConfig `json:"outbound"`
|
|
|
|
// Deprecated: InboundDetours exists for historical compatibility
|
|
// and should not be used.
|
|
InboundDetours []InboundDetourConfig `json:"inboundDetour"`
|
|
|
|
// Deprecated: OutboundDetours exists for historical compatibility
|
|
// and should not be used.
|
|
OutboundDetours []OutboundDetourConfig `json:"outboundDetour"`
|
|
|
|
LogConfig *LogConfig `json:"log"`
|
|
RouterConfig *RouterConfig `json:"routing"`
|
|
DNSConfig *DNSConfig `json:"dns"`
|
|
InboundConfigs []InboundDetourConfig `json:"inbounds"`
|
|
OutboundConfigs []OutboundDetourConfig `json:"outbounds"`
|
|
Transport *TransportConfig `json:"transport"`
|
|
Policy *PolicyConfig `json:"policy"`
|
|
API *APIConfig `json:"api"`
|
|
Metrics *MetricsConfig `json:"metrics"`
|
|
Stats *StatsConfig `json:"stats"`
|
|
Reverse *ReverseConfig `json:"reverse"`
|
|
FakeDNS *FakeDNSConfig `json:"fakeDns"`
|
|
Observatory *ObservatoryConfig `json:"observatory"`
|
|
}
|
|
|
|
func (c *Config) findInboundTag(tag string) int {
|
|
found := -1
|
|
for idx, ib := range c.InboundConfigs {
|
|
if ib.Tag == tag {
|
|
found = idx
|
|
break
|
|
}
|
|
}
|
|
return found
|
|
}
|
|
|
|
func (c *Config) findOutboundTag(tag string) int {
|
|
found := -1
|
|
for idx, ob := range c.OutboundConfigs {
|
|
if ob.Tag == tag {
|
|
found = idx
|
|
break
|
|
}
|
|
}
|
|
return found
|
|
}
|
|
|
|
// Override method accepts another Config overrides the current attribute
|
|
func (c *Config) Override(o *Config, fn string) {
|
|
// only process the non-deprecated members
|
|
|
|
if o.LogConfig != nil {
|
|
c.LogConfig = o.LogConfig
|
|
}
|
|
if o.RouterConfig != nil {
|
|
c.RouterConfig = o.RouterConfig
|
|
}
|
|
if o.DNSConfig != nil {
|
|
c.DNSConfig = o.DNSConfig
|
|
}
|
|
if o.Transport != nil {
|
|
c.Transport = o.Transport
|
|
}
|
|
if o.Policy != nil {
|
|
c.Policy = o.Policy
|
|
}
|
|
if o.API != nil {
|
|
c.API = o.API
|
|
}
|
|
if o.Metrics != nil {
|
|
c.Metrics = o.Metrics
|
|
}
|
|
if o.Stats != nil {
|
|
c.Stats = o.Stats
|
|
}
|
|
if o.Reverse != nil {
|
|
c.Reverse = o.Reverse
|
|
}
|
|
|
|
if o.FakeDNS != nil {
|
|
c.FakeDNS = o.FakeDNS
|
|
}
|
|
|
|
if o.Observatory != nil {
|
|
c.Observatory = o.Observatory
|
|
}
|
|
|
|
// deprecated attrs... keep them for now
|
|
if o.InboundConfig != nil {
|
|
c.InboundConfig = o.InboundConfig
|
|
}
|
|
if o.OutboundConfig != nil {
|
|
c.OutboundConfig = o.OutboundConfig
|
|
}
|
|
if o.InboundDetours != nil {
|
|
c.InboundDetours = o.InboundDetours
|
|
}
|
|
if o.OutboundDetours != nil {
|
|
c.OutboundDetours = o.OutboundDetours
|
|
}
|
|
// deprecated attrs
|
|
|
|
// update the Inbound in slice if the only one in overide config has same tag
|
|
if len(o.InboundConfigs) > 0 {
|
|
if len(c.InboundConfigs) > 0 && len(o.InboundConfigs) == 1 {
|
|
if idx := c.findInboundTag(o.InboundConfigs[0].Tag); idx > -1 {
|
|
c.InboundConfigs[idx] = o.InboundConfigs[0]
|
|
ctllog.Println("[", fn, "] updated inbound with tag: ", o.InboundConfigs[0].Tag)
|
|
} else {
|
|
c.InboundConfigs = append(c.InboundConfigs, o.InboundConfigs[0])
|
|
ctllog.Println("[", fn, "] appended inbound with tag: ", o.InboundConfigs[0].Tag)
|
|
}
|
|
} else {
|
|
c.InboundConfigs = o.InboundConfigs
|
|
}
|
|
}
|
|
|
|
// update the Outbound in slice if the only one in overide config has same tag
|
|
if len(o.OutboundConfigs) > 0 {
|
|
if len(c.OutboundConfigs) > 0 && len(o.OutboundConfigs) == 1 {
|
|
if idx := c.findOutboundTag(o.OutboundConfigs[0].Tag); idx > -1 {
|
|
c.OutboundConfigs[idx] = o.OutboundConfigs[0]
|
|
ctllog.Println("[", fn, "] updated outbound with tag: ", o.OutboundConfigs[0].Tag)
|
|
} else {
|
|
if strings.Contains(strings.ToLower(fn), "tail") {
|
|
c.OutboundConfigs = append(c.OutboundConfigs, o.OutboundConfigs[0])
|
|
ctllog.Println("[", fn, "] appended outbound with tag: ", o.OutboundConfigs[0].Tag)
|
|
} else {
|
|
c.OutboundConfigs = append(o.OutboundConfigs, c.OutboundConfigs...)
|
|
ctllog.Println("[", fn, "] prepended outbound with tag: ", o.OutboundConfigs[0].Tag)
|
|
}
|
|
}
|
|
} else {
|
|
c.OutboundConfigs = o.OutboundConfigs
|
|
}
|
|
}
|
|
}
|
|
|
|
func applyTransportConfig(s *StreamConfig, t *TransportConfig) {
|
|
if s.TCPSettings == nil {
|
|
s.TCPSettings = t.TCPConfig
|
|
}
|
|
if s.KCPSettings == nil {
|
|
s.KCPSettings = t.KCPConfig
|
|
}
|
|
if s.WSSettings == nil {
|
|
s.WSSettings = t.WSConfig
|
|
}
|
|
if s.HTTPSettings == nil {
|
|
s.HTTPSettings = t.HTTPConfig
|
|
}
|
|
if s.DSSettings == nil {
|
|
s.DSSettings = t.DSConfig
|
|
}
|
|
}
|
|
|
|
// Build implements Buildable.
|
|
func (c *Config) Build() (*core.Config, error) {
|
|
if err := PostProcessConfigureFile(c); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config := &core.Config{
|
|
App: []*serial.TypedMessage{
|
|
serial.ToTypedMessage(&dispatcher.Config{}),
|
|
serial.ToTypedMessage(&proxyman.InboundConfig{}),
|
|
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
|
|
},
|
|
}
|
|
|
|
if c.API != nil {
|
|
apiConf, err := c.API.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(apiConf))
|
|
}
|
|
if c.Metrics != nil {
|
|
metricsConf, err := c.Metrics.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(metricsConf))
|
|
}
|
|
if c.Stats != nil {
|
|
statsConf, err := c.Stats.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(statsConf))
|
|
}
|
|
|
|
var logConfMsg *serial.TypedMessage
|
|
if c.LogConfig != nil {
|
|
logConfMsg = serial.ToTypedMessage(c.LogConfig.Build())
|
|
} else {
|
|
logConfMsg = serial.ToTypedMessage(DefaultLogConfig())
|
|
}
|
|
// let logger module be the first App to start,
|
|
// so that other modules could print log during initiating
|
|
config.App = append([]*serial.TypedMessage{logConfMsg}, config.App...)
|
|
|
|
if c.RouterConfig != nil {
|
|
routerConfig, err := c.RouterConfig.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(routerConfig))
|
|
}
|
|
|
|
if c.DNSConfig != nil {
|
|
dnsApp, err := c.DNSConfig.Build()
|
|
if err != nil {
|
|
return nil, newError("failed to parse DNS config").Base(err)
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(dnsApp))
|
|
}
|
|
|
|
if c.Policy != nil {
|
|
pc, err := c.Policy.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(pc))
|
|
}
|
|
|
|
if c.Reverse != nil {
|
|
r, err := c.Reverse.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(r))
|
|
}
|
|
|
|
if c.FakeDNS != nil {
|
|
r, err := c.FakeDNS.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append([]*serial.TypedMessage{serial.ToTypedMessage(r)}, config.App...)
|
|
}
|
|
|
|
if c.Observatory != nil {
|
|
r, err := c.Observatory.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.App = append(config.App, serial.ToTypedMessage(r))
|
|
}
|
|
|
|
var inbounds []InboundDetourConfig
|
|
|
|
if c.InboundConfig != nil {
|
|
inbounds = append(inbounds, *c.InboundConfig)
|
|
}
|
|
|
|
if len(c.InboundDetours) > 0 {
|
|
inbounds = append(inbounds, c.InboundDetours...)
|
|
}
|
|
|
|
if len(c.InboundConfigs) > 0 {
|
|
inbounds = append(inbounds, c.InboundConfigs...)
|
|
}
|
|
|
|
// Backward compatibility.
|
|
if len(inbounds) > 0 && inbounds[0].PortList == nil && c.Port > 0 {
|
|
inbounds[0].PortList = &PortList{[]PortRange{{
|
|
From: uint32(c.Port),
|
|
To: uint32(c.Port),
|
|
}}}
|
|
}
|
|
|
|
for _, rawInboundConfig := range inbounds {
|
|
if c.Transport != nil {
|
|
if rawInboundConfig.StreamSetting == nil {
|
|
rawInboundConfig.StreamSetting = &StreamConfig{}
|
|
}
|
|
applyTransportConfig(rawInboundConfig.StreamSetting, c.Transport)
|
|
}
|
|
ic, err := rawInboundConfig.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Inbound = append(config.Inbound, ic)
|
|
}
|
|
|
|
var outbounds []OutboundDetourConfig
|
|
|
|
if c.OutboundConfig != nil {
|
|
outbounds = append(outbounds, *c.OutboundConfig)
|
|
}
|
|
|
|
if len(c.OutboundDetours) > 0 {
|
|
outbounds = append(outbounds, c.OutboundDetours...)
|
|
}
|
|
|
|
if len(c.OutboundConfigs) > 0 {
|
|
outbounds = append(outbounds, c.OutboundConfigs...)
|
|
}
|
|
|
|
for _, rawOutboundConfig := range outbounds {
|
|
if c.Transport != nil {
|
|
if rawOutboundConfig.StreamSetting == nil {
|
|
rawOutboundConfig.StreamSetting = &StreamConfig{}
|
|
}
|
|
applyTransportConfig(rawOutboundConfig.StreamSetting, c.Transport)
|
|
}
|
|
oc, err := rawOutboundConfig.Build()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Outbound = append(config.Outbound, oc)
|
|
}
|
|
|
|
return config, nil
|
|
}
|