diff --git a/main b/main index c0eec8a..ec4a777 100755 Binary files a/main and b/main differ diff --git a/main.go b/main.go index de0d46c..3dafe47 100644 --- a/main.go +++ b/main.go @@ -2,15 +2,19 @@ package main import ( "fmt" + "io/ioutil" "net" + //"os" + "path/filepath" + //"strings" "github.com/charmbracelet/lipgloss" "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" "golang.org/x/sys/unix" ) func main() { - // Styles headerStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("63")) ipStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("203")) upStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("42")) @@ -18,7 +22,14 @@ func main() { addrStyle := lipgloss.NewStyle().Faint(true) infoStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("33")) - // Get all links + // Save the current netns + origNS, err := netns.Get() + if err != nil { + fmt.Println("Error getting current netns:", err) + return + } + defer origNS.Close() + links, err := netlink.LinkList() if err != nil { fmt.Println("Error listing links:", err) @@ -31,55 +42,89 @@ func main() { continue } - // Link state state := downStyle.Render("DOWN") if attrs.Flags&net.FlagUp != 0 { state = upStyle.Render("UP") } - // Interface header fmt.Print(headerStyle.Render(attrs.Name), " ") fmt.Printf(addrStyle.Render(" %s"), attrs.HardwareAddr) fmt.Printf(addrStyle.Render(" %d"), attrs.MTU) fmt.Printf(" %s\n", state) - // IPv4 addresses + // IP addresses (IPv4 only) addrs, err := netlink.AddrList(link, unix.AF_INET) - if err != nil { - fmt.Println(" Error getting addresses:", err) + if err == nil { + for _, addr := range addrs { + fmt.Println(" ", ipStyle.Render(addr.IPNet.String())) + } + } + + if link.Type() != "veth" { + fmt.Println() continue } - for _, addr := range addrs { - fmt.Println(" ", ipStyle.Render(addr.IPNet.String())) - } + fmt.Println(" ", infoStyle.Render("Veth interface")) - // Veth handling - if link.Type() == "veth" { - fmt.Println(" ", infoStyle.Render("Veth interface")) - - // Try to find peer by looking for other veths with same parent or hint from name - // No peer name is available here, so we must guess - // We'll mention that if no matching veth exists, it's likely in another netns - peerFound := false - for _, other := range links { - if other.Attrs().Index == attrs.Index { - continue - } - if other.Type() == "veth" && other.Attrs().ParentIndex == attrs.Index { - fmt.Println(" ", infoStyle.Render("Likely peer:"), other.Attrs().Name) - peerFound = true - break - } + // Try to find peer locally + peerFound := false + for _, other := range links { + if other.Attrs().Index == attrs.Index { + continue } - - if !peerFound { - fmt.Println(" ", infoStyle.Render("Peer likely in another namespace")) + if other.Type() == "veth" && other.Attrs().ParentIndex == attrs.Index { + fmt.Println(" ", infoStyle.Render("Likely peer:"), other.Attrs().Name) + peerFound = true + break } } + + // If not found, scan /var/run/netns/ + if !peerFound { + netnsDir := "/var/run/netns/" + entries, err := ioutil.ReadDir(netnsDir) + if err != nil { + fmt.Println(" ", infoStyle.Render("Could not scan netns dir")) + } else { + for _, entry := range entries { + nsPath := filepath.Join(netnsDir, entry.Name()) + + nsHandle, err := netns.GetFromPath(nsPath) + if err != nil { + continue + } + + if err := netns.Set(nsHandle); err != nil { + nsHandle.Close() + continue + } + + remoteLinks, err := netlink.LinkList() + if err == nil { + for _, rl := range remoteLinks { + if rl.Type() == "veth" && rl.Attrs().ParentIndex == attrs.Index { + fmt.Println(" ", infoStyle.Render("Peer in namespace:"), entry.Name(), "as", rl.Attrs().Name) + peerFound = true + break + } + } + } + nsHandle.Close() + netns.Set(origNS) + + if peerFound { + break + } + } + } + } + + if !peerFound { + fmt.Println(" ", infoStyle.Render("Peer not found — may be deleted or hidden")) + } + fmt.Println() - } } -