(注:我从 StackOverflow 移出了这个问题,因为在那里它被认为是题外话,更适合这里,而且仍然没有解决)
我有一个使用 luasocket 的 udp 客户端,基本上是这样做的(带有几个抽象层,但这是那里发生的事情):
s=socket.udp()
s:setsockname("*",0)
s:setpeername(socket.dns.toip("example.com"),64299)
s:settimeout(0)
s:send(...)
s:settimeout(10)
msg,err=s:receive()
s:settimeout(0)
print(msg,err)
虽然在服务器的调试输出(ssh 到远程主机)中看到一切正常,但我在客户端收到“超时”错误。
当使用客户端 wireshark 检查所有内容时,我看到了客户端发送的数据包和来自服务器的响应数据包(正确的端口和所有内容),以及从我的客户端主机发送到服务器以响应其(正确)响应的 ICMP“端口不可达”数据包。
那里发生了什么?我尝试了所有方法,包括将我的 iptables 重置为“接受所有内容”,但我的客户端仍然发送“端口不可达”。
相关数据包为:
From To Len Description
192.168.2.100 95.143.172.171 UDP 61 Source port: 45025 Destination port: 64299
000e8f11e7000025229835a908004500002f4008400040112b6fc0a802645f8facabafe1fb2b001b28d794d2000ec8360100aa81a477616e74a3756964
95.143.172.171 192.168.2.100 UDP 60 Source port: 64299 Destination port: 45025
0025229835a9000e8f11e70008004500002b000040003911727b5f8facabc0a80264fb2bafe100172e8d94d2000e0ea10100a681a3756964ff000000
192.168.2.100 95.143.172.171 ICMP 85 Destination unreachable (Port unreachable)
000e8f11e7000025229835a9080045c00047061d00004001a492c0a802645f8facab0303cc6c000000004500002b000040003911727b5f8facabc0a80264fb2bafe100172e8d94d2000e0ea10100a681a3756964ff
防火墙,以防万一(我不这么认为,因为当这种情况发生时,iptables 不会增加任何 INPUT 数据包计数器):
$ sudo iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -i eth0 -p udp -m udp --sport 64299 -j ACCEPT
-A INPUT -i eth0 -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i eth0 -p tcp -m tcp --dport 10001:30000 -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -o lo -j ACCEPT
客户端和服务器都使用完全相同的代码,因此我的客户端主机上的某些东西似乎会干扰传入的响应数据包。
TL;DR 时间线:
- 客户端应用程序打开 UDP 套接字,“连接”到服务器
- 客户端应用程序发送请求数据包
- 服务器应用程序接收请求数据包
- 服务器应用程序发送响应数据包
- 客户端主机收到响应数据包(通过客户端的wireshark验证)
- 客户端主机发送 ICMP 端口不可达(在客户端的 wireshark 中注意到)
- 客户端应用程序在 10 秒后收到读取超时
- (刚刚尝试过:)从客户端向服务器发送更多数据包确实有效,所以套接字没有关闭。