20

好的,我意识到这种情况有点不寻常,但我需要仅使用原始套接字(在 C 中,在 linux 中)建立 TCP 连接(3 次握手)——即我需要自己构建 IP 标头和 TCP 标头. 我正在编写一个服务器(所以我必须首先响应传入的 SYN 数据包),无论出于何种原因,我似乎都无法正确处理。是的,我意识到 SOCK_STREAM 会为我处理这个问题,但出于我不想进入的原因,这不是一个选择。

我在网上找到的关于使用原始套接字的教程都描述了如何构建 SYN 泛洪器,但这比实际建立 TCP 连接要容易一些,因为您不必基于原始数据包构建响应。我已经让 SYN 泛洪器示例正常工作,我可以从原始套接字读取传入的 SYN 数据包,但我仍然无法为来自客户端的传入 SYN 创建有效的 SYN/ACK 响应。

那么,有没有人知道一个关于使用原始套接字的好教程,它超越了创建 SYN 泛洪器,或者有没有人有一些可以做到这一点的代码(使用 SOCK_RAW,而不是 SOCK_STREAM)?我会很感激。


MarkR 是绝对正确的——问题在于内核正在发送重置数据包以响应初始数据包,因为它认为端口已关闭。内核正在击败我的响应并且连接消失了。我已经在使用 tcpdump 来监视连接了——我应该更加细心,并注意到有两个回复,其中一个是搞砸了的重置,以及我的程序创建的响应。哦!

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

iptables -t filter -I OUTPUT -p tcp --sport 9999 --tcp-flags RST RST -j DROP
4

7 回答 7

12

您想在用户空间中实现 TCP 堆栈的一部分……这没关系,其他一些应用程序会这样做。

您将遇到的一个问题是内核将对传入的数据包发送(通常是否定的、无用的)回复。这将破坏您尝试发起的任何通信。

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

也可以使用 iptables 规则来阻止内核的响应——但我怀疑这些规则也会以某种方式应用于你自己的数据包,除非你能设法让它们得到不同的处理(也许应用一个 netfilter“标记”到你自己的数据包?)

阅读手册页

套接字(7) ip(7) 数据包(7)

其中解释了适用于套接字类型的各种选项和 ioctl。

当然,您需要像 Wireshark 这样的工具来检查正在发生的事情。您将需要几台机器来测试它,我建议使用 vmware(或类似的)来减少所需的硬件数量。

对不起,我不能推荐一个具体的教程。

祝你好运。

于 2008-09-21T06:57:38.577 回答
4

我意识到这是一个旧线程,但这里有一个超出普通 SYN 泛洪器的教程:http ://www.enderunix.org/docs/en/rawipspoof/

希望它可能对某人有所帮助。

于 2012-07-30T11:30:25.827 回答
2

我无法在任何教程上为您提供帮助。

但我可以就可以用来协助调试的工具给你一些建议。

首先,正如bmdhacks所建议的,给自己准备一份wireshark(或 tcpdump - 但 wireshark 更容易使用)。捕捉良好的握手。确保保存此内容。

捕获您失败的握手之一。Wireshark 有很好的数据包解析和错误检查,所以如果有一个简单的错误,它可能会告诉你。

接下来,为自己获取一份tcpreplay的副本。这还应该包括一个名为“tcprewrite”的工具。tcprewrite 将允许您将之前保存的捕获文件分成两个 - 握手的每一侧一个。然后,您可以使用 tcpreplay 回放握手的一侧,这样您就可以使用一组一致的数据包。

然后,您(再次)使用 wireshark 来检查您的回复。

于 2008-09-21T06:44:13.010 回答
1

我没有教程,但我最近使用Wireshark来调试我正在做的一些原始套接字编程效果很好。如果您捕获了您发送的数据包,wireshark 会很好地向您显示它们是否格式错误。这对于与普通连接进行比较也很有用。

于 2008-09-21T05:51:49.500 回答
0

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

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

您还需要确保计算适当的 TCP/IP 校验和并为您发送的数据包填写标头的其余部分。另外,不要忘记主机和网络字节顺序之类的东西。

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

于 2008-09-21T07:22:20.640 回答
0

根据您尝试执行的操作,让现有软件为您处理 TCP 握手可能会更容易。

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

于 2009-06-06T14:53:24.783 回答
0

如果您使用的是原始套接字,如果您使用与实际不同的源 mac 地址发送,linux 将忽略响应数据包而不发送 rst。

于 2012-11-02T16:07:51.263 回答