《网络工程》
探究式项目结题报告汇编
网络源代码分析
作者(学号) 王 燕 1081000088
作者(学号) 袁雅宜 1081000095
20010-2011年第一学期
任课教师:徐远超
首都师范大学信息工程学院
* INET An implementation of the TCP/IP protocol suite for the LINUX
*TCP / IP协议套件的Linux实现INET电子交易系统
* operating system. INET is implemented using the BSD Socket
*操作系统。 INET是实现使用的BSD套接字
* interface as the means of communication with the user level.
*接口作为与用户沟通水平的手段。
* Internet Control Message Protocol (ICMP)
*互联网控制消息协议
* Version: @(#)icmp.c 1.0.11
*版本: @(#)icmp.c 1.0.11
* Authors: Ross Biro,
* Fred N. van Kempen,
* Mark Evans,
* 作者: Ross Biro, Fred N. van Kempen, Mark Evans
* Fixes:// 修正:
* Alan Cox : Generic queue usage.// 通用队列使用
* Gerhard Koerting: ICMP addressing corrected//ICMP的处理纠正
* Alan Cox : Use tos/ttl settings//使用渡/ TTL电设置
*
*
* This program is free software; you can redistribute it and/or//本程序为自由软件,你可以重新发布与/或
* modify it under the terms of the GNU General Public License//修改根据GNU通用公共许可证的条款是
* as published by the Free Software Foundation; either version//如出版自由软件基金会;任一版本
* 2 of the License, or (at your option) any later version.// 2使用许可,或在您的选择()的任何版本
IP协议是在网络层的协议,它主要完成数据包的发送作用,下面这个表是IPv4的数据包格式:
ICMP报文格式
IP头标 |
类型(8位) |
代码(8位) |
校验和(16位) |
参数(若无,可不用) |
信息(长度可变) |
ICMP类型编码列表
类型代码值 |
ICMP报文类型描述 |
类型代码值 |
ICMP报文类型描述 |
0 |
响应应答(ECHO答应) |
13 |
时戳请求 |
3 |
信宿不可达 |
14 |
时戳应答 |
4 |
源抑制 |
15 |
信息请求 |
5 |
重定向 |
16 |
信息应答 |
8 |
响应请求(ECHO请求) |
17 |
地址掩码请求 |
11 |
超时 |
18 |
地址掩码应答 |
12 |
参数失灵 |
|
|
#include
#include
#include
#include
#include
#include
#include "inet.h"
#include "dev.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "icmp.h"
#include "tcp.h"
#include "skbuff.h"
#include "sock.h"
#include
#include
#include
#include
//以上为头文件.
#define min(a,b) ((a)<(b)?(a):(b))//宏定义 求a、b的最小值
/* An array of errno for error messages from dest unreach. */
//一个数组——errno(封装在结构体内的复合数据类型)用来表示从目标主机发来的(目标主机)不可达的错误信息
struct icmp_err icmp_err_convert[] = {
/* ICMP报文不可达代码域常量定义 */
{ ENETUNREACH, 1 }, /* ICMP_NET_UNREACH */ /* 网络不可达 */
{ EHOSTUNREACH, 1 }, /* ICMP_HOST_UNREACH */ /* 主机不可达 */
{ ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */ /* 协议不可达 */
{ ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */ /* 端口不可达 */
{ EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */ /* 需设置DF位,分段 */
{ EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */ /* 源路由失败 */
{ ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */ /* 未知网络*/
{ EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */ /* 未知主机 */
{ ENONET, 1 }, /* ICMP_HOST_ISOLATED *//* 源主机被隔离 */
{ ENETUNREACH, 1 }, /* ICMP_NET_ANO *//* 从管理上禁止与目的网通信 */
{ EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO *//*从管理上禁止与目的主机通信*/
{ EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS *//*对服务器类型,网络不可达 */
{ EOPNOTSUPP, 0 } /* ICMP_HOST_UNR_TOS *//* 对服务类型,主机不可达 */
};
/* Display the contents of an ICMP header. */
//显示ICMP数据包头部内容信息
static void
print_icmp(struct icmphdr *icmph) //打印icmp//
{
if (inet_debug != DBG_ICMP) return;
//判断IP头部Protol与ICMP的头部的Protol域值相同,说明IP数据报装载的是ICMP报文
printk("ICMP: type = %d, code = %d, checksum = %X\n",
icmph->type, icmph->code, icmph->checksum);
//输出ICMP数据包中的类型,代码,校验和
printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
//输出存放在套接口实现所分配的内存中的网关
}
/* Send an ICMP message. */
//发送ICMP数据包
void
icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
//icmp数据包封装在ip数据报文中发送{
struct sk_buff *skb; //定义缓存结构
struct iphdr *iph; //定义IP头部
int offset; //定义偏移量
struct icmphdr *icmph; //定义ICMP头部
int len; //定义IP数据报长度
//发送ICMP报文(封装在TCP/IP数据包中)
DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
skb_in, type, code, dev));
/* Get some memory for the reply. */递归语句
//从回复包中得到一些信息
len = sizeof(struct sk_buff)(包头) + dev->hard_header_len (数据字段长度)+
sizeof(struct iphdr)(IP数据报长度) + sizeof(struct icmphdr)(ICMP的前8个字节) +(sizeof(struct iphdr) + 8)(IP数据报首部以后的8个字节);/* amount of header to return *///计算IP数据报长度
skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);//在IP数据包中,为包头分配内存空间
if (skb == NULL) //判断以上的内存申请是否成功
return;
skb->sk = NULL;//包头所指向的头指针
skb->mem_addr = skb; //包头在片中的地址
skb->mem_len = len; //包头的长度
len -= sizeof(struct sk_buff); //包头的长度等于
/* Find the IP header. */
//计算IP数据包头部
iph = (struct iphdr *) (skb_in->data + dev->hard_header_len);
/* Build Layer 2-3 headers for message back to source. */
offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
&dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255);
//计算偏移量offset
if (offset < 0) {//当offset<0时进行如下操作
skb->sk = NULL;//指针清空
kfree_skb(skb, FREE_READ); //查看接收缓存还够不够
return;
}
/* Re-adjust length according to actual IP header size. */
//根据实际IP头部大小重新调整IP数据包长度
skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;//重新计算长度
icmph = (struct icmphdr *) (skb->data + offset);// //重新计算icmp包头部长度
icmph->type = type; //重新计算icmp包头类型
icmph->code = code; //重新计算icmp包头代码
icmph->checksum = 0; //重新计算icmp包头校验和
icmph->un.gateway = 0;// icmph->un.gateway清0
memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);//内存复制操作
icmph->checksum = ip_compute_csum((unsigned char *)icmph,
sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
//重新计算icmp包头校验和
DPRINTF((DBG_ICMP, ">>\n"));
print_icmp(icmph);//输出icmp头部信息
/* Send it and free it. *///将IP包发送并清理内存空间
ip_queue_xmit(NULL, dev, skb, 1);
}
功能:(响应状态)发送ICMP报文。
1.Skb结构的包类型不是本机(物理多播或广播),则返回。
2.检查IP的目标地址,是广播或多播,则返回。
3.IP fragment不是第一个(不处理),返回。
4.这个ICMP的类型大于18或error域不为空,返回。
5.在没有定义“无限制”条件下,有限制则返回。
6.IP目标地址不是本设备地址和本机地址,以设备地址作源地址入参调用ip_options_echo(在IP_OPTIONS.C中定义),否则以IP目标地址为源地址入参调用,结果不为0(出错),返回。
7.为ICMP头准备数据(长度不大于576)。
8.调用icmp_build_xmit,建立和发送ICMP报文,若为“错误报文”,则置优先级为6(网络控制)。
小节:这一部分的功能主要是发送一个IP数据包,通过返回的ICMP数据包判断出现了说明问题,根据这个问题重新发送。