github.com/imannamdari/v2ray-core/v5@v5.0.5/infra/conf/v4/v2ray.go (about)

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