简体   繁体   English

带SOCK_RAW套接字的TCP握手

[英]TCP handshake with SOCK_RAW socket

Ok, I realize this situation is somewhat unusual, but I need to establish a TCP connection (the 3-way handshake) using only raw sockets (in C, in linux) -- ie I need to construct the IP headers and TCP headers myself. 好的,我意识到这种情况有些不寻常,但是我需要仅使用原始套接字(在C中,在Linux中)建立TCP连接(三向握手),即我需要自己构造IP标头和TCP标头。 I'm writing a server (so I have to first respond to the incoming SYN packet), and for whatever reason I can't seem to get it right. 我正在编写服务器(因此我必须首先响应传入的SYN数据包),无论出于什么原因,我似乎都无法正确处理它。 Yes, I realize that a SOCK_STREAM will handle this for me, but for reasons I don't want to go into that isn't an option. 是的,我意识到SOCK_STREAM会为我处理此问题,但是由于某些原因,我不想进入该选项,这是不可行的。

The tutorials I've found online on using raw sockets all describe how to build a SYN flooder, but this is somewhat easier than actually establishing a TCP connection, since you don't have to construct a response based on the original packet. 我在网上找到的有关使用原始套接字的教程都描述了如何构建SYN泛洪器,但这比实际建立TCP连接要容易一些,因为您不必基于原始数据包构造响应。 I've gotten the SYN flooder examples working, and I can read the incoming SYN packet just fine from the raw socket, but I'm still having trouble creating a valid SYN/ACK response to an incoming SYN from the client. 我已经使用了SYN Flooder示例,并且可以从原始套接字读取传入的SYN数据包,但是我仍然无法为从客户端传入的SYN创建有效的SYN / ACK响应。

So, does anyone know a good tutorial on using raw sockets that goes beyond creating a SYN flooder, or does anyone have some code that could do this (using SOCK_RAW, and not SOCK_STREAM)? 那么,有谁知道关于使用原始套接字的优秀教程,而不仅仅是创建SYN泛洪器,或者没有人有一些代码可以做到这一点(使用SOCK_RAW,而不是SOCK_STREAM)? I would be very grateful. 我会很感激。


MarkR is absolutely right -- the problem is that the kernel is sending reset packets in response to the initial packet because it thinks the port is closed. MarkR绝对正确-问题在于内核正在发送重置数据包以响应初始数据包,因为它认为端口已关闭。 The kernel is beating me to the response and the connection dies. 内核是打我的反应和连接模具。 I was using tcpdump to monitor the connection already -- I should have been more observant and noticed that there were TWO replies one of which was a reset that was screwing things up, as well as the response my program created. 我已经在使用tcpdump来监视连接了-我应该更加观察并注意到,有两个答复,其中之一是重置,这使事情搞砸了,还有我的程序创建的响应。 D'OH! D'OH!

The solution that seems to work best is to use an iptables rule, as suggested by MarkR, to block the outbound packets. 这似乎工作最好的解决办法是使用iptables规则,通过MarkR的建议,以阻止出站数据包。 However, there's an easier way to do it than using the mark option, as suggested. 但是,正如建议的那样,有一种比使用mark选项更简单的方法。 I just match whether the reset TCP flag is set. 我只是匹配是否设置了重置TCP标志。 During the course of a normal connection this is unlikely to be needed, and it doesn't really matter to my application if I block all outbound reset packets from the port being used. 在正常连接过程中,这不太可能需要,并且如果我阻止正在使用的端口上的所有出站重置数据包,则对我的应用程序来说并不重要。 This effectively blocks the kernel's unwanted response, but not my own packets. 这有效地阻止了内核的有害响应,但阻止了我自己的数据包。 If the port my program is listening on is 9999 then the iptables rule looks like this: 如果我的程序正在侦听的端口是9999,则iptables规则如下所示:

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

You want to implement part of a TCP stack in userspace... this is ok, some other apps do this. 您想在用户空间中实现TCP堆栈的一部分...没关系,其他一些应用程序也可以做到这一点。

One problem you will come across is that the kernel will be sending out (generally negative, unhelpful) replies to incoming packets. 您会遇到的一个问题是,内核将对传入的数据包发出(通常是负面的,无助的)回复。 This is going to screw up any communication you attempt to initiate. 这将搞砸您尝试启动的所有通信。

One way to avoid this is to use an IP address and interface that the kernel does not have its own IP stack using- which is fine but you will need to deal with link-layer stuff (specifically, arp) yourself. 避免这种情况的一种方法是使用内核没有自己的IP堆栈的IP地址和接口-很好,但是您需要自己处理链路层的内容(特别是arp)。 That would require a socket lower than IPPROTO_IP, SOCK_RAW - you need a packet socket (I think). 那将需要一个低于IPPROTO_IP,SOCK_RAW的套接字-您需要一个数据包套接字(我认为)。

It may also be possible to block the kernel's responses using an iptables rule- but I rather suspect that the rules will apply to your own packets as well somehow, unless you can manage to get them treated differently (perhaps applying a netfilter "mark" to your own packets?) 也可以使用iptables规则阻止内核的响应-但我怀疑规则也将以某种方式应用于您自己的数据包,除非您可以设法对它们进行不同处理(也许将netfilter“ mark”应用于您自己的数据包?)

