90 lines
2.5 KiB
Go
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
|
|
}
|