首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BPF滤波器失败

BPF滤波器失败
EN

Stack Overflow用户
提问于 2021-01-04 18:56:04
回答 1查看 450关注 0票数 3

有人能建议为什么这个(经典的) BPF程序有时允许非DHCP响应数据包通过:

代码语言:javascript
复制
# Load the Ethertype field
BPF_LD | BPF_H | BPF_ABS    12
# And reject the packet if it's not 0x0800 (IPv4)
BPF_JMP | BPF_JEQ | BPF_K   0x0800    0    8

# Load the IP protocol field
BPF_LD | BPF_B | BPF_ABS    23
# And reject the packet if it's not 17 (UDP)
BPF_JMP | BPF_JEQ | BPF_K   17        0    6

# Check that the packet has not been fragmented
BPF_LD | BPF_H | BPF_ABS    20
BPF_JMP | BPF_JSET | BPF_K  0x1fff    4    0

# Load the IP header length field
BPF_LDX | BPF_B | BPF_MSH   14
# And load that offset + 16 to get the UDP destination port
BPF_LD | BPF_IND | BPF_H    16
# And reject the packet if the destination port is not 68
BPF_JMP | BPF_JEQ | BPF_K   68        0    1

# Accept the frame
BPF_RET | BPF_K             1500
# Reject the frame
BPF_RET | BPF_K             0

它并不能让每个帧都通过,但是在网络负载很重的情况下,它经常会失败。我正在用这个Python 3程序来测试它:

代码语言:javascript
复制
import ctypes
import struct
import socket
ETH_P_ALL = 0x0003
SO_ATTACH_FILTER = 26
SO_ATTACH_BPF = 50
filters = [
0x28, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,  0x15, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,  0x15, 0x00, 0x00, 0x06, 0x11, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,  0x45, 0x00, 0x04, 0x00, 0xff, 0x1f, 0x00, 0x00,
0xb1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,  0x48, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00, 0x00,  0x06, 0x00, 0x00, 0x00, 0xdc, 0x05, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]

filters = bytes(filters)

b = ctypes.create_string_buffer(filters)
mem_addr_of_filters = ctypes.addressof(b)
pf = struct.pack("HL", 11, mem_addr_of_filters)
pf = bytes(pf)

def main():                                                                                     
    sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))            
    sock.bind(("eth0", ETH_P_ALL))                                                              
    sock.setsockopt(socket.SOL_SOCKET, SO_ATTACH_FILTER, pf)                                    
#    sock.send(req)                                                                             
    sock.settimeout(1)                                                                          
    try:                                                                                        
        data = sock.recv(1500)                                                                  
                                                                                                
        if data[35] == 0x43:                                                                    
            return                                                                              
        print('Packet got through: 0x{:02x} 0x{:02x}, 0x{:02x}, 0x{:02x}'.format(data[12], data[13], data
    except:                   
        print('Timeout')                                                            
        return                                              
    sock.close()                                            
                              
for ii in range(1000):                                                                                   
    main()                    

如果我在运行该脚本的主机上使用SCPing (一个大的核心文件)时这样做,那么在大多数情况下(但不是所有情况下),它不会达到一秒超时。在较轻的负载下,故障要少得多--例如,当套接字接收时,在ssh链接上旋转;有时,它通过1000次迭代而没有失败。

所讨论的主机是Linux4.9.0。内核有CONFIG_BPF=y

编辑

对于同一个问题的更简单的版本,为什么这个BPF程序允许任何数据包进入:

代码语言:javascript
复制
BPF_RET | BPF_K    0

编辑2上面的测试是在ARM64机器上进行的。我已经在amd64 /Linux5.9.0上进行了重新测试。我仍然看到失败,虽然没有那么多。

EN

回答 1

Stack Overflow用户

发布于 2021-01-19 17:48:27

我让对LKML的响应解释这件事。

问题是当框架到达接口时应用过滤器,而不是通过recv()传递到用户空间。因此,在重载下,从socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))套接字的创建到sock.setsockopt(socket.SOL_SOCKET, SO_ATTACH_FILTER, pf)应用的过滤器之间,帧就到达了。这些帧位于队列中;一旦应用了过滤器,随后到达的数据包就会应用过滤器。

因此,一旦应用了过滤器,就必须从套接字中“排出”任何排队的帧,然后才能依赖该筛选器。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65568257

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档