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