全部博文(436)
分类: LINUX
2010-11-05 22:47:36
ICMP差错报文的格式
不可达,超时,源泉抑制
type |
len |
cksum |
Void(必须是0) |
被破坏分组的IP首部 |
需要分片
type |
len |
cksum |
Pmvoid(必须是0) |
nextmtu |
被破坏分组的IP首部 |
参数问题
type |
len |
cksum |
pptr |
(必须是0) |
被破坏分组的IP首部 |
信宿不可达报文类型表
代码值 |
类型描述 |
|
代码值 |
类型描述 |
0 |
网络不可达 |
|
7 |
信宿主机未知 |
1 |
主机不可达 |
|
8 |
信源主机被隔离 |
2 |
协议不可达 |
|
9 |
与信宿网络的通信被禁止 |
3 |
端口不可达 |
|
10 |
与信宿主机的通信杯禁止 |
4 |
需要分片和DF设置 |
|
11 |
对请求的服务类型,网络不可达 |
5 |
源路由失败 |
|
12 |
对请求的服务类型,主机不可达 |
6 |
信宿网络未知 |
|
|
|
/* Handle ICMP_UNREACH and ICMP_QUENCH. */处理ICMP_UNREACH和ICMP_QUENCH。//处理不可达和源终止//
static void
icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) ;//调用icmp_unreach函数类型3
{
struct inet_protocol *ipprot;
struct iphdr *iph; //定义IP头部
unsigned char hash;
int err;//定义变量
err = (icmph->type << 8) | icmph->code;// ICMP包类型小于8,响应请求
iph = (struct iphdr *) (icmph + 1);//IP的头标位ICMP的头标加1
switch(icmph->code & 7) //将icmph指向代码(为8位)并与7与后进行判断,得到不可达类型的代号
{
case ICMP_NET_UNREACH://当网络不可达时
DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
in_ntoa(iph->daddr))); //输出网络不可访问的目的IP地址
break;
case ICMP_HOST_UNREACH: //当主机不可达时
DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
in_ntoa(iph->daddr))); //输出主机不可访问 目的IP地址
break;
break;
case ICMP_PROT_UNREACH://当端口不可达时
printk("ICMP: %s:%d: protocol unreachable.\n",
in_ntoa(iph->daddr), ntohs(iph->protocol));
//输出ICMP协议不可达 目的IP地址 协议首地址
break;
case ICMP_PORT_UNREACH:
DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
break;
case ICMP_FRAG_NEEDED://当需要分片时和DF设置时
printk("ICMP: %s: fragmentation needed and DF set.\n",
in_ntoa(iph->daddr));//输出碎片需要和DF设置 目的IP地址
break;
case ICMP_SR_FAILED://当源路由失败时
printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
break;// 目的IP地址 源路由失败
default:
DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
(icmph->code & 7), in_ntoa(iph->daddr)));
break;
}
//若不是上述情况 则输出DBG_ICMP icmp不可达 code的值 目的ip地址
/* Get the protocol(s). *///获取通讯协定
hash = iph->protocol & (MAX_INET_PROTOS -1);
//hash等于iph->protocol并(MAX_INET_PROTOS -1)
/* This can change while we are doing it. */
ipprot = (struct inet_protocol *) inet_protos[hash];//如果找到相关的协议
while(ipprot != NULL) {
struct inet_protocol *nextip;//到路由的下一跳
nextip = (struct inet_protocol *) ipprot->next;// ipprot 等于inet的协议 inet_protos[hash],ipprot不为空,ipprot等于 inet的协议 *,ipprot指向下一个值
/* Pass it off to everyone who wants it. */
if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
ipprot->err_handler(err, (unsigned char *)(icmph + 1),
iph->daddr, iph->saddr, ipprot);
}//发送给目的端口
ipprot = nextip;
}
skb->sk = NULL;
kfree_skb(skb, FREE_READ); //查看接收缓存还够不够
}
功能:处理ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.
1.长度小于IP头结构长度,则转入FLUSHIT(6)
2.长度小于ihl*4,则转入FLUSHIT(6)
3.处理ICMP-DEST-UNREACH:CODE(低4个bit)为
A.NET、HOST-UNREACH:转入4
B.PROT-UNREACH:调用NETDEBUG(protocol unreachable),其它同C
C.PORT-UNREACH:match_addr=1,其它同A
D.FRAG-NEEDED:没有PMTU-Discovery,则同B(参数不同,为fragmentation needed and DF set.)其它同A;否则,①skb结构对应的路由表的MTU小于等于IP头的TTL,发NETDEBUG(指明基于4.2BSD的路由),然后将MTU置为TTL-4*IHL②若新估MTU小于68或大于旧MTU,则据RFC1191重新定新的MTU③将新MTU放入IP头的ID域,然后动作同A。
E.SR-FAILED:NETDEBUG(源路由失败)其它同A
F.其它情况同A
4.CODE码大于NR-ICMP-UREACH(为非法类型),转入FLUSHIT
5.若match_addr为0或入参saddr等于IP包头的目标地址,据IP头的协议号找到协议哈希表的对应表,遍历这个表,若协议相同且差错处理不为空,则调用差错处理,否则转FLUSHIT:以FR入6。
6.EE_READ为参数释放skb结构空间。
chinaunix网友2011-01-05 17:29:10
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com