原始套接字
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数据。