tracker.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package trafficontrol
  2. import (
  3. "net"
  4. "net/netip"
  5. "time"
  6. "github.com/sagernet/sing-box/adapter"
  7. "github.com/sagernet/sing-box/experimental/trackerconn"
  8. "github.com/sagernet/sing/common"
  9. N "github.com/sagernet/sing/common/network"
  10. "github.com/gofrs/uuid"
  11. "go.uber.org/atomic"
  12. )
  13. type Metadata struct {
  14. NetWork string `json:"network"`
  15. Type string `json:"type"`
  16. SrcIP netip.Addr `json:"sourceIP"`
  17. DstIP netip.Addr `json:"destinationIP"`
  18. SrcPort string `json:"sourcePort"`
  19. DstPort string `json:"destinationPort"`
  20. Host string `json:"host"`
  21. DNSMode string `json:"dnsMode"`
  22. ProcessPath string `json:"processPath"`
  23. }
  24. type tracker interface {
  25. ID() string
  26. Close() error
  27. Leave()
  28. }
  29. type trackerInfo struct {
  30. UUID uuid.UUID `json:"id"`
  31. Metadata Metadata `json:"metadata"`
  32. UploadTotal *atomic.Int64 `json:"upload"`
  33. DownloadTotal *atomic.Int64 `json:"download"`
  34. Start time.Time `json:"start"`
  35. Chain []string `json:"chains"`
  36. Rule string `json:"rule"`
  37. RulePayload string `json:"rulePayload"`
  38. }
  39. type tcpTracker struct {
  40. N.ExtendedConn `json:"-"`
  41. *trackerInfo
  42. manager *Manager
  43. }
  44. func (tt *tcpTracker) ID() string {
  45. return tt.UUID.String()
  46. }
  47. func (tt *tcpTracker) Close() error {
  48. tt.manager.Leave(tt)
  49. return tt.ExtendedConn.Close()
  50. }
  51. func (tt *tcpTracker) Leave() {
  52. tt.manager.Leave(tt)
  53. }
  54. func (tt *tcpTracker) Upstream() any {
  55. return tt.ExtendedConn
  56. }
  57. func (tt *tcpTracker) ReaderReplaceable() bool {
  58. return true
  59. }
  60. func (tt *tcpTracker) WriterReplaceable() bool {
  61. return true
  62. }
  63. func NewTCPTracker(conn net.Conn, manager *Manager, metadata Metadata, router adapter.Router, rule adapter.Rule) *tcpTracker {
  64. uuid, _ := uuid.NewV4()
  65. var chain []string
  66. var next string
  67. if rule == nil {
  68. next = router.DefaultOutbound(N.NetworkTCP).Tag()
  69. } else {
  70. next = rule.Outbound()
  71. }
  72. for {
  73. chain = append(chain, next)
  74. detour, loaded := router.Outbound(next)
  75. if !loaded {
  76. break
  77. }
  78. group, isGroup := detour.(adapter.OutboundGroup)
  79. if !isGroup {
  80. break
  81. }
  82. next = group.Now()
  83. }
  84. upload := atomic.NewInt64(0)
  85. download := atomic.NewInt64(0)
  86. t := &tcpTracker{
  87. ExtendedConn: trackerconn.NewHook(conn, func(n int64) {
  88. upload.Add(n)
  89. manager.PushUploaded(n)
  90. }, func(n int64) {
  91. download.Add(n)
  92. manager.PushDownloaded(n)
  93. }),
  94. manager: manager,
  95. trackerInfo: &trackerInfo{
  96. UUID: uuid,
  97. Start: time.Now(),
  98. Metadata: metadata,
  99. Chain: common.Reverse(chain),
  100. Rule: "",
  101. UploadTotal: upload,
  102. DownloadTotal: download,
  103. },
  104. }
  105. if rule != nil {
  106. t.trackerInfo.Rule = rule.String() + " => " + rule.Outbound()
  107. } else {
  108. t.trackerInfo.Rule = "final"
  109. }
  110. manager.Join(t)
  111. return t
  112. }
  113. type udpTracker struct {
  114. N.PacketConn `json:"-"`
  115. *trackerInfo
  116. manager *Manager
  117. }
  118. func (ut *udpTracker) ID() string {
  119. return ut.UUID.String()
  120. }
  121. func (ut *udpTracker) Close() error {
  122. ut.manager.Leave(ut)
  123. return ut.PacketConn.Close()
  124. }
  125. func (ut *udpTracker) Leave() {
  126. ut.manager.Leave(ut)
  127. }
  128. func (ut *udpTracker) Upstream() any {
  129. return ut.PacketConn
  130. }
  131. func (ut *udpTracker) ReaderReplaceable() bool {
  132. return true
  133. }
  134. func (ut *udpTracker) WriterReplaceable() bool {
  135. return true
  136. }
  137. func NewUDPTracker(conn N.PacketConn, manager *Manager, metadata Metadata, router adapter.Router, rule adapter.Rule) *udpTracker {
  138. uuid, _ := uuid.NewV4()
  139. var chain []string
  140. var next string
  141. if rule == nil {
  142. next = router.DefaultOutbound(N.NetworkUDP).Tag()
  143. } else {
  144. next = rule.Outbound()
  145. }
  146. for {
  147. chain = append(chain, next)
  148. detour, loaded := router.Outbound(next)
  149. if !loaded {
  150. break
  151. }
  152. group, isGroup := detour.(adapter.OutboundGroup)
  153. if !isGroup {
  154. break
  155. }
  156. next = group.Now()
  157. }
  158. upload := atomic.NewInt64(0)
  159. download := atomic.NewInt64(0)
  160. ut := &udpTracker{
  161. PacketConn: trackerconn.NewHookPacket(conn, func(n int64) {
  162. upload.Add(n)
  163. manager.PushUploaded(n)
  164. }, func(n int64) {
  165. download.Add(n)
  166. manager.PushDownloaded(n)
  167. }),
  168. manager: manager,
  169. trackerInfo: &trackerInfo{
  170. UUID: uuid,
  171. Start: time.Now(),
  172. Metadata: metadata,
  173. Chain: common.Reverse(chain),
  174. Rule: "",
  175. UploadTotal: upload,
  176. DownloadTotal: download,
  177. },
  178. }
  179. if rule != nil {
  180. ut.trackerInfo.Rule = rule.String() + " => " + rule.Outbound()
  181. } else {
  182. ut.trackerInfo.Rule = "final"
  183. }
  184. manager.Join(ut)
  185. return ut
  186. }