计算机网络课程设计
一、设计内容及设计要求
1.1 课程设计内容:
利用 ICMP 数据包,通过使用 ICMP 的回送和回送响应消息来确定当前网络中处于活动
状态的主机,即 ping 消息的请求和应答,将发送的 ICMP 的数据包类型设置为回送请求(类
型号为 8),并显示在标准输出上。用命令行形式运行:scanhost Start_IP End_IP,其中 scanhost
为程序名;Start_IP 为被搜索网段的开始 IP;End_IP 为被搜索网段的结束 IP 地址。
1.2 课程设计目的:
IP 协议的优点是简单,但缺少差错控制和查询机制,而网际控制报文协议(ICMP 具有
补充 IP 功能的作用。在网络管理中,常常要确定当前网络在红处于活动状态的主机,这时
可以通过 ICMP 的回送和回送响应消息来完成这项工作。这课程设计的目的就是编制程序,
利用 ICMP 数据包,发现网络中的活动主机,即 ping 消息的请求和应答。通过课程设计,熟
悉 ICMP 报文的结构,对 ICMP 协议有更好的理解和认识,培养综合运用网络知识解决实际
问题能力。
1.3 课程设计要求:
设计程序,其功能是发送 ICMP 数据包,以获取指定望段中的活动主机,并将结果显示
在标准输出设备上程序的具体要求如下:
1.用命令形式运行
scanhost 为程序名;start_ip 为被搜索网段;end_ip 为被搜索网段的结束 IP 地址。如在
命令行输入 scanhost
192.168.0.1
192.168.0.100
2.输出格式
活动主机 1 的 IP 地址
活动主机 2 的 IP 地址
活动主机 n 的 IP 地址
二、总体设计
2.1 设计原理
首先对 ICMP 报文的格式有一定的了解,ICMP 报文是在 IP 数据报内部传输的,其结构
如图所示:
IP 数据报
IP 首部
ICMP 报文
ICMP 报文的格式如图所示:
0
7
8
15
16
31(位)
类型字段
代码字段
校验和字段
(不同类型和代码有不同内容)
所有报文的前 4 个字节都是一样的,但是其它字节则互不相同。其中类型字段可以有
15 个不同的值,以描述特定类型的 ICMP 报文,某些 ICMP 报文还使用代码字段的值来进一
步描述不用的条件。按验和字段为 2 字节,校验的范围是整个 ICMP 报文。检验和是必须的,
其计算方法与 IP 协议头部校验和的计算方法一样。
各种类型的 ICMP 报文如图所示(ICMP 报文类型),不同类型由报文中的类型字段和代
码字段来共同决定。
类 型
代
码
0
3
0
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
描
述
回送响应(PING 应答)
目的不可达
网络不可达
主机不可达
协议不可达
端口不可达
需要进行分片但设置了禁止分片比特
源主机选择路由失败
无法识别目的网络
无法识别目的主机
源主机被隔离
目的网络被禁止
目的主机被禁止
由于服务类型(TOS),网络不可达
由于服务类型(TOS),主机不可达
由于过滤,通信被强行禁止
主机越权
优先权终止生效
4
5
8
9
10
11
12
13
14
15
16
17
18
0
0
1
2
3
0
0
0
0
1
0
1
0
0
0
0
0
0
源端被关闭(基本流控制)
重定向
对网络重定向
对主机重定向
对服务类型和网络重定向
对服务类型和主机重定向
回送请求(PING 请求)
路由器通告
路由器请求
超时
传输期间生存期减为 0
数据报组装期间生存期减为 0
参数问题
各种 IP 头部错误
缺少必须的选项
时间戳请求
时间戳应答
信息请求(已作废)
信息应答(已作废)
地址掩码请求
地址掩码应答
课程设计的目的是发现网络中的活动主机,就是使用 ICMP 的回送和回送响应消息发现
网络中的活动主机,即 Ping 消息的请求和应答。那幺,发送的 ICMP 的数据包类型设置为回
送请求(类型号为 8)。
本程序使用的原始套接字生成 ICMP 请求/应答报文来进行活动主机的探查。这个程序
使用的是回送请求和应答消息。程序的大致思想是把 ICMP 的数据报类型设置为回送请求,
将它发送给网络上的一个 IP 地址,如果这个 IP 地址已经被占用的话,那么使用位于这个 IP
地址的主机上的 TCP/IP 软件就能接受到这个 ICMP 回送请求,从而返回一个 ICMP 回送请
求(类型号为 0)信息。信息封装在一个 IP 包中,我们需要解析该 IP 包,从中找到 ICMP
数据信息,相反,如果这个 IP 地址没有人使用,那么发送的 ICMP 回送请求在设定的延时
内就不可能得到响应。
2.2 概要设计
主程序流程图
开 始
构造原始套接字,并初始化
建立并初始化木的主机的
Sockaddr_in 数据结构 dest
起始 IP 地址->start_ip
ip
结束 IP 地址->end
将 start_ip 填入到 dest 中
Y
start_ip< = end ip?
Y
等待一定时间
线程数目太多?
N
创建一个线程并执行
start_ip ++
Y
等待一定时间
还有线程在执行?
N
结 束
子线程流程图
开 始
填充 ICMP 数据报
发送数据报
接受数据报
去掉 IP 头,获取 ICMP 信息
数据包太短?
不是回送响应?
ID 不符合?
N
N
N
数据库中的 IP 地址
结 束
Y
Y
Y
三、详细设计及代码
3.1 ICMP 报文分析
ICMP 是一种差错和控制报文协议,用于传输错误报告和控制信息。
ICMP 报文分为头部和数据部分。ICMP 报文封装在 IP 数据报中传输。IP 报头中的类型
为 1 时,表示报文的数据部分为 ICMP 报文。虽然 ICMP 报文由 IP 报文传输,但是并不能
认为 ICMP 是 IP 的上层协议,而是 IP 协议的有机补充。把 ICMP 报文放在 IP 包中,是要
利用 IP 的转发功能。
类型(TYPE)是一个字节,表示 ICMP 消息的类型。代码(CODE)也是一个字节,
表示报文类型的下一步信息。校验和共有两个字节,提供对整个 ICMP 报文的校验和(和 IP
报文类型的进一步信息)。校验和共两个字节,提供对整个 ICMP 报文的校验和。按照协议
的功能来分,ICMP 报文可以分为
[1]. ICMP 差错报文
包括目的不可达报告,超时报告,参数出错报告。
[2] .ICMP 控制报文
包括拥塞控制和源抑制报文,路游控制和重定向报文
[3] .ICMP 测试报文
包括请求应答报文,时戳请求应答报文。
本课程设计就是使用 ICMP 请求/应答报文来测试目的主机是否存在,请求者想某特定的
主机发送请求,其中包含任选的数据。目的主机收到请求后,发送应答报文。在同一时刻,
一台机器可以同时向多台主机发送请求报文。ICMP 报文格式如图所示:
类型
代码
校 验 和
数据区(变长)
ICMP 回送报文格式如下图所示:
类型(8,0) 码(0) 校验和
标志位
序号
任选数据
3.2 程序功能分析
本程序使用原始套接字生成 ICMP 报文来进行活动主机的探查。这个程序使用的是回送
请求与应答信息。程序的大致思想是把 ICMP 的数据包类型设置为回送请求,将它发送给网
络上的一个 IP 地址,如果这个 IP 地址已经被占用的话,那么使用位于这个 IP 地址的主机
上的 TCP/IP 软件就能够接受到这个 ICMP 回送请求,从而返回一个 ICMP 回送响应(类型
号为 0)信息。信息封装在一个 IP 包中,需要解析该 IP 包,从中找到 ICMP 数据信息。相
反,如果这个 IP 地址没有人使用,那么发送的 ICMP 回送请求在设定的延时内就不可能得
到响应。
在初始化原始套接字之后,本程序就要开始在一个 IP 网段内寻找活动主机。因为要寻
找活动的主机可能很多,为节省时间可以采用多线程编程。结合核心代码对程序的具体进行
分析。
3.2.1 使用原始套接字
为了实现发送/监听 ICMP 抱文,必须使用原始套接字,创建原始套接字的代码如下:
SOCKET sockraw;
sockraw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,wsa_flag_overlapp
ed);
在 WSASocket 函数中,我们使用 IPPROTO_ICMP 表示接受 ICMP 数据包,为了使用发
送 接 受 超 时 设 置 ( 设 置 SO_RCVTIMEO 或 SO_SNDTIMEO ), 必 须 将 标 志 位 置 为
WSA_FLAG_OVERLAPPED。然后调用 setsockopt 函数设置读取迟延。在 setsockopt 函数中,
sockraw 是之前创建的原始套接字,设置 SOL_SOCKET 表明使用基本套接字处理 ICMP 抱
文。设置 SO_RCVTIMEO 表示使用接受超时设置,SOSNDTIMEO 表示使用发送超时设置,
在这里,超时时间均设置为 1000ms。
3.2.2 定义 IP 头部的数据结构
typedef struct iphdr{
unsigned int headlen:4;
//ip 头长度
unsigned int wersion:4;
//ip 版本号
unsigned char tos;
//服务类型
unsigned short totallen;
//ip 包总长度
unsigned short id;
unsigned short flag;
//ip 号
//标记
unsigned char ttl;
//生存时间
unsigned char prot;
//协议(UDP TCP)
unsigned short checksum;
//校验和
unsigned int sourceip;
//源 ip
unsigned int destip;
//目的 ip
}IpHeader;
3.2.3 定义 ICMP 头部数据结构
typedef struct icmphdr{
BYTE type;
//icmp 类型码,回送请求的类型码为 8
BYTE code;
//子类型码,保存与特定 ICMP 报文类型相关的细节信息
USHORT checksum;
//校验和
USHORT id;
USHORT seq;
//ICMP 报文 id 号
//ICMP 数据报的序列号
}Icmpheader;
3.2.4 填充并发送请求类型的 ICMP 报文
#define ICMP_ECHO 8
//请求回送
#define DEF_PACKET_SIZE 32
//缺省数据报长度
#define MAX_PACKET 1024
//最大数据报长度
#char icmp_data[MAX_PACKET]; //ICMP 数据报最大可能长度
Memset(icmp_data,0, MAX_PACKET) //将数据报清空初始化
Int datasize=DEF_PACKET_SIZE;
//ICMP 数据报报文体的额缺省长度
Datasize+=sizeof(icmpHeader); //加上 ICMP 数据头部
icmp_header *icmp_hdr;
char *datapart;
icmp_hdr=(icmpheader*)icmp_data;
icmp_hdr->type=icmp_echo;
//设置类型
icmp_hdr->id=(ushort)getcurrentthreadid(); //设置其 ID 号为当前线程号
datapart=icmp_data+sizeof(icmpheader);
//计算出 ICMP 数据报的数据部分
memset(datapart,'A',datasize-sizeof(icmphearder)); //填入数据