type
status
date
slug
summary
tags
category
icon
password
AI 摘要
在学习使用Cilium ebpf的过程中遇到了个问题:socket ebpf程序如何加载到Socket上? 这里对ebpf内核程序代码不做具体讲解,简单来说是通过socket解析以太网帧,再通过以太网帧获取IP数据报,接着再获取TCP,通过TCP获取HTTP请求头。具体源码请参考:https://github.com/CeerDecy/study-ebpf
1. 尝试使用Cilium ebpf函数
在"github.com/cilium/ebpf/link"包下有一个函数叫做
link.AttachSocketFilter() 这个函数似乎是可以用来加载socket ebpf程序的。但查看其源码可以发现,第一个参数是
syscall.Conn类型的接口。那不就意味着这个ebpf加载程序必须得写在业务代码中,这不就有点扯了嘛。
因为我想监控的是另一个程序中的http服务。
2. 使用syscall进行绑定
于是参考eunomia中的http案例,需要自己实现一套syscall函数;案例中的方式是创建一个新的socket描述符,然后将网卡绑定到这个socket上。
所以我在Docker中跑了一个HTTP应用

2.1 绑定网卡
在eunomia的案例中,可以看到有一个
open_raw_sock 函数,这个函数的作用是将一个网卡绑定到一个socket上,那么我们只需要用Go去实现一下对应的方法即可。可以看到案例中
open_raw_sock 的参数是一个字符串,查看代码可以知道,这个参数指的是网卡的名称,通过if_nametoindex 函数获取对应网卡的index。那么在我们自己的项目中,我们只需要将docker容器对应的虚拟网卡进行绑定即可。使用
github.com/vishvananda/netlink 包可以很方便得获取当前宿主机上的网卡,通过其Type即可过滤出docker容器的虚拟网卡,并获取到它的index。仿照案例中的代码,再问问GPT,就可以改造出以下的Go代码,其中的
Htons 函数可以将小端字节序的数据转换成大端,因为网络是基于大端传输的。3. 加载ebpf程序
接着参考Cilium ebpf中的
AttachSocketFilter 函数,将ebpf手动加载到socket上。然后让我们运行一下,向这个docker服务发送个请求试试。可以看到请求已经被正确过滤了出来,程序已经可以正常执行了,但是又有个疑问,既然Cilium ebpf已经封装好了
AttachSocketFilter 那我能不能将sock转换成其参数类型syscall.Conn呢?

4. 使用AttachSocketFilter()
我翻阅了github上的一些开源项目,参考了一位日本的开发者的案例ebpf-http-monitor-go,其实可以将socket转换成file,因为file本身就是syscall.Conn的实现。