1
0

types.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package tuic
  2. import (
  3. "crypto/sha256"
  4. "encoding/json"
  5. "fmt"
  6. "net"
  7. "os"
  8. "slices"
  9. "strconv"
  10. "strings"
  11. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  12. )
  13. type TuicServerSettings struct {
  14. Certificate string `json:"certificate"`
  15. PrivateKey string `json:"private_key"`
  16. CongestionControl string `json:"congestion_control"`
  17. ALPN []string `json:"alpn"`
  18. UDPRelayMode string `json:"udp_relay_mode"`
  19. ZeroRTTHandshake bool `json:"zero_rtt_handshake"`
  20. LogLevel string `json:"log_level"`
  21. MaxIdleTime int `json:"max_idle_time"`
  22. AuthenticationTimeout int `json:"authentication_timeout"`
  23. MaxUdpRelayPacketSize int `json:"max_udp_relay_packet_size"`
  24. SNI string `json:"sni,omitempty"`
  25. }
  26. type TuicClientSettings struct {
  27. TrafficID int `json:"-"`
  28. UUID string `json:"uuid"`
  29. Password string `json:"password"`
  30. Email string `json:"email"`
  31. }
  32. type Instance struct {
  33. Id int
  34. Tag string
  35. Listen string
  36. Port int
  37. Certificate string
  38. PrivateKey string
  39. CongestionControl string // Applied to new native QUIC connections and exported to client profiles.
  40. ALPN []string
  41. UDPRelayMode string // Default mode exported to client links; the listener accepts both modes.
  42. ZeroRTTHandshake bool
  43. LogLevel string
  44. MaxIdleTime int
  45. AuthenticationTimeout int
  46. MaxUdpRelayPacketSize int
  47. SNI string // Exported to client links; it doesn't change the native listener certificate.
  48. Clients []TuicClientSettings
  49. }
  50. func (inst Instance) BindTo() string {
  51. return net.JoinHostPort(inst.Listen, strconv.Itoa(inst.Port))
  52. }
  53. func (inst Instance) StructuralFingerprint() string {
  54. parts := []string{
  55. inst.BindTo(),
  56. fingerprintMaterial(inst.Certificate),
  57. fingerprintMaterial(inst.PrivateKey),
  58. strings.Join(inst.ALPN, ","),
  59. strconv.FormatBool(inst.ZeroRTTHandshake),
  60. strconv.Itoa(inst.MaxIdleTime),
  61. strconv.Itoa(inst.AuthenticationTimeout),
  62. strconv.Itoa(inst.MaxUdpRelayPacketSize),
  63. }
  64. return strings.Join(parts, "|")
  65. }
  66. func fingerprintMaterial(value string) string {
  67. material := []byte(value)
  68. if value != "" && !strings.Contains(value, "-----BEGIN ") {
  69. if file, err := os.ReadFile(value); err == nil {
  70. material = file
  71. }
  72. }
  73. return fmt.Sprintf("%x", sha256.Sum256(material))
  74. }
  75. func (inst Instance) UsersFingerprint() string {
  76. pairs := make([]string, 0, len(inst.Clients))
  77. for _, c := range inst.Clients {
  78. pairs = append(pairs, fmt.Sprintf("%d:%s=%s:%s", c.TrafficID, c.Email, c.UUID, c.Password))
  79. }
  80. slices.Sort(pairs)
  81. return strings.Join(pairs, "|")
  82. }
  83. func (inst Instance) FullFingerprint() string {
  84. return inst.StructuralFingerprint() + "#" + inst.UsersFingerprint()
  85. }
  86. func InstanceFromInbound(ib *model.Inbound) (Instance, bool) {
  87. if ib == nil || ib.Protocol != model.TUIC {
  88. return Instance{}, false
  89. }
  90. var parsed struct {
  91. Certificate string `json:"certificate"`
  92. PrivateKey string `json:"private_key"`
  93. CongestionControl string `json:"congestion_control"`
  94. ALPN []string `json:"alpn"`
  95. UDPRelayMode string `json:"udp_relay_mode"`
  96. ZeroRTTHandshake *bool `json:"zero_rtt_handshake"`
  97. LogLevel string `json:"log_level"`
  98. MaxIdleTime int `json:"max_idle_time"`
  99. AuthenticationTimeout int `json:"authentication_timeout"`
  100. MaxUdpRelayPacketSize int `json:"max_udp_relay_packet_size"`
  101. SNI string `json:"sni"`
  102. Server *struct {
  103. Certificate string `json:"certificate"`
  104. PrivateKey string `json:"private_key"`
  105. CongestionControl string `json:"congestion_control"`
  106. ALPN []string `json:"alpn"`
  107. UDPRelayMode string `json:"udp_relay_mode"`
  108. ZeroRTTHandshake *bool `json:"zero_rtt_handshake"`
  109. LogLevel string `json:"log_level"`
  110. MaxIdleTime int `json:"max_idle_time"`
  111. AuthenticationTimeout int `json:"authentication_timeout"`
  112. MaxUdpRelayPacketSize int `json:"max_udp_relay_packet_size"`
  113. SNI string `json:"sni"`
  114. } `json:"server"`
  115. Clients []struct {
  116. TrafficID int `json:"traffic_id"`
  117. UUID string `json:"uuid"`
  118. ID string `json:"id"`
  119. Password string `json:"password"`
  120. Email string `json:"email"`
  121. Enable *bool `json:"enable"`
  122. TotalGB int64 `json:"totalGB"`
  123. ExpiryTime int64 `json:"expiryTime"`
  124. } `json:"clients"`
  125. }
  126. if ib.Settings != "" {
  127. if err := json.Unmarshal([]byte(ib.Settings), &parsed); err != nil {
  128. return Instance{}, false
  129. }
  130. }
  131. cert := parsed.Certificate
  132. key := parsed.PrivateKey
  133. cc := parsed.CongestionControl
  134. alpn := parsed.ALPN
  135. udpRelayMode := parsed.UDPRelayMode
  136. zeroRtt := true
  137. if parsed.ZeroRTTHandshake != nil {
  138. zeroRtt = *parsed.ZeroRTTHandshake
  139. }
  140. logLevel := parsed.LogLevel
  141. maxIdle := parsed.MaxIdleTime
  142. authTimeout := parsed.AuthenticationTimeout
  143. maxPacketSize := parsed.MaxUdpRelayPacketSize
  144. sni := parsed.SNI
  145. if parsed.Server != nil {
  146. if parsed.Server.Certificate != "" {
  147. cert = parsed.Server.Certificate
  148. }
  149. if parsed.Server.PrivateKey != "" {
  150. key = parsed.Server.PrivateKey
  151. }
  152. if parsed.Server.CongestionControl != "" {
  153. cc = parsed.Server.CongestionControl
  154. }
  155. if len(parsed.Server.ALPN) > 0 {
  156. alpn = parsed.Server.ALPN
  157. }
  158. if parsed.Server.UDPRelayMode != "" {
  159. udpRelayMode = parsed.Server.UDPRelayMode
  160. }
  161. if parsed.Server.ZeroRTTHandshake != nil {
  162. zeroRtt = *parsed.Server.ZeroRTTHandshake
  163. }
  164. if parsed.Server.LogLevel != "" {
  165. logLevel = parsed.Server.LogLevel
  166. }
  167. if parsed.Server.MaxIdleTime > 0 {
  168. maxIdle = parsed.Server.MaxIdleTime
  169. }
  170. if parsed.Server.AuthenticationTimeout > 0 {
  171. authTimeout = parsed.Server.AuthenticationTimeout
  172. }
  173. if parsed.Server.MaxUdpRelayPacketSize > 0 {
  174. maxPacketSize = parsed.Server.MaxUdpRelayPacketSize
  175. }
  176. if parsed.Server.SNI != "" {
  177. sni = parsed.Server.SNI
  178. }
  179. }
  180. if normalized, err := NormalizeCongestionControl(cc); err == nil {
  181. cc = normalized
  182. } else {
  183. cc = "new_reno"
  184. }
  185. if len(alpn) == 0 {
  186. alpn = []string{"h3", "spdy/3.1"}
  187. }
  188. if udpRelayMode == "" {
  189. udpRelayMode = "native"
  190. }
  191. if logLevel == "" {
  192. logLevel = "info"
  193. }
  194. if maxIdle <= 0 {
  195. maxIdle = 15
  196. }
  197. if authTimeout <= 0 {
  198. authTimeout = 3
  199. }
  200. if maxPacketSize <= 0 {
  201. maxPacketSize = 1500
  202. } else if maxPacketSize > maxSafeUdpRelayPacketSize && maxPacketSize <= maxLegacyUdpRelayPacketSize {
  203. maxPacketSize = maxSafeUdpRelayPacketSize
  204. }
  205. clients := make([]TuicClientSettings, 0, len(parsed.Clients))
  206. for _, c := range parsed.Clients {
  207. if c.Enable != nil && !*c.Enable {
  208. continue
  209. }
  210. uuidVal := strings.ToLower(strings.TrimSpace(c.UUID))
  211. if uuidVal == "" {
  212. uuidVal = strings.ToLower(strings.TrimSpace(c.ID))
  213. }
  214. if uuidVal == "" || c.Password == "" {
  215. continue
  216. }
  217. clients = append(clients, TuicClientSettings{
  218. TrafficID: c.TrafficID,
  219. UUID: uuidVal,
  220. Password: c.Password,
  221. Email: c.Email,
  222. })
  223. }
  224. return Instance{
  225. Id: ib.Id,
  226. Tag: ib.Tag,
  227. Listen: ib.Listen,
  228. Port: ib.Port,
  229. Certificate: cert,
  230. PrivateKey: key,
  231. CongestionControl: cc,
  232. ALPN: alpn,
  233. UDPRelayMode: udpRelayMode,
  234. ZeroRTTHandshake: zeroRtt,
  235. LogLevel: logLevel,
  236. MaxIdleTime: maxIdle,
  237. AuthenticationTimeout: authTimeout,
  238. MaxUdpRelayPacketSize: maxPacketSize,
  239. SNI: sni,
  240. Clients: clients,
  241. }, true
  242. }
  243. func NormalizeCongestionControl(value string) (string, error) {
  244. switch strings.ToLower(strings.TrimSpace(value)) {
  245. case "", "bbr":
  246. return "bbr", nil
  247. case "cubic":
  248. return "cubic", nil
  249. case "new_reno", "reno":
  250. return "new_reno", nil
  251. default:
  252. return "", fmt.Errorf("tuic: unsupported congestion controller %q", value)
  253. }
  254. }