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