udp_associations.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package tuic
  2. import (
  3. "context"
  4. "errors"
  5. "sync"
  6. "time"
  7. )
  8. const (
  9. maxUdpAssociations = 256
  10. udpAssociationIdleTimeout = 5 * time.Minute
  11. )
  12. var errUdpAssociationClosed = errors.New("tuic: UDP association is closed")
  13. type udpAssociation struct {
  14. responseTransport uint8
  15. relay *udpRelaySession
  16. lastActive time.Time
  17. }
  18. type udpAssociationRegistry struct {
  19. mu sync.Mutex
  20. associations map[uint16]*udpAssociation
  21. datagramReassembler *packetReassembler
  22. streamReassembler *packetReassembler
  23. maxPacketSize int
  24. }
  25. func newUdpAssociationRegistry(maxPacketSize int) *udpAssociationRegistry {
  26. return &udpAssociationRegistry{
  27. associations: make(map[uint16]*udpAssociation),
  28. datagramReassembler: newPacketReassembler(maxPacketSize),
  29. streamReassembler: newPacketReassembler(maxPacketSize),
  30. maxPacketSize: maxPacketSize,
  31. }
  32. }
  33. func (r *udpAssociationRegistry) feed(transport uint8, hdr *PacketHeader, payload []byte) (*udpAssociation, *Address, []byte, bool) {
  34. if !validPacketFragment(hdr, payload, r.maxPacketSize) {
  35. return nil, nil, nil, false
  36. }
  37. now := time.Now()
  38. r.mu.Lock()
  39. defer r.mu.Unlock()
  40. r.expireLocked(now)
  41. association := r.associations[hdr.AssocID]
  42. if association == nil {
  43. if len(r.associations) >= maxUdpAssociations {
  44. return nil, nil, nil, false
  45. }
  46. association = &udpAssociation{responseTransport: transport, lastActive: now}
  47. r.associations[hdr.AssocID] = association
  48. }
  49. association.lastActive = now
  50. reassembler := r.datagramReassembler
  51. if transport == packetTransportStream {
  52. reassembler = r.streamReassembler
  53. }
  54. addr, completePayload, complete := reassembler.feed(transport, hdr, payload)
  55. return association, addr, completePayload, complete
  56. }
  57. func validPacketFragment(hdr *PacketHeader, payload []byte, maxPacketSize int) bool {
  58. if hdr == nil || hdr.FragTotal == 0 || hdr.FragID >= hdr.FragTotal || int(hdr.Size) != len(payload) || len(payload) > maxPacketSize {
  59. return false
  60. }
  61. if hdr.FragTotal == 1 {
  62. return hdr.FragID == 0 && isPacketTarget(hdr.Addr)
  63. }
  64. return (hdr.FragID != 0 || isPacketTarget(hdr.Addr)) &&
  65. (hdr.FragID == 0 || hdr.Addr == nil || hdr.Addr.Type == AddrTypeNone)
  66. }
  67. func (r *udpAssociationRegistry) ensureRelay(ctx context.Context, assocID uint16, expected *udpAssociation, user *User, relay *SocksRelay) (*udpAssociation, bool, error) {
  68. r.mu.Lock()
  69. association := r.associations[assocID]
  70. if association == nil || association != expected {
  71. r.mu.Unlock()
  72. return nil, false, errUdpAssociationClosed
  73. }
  74. if association.relay != nil {
  75. association.lastActive = time.Now()
  76. r.mu.Unlock()
  77. return association, false, nil
  78. }
  79. r.mu.Unlock()
  80. socksSession, err := relay.DialUDP(ctx, user.Email)
  81. if err != nil {
  82. return nil, false, err
  83. }
  84. r.mu.Lock()
  85. defer r.mu.Unlock()
  86. current := r.associations[assocID]
  87. if current != association {
  88. _ = socksSession.Close()
  89. return nil, false, errUdpAssociationClosed
  90. }
  91. if current.relay != nil {
  92. _ = socksSession.Close()
  93. current.lastActive = time.Now()
  94. return current, false, nil
  95. }
  96. current.relay = &udpRelaySession{relay: socksSession, responseTransport: current.responseTransport}
  97. current.lastActive = time.Now()
  98. return current, true, nil
  99. }
  100. func (r *udpAssociationRegistry) dissociate(assocID uint16) bool {
  101. r.mu.Lock()
  102. association := r.associations[assocID]
  103. delete(r.associations, assocID)
  104. r.datagramReassembler.clearAssociation(assocID)
  105. r.streamReassembler.clearAssociation(assocID)
  106. r.mu.Unlock()
  107. if association == nil {
  108. return false
  109. }
  110. if association.relay != nil {
  111. _ = association.relay.relay.Close()
  112. }
  113. return true
  114. }
  115. func (r *udpAssociationRegistry) touch(assocID uint16, expected *udpAssociation, now time.Time) bool {
  116. r.mu.Lock()
  117. defer r.mu.Unlock()
  118. current := r.associations[assocID]
  119. if current == nil || current != expected {
  120. return false
  121. }
  122. current.lastActive = now
  123. return true
  124. }
  125. func (r *udpAssociationRegistry) reapIdle(now time.Time) {
  126. r.mu.Lock()
  127. r.expireLocked(now)
  128. r.mu.Unlock()
  129. }
  130. func (r *udpAssociationRegistry) expireLocked(now time.Time) {
  131. for assocID, association := range r.associations {
  132. if now.Sub(association.lastActive) <= udpAssociationIdleTimeout {
  133. continue
  134. }
  135. delete(r.associations, assocID)
  136. r.datagramReassembler.clearAssociation(assocID)
  137. r.streamReassembler.clearAssociation(assocID)
  138. if association.relay != nil {
  139. _ = association.relay.relay.Close()
  140. }
  141. }
  142. }
  143. func (r *udpAssociationRegistry) closeAll() {
  144. r.mu.Lock()
  145. for _, association := range r.associations {
  146. if association.relay != nil {
  147. _ = association.relay.relay.Close()
  148. }
  149. }
  150. r.associations = make(map[uint16]*udpAssociation)
  151. r.datagramReassembler.clearAll()
  152. r.streamReassembler.clearAll()
  153. r.mu.Unlock()
  154. }
  155. func (r *udpAssociationRegistry) release(id uint16, expected *udpAssociation) {
  156. r.mu.Lock()
  157. if r.associations[id] == expected {
  158. delete(r.associations, id)
  159. r.datagramReassembler.clearAssociation(id)
  160. r.streamReassembler.clearAssociation(id)
  161. }
  162. r.mu.Unlock()
  163. if expected.relay != nil {
  164. _ = expected.relay.relay.Close()
  165. }
  166. }