赞
踩
目录
ICMP协议是网络层中一个非常重要的协议,其全称为Internet Control Message Protocol(因特网控制报文协议),ICMP协议弥补了IP的缺限,它使用IP协议进行信息传递,向数据包中的源端节点提供发生在网络层的错误信息反馈。
在实现中,路由器会使用该协议来报告问题,而主机则会使用该机制来测试目的站是否可达。该报文的最终目的地不是一个应用程序或者目的设备上的用户,而是目的设备上的网际协议软件,一般icmp报文的接收是linux内核里的icmp接收模块来处理的,而icmp请求报文的发送即可以是内核里相关子系统也可以是应用层的程序发送(比如ping应用)。
各种ICMP报文的前32bits都是三个长度固定的字段,为8bit的type字段、8bit的code字段、16bit的校验和字段(包括icmp数据字段的校验和),而对于不同类型的icmp报文,其余下字段的含义则是不同的。
icmp类型目前有40个,下面几个是比较常用的,也是目前 linux 支持的类型。
- #define ICMP_ECHOREPLY 0 /* Echo Reply,回显应答(ECHO-REPLY) */
- #define ICMP_DEST_UNREACH 3 /* Destination Unreachable,不可到达 */
- #define ICMP_SOURCE_QUENCH 4 /* Source Quench,源站抑制 */
- #define ICMP_REDIRECT 5 /* Redirect (change route),重定向 */
- #define ICMP_ECHO 8 /* Echo Request,回显请求(ECHO-REQUEST) */
- #define ICMP_TIME_EXCEEDED 11 /* Time Exceeded,数据报超时 */
- #define ICMP_PARAMETERPROB 12 /* Parameter Problem,参数失灵 */
- #define ICMP_TIMESTAMP 13 /* Timestamp Request,时间戳请求 */
- #define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply,时间戳应答 */
- #define ICMP_INFO_REQUEST 15 /* Information Request,信息请求(已不再使用) */
- #define ICMP_INFO_REPLY 16 /* Information Reply,信息应答(已不再使用) */
- #define ICMP_ADDRESS 17 /* Address Mask Request,地址掩码请求(已不再使用) */
- #define ICMP_ADDRESSREPLY 18 /* Address Mask Reply,地址掩码应答(已不再使用) */
- #define NR_ICMP_TYPES 18
对于 以上类型,比较重要的有:回显请求与应答(type 0、8)、不可到达(3)、源站抑制(4)、路由重定向(5)、时间戳请求与应答(13、14)
其中type值表示是一个回显请求或应答,code 值为 0,而 identifier 在 linux 的实现为进程 pid(因为ping请求是应用程序,通过该值能够确认是机器上的哪一个应用程序执行的ping操作,能够对进行的接收数据进行匹配操作),而 sequence 则为一个计数器,主要是为每一个回显请求数据包设置序列值。Option是可选数据,其大小是可变的。
TYPE(8/0) | CODE(0) | Checksum |
identifier | Sequence | |
Option |
报文格式如下:
TYPE(3) | CODE(0-15) | Checksum |
Not used (must set 0) | ||
Option |
由于目的站不可达的原因很多,所以需要用code来进行进一步细分。对于option字段,其值为ip头部(包括可选项)加上原始ip数据部分的前8个字节。而code的定义如下(linux 3.10):
- /* Codes for UNREACH. */
- #define ICMP_NET_UNREACH 0 /* Network Unreachable */
- #define ICMP_HOST_UNREACH 1 /* Host Unreachable */
- #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */
- #define ICMP_PORT_UNREACH 3 /* Port Unreachable */
- #define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */
- #define ICMP_SR_FAILED 5 /* Source Route failed */
- #define ICMP_NET_UNKNOWN 6
- #define ICMP_HOST_UNKNOWN 7
- #define ICMP_HOST_ISOLATED 8
- #define ICMP_NET_ANO 9
- #define ICMP_HOST_ANO 10
- #define ICMP_NET_UNR_TOS 11
- #define ICMP_HOST_UNR_TOS 12
- #define ICMP_PKT_FILTERED 13 /* Packet filtered */
- #define ICMP_PREC_VIOLATION 14 /* Precedence violation */
- #define ICMP_PREC_CUTOFF 15 /* Precedence cut off */
- #define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */
如下所示为端口不可达报文,值得注意的是,icmp返回不可达报文时会将之前的原始报文封装作为 icmp 的数据区报文。远端收到icmpde不可达报文后,通过解析 icmp 的 data 区报文后到相应的传输层继续解析差错报文来执行相应的动作。
TYPE(5) | CODE(0-3) | Checksum |
Route’s ip | ||
Option |
对于option字段,其值为ip头部(包括可选项)加上原始ip数据部分的前8个字节。
第二个32bits代表路由器的wan側地址。Code类型如下:
- /* Codes for REDIRECT. */
- #define ICMP_REDIR_NET 0 /* Redirect Net */
- #define ICMP_REDIR_HOST 1 /* Redirect Host */
- #define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */
- #define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */
重定向报文仅限于在直接连接到同一网络上的路由器与主机间交互。
因为每一个ip数据包都有一个ttl计数器,即跳数计数器,当数据包中的ttl的值为0时,就丢弃数据包,并发送一个数据包超时的icmp 报文。下面即是icmp 数据包超时报文的格式
TYPE(11) | CODE(0-1) | Checksum |
Not used(must set 0) | ||
Option |
- /* Codes for TIME_EXCEEDED. */
- #define ICMP_EXC_TTL 0 /* TTL count exceeded */
- #define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */
对于option字段,其值为ip头部(包括可选项)加上原始ip数据部分的前8个字节。
对于命令 traceroute(windows 下为 tracert),即是根据ttl来实现查找到目的站点所有跳点的ip地址的。即先发送3个ttl为1的数据包,根据接收到的icmp 数据包超时报文获取到第一个下一跳地址;然后再发送3个ttl为的数据包,根据接收到的数据包超时报文获取到第二个下一跳地址;依此类推直到找到所有的跳点地址或者已经到了ttl的max值还没有到目的站点则程序返回。具体抓包参见《traceroute、tracert服务的工作原理》
- struct icmphdr {
- __u8 type;
- __u8 code;
- __sum16 checksum;
- union {
- struct {
- __be16 id;
- __be16 sequence;
- } echo;
- __be32 gateway;
- struct {
- __be16 __unused;
- __be16 mtu;
- } frag;
- } un;
- };
在该数据结构中,前32bits的定义是一样的,而后面32bits的定义,因回显请求与应答、重定向等报文定义不同而有不同的含义。
- struct icmp_bxm {
- struct sk_buff *skb;//接收到的icmp报文
- int offset;//选项数据在icmp数据中的偏移量
- int data_len;//icmp数据报文长度
-
- struct {
- struct icmphdr icmph;//icmp头部
- __be32 times[3];
- } data;
- int head_len;//icmp头部长度
- struct ip_options_data replyopts;
- };
-
- struct ip_options_data {
- struct ip_options_rcu opt;
- char data[40];
- };
-
- struct ip_options_rcu {
- struct rcu_head rcu;
- struct ip_options opt;//存储的接收icmp报文的选项数据,待发送时使用
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。