linux raw限制端口访出,使用Linux raw socket时需要注意的一些问题

本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。

作者:gfree.wind@gmail.com

博客:linuxfocus.blog.chinaunix.net

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

自己去创建TCP的包,并完成3次握手。

在这个过程中,发现了几个问题:

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

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

不会把UDP和TCP的分组传递给任何原始套接口。——见《UNIX网络编程》28.3.

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

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

这样该socket就可以读取到所有的数据包。当然这样的数据包无疑是非常庞大的,那么我们可以

使用bind和connect来过滤数据包。bind可以指定本地的IP和端口,connect可以指定对端的IP和端口。

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

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

所以,当它收到ACK的时候,会认为这是一个非法包,会直接发送一个RST给对端。这样我们拿到了这个ACK,

也没有实际的用处了——因为这个连接已经被RST了。

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

当对端返回ACK时,内核根本不认为我们已经打开了这个TCP端口,所以会直接RST掉这个连接。

那么问题就在于,我们如何告诉内核,我们打开了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.

该解释来自于,

感谢Mr Andreas Masur 和Mr Mathew Joy. Thanks Mr Andreas Masur and Mr Mathew Joy.

作者:gfree.wind@gmail.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值