package collector import ( "os/exec" "strconv" "strings" ) type NetworkInterface struct { Name string `json:"name"` Role string `json:"role"` IP string `json:"ip"` MAC string `json:"mac"` Status string `json:"status"` RxBytes int64 `json:"rx_bytes"` TxBytes int64 `json:"tx_bytes"` } func CollectNetwork() []NetworkInterface { ifaces := parseIfconfig() addTrafficStats(ifaces) return ifaces } // parseIfconfig parst ifconfig -a Output func parseIfconfig() []NetworkInterface { out, err := exec.Command("ifconfig", "-a").Output() if err != nil { return nil } var ifaces []NetworkInterface var current *NetworkInterface for _, line := range strings.Split(string(out), "\n") { // Neues Interface: "igb0: flags=..." if len(line) > 0 && line[0] != '\t' && line[0] != ' ' && strings.Contains(line, ": flags=") { if current != nil { ifaces = append(ifaces, *current) } name := strings.Split(line, ":")[0] // Loopback und virtuelle Interfaces ueberspringen if name == "lo0" || strings.HasPrefix(name, "pflog") || strings.HasPrefix(name, "pfsync") || strings.HasPrefix(name, "enc") { current = nil continue } status := "down" if strings.Contains(line, "UP") { status = "up" } current = &NetworkInterface{ Name: name, Status: status, Role: guessRole(name), } continue } if current == nil { continue } trimmed := strings.TrimSpace(line) // IPv4 Adresse if strings.HasPrefix(trimmed, "inet ") && !strings.HasPrefix(trimmed, "inet6") { fields := strings.Fields(trimmed) if len(fields) >= 2 { current.IP = fields[1] } } // MAC Adresse if strings.HasPrefix(trimmed, "ether ") { fields := strings.Fields(trimmed) if len(fields) >= 2 { current.MAC = fields[1] } } } if current != nil { ifaces = append(ifaces, *current) } return ifaces } // addTrafficStats fuegt RX/TX Bytes via netstat -ib hinzu func addTrafficStats(ifaces []NetworkInterface) { out, err := exec.Command("/usr/bin/netstat", "-ib").Output() if err != nil { return } // Nur Zeilen haben die totalen Byte-Zaehler // Format variiert, aber die letzten 4 Felder sind immer: Opkts Oerrs Obytes Coll // und davor: Ipkts Ierrs Idrop Ibytes lines := strings.Split(string(out), "\n") for _, line := range lines[1:] { if !strings.Contains(line, "vtnet1... // Wir suchen nach IFNAME und schauen welcher Block (wan/lan/opt) es enthaelt out, err := exec.Command("grep", "-B5", ""+ifName+"", "/conf/config.xml").Output() if err != nil { return "" } content := string(out) // Suche nach dem oeffnenden Tag des Parent-Elements for _, role := range []string{"wan", "lan", "opt1", "opt2", "opt3", "opt4", "opt5", "opt6"} { if strings.Contains(content, "<"+role+">") { return strings.ToUpper(role) } } return "" }