mirror of
https://github.com/netbirdio/netbird.git
synced 2025-08-18 02:50:43 +02:00
[client] Add detailed routes and resolved IPs to debug bundle (#4141)
This commit is contained in:
@@ -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
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user