使用SOCK_RAW套接字进行TCP握手

20

好的,我知道这种情况有些不寻常,但是我需要使用原始套接字(在Linux中使用C语言)建立TCP连接(3次握手)——也就是说,我需要自己构造IP头和TCP头。我正在编写一个服务器(因此必须首先响应传入的SYN数据包),但出于某些原因,我似乎无法做到正确地处理它。是的,我知道SOCK_STREAM会自动处理这个问题,但由于某些原因我不想去深究,所以这不是一个选择。

我在网上找到的所有关于使用原始套接字的教程都只介绍如何构建SYN洪泛器,但这比实际建立TCP连接要容易一些,因为您不必根据原始数据包构建响应。我已经成功地运行了SYN洪泛器示例,并且可以通过原始套接字很好地读取传入的SYN数据包,但是我仍然无法创建有效的SYN/ACK响应以响应客户端发送的SYN。

那么,有没有人知道有关使用原始套接字的好教程,超越了创建SYN洪泛器的范畴,或者有没有一些代码可以使用SOCK_RAW而不是SOCK_STREAM来实现此目的?如果有的话,我将非常感激。


MarkR是完全正确的——问题在于内核在响应初始数据包时发送了复位数据包,因为它认为端口关闭了。内核比我更快地响应了请求,并且连接中断了。我已经使用tcpdump监视了连接——我应该更加细心地注意到有两个回复,其中之一是复位,这破坏了事情进展以及程序创建的响应。我太傻了!

最好的解决方案似乎是使用像MarkR建议的iptables规则来阻止出站数据包。然而,有一种比使用mark选项更简单的方法。我只匹配是否设置了复位TCP标志。在正常连接的过程中,这不太可能需要,而且如果我阻止正在使用的端口的所有出站复位数据包,对我的应用程序也没有什么影响。这有效地阻止了内核不需要的响应,但不影响我的数据包。如果我的程序侦听的端口是9999,则iptables规则如下:

iptables -t filter -I OUTPUT -p tcp --sport 9999 --tcp-flags RST RST -j DROP
7个回答

12

您想在用户空间中实现TCP协议栈的一部分...这是可以的,其他一些应用程序也这样做。

您会遇到一个问题,即内核将发送出(通常是负面且不实用的)答复来响应传入数据包。这将破坏您尝试启动的任何通信。

避免这种情况的一种方法是使用内核没有自己的IP堆栈的IP地址和接口-这很好,但您需要自己处理链路层内容(具体地,arp)。这将需要使用低于IPPROTO_IP、SOCK_RAW的套接字-您需要一个数据包套接字(我想是这样的)。

还可能有可能使用iptables规则阻止内核的响应-但我怀疑规则也会以某种方式适用于您自己的数据包,除非您设法使它们被不同对待(也许是对自己的数据包应用netfilter“标记”?)

阅读man页面吧

socket(7) ip(7) packet(7)

这些页面介绍了适用于各种类型套接字的各种选项和ioctls。

当然您需要一个像Wireshark这样的工具来检查发生了什么。您需要多台机器来测试,我建议使用vmware(或类似产品)来减少所需硬件的数量。

很抱歉我无法推荐具体的教程。

祝你好运。


4

2
我无法为任何教程提供帮助。
但我可以给你一些关于调试工具的建议。
首先,像 bmdhacks 建议的那样,获取一个 wireshark 的副本(或者 tcpdump - 但 wireshark 更容易使用)。捕获一个好的握手。确保保存它。
捕获一个失败的握手。Wireshark 具有相当不错的数据包解析和错误检查功能,因此如果有明显的错误,它可能会告诉你。
接下来,获取一个 tcpreplay 的副本。这应该也包括一个名为 "tcprewrite" 的工具。tcprewrite 可以让你将之前保存的捕获文件分成两个 - 每个握手的一侧。然后,您可以使用 tcpreplay 播放握手的一侧,以便您有一组一致的数据包进行操作。
然后,再次使用 Wireshark 来检查您的响应。

1

我没有教程,不过最近我使用 Wireshark 来调试一些原始套接字编程,效果很好。如果你捕获发送的数据包,Wireshark 能够很好地显示它们是否格式错误。对于与正常连接进行比较也很有用。


0

如果您正在使用原始套接字,如果您发送的源MAC地址与实际地址不同,Linux将忽略响应数据包并不会发送RST。


我知道这是一个四年前的问题,但是你的建议看起来非常有趣,所以我决定向你询问澄清。问题是:当路由器将响应数据包路由到某个带有错误设备MAC地址的机器时,是否会出现任何问题?这个数据包会被现代防火墙或杀毒软件过滤吗? - vantrung -cuncon
如果交换机配置了端口安全,伪造的MAC地址可能会被过滤。在MAC层可能会有ACL,但通常没有什么可以阻止您伪造MAC地址。您只需要确保您的网络卡将接受此伪造的MAC地址的答案(通过将MAC地址添加到接受数据包表中或将其放入混杂模式)。如果未经授权就这样做,那么这是一个坏主意。 - eckes

0

根据您想要做什么,使用现有软件来处理TCP握手可能会更容易。

一个开源的IP协议栈是lwIP (http://savannah.nongnu.org/projects/lwip/),它提供了完整的TCP/IP协议栈。使用SOCK_RAW或pcap,非常可能在用户模式下运行它。


0

在netinet/ip.h和netinet/tcp.h中声明了IP和TCP头的结构。您可能希望查看此目录中的其他标头以获取额外的宏和有用的信息。

您发送设置了SYN标志和随机序列号x 的数据包。您应该从对面收到一个SYN+ACK。这个数据包将具有确认号y,指示另一侧期望接收的下一个序列号,以及另一个序列号z。您发送一个ACK数据包,其序列号为x+1,确认号为z+1,以完成连接。

您还需要确保计算适当的TCP/IP校验和,并填写发送的数据包的剩余头部。此外,不要忘记主机和网络字节顺序等问题。

TCP在RFC 793中定义,可在此处获得:http://www.faqs.org/rfcs/rfc793.html


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