daeuniverse / dae

eBPF-based Linux high-performance transparent proxy solution.
GNU Affero General Public License v3.0
2.62k stars 165 forks source link

[Enhancement] Troubeshooting tools #524

Open jschwinger233 opened 1 month ago

jschwinger233 commented 1 month ago

Improvement Suggestion

Two ideas:

  1. Add dae sysdump to automatically collect network settings (routing, netfilter, sysctl, ...) and archive all info into a tar. This can save us from asking "would you mind showing me your netfilter using xxx cmd".
  2. Add dae trace --drop-only. This can make the tool much easier as users don't have specify ip or port.

Potential Benefits

An ideal bug report would be providing with sysdump.tar + trace.log if possible.

dae-prow[bot] commented 1 month ago

Thanks for opening this issue!

linglilongyi commented 1 week ago

Should different command set be run based on different OS? Or just traverse the commands and collect the standard output into the pack?

jschwinger233 commented 1 week ago

@linglilongyi Hi thanks for asking!

I was wondering if calling syscall (wrapped by 3rd party library of course) rather than relying on external commands is a good idea.

For example, if we want to collect routing information on the system, instead of os.Exec("ip", "route"), we can call vishvananda/netlink#Handle.RouteList in the dae process, something like (demo code generated by ChatGPT ).

package main

import (
    "fmt"
    "log"
    "net"

    "github.com/vishvananda/netlink"
)

func main() {
    // Create a new netlink handle
    handle, err := netlink.NewHandle()
    if err != nil {
        log.Fatalf("Failed to create netlink handle: %v", err)
    }
    defer handle.Delete()

    // Retrieve all routes
    routes, err := handle.RouteList(nil, netlink.FAMILY_ALL)
    if err != nil {
        log.Fatalf("Failed to list routes: %v", err)
    }

    // Format and print each route
    for _, route := range routes {
        fmt.Println(formatRoute(route))
    }
}

func formatRoute(route netlink.Route) string {
    var dst, gw, dev string

    if route.Dst == nil {
        dst = "default"
    } else {
        dst = route.Dst.String()
    }

    if route.Gw != nil {
        gw = route.Gw.String()
    }

    link, err := netlink.LinkByIndex(route.LinkIndex)
    if err == nil {
        dev = link.Attrs().Name
    }

    flags := ""
    if route.Flags&netlink.FLAG_ONLINK != 0 {
        flags += " onlink"
    }

    if route.Flags&netlink.FLAG_PERMANENT != 0 {
        flags += " permanent"
    }

    return fmt.Sprintf("%s via %s dev %s%s", dst, gw, dev, flags)
}

This is faster and lower-costly.