1
0

server.go 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. package tuic
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/tls"
  6. "encoding/binary"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "net"
  11. "strings"
  12. "sync"
  13. "sync/atomic"
  14. "time"
  15. "github.com/apernet/quic-go"
  16. xraycongestion "github.com/xtls/xray-core/transport/internet/hysteria/congestion"
  17. "github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
  18. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  19. )
  20. // Server is an in-process native Go TUIC v5 server terminating QUIC
  21. // and bridging decrypted TCP/UDP into a local SOCKS5 inbound.
  22. type Server struct {
  23. id int
  24. tag atomic.Pointer[string]
  25. listenAddr string
  26. authTimeout time.Duration
  27. congestionControl atomic.Value
  28. logLevel atomic.Uint32
  29. maxUdpRelayPacketSize int
  30. users *UserRegistry
  31. relay *SocksRelay
  32. tlsConfig *tls.Config
  33. quicConfig *quic.Config
  34. quicListener *quic.Listener
  35. packetConn net.PacketConn
  36. lastOnline sync.Map // email string -> time.Time
  37. logThrottle sync.Map // event name -> *atomic.Int64 timestamp
  38. activeConnsMu sync.Mutex
  39. activeConns map[[16]byte]map[*quic.Conn]*User
  40. connectionsMu sync.Mutex
  41. connections map[*quic.Conn]struct{}
  42. ctx context.Context
  43. cancel context.CancelFunc
  44. wg sync.WaitGroup
  45. closed atomic.Bool
  46. running atomic.Bool
  47. }
  48. // NewServer creates a new TUIC v5 Server instance.
  49. func NewServer(inst Instance, relay *SocksRelay) (*Server, error) {
  50. if err := ValidateClients(inst.Clients); err != nil {
  51. return nil, err
  52. }
  53. if inst.Certificate == "" || inst.PrivateKey == "" {
  54. return nil, errors.New("tuic: certificate or private key missing")
  55. }
  56. tlsCert, err := loadCertificate(inst.Certificate, inst.PrivateKey)
  57. if err != nil {
  58. return nil, fmt.Errorf("tuic: load tls certificate: %w", err)
  59. }
  60. alpn := inst.ALPN
  61. if len(alpn) == 0 {
  62. alpn = []string{"h3", "spdy/3.1"}
  63. }
  64. tlsConfig := &tls.Config{
  65. Certificates: []tls.Certificate{tlsCert},
  66. NextProtos: alpn,
  67. }
  68. maxIdle := inst.MaxIdleTime
  69. if maxIdle <= 0 {
  70. maxIdle = 15
  71. }
  72. authTimeout := inst.AuthenticationTimeout
  73. if authTimeout <= 0 {
  74. authTimeout = 3
  75. }
  76. maxUdpSize := inst.MaxUdpRelayPacketSize
  77. if maxUdpSize <= 0 {
  78. maxUdpSize = 1500
  79. }
  80. if maxUdpSize > maxSafeUdpRelayPacketSize && maxUdpSize <= maxLegacyUdpRelayPacketSize {
  81. maxUdpSize = maxSafeUdpRelayPacketSize
  82. }
  83. if maxUdpSize > maxLegacyUdpRelayPacketSize {
  84. return nil, fmt.Errorf("tuic: max UDP relay packet size %d exceeds %d", maxUdpSize, maxSafeUdpRelayPacketSize)
  85. }
  86. quicConfig := &quic.Config{
  87. EnableDatagrams: true,
  88. MaxIdleTimeout: time.Duration(maxIdle) * time.Second,
  89. KeepAlivePeriod: time.Duration(maxIdle/2) * time.Second,
  90. Allow0RTT: inst.ZeroRTTHandshake,
  91. }
  92. registry := NewUserRegistry()
  93. registry.SetUsers(inst.Clients)
  94. ctx, cancel := context.WithCancel(context.Background())
  95. s := &Server{
  96. id: inst.Id,
  97. listenAddr: inst.BindTo(),
  98. authTimeout: time.Duration(authTimeout) * time.Second,
  99. maxUdpRelayPacketSize: maxUdpSize,
  100. users: registry,
  101. activeConns: make(map[[16]byte]map[*quic.Conn]*User),
  102. connections: make(map[*quic.Conn]struct{}),
  103. relay: relay,
  104. tlsConfig: tlsConfig,
  105. quicConfig: quicConfig,
  106. ctx: ctx,
  107. cancel: cancel,
  108. }
  109. s.updateRuntimeSettings(inst.Tag, inst.CongestionControl, inst.LogLevel)
  110. return s, nil
  111. }
  112. // Start opens the UDP socket and starts the QUIC listener.
  113. func (s *Server) Start() error {
  114. var lc net.ListenConfig
  115. pConn, err := lc.ListenPacket(s.ctx, "udp", s.listenAddr)
  116. if err != nil {
  117. return fmt.Errorf("tuic: listen packet on %s: %w", s.listenAddr, err)
  118. }
  119. s.packetConn = pConn
  120. ln, err := quic.Listen(pConn, s.tlsConfig, s.quicConfig)
  121. if err != nil {
  122. _ = pConn.Close()
  123. return fmt.Errorf("tuic: quic listen on %s: %w", s.listenAddr, err)
  124. }
  125. s.quicListener = ln
  126. s.running.Store(true)
  127. s.logf(tuicLogInfo, "listener started on %s", s.listenAddr)
  128. s.wg.Add(1)
  129. go s.acceptLoop()
  130. return nil
  131. }
  132. // IsRunning returns whether the server is currently accepting connections.
  133. func (s *Server) IsRunning() bool {
  134. return s.running.Load() && !s.closed.Load()
  135. }
  136. func (s *Server) updateRuntimeSettings(tag, controller, logLevel string) {
  137. tagCopy := tag
  138. s.tag.Store(&tagCopy)
  139. s.logLevel.Store(parseLogLevel(logLevel))
  140. normalized, valid := normalizeCongestionControl(controller)
  141. s.congestionControl.Store(normalized)
  142. if !valid {
  143. s.logf(tuicLogWarn, "unsupported congestion controller %q; using %s", controller, normalized)
  144. }
  145. }
  146. func (s *Server) UpdateRuntimeSettings(tag, controller, logLevel string) {
  147. s.updateRuntimeSettings(tag, controller, logLevel)
  148. }
  149. // applyCongestionControl installs Xray's BBR on an accepted connection; quic-go
  150. // itself only ships New Reno, so a CUBIC choice is served as New Reno.
  151. func (s *Server) applyCongestionControl(conn *quic.Conn) {
  152. controller, _ := s.congestionControl.Load().(string)
  153. switch controller {
  154. case "bbr":
  155. xraycongestion.UseBBR(conn, bbr.ProfileStandard)
  156. s.logf(tuicLogDebug, "applied bbr congestion controller")
  157. case "cubic":
  158. s.logf(tuicLogDebug, "cubic is not available; applied new_reno congestion controller")
  159. default:
  160. s.logf(tuicLogDebug, "applied new_reno congestion controller")
  161. }
  162. }
  163. func (s *Server) registerConn(user *User, conn *quic.Conn) {
  164. s.activeConnsMu.Lock()
  165. defer s.activeConnsMu.Unlock()
  166. if s.activeConns[user.UUID] == nil {
  167. s.activeConns[user.UUID] = make(map[*quic.Conn]*User)
  168. }
  169. s.activeConns[user.UUID][conn] = user
  170. user.sessions.Add(1)
  171. }
  172. func (s *Server) unregisterConn(user *User, conn *quic.Conn) {
  173. s.activeConnsMu.Lock()
  174. if conns := s.activeConns[user.UUID]; conns != nil {
  175. if registered, ok := conns[conn]; ok {
  176. delete(conns, conn)
  177. if registered == user {
  178. s.users.sessionEnded(user)
  179. }
  180. }
  181. if len(conns) == 0 {
  182. delete(s.activeConns, user.UUID)
  183. }
  184. }
  185. s.activeConnsMu.Unlock()
  186. }
  187. func (s *Server) closeUserConns(user *User) {
  188. s.activeConnsMu.Lock()
  189. conns := s.activeConns[user.UUID]
  190. var toClose []*quic.Conn
  191. for conn, registered := range conns {
  192. if registered == user {
  193. toClose = append(toClose, conn)
  194. }
  195. }
  196. s.activeConnsMu.Unlock()
  197. for _, conn := range toClose {
  198. _ = conn.CloseWithError(0x100, "tuic: user revoked")
  199. }
  200. }
  201. func (s *Server) closeAllConns() {
  202. s.connectionsMu.Lock()
  203. var all []*quic.Conn
  204. for conn := range s.connections {
  205. all = append(all, conn)
  206. }
  207. s.connectionsMu.Unlock()
  208. for _, conn := range all {
  209. _ = conn.CloseWithError(0x00, "tuic: server closed")
  210. }
  211. }
  212. // UpdateUsers updates the active users dynamically without restarting the listener,
  213. // and terminates active QUIC sessions for any revoked or disabled users.
  214. func (s *Server) UpdateUsers(clients []TuicClientSettings) {
  215. if err := ValidateClients(clients); err != nil {
  216. s.logLimited(tuicLogWarn, "users-invalid", 30*time.Second, "User update rejected: %v", err)
  217. return
  218. }
  219. revoked := s.users.SetUsers(clients)
  220. if len(revoked) > 0 {
  221. s.logf(tuicLogDebug, "Revoked %d user registrations", len(revoked))
  222. }
  223. for _, u := range revoked {
  224. s.closeUserConns(u)
  225. }
  226. }
  227. // GetActiveEmails returns emails that were active within the specified time window.
  228. func (s *Server) GetActiveEmails(window time.Duration) []string {
  229. now := time.Now()
  230. var active []string
  231. s.lastOnline.Range(func(key, value any) bool {
  232. email := key.(string)
  233. lastTime := value.(time.Time)
  234. if now.Sub(lastTime) <= window {
  235. active = append(active, email)
  236. }
  237. return true
  238. })
  239. return active
  240. }
  241. // CollectClientTraffic drains and returns traffic deltas for each client.
  242. func (s *Server) CollectClientTraffic() []ClientTrafficDelta {
  243. deltas := s.users.CollectTrafficDeltas()
  244. for i := range deltas {
  245. deltas[i].InboundID = s.id
  246. }
  247. return deltas
  248. }
  249. // CollectAllTraffic drains client deltas once and returns total up, down and individual client deltas.
  250. func (s *Server) CollectAllTraffic() (int64, int64, []ClientTrafficDelta) {
  251. deltas := s.CollectClientTraffic()
  252. var totalUp, totalDown int64
  253. for _, d := range deltas {
  254. totalUp += d.Up
  255. totalDown += d.Down
  256. }
  257. return totalUp, totalDown, deltas
  258. }
  259. func (s *Server) markActive(email string) {
  260. if email != "" {
  261. s.lastOnline.Store(email, time.Now())
  262. }
  263. }
  264. // AddTestTraffic adds byte counts to a client for testing purposes.
  265. func (s *Server) AddTestTraffic(email string, up, down int64) bool {
  266. s.markActive(email)
  267. return s.users.AddTestTraffic(email, up, down)
  268. }
  269. func (s *Server) acceptLoop() {
  270. defer s.wg.Done()
  271. for {
  272. conn, err := s.quicListener.Accept(s.ctx)
  273. if err != nil {
  274. if s.closed.Load() {
  275. return
  276. }
  277. s.running.Store(false)
  278. s.logf(tuicLogError, "QUIC listener stopped accepting connections: %v", err)
  279. _ = s.quicListener.Close()
  280. return
  281. }
  282. s.connectionsMu.Lock()
  283. if s.closed.Load() {
  284. s.connectionsMu.Unlock()
  285. _ = conn.CloseWithError(0x00, "tuic: server closed")
  286. return
  287. }
  288. s.connections[conn] = struct{}{}
  289. s.connectionsMu.Unlock()
  290. s.wg.Add(1)
  291. go func(c *quic.Conn) {
  292. defer s.wg.Done()
  293. s.handleConn(c)
  294. }(conn)
  295. }
  296. }
  297. func (s *Server) handleConn(conn *quic.Conn) {
  298. defer func() {
  299. s.connectionsMu.Lock()
  300. delete(s.connections, conn)
  301. s.connectionsMu.Unlock()
  302. }()
  303. s.applyCongestionControl(conn)
  304. sessCtx, sessCancel := context.WithCancel(s.ctx)
  305. stopConnWatch := context.AfterFunc(conn.Context(), sessCancel)
  306. defer stopConnWatch()
  307. var (
  308. authUser atomic.Pointer[User]
  309. authState atomic.Uint32 // 0 pending, 1 authenticated, 2 timed out
  310. authSignal = make(chan struct{})
  311. authOnce sync.Once
  312. udpAssociations = newUdpAssociationRegistry(s.maxUdpRelayPacketSize)
  313. )
  314. authTimer := time.AfterFunc(s.authTimeout, func() {
  315. if authState.CompareAndSwap(0, 2) {
  316. s.logf(tuicLogWarn, "client authentication timed out")
  317. sessCancel()
  318. _ = conn.CloseWithError(0x100, "tuic: authentication timeout")
  319. }
  320. })
  321. defer authTimer.Stop()
  322. authenticate := func(rawUUID [16]byte, token [32]byte) (*User, error) {
  323. tlsState := conn.ConnectionState().TLS
  324. return s.users.AuthenticateAndRegister(&tlsState, rawUUID, token, func(user *User) bool {
  325. if !authState.CompareAndSwap(0, 1) {
  326. return authState.Load() == 1 && authUser.Load() == user
  327. }
  328. authUser.Store(user)
  329. s.registerConn(user, conn)
  330. s.markActive(user.Email)
  331. authTimer.Stop()
  332. s.logf(tuicLogInfo, "client authenticated")
  333. authOnce.Do(func() { close(authSignal) })
  334. return true
  335. })
  336. }
  337. waitForAuth := func() (*User, error) {
  338. if authState.Load() == 1 {
  339. if u := authUser.Load(); u != nil {
  340. return u, nil
  341. }
  342. }
  343. if authState.Load() == 2 {
  344. return nil, errors.New("tuic: authentication timeout")
  345. }
  346. select {
  347. case <-authSignal:
  348. if u := authUser.Load(); u != nil {
  349. return u, nil
  350. }
  351. return nil, errors.New("tuic: authentication unavailable")
  352. case <-sessCtx.Done():
  353. return nil, sessCtx.Err()
  354. }
  355. }
  356. var relayWg sync.WaitGroup
  357. cleanup := func() {
  358. sessCancel()
  359. udpAssociations.closeAll()
  360. relayWg.Wait()
  361. if u := authUser.Load(); u != nil {
  362. s.unregisterConn(u, conn)
  363. }
  364. _ = conn.CloseWithError(0, "")
  365. }
  366. defer cleanup()
  367. var innerWg sync.WaitGroup
  368. // Loop 1: Unidirectional streams
  369. innerWg.Add(1)
  370. go func() {
  371. defer innerWg.Done()
  372. for {
  373. uniStream, err := conn.AcceptUniStream(sessCtx)
  374. if err != nil {
  375. return
  376. }
  377. innerWg.Add(1)
  378. go func(stream *quic.ReceiveStream) {
  379. defer innerWg.Done()
  380. s.handleUniStream(sessCtx, conn, stream, authenticate, waitForAuth, udpAssociations, &relayWg)
  381. }(uniStream)
  382. }
  383. }()
  384. // Loop 2: Bidirectional streams
  385. innerWg.Add(1)
  386. go func() {
  387. defer innerWg.Done()
  388. for {
  389. biStream, err := conn.AcceptStream(sessCtx)
  390. if err != nil {
  391. return
  392. }
  393. innerWg.Add(1)
  394. go func(stream *quic.Stream) {
  395. defer innerWg.Done()
  396. s.handleBiStream(sessCtx, conn, stream, authenticate, waitForAuth)
  397. }(biStream)
  398. }
  399. }()
  400. // Loop 3: Datagrams
  401. innerWg.Add(1)
  402. go func() {
  403. defer innerWg.Done()
  404. for {
  405. dgram, err := conn.ReceiveDatagram(sessCtx)
  406. if err != nil {
  407. return
  408. }
  409. s.handleDatagram(sessCtx, conn, dgram, waitForAuth, udpAssociations, &relayWg)
  410. }
  411. }()
  412. innerWg.Add(1)
  413. go func() {
  414. defer innerWg.Done()
  415. ticker := time.NewTicker(time.Minute)
  416. defer ticker.Stop()
  417. for {
  418. select {
  419. case <-ticker.C:
  420. udpAssociations.reapIdle(time.Now())
  421. case <-sessCtx.Done():
  422. return
  423. }
  424. }
  425. }()
  426. innerWg.Wait()
  427. }
  428. func (s *Server) handleUniStream(
  429. ctx context.Context,
  430. conn *quic.Conn,
  431. stream *quic.ReceiveStream,
  432. authenticate func([16]byte, [32]byte) (*User, error),
  433. waitForAuth func() (*User, error),
  434. udpAssociations *udpAssociationRegistry,
  435. relayWg *sync.WaitGroup,
  436. ) {
  437. defer stream.CancelRead(0)
  438. _, cmd, err := ReadCommand(stream)
  439. if err != nil {
  440. return
  441. }
  442. switch cmd {
  443. case CmdAuthenticate:
  444. var authData [16 + 32]byte
  445. if _, err := io.ReadFull(stream, authData[:]); err != nil {
  446. return
  447. }
  448. var rawUUID [16]byte
  449. var token [32]byte
  450. copy(rawUUID[:], authData[0:16])
  451. copy(token[:], authData[16:48])
  452. _, err := authenticate(rawUUID, token)
  453. if err != nil {
  454. s.logLimited(tuicLogWarn, "auth-rejected", 30*time.Second, "client authentication rejected")
  455. _ = conn.CloseWithError(0x100, "tuic: authentication failed")
  456. return
  457. }
  458. case CmdDissociate:
  459. if _, err := waitForAuth(); err != nil {
  460. return
  461. }
  462. var assocIDBytes [2]byte
  463. if _, err := io.ReadFull(stream, assocIDBytes[:]); err != nil {
  464. return
  465. }
  466. assocID := binary.BigEndian.Uint16(assocIDBytes[:])
  467. if udpAssociations.dissociate(assocID) {
  468. s.logf(tuicLogInfo, "UDP association %d closed", assocID)
  469. }
  470. case CmdPacket:
  471. user, err := waitForAuth()
  472. if err != nil {
  473. return
  474. }
  475. hdr, err := ReadPacketHeader(stream)
  476. if err != nil || int(hdr.Size) > s.maxUdpRelayPacketSize {
  477. s.logLimited(tuicLogWarn, "udp-malformed", 30*time.Second, "UDP packet rejected: malformed header or size limit")
  478. return
  479. }
  480. payload, err := readPacketPayload(stream, hdr)
  481. if err != nil {
  482. return
  483. }
  484. s.handlePacket(ctx, conn, user, hdr, payload, packetTransportStream, udpAssociations, relayWg)
  485. }
  486. }
  487. func (s *Server) handleBiStream(
  488. ctx context.Context,
  489. conn *quic.Conn,
  490. stream *quic.Stream,
  491. authenticate func([16]byte, [32]byte) (*User, error),
  492. waitForAuth func() (*User, error),
  493. ) {
  494. defer stream.Close()
  495. defer stream.CancelRead(0)
  496. _, cmd, err := ReadCommand(stream)
  497. if err != nil {
  498. return
  499. }
  500. switch cmd {
  501. case CmdAuthenticate:
  502. var authData [16 + 32]byte
  503. if _, err := io.ReadFull(stream, authData[:]); err != nil {
  504. return
  505. }
  506. var rawUUID [16]byte
  507. var token [32]byte
  508. copy(rawUUID[:], authData[0:16])
  509. copy(token[:], authData[16:48])
  510. _, err := authenticate(rawUUID, token)
  511. if err != nil {
  512. s.logLimited(tuicLogWarn, "auth-rejected", 30*time.Second, "client authentication rejected")
  513. _ = conn.CloseWithError(0x100, "tuic: authentication failed")
  514. return
  515. }
  516. case CmdConnect:
  517. user, err := waitForAuth()
  518. if err != nil {
  519. return
  520. }
  521. target, err := ReadAddress(stream)
  522. if err != nil {
  523. s.logLimited(tuicLogWarn, "tcp-relay", 30*time.Second, "TCP relay failed: malformed target address")
  524. return
  525. }
  526. s.markActive(user.Email)
  527. if !isPacketTarget(target) {
  528. s.logLimited(tuicLogWarn, "tcp-relay", 30*time.Second, "TCP relay failed: invalid target address")
  529. return
  530. }
  531. socksConn, err := s.relay.DialTCP(ctx, user.Email, target)
  532. if err != nil {
  533. s.logLimited(tuicLogWarn, "tcp-relay", 30*time.Second, "TCP relay failed: %v", err)
  534. return
  535. }
  536. s.logf(tuicLogInfo, "TCP relay started")
  537. PipeBiDirectionalContext(ctx, tcpRelayStream{stream}, socksConn, &user.Traffic.BytesUp, &user.Traffic.BytesDown)
  538. s.logf(tuicLogDebug, "TCP relay closed")
  539. }
  540. }
  541. type packetFragmentKey struct {
  542. assocID uint16
  543. pktID uint16
  544. transport uint8
  545. }
  546. const (
  547. packetTransportDatagram uint8 = iota
  548. packetTransportStream
  549. )
  550. type udpRelaySession struct {
  551. relay *SocksUDPSession
  552. responseTransport uint8
  553. }
  554. type packetReassembly struct {
  555. total uint8
  556. received uint8
  557. size int
  558. frags [][]byte
  559. addr *Address
  560. updatedAt time.Time
  561. }
  562. type packetReassembler struct {
  563. mu sync.Mutex
  564. maxPacketSize int
  565. packets map[packetFragmentKey]*packetReassembly
  566. }
  567. const (
  568. maxSafeUdpRelayPacketSize = maxSocksUdpDatagramSize - 262
  569. maxLegacyUdpRelayPacketSize = maxSocksUdpDatagramSize
  570. maxUdpRelayPacketSize = maxSafeUdpRelayPacketSize
  571. maxPendingPacketAssemblies = 32
  572. packetAssemblyTimeout = 10 * time.Second
  573. )
  574. func newPacketReassembler(maxPacketSize int) *packetReassembler {
  575. if maxPacketSize <= 0 || maxPacketSize > maxUdpRelayPacketSize {
  576. maxPacketSize = maxUdpRelayPacketSize
  577. }
  578. return &packetReassembler{
  579. maxPacketSize: maxPacketSize,
  580. packets: make(map[packetFragmentKey]*packetReassembly),
  581. }
  582. }
  583. func (pr *packetReassembler) feed(transport uint8, hdr *PacketHeader, payload []byte) (*Address, []byte, bool) {
  584. if hdr == nil || hdr.FragTotal == 0 || hdr.FragID >= hdr.FragTotal || int(hdr.Size) != len(payload) || len(payload) > pr.maxPacketSize {
  585. return nil, nil, false
  586. }
  587. pr.mu.Lock()
  588. defer pr.mu.Unlock()
  589. now := time.Now()
  590. pr.expireLocked(now)
  591. key := packetFragmentKey{assocID: hdr.AssocID, pktID: hdr.PktID, transport: transport}
  592. if hdr.FragTotal == 1 {
  593. if hdr.FragID != 0 || !isPacketTarget(hdr.Addr) {
  594. return nil, nil, false
  595. }
  596. delete(pr.packets, key)
  597. return hdr.Addr, payload, true
  598. }
  599. if (hdr.FragID == 0 && !isPacketTarget(hdr.Addr)) || (hdr.FragID != 0 && hdr.Addr != nil && hdr.Addr.Type != AddrTypeNone) {
  600. return nil, nil, false
  601. }
  602. entry, ok := pr.packets[key]
  603. if !ok {
  604. if len(pr.packets) >= maxPendingPacketAssemblies {
  605. return nil, nil, false
  606. }
  607. entry = &packetReassembly{
  608. total: hdr.FragTotal,
  609. frags: make([][]byte, hdr.FragTotal),
  610. updatedAt: now,
  611. }
  612. pr.packets[key] = entry
  613. } else if entry.total != hdr.FragTotal {
  614. delete(pr.packets, key)
  615. return nil, nil, false
  616. }
  617. fragment := entry.frags[hdr.FragID]
  618. if fragment != nil {
  619. if !bytes.Equal(fragment, payload) {
  620. delete(pr.packets, key)
  621. }
  622. return nil, nil, false
  623. }
  624. if entry.size+len(payload) > pr.maxPacketSize {
  625. delete(pr.packets, key)
  626. return nil, nil, false
  627. }
  628. entry.frags[hdr.FragID] = make([]byte, len(payload))
  629. copy(entry.frags[hdr.FragID], payload)
  630. entry.size += len(payload)
  631. entry.received++
  632. entry.updatedAt = now
  633. if hdr.FragID == 0 {
  634. entry.addr = hdr.Addr
  635. }
  636. if entry.received == entry.total {
  637. delete(pr.packets, key)
  638. if !isPacketTarget(entry.addr) {
  639. return nil, nil, false
  640. }
  641. assembled := make([]byte, 0, entry.size)
  642. for _, f := range entry.frags {
  643. assembled = append(assembled, f...)
  644. }
  645. return entry.addr, assembled, true
  646. }
  647. return nil, nil, false
  648. }
  649. func (pr *packetReassembler) expireLocked(now time.Time) {
  650. for key, entry := range pr.packets {
  651. if now.Sub(entry.updatedAt) > packetAssemblyTimeout {
  652. delete(pr.packets, key)
  653. }
  654. }
  655. }
  656. func (pr *packetReassembler) clearAssociation(assocID uint16) {
  657. pr.mu.Lock()
  658. defer pr.mu.Unlock()
  659. for key := range pr.packets {
  660. if key.assocID == assocID {
  661. delete(pr.packets, key)
  662. }
  663. }
  664. }
  665. func (pr *packetReassembler) clearAll() {
  666. pr.mu.Lock()
  667. pr.packets = make(map[packetFragmentKey]*packetReassembly)
  668. pr.mu.Unlock()
  669. }
  670. func isPacketTarget(addr *Address) bool {
  671. return addr != nil && addr.Type != AddrTypeNone
  672. }
  673. func readPacketPayload(r io.Reader, hdr *PacketHeader) ([]byte, error) {
  674. payload := make([]byte, int(hdr.Size))
  675. if _, err := io.ReadFull(r, payload); err != nil {
  676. return nil, err
  677. }
  678. return payload, nil
  679. }
  680. func (s *Server) handlePacket(
  681. ctx context.Context,
  682. conn *quic.Conn,
  683. user *User,
  684. hdr *PacketHeader,
  685. payload []byte,
  686. transport uint8,
  687. udpAssociations *udpAssociationRegistry,
  688. relayWg *sync.WaitGroup,
  689. ) {
  690. association, addr, fullPayload, complete := udpAssociations.feed(transport, hdr, payload)
  691. if association == nil {
  692. s.logLimited(tuicLogWarn, "udp-malformed", 30*time.Second, "UDP packet rejected")
  693. }
  694. if !complete {
  695. return
  696. }
  697. s.forwardUDPPacket(ctx, conn, user, hdr.AssocID, association, addr, fullPayload, udpAssociations, relayWg)
  698. }
  699. func (s *Server) handleDatagram(
  700. ctx context.Context,
  701. conn *quic.Conn,
  702. dgram []byte,
  703. waitForAuth func() (*User, error),
  704. udpAssociations *udpAssociationRegistry,
  705. relayWg *sync.WaitGroup,
  706. ) {
  707. if len(dgram) < 2 || dgram[0] != ProtocolVersion {
  708. return
  709. }
  710. cmd := dgram[1]
  711. switch cmd {
  712. case CmdHeartbeat:
  713. if u, _ := waitForAuth(); u != nil {
  714. s.markActive(u.Email)
  715. }
  716. case CmdPacket:
  717. user, err := waitForAuth()
  718. if err != nil {
  719. return
  720. }
  721. r := bytes.NewReader(dgram[2:])
  722. hdr, err := ReadPacketHeader(r)
  723. if err != nil || int(hdr.Size) > s.maxUdpRelayPacketSize {
  724. s.logLimited(tuicLogWarn, "udp-malformed", 30*time.Second, "UDP packet rejected: malformed header or size limit")
  725. return
  726. }
  727. payload, err := readPacketPayload(r, hdr)
  728. if err != nil || r.Len() != 0 {
  729. return
  730. }
  731. s.handlePacket(ctx, conn, user, hdr, payload, packetTransportDatagram, udpAssociations, relayWg)
  732. case CmdDissociate:
  733. if len(dgram) >= 4 {
  734. assocID := binary.BigEndian.Uint16(dgram[2:4])
  735. if udpAssociations.dissociate(assocID) {
  736. s.logf(tuicLogInfo, "UDP association %d closed", assocID)
  737. }
  738. }
  739. }
  740. }
  741. func (s *Server) forwardUDPPacket(
  742. ctx context.Context,
  743. conn *quic.Conn,
  744. user *User,
  745. assocID uint16,
  746. association *udpAssociation,
  747. target *Address,
  748. payload []byte,
  749. udpAssociations *udpAssociationRegistry,
  750. relayWg *sync.WaitGroup,
  751. ) {
  752. if len(payload) > s.maxUdpRelayPacketSize || !isPacketTarget(target) {
  753. return
  754. }
  755. if association == nil || len(payload) > s.maxUdpRelayPacketSize || !isPacketTarget(target) {
  756. return
  757. }
  758. association, created, err := udpAssociations.ensureRelay(ctx, assocID, association, user, s.relay)
  759. if err != nil {
  760. s.logLimited(tuicLogWarn, "udp-dial", 30*time.Second, "UDP relay could not be opened: %v", err)
  761. return
  762. }
  763. sess := association.relay
  764. if created {
  765. s.logf(tuicLogInfo, "UDP association %d started", assocID)
  766. relayWg.Add(1)
  767. go func() {
  768. defer relayWg.Done()
  769. s.relayUDPResponses(ctx, conn, user, assocID, association, udpAssociations, sess)
  770. }()
  771. }
  772. if _, err := sess.relay.Send(target, payload); err != nil {
  773. s.logLimited(tuicLogWarn, "udp-send", 30*time.Second, "UDP relay request failed: %v", err)
  774. return
  775. }
  776. user.Traffic.BytesUp.Add(int64(len(payload)))
  777. s.markActive(user.Email)
  778. }
  779. const (
  780. maxDatagramFragmentSize = 850
  781. maxStreamFragmentSize = 8 * 1024
  782. )
  783. func (s *Server) relayUDPResponses(
  784. ctx context.Context,
  785. conn *quic.Conn,
  786. user *User,
  787. assocID uint16,
  788. association *udpAssociation,
  789. associations *udpAssociationRegistry,
  790. sess *udpRelaySession,
  791. ) {
  792. defer associations.release(assocID, association)
  793. buf := make([]byte, s.maxUdpRelayPacketSize+263)
  794. var nextPktID uint16
  795. for {
  796. srcAddr, respPayload, err := sess.relay.Receive(buf)
  797. if err != nil {
  798. if ctx.Err() == nil && !sess.relay.closed.Load() {
  799. s.logLimited(tuicLogWarn, "udp-receive", 30*time.Second, "UDP relay receive failed: %v", err)
  800. }
  801. return
  802. }
  803. if len(respPayload) > s.maxUdpRelayPacketSize {
  804. continue
  805. }
  806. user.Traffic.BytesDown.Add(int64(len(respPayload)))
  807. s.markActive(user.Email)
  808. nextPktID++
  809. if err := s.sendUDPPacketFragments(ctx, conn, assocID, nextPktID, srcAddr, respPayload, sess.responseTransport); err != nil {
  810. if ctx.Err() == nil {
  811. s.logLimited(tuicLogWarn, "udp-response", 30*time.Second, "UDP relay response failed: %v", err)
  812. }
  813. return
  814. }
  815. associations.touch(assocID, association, time.Now())
  816. }
  817. }
  818. func (s *Server) sendUDPPacketFragments(
  819. ctx context.Context,
  820. conn *quic.Conn,
  821. assocID, pktID uint16,
  822. srcAddr *Address,
  823. payload []byte,
  824. transport uint8,
  825. ) error {
  826. if len(payload) > s.maxUdpRelayPacketSize || !isPacketTarget(srcAddr) {
  827. return fmt.Errorf("tuic: UDP response exceeds configured limit or has invalid source address")
  828. }
  829. fragmentSize := maxDatagramFragmentSize
  830. if transport == packetTransportStream {
  831. fragmentSize = maxStreamFragmentSize
  832. }
  833. fragmentTotal := (len(payload) + fragmentSize - 1) / fragmentSize
  834. if fragmentTotal == 0 {
  835. fragmentTotal = 1
  836. }
  837. if fragmentTotal > 255 {
  838. return fmt.Errorf("tuic: UDP response requires too many fragments: %d", fragmentTotal)
  839. }
  840. for i := 0; i < fragmentTotal; i++ {
  841. start := i * fragmentSize
  842. end := min(start+fragmentSize, len(payload))
  843. addr := (*Address)(nil)
  844. if i == 0 {
  845. addr = srcAddr
  846. }
  847. var frame bytes.Buffer
  848. if err := WritePacket(&frame, assocID, pktID, uint8(fragmentTotal), uint8(i), addr, payload[start:end]); err != nil {
  849. return err
  850. }
  851. if transport == packetTransportStream {
  852. stream, err := conn.OpenUniStreamSync(ctx)
  853. if err != nil {
  854. return err
  855. }
  856. if _, err := stream.Write(frame.Bytes()); err != nil {
  857. stream.CancelWrite(0)
  858. return err
  859. }
  860. if err := stream.Close(); err != nil {
  861. return err
  862. }
  863. continue
  864. }
  865. if err := conn.SendDatagram(frame.Bytes()); err != nil {
  866. return err
  867. }
  868. }
  869. return nil
  870. }
  871. // Close gracefully stops the server and releases all network resources.
  872. func (s *Server) Close() error {
  873. if s.closed.Swap(true) {
  874. return nil
  875. }
  876. s.running.Store(false)
  877. s.logf(tuicLogInfo, "listener stopped")
  878. s.cancel()
  879. var err error
  880. if s.quicListener != nil {
  881. err = s.quicListener.Close()
  882. }
  883. if s.packetConn != nil {
  884. _ = s.packetConn.Close()
  885. }
  886. s.closeAllConns()
  887. s.wg.Wait()
  888. return err
  889. }
  890. const (
  891. tuicLogDebug uint32 = iota
  892. tuicLogInfo
  893. tuicLogWarn
  894. tuicLogError
  895. )
  896. func parseLogLevel(level string) uint32 {
  897. switch strings.ToLower(strings.TrimSpace(level)) {
  898. case "debug":
  899. return tuicLogDebug
  900. case "warn", "warning":
  901. return tuicLogWarn
  902. case "error":
  903. return tuicLogError
  904. default:
  905. return tuicLogInfo
  906. }
  907. }
  908. func normalizeCongestionControl(controller string) (string, bool) {
  909. normalized, err := NormalizeCongestionControl(controller)
  910. if err != nil {
  911. return "new_reno", false
  912. }
  913. return normalized, true
  914. }
  915. func (s *Server) logf(level uint32, format string, args ...any) {
  916. if level < s.logLevel.Load() {
  917. return
  918. }
  919. tag := ""
  920. if value := s.tag.Load(); value != nil && *value != "" {
  921. tag = fmt.Sprintf(" (%s)", *value)
  922. }
  923. message := fmt.Sprintf("tuic: inbound %d%s: %s", s.id, tag, fmt.Sprintf(format, args...))
  924. switch level {
  925. case tuicLogDebug:
  926. logger.Debugf("%s", message)
  927. case tuicLogInfo:
  928. logger.Infof("%s", message)
  929. case tuicLogWarn:
  930. logger.Warningf("%s", message)
  931. case tuicLogError:
  932. logger.Errorf("%s", message)
  933. }
  934. }
  935. func (s *Server) logLimited(level uint32, key string, interval time.Duration, format string, args ...any) {
  936. if level < s.logLevel.Load() {
  937. return
  938. }
  939. value, _ := s.logThrottle.LoadOrStore(key, &atomic.Int64{})
  940. stamp := value.(*atomic.Int64)
  941. now := time.Now().UnixNano()
  942. last := stamp.Load()
  943. if last != 0 && time.Duration(now-last) < interval {
  944. return
  945. }
  946. if stamp.CompareAndSwap(last, now) {
  947. s.logf(level, format, args...)
  948. }
  949. }
  950. func loadCertificate(certInput, keyInput string) (tls.Certificate, error) {
  951. if strings.Contains(certInput, "-----BEGIN CERTIFICATE-----") {
  952. return tls.X509KeyPair([]byte(certInput), []byte(keyInput))
  953. }
  954. return tls.LoadX509KeyPair(certInput, keyInput)
  955. }
  956. // QUIC Close sends FIN but does not interrupt reads. Relay cancellation must
  957. // cancel reads too, while a normal EOF preserves the peer's half-close.
  958. type tcpRelayStream struct{ *quic.Stream }
  959. func (stream tcpRelayStream) Close() error {
  960. stream.CancelRead(0)
  961. return stream.Stream.Close()
  962. }
  963. func (stream tcpRelayStream) CloseWrite() error { return stream.Stream.Close() }