原始套接字
1. 前言
原始套接字是一种较为底层的套接字,使用它可以直接发送或接收IP层数据包,因此具有较大的灵活性。通常被用于抓包、测试等领域。
2. IP数据包协议格式
现在最常见的是IPv4协议,格式定义如下:

2.1. IP字段解释
版本: ipv4中固定为4
首部长度: ip头的长度,ipv4中包头长度固定为20,该字段的值为5(20/4)
服务类型: 一般设为0
总长度: IP数据包的总长度(包含包头)
标识: 用来标识IP数据包,当IP包分片时,所有分片需要使用相同的标识
标志: 共3位
- 第1位为保留位
- 第2位为
DF(Don't Fragment)位,为1表示不允许分片 - 第3位为
MF(More Fragment)位,为1表示后面还有分片,为0表示是最后一个分片
片偏移: 当IP包分片的时候,当前分片在原IP包中的偏移值。片偏移以8字节为偏移单元
生存时间: TTL(Time To Live) 每经过一个路由器,TTL值减一,如果该值为0,则丢弃该数据包
协议: 传输层使用的协议
常见协议定义如下:
| 协议号 | 协议类型 |
|---|---|
| 1 | ICMP |
| 2 | IGMP |
| 6 | TCP |
| 17 | UDP |
| 47 | GRE |
| 136 | UDPLITE |
首部校验和: 只对IP头计算校验和,以减少计算量
源IP地址: 发送IP数据包的主机地址。请求包经过NAT设备时,该值会发生变化
目的IP地址: IP数据包要发送的目的地址。返回包经过NAT设备时,该值会发生变化
选项: 目前IP数据包都没有该字段,因此IP数据包固定长度为20
3. 使用原始套接字
3.1. 创建socket对象
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, protocol)
与创建TCP或UDP socket对象不同,这里传入的type是socket.SOCK_RAW,表示是原始套接字。
protocol字段传入的值与IP协议中的协议字段的值是一致的。
3.2. 绑定地址
s.bind(('127.0.0.1', 0))
绑定的ip地址必须是某一网卡的ip地址,这样才能抓取该网卡收发的数据包。
3.3. 接收数据包
buff, addr = s.recvfrom(4096)
3.4. 发送数据包
s.sendto(buff, (ip, port))
可以看到,原始套接字与UDP通信还是挺像的。
4. 使用原始套接字实现ping程序
ping是一个用来检测网络连通性的常用工具,使用ICMP协议进行通信。
4.1. ICMP协议格式

ICMP字段解释
ICMP包头共8个字节,前4个字节定义如下:
类型: ICMP数据包类型,常见类型定义如下:
| TYPE | Description | 描述 |
|---|---|---|
| 0 | Echo Reply | 回显应答(Ping应答) |
| 3 | Destination Unreachable | 目标不可达 |
| 4 | Source Quench | 源端被关闭(基本流控制) |
| 5 | Redirect | 重定向 |
| 8 | Echo Request | 回显请求(Ping请求) |
ping主要就是用的8和0这两个类型。
代码: 部分类型还会有子类型,使用代码表示,如:类型3、类型5等
校验和: ICMP包头和包体一起计算校验和,算法与IP协议相同
后面4个字节的内容与具体类型有关,在ping请求和应答中,这4个字节是由2字节的ID和2字节的序号组成。并且请求包和应答包思维这两个字段必须一致。
数据包示例
下面是一个ping请求包的示例(每行4个字节)
+---+---+-------+---------------+------
| 4 | 5 | 0 | 60 | ^
+---+---+-----------------------+ |
| 0x6f18 | 0 | |
+-------+-----------------------+ | IP协议头
| 64 | 1 | 0x09c0 | |
+-------+-------+---------------+ |
| 10.0.0.101 | |
+-------------------------------+ |
| 10.0.0.102 | v
+-------+-------+----------------------
| 8 | 0 | 0x2070 | ^
+-------+-----------------------+ | ICMP协议头
| 1 | 12345 | v
+---------------+----------------------
| abcd | ^
+-------------------------------+ |
| efgh | |
+-------------------------------+ |
| ijkl | |
+-------------------------------+ | ICMP数据
| mnop | |
+-------------------------------+ |
| qrst | |
+-------------------------------+ |
| uvwx | |
+-------------------------------+ |
| yzAB | |
+-------------------------------+ |
| CDEF | v
+-------------------------------+------
该IP包共有60个字节,其中包含20个字节的IP头,8个字节的ICMP头,以及32个字节的ICMP数据。