github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/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/xmplusdev/xmcore/common/net"
    15  	"github.com/xmplusdev/xmcore/common/platform/filesystem"
    16  	"github.com/xmplusdev/xmcore/common/protocol"
    17  	"github.com/xmplusdev/xmcore/common/serial"
    18  	"github.com/xmplusdev/xmcore/transport/internet"
    19  	"github.com/xmplusdev/xmcore/transport/internet/domainsocket"
    20  	httpheader "github.com/xmplusdev/xmcore/transport/internet/headers/http"
    21  	"github.com/xmplusdev/xmcore/transport/internet/http"
    22  	"github.com/xmplusdev/xmcore/transport/internet/httpupgrade"
    23  	"github.com/xmplusdev/xmcore/transport/internet/kcp"
    24  	"github.com/xmplusdev/xmcore/transport/internet/quic"
    25  	"github.com/xmplusdev/xmcore/transport/internet/reality"
    26  	"github.com/xmplusdev/xmcore/transport/internet/tcp"
    27  	"github.com/xmplusdev/xmcore/transport/internet/tls"
    28  	"github.com/xmplusdev/xmcore/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  	PreferServerCipherSuites             bool             `json:"preferServerCipherSuites"`
   396  	Fingerprint                          string           `json:"fingerprint"`
   397  	RejectUnknownSNI                     bool             `json:"rejectUnknownSni"`
   398  	PinnedPeerCertificateChainSha256     *[]string        `json:"pinnedPeerCertificateChainSha256"`
   399  	PinnedPeerCertificatePublicKeySha256 *[]string        `json:"pinnedPeerCertificatePublicKeySha256"`
   400  	MasterKeyLog                         string           `json:"masterKeyLog"`
   401  }
   402  
   403  // Build implements Buildable.
   404  func (c *TLSConfig) Build() (proto.Message, error) {
   405  	config := new(tls.Config)
   406  	config.Certificate = make([]*tls.Certificate, len(c.Certs))
   407  	for idx, certConf := range c.Certs {
   408  		cert, err := certConf.Build()
   409  		if err != nil {
   410  			return nil, err
   411  		}
   412  		config.Certificate[idx] = cert
   413  	}
   414  	serverName := c.ServerName
   415  	config.AllowInsecure = c.Insecure
   416  	if len(c.ServerName) > 0 {
   417  		config.ServerName = serverName
   418  	}
   419  	if c.ALPN != nil && len(*c.ALPN) > 0 {
   420  		config.NextProtocol = []string(*c.ALPN)
   421  	}
   422  	config.EnableSessionResumption = c.EnableSessionResumption
   423  	config.DisableSystemRoot = c.DisableSystemRoot
   424  	config.MinVersion = c.MinVersion
   425  	config.MaxVersion = c.MaxVersion
   426  	config.CipherSuites = c.CipherSuites
   427  	config.PreferServerCipherSuites = c.PreferServerCipherSuites
   428  	config.Fingerprint = strings.ToLower(c.Fingerprint)
   429  	if config.Fingerprint != "" && tls.GetFingerprint(config.Fingerprint) == nil {
   430  		return nil, newError(`unknown fingerprint: `, config.Fingerprint)
   431  	}
   432  	config.RejectUnknownSni = c.RejectUnknownSNI
   433  
   434  	if c.PinnedPeerCertificateChainSha256 != nil {
   435  		config.PinnedPeerCertificateChainSha256 = [][]byte{}
   436  		for _, v := range *c.PinnedPeerCertificateChainSha256 {
   437  			hashValue, err := base64.StdEncoding.DecodeString(v)
   438  			if err != nil {
   439  				return nil, err
   440  			}
   441  			config.PinnedPeerCertificateChainSha256 = append(config.PinnedPeerCertificateChainSha256, hashValue)
   442  		}
   443  	}
   444  
   445  	if c.PinnedPeerCertificatePublicKeySha256 != nil {
   446  		config.PinnedPeerCertificatePublicKeySha256 = [][]byte{}
   447  		for _, v := range *c.PinnedPeerCertificatePublicKeySha256 {
   448  			hashValue, err := base64.StdEncoding.DecodeString(v)
   449  			if err != nil {
   450  				return nil, err
   451  			}
   452  			config.PinnedPeerCertificatePublicKeySha256 = append(config.PinnedPeerCertificatePublicKeySha256, hashValue)
   453  		}
   454  	}
   455  
   456  	config.MasterKeyLog = c.MasterKeyLog
   457  
   458  	return config, nil
   459  }
   460  
   461  type REALITYConfig struct {
   462  	Show         bool            `json:"show"`
   463  	MasterKeyLog string          `json:"masterKeyLog"`
   464  	Dest         json.RawMessage `json:"dest"`
   465  	Type         string          `json:"type"`
   466  	Xver         uint64          `json:"xver"`
   467  	ServerNames  []string        `json:"serverNames"`
   468  	PrivateKey   string          `json:"privateKey"`
   469  	MinClientVer string          `json:"minClientVer"`
   470  	MaxClientVer string          `json:"maxClientVer"`
   471  	MaxTimeDiff  uint64          `json:"maxTimeDiff"`
   472  	ShortIds     []string        `json:"shortIds"`
   473  
   474  	Fingerprint string `json:"fingerprint"`
   475  	ServerName  string `json:"serverName"`
   476  	PublicKey   string `json:"publicKey"`
   477  	ShortId     string `json:"shortId"`
   478  	SpiderX     string `json:"spiderX"`
   479  }
   480  
   481  func (c *REALITYConfig) Build() (proto.Message, error) {
   482  	config := new(reality.Config)
   483  	config.Show = c.Show
   484  	config.MasterKeyLog = c.MasterKeyLog
   485  	var err error
   486  	if c.Dest != nil {
   487  		var i uint16
   488  		var s string
   489  		if err = json.Unmarshal(c.Dest, &i); err == nil {
   490  			s = strconv.Itoa(int(i))
   491  		} else {
   492  			_ = json.Unmarshal(c.Dest, &s)
   493  		}
   494  		if c.Type == "" && s != "" {
   495  			switch s[0] {
   496  			case '@', '/':
   497  				c.Type = "unix"
   498  				if s[0] == '@' && len(s) > 1 && s[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
   499  					fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
   500  					copy(fullAddr, s[1:])
   501  					s = string(fullAddr)
   502  				}
   503  			default:
   504  				if _, err = strconv.Atoi(s); err == nil {
   505  					s = "127.0.0.1:" + s
   506  				}
   507  				if _, _, err = net.SplitHostPort(s); err == nil {
   508  					c.Type = "tcp"
   509  				}
   510  			}
   511  		}
   512  		if c.Type == "" {
   513  			return nil, newError(`please fill in a valid value for "dest"`)
   514  		}
   515  		if c.Xver > 2 {
   516  			return nil, newError(`invalid PROXY protocol version, "xver" only accepts 0, 1, 2`)
   517  		}
   518  		if len(c.ServerNames) == 0 {
   519  			return nil, newError(`empty "serverNames"`)
   520  		}
   521  		if c.PrivateKey == "" {
   522  			return nil, newError(`empty "privateKey"`)
   523  		}
   524  		if config.PrivateKey, err = base64.RawURLEncoding.DecodeString(c.PrivateKey); err != nil || len(config.PrivateKey) != 32 {
   525  			return nil, newError(`invalid "privateKey": `, c.PrivateKey)
   526  		}
   527  		if c.MinClientVer != "" {
   528  			config.MinClientVer = make([]byte, 3)
   529  			var u uint64
   530  			for i, s := range strings.Split(c.MinClientVer, ".") {
   531  				if i == 3 {
   532  					return nil, newError(`invalid "minClientVer": `, c.MinClientVer)
   533  				}
   534  				if u, err = strconv.ParseUint(s, 10, 8); err != nil {
   535  					return nil, newError(`"minClientVer[`, i, `]" should be lesser than 256`)
   536  				} else {
   537  					config.MinClientVer[i] = byte(u)
   538  				}
   539  			}
   540  		}
   541  		if c.MaxClientVer != "" {
   542  			config.MaxClientVer = make([]byte, 3)
   543  			var u uint64
   544  			for i, s := range strings.Split(c.MaxClientVer, ".") {
   545  				if i == 3 {
   546  					return nil, newError(`invalid "maxClientVer": `, c.MaxClientVer)
   547  				}
   548  				if u, err = strconv.ParseUint(s, 10, 8); err != nil {
   549  					return nil, newError(`"maxClientVer[`, i, `]" should be lesser than 256`)
   550  				} else {
   551  					config.MaxClientVer[i] = byte(u)
   552  				}
   553  			}
   554  		}
   555  		if len(c.ShortIds) == 0 {
   556  			return nil, newError(`empty "shortIds"`)
   557  		}
   558  		config.ShortIds = make([][]byte, len(c.ShortIds))
   559  		for i, s := range c.ShortIds {
   560  			config.ShortIds[i] = make([]byte, 8)
   561  			if _, err = hex.Decode(config.ShortIds[i], []byte(s)); err != nil {
   562  				return nil, newError(`invalid "shortIds[`, i, `]": `, s)
   563  			}
   564  		}
   565  		config.Dest = s
   566  		config.Type = c.Type
   567  		config.Xver = c.Xver
   568  		config.ServerNames = c.ServerNames
   569  		config.MaxTimeDiff = c.MaxTimeDiff
   570  	} else {
   571  		if c.Fingerprint == "" {
   572  			return nil, newError(`empty "fingerprint"`)
   573  		}
   574  		if config.Fingerprint = strings.ToLower(c.Fingerprint); tls.GetFingerprint(config.Fingerprint) == nil {
   575  			return nil, newError(`unknown "fingerprint": `, config.Fingerprint)
   576  		}
   577  		if config.Fingerprint == "hellogolang" {
   578  			return nil, newError(`invalid "fingerprint": `, config.Fingerprint)
   579  		}
   580  		if len(c.ServerNames) != 0 {
   581  			return nil, newError(`non-empty "serverNames", please use "serverName" instead`)
   582  		}
   583  		if c.PublicKey == "" {
   584  			return nil, newError(`empty "publicKey"`)
   585  		}
   586  		if config.PublicKey, err = base64.RawURLEncoding.DecodeString(c.PublicKey); err != nil || len(config.PublicKey) != 32 {
   587  			return nil, newError(`invalid "publicKey": `, c.PublicKey)
   588  		}
   589  		if len(c.ShortIds) != 0 {
   590  			return nil, newError(`non-empty "shortIds", please use "shortId" instead`)
   591  		}
   592  		config.ShortId = make([]byte, 8)
   593  		if _, err = hex.Decode(config.ShortId, []byte(c.ShortId)); err != nil {
   594  			return nil, newError(`invalid "shortId": `, c.ShortId)
   595  		}
   596  		if c.SpiderX == "" {
   597  			c.SpiderX = "/"
   598  		}
   599  		if c.SpiderX[0] != '/' {
   600  			return nil, newError(`invalid "spiderX": `, c.SpiderX)
   601  		}
   602  		config.SpiderY = make([]int64, 10)
   603  		u, _ := url.Parse(c.SpiderX)
   604  		q := u.Query()
   605  		parse := func(param string, index int) {
   606  			if q.Get(param) != "" {
   607  				s := strings.Split(q.Get(param), "-")
   608  				if len(s) == 1 {
   609  					config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
   610  					config.SpiderY[index+1], _ = strconv.ParseInt(s[0], 10, 64)
   611  				} else {
   612  					config.SpiderY[index], _ = strconv.ParseInt(s[0], 10, 64)
   613  					config.SpiderY[index+1], _ = strconv.ParseInt(s[1], 10, 64)
   614  				}
   615  			}
   616  			q.Del(param)
   617  		}
   618  		parse("p", 0) // padding
   619  		parse("c", 2) // concurrency
   620  		parse("t", 4) // times
   621  		parse("i", 6) // interval
   622  		parse("r", 8) // return
   623  		u.RawQuery = q.Encode()
   624  		config.SpiderX = u.String()
   625  		config.ServerName = c.ServerName
   626  	}
   627  	return config, nil
   628  }
   629  
   630  type TransportProtocol string
   631  
   632  // Build implements Buildable.
   633  func (p TransportProtocol) Build() (string, error) {
   634  	switch strings.ToLower(string(p)) {
   635  	case "tcp":
   636  		return "tcp", nil
   637  	case "kcp", "mkcp":
   638  		return "mkcp", nil
   639  	case "ws", "websocket":
   640  		return "websocket", nil
   641  	case "h2", "http":
   642  		return "http", nil
   643  	case "ds", "domainsocket":
   644  		return "domainsocket", nil
   645  	case "quic":
   646  		return "quic", nil
   647  	case "grpc", "gun":
   648  		return "grpc", nil
   649  	case "httpupgrade":
   650  		return "httpupgrade", nil
   651  	default:
   652  		return "", newError("Config: unknown transport protocol: ", p)
   653  	}
   654  }
   655  
   656  type SocketConfig struct {
   657  	Mark                 int32       `json:"mark"`
   658  	TFO                  interface{} `json:"tcpFastOpen"`
   659  	TProxy               string      `json:"tproxy"`
   660  	AcceptProxyProtocol  bool        `json:"acceptProxyProtocol"`
   661  	DomainStrategy       string      `json:"domainStrategy"`
   662  	DialerProxy          string      `json:"dialerProxy"`
   663  	TCPKeepAliveInterval int32       `json:"tcpKeepAliveInterval"`
   664  	TCPKeepAliveIdle     int32       `json:"tcpKeepAliveIdle"`
   665  	TCPCongestion        string      `json:"tcpCongestion"`
   666  	TCPWindowClamp       int32       `json:"tcpWindowClamp"`
   667  	TCPMaxSeg            int32       `json:"tcpMaxSeg"`
   668  	TcpNoDelay           bool        `json:"tcpNoDelay"`
   669  	TCPUserTimeout       int32       `json:"tcpUserTimeout"`
   670  	V6only               bool        `json:"v6only"`
   671  	Interface            string      `json:"interface"`
   672  	TcpMptcp             bool        `json:"tcpMptcp"`
   673  }
   674  
   675  // Build implements Buildable.
   676  func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
   677  	tfo := int32(0) // don't invoke setsockopt() for TFO
   678  	if c.TFO != nil {
   679  		switch v := c.TFO.(type) {
   680  		case bool:
   681  			if v {
   682  				tfo = 256
   683  			} else {
   684  				tfo = -1 // TFO need to be disabled
   685  			}
   686  		case float64:
   687  			tfo = int32(math.Min(v, math.MaxInt32))
   688  		default:
   689  			return nil, newError("tcpFastOpen: only boolean and integer value is acceptable")
   690  		}
   691  	}
   692  	var tproxy internet.SocketConfig_TProxyMode
   693  	switch strings.ToLower(c.TProxy) {
   694  	case "tproxy":
   695  		tproxy = internet.SocketConfig_TProxy
   696  	case "redirect":
   697  		tproxy = internet.SocketConfig_Redirect
   698  	default:
   699  		tproxy = internet.SocketConfig_Off
   700  	}
   701  
   702  	dStrategy := internet.DomainStrategy_AS_IS
   703  	switch strings.ToLower(c.DomainStrategy) {
   704  	case "asis", "":
   705  		dStrategy = internet.DomainStrategy_AS_IS
   706  	case "useip":
   707  		dStrategy = internet.DomainStrategy_USE_IP
   708  	case "useipv4":
   709  		dStrategy = internet.DomainStrategy_USE_IP4
   710  	case "useipv6":
   711  		dStrategy = internet.DomainStrategy_USE_IP6
   712  	case "useipv4v6":
   713  		dStrategy = internet.DomainStrategy_USE_IP46
   714  	case "useipv6v4":
   715  		dStrategy = internet.DomainStrategy_USE_IP64
   716  	case "forceip":
   717  		dStrategy = internet.DomainStrategy_FORCE_IP
   718  	case "forceipv4":
   719  		dStrategy = internet.DomainStrategy_FORCE_IP4
   720  	case "forceipv6":
   721  		dStrategy = internet.DomainStrategy_FORCE_IP6
   722  	case "forceipv4v6":
   723  		dStrategy = internet.DomainStrategy_FORCE_IP46
   724  	case "forceipv6v4":
   725  		dStrategy = internet.DomainStrategy_FORCE_IP64
   726  	default:
   727  		return nil, newError("unsupported domain strategy: ", c.DomainStrategy)
   728  	}
   729  
   730  	return &internet.SocketConfig{
   731  		Mark:                 c.Mark,
   732  		Tfo:                  tfo,
   733  		Tproxy:               tproxy,
   734  		DomainStrategy:       dStrategy,
   735  		AcceptProxyProtocol:  c.AcceptProxyProtocol,
   736  		DialerProxy:          c.DialerProxy,
   737  		TcpKeepAliveInterval: c.TCPKeepAliveInterval,
   738  		TcpKeepAliveIdle:     c.TCPKeepAliveIdle,
   739  		TcpCongestion:        c.TCPCongestion,
   740  		TcpWindowClamp:       c.TCPWindowClamp,
   741  		TcpMaxSeg:            c.TCPMaxSeg,
   742  		TcpNoDelay:           c.TcpNoDelay,
   743  		TcpUserTimeout:       c.TCPUserTimeout,
   744  		V6Only:               c.V6only,
   745  		Interface:            c.Interface,
   746  		TcpMptcp:             c.TcpMptcp,
   747  	}, nil
   748  }
   749  
   750  type StreamConfig struct {
   751  	Network             *TransportProtocol  `json:"network"`
   752  	Security            string              `json:"security"`
   753  	TLSSettings         *TLSConfig          `json:"tlsSettings"`
   754  	REALITYSettings     *REALITYConfig      `json:"realitySettings"`
   755  	TCPSettings         *TCPConfig          `json:"tcpSettings"`
   756  	KCPSettings         *KCPConfig          `json:"kcpSettings"`
   757  	WSSettings          *WebSocketConfig    `json:"wsSettings"`
   758  	HTTPSettings        *HTTPConfig         `json:"httpSettings"`
   759  	DSSettings          *DomainSocketConfig `json:"dsSettings"`
   760  	QUICSettings        *QUICConfig         `json:"quicSettings"`
   761  	SocketSettings      *SocketConfig       `json:"sockopt"`
   762  	GRPCConfig          *GRPCConfig         `json:"grpcSettings"`
   763  	GUNConfig           *GRPCConfig         `json:"gunSettings"`
   764  	HTTPUPGRADESettings *HttpUpgradeConfig  `json:"httpupgradeSettings"`
   765  }
   766  
   767  // Build implements Buildable.
   768  func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
   769  	config := &internet.StreamConfig{
   770  		ProtocolName: "tcp",
   771  	}
   772  	if c.Network != nil {
   773  		protocol, err := c.Network.Build()
   774  		if err != nil {
   775  			return nil, err
   776  		}
   777  		config.ProtocolName = protocol
   778  	}
   779  	switch strings.ToLower(c.Security) {
   780  	case "", "none":
   781  	case "tls":
   782  		tlsSettings := c.TLSSettings
   783  		if tlsSettings == nil {
   784  			tlsSettings = &TLSConfig{}
   785  		}
   786  		ts, err := tlsSettings.Build()
   787  		if err != nil {
   788  			return nil, newError("Failed to build TLS config.").Base(err)
   789  		}
   790  		tm := serial.ToTypedMessage(ts)
   791  		config.SecuritySettings = append(config.SecuritySettings, tm)
   792  		config.SecurityType = tm.Type
   793  	case "reality":
   794  		if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "grpc" && config.ProtocolName != "domainsocket" {
   795  			return nil, newError("REALITY only supports TCP, H2, gRPC and DomainSocket for now.")
   796  		}
   797  		if c.REALITYSettings == nil {
   798  			return nil, newError(`REALITY: Empty "realitySettings".`)
   799  		}
   800  		ts, err := c.REALITYSettings.Build()
   801  		if err != nil {
   802  			return nil, newError("Failed to build REALITY config.").Base(err)
   803  		}
   804  		tm := serial.ToTypedMessage(ts)
   805  		config.SecuritySettings = append(config.SecuritySettings, tm)
   806  		config.SecurityType = tm.Type
   807  	case "xtls":
   808  		return nil, newError(`Please use VLESS flow "xtls-rprx-vision" with TLS or REALITY.`)
   809  	default:
   810  		return nil, newError(`Unknown security "` + c.Security + `".`)
   811  	}
   812  	if c.TCPSettings != nil {
   813  		ts, err := c.TCPSettings.Build()
   814  		if err != nil {
   815  			return nil, newError("Failed to build TCP config.").Base(err)
   816  		}
   817  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   818  			ProtocolName: "tcp",
   819  			Settings:     serial.ToTypedMessage(ts),
   820  		})
   821  	}
   822  	if c.KCPSettings != nil {
   823  		ts, err := c.KCPSettings.Build()
   824  		if err != nil {
   825  			return nil, newError("Failed to build mKCP config.").Base(err)
   826  		}
   827  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   828  			ProtocolName: "mkcp",
   829  			Settings:     serial.ToTypedMessage(ts),
   830  		})
   831  	}
   832  	if c.WSSettings != nil {
   833  		ts, err := c.WSSettings.Build()
   834  		if err != nil {
   835  			return nil, newError("Failed to build WebSocket config.").Base(err)
   836  		}
   837  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   838  			ProtocolName: "websocket",
   839  			Settings:     serial.ToTypedMessage(ts),
   840  		})
   841  	}
   842  	if c.HTTPSettings != nil {
   843  		ts, err := c.HTTPSettings.Build()
   844  		if err != nil {
   845  			return nil, newError("Failed to build HTTP config.").Base(err)
   846  		}
   847  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   848  			ProtocolName: "http",
   849  			Settings:     serial.ToTypedMessage(ts),
   850  		})
   851  	}
   852  	if c.DSSettings != nil {
   853  		ds, err := c.DSSettings.Build()
   854  		if err != nil {
   855  			return nil, newError("Failed to build DomainSocket config.").Base(err)
   856  		}
   857  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   858  			ProtocolName: "domainsocket",
   859  			Settings:     serial.ToTypedMessage(ds),
   860  		})
   861  	}
   862  	if c.QUICSettings != nil {
   863  		qs, err := c.QUICSettings.Build()
   864  		if err != nil {
   865  			return nil, newError("Failed to build QUIC config").Base(err)
   866  		}
   867  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   868  			ProtocolName: "quic",
   869  			Settings:     serial.ToTypedMessage(qs),
   870  		})
   871  	}
   872  	if c.GRPCConfig == nil {
   873  		c.GRPCConfig = c.GUNConfig
   874  	}
   875  	if c.GRPCConfig != nil {
   876  		gs, err := c.GRPCConfig.Build()
   877  		if err != nil {
   878  			return nil, newError("Failed to build gRPC config.").Base(err)
   879  		}
   880  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   881  			ProtocolName: "grpc",
   882  			Settings:     serial.ToTypedMessage(gs),
   883  		})
   884  	}
   885  	if c.HTTPUPGRADESettings != nil {
   886  		hs, err := c.HTTPUPGRADESettings.Build()
   887  		if err != nil {
   888  			return nil, newError("Failed to build HttpUpgrade config.").Base(err)
   889  		}
   890  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   891  			ProtocolName: "httpupgrade",
   892  			Settings:     serial.ToTypedMessage(hs),
   893  		})
   894  	}
   895  	if c.SocketSettings != nil {
   896  		ss, err := c.SocketSettings.Build()
   897  		if err != nil {
   898  			return nil, newError("Failed to build sockopt").Base(err)
   899  		}
   900  		config.SocketSettings = ss
   901  	}
   902  	return config, nil
   903  }
   904  
   905  type ProxyConfig struct {
   906  	Tag string `json:"tag"`
   907  
   908  	// TransportLayerProxy: For compatibility.
   909  	TransportLayerProxy bool `json:"transportLayer"`
   910  }
   911  
   912  // Build implements Buildable.
   913  func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
   914  	if v.Tag == "" {
   915  		return nil, newError("Proxy tag is not set.")
   916  	}
   917  	return &internet.ProxyConfig{
   918  		Tag:                 v.Tag,
   919  		TransportLayerProxy: v.TransportLayerProxy,
   920  	}, nil
   921  }