Raw Socket注意

一般情况下,我们使用raw socket都是用于发送icmp包或者自己定义的包。最近我想用raw socket



1. 发现收不到对端返回的ACK,但是通过tcpdump却可以看到。这个通过修改创建socket的API参数得以纠正。

原来创建socket使用如下参数s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)。因为linux的raw socket不会把


所以为了读到ACK包,我们创建的raw socket需要建立在数据链路层上。

s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))



2. 在修改完创建socket的API,我发现还有一个问题,到现在依然没有找到合适的解决方法。

通过链路层的raw socket,我们可以收到对端的ACK。但是因为linux内核也会处理TCP的握手过程,



我想,内核之所以会直接发送RST,也许是因为我们创建的是raw socket,但是发送的确是TCP包,



我想过一个方法,除了一个raw socket,再创建一个真正的TCP socket。但是细想起来,这条路应该行不通。

在网上搜了半天,总算找到一个比较详细的解释了。原因给我猜想的相差不远,当我们使用raw socket来发送sync包时,内核的TCP协议栈并不知道你发送了sync包,所以当对端返回SYNC/ACK时,内核首先要处理这个包,发现它是一个SYNC/ACK,然而协议栈却不知道前面的sync,所以就认为这个包是非法的,于是就会发送RST来中止连接。


This is one of the most frequently asked question by someone who is experimenting with raw sockets and TCP/IP. It is known that the 'IP_HDRINCL' socket option allows you to include the IP header along with the data. Since TCP encapsulates the IP header, we can also build a TCP packet and send it over a network. But the problem is, a TCP connection can never be established this way. The scenario is as follows:
A TCP connection is always made by a three-way handshake. So, initially you send a 'SYN' packet to the remote machine. If it is actively listening on the port, you get a 'SYN/ACK' packet. So far so good. But before you can respond, your machine sends an 'ACK/RST' packet and connection attempt is ended. For the connection to be complete, instead of the 'RST' packet, your machine should be sending an 'ACK' to the remote machine.
The difference lies where the connection is exactly made. Although the programs are communicating after the connection is complete, the TCP connection is never between two programs but rather between the TCP stacks of the two machines. Here 'stack' means a layer of programs that communicates between each other. TCP stack stands for the protocol driver or the actual network transport protocol. Now lets look at exactly what happens when you send a 'SYN' packet...
Since you are using raw sockets ('SOCK_RAW') and not TCP/Stream sockets ('SOCK_STREAM') the TCP stack has no information about what you are doing at program level. And since the 'IP_HDRINCL' allows you to build any type of IP packet and send it along with the data, you can build a 'SYN' packet and send it to the TCP server program which is actively listening. But the point is that the 'SYN' packet is being sent from your program and not the stack. In other words the TCP stack of your machine has no idea how of sending the 'SYN' packet.
On the other side the 'SYN' packet is received by the stack at the remote machine and not exactly by the program. As with the case of the arrival of any 'SYN' packet, the stack at the remote machine responds with a 'SYN/ACK' packet. This packet is now received by the TCP stack of your machine. In other words, the incoming TCP packet ('SYN/ACK') will be processed by the stack. Since it has no information of the previous sent 'SYN' packet, it responds with a 'RST' packet, as in the case of any improper or unacceptable packet for a connection.
So the difference between sending and receiving a TCP packet using raw sockets is, the former is not processed while the latter is processed by the TCP stack of your machine.
posted @ 2010-10-22 22:26  规格严格-功夫到家  阅读(...)  评论(...编辑  收藏