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 }