network.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package analytic
  2. import (
  3. stdnet "net"
  4. "strings"
  5. "github.com/shirou/gopsutil/v4/net"
  6. "github.com/uozi-tech/cosy/logger"
  7. )
  8. func GetNetworkStat() (data *net.IOCountersStat, err error) {
  9. networkStats, err := net.IOCounters(true)
  10. if err != nil {
  11. return
  12. }
  13. if len(networkStats) == 0 {
  14. return &net.IOCountersStat{}, nil
  15. }
  16. // Get all network interfaces
  17. interfaces, err := stdnet.Interfaces()
  18. if err != nil {
  19. logger.Error(err)
  20. return
  21. }
  22. var (
  23. totalBytesRecv uint64
  24. totalBytesSent uint64
  25. totalPacketsRecv uint64
  26. totalPacketsSent uint64
  27. totalErrIn uint64
  28. totalErrOut uint64
  29. totalDropIn uint64
  30. totalDropOut uint64
  31. totalFifoIn uint64
  32. totalFifoOut uint64
  33. )
  34. // Create a map of external interface names
  35. externalInterfaces := make(map[string]bool)
  36. // Identify external interfaces
  37. for _, iface := range interfaces {
  38. // Skip down or loopback interfaces
  39. if iface.Flags&stdnet.FlagUp == 0 ||
  40. iface.Flags&stdnet.FlagLoopback != 0 {
  41. continue
  42. }
  43. // Skip common virtual interfaces by name pattern
  44. if isVirtualInterface(iface.Name) {
  45. continue
  46. }
  47. // Handle container main interfaces like eth0 in container environments
  48. if isContainerInterface(iface.Name) {
  49. externalInterfaces[iface.Name] = true
  50. continue
  51. }
  52. // Get addresses for this interface
  53. addrs, err := iface.Addrs()
  54. if err != nil {
  55. logger.Error(err)
  56. continue
  57. }
  58. // Skip interfaces without addresses
  59. if len(addrs) == 0 {
  60. continue
  61. }
  62. // Check for non-private IP addresses
  63. for _, addr := range addrs {
  64. ip, ipNet, err := stdnet.ParseCIDR(addr.String())
  65. if err != nil {
  66. continue
  67. }
  68. // Skip virtual, local, multicast, and special purpose IPs
  69. if !isRealExternalIP(ip, ipNet) {
  70. continue
  71. }
  72. externalInterfaces[iface.Name] = true
  73. break
  74. }
  75. }
  76. // Accumulate stats only from external interfaces
  77. for _, stat := range networkStats {
  78. if externalInterfaces[stat.Name] {
  79. totalBytesRecv += stat.BytesRecv
  80. totalBytesSent += stat.BytesSent
  81. totalPacketsRecv += stat.PacketsRecv
  82. totalPacketsSent += stat.PacketsSent
  83. totalErrIn += stat.Errin
  84. totalErrOut += stat.Errout
  85. totalDropIn += stat.Dropin
  86. totalDropOut += stat.Dropout
  87. totalFifoIn += stat.Fifoin
  88. totalFifoOut += stat.Fifoout
  89. }
  90. }
  91. return &net.IOCountersStat{
  92. Name: "analytic.network",
  93. BytesRecv: totalBytesRecv,
  94. BytesSent: totalBytesSent,
  95. PacketsRecv: totalPacketsRecv,
  96. PacketsSent: totalPacketsSent,
  97. Errin: totalErrIn,
  98. Errout: totalErrOut,
  99. Dropin: totalDropIn,
  100. Dropout: totalDropOut,
  101. Fifoin: totalFifoIn,
  102. Fifoout: totalFifoOut,
  103. }, nil
  104. }
  105. // isVirtualInterface checks if the interface is a virtual one based on name patterns
  106. func isVirtualInterface(name string) bool {
  107. // Common virtual interface name patterns
  108. virtualPatterns := []string{
  109. "veth", "virbr", "vnet", "vmnet", "vboxnet", "docker",
  110. "br-", "bridge", "tun", "tap", "bond", "dummy",
  111. "vpn", "ipsec", "gre", "sit", "vlan", "virt",
  112. "wg", "vmk", "ib", "vxlan", "geneve", "ovs",
  113. "hyperv", "hyper-v", "awdl", "llw", "utun",
  114. "vpn", "zt", "zerotier", "wireguard",
  115. }
  116. for _, pattern := range virtualPatterns {
  117. if strings.Contains(strings.ToLower(name), pattern) {
  118. return true
  119. }
  120. }
  121. return false
  122. }
  123. // isContainerInterface checks if this is a main container interface
  124. func isContainerInterface(name string) bool {
  125. // Common main container interface patterns
  126. // eth0 is usually the main interface inside containers
  127. // en0, en1 are common physical interfaces on macOS
  128. // ens/enp/eno are common physical interfaces on Linux
  129. containerPatterns := []string{
  130. "eth0", "en0", "en1",
  131. "ens", "enp", "eno",
  132. "eth1", "eth2", // Potential physical interfaces
  133. "wlan", "wifi", "wl", // Wireless interfaces
  134. "bond0", // Bonded interfaces that might be external
  135. }
  136. for _, pattern := range containerPatterns {
  137. if strings.HasPrefix(strings.ToLower(name), pattern) {
  138. return true
  139. }
  140. }
  141. return false
  142. }
  143. // isRealExternalIP checks if an IP is a genuine external (public) IP
  144. func isRealExternalIP(ip stdnet.IP, ipNet *stdnet.IPNet) bool {
  145. // Skip if it's not a global unicast address
  146. if !ip.IsGlobalUnicast() {
  147. return false
  148. }
  149. // Skip private IPs
  150. if ip.IsPrivate() {
  151. return false
  152. }
  153. // Skip link-local addresses
  154. if ip.IsLinkLocalUnicast() {
  155. return false
  156. }
  157. // Skip loopback
  158. if ip.IsLoopback() {
  159. return false
  160. }
  161. // Skip multicast
  162. if ip.IsMulticast() {
  163. return false
  164. }
  165. // Check for special reserved ranges
  166. if isReservedIP(ip) {
  167. return false
  168. }
  169. return true
  170. }
  171. // isReservedIP checks if an IP belongs to special reserved ranges
  172. func isReservedIP(ip stdnet.IP) bool {
  173. // Handle IPv4
  174. if ip4 := ip.To4(); ip4 != nil {
  175. // TEST-NET-1: 192.0.2.0/24 (RFC 5737)
  176. if ip4[0] == 192 && ip4[1] == 0 && ip4[2] == 2 {
  177. return true
  178. }
  179. // TEST-NET-2: 198.51.100.0/24 (RFC 5737)
  180. if ip4[0] == 198 && ip4[1] == 51 && ip4[2] == 100 {
  181. return true
  182. }
  183. // TEST-NET-3: 203.0.113.0/24 (RFC 5737)
  184. if ip4[0] == 203 && ip4[1] == 0 && ip4[2] == 113 {
  185. return true
  186. }
  187. // Benchmark tests: 198.18.0.0/15 (includes 198.19.0.0/16) (RFC 2544)
  188. if ip4[0] == 198 && (ip4[1] == 18 || ip4[1] == 19) {
  189. return true
  190. }
  191. // Documentation: 240.0.0.0/4 (RFC 1112)
  192. if ip4[0] >= 240 {
  193. return true
  194. }
  195. // CGNAT: 100.64.0.0/10 (RFC 6598)
  196. if ip4[0] == 100 && (ip4[1]&0xC0) == 64 {
  197. return true
  198. }
  199. } else if ip.To16() != nil {
  200. // Documentation prefix (2001:db8::/32) - RFC 3849
  201. if ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x0d && ip[3] == 0xb8 {
  202. return true
  203. }
  204. // Unique Local Addresses (fc00::/7) - RFC 4193
  205. if (ip[0] & 0xfe) == 0xfc {
  206. return true
  207. }
  208. // 6to4 relay (2002::/16) - RFC 3056
  209. if ip[0] == 0x20 && ip[1] == 0x02 {
  210. return true
  211. }
  212. // Teredo tunneling (2001:0::/32) - RFC 4380
  213. if ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x00 && ip[3] == 0x00 {
  214. return true
  215. }
  216. // Deprecated site-local addresses (fec0::/10) - RFC 3879
  217. if (ip[0]&0xff) == 0xfe && (ip[1]&0xc0) == 0xc0 {
  218. return true
  219. }
  220. // Old 6bone addresses (3ffe::/16) - Deprecated
  221. if ip[0] == 0x3f && ip[1] == 0xfe {
  222. return true
  223. }
  224. // ORCHID addresses (2001:10::/28) - RFC 4843
  225. if ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x00 && (ip[3]&0xf0) == 0x10 {
  226. return true
  227. }
  228. // ORCHID v2 addresses (2001:20::/28) - RFC 7343
  229. if ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x00 && (ip[3]&0xf0) == 0x20 {
  230. return true
  231. }
  232. }
  233. return false
  234. }