使用Scapy遇到不想要的RST TCP数据包

34
为了理解TCP的工作原理,我尝试编写自己的TCP SYN/SYN-ACK/ACK(基于该教程:http://www.thice.nl/creating-ack-get-packets-with-scapy/)。
问题是每当我的计算机收到来自服务器的SYN-ACK时,它都会生成一个RST数据包,停止连接过程。
我在OS X Lion和Ubuntu 10.10 Maverick Meerkat上尝试过,两者都重置了连接。我找到了这个链接:http://lkml.indiana.edu/hypermail/linux/net/0404.2/0021.html,但不知道是否是原因。
请问有人可以告诉我可能的原因并如何避免这个问题吗?
谢谢。

我认为这段代码片段使问题更加明显:ans = scapy.all.sr1(generate_tcp_syn_pkt()); ack_pkt = generate_tcp_ack_pkt(ans); scapy.all.send(ack_pkt) - diabloneo
你是如何解决 OS X 的这个问题的? - user1505986
4个回答

35

你引用的文章已经很明确地说明了...

由于你没有完成完整的TCP握手,你的操作系统可能会尝试控制并开始发送RST(重置)数据包,为了避免这种情况,我们可以使用iptables:

iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.1.20 -j DROP

问题在于scapy在用户空间运行,而Linux内核会首先接收到SYN-ACK。 在您有机会使用scapy之前,内核将发送RST,因为它不会在涉及的端口号上打开套接字。

解决方案(如博客所述)是防火墙使内核无法发送RST数据包。


6
有没有不用IPTables的解决方案?我真的无法更改我的机器上的iptables配置。除此之外,我还想从我的实现中发送RST(为了测试目的创建自己的TCP流)。 - KillianDS

6

我没有非iptables的答案,但可以解决复位问题。不要尝试在过滤器表中过滤出站复位,而是在原始表中过滤目标的所有入站数据包。这样可以防止内核处理来自目标的返回数据包,虽然scapy仍然能够看到它们。我使用了以下语法:

iptables -t raw -A PREROUTING -p tcp --dport <source port I use for scapy traffic> -j DROP

这种解决方法强制我使用相同的源端口传输数据;您可以使用自己的iptables技巧来识别目标返回的数据包。


6
其他答案中引用的博客文章并不完全正确。问题不仅在于您没有完成三次握手,而且内核的IP堆栈也不知道正在发生连接。当它收到SYN-ACK时,会发送RST-ACK,因为这是意外的。首先接收还是最后接收并不重要。堆栈接收SYN-ACK是问题所在。
使用IPTables删除出站RST数据包是一种常见且有效的方法,但有时您需要从Scapy发送RST。一种更复杂但非常可行的方法是降低层级,生成并响应带有与主机不同的MAC地址的ARP。这使您能够在没有任何干扰的情况下发送和接收任何内容。
显然,这需要更多的努力。个人而言,我只在实际需要自己发送RST时采取这种方法(而不是RST删除方法)。

3
我在https://widu.tumblr.com/post/43624355124/suppressing-tcp-rst-on-raw-sockets上找到了一种不需要使用IPTables的解决方案。
为了绕过这个问题,只需创建一个标准的TCP套接字作为服务器套接字并绑定到请求的端口。不要执行accept()操作。只需对该端口进行socket()、bind()和listen()操作即可。这会放松内核并让您完成三次握手。

在我的情况下没有起作用。iptables可以。 - undefined
答案中所写的并没有太多意义。在我的情况下,我想要发送数据包的套接字(服务器套接字)已经创建了,我相信对于大多数人来说也是如此。然而,仍然发送了RST。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接