如果你练习过前面的接收 IP 数据报的程序,相信写出这个不会很难。
1. 程序路径
本文使用的程序托管在 gitos 上:http://git.oschina.net/ivan_allen/unp
如果你已经 clone 过这个代码了,请使用 git pull
更新一下。本节程序所使用的程序路径是 unp/program/icmp/basic
.
2. 程序编写思路
因为这一次我们只想要 ICMP 协议,因此可以只接收 IP 数据报中协议字段为 1 的 IP 数据报。具体就是创建下面这样的原始套接字:
// IPPROTO_ICMP 的宏定义值就是 1 sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
通过编写获取 IP 数据报的实验我们已经掌握了拿到了 IP 数据报的方法,接下来,就是从 IP 数据报中拿出它的数据部分。
// 假设我们拿到的 ip 数据报保存在指针 struct ip *ip 中,长度为 len. // 计算 ip 首部长度 iphlen = ip->ip_hl << 2; // 计算 ip 数据报中数据起始地址,ip 首部地址 + ip 首部长度: char *buf = (char*)ip + iphlen; // buf 的地址就是 ICMP 报文的首地址,强制转换到 struct icmp* 类型中 struct icmp *icmp = (struct icmp*)buf; // 这样一来我们就拿到了 icmp 报文了,后面该打印的就打印去吧。
3. 实验
为了能产生 ICMP 报文,我在 flower 主机上使用 ping 命令发送了两个报文。
图1 运行结果
ping 命令发送的每一个 ICMP 报文大小都是 64 字节,这 64 字节表示 ICMP 首部长度 + ICMP 数据部分的长度。从图 1 中可以看到,数据部分是 60 字节(每行 16 字节),加上 type+code+checksum 一共 4 字节,刚好 64 字节。
实际上,ping 命令发送的报文是请求回显 ICMP 报文,细心的同学可以观察到图 1 中的 type 字段的值是 8,code 字段的值是 0,根据 ICMP 协议文档描述,这是一个请求回显报文。
下一篇文章会详细讨论请求回显报文是干嘛的。
4. 总结
- 掌握解析 ICMP 报文的方法