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