package cmd import ( "fmt" "net" "os/exec" "runtime" "strings" "github.com/zemenawi/zutils/pkg/colors" ) func NetworkInfoCommand(args []string) error { PrintBoxHeader("NETWORK INFORMATION", colors.Cyan) PrintSectionHeader("IP ADDRESSES") interfaces, err := net.Interfaces() if err == nil { for _, iface := range interfaces { if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 { addrs, err := iface.Addrs() if err == nil { for _, addr := range addrs { var ip net.IP switch v := addr.(type) { case *net.IPNet: ip = v.IP case *net.IPAddr: ip = v.IP } if ip != nil && !ip.IsLoopback() { fmt.Printf("%s%s🌐%s %s%-18s%s %s\n", colors.Green, colors.Bold, colors.Reset, colors.Cyan, iface.Name, colors.Reset, ip.String()) } } } } } } else { fmt.Printf("%sError getting network interfaces: %v%s\n", colors.Red, err, colors.Reset) } fmt.Println() PrintSectionHeader("PUBLIC IP") publicIP := getPublicIP() if publicIP != "" { fmt.Printf("%s%s🌍%s Public IP: %s%s%s\n", colors.Green, colors.Bold, colors.Reset, colors.Cyan, publicIP, colors.Reset) } else { fmt.Printf("%sUnable to determine public IP%s\n", colors.Yellow, colors.Reset) } fmt.Println() PrintSectionHeader("DNS INFO") dnsServers := getDNSServers() for i, dns := range dnsServers { fmt.Printf("%s%s🔗%s DNS Server %d: %s%s%s\n", colors.Green, colors.Bold, colors.Reset, i+1, colors.Cyan, dns, colors.Reset) } fmt.Println() PrintSectionHeader("ACTIVE CONNECTIONS") connections := getNetworkConnections() if len(connections) > 0 { maxShow := 10 if len(connections) < maxShow { maxShow = len(connections) } headers := []string{"#", "Proto", "State", "Local Address", "Remote Address"} data := make([][]string, 0, maxShow) for i := 0; i < maxShow; i++ { parsed := parseConnection(connections[i]) row := []string{ fmt.Sprintf("%d", i+1), parsed.proto, parsed.state, parsed.local, parsed.remote, } data = append(data, row) } printSimpleTable(headers, data) if len(connections) > maxShow { fmt.Printf("%s%s...and %d more connections%s\n", colors.Gray, colors.Bold, len(connections)-maxShow, colors.Reset) } fmt.Println() } else { fmt.Printf("%sNo active connections detected%s\n", colors.Yellow, colors.Reset) fmt.Println() } return nil } func getPublicIP() string { var cmd *exec.Cmd if runtime.GOOS == "windows" { cmd = exec.Command("curl", "-s", "ifconfig.me") } else { cmd = exec.Command("curl", "-s", "ifconfig.me") } output, err := cmd.CombinedOutput() if err == nil { return strings.TrimSpace(string(output)) } cmd = exec.Command("wget", "-qO-", "ifconfig.me") output, err = cmd.CombinedOutput() if err == nil { return strings.TrimSpace(string(output)) } return "" } func getDNSServers() []string { var dnsServers []string if runtime.GOOS == "linux" { cmd := exec.Command("sh", "-c", "grep '^nameserver' /etc/resolv.conf | awk '{print $2}'") output, err := cmd.CombinedOutput() if err == nil { lines := strings.Split(strings.TrimSpace(string(output)), "\n") for _, line := range lines { if line != "" { dnsServers = append(dnsServers, line) } } } } else if runtime.GOOS == "darwin" { cmd := exec.Command("scutil", "--dns") output, err := cmd.CombinedOutput() if err == nil { lines := strings.Split(string(output), "\n") for _, line := range lines { if strings.Contains(line, "nameserver[") { parts := strings.Fields(line) if len(parts) >= 3 { dnsServers = append(dnsServers, parts[2]) } } } } } if len(dnsServers) == 0 { dnsServers = append(dnsServers, "8.8.8.8 (Google DNS)") dnsServers = append(dnsServers, "1.1.1.1 (Cloudflare DNS)") } return dnsServers } func getNetworkConnections() []string { var connections []string if runtime.GOOS == "linux" { cmd := exec.Command("ss", "-tun") output, err := cmd.CombinedOutput() if err == nil { lines := strings.Split(string(output), "\n") for i := 1; i < len(lines) && i < 12; i++ { line := strings.TrimSpace(lines[i]) if line != "" { connections = append(connections, line) } } } } else if runtime.GOOS == "darwin" { cmd := exec.Command("netstat", "-an") output, err := cmd.CombinedOutput() if err == nil { lines := strings.Split(string(output), "\n") for i := 0; i < len(lines) && i < 11; i++ { line := strings.TrimSpace(lines[i]) if strings.Contains(line, "ESTABLISHED") { connections = append(connections, line) } } } } return connections } type connectionInfo struct { proto string state string local string remote string } func parseConnection(conn string) connectionInfo { parts := strings.Fields(conn) result := connectionInfo{} if len(parts) >= 5 { result.proto = parts[0] result.state = parts[1] // ss output format: proto state recv-q send-q local remote // Try to find addresses by position for i := 4; i < len(parts); i++ { part := parts[i] // Look for IP:port patterns if strings.Contains(part, ":") && (strings.Contains(part, ".") || strings.Contains(part, ":")) { if result.local == "" { result.local = part } else { result.remote = part } } } } return result }