mirror of https://github.com/v2ray/v2ray-core
				
				
				
			
		
			
				
	
	
		
			479 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			479 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
package conf
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/golang/protobuf/proto"
 | 
						|
	"v2ray.com/core/common/platform/filesystem"
 | 
						|
	"v2ray.com/core/common/protocol"
 | 
						|
	"v2ray.com/core/common/serial"
 | 
						|
	"v2ray.com/core/transport/internet"
 | 
						|
	"v2ray.com/core/transport/internet/domainsocket"
 | 
						|
	"v2ray.com/core/transport/internet/http"
 | 
						|
	"v2ray.com/core/transport/internet/kcp"
 | 
						|
	"v2ray.com/core/transport/internet/quic"
 | 
						|
	"v2ray.com/core/transport/internet/tcp"
 | 
						|
	"v2ray.com/core/transport/internet/tls"
 | 
						|
	"v2ray.com/core/transport/internet/websocket"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
 | 
						|
		"none":         func() interface{} { return new(NoOpAuthenticator) },
 | 
						|
		"srtp":         func() interface{} { return new(SRTPAuthenticator) },
 | 
						|
		"utp":          func() interface{} { return new(UTPAuthenticator) },
 | 
						|
		"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
 | 
						|
		"dtls":         func() interface{} { return new(DTLSAuthenticator) },
 | 
						|
		"wireguard":    func() interface{} { return new(WireguardAuthenticator) },
 | 
						|
	}, "type", "")
 | 
						|
 | 
						|
	tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
 | 
						|
		"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
 | 
						|
		"http": func() interface{} { return new(HTTPAuthenticator) },
 | 
						|
	}, "type", "")
 | 
						|
)
 | 
						|
 | 
						|
