linux raw限制端口访出,使用Linux raw socket时需要注意的一些问题
本文的copyleft歸gfree.wind@gmail.com所有,使用GPL發(fā)布,可以自由拷貝,轉(zhuǎn)載。但轉(zhuǎn)載請(qǐng)保持文檔的完整性,注明原作者及原鏈接,嚴(yán)禁用于任何商業(yè)用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
一般情況下,我們使用raw socket都是用于發(fā)送icmp包或者自己定義的包。最近我想用raw socket
自己去創(chuàng)建TCP的包,并完成3次握手。
在這個(gè)過程中,發(fā)現(xiàn)了幾個(gè)問題:
1. 發(fā)現(xiàn)收不到對(duì)端返回的ACK,但是通過tcpdump卻可以看到。這個(gè)通過修改創(chuàng)建socket的API參數(shù)得以糾正。
原來創(chuàng)建socket使用如下參數(shù)s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)。因?yàn)閘inux的raw socket不會(huì)把
不會(huì)把UDP和TCP的分組傳遞給任何原始套接口。——見《UNIX網(wǎng)絡(luò)編程》28.3.
所以為了讀到ACK包,我們創(chuàng)建的raw socket需要建立在數(shù)據(jù)鏈路層上。
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))
這樣該socket就可以讀取到所有的數(shù)據(jù)包。當(dāng)然這樣的數(shù)據(jù)包無疑是非常龐大的,那么我們可以
使用bind和connect來過濾數(shù)據(jù)包。bind可以指定本地的IP和端口,connect可以指定對(duì)端的IP和端口。
2. 在修改完創(chuàng)建socket的API,我發(fā)現(xiàn)還有一個(gè)問題,到現(xiàn)在依然沒有找到合適的解決方法。
通過鏈路層的raw socket,我們可以收到對(duì)端的ACK。但是因?yàn)閘inux內(nèi)核也會(huì)處理TCP的握手過程,
所以,當(dāng)它收到ACK的時(shí)候,會(huì)認(rèn)為這是一個(gè)非法包,會(huì)直接發(fā)送一個(gè)RST給對(duì)端。這樣我們拿到了這個(gè)ACK,
也沒有實(shí)際的用處了——因?yàn)檫@個(gè)連接已經(jīng)被RST了。
我想,內(nèi)核之所以會(huì)直接發(fā)送RST,也許是因?yàn)槲覀儎?chuàng)建的是raw socket,但是發(fā)送的確是TCP包,
當(dāng)對(duì)端返回ACK時(shí),內(nèi)核根本不認(rèn)為我們已經(jīng)打開了這個(gè)TCP端口,所以會(huì)直接RST掉這個(gè)連接。
那么問題就在于,我們?nèi)绾胃嬖V內(nèi)核,我們打開了TCP的這個(gè)端口。
我想過一個(gè)方法,除了一個(gè)raw socket,再創(chuàng)建一個(gè)真正的TCP socket。但是細(xì)想起來,這條路應(yīng)該行不通。
在網(wǎng)上搜了半天,總算找到一個(gè)比較詳細(xì)的解釋了。原因給我猜想的相差不遠(yuǎn),當(dāng)我們使用raw
socket來發(fā)送sync包時(shí),內(nèi)核的TCP協(xié)議棧并不知道你發(fā)送了sync包,所以當(dāng)對(duì)端返回SYNC/ACK時(shí),內(nèi)核首先要處理這個(gè)包,發(fā)現(xiàn)它是一
個(gè)SYNC/ACK,然而協(xié)議棧卻不知道前面的sync,所以就認(rèn)為這個(gè)包是非法的,于是就會(huì)發(fā)送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.
該解釋來自于,
感謝Mr Andreas Masur 和Mr Mathew Joy. Thanks Mr Andreas Masur and Mr Mathew Joy.
作者:gfree.wind@gmail.com
總結(jié)
以上是生活随笔為你收集整理的linux raw限制端口访出,使用Linux raw socket时需要注意的一些问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用java判断一个年份是否为闰年_判断闰
- 下一篇: linux的HAL库函数,STM32 H