Networking ebpf:在lo接口上的套接字筛选器程序中丢弃ICMP数据包
考虑一个非常简单的Networking ebpf:在lo接口上的套接字筛选器程序中丢弃ICMP数据包,networking,linux-kernel,bpf,ebpf,Networking,Linux Kernel,Bpf,Ebpf,考虑一个非常简单的ebpf代码BPF\u PROG\u TYPE\u SOCKET\u FILTER类型: struct bpf_insn prog[] = { BPF_MOV64_IMM(BPF_REG_0, -1), BPF_EXIT_INSN(), }; 下面来自net/core/filter.c和net/core/sock/c的代码片段显示了如何调用过滤器: static inline int pskb_trim(struct sk_buff *skb, unsigned
ebpf
代码BPF\u PROG\u TYPE\u SOCKET\u FILTER
类型:
struct bpf_insn prog[] = {
BPF_MOV64_IMM(BPF_REG_0, -1),
BPF_EXIT_INSN(),
};
下面来自net/core/filter.c
和net/core/sock/c
的代码片段显示了如何调用过滤器:
static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
{
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
}
...
int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap)
{
int err;
...
if (filter) {
pkt_len = bpf_prog_run_save_cb(filter->prog, skb);
skb->sk = save_sk;
err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM;
}
...
return err;
}
...
static inline int sk_filter(struct sock *sk, struct sk_buff *skb)
{
return sk_filter_trim_cap(sk, skb, 1);
}
这将把数据包传递给AF_数据包
处理程序,该处理程序最终将运行ebpf过滤器
为了确认ebpf
过滤器确实在原始AF_数据包套接字上进行过滤,可以按如下方式转储统计数据:
struct tpacket_stats stats;
...
len = sizeof(stats);
err = getsockopt(sock, SOL_PACKET, PACKET_STATISTICS, &stats, &len);
此统计信息将指示筛选器行为。相反:如果返回0,它将丢弃数据包。。从代码中:
* sk_filter_trim_cap - run a packet through a socket filter
* [...]
*
* Run the eBPF program and then cut skb->data to correct size returned by
* the program. If pkt_len is 0 we toss packet. If skb->len is smaller
* than pkt_len we keep whole skb->data. [...]
相反:如果返回0,它将丢弃数据包。从代码中:
* sk_filter_trim_cap - run a packet through a socket filter
* [...]
*
* Run the eBPF program and then cut skb->data to correct size returned by
* the program. If pkt_len is 0 we toss packet. If skb->len is smaller
* than pkt_len we keep whole skb->data. [...]
pchaigno的答案是正确的,内核代码始终是真理的最终来源,但在这种情况下,我还将重定向到套接字的手册页。这里描述了将BPF过滤器连接到套接字的选项,并指出:
SO_ATTACH_FILTER (since Linux 2.2), SO_ATTACH_BPF (since Linux
3.19)
Attach a classic BPF (SO_ATTACH_FILTER) or an extended BPF
(SO_ATTACH_BPF) program to the socket for use as a filter
of incoming packets. A packet will be dropped if the
filter program returns zero. If the filter program
returns a nonzero value which is less than the packet's
data length, the packet will be truncated to the length
returned. If the value returned by the filter is greater
than or equal to the packet's data length, the packet is
allowed to proceed unmodified.
因此:
丢弃数据包(“截断为长度0”)0
- 小值截断数据包(到与该值对应的长度)
- 大值传递数据包
这对cBPF和eBPF都是有效的。来自pchaigno的答案是正确的,内核代码始终是真理的最终来源,但在这种情况下,我还将重定向到套接字的手册页面。这里描述了将BPF过滤器连接到套接字的选项,并指出:
SO_ATTACH_FILTER (since Linux 2.2), SO_ATTACH_BPF (since Linux
3.19)
Attach a classic BPF (SO_ATTACH_FILTER) or an extended BPF
(SO_ATTACH_BPF) program to the socket for use as a filter
of incoming packets. A packet will be dropped if the
filter program returns zero. If the filter program
returns a nonzero value which is less than the packet's
data length, the packet will be truncated to the length
returned. If the value returned by the filter is greater
than or equal to the packet's data length, the packet is
allowed to proceed unmodified.
因此:
丢弃数据包(“截断为长度0”)0
- 小值截断数据包(到与该值对应的长度)
- 大值传递数据包
这对cBPF和eBPF都有效。Hmm。。使用
BPF\u MOV64\u IMM(BPF\u REG\u 0,0)
ICMP仍然通过,即ping-c127.0.0.1
成功。我确信数据包符合ebpf
代码,因为我在tracelog
中打印数据包的ethertype。不知何故,ping
接收到数据包。您是如何加载和附加BPF程序的?您是如何检查ICMP数据包是否仍然收到的?套接字筛选器程序通常在数据包的副本上运行,因此删除该副本不会影响实际流量;它通过setsockopt(..,所以\u ATTACH\u BPF)
进行连接。我只是ping-c127.0.0.1
并查看0%数据包丢失
stats。我还运行了tcpdump-ilo
,这更接近于我的实验,因为tcpdump打开了PF_数据包原始套接字,如果我理解正确,套接字过滤器程序应该立即启动。当你说套接字过滤程序通常在数据包的副本上运行时,这是否意味着它们有时不在副本上运行?我用一些发现更新了我的问题。嗯。。使用BPF\u MOV64\u IMM(BPF\u REG\u 0,0)
ICMP仍然通过,即ping-c127.0.0.1
成功。我确信数据包符合ebpf
代码,因为我在tracelog
中打印数据包的ethertype。不知何故,ping
接收到数据包。您是如何加载和附加BPF程序的?您是如何检查ICMP数据包是否仍然收到的?套接字筛选器程序通常在数据包的副本上运行,因此删除该副本不会影响实际流量;它通过setsockopt(..,所以\u ATTACH\u BPF)
进行连接。我只是ping-c127.0.0.1
并查看0%数据包丢失
stats。我还运行了tcpdump-ilo
,这更接近于我的实验,因为tcpdump打开了PF_数据包原始套接字,如果我理解正确,套接字过滤器程序应该立即启动。当你说套接字筛选器程序通常在数据包的副本上运行时,这是否意味着它们有时不在副本上运行?我已经用一些发现更新了我的问题。man
总是规则<代码>人永远是规则!