sysinfo/internal/sysinfo/collector_network.go
2025-05-01 03:25:38 -07:00

90 lines
2.5 KiB
Go

package sysinfo
import (
"encoding/json"
"path/filepath"
"strings"
"time"
)
type NetworkCollector struct{}
func (NetworkCollector) SectionKey() string { return "network" }
/* ------------------------------------------------------------------ */
/* prerequisite / support checks */
/* ------------------------------------------------------------------ */
func (NetworkCollector) EnsurePrerequisites(pm PackageManager, _ *Context) error {
if pm.Distro() == "ubuntu" {
return pm.InstallPackages("iproute2", "curl", "ethtool")
}
return nil
}
func (NetworkCollector) IsSupported(pm PackageManager, _ *Context) bool {
return pm.ExecExists("ip")
}
/* ------------------------------------------------------------------ */
/* collection */
/* ------------------------------------------------------------------ */
func (NetworkCollector) CollectData(c *Context) (json.RawMessage, error) {
def, _ := defaultIfaceSet(c)
sections := map[string]any{}
nets, _ := filepath.Glob("/sys/class/net/*")
for _, n := range nets {
if strings.HasSuffix(n, "/lo") {
continue
}
iface := filepath.Base(n)
mac := strings.ToLower(strings.ReplaceAll(
c.SafeRead(filepath.Join(n, "address")), ":", ""))
if mac == "" {
continue
}
entry := map[string]any{
"iface": iface,
"timestamp": c.Now.Format(time.RFC3339),
"link": c.SafeRun("ip", "-details", "link", "show", iface),
"ethtool": c.SafeRun("ethtool", iface),
}
ipJSON, _ := c.Run("ip", "-j", "address", "show", iface)
entry["ip_addr"] = json.RawMessage(ipJSON)
stats, _ := readNetStats(iface)
entry["statistics"] = json.RawMessage(stats)
if def[iface] {
if out := c.SafeRun("curl", "--interface", iface, "-s",
"https://ipinfo.io"); json.Valid([]byte(out)) {
entry["ipinfo"] = json.RawMessage(out)
}
}
sections[mac] = entry
}
return json.Marshal(sections)
}
/* ------------------------------------------------------------------ */
/* helpers */
/* ------------------------------------------------------------------ */
func defaultIfaceSet(c *Context) (map[string]bool, error) {
out, err := c.Run("ip", "-j", "route", "show", "default")
if err != nil {
return nil, err
}
var routes []struct{ Dev string `json:"dev"` }
_ = json.Unmarshal(out, &routes)
m := map[string]bool{}
for _, r := range routes {
m[r.Dev] = true
}
return m, nil
}