v.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package convert
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/url"
  6. "strconv"
  7. "strings"
  8. )
  9. func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy map[string]any) error {
  10. // Xray VMessAEAD / VLESS share link standard
  11. // https://github.com/XTLS/Xray-core/discussions/716
  12. query := url.Query()
  13. proxy["name"] = uniqueName(names, url.Fragment)
  14. if url.Hostname() == "" {
  15. return errors.New("url.Hostname() is empty")
  16. }
  17. if url.Port() == "" {
  18. return errors.New("url.Port() is empty")
  19. }
  20. proxy["type"] = scheme
  21. proxy["server"] = url.Hostname()
  22. proxy["port"] = url.Port()
  23. proxy["uuid"] = url.User.Username()
  24. proxy["udp"] = true
  25. tls := strings.ToLower(query.Get("security"))
  26. if strings.HasSuffix(tls, "tls") || tls == "reality" {
  27. proxy["tls"] = true
  28. if fingerprint := query.Get("fp"); fingerprint == "" {
  29. proxy["client-fingerprint"] = "chrome"
  30. } else {
  31. proxy["client-fingerprint"] = fingerprint
  32. }
  33. if alpn := query.Get("alpn"); alpn != "" {
  34. proxy["alpn"] = strings.Split(alpn, ",")
  35. }
  36. }
  37. if sni := query.Get("sni"); sni != "" {
  38. proxy["servername"] = sni
  39. }
  40. if realityPublicKey := query.Get("pbk"); realityPublicKey != "" {
  41. proxy["reality-opts"] = map[string]any{
  42. "public-key": realityPublicKey,
  43. "short-id": query.Get("sid"),
  44. }
  45. }
  46. switch query.Get("packetEncoding") {
  47. case "none":
  48. case "packet":
  49. proxy["packet-addr"] = true
  50. default:
  51. proxy["xudp"] = true
  52. }
  53. network := strings.ToLower(query.Get("type"))
  54. if network == "" {
  55. network = "tcp"
  56. }
  57. fakeType := strings.ToLower(query.Get("headerType"))
  58. if fakeType == "http" {
  59. network = "http"
  60. } else if network == "http" {
  61. network = "h2"
  62. }
  63. proxy["network"] = network
  64. switch network {
  65. case "tcp":
  66. if fakeType != "none" {
  67. headers := make(map[string]any)
  68. httpOpts := make(map[string]any)
  69. httpOpts["path"] = []string{"/"}
  70. if host := query.Get("host"); host != "" {
  71. headers["Host"] = []string{host}
  72. }
  73. if method := query.Get("method"); method != "" {
  74. httpOpts["method"] = method
  75. }
  76. if path := query.Get("path"); path != "" {
  77. httpOpts["path"] = []string{path}
  78. }
  79. httpOpts["headers"] = headers
  80. proxy["http-opts"] = httpOpts
  81. }
  82. case "http":
  83. headers := make(map[string]any)
  84. h2Opts := make(map[string]any)
  85. h2Opts["path"] = []string{"/"}
  86. if path := query.Get("path"); path != "" {
  87. h2Opts["path"] = []string{path}
  88. }
  89. if host := query.Get("host"); host != "" {
  90. h2Opts["host"] = []string{host}
  91. }
  92. h2Opts["headers"] = headers
  93. proxy["h2-opts"] = h2Opts
  94. case "ws", "httpupgrade":
  95. headers := make(map[string]any)
  96. wsOpts := make(map[string]any)
  97. headers["User-Agent"] = RandUserAgent()
  98. headers["Host"] = query.Get("host")
  99. wsOpts["path"] = query.Get("path")
  100. wsOpts["headers"] = headers
  101. if earlyData := query.Get("ed"); earlyData != "" {
  102. med, err := strconv.Atoi(earlyData)
  103. if err != nil {
  104. return fmt.Errorf("bad WebSocket max early data size: %v", err)
  105. }
  106. switch network {
  107. case "ws":
  108. wsOpts["max-early-data"] = med
  109. wsOpts["early-data-header-name"] = "Sec-WebSocket-Protocol"
  110. case "httpupgrade":
  111. wsOpts["v2ray-http-upgrade-fast-open"] = true
  112. }
  113. }
  114. if earlyDataHeader := query.Get("eh"); earlyDataHeader != "" {
  115. wsOpts["early-data-header-name"] = earlyDataHeader
  116. }
  117. proxy["ws-opts"] = wsOpts
  118. case "grpc":
  119. grpcOpts := make(map[string]any)
  120. grpcOpts["grpc-service-name"] = query.Get("serviceName")
  121. proxy["grpc-opts"] = grpcOpts
  122. }
  123. return nil
  124. }