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
总是规则<代码>人永远是规则!