github.com/v2fly/v2ray-core/v4@v4.45.2/infra/conf/transport_internet.go (about)

     1  package conf
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"strings"
     7  
     8  	"github.com/golang/protobuf/proto"
     9  
    10  	"github.com/v2fly/v2ray-core/v4/common/platform/filesystem"
    11  	"github.com/v2fly/v2ray-core/v4/common/protocol"
    12  	"github.com/v2fly/v2ray-core/v4/common/serial"
    13  	"github.com/v2fly/v2ray-core/v4/infra/conf/cfgcommon"
    14  	"github.com/v2fly/v2ray-core/v4/transport/internet"
    15  	"github.com/v2fly/v2ray-core/v4/transport/internet/domainsocket"
    16  	httpheader "github.com/v2fly/v2ray-core/v4/transport/internet/headers/http"
    17  	"github.com/v2fly/v2ray-core/v4/transport/internet/http"
    18  	"github.com/v2fly/v2ray-core/v4/transport/internet/kcp"
    19  	"github.com/v2fly/v2ray-core/v4/transport/internet/quic"
    20  	"github.com/v2fly/v2ray-core/v4/transport/internet/tcp"
    21  	"github.com/v2fly/v2ray-core/v4/transport/internet/tls"
    22  	"github.com/v2fly/v2ray-core/v4/transport/internet/websocket"
    23  )
    24  
    25  var (
    26  	kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
    27  		"none":         func() interface{} { return new(NoOpAuthenticator) },
    28  		"srtp":         func() interface{} { return new(SRTPAuthenticator) },
    29  		"utp":          func() interface{} { return new(UTPAuthenticator) },
    30  		"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
    31  		"dtls":         func() interface{} { return new(DTLSAuthenticator) },
    32  		"wireguard":    func() interface{} { return new(WireguardAuthenticator) },
    33  	}, "type", "")
    34  
    35  	tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
    36  		"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
    37  		"http": func() interface{} { return new(Authenticator) },
    38  	}, "type", "")
    39  )
    40  
    41  type KCPConfig struct {
    42  	Mtu             *uint32         `json:"mtu"`
    43  	Tti             *uint32         `json:"tti"`
    44  	UpCap           *uint32         `json:"uplinkCapacity"`
    45  	DownCap         *uint32         `json:"downlinkCapacity"`
    46  	Congestion      *bool           `json:"congestion"`
    47  	ReadBufferSize  *uint32         `json:"readBufferSize"`
    48  	WriteBufferSize *uint32         `json:"writeBufferSize"`
    49  	HeaderConfig    json.RawMessage `json:"header"`
    50  	Seed            *string         `json:"seed"`
    51  }
    52  
    53  // Build implements Buildable.
    54  func (c *KCPConfig) Build() (proto.Message, error) {
    55  	config := new(kcp.Config)
    56  
    57  	if c.Mtu != nil {
    58  		mtu := *c.Mtu
    59  		if mtu < 576 || mtu > 1460 {
    60  			return nil, newError("invalid mKCP MTU size: ", mtu).AtError()
    61  		}
    62  		config.Mtu = &kcp.MTU{Value: mtu}
    63  	}
    64  	if c.Tti != nil {
    65  		tti := *c.Tti
    66  		if tti < 10 || tti > 100 {
    67  			return nil, newError("invalid mKCP TTI: ", tti).AtError()
    68  		}
    69  		config.Tti = &kcp.TTI{Value: tti}
    70  	}
    71  	if c.UpCap != nil {
    72  		config.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap}
    73  	}
    74  	if c.DownCap != nil {
    75  		config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap}
    76  	}
    77  	if c.Congestion != nil {
    78  		config.Congestion = *c.Congestion
    79  	}
    80  	if c.ReadBufferSize != nil {
    81  		size := *c.ReadBufferSize
    82  		if size > 0 {
    83  			config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}
    84  		} else {
    85  			config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}
    86  		}
    87  	}
    88  	if c.WriteBufferSize != nil {
    89  		size := *c.WriteBufferSize
    90  		if size > 0 {
    91  			config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}
    92  		} else {
    93  			config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
    94  		}
    95  	}
    96  	if len(c.HeaderConfig) > 0 {
    97  		headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
    98  		if err != nil {
    99  			return nil, newError("invalid mKCP header config.").Base(err).AtError()
   100  		}
   101  		ts, err := headerConfig.(Buildable).Build()
   102  		if err != nil {
   103  			return nil, newError("invalid mKCP header config").Base(err).AtError()
   104  		}
   105  		config.HeaderConfig = serial.ToTypedMessage(ts)
   106  	}
   107  
   108  	if c.Seed != nil {
   109  		config.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}
   110  	}
   111  
   112  	return config, nil
   113  }
   114  
   115  type TCPConfig struct {
   116  	HeaderConfig        json.RawMessage `json:"header"`
   117  	AcceptProxyProtocol bool            `json:"acceptProxyProtocol"`
   118  }
   119  
   120  // Build implements Buildable.
   121  func (c *TCPConfig) Build() (proto.Message, error) {
   122  	config := new(tcp.Config)
   123  	if len(c.HeaderConfig) > 0 {
   124  		headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
   125  		if err != nil {
   126  			return nil, newError("invalid TCP header config").Base(err).AtError()
   127  		}
   128  		ts, err := headerConfig.(Buildable).Build()
   129  		if err != nil {
   130  			return nil, newError("invalid TCP header config").Base(err).AtError()
   131  		}
   132  		config.HeaderSettings = serial.ToTypedMessage(ts)
   133  	}
   134  	if c.AcceptProxyProtocol {
   135  		config.AcceptProxyProtocol = c.AcceptProxyProtocol
   136  	}
   137  	return config, nil
   138  }
   139  
   140  type WebSocketConfig struct {
   141  	Path                 string            `json:"path"`
   142  	Headers              map[string]string `json:"headers"`
   143  	AcceptProxyProtocol  bool              `json:"acceptProxyProtocol"`
   144  	MaxEarlyData         int32             `json:"maxEarlyData"`
   145  	UseBrowserForwarding bool              `json:"useBrowserForwarding"`
   146  	EarlyDataHeaderName  string            `json:"earlyDataHeaderName"`
   147  }
   148  
   149  // Build implements Buildable.
   150  func (c *WebSocketConfig) Build() (proto.Message, error) {
   151  	path := c.Path
   152  	header := make([]*websocket.Header, 0, 32)
   153  	for key, value := range c.Headers {
   154  		header = append(header, &websocket.Header{
   155  			Key:   key,
   156  			Value: value,
   157  		})
   158  	}
   159  	config := &websocket.Config{
   160  		Path:                 path,
   161  		Header:               header,
   162  		MaxEarlyData:         c.MaxEarlyData,
   163  		UseBrowserForwarding: c.UseBrowserForwarding,
   164  		EarlyDataHeaderName:  c.EarlyDataHeaderName,
   165  	}
   166  	if c.AcceptProxyProtocol {
   167  		config.AcceptProxyProtocol = c.AcceptProxyProtocol
   168  	}
   169  	return config, nil
   170  }
   171  
   172  type HTTPConfig struct {
   173  	Host    *cfgcommon.StringList            `json:"host"`
   174  	Path    string                           `json:"path"`
   175  	Method  string                           `json:"method"`
   176  	Headers map[string]*cfgcommon.StringList `json:"headers"`
   177  }
   178  
   179  // Build implements Buildable.
   180  func (c *HTTPConfig) Build() (proto.Message, error) {
   181  	config := &http.Config{
   182  		Path: c.Path,
   183  	}
   184  	if c.Host != nil {
   185  		config.Host = []string(*c.Host)
   186  	}
   187  	if c.Method != "" {
   188  		config.Method = c.Method
   189  	}
   190  	if len(c.Headers) > 0 {
   191  		config.Header = make([]*httpheader.Header, 0, len(c.Headers))
   192  		headerNames := sortMapKeys(c.Headers)
   193  		for _, key := range headerNames {
   194  			value := c.Headers[key]
   195  			if value == nil {
   196  				return nil, newError("empty HTTP header value: " + key).AtError()
   197  			}
   198  			config.Header = append(config.Header, &httpheader.Header{
   199  				Name:  key,
   200  				Value: append([]string(nil), (*value)...),
   201  			})
   202  		}
   203  	}
   204  	return config, nil
   205  }
   206  
   207  type QUICConfig struct {
   208  	Header   json.RawMessage `json:"header"`
   209  	Security string          `json:"security"`
   210  	Key      string          `json:"key"`
   211  }
   212  
   213  // Build implements Buildable.
   214  func (c *QUICConfig) Build() (proto.Message, error) {
   215  	config := &quic.Config{
   216  		Key: c.Key,
   217  	}
   218  
   219  	if len(c.Header) > 0 {
   220  		headerConfig, _, err := kcpHeaderLoader.Load(c.Header)
   221  		if err != nil {
   222  			return nil, newError("invalid QUIC header config.").Base(err).AtError()
   223  		}
   224  		ts, err := headerConfig.(Buildable).Build()
   225  		if err != nil {
   226  			return nil, newError("invalid QUIC header config").Base(err).AtError()
   227  		}
   228  		config.Header = serial.ToTypedMessage(ts)
   229  	}
   230  
   231  	var st protocol.SecurityType
   232  	switch strings.ToLower(c.Security) {
   233  	case "aes-128-gcm":
   234  		st = protocol.SecurityType_AES128_GCM
   235  	case "chacha20-poly1305":
   236  		st = protocol.SecurityType_CHACHA20_POLY1305
   237  	default:
   238  		st = protocol.SecurityType_NONE
   239  	}
   240  
   241  	config.Security = &protocol.SecurityConfig{
   242  		Type: st,
   243  	}
   244  
   245  	return config, nil
   246  }
   247  
   248  type DomainSocketConfig struct {
   249  	Path     string `json:"path"`
   250  	Abstract bool   `json:"abstract"`
   251  	Padding  bool   `json:"padding"`
   252  }
   253  
   254  // Build implements Buildable.
   255  func (c *DomainSocketConfig) Build() (proto.Message, error) {
   256  	return &domainsocket.Config{
   257  		Path:     c.Path,
   258  		Abstract: c.Abstract,
   259  		Padding:  c.Padding,
   260  	}, nil
   261  }
   262  
   263  func readFileOrString(f string, s []string) ([]byte, error) {
   264  	if len(f) > 0 {
   265  		return filesystem.ReadFile(f)
   266  	}
   267  	if len(s) > 0 {
   268  		return []byte(strings.Join(s, "\n")), nil
   269  	}
   270  	return nil, newError("both file and bytes are empty.")
   271  }
   272  
   273  type TLSCertConfig struct {
   274  	CertFile string   `json:"certificateFile"`
   275  	CertStr  []string `json:"certificate"`
   276  	KeyFile  string   `json:"keyFile"`
   277  	KeyStr   []string `json:"key"`
   278  	Usage    string   `json:"usage"`
   279  }
   280  
   281  // Build implements Buildable.
   282  func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
   283  	certificate := new(tls.Certificate)
   284  
   285  	cert, err := readFileOrString(c.CertFile, c.CertStr)
   286  	if err != nil {
   287  		return nil, newError("failed to parse certificate").Base(err)
   288  	}
   289  	certificate.Certificate = cert
   290  
   291  	if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
   292  		key, err := readFileOrString(c.KeyFile, c.KeyStr)
   293  		if err != nil {
   294  			return nil, newError("failed to parse key").Base(err)
   295  		}
   296  		certificate.Key = key
   297  	}
   298  
   299  	switch strings.ToLower(c.Usage) {
   300  	case "encipherment":
   301  		certificate.Usage = tls.Certificate_ENCIPHERMENT
   302  	case "verify":
   303  		certificate.Usage = tls.Certificate_AUTHORITY_VERIFY
   304  	case "verifyclient":
   305  		certificate.Usage = tls.Certificate_AUTHORITY_VERIFY_CLIENT
   306  	case "issue":
   307  		certificate.Usage = tls.Certificate_AUTHORITY_ISSUE
   308  	default:
   309  		certificate.Usage = tls.Certificate_ENCIPHERMENT
   310  	}
   311  
   312  	return certificate, nil
   313  }
   314  
   315  type TLSConfig struct {
   316  	Insecure                         bool                  `json:"allowInsecure"`
   317  	Certs                            []*TLSCertConfig      `json:"certificates"`
   318  	ServerName                       string                `json:"serverName"`
   319  	ALPN                             *cfgcommon.StringList `json:"alpn"`
   320  	EnableSessionResumption          bool                  `json:"enableSessionResumption"`
   321  	DisableSystemRoot                bool                  `json:"disableSystemRoot"`
   322  	PinnedPeerCertificateChainSha256 *[]string             `json:"pinnedPeerCertificateChainSha256"`
   323  	VerifyClientCertificate          bool                  `json:"verifyClientCertificate"`
   324  }
   325  
   326  // Build implements Buildable.
   327  func (c *TLSConfig) Build() (proto.Message, error) {
   328  	config := new(tls.Config)
   329  	config.Certificate = make([]*tls.Certificate, len(c.Certs))
   330  	for idx, certConf := range c.Certs {
   331  		cert, err := certConf.Build()
   332  		if err != nil {
   333  			return nil, err
   334  		}
   335  		config.Certificate[idx] = cert
   336  	}
   337  	serverName := c.ServerName
   338  	config.AllowInsecure = c.Insecure
   339  	config.VerifyClientCertificate = c.VerifyClientCertificate
   340  	if len(c.ServerName) > 0 {
   341  		config.ServerName = serverName
   342  	}
   343  	if c.ALPN != nil && len(*c.ALPN) > 0 {
   344  		config.NextProtocol = []string(*c.ALPN)
   345  	}
   346  	config.EnableSessionResumption = c.EnableSessionResumption
   347  	config.DisableSystemRoot = c.DisableSystemRoot
   348  
   349  	if c.PinnedPeerCertificateChainSha256 != nil {
   350  		config.PinnedPeerCertificateChainSha256 = [][]byte{}
   351  		for _, v := range *c.PinnedPeerCertificateChainSha256 {
   352  			hashValue, err := base64.StdEncoding.DecodeString(v)
   353  			if err != nil {
   354  				return nil, err
   355  			}
   356  			config.PinnedPeerCertificateChainSha256 = append(config.PinnedPeerCertificateChainSha256, hashValue)
   357  		}
   358  	}
   359  
   360  	return config, nil
   361  }
   362  
   363  type TransportProtocol string
   364  
   365  // Build implements Buildable.
   366  func (p TransportProtocol) Build() (string, error) {
   367  	switch strings.ToLower(string(p)) {
   368  	case "tcp":
   369  		return "tcp", nil
   370  	case "kcp", "mkcp":
   371  		return "mkcp", nil
   372  	case "ws", "websocket":
   373  		return "websocket", nil
   374  	case "h2", "http":
   375  		return "http", nil
   376  	case "ds", "domainsocket":
   377  		return "domainsocket", nil
   378  	case "quic":
   379  		return "quic", nil
   380  	case "gun", "grpc":
   381  		return "gun", nil
   382  	default:
   383  		return "", newError("Config: unknown transport protocol: ", p)
   384  	}
   385  }
   386  
   387  type SocketConfig struct {
   388  	Mark                 uint32 `json:"mark"`
   389  	TFO                  *bool  `json:"tcpFastOpen"`
   390  	TFOQueueLength       uint32 `json:"tcpFastOpenQueueLength"`
   391  	TProxy               string `json:"tproxy"`
   392  	AcceptProxyProtocol  bool   `json:"acceptProxyProtocol"`
   393  	TCPKeepAliveInterval int32  `json:"tcpKeepAliveInterval"`
   394  	TCPKeepAliveIdle     int32  `json:"tcpKeepAliveIdle"`
   395  }
   396  
   397  // Build implements Buildable.
   398  func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
   399  	var tfoSettings internet.SocketConfig_TCPFastOpenState
   400  	if c.TFO != nil {
   401  		if *c.TFO {
   402  			tfoSettings = internet.SocketConfig_Enable
   403  		} else {
   404  			tfoSettings = internet.SocketConfig_Disable
   405  		}
   406  	}
   407  
   408  	tfoQueueLength := c.TFOQueueLength
   409  	if tfoQueueLength == 0 {
   410  		tfoQueueLength = 4096
   411  	}
   412  
   413  	var tproxy internet.SocketConfig_TProxyMode
   414  	switch strings.ToLower(c.TProxy) {
   415  	case "tproxy":
   416  		tproxy = internet.SocketConfig_TProxy
   417  	case "redirect":
   418  		tproxy = internet.SocketConfig_Redirect
   419  	default:
   420  		tproxy = internet.SocketConfig_Off
   421  	}
   422  
   423  	return &internet.SocketConfig{
   424  		Mark:                 c.Mark,
   425  		Tfo:                  tfoSettings,
   426  		TfoQueueLength:       tfoQueueLength,
   427  		Tproxy:               tproxy,
   428  		AcceptProxyProtocol:  c.AcceptProxyProtocol,
   429  		TcpKeepAliveInterval: c.TCPKeepAliveInterval,
   430  		TcpKeepAliveIdle:     c.TCPKeepAliveIdle,
   431  	}, nil
   432  }
   433  
   434  type StreamConfig struct {
   435  	Network        *TransportProtocol  `json:"network"`
   436  	Security       string              `json:"security"`
   437  	TLSSettings    *TLSConfig          `json:"tlsSettings"`
   438  	TCPSettings    *TCPConfig          `json:"tcpSettings"`
   439  	KCPSettings    *KCPConfig          `json:"kcpSettings"`
   440  	WSSettings     *WebSocketConfig    `json:"wsSettings"`
   441  	HTTPSettings   *HTTPConfig         `json:"httpSettings"`
   442  	DSSettings     *DomainSocketConfig `json:"dsSettings"`
   443  	QUICSettings   *QUICConfig         `json:"quicSettings"`
   444  	GunSettings    *GunConfig          `json:"gunSettings"`
   445  	GRPCSettings   *GunConfig          `json:"grpcSettings"`
   446  	SocketSettings *SocketConfig       `json:"sockopt"`
   447  }
   448  
   449  // Build implements Buildable.
   450  func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
   451  	config := &internet.StreamConfig{
   452  		ProtocolName: "tcp",
   453  	}
   454  	if c.Network != nil {
   455  		protocol, err := c.Network.Build()
   456  		if err != nil {
   457  			return nil, err
   458  		}
   459  		config.ProtocolName = protocol
   460  	}
   461  	if strings.EqualFold(c.Security, "tls") {
   462  		tlsSettings := c.TLSSettings
   463  		if tlsSettings == nil {
   464  			tlsSettings = &TLSConfig{}
   465  		}
   466  		ts, err := tlsSettings.Build()
   467  		if err != nil {
   468  			return nil, newError("Failed to build TLS config.").Base(err)
   469  		}
   470  		tm := serial.ToTypedMessage(ts)
   471  		config.SecuritySettings = append(config.SecuritySettings, tm)
   472  		config.SecurityType = tm.Type
   473  	}
   474  	if c.TCPSettings != nil {
   475  		ts, err := c.TCPSettings.Build()
   476  		if err != nil {
   477  			return nil, newError("Failed to build TCP config.").Base(err)
   478  		}
   479  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   480  			ProtocolName: "tcp",
   481  			Settings:     serial.ToTypedMessage(ts),
   482  		})
   483  	}
   484  	if c.KCPSettings != nil {
   485  		ts, err := c.KCPSettings.Build()
   486  		if err != nil {
   487  			return nil, newError("Failed to build mKCP config.").Base(err)
   488  		}
   489  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   490  			ProtocolName: "mkcp",
   491  			Settings:     serial.ToTypedMessage(ts),
   492  		})
   493  	}
   494  	if c.WSSettings != nil {
   495  		ts, err := c.WSSettings.Build()
   496  		if err != nil {
   497  			return nil, newError("Failed to build WebSocket config.").Base(err)
   498  		}
   499  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   500  			ProtocolName: "websocket",
   501  			Settings:     serial.ToTypedMessage(ts),
   502  		})
   503  	}
   504  	if c.HTTPSettings != nil {
   505  		ts, err := c.HTTPSettings.Build()
   506  		if err != nil {
   507  			return nil, newError("Failed to build HTTP config.").Base(err)
   508  		}
   509  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   510  			ProtocolName: "http",
   511  			Settings:     serial.ToTypedMessage(ts),
   512  		})
   513  	}
   514  	if c.DSSettings != nil {
   515  		ds, err := c.DSSettings.Build()
   516  		if err != nil {
   517  			return nil, newError("Failed to build DomainSocket config.").Base(err)
   518  		}
   519  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   520  			ProtocolName: "domainsocket",
   521  			Settings:     serial.ToTypedMessage(ds),
   522  		})
   523  	}
   524  	if c.QUICSettings != nil {
   525  		qs, err := c.QUICSettings.Build()
   526  		if err != nil {
   527  			return nil, newError("Failed to build QUIC config.").Base(err)
   528  		}
   529  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   530  			ProtocolName: "quic",
   531  			Settings:     serial.ToTypedMessage(qs),
   532  		})
   533  	}
   534  	if c.GunSettings == nil {
   535  		c.GunSettings = c.GRPCSettings
   536  	}
   537  	if c.GunSettings != nil {
   538  		gs, err := c.GunSettings.Build()
   539  		if err != nil {
   540  			return nil, newError("Failed to build Gun config.").Base(err)
   541  		}
   542  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   543  			ProtocolName: "gun",
   544  			Settings:     serial.ToTypedMessage(gs),
   545  		})
   546  	}
   547  	if c.SocketSettings != nil {
   548  		ss, err := c.SocketSettings.Build()
   549  		if err != nil {
   550  			return nil, newError("Failed to build sockopt.").Base(err)
   551  		}
   552  		config.SocketSettings = ss
   553  	}
   554  	return config, nil
   555  }
   556  
   557  type ProxyConfig struct {
   558  	Tag                 string `json:"tag"`
   559  	TransportLayerProxy bool   `json:"transportLayer"`
   560  }
   561  
   562  // Build implements Buildable.
   563  func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
   564  	if v.Tag == "" {
   565  		return nil, newError("Proxy tag is not set.")
   566  	}
   567  	return &internet.ProxyConfig{
   568  		Tag:                 v.Tag,
   569  		TransportLayerProxy: v.TransportLayerProxy,
   570  	}, nil
   571  }