BCC
BCC
目录
用例实践
网络项
tunnel_monitor
坑1,chord-transitions 仓库丢失
https://github.com/iovisor/bcc/tree/master/examples/networking/tunnel_monitor
这个好像没办法用,setup.sh 里的clone仓库发现是不存在的。后来发现需要修改里面的仓库地址为:https://github.com/sghall/chord-transitions.git
坑1.2,bower.json 丢失
但好像还是不行,还是会报这个错:
bower ENOENT No bower.json present
坑1.3,setup卡住
一直卡在这里:
/git/public/bcc/examples/networking/tunnel_monitor$ ./setup.sh
npm WARN old lockfile
npm WARN old lockfile The package-lock.json file was created with an old version of npm,
npm WARN old lockfile so supplemental metadata must be fetched from the registry.
npm WARN old lockfile
npm WARN old lockfile This is a one-time fix-up, please be patient...
npm WARN old lockfile
(⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂) ⠏ idealTree:inflate:code-point-at: sill inflate node_modules/code-point-at
另外还有关于一直 npm WARN old lockfile
的警告。
更新npm,现在尝试从官网中更新node.js
# 更新apt
sudo apt update
sudo apt upgrade
# 更新nodejs
sudo apt install curl
# 命令解释:curl 用于从 NodeSource 存储库下载 Node.js 安装脚本,,将下载的脚本数据传递给 bash 以 root 权限执行
curl -sL https://deb.nodesource.com/setup_lts.x | sudo -E bash - # 这里的lts.x可以替换为具体的版本号,如18.17。
apt install -y nodejs
# 如果由于残留原因报错,尝试卸载旧版本再重装
apt-get remove nodejs libnode-dev
apt-get autoremove
curl -sL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
# 验证版本
node -v
npm -v
坑1.4,'insert' of undefined
错误:
npm ERR! Cannot read property 'insert' of undefined
npm ERR! A complete log of this run can be found in:
npm ERR! /root/.npm/_logs/2023-07-28T03_32_20_463Z-debug-0.log
对应于 setup.sh 里的 npm install bower
命令。
建议还是更新npm,现在尝试从官网中更新node.js
……
(话说我wsl npm@6.14.4 是可以的,为什么208的 npm@8.5.1 不行呢,就很奇怪)
坑2,pyroute2库存在问题
若无视上面的setup.sh直接运行tunnel_monitor.py,则会报错:
Traceback (most recent call last):
File "./main.py", line 80, in <module>
sim.start()
File "./main.py", line 36, in start
with self.ipdb.create(ifname="br100", kind="bridge") as br100:
File "/usr/local/lib/python3.8/dist-packages/pyroute2/ipdb/main.py", line 1202, in create
return self.interfaces.add(kind, ifname, reuse, **kwarg)
File "/usr/local/lib/python3.8/dist-packages/pyroute2/ipdb/interfaces.py", line 1230, in add
raise CreateException("interface %s exists" % ifname)
pyroute2.ipdb.exceptions.CreateException: interface br100 exists
其实运行其他脚本也有这个库的问题,例如:
/git/public/bcc/examples/networking$ python3 ./simple_tc.py
Traceback (most recent call last):
File "./simple_tc.py", line 23, in <module>
ipr.tc("add-filter", "bpf", idx, ":1", fd=fn.fd,
File "/usr/local/lib/python3.8/dist-packages/pyroute2/iproute/linux.py", line 1931, in tc
return tuple(self.nlm_request(msg, msg_type=command, msg_flags=flags))
File "/usr/local/lib/python3.8/dist-packages/pyroute2/netlink/nlsocket.py", line 870, in nlm_request
return tuple(self._genlm_request(*argv, **kwarg))
File "/usr/local/lib/python3.8/dist-packages/pyroute2/netlink/nlsocket.py", line 1214, in nlm_request
for msg in self.get(
File "/usr/local/lib/python3.8/dist-packages/pyroute2/netlink/nlsocket.py", line 873, in get
return tuple(self._genlm_get(*argv, **kwarg))
File "/usr/local/lib/python3.8/dist-packages/pyroute2/netlink/nlsocket.py", line 550, in get
raise msg['header']['error']
pyroute2.netlink.exceptions.NetlinkError: (2, 'No such file or directory')
这个错误是由 Python 的 pyroute2 库抛出的一个 NetlinkError 异常。具体来说,这个错误表示在尝试与内核通信进行网络操作时,找不到预期的文件或目录(错误码 2 表示 "No such file or directory")。
从给出的代码片段来看,这个错误发生在尝试添加一个 BPF 过滤器到网络接口时。为了解决这个问题,你可以尝试以下步骤:
这个是wsl里出现的错误,后来试了下实机是没有这个问题的。实机是其他问题:
/git/public/bcc/examples/networking$ python tunnel_monitor/main.py
Traceback (most recent call last):
File "/home/msy/git/public/bcc/examples/networking/tunnel_monitor/main.py", line 11, in <module>
from simulation import Simulation
File "/home/msy/git/public/bcc/examples/networking/tunnel_monitor/simulation.py", line 1
../simulation.py
^
SyntaxError: invalid syntax
/git/public/bcc/examples/networking$ python ./simple_tc.py
BPF tc functionality - SCHED_CLS: OK
坑3,无效语法,找不到simulation.py
这里应该是仓库作者为了压缩空间,但是又懒得做路由重定义。这里需要手动复制一下
# 错误
root@msy:/home/msy/git/public/bcc/examples/networking$ python3 tunnel_monitor/main.py
Traceback (most recent call last):
File "/home/msy/git/public/bcc/examples/networking/tunnel_monitor/main.py", line 11, in <module>
from simulation import Simulation
File "/home/msy/git/public/bcc/examples/networking/tunnel_monitor/simulation.py", line 1
../simulation.py
^
SyntaxError: invalid syntax
root@msy:/home/msy/git/public/bcc/examples/networking$ ls
CMakeLists.txt http_filter simple_tc.py tc_perf_event.py vlan_filter
distributed_bridge neighbor_sharing simulation.py tcp_mon_block vlan_learning
dns_matching net_monitor.py sockmap.py tunnel_monitor xdp
# 修复
root@msy:/home/msy/git/public/bcc/examples/networking$ cp simulation.py ./tunnel_monitor/simulation.py
root@msy:/home/msy/git/public/bcc/examples/networking$ python3 tunnel_monitor/main.py
其他项
undump
使用
root@msy:/home/msy/git/public/bcc/examples/tracing# python ./undump.py
Tracing UNIX socket packets ... Hit Ctrl-C to end
Recv 260 bytes
6c 04 01 01 54 00 00 00 35 00 00 00 9a 00 00 00
01 01 6f 00 38 00 00 00 2f 6f 72 67 2f 66 72 65
65 64 65 73 6b 74 6f 70 2f 55 44 69 73 6b 73 32
2f 64 72 69 76 65 73 2f 54 53 31 32 30 47 53 53
44 32 32 30 53 5f 45 36 30 38 39 36 30 32 34 36
00 00 00 00 00 00 00 00 02 01 73 00 1f 00 00 00
6f 72 67 2e 66 72 65 65 64 65 73 6b 74 6f 70 2e
44 42 75 73 2e 50 72 6f 70 65 72 74 69 65 73 00
08 01 67 00 08 73 61 7b 73 76 7d 61 73 00 00 00
03 01 73 00 11 00 00 00 50 72 6f 70 65 72 74 69
65 73 43 68 61 6e 67 65 64 00 00 00 00 00 00 00
21 00 00 00 6f 72 67 2e 66 72 65 65 64 65 73 6b
74 6f 70 2e 55 44 69 73 6b 73 32 2e 44 72 69 76
65 2e 41 74 61 00 00 00 20 00 00 00 00 00 00 00
0c 00 00 00 53 6d 61 72 74 55 70 64 61 74 65 64
00 01 74 00 00 00 00 00 33 64 c3 64 00 00 00 00
00 00 00 00
这个程序(undump.py)是用来抓取和打印通过 UNIX socket(通常被用于进程间通信) 传输的数据包的。它使用了一个名为bcc
的库,该库允许在内核中运行eBPF程序来捕获事件。在本例中,这个程序捕获了连接到UNIX socket的进程的发送和接收数据包的事件。
由于UNIX socket主要用于本地进程间通信,数据包的传输可能不像网络包那样频繁。因此,在运行und_dump.py程序时,可能要等待一段时间才能抓取到足够的UNIX socket数据包并将其打印出来。
此外,这个程序可能会因操作系统的不同和权限设置而产生不同的结果。在一些系统上,为了获取UNIX socket传输的数据包信息,需要在root身份下运行该程序。请确保您是以最高权限运行这个程序,以便于获取更多相关数据包。
代码
#!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
#
# undump Dump UNIX socket packets.
# For Linux, uses BCC, eBPF. Embedded C.
# USAGE: undump [-h] [-t] [-p PID]
#
# This uses dynamic tracing of kernel functions, and will need to be updated
# to match kernel changes.
#
# Copyright (c) 2021 Rong Tao.
# Licensed under the GPL License, Version 2.0
#
# 27-Aug-2021 Rong Tao Created this.
# 17-Sep-2021 Rong Tao Simplify according to chenhengqi's suggestion
# https://github.com/iovisor/bcc/pull/3615
#
from __future__ import print_function
from bcc import BPF
from bcc.containers import filter_by_containers
from bcc.utils import printb
import argparse
from socket import inet_ntop, ntohs, AF_INET, AF_INET6
from struct import pack
from time import sleep
from datetime import datetime
import sys
# 参数
examples = """examples:
./undump # trace/dump all UNIX packets
./undump -p 181 # only trace/dump PID 181
"""
parser = argparse.ArgumentParser(
description="Dump UNIX socket packets",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples)
parser.add_argument("-p", "--pid",
help="trace this PID only")
args = parser.parse_args()
# 定义BPF程序
bpf_text = """..."""
if args.pid:
bpf_text = bpf_text.replace('FILTER_PID',
'if (pid != %s) { return 0; }' % args.pid)
bpf_text = bpf_text.replace('FILTER_PID', '')
# process event
def print_recv_pkg(cpu, data, size):
event = b["unix_recv_events"].event(data)
if args.pid:
print("PID \033[1;31m%s\033[m " % args.pid, end="")
print("Recv \033[1;31m%d\033[m bytes" % event.recv_len)
print(" ", end="")
for i in range(0, event.recv_len):
print("%02x " % event.pkt[i], end="")
sys.stdout.flush()
if (i+1)%16 == 0:
print("")
print(" ", end="")
print("")
# initialize BPF
b = BPF(text=bpf_text)
b.attach_kprobe(event="unix_stream_read_actor", fn_name="trace_unix_stream_read_actor")
if args.pid:
print("Tracing \033[1;31mPID=%s\033[m UNIX socket packets ... Hit Ctrl-C to end" % args.pid)
else:
print("Tracing UNIX socket packets ... Hit Ctrl-C to end")
start_ts = 0
# read events
b["unix_recv_events"].open_perf_buffer(print_recv_pkg)
while True:
try:
b.perf_buffer_poll()
except KeyboardInterrupt:
exit()
0
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
#include <linux/aio.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/module.h>
#include <net/sock.h>
#include <net/af_unix.h>
#define MAX_PKT 512
struct recv_data_t {
u32 recv_len;
u8 pkt[MAX_PKT];
};
// single element per-cpu array to hold the current event off the stack
BPF_PERCPU_ARRAY(unix_data, struct recv_data_t, 1);
BPF_PERF_OUTPUT(unix_recv_events);
int trace_unix_stream_read_actor(struct pt_regs *ctx)
{
u32 zero = 0;
int ret = PT_REGS_RC(ctx);
u64 pid_tgid = bpf_get_current_pid_tgid();
u32 pid = pid_tgid >> 32;
u32 tid = pid_tgid;
FILTER_PID
struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx);
struct recv_data_t *data = unix_data.lookup(&zero);
if (!data)
return 0;
unsigned int data_len = skb->len;
if(data_len > MAX_PKT)
return 0;
void *iodata = (void *)skb->data;
data->recv_len = data_len;
bpf_probe_read(data->pkt, data_len, iodata);
unix_recv_events.perf_submit(ctx, data, data_len+sizeof(u32));
return 0;
}
tcp专项
tcpdump
这个好像不是eBPF程序,而是原生命令。tcpdump是一个基于命令行的网络抓包工具,用于捕获和分析网络数据包。它可以帮助您诊断和调试网络问题,以及深入了解网络通讯的细节。通过使用不同的过滤器和选项,您可以定制tcpdump来捕获特定类型的数据包,非常灵活地进行网路通讯分析。
这里只收1次tcp往返包,208发给209再让209返回给208:
root@msy:/home/msy/SatelliteTester$ tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp4s0f0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
07:55:54.617982 IP 192.168.208.1.57237 > 192.168.208.199.8811: Flags [P.], seq 1274094941:1274095017, ack 3189192749, win 502, options [nop,nop,TS val 422140321 ecr 68892766], length 76
07:55:54.618245 IP 192.168.208.199.8811 > 192.168.208.1.57237: Flags [P.], seq 1:77, ack 76, win 509, options [nop,nop,TS val 68902766 ecr 422140321], length 76
07:55:54.618259 IP 192.168.208.1.57237 > 192.168.208.199.8811: Flags [.], ack 77, win 502, options [nop,nop,TS val 422140321 ecr 68902766], length 0
tclcalls
lib/ucalls_example.txt
tclflow
lib/uflow_example.txt
tclobjnew
lib/uobjnew_example.txt
tclstat
lib/ustat_example.txt
tcpaccept
tcpaccept的演示,Linux eBPF/bcc版本
该工具跟踪接受TCP套接字连接的内核函数 (例如,a passive connection via accept(); not connect())。
一些示例输出 (更改IP地址以保护无辜) :
# ./tcpaccept
PID COMM IP RADDR RPORT LADDR LPORT
907 sshd 4 192.168.56.1 32324 192.168.56.102 22
907 sshd 4 127.0.0.1 39866 127.0.0.1 22
5389 perl 6 1234:ab12:2040:5020:2299:0:5:0 52352 1234:ab12:2040:5020:2299:0:5:0 7001
This output shows three connections, two IPv4 connections to PID 907, an "sshd" process listening on port 22, and one IPv6 connection to a "perl" process listening on port 7001.
The overhead of this tool should be negligible, since it is only tracing the kernel function performing accept. It is not tracing every packet and then filtering.
This tool only traces successful TCP accept()s. Connection attempts to closed ports will not be shown (those can be traced via other functions).
The -t option prints a timestamp column:
该输出显示了三个连接,两个到PID 907的IPv4连接,一个监听端口22的 “sshd” 进程,以及一个监听端口7001的 “perl” 进程的IPv6连接。
这个工具的开销应该可以忽略不计,因为它只跟踪执行accept的内核函数。它不是跟踪每个包,然后过滤。
此工具仅跟踪成功的TCP accept()。将不会显示对关闭端口的连接尝试(这些尝试可以通过其他功能跟踪)。
# ./tcpaccept -t
TIME(s) PID COMM IP RADDR RPORT LADDR LPORT
0.000 907 sshd 4 127.0.0.1 53700 127.0.0.1 22
0.010 5389 perl 6 1234:ab12:2040:5020:2299:0:5:0 40614 1234:ab12:2040:5020:2299:0:5:0 7001
0.992 907 sshd 4 127.0.0.1 32548 127.0.0.1 22
1.984 907 sshd 4 127.0.0.1 51250 127.0.0.1 22
The --cgroupmap option filters based on a cgroup set. It is meant to be used with an externally created map.
# ./tcpaccept --cgroupmap /sys/fs/bpf/test01
For more details, see docs/special_filtering.md
USAGE message:
# ./tcpaccept -h
usage: tcpaccept.py [-h] [-T] [-t] [-p PID] [-P PORT] [-4 | -6] [--cgroupmap CGROUPMAP]
Trace TCP accepts
optional arguments:
-h, --help show this help message and exit
-T, --time include time column on output (HH:MM:SS)
-t, --timestamp include timestamp on output
-p PID, --pid PID trace this PID only
-P PORT, --port PORT comma-separated list of local ports to trace
-4, --ipv4 trace IPv4 family only
-6, --ipv6 trace IPv6 family only
--cgroupmap CGROUPMAP
trace cgroups in this BPF map only
examples:
./tcpaccept # trace all TCP accept()s
./tcpaccept -t # include timestamps
./tcpaccept -P 80,81 # only trace port 80 and 81
./tcpaccept -p 181 # only trace PID 181
./tcpaccept --cgroupmap mappath # only trace cgroups in this BPF map
./tcpaccept --mntnsmap mappath # only trace mount namespaces in the map
./tcpaccept -4 # trace IPv4 family only
./tcpaccept -6 # trace IPv6 family only
tcptop