V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
LeonHuayra
V2EX  ›  Linux

Linux 内核网络包路径追踪利器 skbtracer, Go 语言版本

  •  
  •   LeonHuayra · 55 天前 · 1699 次点击
    这是一个创建于 55 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Linux 内核网络包路径追踪利器 skbtracer,Go 语言版本

    skbtracer 是基于 eBPF 技术的 skb 网络包路径追踪利器,基于 goebpf , libbpf-bootstrap (required Linux Kernel 4.15+ with CONFIG_DEBUG_INFO_BTF=y, Go 1.16+) 实现,参考 Python 版本 github.com/DavadDi/skbtracer

    skbtracer 是一个 Linux 可执行文件,不依赖 libbcc.so 动态链接库,就可以在开启了 CONFIG_DEBUG_INFO_BTF 的环境中运行。

    开源地址:github.com/Asphaltt/skbtracer

    使用

    运行效果:

    $ sudo ./skbtracer -c 10
    TIME       NETWORK_NS   CPU    INTERFACE          DEST_MAC           IP_LEN PKT_INFO                                               TRACE_INFO
    [13:43:45] [0         ] 3      nil                00:00:00:00:00:00  168    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b3ae0.0:ip_output
    [13:43:45] [0         ] 3      ens18              00:00:00:00:00:00  168    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b3ae0.0:ip_finish_output
    [13:43:45] [0         ] 3      ens18              00:00:00:00:00:00  168    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b3ae0.0:__dev_queue_xmit
    [13:43:45] [0         ] 3      nil                00:00:00:00:00:00  248    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b36e0.0:ip_output
    [13:43:45] [0         ] 3      ens18              00:00:00:00:00:00  248    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b36e0.0:ip_finish_output
    [13:43:45] [0         ] 3      ens18              00:00:00:00:00:00  248    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b36e0.0:__dev_queue_xmit
    [13:43:45] [0         ] 3      nil                00:00:00:00:00:00  120    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b2ce0.0:ip_output
    [13:43:45] [0         ] 3      ens18              00:00:00:00:00:00  120    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b2ce0.0:ip_finish_output
    [13:43:45] [0         ] 3      ens18              00:00:00:00:00:00  120    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b2ce0.0:__dev_queue_xmit
    [13:43:45] [0         ] 3      nil                00:00:00:00:00:00  120    T_ACK,PSH:10.0.1.10:22->10.0.4.15:55343                ffff9a271b1b30e0.0:ip_output
    
    15 event(s) received
    0 event(s) lost (e.g. small buffer, delays in processing)
    

    使用帮助:

    $ ./skbtracer -h
    examples:
    skbtracer                                      # trace all packets
    skbtracer --proto=icmp -H 1.2.3.4 --icmpid 22  # trace icmp packet with addr=1.2.3.4 and icmpid=22
    skbtracer --proto=tcp  -H 1.2.3.4 -P 22        # trace tcp  packet with addr=1.2.3.4:22
    skbtracer --proto=udp  -H 1.2.3.4 -P 22        # trace udp  packet wich addr=1.2.3.4:22
    skbtracer -t -T -p 1 -P 80 -H 127.0.0.1 --proto=tcp --callstack --icmpid=100 -N 10000
    
    Usage:
      skbtracer [flags]
    
    Flags:
          --callstack          output kernel stack trace (DEPRECATED: not implemented to print the function stack)
      -c, --catch-count uint   catch and print count (default 1000)
          --dropstack          output kernel stack trace when drop packet (DEPRECATED: not supported on Ubuntu 18.04.5 LTS with kernel 5.10.29-051029-generic)
      -h, --help               help for skbtracer
          --icmpid uint        trace icmp id
      -H, --ipaddr string      ip address
          --iptable            output iptable path
          --keep               keep trace packet all lifetime (DEPRECATED: not implemented yet)
      -N, --netns uint         trace this Network Namespace only
          --noroute            do not output route path
      -p, --pid uint           trace this PID only
      -P, --port uint          udp or tcp port
          --proto string       tcp|udp|icmp|any
      -T, --time               show HH:MM:SS timestamp (default true)
      -t, --timestamp          show timestamp in seconds at us resolution
    

    编译

    编译 skbtracer 需要使用较新版本的 llvm,要求 Go 语言的版本 1.16 及以上,因为需要使用 embed 包将 BPF 的 ELF 文件内嵌到 Go 程序里面,不依赖 Linux 内核头文件。

    只需要以下几步即可编译得到可执行文件:

    $ git clone https://github.com/Asphaltt/skbtracer.git
    $ cd skbtracer
    $ make
    $ ./bin/skbtracer -h  # 可执行文件在 bin 目录下
    

    实现原理

    使用 clang -target bpf 编译 BPF 代码,得到对应的 ELF 文件。

    然后在 Go 代码里使用

    //go:embed skbtracer.elf
    var bpfProg []byte
    

    将 BPF ELF 文件内嵌进来。接着使用 goebpf 加载 BPF ELF 文件,并将 BPF 程序装载到内核里去运行。

    BPF 程序通过 perf event 将网络包路径信息发送到 Go 程序,Go 程序就可以解析 perf event 得到 struct 。

    BPF 程序里使用以下 kprobe 追踪网络包路径信息:

    • netif_rx
    • __netif_receive_skb
    • tpacket_rcv
    • packet_rcv
    • napi_gro_receive
    • __dev_queue_xmit
    • br_handle_frame_finish
    • br_nf_pre_routing
    • br_nf_pre_routing_finish
    • br_pass_frame_up
    • br_netif_receive_skb
    • br_forward
    • __br_forward
    • br_forward_finish
    • br_nf_forward_ip
    • br_nf_forward_finish
    • br_nf_post_routing
    • br_nf_dev_queue_xmit
    • ip_rcv
    • ip_rcv_finish
    • ip_output
    • ip_finish_output

    使用 kprobekretprobe 探测 ipt_do_table 去追踪网络包的 iptables 信息。

    相关文档

    2 条回复    2021-10-09 12:13:42 +08:00
    airqj
        1
    airqj   55 天前
    好东西 关注一下
    sbilly
        2
    sbilly   53 天前
    感谢!定睛一看,还真是 Go 开发的
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3055 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:23 · PVG 18:23 · LAX 02:23 · JFK 05:23
    ♥ Do have faith in what you're doing.