in the packet header. If IP_PKTINFO is passed to sendmsg(2) and ipi_spec_dst is not zero, then it is used as the local source address for the routing table lookup
and for setting up IP source route options. When ipi_ifindex is not zero, the primary local address of the interface specified by the index overwrites ipi_spec_dst
for the routing table lookup.
假设 ipi_spec_dst 和 ipi_ifindex 不为空,它们都能作为源地址选择的依据,而不是让内核经过路由决议。
也就是说,经过设置 IP_PKTINFO socket 选项为 1,然后运用 recvmsg 和 sendmsg 传输数据就能保证源地址选择契合我们的希冀。这也是 dnsmasq 运用的方案,而出成绩的运用是由于运用了默许的 recvfrom 和 sendto 。
关于 UDP 衔接的疑惑
另外一个疑惑是:为什么内核会把源地址和之前不同的报文丢弃?以为它是合法的?由于我们前面曾经说过,UDP 协议是无衔接的,默许状况下 socket 也不会保存双方衔接的信息。即使效劳端发送报文的源地址有误,只需对方能正常接纳并处置,也不会招致网络不通。
由于 conntrack,内核的 netfilter 模块会保存衔接的形状,并作为防火墙设置的依据。它保存的 UDP 衔接,只是复杂记载了主机上本地 ip 和端口,和对端 ip 和端口,并不会保存更多的内容。
可以参考 intables info 网站的文章:#UDPCONNECTIONS。
在找到本源之前,我们曾经尝试过用 SNAT 来修正效劳端应对报文的源地址,希冀可以修复该成绩。但是却发现这种办法行不通,为什么呢?
由于 SNAT 是在 netfilter 最后做的,在之前 netfilter 的 conntrack 由于不看法该 connection,直接丢弃了,所以即使添加了 SNAT 也是无法任务的。
那能不能把 conntrack 功用去掉呢?比如处置方案:
iptables -I OUTPUT -t raw -p udp --sport 5060 -j CT --notrack
iptables -I PREROUTING -t raw -p udp --dport 5060 -j CT --notrack
答案也能否认的,由于 NAT 需求 conntrack 来做翻译任务,假设去掉 conntrack 等于 SNAT 完全没用。
处置方案
知道了成绩的缘由,处置方案也就很容易找到。
运用 TCP 协议
假设效劳端和客户端运用 TCP 协议停止通讯,它们之间的网络是正常的。
$ nc -l 56789
监听在特定端口
运用 nc 启动一个 udp 效劳器,监听在 eth0 上:
➜ ~ nc -ul 172.16.13.13 56789
nc 可以跟两个参数,辨别代表 ip 和 端口,表示效劳端监听在某个特定 ip 上。假设接纳到的报文目的地址不是 172.16.13.13,也会被内核直接丢弃。
这种状况下,效劳端和客户端也能正常通讯。
改动运用顺序完成
修正运用顺序的逻辑,在 UDP socket 上设置 IP_PKTIFO ,并经过 recvmsg 和 sendmsg 函数传输数据。
【编辑引荐】
在Docker中运转MySQL:多主机网络下Docker Swarm形式的容器管理
搭建前端开发环境——docker篇
使Docker搭建Java Web运转环境
在Docker中运转Java:为了避免失败,你应该知道的
踩坑小结!喜马拉雅 FM 测试环境的 Docker 化实际
(责任编辑:admin)