【发布时间】:2020-08-28 15:37:05
【问题描述】:
我有一些 Python 代码可以打开一个套接字并使用 socket.setsockopt(..., SO_ATTACH_FILTER) 将 BPF 过滤器附加到它。不幸的是,生成过滤器的代码与其他东西有点纠结,但下面有一个可运行的大纲展示了我正在尝试做的事情。过滤器检查 EthernetType 字段是否为ETH_P_IP,IP 协议为IPPROTO_UDP,目标端口为 68 - 这应该将数据包限制为仅 DHCP 响应。
在主机上使用sudo python3 test.py 运行下面的脚本每次都会导致超时,除非我在超时发生之前手动执行 DHCP 租约更新(或者在网络上更新 DHCP 租约时非常偶尔)。但是,如果我在具有主机模式网络的 Docker 容器中做同样的事情,它几乎永远不会导致超时,总是会收到一个数据包,而且它几乎永远不会是 DHCP 响应。
docker 容器以 --privileged --net=host 并以 root 用户身份运行。
我必须做些什么才能让数据包过滤器在容器内工作吗?还是根本不可能?
import ctypes
import struct
import socket
ETH_P_ALL = 0x0003
SO_ATTACH_FILTER = 26
filters = bytes([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])
b = ctypes.create_string_buffer(filters)
mem_addr_of_filters = ctypes.addressof(b)
pf = struct.pack("HL", 11, mem_addr_of_filters)
def main():
sock = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
sock.bind(("eth0_bridge", ETH_P_ALL))
sock.settimeout(2)
sock.setsockopt(socket.SOL_SOCKET, SO_ATTACH_FILTER, pf)
try:
data = sock.recv(1500)
except:
print('Timeout')
exit(-1)
print('No timeout')
main()
【问题讨论】:
-
filters字节数组的第一行末尾缺少逗号。可以肯定的是,这只是一个复制粘贴错误吗?您的代码中有逗号吗? -
tcpdump ip proto \\udp and dst port 68在您的容器中工作吗?它应该使用相同的过滤器。 -
@Qeole - 是的,tcpdump 按预期工作。然而,事实证明这不是特定于 docker 容器,所以我要开始另一个问题。