我已经设置了一些路由规则,以确保数据包通过与套接字绑定的相同接口发送。(C++ 中的 sendto 函数将尝试根据目标地址选择最佳接口)。我正在向本地网络内外的其他设备发送 UDP 数据包,作为回报,它们通过向同一地址发送 UDP 数据包来响应。使用Wireshark,我可以验证是否发生了这种情况。
但是,尽管数据包到达网络堆栈,因此可以被 Wireshark 读取,但它们不会被绑定到特定接口的套接字接收。
我的 Ubuntu 系统上的路由规则如下:
iptables -A OUTPUT -o wlan0 -t mangle -p udp -s 193.156.108.78 --sport 12346 -j MARK --set-mark 21
ip rule add fwmark 21 table 21
ip route add dev wlan0 default via 193.156.108.1 table 21
我认为我需要对传入流量的iptables进行更改,但我不确定什么不起作用,因为以太网帧和 ip 标头上的地址似乎都是正确的。
编辑:
在 iptables 中使用 LOG 目标我已经确定数据包使用mangle表中的PREROUTING ,而不是nat表中的PREROUTING 。它也不会通过INPUT表。我不知道为什么在这一点上。
在PREROUTING in raw中设置为规则的 iptables TRACE跟踪数据包。它通过PREROUTING mangle中的规则(我没有尝试过但没有让我到任何地方)并最终以一些策略停止在那里 #。该数字代表选择了该特定表中的哪个规则。默认策略是ACCEPT ,它是可用的最高数字。(用户规则数+1)
使用iptables -L -nvx
和iptables -S -v
接受数据包的数量和规则可以可视化。
所以即使我的数据包似乎被接受了,它仍然被丢弃在某个地方。我真的可以在这里使用一些帮助。
这是一个这样的数据包的完整跟踪:
Nov 1 09:18:23 XXX kernel: [ 2377.505697] TRACE: raw:PREROUTING:policy:3 IN=wlan0 OUT= MAC=XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX SRC=XXX.XXX.XXX.XXX DST=193.156.108.67 LEN=83 TOS=0x00 PREC=0x00 TTL=50 ID=0 DF PROTO=UDP SPT=6428 DPT=12346 LEN=63
Nov 1 09:18:23 XXX kernel: [ 2377.505721] TRACE: mangle:PREROUTING:policy:2 IN=wlan0 OUT= MAC=XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX SRC=XXX.XXX.XXX.XXX DST=193.156.108.67 LEN=83 TOS=0x00 PREC=0x00 TTL=50 ID=0 DF PROTO=UDP SPT=6428 DPT=12346 LEN=63
编辑2:
从同一无线网络中的设备发回的 UDP 数据包确实有效。它也适用于本地和外部网络绑定到 eth0 的套接字。这些路由通常也会跳过nat PREROUTING部分,直接进入 ip 路由表。(可视化)这显然是哪里出了问题。我无法验证重定向到另一个表是否确实有效(使用MARK或ip rule add from "source" table #
),也欢迎提出有关此问题的建议。此外,我还无法弄清楚路由表中应该有什么以允许数据包继续输入 INPUT。
不满意的解决方案:
在/etc/sysctl.conf中设置log_martians变量我终于可以看到数据包被丢弃了,大概是由于反向路径过滤。幸运的是,在同一个文件中将rp_filter变量设置为2可以解决问题。
正如这里所解释的,如果数据包进入的接口找不到到源的路由,数据包将被阻止。将此rp_filter值设置为 2 将解决我的问题,因为它依赖于我的默认接口实际上可以路由到此源的事实。
剩下的问题:
由于某种原因,将此rp_filter值设置为 0 并不总是有效(它根本不应该丢弃任何火星数据包)。不知道为什么会这样。
此外,我不太喜欢这个解决方案,如果有的话,我很乐意实施一个更好的解决方案。在我看来,我需要找到一种方法来为 wlan0 接口提供一种标准方法来路由到此源,而不仅仅是通过标记数据包。建议?