ICMP是layer 4协议,用户可以使用icmp来得到自己想要的东西。大名鼎鼎的ping就是利用ICMP的api写成的。
这个协议主要是用来处理(L3)层的错误信息与控制信息的,
ICMPv4
这里主要是两类: 错误报文和消息报文。著名的ip(来自于iputils包)就是打开 raw socket并且发送一个ICMP_ECHO报文、产生ICMP_REPLY报文作为回应。
icmpv4初始化
首先,在/net/ipv4/icmp.c中首先呼叫inet_init()(在boot阶段),方法,此方法激活icmp_init()方法,然后就会呼叫icmp_sk_init()产生ICMP包。
在 net/ipv4/af_inet.c 中有各种协议的注册。
接下来看看 icmp_protocal的结构
handler
首先看看handler, 当接受到由外面发来的包,只要在ip头部等于IPPROTO_ICMP(0x1), icmp_rcv就会触发。
no_policy
当设置为1,意味着不需要表现IPsec策略检查(policy check),
netns_ok
设置为1时提醒协议是network命名空间
icmp_sk_init() 位于net/ipv4/icmp.c 中
ICMPv4 Header
主要参考下面的这幅图片就可以了:
前64 bits是属于头文件的部分,后面的Payload包括原始包IPv4头文件和它的的负载。
头部的定义在include/uapi/linux/icmp.h
通过这张表,是不是可以得出这样一个结论:在网络协议中,它的bits size可以通过它的的类型的大小推断出来。
然后ICMPv4模块定义了icmp_control对象, 命名为 icmp_pointer,这个对象被ICMpv4消息的类型索引。
该定义位于 include/uapi/linux/icmp.c
其中, error是1,代表着错误消息(ICMP_DEST_UNREACH), 为0代表着正常消息(ICMP_ECHO)。 而handler有时会被赋值超过一种类型。
ping_rcv()接受一个ping的回应(ICMP_ECHOREPLY)。 位于net/ipv4/icmp.c
在3.0以前的内核版本中,你需要在用户空间程序中创建一个raw socket,当接收到一个(ICMP_ECHOREPLY)消息, 原来的raw socket处理它(理解不准确)。为了详细理解这个过程,先看一个函数。
在 /net/ipv4/in_input.c中。