[client] Add detailed routes and resolved IPs to debug bundle (#4141)

This commit is contained in:
Viktor Liu
2025-07-25 15:31:06 +02:00
committed by GitHub
parent 2c4ac33b38
commit e0d9306b05
15 changed files with 1501 additions and 165 deletions

View File

@@ -16,12 +16,6 @@ import (
"golang.org/x/net/route"
)
type Route struct {
Dst netip.Prefix
Gw netip.Addr
Interface *net.Interface
}
func GetRoutesFromTable() ([]netip.Prefix, error) {
tab, err := retryFetchRIB()
if err != nil {
@@ -47,25 +41,134 @@ func GetRoutesFromTable() ([]netip.Prefix, error) {
continue
}
route, err := MsgToRoute(m)
r, err := MsgToRoute(m)
if err != nil {
log.Warnf("Failed to parse route message: %v", err)
continue
}
if route.Dst.IsValid() {
prefixList = append(prefixList, route.Dst)
if r.Dst.IsValid() {
prefixList = append(prefixList, r.Dst)
}
}
return prefixList, nil
}
func GetDetailedRoutesFromTable() ([]DetailedRoute, error) {
tab, err := retryFetchRIB()
if err != nil {
return nil, fmt.Errorf("fetch RIB: %v", err)
}
msgs, err := route.ParseRIB(route.RIBTypeRoute, tab)
if err != nil {
return nil, fmt.Errorf("parse RIB: %v", err)
}
return processRouteMessages(msgs)
}
func processRouteMessages(msgs []route.Message) ([]DetailedRoute, error) {
var detailedRoutes []DetailedRoute
for _, msg := range msgs {
m := msg.(*route.RouteMessage)
if !isValidRouteMessage(m) {
continue
}
if filterRoutesByFlags(m.Flags) {
continue
}
detailed, err := buildDetailedRouteFromMessage(m)
if err != nil {
log.Warnf("Failed to parse route message: %v", err)
continue
}
if detailed != nil {
detailedRoutes = append(detailedRoutes, *detailed)
}
}
return detailedRoutes, nil
}
func isValidRouteMessage(m *route.RouteMessage) bool {
if m.Version < 3 || m.Version > 5 {
log.Warnf("Unexpected RIB message version: %d", m.Version)
return false
}
if m.Type != syscall.RTM_GET {
log.Warnf("Unexpected RIB message type: %d", m.Type)
return false
}
return true
}
func buildDetailedRouteFromMessage(m *route.RouteMessage) (*DetailedRoute, error) {
routeMsg, err := MsgToRoute(m)
if err != nil {
return nil, err
}
if !routeMsg.Dst.IsValid() {
return nil, errors.New("invalid destination")
}
detailed := DetailedRoute{
Route: Route{
Dst: routeMsg.Dst,
Gw: routeMsg.Gw,
Interface: routeMsg.Interface,
},
Metric: extractBSDMetric(m),
Protocol: extractBSDProtocol(m.Flags),
Scope: "global",
Type: "unicast",
Table: "main",
Flags: formatBSDFlags(m.Flags),
}
return &detailed, nil
}
func buildLinkInterface(t *route.LinkAddr) *net.Interface {
interfaceName := fmt.Sprintf("link#%d", t.Index)
if t.Name != "" {
interfaceName = t.Name
}
return &net.Interface{
Index: t.Index,
Name: interfaceName,
}
}
func extractBSDMetric(m *route.RouteMessage) int {
return -1
}
func extractBSDProtocol(flags int) string {
if flags&syscall.RTF_STATIC != 0 {
return "static"
}
if flags&syscall.RTF_DYNAMIC != 0 {
return "dynamic"
}
if flags&syscall.RTF_LOCAL != 0 {
return "local"
}
return "kernel"
}
func retryFetchRIB() ([]byte, error) {
var out []byte
operation := func() error {
var err error
out, err = route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeRoute, 0)
if errors.Is(err, syscall.ENOMEM) {
log.Debug("~etrying fetchRIB due to 'cannot allocate memory' error")
log.Debug("Retrying fetchRIB due to 'cannot allocate memory' error")
return err
} else if err != nil {
return backoff.Permanent(err)
@@ -100,7 +203,6 @@ func toNetIP(a route.Addr) netip.Addr {
}
}
// ones returns the number of leading ones in the mask.
func ones(a route.Addr) (int, error) {
switch t := a.(type) {
case *route.Inet4Addr:
@@ -114,7 +216,6 @@ func ones(a route.Addr) (int, error) {
}
}
// MsgToRoute converts a route message to a Route.
func MsgToRoute(msg *route.RouteMessage) (*Route, error) {
dstIP, nexthop, dstMask := msg.Addrs[0], msg.Addrs[1], msg.Addrs[2]
@@ -127,10 +228,7 @@ func MsgToRoute(msg *route.RouteMessage) (*Route, error) {
case *route.Inet4Addr, *route.Inet6Addr:
nexthopAddr = toNetIP(t)
case *route.LinkAddr:
nexthopIntf = &net.Interface{
Index: t.Index,
Name: t.Name,
}
nexthopIntf = buildLinkInterface(t)
default:
return nil, fmt.Errorf("unexpected next hop type: %T", t)
}
@@ -156,5 +254,4 @@ func MsgToRoute(msg *route.RouteMessage) (*Route, error) {
Gw: nexthopAddr,
Interface: nexthopIntf,
}, nil
}