github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/infra/conf/v4/v2ray.go (about)

     1  package v4
     2  
     3  import (
     4  	"encoding/json"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"google.golang.org/protobuf/types/known/anypb"
     9  
    10  	core "github.com/v2fly/v2ray-core/v5"
    11  	"github.com/v2fly/v2ray-core/v5/app/dispatcher"
    12  	"github.com/v2fly/v2ray-core/v5/app/proxyman"
    13  	"github.com/v2fly/v2ray-core/v5/app/stats"
    14  	"github.com/v2fly/v2ray-core/v5/common/serial"
    15  	"github.com/v2fly/v2ray-core/v5/features"
    16  	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon"
    17  	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/loader"
    18  	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/muxcfg"
    19  	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/proxycfg"
    20  	"github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon/sniffer"
    21  	"github.com/v2fly/v2ray-core/v5/infra/conf/synthetic/dns"
    22  	"github.com/v2fly/v2ray-core/v5/infra/conf/synthetic/log"
    23  	"github.com/v2fly/v2ray-core/v5/infra/conf/synthetic/router"
    24  )
    25  
    26  var (
    27  	inboundConfigLoader = loader.NewJSONConfigLoader(loader.ConfigCreatorCache{
    28  		"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
    29  		"http":          func() interface{} { return new(HTTPServerConfig) },
    30  		"shadowsocks":   func() interface{} { return new(ShadowsocksServerConfig) },
    31  		"socks":         func() interface{} { return new(SocksServerConfig) },
    32  		"vless":         func() interface{} { return new(VLessInboundConfig) },
    33  		"vmess":         func() interface{} { return new(VMessInboundConfig) },
    34  		"trojan":        func() interface{} { return new(TrojanServerConfig) },
    35  	}, "protocol", "settings")
    36  
    37  	outboundConfigLoader = loader.NewJSONConfigLoader(loader.ConfigCreatorCache{
    38  		"blackhole":   func() interface{} { return new(BlackholeConfig) },
    39  		"freedom":     func() interface{} { return new(FreedomConfig) },
    40  		"http":        func() interface{} { return new(HTTPClientConfig) },
    41  		"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
    42  		"socks":       func() interface{} { return new(SocksClientConfig) },
    43  		"vless":       func() interface{} { return new(VLessOutboundConfig) },
    44  		"vmess":       func() interface{} { return new(VMessOutboundConfig) },
    45  		"trojan":      func() interface{} { return new(TrojanClientConfig) },
    46  		"dns":         func() interface{} { return new(DNSOutboundConfig) },
    47  		"loopback":    func() interface{} { return new(LoopbackConfig) },
    48  	}, "protocol", "settings")
    49  )
    50  
    51  func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {
    52  	kp := make([]proxyman.KnownProtocols, 0, 8)
    53  	for _, p := range s {
    54  		switch strings.ToLower(p) {
    55  		case "http":
    56  			kp = append(kp, proxyman.KnownProtocols_HTTP)
    57  		case "https", "tls", "ssl":
    58  			kp = append(kp, proxyman.KnownProtocols_TLS)
    59  		default:
    60  			return nil, newError("Unknown protocol: ", p)
    61  		}
    62  	}
    63  	return kp, nil
    64  }
    65  
    66  type InboundDetourAllocationConfig struct {
    67  	Strategy    string  `json:"strategy"`
    68  	Concurrency *uint32 `json:"concurrency"`
    69  	RefreshMin  *uint32 `json:"refresh"`
    70  }
    71  
    72  // Build implements Buildable.
    73  func (c *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {
    74  	config := new(proxyman.AllocationStrategy)
    75  	switch strings.ToLower(c.Strategy) {
    76  	case "always":
    77  		config.Type = proxyman.AllocationStrategy_Always
    78  	case "random":
    79  		config.Type = proxyman.AllocationStrategy_Random
    80  	case "external":
    81  		config.Type = proxyman.AllocationStrategy_External
    82  	default:
    83  		return nil, newError("unknown allocation strategy: ", c.Strategy)
    84  	}
    85  	if c.Concurrency != nil {
    86  		config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
    87  			Value: *c.Concurrency,
    88  		}
    89  	}
    90  
    91  	if c.RefreshMin != nil {
    92  		config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{
    93  			Value: *c.RefreshMin,
    94  		}
    95  	}
    96  
    97  	return config, nil
    98  }
    99  
   100  type InboundDetourConfig struct {
   101  	Protocol       string                         `json:"protocol"`
   102  	PortRange      *cfgcommon.PortRange           `json:"port"`
   103  	ListenOn       *cfgcommon.Address             `json:"listen"`
   104  	Settings       *json.RawMessage               `json:"settings"`
   105  	Tag            string                         `json:"tag"`
   106  	Allocation     *InboundDetourAllocationConfig `json:"allocate"`
   107  	StreamSetting  *StreamConfig                  `json:"streamSettings"`
   108  	DomainOverride *cfgcommon.StringList          `json:"domainOverride"`
   109  	SniffingConfig *sniffer.SniffingConfig        `json:"sniffing"`
   110  }
   111  
   112  // Build implements Buildable.
   113  func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) {
   114  	receiverSettings := &proxyman.ReceiverConfig{}
   115  
   116  	if c.ListenOn == nil {
   117  		// Listen on anyip, must set PortRange
   118  		if c.PortRange == nil {
   119  			return nil, newError("Listen on AnyIP but no Port(s) set in InboundDetour.")
   120  		}
   121  		receiverSettings.PortRange = c.PortRange.Build()
   122  	} else {
   123  		// Listen on specific IP or Unix Domain Socket
   124  		receiverSettings.Listen = c.ListenOn.Build()
   125  		listenDS := c.ListenOn.Family().IsDomain() && (filepath.IsAbs(c.ListenOn.Domain()) || c.ListenOn.Domain()[0] == '@')
   126  		listenIP := c.ListenOn.Family().IsIP() || (c.ListenOn.Family().IsDomain() && c.ListenOn.Domain() == "localhost")
   127  		switch {
   128  		case listenIP:
   129  			// Listen on specific IP, must set PortRange
   130  			if c.PortRange == nil {
   131  				return nil, newError("Listen on specific ip without port in InboundDetour.")
   132  			}
   133  			// Listen on IP:Port
   134  			receiverSettings.PortRange = c.PortRange.Build()
   135  		case listenDS:
   136  			if c.PortRange != nil {
   137  				// Listen on Unix Domain Socket, PortRange should be nil
   138  				receiverSettings.PortRange = nil
   139  			}
   140  		default:
   141  			return nil, newError("unable to listen on domain address: ", c.ListenOn.Domain())
   142  		}
   143  	}
   144  
   145  	if c.Allocation != nil {
   146  		concurrency := -1
   147  		if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" {
   148  			concurrency = int(*c.Allocation.Concurrency)
   149  		}
   150  		portRange := int(c.PortRange.To - c.PortRange.From + 1)
   151  		if concurrency >= 0 && concurrency >= portRange {
   152  			return nil, newError("not enough ports. concurrency = ", concurrency, " ports: ", c.PortRange.From, " - ", c.PortRange.To)
   153  		}
   154  
   155  		as, err := c.Allocation.Build()
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  		receiverSettings.AllocationStrategy = as
   160  	}
   161  	if c.StreamSetting != nil {
   162  		ss, err := c.StreamSetting.Build()
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  		receiverSettings.StreamSettings = ss
   167  	}
   168  	if c.SniffingConfig != nil {
   169  		s, err := c.SniffingConfig.Build()
   170  		if err != nil {
   171  			return nil, newError("failed to build sniffing config").Base(err)
   172  		}
   173  		receiverSettings.SniffingSettings = s
   174  	}
   175  	if c.DomainOverride != nil {
   176  		kp, err := toProtocolList(*c.DomainOverride)
   177  		if err != nil {
   178  			return nil, newError("failed to parse inbound detour config").Base(err)
   179  		}
   180  		receiverSettings.DomainOverride = kp
   181  	}
   182  
   183  	settings := []byte("{}")
   184  	if c.Settings != nil {
   185  		settings = ([]byte)(*c.Settings)
   186  	}
   187  	rawConfig, err := inboundConfigLoader.LoadWithID(settings, c.Protocol)
   188  	if err != nil {
   189  		return nil, newError("failed to load inbound detour config.").Base(err)
   190  	}
   191  	if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
   192  		receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect
   193  	}
   194  	ts, err := rawConfig.(cfgcommon.Buildable).Build()
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  
   199  	return &core.InboundHandlerConfig{
   200  		Tag:              c.Tag,
   201  		ReceiverSettings: serial.ToTypedMessage(receiverSettings),
   202  		ProxySettings:    serial.ToTypedMessage(ts),
   203  	}, nil
   204  }
   205  
   206  type OutboundDetourConfig struct {
   207  	Protocol       string                `json:"protocol"`
   208  	SendThrough    *cfgcommon.Address    `json:"sendThrough"`
   209  	Tag            string                `json:"tag"`
   210  	Settings       *json.RawMessage      `json:"settings"`
   211  	StreamSetting  *StreamConfig         `json:"streamSettings"`
   212  	ProxySettings  *proxycfg.ProxyConfig `json:"proxySettings"`
   213  	MuxSettings    *muxcfg.MuxConfig     `json:"mux"`
   214  	DomainStrategy string                `json:"domainStrategy"`
   215  }
   216  
   217  // Build implements Buildable.
   218  func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
   219  	senderSettings := &proxyman.SenderConfig{}
   220  
   221  	if c.SendThrough != nil {
   222  		address := c.SendThrough
   223  		if address.Family().IsDomain() {
   224  			return nil, newError("unable to send through: " + address.String())
   225  		}
   226  		senderSettings.Via = address.Build()
   227  	}
   228  
   229  	if c.StreamSetting != nil {
   230  		ss, err := c.StreamSetting.Build()
   231  		if err != nil {
   232  			return nil, err
   233  		}
   234  		senderSettings.StreamSettings = ss
   235  	}
   236  
   237  	if c.ProxySettings != nil {
   238  		ps, err := c.ProxySettings.Build()
   239  		if err != nil {
   240  			return nil, newError("invalid outbound detour proxy settings.").Base(err)
   241  		}
   242  		senderSettings.ProxySettings = ps
   243  	}
   244  
   245  	if c.MuxSettings != nil {
   246  		senderSettings.MultiplexSettings = c.MuxSettings.Build()
   247  	}
   248  
   249  	senderSettings.DomainStrategy = proxyman.SenderConfig_AS_IS
   250  	switch strings.ToLower(c.DomainStrategy) {
   251  	case "useip", "use_ip", "use-ip":
   252  		senderSettings.DomainStrategy = proxyman.SenderConfig_USE_IP
   253  	case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
   254  		senderSettings.DomainStrategy = proxyman.SenderConfig_USE_IP4
   255  	case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
   256  		senderSettings.DomainStrategy = proxyman.SenderConfig_USE_IP6
   257  	}
   258  
   259  	settings := []byte("{}")
   260  	if c.Settings != nil {
   261  		settings = ([]byte)(*c.Settings)
   262  	}
   263  	rawConfig, err := outboundConfigLoader.LoadWithID(settings, c.Protocol)
   264  	if err != nil {
   265  		return nil, newError("failed to parse to outbound detour config.").Base(err)
   266  	}
   267  	ts, err := rawConfig.(cfgcommon.Buildable).Build()
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  
   272  	return &core.OutboundHandlerConfig{
   273  		SenderSettings: serial.ToTypedMessage(senderSettings),
   274  		Tag:            c.Tag,
   275  		ProxySettings:  serial.ToTypedMessage(ts),
   276  	}, nil
   277  }
   278  
   279  type StatsConfig struct{}
   280  
   281  // Build implements Buildable.
   282  func (c *StatsConfig) Build() (*stats.Config, error) {
   283  	return &stats.Config{}, nil
   284  }
   285  
   286  type Config struct {
   287  	// Port of this Point server.
   288  	// Deprecated: Port exists for historical compatibility
   289  	// and should not be used.
   290  	Port uint16 `json:"port"`
   291  
   292  	// Deprecated: InboundConfig exists for historical compatibility
   293  	// and should not be used.
   294  	InboundConfig *InboundDetourConfig `json:"inbound"`
   295  
   296  	// Deprecated: OutboundConfig exists for historical compatibility
   297  	// and should not be used.
   298  	OutboundConfig *OutboundDetourConfig `json:"outbound"`
   299  
   300  	// Deprecated: InboundDetours exists for historical compatibility
   301  	// and should not be used.
   302  	InboundDetours []InboundDetourConfig `json:"inboundDetour"`
   303  
   304  	// Deprecated: OutboundDetours exists for historical compatibility
   305  	// and should not be used.
   306  	OutboundDetours []OutboundDetourConfig `json:"outboundDetour"`
   307  
   308  	LogConfig        *log.LogConfig          `json:"log"`
   309  	RouterConfig     *router.RouterConfig    `json:"routing"`
   310  	DNSConfig        *dns.DNSConfig          `json:"dns"`
   311  	InboundConfigs   []InboundDetourConfig   `json:"inbounds"`
   312  	OutboundConfigs  []OutboundDetourConfig  `json:"outbounds"`
   313  	Transport        *TransportConfig        `json:"transport"`
   314  	Policy           *PolicyConfig           `json:"policy"`
   315  	API              *APIConfig              `json:"api"`
   316  	Stats            *StatsConfig            `json:"stats"`
   317  	Reverse          *ReverseConfig          `json:"reverse"`
   318  	FakeDNS          *dns.FakeDNSConfig      `json:"fakeDns"`
   319  	BrowserForwarder *BrowserForwarderConfig `json:"browserForwarder"`
   320  	Observatory      *ObservatoryConfig      `json:"observatory"`
   321  	BurstObservatory *BurstObservatoryConfig `json:"burstObservatory"`
   322  	MultiObservatory *MultiObservatoryConfig `json:"multiObservatory"`
   323  
   324  	Services map[string]*json.RawMessage `json:"services"`
   325  }
   326  
   327  func (c *Config) findInboundTag(tag string) int {
   328  	found := -1
   329  	for idx, ib := range c.InboundConfigs {
   330  		if ib.Tag == tag {
   331  			found = idx
   332  			break
   333  		}
   334  	}
   335  	return found
   336  }
   337  
   338  func (c *Config) findOutboundTag(tag string) int {
   339  	found := -1
   340  	for idx, ob := range c.OutboundConfigs {
   341  		if ob.Tag == tag {
   342  			found = idx
   343  			break
   344  		}
   345  	}
   346  	return found
   347  }
   348  
   349  func applyTransportConfig(s *StreamConfig, t *TransportConfig) {
   350  	if s.TCPSettings == nil {
   351  		s.TCPSettings = t.TCPConfig
   352  	}
   353  	if s.KCPSettings == nil {
   354  		s.KCPSettings = t.KCPConfig
   355  	}
   356  	if s.WSSettings == nil {
   357  		s.WSSettings = t.WSConfig
   358  	}
   359  	if s.HTTPSettings == nil {
   360  		s.HTTPSettings = t.HTTPConfig
   361  	}
   362  	if s.DSSettings == nil {
   363  		s.DSSettings = t.DSConfig
   364  	}
   365  }
   366  
   367  // Build implements Buildable.
   368  func (c *Config) Build() (*core.Config, error) {
   369  	if err := PostProcessConfigureFile(c); err != nil {
   370  		return nil, err
   371  	}
   372  
   373  	config := &core.Config{
   374  		App: []*anypb.Any{
   375  			serial.ToTypedMessage(&dispatcher.Config{}),
   376  			serial.ToTypedMessage(&proxyman.InboundConfig{}),
   377  			serial.ToTypedMessage(&proxyman.OutboundConfig{}),
   378  		},
   379  	}
   380  
   381  	if c.API != nil {
   382  		apiConf, err := c.API.Build()
   383  		if err != nil {
   384  			return nil, err
   385  		}
   386  		config.App = append(config.App, serial.ToTypedMessage(apiConf))
   387  	}
   388  
   389  	if c.Stats != nil {
   390  		statsConf, err := c.Stats.Build()
   391  		if err != nil {
   392  			return nil, err
   393  		}
   394  		config.App = append(config.App, serial.ToTypedMessage(statsConf))
   395  	}
   396  
   397  	var logConfMsg *anypb.Any
   398  	if c.LogConfig != nil {
   399  		logConfMsg = serial.ToTypedMessage(c.LogConfig.Build())
   400  	} else {
   401  		logConfMsg = serial.ToTypedMessage(log.DefaultLogConfig())
   402  	}
   403  	// let logger module be the first App to start,
   404  	// so that other modules could print log during initiating
   405  	config.App = append([]*anypb.Any{logConfMsg}, config.App...)
   406  
   407  	if c.RouterConfig != nil {
   408  		routerConfig, err := c.RouterConfig.Build()
   409  		if err != nil {
   410  			return nil, err
   411  		}
   412  		config.App = append(config.App, serial.ToTypedMessage(routerConfig))
   413  	}
   414  
   415  	if c.FakeDNS != nil {
   416  		features.PrintDeprecatedFeatureWarning("root fakedns settings")
   417  		if c.DNSConfig != nil {
   418  			c.DNSConfig.FakeDNS = c.FakeDNS
   419  		} else {
   420  			c.DNSConfig = &dns.DNSConfig{
   421  				FakeDNS: c.FakeDNS,
   422  			}
   423  		}
   424  	}
   425  
   426  	if c.DNSConfig != nil {
   427  		dnsApp, err := c.DNSConfig.Build()
   428  		if err != nil {
   429  			return nil, newError("failed to parse DNS config").Base(err)
   430  		}
   431  		config.App = append(config.App, serial.ToTypedMessage(dnsApp))
   432  	}
   433  
   434  	if c.Policy != nil {
   435  		pc, err := c.Policy.Build()
   436  		if err != nil {
   437  			return nil, err
   438  		}
   439  		config.App = append(config.App, serial.ToTypedMessage(pc))
   440  	}
   441  
   442  	if c.Reverse != nil {
   443  		r, err := c.Reverse.Build()
   444  		if err != nil {
   445  			return nil, err
   446  		}
   447  		config.App = append(config.App, serial.ToTypedMessage(r))
   448  	}
   449  
   450  	if c.BrowserForwarder != nil {
   451  		r, err := c.BrowserForwarder.Build()
   452  		if err != nil {
   453  			return nil, err
   454  		}
   455  		config.App = append(config.App, serial.ToTypedMessage(r))
   456  	}
   457  
   458  	if c.Observatory != nil {
   459  		r, err := c.Observatory.Build()
   460  		if err != nil {
   461  			return nil, err
   462  		}
   463  		config.App = append(config.App, serial.ToTypedMessage(r))
   464  	}
   465  
   466  	if c.BurstObservatory != nil {
   467  		r, err := c.BurstObservatory.Build()
   468  		if err != nil {
   469  			return nil, err
   470  		}
   471  		config.App = append(config.App, serial.ToTypedMessage(r))
   472  	}
   473  
   474  	if c.MultiObservatory != nil {
   475  		r, err := c.MultiObservatory.Build()
   476  		if err != nil {
   477  			return nil, err
   478  		}
   479  		config.App = append(config.App, serial.ToTypedMessage(r))
   480  	}
   481  
   482  	// Load Additional Services that do not have a json translator
   483  
   484  	if msg, err := c.BuildServices(c.Services); err != nil {
   485  		developererr := newError("Loading a V2Ray Features as a service is intended for developers only. " +
   486  			"This is used for developers to prototype new features or for an advanced client to use special features in V2Ray," +
   487  			" instead of allowing end user to enable it without special tool and knowledge.")
   488  		sb := strings.Builder{}
   489  		return nil, newError("Cannot load service").Base(developererr).Base(err).Base(newError(sb.String()))
   490  	} else { // nolint: revive
   491  		// Using a else here is required to keep msg in scope
   492  		config.App = append(config.App, msg...)
   493  	}
   494  
   495  	var inbounds []InboundDetourConfig
   496  
   497  	if c.InboundConfig != nil {
   498  		inbounds = append(inbounds, *c.InboundConfig)
   499  	}
   500  
   501  	if len(c.InboundDetours) > 0 {
   502  		inbounds = append(inbounds, c.InboundDetours...)
   503  	}
   504  
   505  	if len(c.InboundConfigs) > 0 {
   506  		inbounds = append(inbounds, c.InboundConfigs...)
   507  	}
   508  
   509  	// Backward compatibility.
   510  	if len(inbounds) > 0 && inbounds[0].PortRange == nil && c.Port > 0 {
   511  		inbounds[0].PortRange = &cfgcommon.PortRange{
   512  			From: uint32(c.Port),
   513  			To:   uint32(c.Port),
   514  		}
   515  	}
   516  
   517  	for _, rawInboundConfig := range inbounds {
   518  		if c.Transport != nil {
   519  			if rawInboundConfig.StreamSetting == nil {
   520  				rawInboundConfig.StreamSetting = &StreamConfig{}
   521  			}
   522  			applyTransportConfig(rawInboundConfig.StreamSetting, c.Transport)
   523  		}
   524  		ic, err := rawInboundConfig.Build()
   525  		if err != nil {
   526  			return nil, err
   527  		}
   528  		config.Inbound = append(config.Inbound, ic)
   529  	}
   530  
   531  	var outbounds []OutboundDetourConfig
   532  
   533  	if c.OutboundConfig != nil {
   534  		outbounds = append(outbounds, *c.OutboundConfig)
   535  	}
   536  
   537  	if len(c.OutboundDetours) > 0 {
   538  		outbounds = append(outbounds, c.OutboundDetours...)
   539  	}
   540  
   541  	if len(c.OutboundConfigs) > 0 {
   542  		outbounds = append(outbounds, c.OutboundConfigs...)
   543  	}
   544  
   545  	for _, rawOutboundConfig := range outbounds {
   546  		if c.Transport != nil {
   547  			if rawOutboundConfig.StreamSetting == nil {
   548  				rawOutboundConfig.StreamSetting = &StreamConfig{}
   549  			}
   550  			applyTransportConfig(rawOutboundConfig.StreamSetting, c.Transport)
   551  		}
   552  		oc, err := rawOutboundConfig.Build()
   553  		if err != nil {
   554  			return nil, err
   555  		}
   556  		config.Outbound = append(config.Outbound, oc)
   557  	}
   558  
   559  	return config, nil
   560  }