TCP标准具有“同时打开”功能。
当端口来自ephemeral range时,客户端尝试连接到本地端口时,该功能的含义有时会连接到自身(请参阅here)。
因此客户认为它与服务器连接,而实际上它与自身连接。从另一方面来说,服务器无法打开其服务器端口,因为它被客户端占用/窃取。
我正在使用RHEL 5.3,我的客户不断尝试连接到本地服务器。 最终客户端连接到自身。
我想防止这种情况发生。我看到了两个可能解决问题的方法:
P.S。 1
除了我明显寻找的解决方案, 我希望你能分享你对这个问题的真实体验。
当我找到问题的原因时,我对我的工作场所感到“惊讶”,人们并不熟悉它。通过定期连接轮询服务器是恕我直言的常见做法, 那么这个问题怎么会不为人所知。
答案 0 :(得分:14)
当我偶然发现这一点时,我惊呆了。我可以弄明白即将离任 端口号意外匹配传入端口号,但不是TCP的原因 握手(SYN SYN-ACK ACK)会成功(问问自己:如果是,谁发送ACK) 没有人在做listen()和接受()???)
Linux和FreeBSD都显示了这种行为。
无论如何,一种解决方案是远离服务器的高端口号。
我注意到Darwin通过不允许传出端口来解决这个问题 与目标端口相同。他们一定也被这个咬了......
显示此效果的简单方法如下:
while true
do
telnet 127.0.0.1 50000
done
等一下左右,你会和自己聊天......
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello?
hello?
无论如何,这是一本很好的面试材料。
答案 1 :(得分:3)
将客户端套接字绑定到端口0(系统分配),检查系统分配的端口,如果它与您已知服务器已关闭的本地服务器端口匹配,并且可以跳过connect()。
答案 2 :(得分:2)
对于服务器,您需要将()套接字绑定到端口。一旦addr:port对具有套接字绑定,它将不再用于connect()中的隐式绑定。
没问题,没问题。
答案 3 :(得分:1)
请注意,这个解决方案是理论上的,我没有自己测试过。我之前没有经历过(或没有意识到),希望我再也不会体验它了。
我假设您既不能编辑客户端源代码也不能编辑服务器源代码。另外,我假设真正的问题是无法启动的服务器。
使用入门应用程序启动服务器。如果任何进程正在使用服务器将绑定的目标端口,请使用原始套接字创建RST(重置数据包)。
以下帖子简要介绍了RST数据包的内容(取自http://forum.soft32.com/linux/killing-socket-connection-cmdline-ftopict473059.html)
你必须看一下"原始套接字"包发生器。
你必须是超级用户。
您可能也需要网络嗅探器。
http://en.wikipedia.org/wiki/Raw_socket
http://kerneltrap.org/node/3072 - TCP RST攻击
http://search.cpan.org/dist/Net-RawIP/lib/Net/RawIP.pm - Perl模块
http://mixter.void.ru/rawip.html - C中的原始IP在C版本中,您需要一个TH_RST数据包。
RST旨在处理以下情况。
A和B建立连接。
B重新启动,忘掉了这一点。
A从端口Y向B发送数据包到端口X.
B发回一个RST数据包,说"你在说什么?我不是 与你有联系。请关闭此连接。"
所以你必须知道/伪造B的IP地址,并且知道两个端口X
和Y.其中一个端口将是众所周知的端口号。另一个 你必须找出答案。我知道你还需要知道序列
数。
通常人们会用嗅探器来做这件事。你可以使用带有
的开关 数据包镜像功能,或在主机A或B上运行嗅探器。
作为一个说明,康卡斯特这样做是为了禁用P2P流量。
http://www.eff.org/wp/packet-forgery-isps-report-comcast-affair
在我们的案例中,我们不需要使用嗅探器,因为我们知道以下信息:
所以你必须知道/伪造B的IP地址,并且知道两个端口X. 和Y
X = Y,B' IP地址为localhost
http://mixter.void.ru/rawip.html上的教程描述了如何使用原始套接字。
注意,系统上的任何其他进程也可能从临时池中窃取目标端口。 (例如Mozilla Firefox)此解决方案不适用于此类连接,因为X!= Y B的IP地址不是localhost,而是类似于eth0上的192.168.1.43。在这种情况下,您可以使用netstat检索X,Y和B的IP地址,然后相应地创建RST数据包。
答案 4 :(得分:0)
其他选项是在固定端口上运行服务器,在固定源端口上运行客户端。比如,服务器运行在5000上,客户端运行在5001.如果其他东西绑定到它们,你确实遇到了绑定到其中任何一个的问题。
您可以在偶数端口号上运行服务器并强制客户端使用奇数端口号。在短暂范围内选择一个随机数,或者选择1,然后用它调用bind()。如果bind()因EADDRINUSE而失败,则选择一个不同的奇数端口号,然后重试。
答案 5 :(得分:0)
此选项实际上并未在大多数TCP中实现。你有实际的问题吗?
答案 6 :(得分:0)
这是一个有趣的问题!如果您最担心服务器正在运行,则可以始终在服务器本身中实施心跳机制,以向另一个进程报告状态。或者您可以编写一个脚本来检查并查看您的服务器进程是否正在运行。
如果您更关心与可用服务器的实际连接,我建议您将客户端移至另一台计算机。这样您就可以验证您的服务器至少具有一些网络连接。
答案 7 :(得分:0)
在我看来,这是TCP规范中的一个错误;监听套接字不应该能够发送未经请求的SYN,并且在发送一个SYN之后接收SYN(而不是SYN + ACK)应该是非法的并导致重置,这将很快让客户关闭不幸的选择当地港口。但没有人问我的意见;)
正如你所说,显而易见的答案是不要在短暂的端口范围内收听。如果你知道你将连接到本地机器,另一个解决方案是设计你的协议,以便服务器发送第一条消息,并在客户端短暂超时以接收该消息
答案 8 :(得分:0)
您遇到的实际问题似乎是,当服务器关闭时,其他东西可以使用您期望服务器的临时端口作为传出连接的源端口。这种情况的细节与实际问题是分开的,它可能以你描述的方式以外的方式发生。
该问题的解决方案是在套接字上设置SO_REUSEADDR。这将允许您在具有当前传出连接的端口上创建服务器。
如果您真的关心该端口号,可以使用特定于操作的方法来阻止它被分配为短暂的端口。