通过特定接口发送后,响应UDP数据包无法通过正确的IP和端口到达

时间:2013-10-31 09:19:06

标签: c++ sockets routing udp wireshark

我已经设置了一些路由规则,以确保通过与套接字绑定的同一接口发送数据包。 (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 ,而不是 PREROUTING 中的 PREROUTING nat 表。它也没有通过 INPUT 表。我不知道为什么在这一点上。

原始 PREROUTING 中设置的iptables TRACE 跟踪数据包。它完成了 PREROUTING mangle 中的规则(我没有试过任何东西),并最终在那里停止了一些政策#。该数字代表选择该特定表中的哪个规则。默认策略是 ACCEPT 无处不在,是可用的最高数量。 (用户规则数量+ 1)

使用iptables -L -nvxiptables -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

EDIT2:

从同一无线网络内的设备发回的UDP数据包确实有效。它也适用于本地和外部网络绑定到eth0的套接字。这些路由通常也会跳过 nat PREROUTING 部分,直接进入ip路由表。 (Visualization)显然出现了问题。我无法验证到另一个表的重定向是否真正有效(使用 MARK ip rule add from "source" table #),我们也欢迎提出相关建议。此外,我还无法弄清楚路由表中应该包含哪些内容以允许数据包继续 INPUT

不满意的解决方案:

/etc/sysctl.conf 中设置 log_martians 变量由于反向路径过滤,我终于可以看到数据包被丢弃了。幸运的是,在同一个文件中将 rp_filter 变量设置为 2 可以解决问题。

正如所解释的here数据包将被阻止,如果他们进入的接口无法找到到源的路由。将此 rp_filter 值设置为2将解决我的问题,因为它依赖于我的默认接口实际上可以路由到此源的事实。

剩余问题:

出于某种原因,将此 rp_filter 值设置为0并不总是有效(它应该根本不丢弃任何火星数据包)。不知道为什么会这样。

此外,我真的不喜欢这个解决方案,如果有的话,很乐意实现更好的解决方案。在我看来,我需要找到一种方法来为wlan0接口提供一种标准方式来路由到这个源,而不仅仅是标记数据包。建议?

1 个答案:

答案 0 :(得分:0)

此问题的简单答案是将/etc/sysctl.conf中的 rp_filter 值设置为2。您可以单独为每个接口执行此操作,也可以将它们设置为默认和全部。我不完全确定这些值是如何工作的,但我认为默认将每个新接口设置为该特定值,并且所有接口都设置为该值(但可能存在例外情况?)。

net.ipv4.conf.default.rp_filter=2
net.ipv4.conf.all.rp_filter=2

请注意,您必须重置sysctl和网络管理器,以确保使用新设置。

sysctl -p /etc/sysctl.conf
service network-manager restart

修改

更好的方法是将路由呼叫更改为:

ip rule add from 193.156.108.78 table 21
ip route add dev wlan0 default via 193.156.108.1 table 21

通过这种方式,您的系统将能够找到源地址的路由路径,这将使包通过,而无需设置 rp_filter