多网卡Ubuntu环境下255.255.255.255广播被抓包但程序未接收问题
问题根因
1. 内核反向路径过滤(rp_filter)丢弃数据包
这是多网卡场景下UDP广播收不到最常见的原因:Ubuntu默认开启rp_filter机制,会校验收到的IP包的源地址对应的路由出口,是否和实际收包的网卡一致,不一致就直接丢弃。tcpdump/wireshark能抓到包是因为抓包动作发生在内核过滤逻辑之前,所以你能看到包但上层程序收不到。
你的环境里两张网卡都属于192.168段,路由表存在两条同段路由:
- ens160对应192.168.0.0/24路由,优先级100
- ens192对应192.168.0.0/16路由,优先级101
设备回复的广播包源IP属于192.168段,内核计算源IP路由时会匹配优先级更高的ens160路由,如果广播包实际从ens192进入,就会触发rp_filter规则被直接丢弃。
2. 防火墙规则拦截端口
如果系统防火墙配置了UDP 2000、2001端口的入站拦截规则,也会导致程序收不到包。
解决步骤
第一步:临时关闭rp_filter验证问题
执行以下命令临时关闭rp_filter:
sudo sysctl -w net.ipv4.conf.all.rp_filter=0 sudo sysctl -w net.ipv4.conf.ens160.rp_filter=0 sudo sysctl -w net.ipv4.conf.ens192.rp_filter=0
运行程序测试如果能正常收到广播包,说明就是rp_filter的问题。可以修改/etc/sysctl.conf文件添加以下配置永久生效:
net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.ens160.rp_filter = 0 net.ipv4.conf.ens192.rp_filter = 0
执行sudo sysctl -p让配置生效。
第二步:检查防火墙规则
执行以下命令查看是否有拦截2000、2001端口的规则:
sudo iptables -L INPUT -n | grep -E '2000|2001'
如果存在DROP或者REJECT规则,执行以下命令放行对应端口的UDP流量:
sudo iptables -I INPUT -p udp --dport 2000 -j ACCEPT sudo iptables -I INPUT -p udp --dport 2001 -j ACCEPT
可选优化:显式绑定监听网卡
如果需要指定从某张网卡收广播包,可以在监听socket上添加SO_BINDTODEVICE选项,修改create_probing_listen_server函数如下:
def create_probing_listen_server(bind_interface, bind_port, nic_name=None): server = SocketServer.UDPServer((bind_interface, bind_port), BroadcastMessageHandler) server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) if nic_name: # 绑定到指定网卡,注意字符串末尾要加\0结束符 server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, nic_name + '\0') return server
创建监听服务时传入对应网卡名称即可:
listen_server = create_probing_listen_server('0.0.0.0', port, nic_name='ens160')
内容的提问来源于stack exchange,提问作者nonamer92
相关产品推荐
相关产品推荐

