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

2021-10-07 14:30:07 +08:00
 LeonHuayra

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 追踪网络包路径信息:

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

相关文档

2817 次点击
所在节点    Linux
2 条回复
airqj
2021-10-07 14:46:28 +08:00
好东西 关注一下
sbilly
2021-10-09 12:13:42 +08:00
感谢!定睛一看,还真是 Go 开发的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/806221

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX