初试Python raw socket编程

August 16th, 2014 Leave a comment Go to comments

前两天在hacker news看到有人尝试用python构建一个简单的tcp stack,里面为了绕过内核的干扰而采用了ARP spoofing这种奇葩的方式。然后评论里有人说是因为作者没有使用raw socket的缘故。

Raw socket允许用户自定义tcp/ip数据包的header,赋予用户创建自定义数据包的能力,不使用底层操作系统生成的header。一般程序很少用到此项技术,主要是一些网络安全相关的软件,比如firewall、sniffer、port scanner会使用。Linux下有socket api提供raw socket的支持,windows下就比较悲剧了。抱着玩玩的心态,尝试了一下用python实现一个raw socket通信,顺便温习下tcp/ip。感谢Silver Moon的一篇精彩易懂的文章,是本文的主要参考资料。

首先是一点基础概念。
IP header的结构由RFC 791定义,如图(第一行每个数字代表一个bit位):

然后TCP header的结构是由RFC 793定义的:

而一个tcp/ip数据包是由ip header + tcp header + data(optional)组成的。

下面开工!
Python下创建一个raw socket:

注意这里使用了SOCK_RAW,而不是SOCK_STREAM或者SOCK_DGRAM。前者允许你操作header和data部分,后面俩只能访问到data部分。

raw socket通道构建好了,下面就开始构建需要发送的packet。
首先是ip header:

然后接着是tcp header:

至此,TCP/IP headers的构建已经基本完成。接着编写tcp checksum函数。

首先是算法。tcp checksum算法(或者icmp、udp、ip的checksum算法)是用one’s complement(不知道中文叫啥)算法,以每2字节为单位,将数据加起来,最后的结果(还是2字节)再来一次按位取反,就是最终的checksum值,填到checksum区域即可。

然后是check的范围。简单地说,范围包括pseudo ip header + tcp header + tcp data。注意checksum区域本身也在范围内,所以发送方一开始要把那里置为零以方便计算。

pseudo ip header是利用ip header里的一些值来生成的,结构如下:
tcppseudoheader

下面这张图就是整个需要进行checksum的内容:
tcppseudocalc

接收方收到数据包后的校验操作,用的是同样算法,结果为0则说明数据包在传输过程中没有损坏(想想为什么?)。

下面就是完整代码,记得在Linux下以root身份运行哦!打开wireshark抓包看看吧。
这里只实现了一个最简单的发包动作,连tcp三步握手都谈不上,监听、绑定操作也一概没有 = =
PS:本想改用Python3写,但是技术太水搞不定它的bytes, bytearray, string,只好用Python2了。

看效果的时候注意,Wireshark默认不检查TCP checksum的正确性,需要在其TCP Protocol的设置画面里把”Validate the TCP checksum if possible”勾上。

下面是我自己运行的结果,首先是IP header(点开看大图):
python_raw_socket_ip_header
可以看到程序中设定的各种参数,而且内核自动把ip header的total length和checksum填好了。

然后是TCP header:
python_raw_socket_tcp_header
可以看到正如程序中flag设定的那样,这是一个tcp握手包。各项参数也正常,程序计算出来的tcp checksum(0xAF21)也是对的。payload data的长度也正常(”wordpress.youran.me” = 19 bytes)

至此,一个最简单的raw socket通信已经完成。
再仔细观察Wireshark的抓包结果,会发现当我将SYN包发至微软网站后,微软正常回复了一个SYN+ACK的握手包,紧接着内核立刻向微软发送了一个RST包,直接中断了本次握手。本来以为用raw socket不会出现这个现象,看来光这样还不行,还得bind()+listen()本地端口才能通过内核的检查。

本文为悠然居(https://wordpress.youran.me/)的原创文章,转载请注明出处!

声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: 初试Python raw socket编程
  1. youran | #1
    August 17th, 2014 at 00:29 |

    程序:SYN
    微软:SYNACK
    内核:纳尼?谁让你发出去的?RESET!
    程序:…………

    Google Chrome 36.0.1985.143 Google Chrome 36.0.1985.143 Windows 7 x64 Edition Windows 7 x64 Edition
  1. No trackbacks yet.