github.com/eagleql/xray-core@v1.4.4/infra/conf/transport_internet.go (about)

     1  package conf
     2  
     3  import (
     4  	"encoding/json"
     5  	"math"
     6  	"net/url"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/eagleql/xray-core/common/platform/filesystem"
    11  	"github.com/eagleql/xray-core/common/protocol"
    12  	"github.com/eagleql/xray-core/common/serial"
    13  	"github.com/eagleql/xray-core/transport/internet"
    14  	"github.com/eagleql/xray-core/transport/internet/domainsocket"
    15  	"github.com/eagleql/xray-core/transport/internet/http"
    16  	"github.com/eagleql/xray-core/transport/internet/kcp"
    17  	"github.com/eagleql/xray-core/transport/internet/quic"
    18  	"github.com/eagleql/xray-core/transport/internet/tcp"
    19  	"github.com/eagleql/xray-core/transport/internet/tls"
    20  	"github.com/eagleql/xray-core/transport/internet/websocket"
    21  	"github.com/eagleql/xray-core/transport/internet/xtls"
    22  	"github.com/golang/protobuf/proto"
    23  )
    24  
    25  var (
    26  	kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
    27  		"none":         func() interface{} { return new(NoOpAuthenticator) },
    28  		"srtp":         func() interface{} { return new(SRTPAuthenticator) },
    29  		"utp":          func() interface{} { return new(UTPAuthenticator) },
    30  		"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
    31  		"dtls":         func() interface{} { return new(DTLSAuthenticator) },
    32  		"wireguard":    func() interface{} { return new(WireguardAuthenticator) },
    33  	}, "type", "")
    34  
    35  	tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
    36  		"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
    37  		"http": func() interface{} { return new(Authenticator) },
    38  	}, "type", "")
    39  )
    40  
    41  type KCPConfig struct {
    42  	Mtu             *uint32         `json:"mtu"`
    43  	Tti             *uint32         `json:"tti"`
    44  	UpCap           *uint32         `json:"uplinkCapacity"`
    45  	DownCap         *uint32         `json:"downlinkCapacity"`
    46  	Congestion      *bool           `json:"congestion"`
    47  	ReadBufferSize  *uint32         `json:"readBufferSize"`
    48  	WriteBufferSize *uint32         `json:"writeBufferSize"`
    49  	HeaderConfig    json.RawMessage `json:"header"`
    50  	Seed            *string         `json:"seed"`
    51  }
    52  
    53  // Build implements Buildable.
    54  func (c *KCPConfig) Build() (proto.Message, error) {
    55  	config := new(kcp.Config)
    56  
    57  	if c.Mtu != nil {
    58  		mtu := *c.Mtu
    59  		if mtu < 576 || mtu > 1460 {
    60  			return nil, newError("invalid mKCP MTU size: ", mtu).AtError()
    61  		}
    62  		config.Mtu = &kcp.MTU{Value: mtu}
    63  	}
    64  	if c.Tti != nil {
    65  		tti := *c.Tti
    66  		if tti < 10 || tti > 100 {
    67  			return nil, newError("invalid mKCP TTI: ", tti).AtError()
    68  		}
    69  		config.Tti = &kcp.TTI{Value: tti}
    70  	}
    71  	if c.UpCap != nil {
    72  		config.UplinkCapacity = &kcp.UplinkCapacity{Value: *c.UpCap}
    73  	}
    74  	if c.DownCap != nil {
    75  		config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *c.DownCap}
    76  	}
    77  	if c.Congestion != nil {
    78  		config.Congestion = *c.Congestion
    79  	}
    80  	if c.ReadBufferSize != nil {
    81  		size := *c.ReadBufferSize
    82  		if size > 0 {
    83  			config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}
    84  		} else {
    85  			config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}
    86  		}
    87  	}
    88  	if c.WriteBufferSize != nil {
    89  		size := *c.WriteBufferSize
    90  		if size > 0 {
    91  			config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}
    92  		} else {
    93  			config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
    94  		}
    95  	}
    96  	if len(c.HeaderConfig) > 0 {
    97  		headerConfig, _, err := kcpHeaderLoader.Load(c.HeaderConfig)
    98  		if err != nil {
    99  			return nil, newError("invalid mKCP header config.").Base(err).AtError()
   100  		}
   101  		ts, err := headerConfig.(Buildable).Build()
   102  		if err != nil {
   103  			return nil, newError("invalid mKCP header config").Base(err).AtError()
   104  		}
   105  		config.HeaderConfig = serial.ToTypedMessage(ts)
   106  	}
   107  
   108  	if c.Seed != nil {
   109  		config.Seed = &kcp.EncryptionSeed{Seed: *c.Seed}
   110  	}
   111  
   112  	return config, nil
   113  }
   114  
   115  type TCPConfig struct {
   116  	HeaderConfig        json.RawMessage `json:"header"`
   117  	AcceptProxyProtocol bool            `json:"acceptProxyProtocol"`
   118  }
   119  
   120  // Build implements Buildable.
   121  func (c *TCPConfig) Build() (proto.Message, error) {
   122  	config := new(tcp.Config)
   123  	if len(c.HeaderConfig) > 0 {
   124  		headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
   125  		if err != nil {
   126  			return nil, newError("invalid TCP header config").Base(err).AtError()
   127  		}
   128  		ts, err := headerConfig.(Buildable).Build()
   129  		if err != nil {
   130  			return nil, newError("invalid TCP header config").Base(err).AtError()
   131  		}
   132  		config.HeaderSettings = serial.ToTypedMessage(ts)
   133  	}
   134  	if c.AcceptProxyProtocol {
   135  		config.AcceptProxyProtocol = c.AcceptProxyProtocol
   136  	}
   137  	return config, nil
   138  }
   139  
   140  type WebSocketConfig struct {
   141  	Path                string            `json:"path"`
   142  	Path2               string            `json:"Path"` // The key was misspelled. For backward compatibility, we have to keep track the old key.
   143  	Headers             map[string]string `json:"headers"`
   144  	AcceptProxyProtocol bool              `json:"acceptProxyProtocol"`
   145  }
   146  
   147  // Build implements Buildable.
   148  func (c *WebSocketConfig) Build() (proto.Message, error) {
   149  	path := c.Path
   150  	if path == "" && c.Path2 != "" {
   151  		path = c.Path2
   152  	}
   153  	header := make([]*websocket.Header, 0, 32)
   154  	for key, value := range c.Headers {
   155  		header = append(header, &websocket.Header{
   156  			Key:   key,
   157  			Value: value,
   158  		})
   159  	}
   160  	var ed uint32
   161  	if u, err := url.Parse(path); err == nil {
   162  		if q := u.Query(); q.Get("ed") != "" {
   163  			Ed, _ := strconv.Atoi(q.Get("ed"))
   164  			ed = uint32(Ed)
   165  			q.Del("ed")
   166  			u.RawQuery = q.Encode()
   167  			path = u.String()
   168  		}
   169  	}
   170  	config := &websocket.Config{
   171  		Path:   path,
   172  		Header: header,
   173  		Ed:     ed,
   174  	}
   175  	if c.AcceptProxyProtocol {
   176  		config.AcceptProxyProtocol = c.AcceptProxyProtocol
   177  	}
   178  	return config, nil
   179  }
   180  
   181  type HTTPConfig struct {
   182  	Host *StringList `json:"host"`
   183  	Path string      `json:"path"`
   184  }
   185  
   186  // Build implements Buildable.
   187  func (c *HTTPConfig) Build() (proto.Message, error) {
   188  	config := &http.Config{
   189  		Path: c.Path,
   190  	}
   191  	if c.Host != nil {
   192  		config.Host = []string(*c.Host)
   193  	}
   194  	return config, nil
   195  }
   196  
   197  type QUICConfig struct {
   198  	Header   json.RawMessage `json:"header"`
   199  	Security string          `json:"security"`
   200  	Key      string          `json:"key"`
   201  }
   202  
   203  // Build implements Buildable.
   204  func (c *QUICConfig) Build() (proto.Message, error) {
   205  	config := &quic.Config{
   206  		Key: c.Key,
   207  	}
   208  
   209  	if len(c.Header) > 0 {
   210  		headerConfig, _, err := kcpHeaderLoader.Load(c.Header)
   211  		if err != nil {
   212  			return nil, newError("invalid QUIC header config.").Base(err).AtError()
   213  		}
   214  		ts, err := headerConfig.(Buildable).Build()
   215  		if err != nil {
   216  			return nil, newError("invalid QUIC header config").Base(err).AtError()
   217  		}
   218  		config.Header = serial.ToTypedMessage(ts)
   219  	}
   220  
   221  	var st protocol.SecurityType
   222  	switch strings.ToLower(c.Security) {
   223  	case "aes-128-gcm":
   224  		st = protocol.SecurityType_AES128_GCM
   225  	case "chacha20-poly1305":
   226  		st = protocol.SecurityType_CHACHA20_POLY1305
   227  	default:
   228  		st = protocol.SecurityType_NONE
   229  	}
   230  
   231  	config.Security = &protocol.SecurityConfig{
   232  		Type: st,
   233  	}
   234  
   235  	return config, nil
   236  }
   237  
   238  type DomainSocketConfig struct {
   239  	Path     string `json:"path"`
   240  	Abstract bool   `json:"abstract"`
   241  	Padding  bool   `json:"padding"`
   242  }
   243  
   244  // Build implements Buildable.
   245  func (c *DomainSocketConfig) Build() (proto.Message, error) {
   246  	return &domainsocket.Config{
   247  		Path:     c.Path,
   248  		Abstract: c.Abstract,
   249  		Padding:  c.Padding,
   250  	}, nil
   251  }
   252  
   253  func readFileOrString(f string, s []string) ([]byte, error) {
   254  	if len(f) > 0 {
   255  		return filesystem.ReadFile(f)
   256  	}
   257  	if len(s) > 0 {
   258  		return []byte(strings.Join(s, "\n")), nil
   259  	}
   260  	return nil, newError("both file and bytes are empty.")
   261  }
   262  
   263  type TLSCertConfig struct {
   264  	CertFile       string   `json:"certificateFile"`
   265  	CertStr        []string `json:"certificate"`
   266  	KeyFile        string   `json:"keyFile"`
   267  	KeyStr         []string `json:"key"`
   268  	Usage          string   `json:"usage"`
   269  	OcspStapling   uint64   `json:"ocspStapling"`
   270  	OneTimeLoading bool     `json:"oneTimeLoading"`
   271  }
   272  
   273  // Build implements Buildable.
   274  func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
   275  	certificate := new(tls.Certificate)
   276  
   277  	cert, err := readFileOrString(c.CertFile, c.CertStr)
   278  	if err != nil {
   279  		return nil, newError("failed to parse certificate").Base(err)
   280  	}
   281  	certificate.Certificate = cert
   282  	certificate.CertificatePath = c.CertFile
   283  
   284  	if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
   285  		key, err := readFileOrString(c.KeyFile, c.KeyStr)
   286  		if err != nil {
   287  			return nil, newError("failed to parse key").Base(err)
   288  		}
   289  		certificate.Key = key
   290  		certificate.KeyPath = c.KeyFile
   291  	}
   292  
   293  	switch strings.ToLower(c.Usage) {
   294  	case "encipherment":
   295  		certificate.Usage = tls.Certificate_ENCIPHERMENT
   296  	case "verify":
   297  		certificate.Usage = tls.Certificate_AUTHORITY_VERIFY
   298  	case "issue":
   299  		certificate.Usage = tls.Certificate_AUTHORITY_ISSUE
   300  	default:
   301  		certificate.Usage = tls.Certificate_ENCIPHERMENT
   302  	}
   303  	if certificate.KeyPath == "" && certificate.CertificatePath == "" {
   304  		certificate.OneTimeLoading = true
   305  	} else {
   306  		certificate.OneTimeLoading = c.OneTimeLoading
   307  	}
   308  	certificate.OcspStapling = c.OcspStapling
   309  
   310  	return certificate, nil
   311  }
   312  
   313  type TLSConfig struct {
   314  	Insecure                 bool             `json:"allowInsecure"`
   315  	Certs                    []*TLSCertConfig `json:"certificates"`
   316  	ServerName               string           `json:"serverName"`
   317  	ALPN                     *StringList      `json:"alpn"`
   318  	EnableSessionResumption  bool             `json:"enableSessionResumption"`
   319  	DisableSystemRoot        bool             `json:"disableSystemRoot"`
   320  	MinVersion               string           `json:"minVersion"`
   321  	MaxVersion               string           `json:"maxVersion"`
   322  	CipherSuites             string           `json:"cipherSuites"`
   323  	PreferServerCipherSuites bool             `json:"preferServerCipherSuites"`
   324  	Fingerprint              string           `json:"fingerprint"`
   325  }
   326  
   327  // Build implements Buildable.
   328  func (c *TLSConfig) Build() (proto.Message, error) {
   329  	config := new(tls.Config)
   330  	config.Certificate = make([]*tls.Certificate, len(c.Certs))
   331  	for idx, certConf := range c.Certs {
   332  		cert, err := certConf.Build()
   333  		if err != nil {
   334  			return nil, err
   335  		}
   336  		config.Certificate[idx] = cert
   337  	}
   338  	serverName := c.ServerName
   339  	config.AllowInsecure = c.Insecure
   340  	if len(c.ServerName) > 0 {
   341  		config.ServerName = serverName
   342  	}
   343  	if c.ALPN != nil && len(*c.ALPN) > 0 {
   344  		config.NextProtocol = []string(*c.ALPN)
   345  	}
   346  	config.EnableSessionResumption = c.EnableSessionResumption
   347  	config.DisableSystemRoot = c.DisableSystemRoot
   348  	config.MinVersion = c.MinVersion
   349  	config.MaxVersion = c.MaxVersion
   350  	config.CipherSuites = c.CipherSuites
   351  	config.PreferServerCipherSuites = c.PreferServerCipherSuites
   352  	config.Fingerprint = strings.ToLower(c.Fingerprint)
   353  	return config, nil
   354  }
   355  
   356  type XTLSCertConfig struct {
   357  	CertFile       string   `json:"certificateFile"`
   358  	CertStr        []string `json:"certificate"`
   359  	KeyFile        string   `json:"keyFile"`
   360  	KeyStr         []string `json:"key"`
   361  	Usage          string   `json:"usage"`
   362  	OcspStapling   uint64   `json:"ocspStapling"`
   363  	OneTimeLoading bool     `json:"oneTimeLoading"`
   364  }
   365  
   366  // Build implements Buildable.
   367  func (c *XTLSCertConfig) Build() (*xtls.Certificate, error) {
   368  	certificate := new(xtls.Certificate)
   369  	cert, err := readFileOrString(c.CertFile, c.CertStr)
   370  	if err != nil {
   371  		return nil, newError("failed to parse certificate").Base(err)
   372  	}
   373  	certificate.Certificate = cert
   374  	certificate.CertificatePath = c.CertFile
   375  
   376  	if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
   377  		key, err := readFileOrString(c.KeyFile, c.KeyStr)
   378  		if err != nil {
   379  			return nil, newError("failed to parse key").Base(err)
   380  		}
   381  		certificate.Key = key
   382  		certificate.KeyPath = c.KeyFile
   383  	}
   384  
   385  	switch strings.ToLower(c.Usage) {
   386  	case "encipherment":
   387  		certificate.Usage = xtls.Certificate_ENCIPHERMENT
   388  	case "verify":
   389  		certificate.Usage = xtls.Certificate_AUTHORITY_VERIFY
   390  	case "issue":
   391  		certificate.Usage = xtls.Certificate_AUTHORITY_ISSUE
   392  	default:
   393  		certificate.Usage = xtls.Certificate_ENCIPHERMENT
   394  	}
   395  	if certificate.KeyPath == "" && certificate.CertificatePath == "" {
   396  		certificate.OneTimeLoading = true
   397  	} else {
   398  		certificate.OneTimeLoading = c.OneTimeLoading
   399  	}
   400  	certificate.OcspStapling = c.OcspStapling
   401  
   402  	return certificate, nil
   403  }
   404  
   405  type XTLSConfig struct {
   406  	Insecure                 bool              `json:"allowInsecure"`
   407  	Certs                    []*XTLSCertConfig `json:"certificates"`
   408  	ServerName               string            `json:"serverName"`
   409  	ALPN                     *StringList       `json:"alpn"`
   410  	EnableSessionResumption  bool              `json:"enableSessionResumption"`
   411  	DisableSystemRoot        bool              `json:"disableSystemRoot"`
   412  	MinVersion               string            `json:"minVersion"`
   413  	MaxVersion               string            `json:"maxVersion"`
   414  	CipherSuites             string            `json:"cipherSuites"`
   415  	PreferServerCipherSuites bool              `json:"preferServerCipherSuites"`
   416  }
   417  
   418  // Build implements Buildable.
   419  func (c *XTLSConfig) Build() (proto.Message, error) {
   420  	config := new(xtls.Config)
   421  	config.Certificate = make([]*xtls.Certificate, len(c.Certs))
   422  	for idx, certConf := range c.Certs {
   423  		cert, err := certConf.Build()
   424  		if err != nil {
   425  			return nil, err
   426  		}
   427  		config.Certificate[idx] = cert
   428  	}
   429  	serverName := c.ServerName
   430  	config.AllowInsecure = c.Insecure
   431  	if len(c.ServerName) > 0 {
   432  		config.ServerName = serverName
   433  	}
   434  	if c.ALPN != nil && len(*c.ALPN) > 0 {
   435  		config.NextProtocol = []string(*c.ALPN)
   436  	}
   437  	config.EnableSessionResumption = c.EnableSessionResumption
   438  	config.DisableSystemRoot = c.DisableSystemRoot
   439  	config.MinVersion = c.MinVersion
   440  	config.MaxVersion = c.MaxVersion
   441  	config.CipherSuites = c.CipherSuites
   442  	config.PreferServerCipherSuites = c.PreferServerCipherSuites
   443  	return config, nil
   444  }
   445  
   446  type TransportProtocol string
   447  
   448  // Build implements Buildable.
   449  func (p TransportProtocol) Build() (string, error) {
   450  	switch strings.ToLower(string(p)) {
   451  	case "tcp":
   452  		return "tcp", nil
   453  	case "kcp", "mkcp":
   454  		return "mkcp", nil
   455  	case "ws", "websocket":
   456  		return "websocket", nil
   457  	case "h2", "http":
   458  		return "http", nil
   459  	case "ds", "domainsocket":
   460  		return "domainsocket", nil
   461  	case "quic":
   462  		return "quic", nil
   463  	case "grpc", "gun":
   464  		return "grpc", nil
   465  	default:
   466  		return "", newError("Config: unknown transport protocol: ", p)
   467  	}
   468  }
   469  
   470  type SocketConfig struct {
   471  	Mark                int32       `json:"mark"`
   472  	TFO                 interface{} `json:"tcpFastOpen"`
   473  	TProxy              string      `json:"tproxy"`
   474  	AcceptProxyProtocol bool        `json:"acceptProxyProtocol"`
   475  	DomainStrategy      string      `json:"domainStrategy"`
   476  	DialerProxy         string      `json:"dialerProxy"`
   477  }
   478  
   479  // Build implements Buildable.
   480  func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
   481  	tfo := int32(0) // don't invoke setsockopt() for TFO
   482  	if c.TFO != nil {
   483  		switch v := c.TFO.(type) {
   484  		case bool:
   485  			if v {
   486  				tfo = 256
   487  			} else {
   488  				tfo = -1 // TFO need to be disabled
   489  			}
   490  		case float64:
   491  			tfo = int32(math.Min(v, math.MaxInt32))
   492  		default:
   493  			return nil, newError("tcpFastOpen: only boolean and integer value is acceptable")
   494  		}
   495  	}
   496  	var tproxy internet.SocketConfig_TProxyMode
   497  	switch strings.ToLower(c.TProxy) {
   498  	case "tproxy":
   499  		tproxy = internet.SocketConfig_TProxy
   500  	case "redirect":
   501  		tproxy = internet.SocketConfig_Redirect
   502  	default:
   503  		tproxy = internet.SocketConfig_Off
   504  	}
   505  
   506  	var dStrategy = internet.DomainStrategy_AS_IS
   507  	switch strings.ToLower(c.DomainStrategy) {
   508  	case "useip", "use_ip":
   509  		dStrategy = internet.DomainStrategy_USE_IP
   510  	case "useip4", "useipv4", "use_ipv4", "use_ip_v4", "use_ip4":
   511  		dStrategy = internet.DomainStrategy_USE_IP4
   512  	case "useip6", "useipv6", "use_ipv6", "use_ip_v6", "use_ip6":
   513  		dStrategy = internet.DomainStrategy_USE_IP6
   514  	}
   515  
   516  	return &internet.SocketConfig{
   517  		Mark:                c.Mark,
   518  		Tfo:                 tfo,
   519  		Tproxy:              tproxy,
   520  		DomainStrategy:      dStrategy,
   521  		AcceptProxyProtocol: c.AcceptProxyProtocol,
   522  		DialerProxy:         c.DialerProxy,
   523  	}, nil
   524  }
   525  
   526  type StreamConfig struct {
   527  	Network        *TransportProtocol  `json:"network"`
   528  	Security       string              `json:"security"`
   529  	TLSSettings    *TLSConfig          `json:"tlsSettings"`
   530  	XTLSSettings   *XTLSConfig         `json:"xtlsSettings"`
   531  	TCPSettings    *TCPConfig          `json:"tcpSettings"`
   532  	KCPSettings    *KCPConfig          `json:"kcpSettings"`
   533  	WSSettings     *WebSocketConfig    `json:"wsSettings"`
   534  	HTTPSettings   *HTTPConfig         `json:"httpSettings"`
   535  	DSSettings     *DomainSocketConfig `json:"dsSettings"`
   536  	QUICSettings   *QUICConfig         `json:"quicSettings"`
   537  	SocketSettings *SocketConfig       `json:"sockopt"`
   538  	GRPCConfig     *GRPCConfig         `json:"grpcSettings"`
   539  	GUNConfig      *GRPCConfig         `json:"gunSettings"`
   540  }
   541  
   542  // Build implements Buildable.
   543  func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
   544  	config := &internet.StreamConfig{
   545  		ProtocolName: "tcp",
   546  	}
   547  	if c.Network != nil {
   548  		protocol, err := c.Network.Build()
   549  		if err != nil {
   550  			return nil, err
   551  		}
   552  		config.ProtocolName = protocol
   553  	}
   554  	if strings.EqualFold(c.Security, "tls") {
   555  		tlsSettings := c.TLSSettings
   556  		if tlsSettings == nil {
   557  			if c.XTLSSettings != nil {
   558  				return nil, newError(`TLS: Please use "tlsSettings" instead of "xtlsSettings".`)
   559  			}
   560  			tlsSettings = &TLSConfig{}
   561  		}
   562  		ts, err := tlsSettings.Build()
   563  		if err != nil {
   564  			return nil, newError("Failed to build TLS config.").Base(err)
   565  		}
   566  		tm := serial.ToTypedMessage(ts)
   567  		config.SecuritySettings = append(config.SecuritySettings, tm)
   568  		config.SecurityType = tm.Type
   569  	}
   570  	if strings.EqualFold(c.Security, "xtls") {
   571  		if config.ProtocolName != "tcp" && config.ProtocolName != "mkcp" && config.ProtocolName != "domainsocket" {
   572  			return nil, newError("XTLS only supports TCP, mKCP and DomainSocket for now.")
   573  		}
   574  		xtlsSettings := c.XTLSSettings
   575  		if xtlsSettings == nil {
   576  			if c.TLSSettings != nil {
   577  				return nil, newError(`XTLS: Please use "xtlsSettings" instead of "tlsSettings".`)
   578  			}
   579  			xtlsSettings = &XTLSConfig{}
   580  		}
   581  		ts, err := xtlsSettings.Build()
   582  		if err != nil {
   583  			return nil, newError("Failed to build XTLS config.").Base(err)
   584  		}
   585  		tm := serial.ToTypedMessage(ts)
   586  		config.SecuritySettings = append(config.SecuritySettings, tm)
   587  		config.SecurityType = tm.Type
   588  	}
   589  	if c.TCPSettings != nil {
   590  		ts, err := c.TCPSettings.Build()
   591  		if err != nil {
   592  			return nil, newError("Failed to build TCP config.").Base(err)
   593  		}
   594  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   595  			ProtocolName: "tcp",
   596  			Settings:     serial.ToTypedMessage(ts),
   597  		})
   598  	}
   599  	if c.KCPSettings != nil {
   600  		ts, err := c.KCPSettings.Build()
   601  		if err != nil {
   602  			return nil, newError("Failed to build mKCP config.").Base(err)
   603  		}
   604  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   605  			ProtocolName: "mkcp",
   606  			Settings:     serial.ToTypedMessage(ts),
   607  		})
   608  	}
   609  	if c.WSSettings != nil {
   610  		ts, err := c.WSSettings.Build()
   611  		if err != nil {
   612  			return nil, newError("Failed to build WebSocket config.").Base(err)
   613  		}
   614  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   615  			ProtocolName: "websocket",
   616  			Settings:     serial.ToTypedMessage(ts),
   617  		})
   618  	}
   619  	if c.HTTPSettings != nil {
   620  		ts, err := c.HTTPSettings.Build()
   621  		if err != nil {
   622  			return nil, newError("Failed to build HTTP config.").Base(err)
   623  		}
   624  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   625  			ProtocolName: "http",
   626  			Settings:     serial.ToTypedMessage(ts),
   627  		})
   628  	}
   629  	if c.DSSettings != nil {
   630  		ds, err := c.DSSettings.Build()
   631  		if err != nil {
   632  			return nil, newError("Failed to build DomainSocket config.").Base(err)
   633  		}
   634  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   635  			ProtocolName: "domainsocket",
   636  			Settings:     serial.ToTypedMessage(ds),
   637  		})
   638  	}
   639  	if c.QUICSettings != nil {
   640  		qs, err := c.QUICSettings.Build()
   641  		if err != nil {
   642  			return nil, newError("Failed to build QUIC config").Base(err)
   643  		}
   644  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   645  			ProtocolName: "quic",
   646  			Settings:     serial.ToTypedMessage(qs),
   647  		})
   648  	}
   649  	if c.GRPCConfig == nil {
   650  		c.GRPCConfig = c.GUNConfig
   651  	}
   652  	if c.GRPCConfig != nil {
   653  		gs, err := c.GRPCConfig.Build()
   654  		if err != nil {
   655  			return nil, newError("Failed to build gRPC config.").Base(err)
   656  		}
   657  		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
   658  			ProtocolName: "grpc",
   659  			Settings:     serial.ToTypedMessage(gs),
   660  		})
   661  	}
   662  	if c.SocketSettings != nil {
   663  		ss, err := c.SocketSettings.Build()
   664  		if err != nil {
   665  			return nil, newError("Failed to build sockopt").Base(err)
   666  		}
   667  		config.SocketSettings = ss
   668  	}
   669  	return config, nil
   670  }
   671  
   672  type ProxyConfig struct {
   673  	Tag string `json:"tag"`
   674  
   675  	// TransportLayerProxy: For compatibility.
   676  	TransportLayerProxy bool `json:"transportLayer"`
   677  }
   678  
   679  // Build implements Buildable.
   680  func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
   681  	if v.Tag == "" {
   682  		return nil, newError("Proxy tag is not set.")
   683  	}
   684  	return &internet.ProxyConfig{
   685  		Tag:                 v.Tag,
   686  		TransportLayerProxy: v.TransportLayerProxy,
   687  	}, nil
   688  }