command_types.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. package libbox
  2. import (
  3. "slices"
  4. "strings"
  5. "time"
  6. "github.com/sagernet/sing-box/daemon"
  7. M "github.com/sagernet/sing/common/metadata"
  8. )
  9. type StatusMessage struct {
  10. Memory int64
  11. Goroutines int32
  12. ConnectionsIn int32
  13. ConnectionsOut int32
  14. TrafficAvailable bool
  15. Uplink int64
  16. Downlink int64
  17. UplinkTotal int64
  18. DownlinkTotal int64
  19. }
  20. type SystemProxyStatus struct {
  21. Available bool
  22. Enabled bool
  23. }
  24. type OutboundGroup struct {
  25. Tag string
  26. Type string
  27. Selectable bool
  28. Selected string
  29. IsExpand bool
  30. itemList []*OutboundGroupItem
  31. }
  32. func (g *OutboundGroup) GetItems() OutboundGroupItemIterator {
  33. return newIterator(g.itemList)
  34. }
  35. type OutboundGroupIterator interface {
  36. Next() *OutboundGroup
  37. HasNext() bool
  38. }
  39. type OutboundGroupItem struct {
  40. Tag string
  41. Type string
  42. URLTestTime int64
  43. URLTestDelay int32
  44. }
  45. type OutboundGroupItemIterator interface {
  46. Next() *OutboundGroupItem
  47. HasNext() bool
  48. }
  49. const (
  50. ConnectionStateAll = iota
  51. ConnectionStateActive
  52. ConnectionStateClosed
  53. )
  54. const (
  55. ConnectionEventNew = iota
  56. ConnectionEventUpdate
  57. ConnectionEventClosed
  58. )
  59. const (
  60. closedConnectionMaxAge = int64((5 * time.Minute) / time.Millisecond)
  61. )
  62. type ConnectionEvent struct {
  63. Type int32
  64. ID string
  65. Connection *Connection
  66. UplinkDelta int64
  67. DownlinkDelta int64
  68. ClosedAt int64
  69. }
  70. type ConnectionEvents struct {
  71. Reset bool
  72. events []*ConnectionEvent
  73. }
  74. func (c *ConnectionEvents) Iterator() ConnectionEventIterator {
  75. return newIterator(c.events)
  76. }
  77. type ConnectionEventIterator interface {
  78. Next() *ConnectionEvent
  79. HasNext() bool
  80. }
  81. type Connections struct {
  82. connectionMap map[string]*Connection
  83. input []Connection
  84. filtered []Connection
  85. filterState int32
  86. filterApplied bool
  87. }
  88. func NewConnections() *Connections {
  89. return &Connections{
  90. connectionMap: make(map[string]*Connection),
  91. }
  92. }
  93. func (c *Connections) ApplyEvents(events *ConnectionEvents) {
  94. if events == nil {
  95. return
  96. }
  97. if events.Reset {
  98. c.connectionMap = make(map[string]*Connection)
  99. }
  100. for _, event := range events.events {
  101. switch event.Type {
  102. case ConnectionEventNew:
  103. if event.Connection != nil {
  104. conn := *event.Connection
  105. c.connectionMap[event.ID] = &conn
  106. }
  107. case ConnectionEventUpdate:
  108. if conn, ok := c.connectionMap[event.ID]; ok {
  109. conn.Uplink = event.UplinkDelta
  110. conn.Downlink = event.DownlinkDelta
  111. conn.UplinkTotal += event.UplinkDelta
  112. conn.DownlinkTotal += event.DownlinkDelta
  113. }
  114. case ConnectionEventClosed:
  115. if event.Connection != nil {
  116. conn := *event.Connection
  117. conn.ClosedAt = event.ClosedAt
  118. conn.Uplink = 0
  119. conn.Downlink = 0
  120. c.connectionMap[event.ID] = &conn
  121. continue
  122. }
  123. if conn, ok := c.connectionMap[event.ID]; ok {
  124. conn.ClosedAt = event.ClosedAt
  125. conn.Uplink = 0
  126. conn.Downlink = 0
  127. }
  128. }
  129. }
  130. c.evictClosedConnections(time.Now().UnixMilli())
  131. c.input = c.input[:0]
  132. for _, conn := range c.connectionMap {
  133. c.input = append(c.input, *conn)
  134. }
  135. if c.filterApplied {
  136. c.FilterState(c.filterState)
  137. } else {
  138. c.filtered = c.filtered[:0]
  139. c.filtered = append(c.filtered, c.input...)
  140. }
  141. }
  142. func (c *Connections) evictClosedConnections(nowMilliseconds int64) {
  143. for id, conn := range c.connectionMap {
  144. if conn.ClosedAt == 0 {
  145. continue
  146. }
  147. if nowMilliseconds-conn.ClosedAt > closedConnectionMaxAge {
  148. delete(c.connectionMap, id)
  149. }
  150. }
  151. }
  152. func (c *Connections) FilterState(state int32) {
  153. c.filterApplied = true
  154. c.filterState = state
  155. c.filtered = c.filtered[:0]
  156. switch state {
  157. case ConnectionStateAll:
  158. c.filtered = append(c.filtered, c.input...)
  159. case ConnectionStateActive:
  160. for _, connection := range c.input {
  161. if connection.ClosedAt == 0 {
  162. c.filtered = append(c.filtered, connection)
  163. }
  164. }
  165. case ConnectionStateClosed:
  166. for _, connection := range c.input {
  167. if connection.ClosedAt != 0 {
  168. c.filtered = append(c.filtered, connection)
  169. }
  170. }
  171. }
  172. }
  173. func (c *Connections) SortByDate() {
  174. slices.SortStableFunc(c.filtered, func(x, y Connection) int {
  175. if x.CreatedAt < y.CreatedAt {
  176. return 1
  177. } else if x.CreatedAt > y.CreatedAt {
  178. return -1
  179. } else {
  180. return strings.Compare(y.ID, x.ID)
  181. }
  182. })
  183. }
  184. func (c *Connections) SortByTraffic() {
  185. slices.SortStableFunc(c.filtered, func(x, y Connection) int {
  186. xTraffic := x.Uplink + x.Downlink
  187. yTraffic := y.Uplink + y.Downlink
  188. if xTraffic < yTraffic {
  189. return 1
  190. } else if xTraffic > yTraffic {
  191. return -1
  192. } else {
  193. return strings.Compare(y.ID, x.ID)
  194. }
  195. })
  196. }
  197. func (c *Connections) SortByTrafficTotal() {
  198. slices.SortStableFunc(c.filtered, func(x, y Connection) int {
  199. xTraffic := x.UplinkTotal + x.DownlinkTotal
  200. yTraffic := y.UplinkTotal + y.DownlinkTotal
  201. if xTraffic < yTraffic {
  202. return 1
  203. } else if xTraffic > yTraffic {
  204. return -1
  205. } else {
  206. return strings.Compare(y.ID, x.ID)
  207. }
  208. })
  209. }
  210. func (c *Connections) Iterator() ConnectionIterator {
  211. return newPtrIterator(c.filtered)
  212. }
  213. type ProcessInfo struct {
  214. ProcessID int64
  215. UserID int32
  216. UserName string
  217. ProcessPath string
  218. packageNames []string
  219. }
  220. func (p *ProcessInfo) PackageNames() StringIterator {
  221. return newIterator(p.packageNames)
  222. }
  223. type Connection struct {
  224. ID string
  225. Inbound string
  226. InboundType string
  227. IPVersion int32
  228. Network string
  229. Source string
  230. Destination string
  231. Domain string
  232. Protocol string
  233. User string
  234. FromOutbound string
  235. CreatedAt int64
  236. ClosedAt int64
  237. Uplink int64
  238. Downlink int64
  239. UplinkTotal int64
  240. DownlinkTotal int64
  241. Rule string
  242. Outbound string
  243. OutboundType string
  244. chainList []string
  245. ProcessInfo *ProcessInfo
  246. }
  247. func (c *Connection) Chain() StringIterator {
  248. return newIterator(c.chainList)
  249. }
  250. func (c *Connection) DisplayDestination() string {
  251. destination := M.ParseSocksaddr(c.Destination)
  252. if destination.IsIP() && c.Domain != "" {
  253. destination = M.Socksaddr{
  254. Fqdn: c.Domain,
  255. Port: destination.Port,
  256. }
  257. return destination.String()
  258. }
  259. return c.Destination
  260. }
  261. type ConnectionIterator interface {
  262. Next() *Connection
  263. HasNext() bool
  264. }
  265. func statusMessageFromGRPC(status *daemon.Status) *StatusMessage {
  266. if status == nil {
  267. return nil
  268. }
  269. return &StatusMessage{
  270. Memory: int64(status.Memory),
  271. Goroutines: status.Goroutines,
  272. ConnectionsIn: status.ConnectionsIn,
  273. ConnectionsOut: status.ConnectionsOut,
  274. TrafficAvailable: status.TrafficAvailable,
  275. Uplink: status.Uplink,
  276. Downlink: status.Downlink,
  277. UplinkTotal: status.UplinkTotal,
  278. DownlinkTotal: status.DownlinkTotal,
  279. }
  280. }
  281. func outboundGroupIteratorFromGRPC(groups *daemon.Groups) OutboundGroupIterator {
  282. if groups == nil || len(groups.Group) == 0 {
  283. return newIterator([]*OutboundGroup{})
  284. }
  285. var libboxGroups []*OutboundGroup
  286. for _, g := range groups.Group {
  287. libboxGroup := &OutboundGroup{
  288. Tag: g.Tag,
  289. Type: g.Type,
  290. Selectable: g.Selectable,
  291. Selected: g.Selected,
  292. IsExpand: g.IsExpand,
  293. }
  294. for _, item := range g.Items {
  295. libboxGroup.itemList = append(libboxGroup.itemList, &OutboundGroupItem{
  296. Tag: item.Tag,
  297. Type: item.Type,
  298. URLTestTime: item.UrlTestTime,
  299. URLTestDelay: item.UrlTestDelay,
  300. })
  301. }
  302. libboxGroups = append(libboxGroups, libboxGroup)
  303. }
  304. return newIterator(libboxGroups)
  305. }
  306. func outboundGroupItemListFromGRPC(list *daemon.OutboundList) OutboundGroupItemIterator {
  307. if list == nil || len(list.Outbounds) == 0 {
  308. return newIterator([]*OutboundGroupItem{})
  309. }
  310. var items []*OutboundGroupItem
  311. for _, ob := range list.Outbounds {
  312. items = append(items, &OutboundGroupItem{
  313. Tag: ob.Tag,
  314. Type: ob.Type,
  315. URLTestTime: ob.UrlTestTime,
  316. URLTestDelay: ob.UrlTestDelay,
  317. })
  318. }
  319. return newIterator(items)
  320. }
  321. func connectionFromGRPC(conn *daemon.Connection) Connection {
  322. var processInfo *ProcessInfo
  323. if conn.ProcessInfo != nil {
  324. processInfo = &ProcessInfo{
  325. ProcessID: int64(conn.ProcessInfo.ProcessId),
  326. UserID: conn.ProcessInfo.UserId,
  327. UserName: conn.ProcessInfo.UserName,
  328. ProcessPath: conn.ProcessInfo.ProcessPath,
  329. packageNames: conn.ProcessInfo.PackageNames,
  330. }
  331. }
  332. return Connection{
  333. ID: conn.Id,
  334. Inbound: conn.Inbound,
  335. InboundType: conn.InboundType,
  336. IPVersion: conn.IpVersion,
  337. Network: conn.Network,
  338. Source: conn.Source,
  339. Destination: conn.Destination,
  340. Domain: conn.Domain,
  341. Protocol: conn.Protocol,
  342. User: conn.User,
  343. FromOutbound: conn.FromOutbound,
  344. CreatedAt: conn.CreatedAt,
  345. ClosedAt: conn.ClosedAt,
  346. Uplink: conn.Uplink,
  347. Downlink: conn.Downlink,
  348. UplinkTotal: conn.UplinkTotal,
  349. DownlinkTotal: conn.DownlinkTotal,
  350. Rule: conn.Rule,
  351. Outbound: conn.Outbound,
  352. OutboundType: conn.OutboundType,
  353. chainList: conn.ChainList,
  354. ProcessInfo: processInfo,
  355. }
  356. }
  357. func connectionEventFromGRPC(event *daemon.ConnectionEvent) *ConnectionEvent {
  358. if event == nil {
  359. return nil
  360. }
  361. libboxEvent := &ConnectionEvent{
  362. Type: int32(event.Type),
  363. ID: event.Id,
  364. UplinkDelta: event.UplinkDelta,
  365. DownlinkDelta: event.DownlinkDelta,
  366. ClosedAt: event.ClosedAt,
  367. }
  368. if event.Connection != nil {
  369. conn := connectionFromGRPC(event.Connection)
  370. libboxEvent.Connection = &conn
  371. }
  372. return libboxEvent
  373. }
  374. func connectionEventsFromGRPC(events *daemon.ConnectionEvents) *ConnectionEvents {
  375. if events == nil {
  376. return nil
  377. }
  378. libboxEvents := &ConnectionEvents{
  379. Reset: events.Reset_,
  380. }
  381. for _, event := range events.Events {
  382. if libboxEvent := connectionEventFromGRPC(event); libboxEvent != nil {
  383. libboxEvents.events = append(libboxEvents.events, libboxEvent)
  384. }
  385. }
  386. return libboxEvents
  387. }
  388. func systemProxyStatusFromGRPC(status *daemon.SystemProxyStatus) *SystemProxyStatus {
  389. if status == nil {
  390. return nil
  391. }
  392. return &SystemProxyStatus{
  393. Available: status.Available,
  394. Enabled: status.Enabled,
  395. }
  396. }
  397. func systemProxyStatusToGRPC(status *SystemProxyStatus) *daemon.SystemProxyStatus {
  398. if status == nil {
  399. return nil
  400. }
  401. return &daemon.SystemProxyStatus{
  402. Available: status.Available,
  403. Enabled: status.Enabled,
  404. }
  405. }