diff --git a/go.mod b/go.mod index c820f21..e2f944e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,11 @@ module jmoore53.com/veth-go-testing go 1.24.0 -require github.com/charmbracelet/lipgloss v1.1.0 +require ( + github.com/charmbracelet/lipgloss v1.1.0 + github.com/vishvananda/netlink v1.3.1 + golang.org/x/sys v0.30.0 +) require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect @@ -15,6 +19,6 @@ require ( github.com/mattn/go-runewidth v0.0.16 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/vishvananda/netns v0.0.5 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - golang.org/x/sys v0.30.0 // indirect ) diff --git a/go.sum b/go.sum index 63e27fc..3965f56 100644 --- a/go.sum +++ b/go.sum @@ -21,10 +21,16 @@ github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= +github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main b/main index 4ef3a65..c0eec8a 100755 Binary files a/main and b/main differ diff --git a/main.go b/main.go index e16b0e3..de0d46c 100644 --- a/main.go +++ b/main.go @@ -3,47 +3,83 @@ package main import ( "fmt" "net" + "github.com/charmbracelet/lipgloss" + "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" ) func main() { - // Define styles + // Styles headerStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("63")) ipStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("203")) upStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("42")) downStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("196")) addrStyle := lipgloss.NewStyle().Faint(true) + infoStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("33")) - interfaces, err := net.Interfaces() + // Get all links + links, err := netlink.LinkList() if err != nil { - fmt.Println("Error:", err) + fmt.Println("Error listing links:", err) return } - for _, iface := range interfaces { + for _, link := range links { + attrs := link.Attrs() + if attrs == nil { + continue + } + + // Link state state := downStyle.Render("DOWN") - if iface.Flags&net.FlagUp != 0 { + if attrs.Flags&net.FlagUp != 0 { state = upStyle.Render("UP") } - fmt.Print(headerStyle.Render(iface.Name), " ") - fmt.Printf(addrStyle.Render(" %s"), iface.HardwareAddr) - fmt.Printf(addrStyle.Render(" %d"), iface.MTU) + // 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) - addrs, err := iface.Addrs() + // IPv4 addresses + addrs, err := netlink.AddrList(link, unix.AF_INET) if err != nil { fmt.Println(" Error getting addresses:", err) continue } - for _, addr := range addrs { - ipNet, ok := addr.(*net.IPNet) - if !ok || ipNet.IP.To4() == nil { - continue // Skip if not an IPv4 address + fmt.Println(" ", ipStyle.Render(addr.IPNet.String())) + } + + + // 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 + } + } + + if !peerFound { + fmt.Println(" ", infoStyle.Render("Peer likely in another namespace")) } - fmt.Println(" ", ipStyle.Render(addr.String())) } fmt.Println() + } } + +