使用 python 原始套接字的 TCP 握手

TCP handshake using python RAW sockets

我正在使用 python RAW 套接字实现 TCP 握手。然而,Linux 内核非常烦人,因为它试图处理该协议的某些方面。

比如我发送一个SYN包,服务器回复了一个SYN,ACK包;内核会自动响应一个 RST 数据包来重置连接。我克服了这个问题,我使用以下 iptable 规则丢弃了所有此类重置数据包:

-A OUTPUT -p tcp -m tcp --sport 999 --tcp-flags RST RST -j DROP

现在我要接收服务器发送的SYN、ACK包并打印出来。但是当我执行以下操作时我什么也没收到:

a = self.s.recvfrom(4096)

我怀疑内核在我可以使用我的套接字接收它之前丢弃了 SYN、ACK。有谁知道合理的解决方法?

虽然我希望有人想出一个更方便的解决方案,但一种方法是使用 iptables 将传入的 TCP Syn 数据包传递给 nfqueue. Nfqueue has existing python bindings,因此使用它不应该是一个问题。

想法是在所有传入的 TCP Syn 到达内核的 TCP 实现之前捕获它们。然后将这些数据包传递到您的用户应用程序可以监控的 nfqueue。对于您的应用将从 nfqueue 获取的每个数据包,它必须决定 (return a verdict) 是自行处理数据包(即,就 OS 而言,丢弃数据包)还是传递它以及常规的 TCP 实现。

我知道这种方法行之有效,但它很麻烦。

您可以使用 libpcap,在 Python 中似乎是这个模块:http://pylibpcap.sourceforge.net/ or this one: https://pypi.python.org/pypi/pypcap

使用 pcap,您可以注册以接收来自内核的消息。通过从您的应用程序提供正确的过滤器,您可以从内核接收 TCP 段。我在 C 中使用过 libpcap,我想您可以以相同的方式使用指示的模块。对我来说,这是最好的解决方案,因为您可以以非常标准的方式从应用程序中处理它。

为了避免内核以 RST 响应,你的 iptables 解决方案对我来说看起来是最好的。

既然你自己用原始数据包做这一切,为什么不创建你自己的 MAC 地址和 IP 地址呢?您需要将适配器置于混杂模式以接收数据包,但如果您这样做,内核不应该向您的传入数据包发送任何响应,因为它们似乎是寻址到 "some other system"。这使得从其他人那里过滤您关心的数据包变得微不足道。

您还需要适当地响应 ARP,以便其他系统找到您的 MAC 地址。如果您需要 DHCP 来获取 IP 地址,您也需要处理这些交互。