Read the man pages 阅读手册页

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

Which explain about various options and ioctls which apply to types of sockets. 其中解释了适用于套接字类型的各种选项和ioctl。

Of course you'll need a tool like Wireshark to inspect what's going on. 当然,您将需要诸如Wireshark之​​类的工具来检查正在发生的事情。 You will need several machines to test this, I recommend using vmware (or similar) to reduce the amount of hardware required. 您将需要多台计算机进行测试,我建议使用vmware(或类似软件)以减少所需的硬件数量。

Sorry I can't recommend a specific tutorial. 抱歉,我不能推荐特定的教程。

Good luck. 祝好运。

I realise that this is an old thread, but here's a tutorial that goes beyond the normal SYN flooders: http://www.enderunix.org/docs/en/rawipspoof/ 我意识到这是一个旧线程,但这是一个超出普通SYN泛洪器的教程: http ://www.enderunix.org/docs/en/rawipspoof/

Hope it might be of help to someone. 希望这可能对某人有所帮助。

I can't help you out on any tutorials. 我无法在任何教程上为您提供帮助。

But I can give you some advice on the tools that you could use to assist in debugging. 但是,我可以为您提供一些建议,以帮助您进行调试。

First off, as bmdhacks has suggested, get yourself a copy of wireshark (or tcpdump - but wireshark is easier to use). 首先,正如bmdhacks所建议的那样,给自己准备一份wireshark的副本(或tcpdump-但wireshark易于使用)。 Capture a good handshake. 握手良好。 Make sure that you save this. 确保您保存此。

Capture one of your handshakes that fails. 捕获失败的握手之一。 Wireshark has quite good packet parsing and error checking, so if there's a straightforward error it will probably tell you. Wireshark具有相当不错的数据包解析和错误检查功能,因此,如果存在直接错误,它可能会告诉您。

Next, get yourself a copy of tcpreplay . 接下来,获取一份tcpreplay副本。 This should also include a tool called "tcprewrite". 它还应包括一个名为“ tcprewrite”的工具。 tcprewrite will allow you to split your previously saved capture files into two - one for each side of the handshake. tcprewrite将允许您将以前保存的捕获文件分为两部分-握手的每一侧。 You can then use tcpreplay to play back one side of the handshake so you have a consistent set of packets to play with. 然后,您可以使用tcpreplay播放握手的一侧,因此您可以使用一组一致的数据包。

Then you use wireshark (again) to check your responses. 然后,您再次使用wireshark检查您的响应。

I don't have a tutorial, but I recently used Wireshark to good effect to debug some raw sockets programming I was doing. 我没有教程,但是最近我使用Wireshark调试了我正在做的一些原始套接字编程,效果很好。 If you capture the packets you're sending, wireshark will do a good job of showing you if they're malformed or not. 如果您捕获了要发送的数据包,wireshark会很好地向您显示它们是否格式错误。 It's useful for comparing to a normal connection too. 与正常连接相比也很有用。

There are structures for IP and TCP headers declared in netinet/ip.h & netinet/tcp.h respectively. netinet / ip.h和netinet / tcp.h中分别声明了IP和TCP标头的结构。 You may want to look at the other headers in this directory for extra macros & stuff that may be of use. 您可能需要查看此目录中的其他标头,以获取可能有用的其他宏和内容。

You send a packet with the SYN flag set and a random sequence number (x). 您发送带有SYN标志设置和一个随机序列号(x)的数据包。 You should receive a SYN+ACK from the other side. 您应该从另一端收到SYN + ACK。 This packet will have an acknowledgement number (y) that indicates the next sequence number the other side is expecting to receive as well as another sequence number (z). 该数据包将具有一个确认号(y),用于指示对方希望接收的下一个序列号以及另一个序列号(z)。 You send back an ACK packet that has sequence number x+1 and ack number z+1 to complete the connection. 您发回具有序列号x + 1和ack号z + 1的ACK数据包以完成连接。

You also need to make sure you calculate appropriate TCP/IP checksums & fill out the remainder of the header for the packets you send. 您还需要确保计算适当的TCP / IP校验和,并为发送的数据包填写标头的其余部分。 Also, don't forget about things like host & network byte order. 另外,不要忘记主机和网络字节顺序之类的东西。

TCP is defined in RFC 793, available here: http://www.faqs.org/rfcs/rfc793.html TCP在RFC 793中定义,可在以下位置找到http : //www.faqs.org/rfcs/rfc793.html

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

Depending on what you're trying to do it may be easier to get existing software to handle the TCP handshaking for you. 根据您要尝试执行的操作,使现有软件为您处理TCP握手可能更容易。

One open source IP stack is lwIP ( http://savannah.nongnu.org/projects/lwip/ ) which provides a full tcp/ip stack. 一个开源IP堆栈是lwIP( http://savannah.nongnu.org/projects/lwip/ ),它提供了完整的tcp / ip堆栈。 It is very possible to get it running in user mode using either SOCK_RAW or pcap. 使用SOCK_RAW或pcap使其很可能在用户模式下运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM