mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-02-12 06:35:16 +08:00
95 lines
2.4 KiB
Markdown
95 lines
2.4 KiB
Markdown
## eBPF 入门实践教程:编写 eBPF 程序 Bindsnoopn 监控 socket 端口绑定事件
|
||
|
||
### 背景
|
||
|
||
Bindsnoop 会跟踪操作 socket 端口绑定的内核函数,并且在可能会影响端口绑定的系统调用发生之前,打印
|
||
现有的 socket 选项。
|
||
|
||
### 实现原理
|
||
|
||
Bindsnoop 通过kprobe实现。其主要挂载点为 inet_bind 和 inet6_bind。inet_bind 为处理 IPV4 类型
|
||
socket 端口绑定系统调用的接口,inet6_bind 为处理IPV6类型 socket 端口绑定系统调用的接口。
|
||
|
||
```c
|
||
SEC("kprobe/inet_bind")
|
||
int BPF_KPROBE(ipv4_bind_entry, struct socket *socket)
|
||
{
|
||
if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
|
||
return 0;
|
||
|
||
return probe_entry(ctx, socket);
|
||
}
|
||
SEC("kretprobe/inet_bind")
|
||
|
||
int BPF_KRETPROBE(ipv4_bind_exit)
|
||
{
|
||
if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
|
||
return 0;
|
||
|
||
return probe_exit(ctx, 4);
|
||
}
|
||
|
||
SEC("kprobe/inet6_bind")
|
||
int BPF_KPROBE(ipv6_bind_entry, struct socket *socket)
|
||
{
|
||
if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
|
||
return 0;
|
||
|
||
return probe_entry(ctx, socket);
|
||
}
|
||
|
||
SEC("kretprobe/inet6_bind")
|
||
int BPF_KRETPROBE(ipv6_bind_exit)
|
||
{
|
||
if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
|
||
return 0;
|
||
|
||
return probe_exit(ctx, 6);
|
||
}
|
||
```
|
||
|
||
当系统试图进行socket端口绑定操作时, kprobe挂载的处理函数会被触发。在进入绑定函数时,`probe_entry`会先被
|
||
调用,它会以 tid 为主键将 socket 信息存入 map 中。
|
||
|
||
```c
|
||
static int probe_entry(struct pt_regs *ctx, struct socket *socket)
|
||
{
|
||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||
__u32 pid = pid_tgid >> 32;
|
||
__u32 tid = (__u32)pid_tgid;
|
||
|
||
if (target_pid && target_pid != pid)
|
||
return 0;
|
||
|
||
bpf_map_update_elem(&sockets, &tid, &socket, BPF_ANY);
|
||
return 0;
|
||
};
|
||
```
|
||
在执行完绑定函数后,`probe_exit`函数会被调用。该函数会读取tid对应的socket信息,将其和其他信息一起
|
||
写入 event 结构体并输出到用户态。
|
||
|
||
```c
|
||
struct bind_event {
|
||
unsigned __int128 addr;
|
||
__u64 ts_us;
|
||
__u32 pid;
|
||
__u32 bound_dev_if;
|
||
int ret;
|
||
__u16 port;
|
||
__u16 proto;
|
||
__u8 opts;
|
||
__u8 ver;
|
||
char task[TASK_COMM_LEN];
|
||
};
|
||
```
|
||
|
||
当用户停止该工具时,其用户态代码会读取存入的数据并按要求打印。
|
||
|
||
### Eunomia中使用方式
|
||
|
||

|
||

|
||
|
||
### 总结
|
||
|
||
Bindsnoop 通过 kprobe 挂载点,实现了对 socket 端口的监视,增强了 Eunomia 的应用范围。 |