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


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 信息。

相关文档

发表评论

您的电子邮箱地址不会被公开。