inbound_protocol.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package service
  2. import (
  3. "encoding/json"
  4. "strings"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  6. "github.com/mhsanaei/3x-ui/v3/internal/util/common"
  7. "github.com/mhsanaei/3x-ui/v3/internal/util/version"
  8. "gorm.io/gorm"
  9. )
  10. // inboundShadowsocksMethod extracts settings.method for Shadowsocks inbounds so
  11. // the client UI can generate a valid PSK (base64 of the method's key length)
  12. // for Shadowsocks 2022 ciphers. Returns "" for non-Shadowsocks inbounds.
  13. func inboundShadowsocksMethod(protocol, settings string) string {
  14. if protocol != string(model.Shadowsocks) || settings == "" {
  15. return ""
  16. }
  17. var s struct {
  18. Method string `json:"method"`
  19. }
  20. if err := json.Unmarshal([]byte(settings), &s); err != nil {
  21. return ""
  22. }
  23. return s.Method
  24. }
  25. // inboundCanEnableTlsFlow mirrors canEnableTlsFlow() from the frontend
  26. // (frontend/src/lib/xray/protocol-capabilities.ts). XTLS Vision is valid for
  27. // VLESS on TCP with tls or reality (classic), and on XHTTP when VLESS encryption
  28. // (vlessenc / ML-KEM) is enabled — there the post-quantum, VLESS-level
  29. // encryption stands in for the transport TLS that Vision relies on. settings is
  30. // the inbound's raw settings JSON, which carries the encryption value
  31. // (streamSettings does not).
  32. func inboundCanEnableTlsFlow(protocol, streamSettings, settings string) bool {
  33. if protocol != string(model.VLESS) {
  34. return false
  35. }
  36. if streamSettings == "" {
  37. return false
  38. }
  39. var stream struct {
  40. Network string `json:"network"`
  41. Security string `json:"security"`
  42. }
  43. if err := json.Unmarshal([]byte(streamSettings), &stream); err != nil {
  44. return false
  45. }
  46. switch stream.Network {
  47. case "tcp":
  48. return stream.Security == "tls" || stream.Security == "reality"
  49. case "xhttp":
  50. return vlessEncryptionEnabled(settings)
  51. default:
  52. return false
  53. }
  54. }
  55. // nodeEligibleProtocols mirrors the frontend's NODE_ELIGIBLE_PROTOCOLS. A sidecar
  56. // protocol's row is local on the node it is pushed to, so that panel runs it.
  57. var nodeEligibleProtocols = map[model.Protocol]bool{
  58. model.VLESS: true,
  59. model.VMESS: true,
  60. model.Trojan: true,
  61. model.Shadowsocks: true,
  62. model.Hysteria: true,
  63. model.WireGuard: true,
  64. model.MTProto: true,
  65. model.AmneziaWG: true,
  66. model.TUIC: true,
  67. model.MASQUE: true,
  68. }
  69. // nodeProtocolFirstRelease is the panel release that introduced each protocol
  70. // newer than node support itself; an older node would hand it to Xray as-is.
  71. var nodeProtocolFirstRelease = map[model.Protocol]string{
  72. model.MTProto: "v3.5.0",
  73. model.AmneziaWG: "v3.7.0",
  74. model.TUIC: "v3.8.0",
  75. model.MASQUE: "v3.9.1",
  76. }
  77. // checkNodeCanHostProtocol refuses assigning protocol to nodeID unless the
  78. // protocol may live on a node and that node's panel is new enough to run it.
  79. func checkNodeCanHostProtocol(db *gorm.DB, nodeID int, protocol model.Protocol) error {
  80. if !nodeEligibleProtocols[protocol] {
  81. return common.NewErrorf("%s inbounds cannot be assigned to a node", protocol)
  82. }
  83. firstRelease, ok := nodeProtocolFirstRelease[protocol]
  84. if !ok {
  85. return nil
  86. }
  87. var node model.Node
  88. if err := db.Select("id", "name", "panel_version").First(&node, nodeID).Error; err != nil {
  89. return err
  90. }
  91. if strings.TrimSpace(node.PanelVersion) == "" {
  92. return common.NewErrorf("node %q has not reported its panel version yet; %s inbounds need %s or newer",
  93. node.Name, protocol, firstRelease)
  94. }
  95. // A dev build reports "dev+<sha>": it tracks main, which carries every protocol.
  96. if cmp, ok := version.Compare(node.PanelVersion, firstRelease); ok && cmp < 0 {
  97. return common.NewErrorf("node %q runs panel %s; %s inbounds need %s or newer",
  98. node.Name, node.PanelVersion, protocol, firstRelease)
  99. }
  100. return nil
  101. }
  102. // vlessEncryptionEnabled reports whether a VLESS inbound has VLESS-level
  103. // encryption (vlessenc / ML-KEM) configured. When enabled these fields hold a
  104. // generated dotted string (e.g. "mlkem768x25519plus.native.0rtt.<key>"); "none"
  105. // or empty means off. The value is never the literal "vlessenc" — that is the
  106. // name of the `xray vlessenc` CLI subcommand, not a stored value.
  107. //
  108. // Both fields are checked: decryption is the authoritative server-side value
  109. // xray-core reads, while encryption is stored by the panel for link generation.
  110. // The ML-KEM/X25519 buttons set both, but accepting either keeps the gate
  111. // working for inbounds configured via the API or raw JSON.
  112. func vlessEncryptionEnabled(settings string) bool {
  113. if settings == "" {
  114. return false
  115. }
  116. var s struct {
  117. Encryption string `json:"encryption"`
  118. Decryption string `json:"decryption"`
  119. }
  120. if err := json.Unmarshal([]byte(settings), &s); err != nil {
  121. return false
  122. }
  123. return vlessEncValueSet(s.Encryption) || vlessEncValueSet(s.Decryption)
  124. }
  125. // vlessEncValueSet reports whether a VLESS encryption/decryption field holds a
  126. // real (generated) value rather than the "none"/empty sentinel.
  127. func vlessEncValueSet(v string) bool {
  128. return v != "" && v != "none"
  129. }
  130. // inboundCanHostFallbacks gates the settings.fallbacks injection.
  131. // Xray only honors fallbacks on VLESS and Trojan inbounds carried over
  132. // TCP transport with TLS or Reality security. This is intentionally stricter
  133. // than inboundCanEnableTlsFlow (which also accepts XHTTP+vlessenc): fallbacks
  134. // are a raw-TCP-only feature.
  135. func inboundCanHostFallbacks(ib *model.Inbound) bool {
  136. if ib == nil {
  137. return false
  138. }
  139. if ib.Protocol != model.VLESS && ib.Protocol != model.Trojan {
  140. return false
  141. }
  142. return streamSupportsFallbacks(ib.StreamSettings)
  143. }
  144. // streamSupportsFallbacks reports whether the stream is raw TCP carried over
  145. // TLS or REALITY — the only transport Xray honors inbound fallbacks on (and the
  146. // classic requirement for XTLS Vision before vlessenc).
  147. func streamSupportsFallbacks(streamSettings string) bool {
  148. if streamSettings == "" {
  149. return false
  150. }
  151. var stream struct {
  152. Network string `json:"network"`
  153. Security string `json:"security"`
  154. }
  155. if err := json.Unmarshal([]byte(streamSettings), &stream); err != nil {
  156. return false
  157. }
  158. if stream.Network != "tcp" {
  159. return false
  160. }
  161. return stream.Security == "tls" || stream.Security == "reality"
  162. }