type KCPConfig struct {
 | 
						|
	Mtu             *uint32         `json:"mtu"`
 | 
						|
	Tti             *uint32         `json:"tti"`
 | 
						|
	UpCap           *uint32         `json:"uplinkCapacity"`
 | 
						|
	DownCap         *uint32         `json:"downlinkCapacity"`
 | 
						|
	Congestion      *bool           `json:"congestion"`
 | 
						|
	ReadBufferSize  *uint32         `json:"readBufferSize"`
 | 
						|
	WriteBufferSize *uint32         `json:"writeBufferSize"`
 | 
						|
	HeaderConfig    json.RawMessage `json:"header"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable.
 | 
						|
func (c *KCPConfig) Build() (proto.Message, error) {
 | 
						|
	config := new(kcp.Config)
 | 
						|
 | 
						|
	if c.Mtu != nil {
 | 
						|
		mtu := *c.Mtu
 | 
						|
		if mtu < 576 || mtu > 1460 {
 | 
						|
			return nil, newError("invalid mKCP MTU size: ", mtu).AtError()
 | 
						|
		}
 | 
						|
		config.Mtu = &kcp.MTU{Value: mtu}
 | 
						|
	}
 | 
						|
	if c.Tti != nil {
 | 
						|
		tti := *c.Tti
 | 
						|
		if tti < 10 || tti > 100 {
 | 
						|
			return nil, newError("invalid mKCP TTI: ", tti).AtError()
 | 
						|
		}
 | 
						|
		config.Tti = &kcp.TTI{Value: tti}
 | 
						|
	}
 | 
						|
	if c.UpCap != nil {
 | 
						|
		config.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap}
 | 
						|
	}
 | 
						|
	if c.DownCap != nil {
 | 
						|
		config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap}
 | 
						|
	}
 | 
						|
	if c.Congestion != nil {
 | 
						|
		config.Congestion = *c.Congestion
 | 
						|
	}
 | 
						|
	if c.ReadBufferSize != nil {
 | 
						|
		size := *c.ReadBufferSize
 | 
						|
		if size > 0 {
 | 
						|
			config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}
 | 
						|
		} else {
 | 
						|
			config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if c.WriteBufferSize != nil {
 | 
						|
		size := *c.WriteBufferSize
 | 
						|
		if size > 0 {
 | 
						|
			config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}
 | 
						|
		} else {
 | 
						|
			config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if len(c.HeaderConfig) > 0 {
 | 
						|
		headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("invalid mKCP header config.").Base(err).AtError()
 | 
						|
		}
 | 
						|
		ts, err := headerConfig.(Buildable).Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("invalid mKCP header config").Base(err).AtError()
 | 
						|
		}
 | 
						|
		config.HeaderConfig = serial.ToTypedMessage(ts)
 | 
						|
	}
 | 
						|
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type TCPConfig struct {
 | 
						|
	HeaderConfig json.RawMessage `json:"header"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable.
 | 
						|
func (c *TCPConfig) Build() (proto.Message, error) {
 | 
						|
	config := new(tcp.Config)
 | 
						|
	if len(c.HeaderConfig) > 0 {
 | 
						|
		headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("invalid TCP header config").Base(err).AtError()
 | 
						|
		}
 | 
						|
		ts, err := headerConfig.(Buildable).Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("invalid TCP header config").Base(err).AtError()
 | 
						|
		}
 | 
						|
		config.HeaderSettings = serial.ToTypedMessage(ts)
 | 
						|
	}
 | 
						|
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type WebSocketConfig struct {
 | 
						|
	Path    string            `json:"path"`
 | 
						|
	Path2   string            `json:"Path"` // The key was misspelled. For backward compatibility, we have to keep track the old key.
 | 
						|
	Headers map[string]string `json:"headers"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable.
 | 
						|
func (c *WebSocketConfig) Build() (proto.Message, error) {
 | 
						|
	path := c.Path
 | 
						|
	if len(path) == 0 && len(c.Path2) > 0 {
 | 
						|
		path = c.Path2
 | 
						|
	}
 | 
						|
	header := make([]*websocket.Header, 0, 32)
 | 
						|
	for key, value := range c.Headers {
 | 
						|
		header = append(header, &websocket.Header{
 | 
						|
			Key:   key,
 | 
						|
			Value: value,
 | 
						|
		})
 | 
						|
	}
 | 
						|
 | 
						|
	config := &websocket.Config{
 | 
						|
		Path:   path,
 | 
						|
		Header: header,
 | 
						|
	}
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type HTTPConfig struct {
 | 
						|
	Host *StringList `json:"host"`
 | 
						|
	Path string      `json:"path"`
 | 
						|
}
 | 
						|
 | 
						|
func (c *HTTPConfig) Build() (proto.Message, error) {
 | 
						|
	config := &http.Config{
 | 
						|
		Path: c.Path,
 | 
						|
	}
 | 
						|
	if c.Host != nil {
 | 
						|
		config.Host = []string(*c.Host)
 | 
						|
	}
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type QUICConfig struct {
 | 
						|
	Header   json.RawMessage `json:"header"`
 | 
						|
	Security string          `json:"security"`
 | 
						|
	Key      string          `json:"key"`
 | 
						|
}
 | 
						|
 | 
						|
func (c *QUICConfig) Build() (proto.Message, error) {
 | 
						|
	config := &quic.Config{
 | 
						|
		Key: c.Key,
 | 
						|
	}
 | 
						|
 | 
						|
	if len(c.Header) > 0 {
 | 
						|
		headerConfig, _, err := kcpHeaderLoader.Load(c.Header)
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("invalid QUIC header config.").Base(err).AtError()
 | 
						|
		}
 | 
						|
		ts, err := headerConfig.(Buildable).Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("invalid QUIC header config").Base(err).AtError()
 | 
						|
		}
 | 
						|
		config.Header = serial.ToTypedMessage(ts)
 | 
						|
	}
 | 
						|
 | 
						|
	var st protocol.SecurityType
 | 
						|
	switch strings.ToLower(c.Security) {
 | 
						|
	case "aes-128-gcm":
 | 
						|
		st = protocol.SecurityType_AES128_GCM
 | 
						|
	case "chacha20-poly1305":
 | 
						|
		st = protocol.SecurityType_CHACHA20_POLY1305
 | 
						|
	default:
 | 
						|
		st = protocol.SecurityType_NONE
 | 
						|
	}
 | 
						|
 | 
						|
	config.Security = &protocol.SecurityConfig{
 | 
						|
		Type: st,
 | 
						|
	}
 | 
						|
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type DomainSocketConfig struct {
 | 
						|
	Path     string `json:"path"`
 | 
						|
	Abstract bool   `json:"abstract"`
 | 
						|
}
 | 
						|
 | 
						|
func (c *DomainSocketConfig) Build() (proto.Message, error) {
 | 
						|
	return &domainsocket.Config{
 | 
						|
		Path:     c.Path,
 | 
						|
		Abstract: c.Abstract,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
type TLSCertConfig struct {
 | 
						|
	CertFile string   `json:"certificateFile"`
 | 
						|
	CertStr  []string `json:"certificate"`
 | 
						|
	KeyFile  string   `json:"keyFile"`
 | 
						|
	KeyStr   []string `json:"key"`
 | 
						|
	Usage    string   `json:"usage"`
 | 
						|
}
 | 
						|
 | 
						|
func readFileOrString(f string, s []string) ([]byte, error) {
 | 
						|
	if len(f) > 0 {
 | 
						|
		return filesystem.ReadFile(f)
 | 
						|
	}
 | 
						|
	if len(s) > 0 {
 | 
						|
		return []byte(strings.Join(s, "\n")), nil
 | 
						|
	}
 | 
						|
	return nil, newError("both file and bytes are empty.")
 | 
						|
}
 | 
						|
 | 
						|
func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
 | 
						|
	certificate := new(tls.Certificate)
 | 
						|
 | 
						|
	cert, err := readFileOrString(c.CertFile, c.CertStr)
 | 
						|
	if err != nil {
 | 
						|
		return nil, newError("failed to parse certificate").Base(err)
 | 
						|
	}
 | 
						|
	certificate.Certificate = cert
 | 
						|
 | 
						|
	if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
 | 
						|
		key, err := readFileOrString(c.KeyFile, c.KeyStr)
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("failed to parse key").Base(err)
 | 
						|
		}
 | 
						|
		certificate.Key = key
 | 
						|
	}
 | 
						|
 | 
						|
	switch strings.ToLower(c.Usage) {
 | 
						|
	case "encipherment":
 | 
						|
		certificate.Usage = tls.Certificate_ENCIPHERMENT
 | 
						|
	case "verify":
 | 
						|
		certificate.Usage = tls.Certificate_AUTHORITY_VERIFY
 | 
						|
	case "issue":
 | 
						|
		certificate.Usage = tls.Certificate_AUTHORITY_ISSUE
 | 
						|
	default:
 | 
						|
		certificate.Usage = tls.Certificate_ENCIPHERMENT
 | 
						|
	}
 | 
						|
 | 
						|
	return certificate, nil
 | 
						|
}
 | 
						|
 | 
						|
type TLSConfig struct {
 | 
						|
	Insecure         bool             `json:"allowInsecure"`
 | 
						|
	InsecureCiphers  bool             `json:"allowInsecureCiphers"`
 | 
						|
	Certs            []*TLSCertConfig `json:"certificates"`
 | 
						|
	ServerName       string           `json:"serverName"`
 | 
						|
	ALPN             *StringList      `json:"alpn"`
 | 
						|
	DiableSystemRoot bool             `json:"disableSystemRoot"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable.
 | 
						|
func (c *TLSConfig) Build() (proto.Message, error) {
 | 
						|
	config := new(tls.Config)
 | 
						|
	config.Certificate = make([]*tls.Certificate, len(c.Certs))
 | 
						|
	for idx, certConf := range c.Certs {
 | 
						|
		cert, err := certConf.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		config.Certificate[idx] = cert
 | 
						|
	}
 | 
						|
	serverName := c.ServerName
 | 
						|
	config.AllowInsecure = c.Insecure
 | 
						|
	config.AllowInsecureCiphers = c.InsecureCiphers
 | 
						|
	if len(c.ServerName) > 0 {
 | 
						|
		config.ServerName = serverName
 | 
						|
	}
 | 
						|
	if c.ALPN != nil && len(*c.ALPN) > 0 {
 | 
						|
		config.NextProtocol = []string(*c.ALPN)
 | 
						|
	}
 | 
						|
	config.DisableSystemRoot = c.DiableSystemRoot
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type TransportProtocol string
 | 
						|
 | 
						|
// Build implements Buildable.
 | 
						|
func (p TransportProtocol) Build() (string, error) {
 | 
						|
	switch strings.ToLower(string(p)) {
 | 
						|
	case "tcp":
 | 
						|
		return "tcp", nil
 | 
						|
	case "kcp", "mkcp":
 | 
						|
		return "mkcp", nil
 | 
						|
	case "ws", "websocket":
 | 
						|
		return "websocket", nil
 | 
						|
	case "h2", "http":
 | 
						|
		return "http", nil
 | 
						|
	case "ds", "domainsocket":
 | 
						|
		return "domainsocket", nil
 | 
						|
	case "quic":
 | 
						|
		return "quic", nil
 | 
						|
	default:
 | 
						|
		return "", newError("Config: unknown transport protocol: ", p)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type SocketConfig struct {
 | 
						|
	Mark   int32  `json:"mark"`
 | 
						|
	TFO    *bool  `json:"tcpFastOpen"`
 | 
						|
	TProxy string `json:"tproxy"`
 | 
						|
}
 | 
						|
 | 
						|
func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
 | 
						|
	var tfoSettings internet.SocketConfig_TCPFastOpenState
 | 
						|
	if c.TFO != nil {
 | 
						|
		if *c.TFO {
 | 
						|
			tfoSettings = internet.SocketConfig_Enable
 | 
						|
		} else {
 | 
						|
			tfoSettings = internet.SocketConfig_Disable
 | 
						|
		}
 | 
						|
	}
 | 
						|
	var tproxy internet.SocketConfig_TProxyMode
 | 
						|
	switch strings.ToLower(c.TProxy) {
 | 
						|
	case "tproxy":
 | 
						|
		tproxy = internet.SocketConfig_TProxy
 | 
						|
	case "redirect":
 | 
						|
		tproxy = internet.SocketConfig_Redirect
 | 
						|
	default:
 | 
						|
		tproxy = internet.SocketConfig_Off
 | 
						|
	}
 | 
						|
 | 
						|
	return &internet.SocketConfig{
 | 
						|
		Mark:   c.Mark,
 | 
						|
		Tfo:    tfoSettings,
 | 
						|
		Tproxy: tproxy,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
type StreamConfig struct {
 | 
						|
	Network        *TransportProtocol  `json:"network"`
 | 
						|
	Security       string              `json:"security"`
 | 
						|
	TLSSettings    *TLSConfig          `json:"tlsSettings"`
 | 
						|
	TCPSettings    *TCPConfig          `json:"tcpSettings"`
 | 
						|
	KCPSettings    *KCPConfig          `json:"kcpSettings"`
 | 
						|
	WSSettings     *WebSocketConfig    `json:"wsSettings"`
 | 
						|
	HTTPSettings   *HTTPConfig         `json:"httpSettings"`
 | 
						|
	DSSettings     *DomainSocketConfig `json:"dsSettings"`
 | 
						|
	QUICSettings   *QUICConfig         `json:"quicSettings"`
 | 
						|
	SocketSettings *SocketConfig       `json:"sockopt"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable.
 | 
						|
func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
 | 
						|
	config := &internet.StreamConfig{
 | 
						|
		ProtocolName: "tcp",
 | 
						|
	}
 | 
						|
	if c.Network != nil {
 | 
						|
		protocol, err := (*c.Network).Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		config.ProtocolName = protocol
 | 
						|
	}
 | 
						|
	if strings.ToLower(c.Security) == "tls" {
 | 
						|
		tlsSettings := c.TLSSettings
 | 
						|
		if tlsSettings == nil {
 | 
						|
			tlsSettings = &TLSConfig{}
 | 
						|
		}
 | 
						|
		ts, err := tlsSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("Failed to build TLS config.").Base(err)
 | 
						|
		}
 | 
						|
		tm := serial.ToTypedMessage(ts)
 | 
						|
		config.SecuritySettings = append(config.SecuritySettings, tm)
 | 
						|
		config.SecurityType = tm.Type
 | 
						|
	}
 | 
						|
	if c.TCPSettings != nil {
 | 
						|
		ts, err := c.TCPSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("Failed to build TCP config.").Base(err)
 | 
						|
		}
 | 
						|
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
						|
			ProtocolName: "tcp",
 | 
						|
			Settings:     serial.ToTypedMessage(ts),
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if c.KCPSettings != nil {
 | 
						|
		ts, err := c.KCPSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("Failed to build mKCP config.").Base(err)
 | 
						|
		}
 | 
						|
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
						|
			ProtocolName: "mkcp",
 | 
						|
			Settings:     serial.ToTypedMessage(ts),
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if c.WSSettings != nil {
 | 
						|
		ts, err := c.WSSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("Failed to build WebSocket config.").Base(err)
 | 
						|
		}
 | 
						|
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
						|
			ProtocolName: "websocket",
 | 
						|
			Settings:     serial.ToTypedMessage(ts),
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if c.HTTPSettings != nil {
 | 
						|
		ts, err := c.HTTPSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("Failed to build HTTP config.").Base(err)
 | 
						|
		}
 | 
						|
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
						|
			ProtocolName: "http",
 | 
						|
			Settings:     serial.ToTypedMessage(ts),
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if c.DSSettings != nil {
 | 
						|
		ds, err := c.DSSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("Failed to build DomainSocket config.").Base(err)
 | 
						|
		}
 | 
						|
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
						|
			ProtocolName: "domainsocket",
 | 
						|
			Settings:     serial.ToTypedMessage(ds),
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if c.QUICSettings != nil {
 | 
						|
		qs, err := c.QUICSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("failed to build QUIC config").Base(err)
 | 
						|
		}
 | 
						|
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
						|
			ProtocolName: "quic",
 | 
						|
			Settings:     serial.ToTypedMessage(qs),
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if c.SocketSettings != nil {
 | 
						|
		ss, err := c.SocketSettings.Build()
 | 
						|
		if err != nil {
 | 
						|
			return nil, newError("failed to build sockopt").Base(err)
 | 
						|
		}
 | 
						|
		config.SocketSettings = ss
 | 
						|
	}
 | 
						|
	return config, nil
 | 
						|
}
 | 
						|
 | 
						|
type ProxyConfig struct {
 | 
						|
	Tag string `json:"tag"`
 | 
						|
}
 | 
						|
 | 
						|
// Build implements Buildable.
 | 
						|
func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
 | 
						|
	if len(v.Tag) == 0 {
 | 
						|
		return nil, newError("Proxy tag is not set.")
 | 
						|
	}
 | 
						|
	return &internet.ProxyConfig{
 | 
						|
		Tag: v.Tag,
 | 
						|
	}, nil
 | 
						|
}
 |