而此时主机上 UDP nc 办事器并没有退出,应用 lsof -i :56789 可能看到它仍然在监听着该端口。
问题原因
大年夜收集报文的分析中可以看到办事端返回的报文源地址不是我们预想的 eth0 地址,而是 docker0 的地址,而客户端直接认为该报文是不法的,返回了 ICMP 的报文给对方。
主机多收集接口 UDP 源地址选择问题
第一个问题的关键词是:UDP 和多收集接口。因为如不雅主机上只有一个收集接口,发出去的报文源地址必定不会有错;而我们也测试过 TCP 协定是可以或许处理这个问题的。
经由过程搜刮,发明这确切是个已知的问题。在 UNP() 这本书中,已经描述过这个问题,下面是对应的内容:
这篇文┞仿就分析一下出现这个问题的原因,欲望给同样碰到这个问题的读者供给些赞助。

这个问题可以归结为一句话:UDP 在多网卡的情况下,可能会产生办事器端源地址纰谬的情况,这是内核选路的结不雅。 为什么 UDP 和 TCP 有不合的选路逻辑呢?因为 UDP 是无状况的协定,内核不会保存连接两边的信息,是以每次发送的报文都认为是自力的,socket 层每次发送报文默认情况不会指明要应用的源地址,只是解释对方地址。是以,内核会为要发出去的报文选择一个 ip,这平日都是报文路由要经由的设备 ip 地址。
有了这个原因,还要解释一下问题: 为什么 dnsmasq 办事没有这个问题呢 ?是以我应用 strace 对象抓取了 dnsmasq 和出问题应用的收集 socket 体系调用,来查看它们两个到底有什么差别。
dnsmasq 在启动阶段监听了 UDP 和 TCP 的 54 端口(因为是在本地机械上测试的,为了防止和本地 DNS 监听的 DNS端口才突,我选择了 54 而不是标准的 53 端口):
- socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
- setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
- bind(4, {sa_family=AF_INET, sin_port=htons(54), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
- setsockopt(4, SOL_IP, IP_PKTINFO, [1], 4) = 0
- socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 5
- setsockopt(5, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
- bind(5, {sa_family=AF_INET, sin_port=htons(54), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
- listen(5, 5) = 0
比起 TCP,UDP 部分少了 listen ,然则多个 setsockopt(4, SOL_IP, IP_PKTINFO, [1], 4) 这句。到底这两点和我们的问题是否有关,先临时放着,持续看传输报文的部分。
dnsmasq 收包和发包的体系调用,直接应用 recvmsg 和 sendmsg 体系调用:
- recvmsg(4, {msg_name(16)={sa_family=AF_INET, sin_port=htons(52072), sin_addr=inet_addr("10.111.59.4")}, msg_iov(1)=[{"\315\n\1 \0\1\0\0\0\0\0\1\fterminal19-0\5u5016\3"..., 4096}], msg_controllen=32, {cmsg_len=28, cmsg_level=SOL_IP, cmsg_type=, ...}, msg_flags=0}, 0) = 67
- sendmsg(4, {msg_name(16)={sa_family=AF_INET, sin_port=htons(52072), sin_addr=inet_addr("10.111.59.4")}, msg_iov(1)=[{"\315\n\201\200\0\1\0\1\0\0\0\1\fterminal19-0\5u5016\3"..., 83}], msg_controllen=28, {cmsg_len=28, cmsg_level=SOL_IP, cmsg_type=, ...}, msg_flags=0}, 0) = 83
而出问题的应用 strace 结不雅如下:
谜底也是否定的,因为 NAT 须要 conntrack 来做翻译工作,如不雅去掉落 conntrack 等于 SNAT 完全没用。

网友点评
精彩导读
科技快报
品牌展示