github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/infra/conf/transport_internet.go (about)

     1  package conf
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"math"
     8  	"net/url"
     9  	"runtime"
    10  	"strconv"
    11  	"strings"
    12  	"syscall"
    13  
    14  	"github.com/xtls/xray-core/common/net"
    15  	"github.com/xtls/xray-core/common/platform/filesystem"
    16  	"github.com/xtls/xray-core/common/protocol"
    17  	"github.com/xtls/xray-core/common/serial"
    18  	"github.com/xtls/xray-core/transport/internet"
    19  	"github.com/xtls/xray-core/transport/internet/domainsocket"
    20  	httpheader "github.com/xtls/xray-core/transport/internet/headers/http"
    21  	"github.com/xtls/xray-core/transport/internet/http"
    22  	"github.com/xtls/xray-core/transport/internet/httpupgrade"
    23  	"github.com/xtls/xray-core/transport/internet/kcp"
    24  	"github.com/xtls/xray-core/transport/internet/quic"
    25  	"github.com/xtls/xray-core/transport/internet/reality"
    26  	"github.com/xtls/xray-core/transport/internet/tcp"
    27  	"github.com/xtls/xray-core/transport/internet/tls"
    28  	"github.com/xtls/xray-core/transport/internet/websocket"
    29  	"google.golang.org/protobuf/proto"
    30  )
    31  
    32  var (
    33  	kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
    34  		"none":         func() interface{} { return new(NoOpAuthenticator) },
    35  		"srtp":         func() interface{} { return new(SRTPAuthenticator) },
    36  		"utp":          func() interface{} { return new(UTPAuthenticator) },
    37  		"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
    38  		"dtls":         func() interface{} { return new(DTLSAuthenticator) },
    39  		"wireguard":    func() interface{} { return new(WireguardAuthenticator) },
    40  		"dns":          func() interface{} { return new(DNSAuthenticator) },
    41  	}, "type", "")
    42  
    43  	tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
    44  		"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
    45  		"http": func() interface{} { return new(Authenticator) },
    46  	}, "type", "")
    47  )
    48  
    49  type KCPConfig struct {
    50  	Mtu             *uint32         `json:"mtu"`
    51  	Tti             *uint32         `json:"tti"`
    52  	UpCap           *uint32         `json:"uplinkCapacity"`
    53  	DownCap         *uint32         `json:"downlinkCapacity"`
    54  	Congestion      *bool           `json:"congestion"`
    55  	ReadBufferSize  *uint32         `json:"readBufferSize"`
    56  	WriteBufferSize *uint32         `json:"writeBufferSize"`
    57  	HeaderConfig    json.RawMessage `json:"header"`
    58  	Seed            *string         `json:"seed"`
    59  }
    60  
    61  // Build implements Buildable.
    62  func (c *KCPConfig) Build() (proto.Message, error) {
    63  	config := new(kcp.Config)
    64  
    65  	if c.Mtu != nil {
    66  		mtu := *c.Mtu
    67  		if mtu < 576 || mtu > 1460 {
    68  			return nil, newError("invalid mKCP MTU size: ", mtu).AtError()
    69  		}
    70  		config.Mtu = &kcp.MTU{Value: mtu}
    71  	}
    72  	if c.Tti != nil {
    73  		tti := *c.Tti
    74  		if tti < 10 || tti > 100 {
    75  			return nil, newError("invalid mKCP TTI: ", tti).AtError()
    76  		}
    77  		config.Tti = &kcp.TTI{Value: tti}
    78  	}
    79  	if c.UpCap != nil {
    80  		config.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap}
    81  	}
    82  	if c.DownCap != nil {
    83  		config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap}
    84  	}
    85  	if c.Congestion != nil {
    86  		config.Congestion = *c.Congestion
    87  	}
    88  	if c.ReadBufferSize != nil {
    89  		size := *c.ReadBufferSize
    90  		if size > 0 {
    91  			config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}
    92  		} else {
    93  			config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}
    94  		}
    95  	}
    96  	if c.WriteBufferSize != nil {
    97  		size := *c.WriteBufferSize
    98  		if size > 0 {
    99  			config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}
   100  		} else {
   101  			config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
   102  		}
   103  	}
   104  	if len(c.HeaderConfig) > 0 {
   105  		headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
   106  		if err != nil {
   107  			return nil, newError("invalid mKCP header config.").Base(err).AtError()
   108  		}
   109  		ts, err := headerConfig.(Buildable).Build()
   110  		if err != nil {
   111  			return nil, newError("invalid mKCP header config").Base(err).AtError()
   112  		}
   113  		config.HeaderConfig = serial.ToTypedMessage(ts)
   114  	}
   115  
   116  	if c.Seed != nil {
   117  		config.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}
   118  	}
   119  
   120  	return config, nil
   121  }
   122  
   123  type TCPConfig struct {
   124  	HeaderConfig        json.RawMessage `json:"header"`
   125  	AcceptProxyProtocol bool            `json:"acceptProxyProtocol"`
   126  }
   127  
   128  // Build implements Buildable.
   129  func (c *TCPConfig) Build() (proto.Message, error) {
   130  	config := new(tcp.Config)
   131  	if len(c.HeaderConfig) > 0 {
   132  		headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
   133  		if err != nil {
   134  			return nil, newError("invalid TCP header config").Base(err).AtError()
   135  		}
   136  		ts, err := headerConfig.(Buildable).Build()
   137  		if err != nil {
   138  			return nil, newError("invalid TCP header config").Base(err).AtError()
   139  		}
   140  		config.HeaderSettings = serial.ToTypedMessage(ts)
   141  	}
   142  	if c.AcceptProxyProtocol {
   143  		config.AcceptProxyProtocol = c.AcceptProxyProtocol
   144  	}
   145  	return config, nil
   146  }
   147  
   148  type WebSocketConfig struct {
   149  	Host                string            `json:"host"`
   150  	Path                string            `json:"path"`
   151  	Headers             map[string]string `json:"headers"`
   152  	AcceptProxyProtocol bool              `json:"acceptProxyProtocol"`
   153  }
   154  
   155  // Build implements Buildable.
   156  func (c *WebSocketConfig) Build() (proto.Message, error) {
   157  	path := c.Path
   158  	var ed uint32
   159  	if u, err := url.Parse(path); err == nil {
   160  		if q := u.Query(); q.Get("ed") != "" {
   161  			Ed, _ := strconv.Atoi(q.Get("ed"))
   162  			ed = uint32(Ed)
   163  			q.Del("ed")
   164  			u.RawQuery = q.Encode()
   165  			path = u.String()
   166  		}
   167  	}
   168  	// If http host is not set in the Host field, but in headers field, we add it to Host Field here.
   169  	// If we don't do that, http host will be overwritten as address.
   170  	// Host priority: Host field > headers field > address.
   171  	if c.Host == "" && c.Headers["host"] != "" {
   172  		c.Host = c.Headers["host"]
   173  	} else if c.Host == "" && c.Headers["Host"] != "" {
   174  		c.Host = c.Headers["Host"]
   175  	}
   176  	config := &websocket.Config{
   177  		Path:                path,
   178  		Host:                c.Host,
   179  		Header:              c.Headers,
   180  		AcceptProxyProtocol: c.AcceptProxyProtocol,
   181  		Ed:                  ed,
   182  	}
   183  	return config, nil
   184  }
   185  
   186  type HttpUpgradeConfig struct {
   187  	Host                string            `json:"host"`
   188  	Path                string            `json:"path"`
   189  	Headers             map[string]string `json:"headers"`
   190  	AcceptProxyProtocol bool              `json:"acceptProxyProtocol"`
   191  }
   192  
   193  // Build implements Buildable.
   194  func (c *HttpUpgradeConfig) Build() (proto.Message, error) {
   195  	path := c.Path
   196  	var ed uint32
   197  	if u, err := url.Parse(path); err == nil {
   198  		if q := u.Query(); q.Get("ed") != "" {
   199  			Ed, _ := strconv.Atoi(q.Get("ed"))
   200  			ed = uint32(Ed)
   201  			q.Del("ed")
   202  			u.RawQuery = q.Encode()
   203  			path = u.String()
   204  		}
   205  	}
   206  	// If http host is not set in the Host field, but in headers field, we add it to Host Field here.
   207  	// If we don't do that, http host will be overwritten as address.
   208  	// Host priority: Host field > headers field > address.
   209  	if c.Host == "" && c.Headers["host"] != "" {
   210  		c.Host = c.Headers["host"]
   211  	} else if c.Host == "" && c.Headers["Host"] != "" {
   212  		c.Host = c.Headers["Host"]
   213  	}
   214  	config := &httpupgrade.Config{
   215  		Path:                path,
   216  		Host:                c.Host,
   217  		Header:              c.Headers,
   218  		AcceptProxyProtocol: c.AcceptProxyProtocol,
   219  		Ed:                  ed,
   220  	}
   221  	return config, nil
   222  }
   223  
   224  type HTTPConfig struct {
   225  	Host               *StringList            `json:"host"`
   226  	Path               string                 `json:"path"`
   227  	ReadIdleTimeout    int32                  `json:"read_idle_timeout"`
   228  	HealthCheckTimeout int32                  `json:"health_check_timeout"`
   229  	Method             string                 `json:"method"`
   230  	Headers            map[string]*StringList `json:"headers"`
   231  }
   232  
   233  // Build implements Buildable.
   234  func (c *HTTPConfig) Build() (proto.Message, error) {
   235  	if c.ReadIdleTimeout <= 0 {
   236  		c.ReadIdleTimeout = 0
   237  	}
   238  	if c.HealthCheckTimeout <= 0 {
   239  		c.HealthCheckTimeout = 0
   240  	}
   241  	config := &http.Config{
   242  		Path:               c.Path,
   243  		IdleTimeout:        c.ReadIdleTimeout,
   244  		HealthCheckTimeout: c.HealthCheckTimeout,
   245  	}
   246  	if c.Host != nil {
   247  		config.Host = []string(*c.Host)
   248  	}
   249  	if c.Method != "" {
   250  		config.Method = c.Method
   251  	}
   252  	if len(c.Headers) > 0 {
   253  		config.Header = make([]*httpheader.Header, 0, len(c.Headers))
   254  		headerNames := sortMapKeys(c.Headers)
   255  		for _, key := range headerNames {
   256  			value := c.Headers[key]
   257  			if value == nil {
   258  				return nil, newError("empty HTTP header value: " + key).AtError()
   259  			}
   260  			config.Header = append(config.Header, &httpheader.Header{
   261  				Name:  key,
   262  				Value: append([]string(nil), (*value)...),
   263  			})
   264  		}
   265  	}
   266  	return config, nil
   267  }
   268  
   269  type QUICConfig struct {
   270  	Header   json.RawMessage `json:"header"`
   271  	Security string          `json:"security"`
   272  	Key      string          `json:"key"`
   273  }
   274  
   275  // Build implements Buildable.
   276  func (c *QUICConfig) Build() (proto.Message, error) {
   277  	config := &quic.Config{
   278  		Key: c.Key,
   279  	}
   280  
   281  	if len(c.Header) > 0 {
   282  		headerConfig, _, err := kcpHeaderLoader.Load(c.Header)
   283  		if err != nil {
   284  			return nil, newError("invalid QUIC header config.").Base(err).AtError()
   285  		}
   286  		ts, err := headerConfig.(Buildable).Build()
   287  		if err != nil {
   288  			return nil, newError("invalid QUIC header config").Base(err).AtError()
   289  		}
   290  		config.Header = serial.ToTypedMessage(ts)
   291  	}
   292  
   293  	var st protocol.SecurityType
   294  	switch strings.ToLower(c.Security) {
   295  	case "aes-128-gcm":
   296  		st = protocol.SecurityType_AES128_GCM
   297  	case "chacha20-poly1305":
   298  		st = protocol.SecurityType_CHACHA20_POLY1305
   299  	default:
   300  		st = protocol.SecurityType_NONE
   301  	}
   302  
   303  	config.Security = &protocol.SecurityConfig{
   304  		Type: st,
   305  	}
   306  
   307  	return config, nil
   308  }
   309  
   310  type DomainSocketConfig struct {
   311  	Path     string `json:"path"`
   312  	Abstract bool   `json:"abstract"`
   313  	Padding  bool   `json:"padding"`
   314  }
   315  
   316  // Build implements Buildable.
   317  func (c *DomainSocketConfig) Build() (proto.Message, error) {
   318  	return &domainsocket.Config{
   319  		Path:     c.Path,
   320  		Abstract: c.Abstract,
   321  		Padding:  c.Padding,
   322  	}, nil
   323  }
   324  
   325  func readFileOrString(f string, s []string) ([]byte, error) {
   326  	if len(f) > 0 {
   327  		return filesystem.ReadFile(f)
   328  	}
   329  	if len(s) > 0 {
   330  		return []byte(strings.Join(s, "\n")), nil
   331  	}
   332  	return nil, newError("both file and bytes are empty.")
   333  }
   334  
   335  type TLSCertConfig struct {
   336  	CertFile       string   `json:"certificateFile"`
   337  	CertStr        []string `json:"certificate"`
   338  	KeyFile        string   `json:"keyFile"`
   339  	KeyStr         []string `json:"key"`
   340  	Usage          string   `json:"usage"`
   341  	OcspStapling   uint64   `json:"ocspStapling"`
   342  	OneTimeLoading bool     `json:"oneTimeLoading"`
   343  }
   344  
   345  // Build implements Buildable.
   346  func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
   347  	certificate := new(tls.Certificate)
   348  
   349  	cert, err := readFileOrString(c.CertFile, c.CertStr)
   350  	if err != nil {
   351  		return nil, newError("failed to parse certificate").Base(err)
   352  	}
   353  	certificate.Certificate = cert
   354  	certificate.CertificatePath = c.CertFile
   355  
   356  	if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
   357  		key, err := readFileOrString(c.KeyFile, c.KeyStr)
   358  		if err != nil {
   359  			return nil, newError("failed to parse key").Base(err)
   360  		}
   361  		certificate.Key = key
   362  		certificate.KeyPath = c.KeyFile
   363  	}
   364  
   365  	switch strings.ToLower(c.Usage) {
   366  	case "encipherment":
   367  		certificate.Usage = tls.Certificate_ENCIPHERMENT
   368  	case "verify":
   369  		certificate.Usage = tls.Certificate_AUTHORITY_VERIFY
   370  	case "issue":
   371  		certificate.Usage = tls.Certificate_AUTHORITY_ISSUE
   372  	default:
   373  		certificate.Usage = tls.Certificate_ENCIPHERMENT
   374  	}
   375  	if certificate.KeyPath == "" && certificate.CertificatePath == "" {
   376  		certificate.OneTimeLoading = true
   377  	} else {
   378  		certificate.OneTimeLoading = c.OneTimeLoading
   379  	}
   380  	certificate.OcspStapling = c.OcspStapling
   381  
   382  	return certificate, nil
   383  }
   384  
   385  type TLSConfig struct {
   386  	Insecure                             bool             `json:"allowInsecure"`
   387  	Certs                                []*TLSCertConfig `json:"certificates"`
   388  	ServerName                           string           `json:"serverName"`
   389  	ALPN                                 *StringList      `json:"alpn"`
   390  	EnableSessionResumption              bool             `json:"enableSessionResumption"`
   391  	DisableSystemRoot                    bool             `json:"disableSystemRoot"`
   392  	MinVersion                           string           `json:"minVersion"`
   393  	MaxVersion                           string           `json:"maxVersion"`
   394  	CipherSuites                         string           `json:"cipherSuites"`
   395  	Fingerprint                          string           `json:"fingerprint"`
   396  	RejectUnknownSNI                     bool             `json:"rejectUnknownSni"`
   397  	PinnedPeerCertificateChainSha256     *[]string        `json:"pinnedPeerCertificateChainSha256"`
   398  	PinnedPeerCertificatePublicKeySha256 *[]string        `json:"pinnedPeerCertificatePublicKeySha256"`
   399  	MasterKeyLog                         string           `json:"masterKeyLog"`
   400  }
   401  
   402  // Build implements Buildable.
   403  func (c *TLSConfig) Build() (proto.Message, error) {
   404  	config := new(tls.Config)
   405  	config.Certificate = make([]*tls.Certificate, len(c.Certs))
   406  	for idx, certConf := range c.Certs {
   407  		cert, err := certConf.Build()
   408  		if err != nil {
   409  			return nil, err
   410  		}
   411  		config.Certificate[idx] = cert
   412  	}
   413  	serverName := c.ServerName
   414  	config.AllowInsecure = c.Insecure
   415  	if len(c.ServerName) > 0 {
   416  		config.ServerName = serverName
   417  	}
   418  	if c.ALPN != nil && len(*c.ALPN) > 0 {
   419  		config.NextProtocol = []string(*c.ALPN)
   420  	}
   421  	config.EnableSessionResumption = c.EnableSessionResumption
   422  	config.DisableSystemRoot = c.DisableSystemRoot
   423  	config.MinVersion = c.MinVersion
   424  	config.MaxVersion = c.MaxVersion
   425  	config.CipherSuites = c.CipherSuites
   426  	config.Fingerprint = strings.ToLower(c.Fingerprint)
   427  	if config.Fingerprint != "" && tls.GetFingerprint(config.Fingerprint) == nil {
   428  		return nil, newError(`unknown fingerprint: `, config.Fingerprint)
   429  	}
   430  	config.RejectUnknownSni = c.RejectUnknownSNI
   431  
   432  	if c.PinnedPeerCertificateChainSha256 != nil {
   433  		config.PinnedPeerCertificateChainSha256 = [][]byte{}
   434  		for _, v := range *c.PinnedPeerCertificateChainSha256 {
   435  			hashValue, err := base64.StdEncoding.DecodeString(v)
   436  			if err != nil {
   437  				return nil, err
   438  			}
   439  			config.PinnedPeerCertificateChainSha256 = append(config.PinnedPeerCertificateChainSha256, hashValue)
   440  		}
   441  	}
   442  
   443  	if c.PinnedPeerCertificatePublicKeySha256 != nil {
   444  		config.PinnedPeerCertificatePublicKeySha256 = [][]byte{}
   445  		for _, v := range *c.PinnedPeerCertificatePublicKeySha256 {
   446  			hashValue, err := base64.StdEncoding.DecodeString(v)
   447  			if err != nil {
   448  				return nil, err
   449  			}
   450  			config.PinnedPeerCertificatePublicKeySha256 = append(config.PinnedPeerCertificatePublicKeySha256, hashValue)
   451  		}
   452  	}
   453  
   454  	config.MasterKeyLog = c.MasterKeyLog
   455  
   456  	return config, nil
   457  }
   458  
   459  type REALITYConfig struct {
   460  	Show         bool            `json:"show"`
   461  	MasterKeyLog string          `json:"masterKeyLog"`
   462  	Dest         json.RawMessage `json:"dest"`
   463  	Type         string          `json:"type"`
   464  	Xver         uint64          `json:"xver"`
   465  	ServerNames  []string        `json:"serverNames"`
   466  	PrivateKey   string          `json:"privateKey"`
   467  	MinClientVer string          `json:"minClientVer"`
   468  	MaxClientVer string          `json:"maxClientVer"`
   469  	MaxTimeDiff  uint64          `json:"maxTimeDiff"`
   470  	ShortIds     []string        `json:"shortIds"`
   471  
   472  	Fingerprint string `json:"fingerprint"`
   473  	ServerName  string `json:"serverName"`
   474  	PublicKey   string `json:"publicKey"`
   475  	ShortId     string `json:"shortId"`
   476  	SpiderX     string `json:"spiderX"`
   477  }
   478  
   479  func (c *REALITYConfig) Build() (proto.Message, error) {
   480  	config := new(reality.Config)
   481  	config.Show = c.Show
   482  	config.MasterKeyLog = c.MasterKeyLog
   483  	var err error
   484  	if c.Dest != nil {
   485  		var i uint16
   486  		var s string
   487  		if err = json.Unmarshal(c.Dest, &i); err == nil {
   488  			s = strconv.Itoa(int(i))
   489  		} else {
   490  			_ = json.Unmarshal(c.Dest, &s)
   491  		}
   492  		if c.Type == "" && s != "" {
   493  			switch s[0] {
   494  			case '@', '/':
   495  				c.Type = "unix"
   496  				if s[0] == '@' && len(s) > 1 && s[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
   497  					fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
   498  					copy(fullAddr, s[1:])
   499  					s = string(fullAddr)
   500  				}
   501  			default:
   502  				if _, err = strconv.Atoi(s); err == nil {
   503  					s = "127.0.0.1:" + s
   504  				}
   505  				if _, _, err = net.SplitHostPort(s); err == nil {
   506  					c.Type = "tcp"
   507  				}
   508  			}
   509  		}
   510  		if c.Type == "" {
   511  			return nil, newError(`please fill in a valid value for "dest"`)
   512  		}
   513  		if c.Xver > 2 {
   514  			return nil, newError(`invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
   515  		}
   516  		if len(c.ServerNames) == 0 {
   517  			return nil, newError(`empty "serverNames"`)
   518  		}
   519  		if c.PrivateKey == "" {
   520  			return nil, newError(`empty "privateKey"`)
   521  		}
   522  		if config.PrivateKey, err = base64.RawURLEncoding.DecodeString(c.PrivateKey); err != nil || len(config.PrivateKey) != 32 {
   523  			return nil, newError(`invalid "privateKey": `, c.PrivateKey)
   524  		}
   525  		if c.MinClientVer != "" {
   526  			config.MinClientVer = make([]byte, 3)
   527  			var u uint64
   528  			for i, s := range strings.Split(c.MinClientVer, ".") {
   529  				if i == 3 {
   530  					return nil, newError(`invalid "minClientVer": `, c.MinClientVer)
   531  				}
   532  				if u, err = strconv.ParseUint(s, 10, 8); err != nil {
   533  					return nil, newError(`"minClientVer[`, i, `]" should be lesser than 256`)
   534  				} else {
   535  					config.MinClientVer[i] = byte(u)
   536  				}
   537  			}
   538  		}
   539  		if c.MaxClientVer != "" {
   540  			config.MaxClientVer = make([]byte, 3)
   541  			var u uint64
   542  			for i, s := range strings.Split(c.MaxClientVer, ".") {
   543  				if i == 3 {
   544  					return nil, newError(`invalid "maxClientVer": `, c.MaxClientVer)
   545  				}
   546  				if u, err = strconv.ParseUint(s, 10, 8); err != nil {
   547  					return nil, newError(`"maxClientVer[`, i, `]" should be lesser than 256`)
   548  				} else {
   549  					config.MaxClientVer[i] = byte(u)
   550  				}
   551  			}
   552  		}
   553  		if len(c.ShortIds) == 0 {
   554  			return nil, newError(`empty "shortIds"`)
   555  		}
   556  		config.ShortIds = make([][]byte, len(c.ShortIds))
   557  		for i, s := range c.ShortIds {
   558  			config.ShortIds[i] = make([]byte, 8)
   559  			if _, err = hex.Decode(config.ShortIds[i], []byte(s)); err != nil {
   560  				return nil, newError(`invalid "shortIds[`, i, `]": `, s)
   561  			}
   562  		}
   563  		config.Dest = s
   564  		config.Type = c.Type
   565  		config.Xver = c.Xver
   566  		config.ServerNames = c.ServerNames
   567  		config.MaxTimeDiff = c.MaxTimeDiff
   568  	} else {
   569  		if c.Fingerprint == "" {
   570  			return nil, newError(`empty "fingerprint"`)
   571  		}
   572  		if config.Fingerprint = strings.ToLower(c.Fingerprint); tls.GetFingerprint(config.Fingerprint) == nil {
   573  			return nil, newError(`unknown "fingerprint": `, config.Fingerprint)
   574  		}
   575  		if config.Fingerprint == "hellogolang" {
   576  			return nil, newError(`invalid "fingerprint": `, config.Fingerprint)
   577  		}
   578  		if len(c.ServerNames) != 0 {
   579  			return nil, newError(`non-empty "serverNames", please use "serverName" instead`)
   580  		}
   581  		if c.PublicKey == "" {
   582  			return nil, newError(`empty "publicKey"`)
   583  		}
   584  		if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 {
   585  			return nil, newError(`invalid "publicKey": `, c.PublicKey)
   586  		}
   587  		if len(c.ShortIds) != 0 {
   588  			return nil, newError(`non-empty "shortIds", please use "shortId" instead`)
   589  		}
   590  		config.ShortId = make([]byte, 8)
   591  		if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
   592  			return nil, newError(`invalid "shortId": `, c.ShortId)
   593  		}
   594  		if c.SpiderX == "" {
   595  			c.SpiderX = "/"
   596  		}
   597  		if c.SpiderX[0] != '/' {
   598  			return nil, newError(`invalid "spiderX": `, c.SpiderX)
   599  		}
   600  		config.SpiderY = make([]int64, 10)
   601  		u, _ := url.Parse(c.SpiderX)
   602  		q := u.Query()
   603  		parse := func(param string, index int) {
   604  			if q.Get(param) != "" {
   605  				s := strings.Split(q.Get(param), "-")
   606  				if len(s) == 1 {
   607  					config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
   608  					config.SpiderY[index+1], _ = strconv.ParseInt(s[0], 10, 64)
   609  				} else {
   610  					config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
   611  					config.SpiderY[index+1], _ = strconv.ParseInt(s[1], 10, 64)
   612  				}
   613  			}
   614  			q.Del(param)
   615  		}
   616  		parse("p", 0) // padding
   617  		parse("c", 2) // concurrency
   618  		parse("t", 4) // times
   619  		parse("i", 6) // interval
   620  		parse("r", 8) // return
   621  		u.RawQuery = q.Encode()
   622  		config.SpiderX = u.String()
   623  		config.ServerName = c.ServerName
   624  	}
   625  	return config, nil
   626  }
   627  
   628  type TransportProtocol string
   629  
   630  // Build implements Buildable.
   631  func (p TransportProtocol) Build() (string, error) {
   632  	switch strings.ToLower(string(p)) {
   633  	case "tcp":
   634  		return "tcp", nil
   635  	case "kcp", "mkcp":
   636  		return "mkcp", nil
   637  	case "ws", "websocket":
   638  		return "websocket", nil
   639  	case "h2", "http":
   640  		return "http", nil
   641  	case "ds", "domainsocket":
   642  		return "domainsocket", nil
   643  	case "quic":
   644  		return "quic", nil
   645  	case "grpc", "gun":
   646  		return "grpc", nil
   647  	case "httpupgrade":
   648  		return "httpupgrade", nil
   649  	default:
   650  		return "", newError("Config: unknown transport protocol: ", p)
   651  	}
   652  }
   653  
   654  type SocketConfig struct {
   655  	Mark                 int32       `json:"mark"`
   656  	TFO                  interface{} `json:"tcpFastOpen"`
   657  	TProxy               string      `json:"tproxy"`
   658  	AcceptProxyProtocol  bool        `json:"acceptProxyProtocol"`
   659  	DomainStrategy       string      `json:"domainStrategy"`
   660  	DialerProxy          string      `json:"dialerProxy"`
   661  	TCPKeepAliveInterval int32       `json:"tcpKeepAliveInterval"`
   662  	TCPKeepAliveIdle     int32       `json:"tcpKeepAliveIdle"`
   663  	TCPCongestion        string      `json:"tcpCongestion"`
   664  	TCPWindowClamp       int32       `json:"tcpWindowClamp"`
   665  	TCPMaxSeg            int32       `json:"tcpMaxSeg"`
   666  	TcpNoDelay           bool        `json:"tcpNoDelay"`
   667  	TCPUserTimeout       int32       `json:"tcpUserTimeout"`
   668  	V6only               bool        `json:"v6only"`
   669  	Interface            string      `json:"interface"`
   670  	TcpMptcp             bool        `json:"tcpMptcp"`
   671  }
   672  
   673  // Build implements Buildable.
   674  func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
   675  	tfo := int32(0) // don't invoke setsockopt() for TFO
   676  	if c.TFO != nil {
   677  		switch v := c.TFO.(type) {
   678  		case bool:
   679  			if v {
   680  				tfo = 256
   681  			} else {
   682  				tfo = -1 // TFO need to be disabled
   683  			}
   684  		case float64:
   685  			tfo = int32(math.Min(v, math.MaxInt32))
   686  		default:
   687  			return nil, newError("tcpFastOpen: only boolean and integer value is acceptable")
   688  		}
   689  	}
   690  	var tproxy internet.SocketConfig_TProxyMode
   691  	switch strings.ToLower(c.TProxy) {
   692  	case "tproxy":
   693  		tproxy = internet.SocketConfig_TProxy
   694  	case "redirect":
   695  		tproxy = internet.SocketConfig_Redirect
   696  	default:
   697  		tproxy = internet.SocketConfig_Off
   698  	}
   699  
   700  	dStrategy := internet.DomainStrategy_AS_IS
   701  	switch strings.ToLower(c.DomainStrategy) {
   702  	case "asis", "":
   703  		dStrategy = internet.DomainStrategy_AS_IS
   704  	case "useip":
   705  		dStrategy = internet.DomainStrategy_USE_IP
   706  	case "useipv4":
   707  		dStrategy = internet.DomainStrategy_USE_IP4
   708  	case "useipv6":
   709  		dStrategy = internet.DomainStrategy_USE_IP6
   710  	case "useipv4v6":
   711  		dStrategy = internet.DomainStrategy_USE_IP46
   712  	case "useipv6v4":
   713  		dStrategy = internet.DomainStrategy_USE_IP64
   714  	case "forceip":
   715  		dStrategy = internet.DomainStrategy_FORCE_IP
   716  	case "forceipv4":
   717  		dStrategy = internet.DomainStrategy_FORCE_IP4
   718  	case "forceipv6":
   719  		dStrategy = internet.DomainStrategy_FORCE_IP6
   720  	case "forceipv4v6":
   721  		dStrategy = internet.DomainStrategy_FORCE_IP46
   722  	case "forceipv6v4":
   723  		dStrategy = internet.DomainStrategy_FORCE_IP64
   724  	default:
   725  		return nil, newError("unsupported domain strategy: ", c.DomainStrategy)
   726  	}
   727  
   728  	return &internet.SocketConfig{
   729  		Mark:                 c.Mark,
   730  		Tfo:                  tfo,
   731  		Tproxy:               tproxy,
   732  		DomainStrategy:       dStrategy,
   733  		AcceptProxyProtocol:  c.AcceptProxyProtocol,
   734  		DialerProxy:          c.DialerProxy,
   735  		TcpKeepAliveInterval: c.TCPKeepAliveInterval,
   736  		TcpKeepAliveIdle:     c.TCPKeepAliveIdle,
   737  		TcpCongestion:        c.TCPCongestion,
   738  		TcpWindowClamp:       c.TCPWindowClamp,
   739  		TcpMaxSeg:            c.TCPMaxSeg,
   740  		TcpNoDelay:           c.TcpNoDelay,
   741  		TcpUserTimeout:       c.TCPUserTimeout,
   742  		V6Only:               c.V6only,
   743  		Interface:            c.Interface,
   744  		TcpMptcp:             c.TcpMptcp,
   745  	}, nil
   746  }
   747  
   748  type StreamConfig struct {
   749  	Network             *TransportProtocol  `json:"network"`
   750  	Security            string              `json:"security"`
   751  	TLSSettings         *TLSConfig          `json:"tlsSettings"`
   752  	REALITYSettings     *REALITYConfig      `json:"realitySettings"`
   753  	TCPSettings         *TCPConfig          `json:"tcpSettings"`
   754  	KCPSettings         *KCPConfig          `json:"kcpSettings"`
   755  	WSSettings          *WebSocketConfig    `json:"wsSettings"`
   756  	HTTPSettings        *HTTPConfig         `json:"httpSettings"`
   757  	DSSettings          *DomainSocketConfig `json:"dsSettings"`
   758  	QUICSettings        *QUICConfig         `json:"quicSettings"`
   759  	SocketSettings      *SocketConfig       `json:"sockopt"`
   760  	GRPCConfig          *GRPCConfig         `json:"grpcSettings"`
   761  	GUNConfig           *GRPCConfig         `json:"gunSettings"`
   762  	HTTPUPGRADESettings *HttpUpgradeConfig  `json:"httpupgradeSettings"`
   763  }
   764  
   765  // Build implements Buildable.
   766  func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
   767  	config := &internet.StreamConfig{
   768  		ProtocolName: "tcp",
   769  	}
   770  	if c.Network != nil {
   771  		protocol, err := c.Network.Build()
   772  		if err != nil {
   773  			return nil, err
   774  		}
   775  		config.ProtocolName = protocol
   776  	}
   777  	switch strings.ToLower(c.Security) {
   778  	case "", "none":
   779  	case "tls":
   780  		tlsSettings := c.TLSSettings
   781  		if tlsSettings == nil {
   782  			tlsSettings = &TLSConfig{}
   783  		}
   784  		ts, err := tlsSettings.Build()
   785  		if err != nil {
   786  			return nil, newError("Failed to build TLS config.").Base(err)
   787  		}
   788  		tm := serial.ToTypedMessage(ts)
   789  		config.SecuritySettings = append(config.SecuritySettings, tm)
   790  		config.SecurityType = tm.Type
   791  	case "reality":
   792  		if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "grpc" && config.ProtocolName != "domainsocket" {
   793  			return nil, newError("REALITY only supports TCP, H2, gRPC and DomainSocket for now.")
   794  		}
   795  		if c.REALITYSettings == nil {
   796  			return nil, newError(`REALITY: Empty "realitySettings".`)
   797  		}
   798  		ts, err := c.REALITYSettings.Build()
   799  		if err != nil {
   800  			return nil, newError("Failed to build REALITY config.").Base(err)
   801  		}
   802  		tm := serial.ToTypedMessage(ts)
   803  		config.SecuritySettings = append(config.SecuritySettings, tm)
   804  		config.SecurityType = tm.Type
   805  	case "xtls":
   806  		return nil, newError(`Please use VLESS flow "xtls-rprx-vision" with TLS or REALITY.`)
   807  	default:
   808  		return nil, newError(`Unknown security "` + c.Security + `".`)
   809  	}
   810  	if c.TCPSettings != nil {
   811  		ts, err := c.TCPSettings.Build()
   812  		if err != nil {
   813  			return nil, newError("Failed to build TCP config.").Base(err)
   814  		}
   815  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   816  			ProtocolName: "tcp",
   817  			Settings:     serial.ToTypedMessage(ts),
   818  		})
   819  	}
   820  	if c.KCPSettings != nil {
   821  		ts, err := c.KCPSettings.Build()
   822  		if err != nil {
   823  			return nil, newError("Failed to build mKCP config.").Base(err)
   824  		}
   825  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   826  			ProtocolName: "mkcp",
   827  			Settings:     serial.ToTypedMessage(ts),
   828  		})
   829  	}
   830  	if c.WSSettings != nil {
   831  		ts, err := c.WSSettings.Build()
   832  		if err != nil {
   833  			return nil, newError("Failed to build WebSocket config.").Base(err)
   834  		}
   835  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   836  			ProtocolName: "websocket",
   837  			Settings:     serial.ToTypedMessage(ts),
   838  		})
   839  	}
   840  	if c.HTTPSettings != nil {
   841  		ts, err := c.HTTPSettings.Build()
   842  		if err != nil {
   843  			return nil, newError("Failed to build HTTP config.").Base(err)
   844  		}
   845  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   846  			ProtocolName: "http",
   847  			Settings:     serial.ToTypedMessage(ts),
   848  		})
   849  	}
   850  	if c.DSSettings != nil {
   851  		ds, err := c.DSSettings.Build()
   852  		if err != nil {
   853  			return nil, newError("Failed to build DomainSocket config.").Base(err)
   854  		}
   855  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   856  			ProtocolName: "domainsocket",
   857  			Settings:     serial.ToTypedMessage(ds),
   858  		})
   859  	}
   860  	if c.QUICSettings != nil {
   861  		qs, err := c.QUICSettings.Build()
   862  		if err != nil {
   863  			return nil, newError("Failed to build QUIC config").Base(err)
   864  		}
   865  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   866  			ProtocolName: "quic",
   867  			Settings:     serial.ToTypedMessage(qs),
   868  		})
   869  	}
   870  	if c.GRPCConfig == nil {
   871  		c.GRPCConfig = c.GUNConfig
   872  	}
   873  	if c.GRPCConfig != nil {
   874  		gs, err := c.GRPCConfig.Build()
   875  		if err != nil {
   876  			return nil, newError("Failed to build gRPC config.").Base(err)
   877  		}
   878  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   879  			ProtocolName: "grpc",
   880  			Settings:     serial.ToTypedMessage(gs),
   881  		})
   882  	}
   883  	if c.HTTPUPGRADESettings != nil {
   884  		hs, err := c.HTTPUPGRADESettings.Build()
   885  		if err != nil {
   886  			return nil, newError("Failed to build HttpUpgrade config.").Base(err)
   887  		}
   888  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   889  			ProtocolName: "httpupgrade",
   890  			Settings:     serial.ToTypedMessage(hs),
   891  		})
   892  	}
   893  	if c.SocketSettings != nil {
   894  		ss, err := c.SocketSettings.Build()
   895  		if err != nil {
   896  			return nil, newError("Failed to build sockopt").Base(err)
   897  		}
   898  		config.SocketSettings = ss
   899  	}
   900  	return config, nil
   901  }
   902  
   903  type ProxyConfig struct {
   904  	Tag string `json:"tag"`
   905  
   906  	// TransportLayerProxy: For compatibility.
   907  	TransportLayerProxy bool `json:"transportLayer"`
   908  }
   909  
   910  // Build implements Buildable.
   911  func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
   912  	if v.Tag == "" {
   913  		return nil, newError("Proxy tag is not set.")
   914  	}
   915  	return &internet.ProxyConfig{
   916  		Tag:                 v.Tag,
   917  		TransportLayerProxy: v.TransportLayerProxy,
   918  	}, nil
   919  }