inbound_protocol.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package service
  2. import (
  3. "encoding/json"
  4. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  5. )
  6. // inboundShadowsocksMethod extracts settings.method for Shadowsocks inbounds so
  7. // the client UI can generate a valid PSK (base64 of the method's key length)
  8. // for Shadowsocks 2022 ciphers. Returns "" for non-Shadowsocks inbounds.
  9. func inboundShadowsocksMethod(protocol, settings string) string {
  10. if protocol != string(model.Shadowsocks) || settings == "" {
  11. return ""
  12. }
  13. var s struct {
  14. Method string `json:"method"`
  15. }
  16. if err := json.Unmarshal([]byte(settings), &s); err != nil {
  17. return ""
  18. }
  19. return s.Method
  20. }
  21. // inboundCanEnableTlsFlow mirrors canEnableTlsFlow() from the frontend
  22. // (frontend/src/lib/xray/protocol-capabilities.ts). XTLS Vision is valid for
  23. // VLESS on TCP with tls or reality (classic), and on XHTTP when VLESS encryption
  24. // (vlessenc / ML-KEM) is enabled — there the post-quantum, VLESS-level
  25. // encryption stands in for the transport TLS that Vision relies on. settings is
  26. // the inbound's raw settings JSON, which carries the encryption value
  27. // (streamSettings does not).
  28. func inboundCanEnableTlsFlow(protocol, streamSettings, settings string) bool {
  29. if protocol != string(model.VLESS) {
  30. return false
  31. }
  32. if streamSettings == "" {
  33. return false
  34. }
  35. var stream struct {
  36. Network string `json:"network"`
  37. Security string `json:"security"`
  38. }
  39. if err := json.Unmarshal([]byte(streamSettings), &stream); err != nil {
  40. return false
  41. }
  42. switch stream.Network {
  43. case "tcp":
  44. return stream.Security == "tls" || stream.Security == "reality"
  45. case "xhttp":
  46. return vlessEncryptionEnabled(settings)
  47. default:
  48. return false
  49. }
  50. }
  51. // nodeEligibleProtocols mirrors the frontend's NODE_ELIGIBLE_PROTOCOLS. The
  52. // sidecar-managed protocols are absent because their reconcile loops only query
  53. // NodeID IS NULL rows, so a node-assigned one would never be reconciled at all.
  54. // A new protocol defaults to ineligible until added here, as on the frontend.
  55. var nodeEligibleProtocols = map[model.Protocol]bool{
  56. model.VLESS: true,
  57. model.VMESS: true,
  58. model.Trojan: true,
  59. model.Shadowsocks: true,
  60. model.Hysteria: true,
  61. model.WireGuard: true,
  62. }
  63. // isNodeEligibleProtocol reports whether protocol may be assigned to a node.
  64. func isNodeEligibleProtocol(protocol model.Protocol) bool {
  65. return nodeEligibleProtocols[protocol]
  66. }
  67. // vlessEncryptionEnabled reports whether a VLESS inbound has VLESS-level
  68. // encryption (vlessenc / ML-KEM) configured. When enabled these fields hold a
  69. // generated dotted string (e.g. "mlkem768x25519plus.native.0rtt.<key>"); "none"
  70. // or empty means off. The value is never the literal "vlessenc" — that is the
  71. // name of the `xray vlessenc` CLI subcommand, not a stored value.
  72. //
  73. // Both fields are checked: decryption is the authoritative server-side value
  74. // xray-core reads, while encryption is stored by the panel for link generation.
  75. // The ML-KEM/X25519 buttons set both, but accepting either keeps the gate
  76. // working for inbounds configured via the API or raw JSON.
  77. func vlessEncryptionEnabled(settings string) bool {
  78. if settings == "" {
  79. return false
  80. }
  81. var s struct {
  82. Encryption string `json:"encryption"`
  83. Decryption string `json:"decryption"`
  84. }
  85. if err := json.Unmarshal([]byte(settings), &s); err != nil {
  86. return false
  87. }
  88. return vlessEncValueSet(s.Encryption) || vlessEncValueSet(s.Decryption)
  89. }
  90. // vlessEncValueSet reports whether a VLESS encryption/decryption field holds a
  91. // real (generated) value rather than the "none"/empty sentinel.
  92. func vlessEncValueSet(v string) bool {
  93. return v != "" && v != "none"
  94. }
  95. // inboundCanHostFallbacks gates the settings.fallbacks injection.
  96. // Xray only honors fallbacks on VLESS and Trojan inbounds carried over
  97. // TCP transport with TLS or Reality security. This is intentionally stricter
  98. // than inboundCanEnableTlsFlow (which also accepts XHTTP+vlessenc): fallbacks
  99. // are a raw-TCP-only feature.
  100. func inboundCanHostFallbacks(ib *model.Inbound) bool {
  101. if ib == nil {
  102. return false
  103. }
  104. if ib.Protocol != model.VLESS && ib.Protocol != model.Trojan {
  105. return false
  106. }
  107. return streamSupportsFallbacks(ib.StreamSettings)
  108. }
  109. // streamSupportsFallbacks reports whether the stream is raw TCP carried over
  110. // TLS or REALITY — the only transport Xray honors inbound fallbacks on (and the
  111. // classic requirement for XTLS Vision before vlessenc).
  112. func streamSupportsFallbacks(streamSettings string) bool {
  113. if streamSettings == "" {
  114. return false
  115. }
  116. var stream struct {
  117. Network string `json:"network"`
  118. Security string `json:"security"`
  119. }
  120. if err := json.Unmarshal([]byte(streamSettings), &stream); err != nil {
  121. return false
  122. }
  123. if stream.Network != "tcp" {
  124. return false
  125. }
  126. return stream.Security == "tls" || stream.Security == "reality"
  127. }