title | date |
---|---|
Let's code a TCP/IP stack, 2 - IPv4 & ICMPv4 |
2018-12-28T23:53:00.000Z |
原文地址:http://www.saminiir.com/lets-code-tcp-ip-stack-2-ipv4-icmpv4/
ICMP: 互联网控制消息协议,它用于 TCP/IP 网络中发送控制消息,提供可能出现在通讯过程中的各种问题反馈,ping 就是基于 ICMP 的
IPv4 是一种无连接协议,它会尽最大努力交付数据包,就是说它不保证发送包的顺序,也不保证包被送达目的地。
如果需要保证通信的可靠性,需要在其上层做相应的处理,如 TCP 协议。
报头结构如下:
struct iphdr {
// version 字段占4bit,表示协议的版本,通信双方使用的版本必须一致。对于IPv4,字段的值是4
uint8_t version : 4;
// internet header length => ihl,表示报头有多少个 32 位字,ihl 最大值为 1111 -> 15,因此最多能放 15 * 32 bit = 15 * 4 byte
uint8_t ihl : 4;
// type of service
uint8_t tos;
// 报文总长,这个字段占 16 bit,因此其最大值为 65535 bytes,大一些的报文会被分割成较小的报文,以满足不同通信接口的最大传输单元(MTU)
uint16_t len;
// 标识符,用来唯一标识一个报文的所有分片,该字段的值是在发送方填写的一个自增的值,接收方可以使用这个值对分片重新排列。
uint16_t id;
// 用于控制和识别分片,发送方指定是否可以对报文进行分片,具体的分片方式等
uint16_t flags : 3;
// 分片偏移,表明当前分片相对于原始报文开头的偏移量
uint16_t frag_offset : 13;
// 存活时间,这个是为了防止报文陷入路由环路而导致其一直存在。
uint8_t ttl;
// 协议,定义了该报文数据区使用的协议
uint8_t proto;
// 首部检验和,用来做完整性验证
uint16_t csum;
// 源地址
uint32_t saddr;
// 目标地址
uint32_t daddr;
} __attribute__((packed));
中文全称:互联网控制消息协议 英语:Internet Control Message Protocol,缩写:ICMP
IP 协议缺乏可靠性,需要通过某种方式告知通信方可能的错误情况。ICMP 就是用来诊断网络问题的,比如当网关不可达时,ICMP 会告知消息的发起者 “Gateway Unreachable”。
struct icmp_v4 {
// ICMP 类型,标识错误报文
uint8_t type;
// 进一步划分 ICMP 类型,用来查找错误原因
uint8_t code;
// 校验码,用于检查数据的错误
uint16_t csum;
uint8_t data[];
} __attribute__((packed));
实际的 ICMP 报文中,会有查询信息和错误信息。我们先看下请求/回复消息:
struct icmp_v4_echo {
// id 由发送方指定,决定由哪个进程进行应答
uint16_t id;
// seq 是一个从 0 开始的序号,每当有一个新的 echo 请求,就 +1。应答的时候需要把这个信息带回来,已确定这条消息是否在传输过程中消失或者重新排序
uint16_t seq;
// data 可选字段,里面经常会包含 echo 的时间戳,以方便估算 hosts 之间的往返时间
uint8_t data[];
}__attribute__((packed));
举个 ICMPv4 中目的地不可达的错误信息的例子:
struct icmp_v4_dst_unreachable {
// 第一个 8 位字节未使用
uint8_t unused;
// 原始数据报的长度
uint8_t len;
uint16_t var;
// 原始数据包
uint8_t data[];
}__attribute__((packed));
ping 一下 shimo.im 看看结果:
PING shimo.im (47.95.42.129): 56 data bytes
64 bytes from 47.95.42.129: icmp_seq=0 ttl=93 time=5.368 ms
64 bytes from 47.95.42.129: icmp_seq=1 ttl=93 time=29.821 ms
64 bytes from 47.95.42.129: icmp_seq=2 ttl=93 time=6.258 ms
64 bytes from 47.95.42.129: icmp_seq=3 ttl=93 time=6.776 ms
64 bytes from 47.95.42.129: icmp_seq=4 ttl=93 time=22.077 ms
64 bytes from 47.95.42.129: icmp_seq=5 ttl=93 time=7.118 ms
--- shimo.im ping statistics ---
6 packets transmitted, 6 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 5.368/12.903/29.821/9.507 ms