计算机网络课程设计报告
题
目:
解析 IP 数据包
学生姓名:
学
号:
专业班级:
同组姓名:
指导教师:
潘梅森
设计时间:
2010 年上学期第 17 周
指导老师意见:
评定成绩:
签名:
日期: 年 月 日
一、课程设计的目的和意义
课程设计目的:
本章课程设计的目的就是设计一个解析 IP 数据包的程序,并根据这个程
序,说明 IP 数据包的结构及 IP 协议的相关问题,从而对 IP 层的工作原理有更
好的理解和认识。
课程设计意义:
1、有利于编程能力的提高
在做设计的过程中,我再一次熟悉了开发设计的基本流程,从分析任务到确
立整体框架再到确定算法,然后再一步步实现各函数的功能。从中,我熟悉了许
多新的库函数,并提高了编程技巧。
2、有利于基础知识的理解
在这次课程设计之前,我们已经学完了网络层的理论知识,可是对它的理解
很粗浅。之前只知道关于网络层的一些概念性的东西。可是做完设计后,我才从
整体上理解了网络层的框架,明白了网络层的每一个组成部分都是有它特定的功
能和意义的,从而对网络层协议有了更深入的理解。
3、有利于逻辑思维的锻炼
程序设计能直接有效地训练我们的创新思维,培养分析问题、解决问题的能
力。即使一个简单的程序,从任务分析、确定算法、界面布局、编写代码到调试
运行,整个过程学生都需要有条理地构思,这中间有猜测设想、判断推理的抽象
思维训练,也有分析问题、解决问题、预测目标等能力的培养。
二、课程设计的内容和要求
本设计的目标是捕获网络中的 IP 数据包,解析数据包的内容,将结果显示
在标准输出上,并同时写入日志文件。
程序的具体要求如下:
1)以命令行形式运行:ipparse logfile,其中 ipparse 是程序名, 而 logfile
则代表记录结果的日志文件。
1
2)在标准输出和日志文件中写入捕获的 IP 包的版本、头长度、服务类型、
数据包总长度、数据包标识、分段标志、分段偏移值、生存时间、上层协议类型、
头校验和、源 IP 地址和目的 IP 地址等内容。
3)当程序接收到键盘输入 Ctrl+C 时退出。
三、课程设计的相关技术
3.1
IP 数据包的格式与分析
互联网层是 TCP/IP 协议参考模型中的关键部分。IP 协议把传输层送来的消
息组装成 IP 数据包,并把 IP 数据传递给数据链路层。IP 协议在 TCP/IP 协议族
中处于核心地位,IP 协议制定了统一的 IP 数据包格式,以消除各通信子网间的
差异,从而为信息发送方和接收方提供了透明的传输通道。编制本程序前,首先
要对 IP 包的格式有一定的了解。图(1)给出了 IP 协议的数据包格式。
IP 数据包的第一字段是版本字段,其长度为 4 位,表示所使用的 IP 协议的
版本。目前的版本 IPV4,版本字段的值为 4,下一代的版本是 IPV6,版本字段
的值为 6。本程序主要针对版本值为 4 的 IP 数据包的解析。
报头标长(IHL)字段为 4 位,它定义了以 4B 为一个单位的 IP 包的报头长度。
报头除了选项字段和填充域字段外,其他各字段是定长的。因此,IP 数据包的
头长度在 20-40B 之间,是可变的。
0
31(位)
16
19
24
4
8
版本 报头标长
服务类型
总长度
标 识
标 志
片偏移
生存时间
协 议
头校验和
源 IP 地址
目的 IP 地址
任选项(0 或多项)
填充
数据部分
图 1IP 数据包的格式
2
服务类型字段共 8 位,用于指示路由器如何处理该数据包。该字段长度由 4
位服务类型(TOS)子域和 3 位优先级(b7 b6 b5)(precedence)子域组成,1 位为保
留位,该字段结构如图(2)所示:
b3
b7 b6
b4
b5
b2
b1
b0
优先级
D
T
R
C
0
图 2 服务类型字段结构
优先级共有关 8 种,优先级越高表明数据包越重要。图(3)列出了各种优
先级所代表的意义。
位数(b7b6b5)
111
110
101
100
011
010
001
000
意义
网络控制
网络间控制
重要(CRITIC/ECP)
即时、优先
即时
立刻
优先
普通
图 3 优先级子域的说明
在 4 位服务类型子域中,b4 b3 b2 b1 分别表示 D(延迟)、T(吞吐量)、R
(可靠性)与(成本)。表图(4)列出了服务类型子域的构成。
位数(b4 b3 b2 b1)
1111
1000
0100
0010
0001
0000
意义
安全
延迟最小
吞吐量最大
可靠性最大
成本最小
普通服务
图 4 列出了服务类型子域
3
总长度字段为 2B,它定义了以字节为单位的数据包的总长度。IP 数据包的
最大长度为 216 =65535B。
标识字段长度为 16 位,用于识别 IP 数据包的编号。每批数据都有一个标识
值,用于让目的主机判断新来的数据属于哪个分组。
报头中的标志字段如图(5)所示。标志字段共 3 位,最高位是 0,禁止分
片标志 DF 字段的值若为 1,表示不能对数据包分片;若 DF 值为 0,则表明可
以分片。分片标志 MF 的值为 1,表示接收到的不是最后一个分片;若 MF 值为
0,表示接收到的是最后一个分片。
0
DF
MF
图 5 标志字段的结构
片偏移字段共 13 位,说明分片在整个数据包中的相对位置。片偏移值是 8B
为单位来计数的,因此选择的分片长度应该是 8B 的整数倍。
生存时间(TTL)字段为 8 位,用来设置数据包在互联网络的传输过程的寿
命,通常是用一个数据包可以经过的最多的路由器跳步数来限定的。
协议字段为 8 位,表示使用 IP 数据包的高层协议类型,常用的协议号如图
(6)所示。
序号
协议名称
序号
协议名称
1
2
4
6
8
ICMP
IGMP
IP in IP
TCP
EGP
17
41
46
89
UDP
IPv6
RSVP
OSPF
图 6 典型的协议号
头部验和字段为 16 位,用于存放检查报头错误的校验码。校验的范围是整
个 IP 包的包头。校验和按如下方法计算:
1)将头校验和的字段置为 0。
2)将报头部分的所有数据以 16 位为单位进行累加,累加方式是求异或。
3)将累加的结果取反码,就是头校验和。
4
当收到一个 IP 包时,要检查报头是否出错,就把报头中的所有数据以 16
位为单位进行累加,若累加的结果为 0,则报头没有出错。
地址字段包含源地址和目的地址。源地址和目的地址的长度都是 32 位,分
别表示发送数据包的源主机和目的主机的 IP 地址。
选项字段的长度范围是 0~40B,主要用于控制和测试。在使用选项字段的
过程中,有可能出现报头部分的长度不是 32 位的整数倍的情况。如果出现这种
情况,就需要通过填充位来凑齐。
3.2 程序分析设计
3.2.1 网卡设置
为了获取网络中的 IP 数据包,必须对网卡进行编程,在这里我们使用套接
字(socket)进行编程。但是,在通常情况下,网络通信的套接字程序只能响应与
自己硬件地址相匹配的数据包或是以广播形式发出的数据包。对于其他形式的数
据包,如已到达网络接口,但却不是发送到此地址的数据包,网络接口在骓投递
地址并非自身地址之后将不引起响应,也就是说应用程序无法收取与自己无关的
数据包。我们要想获取网络设备的所有数据包,就是需要将网卡设置为混杂模式。
3.2.2 程序设计
本程序主要由三部分构成:初始化原始套接字,反复监听捕获数据包和解析
数据包。下面就结合核心代码对程序的具体实现进行分析,同时使程序流程更加
清晰,去掉了错误检查等保护性代码。
3.2.3 使用原始套接字
套接字分为三种,即流套接字(Stream socket)、数据报套接字(Datagram
Socket)和原始套接字(Raw Socket)。要进行 IP 层数据包的接收和发送,应使用
原始套接字。创建原始套接字的代码如下:
SOCKET sock;
sock=WSAsocket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERL
APPED);
本设计不用考虑超时情况。
创建套接后,IP 头就会包含在接收数据包中。然后,我可以设置 IP 头操作
选项,调用 setsockopt 函数。其中 flag 设置为 true,并设定 IP-HDRINCL 选项,
5
表明用户可以亲自对 IP 头进行处理。最后使用 bind()函数将 socket 绑定到本地
网卡上。绑定网卡后,需用 WSAIoctl()函数把网卡设置为混杂模式,使网卡能够
接收所有的网络数据。如果接收的数据包中的协议类型和定义的原始套接字匹
配,那么接收的数据就拷贝到套接字中,因此,网卡就可以接收所有经过的 IP
包。
/* 设置 IP 头操作选项,使用户可以对 IP 头进行处理 */
BOOL flag=true;
Setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(flag));
之后,使用如下代码完成对 socket 的初始化工作:
/* 获取主机名 */
char hostName[128];
gethostname(hostName,100);
/* 获取本地 IP 地址 */
hostent *pHostIP;
pHostIP = gethostbyname(hostName));
/* 填充 SOCKADDR_IN 结构的内容 */
sockaddr_in addr_in;
addr_in.sin_addr = *(in_addr*)pHostIP->h_addr_list[0];
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(6000);
bind(sock,(PSOCKADDR)&addr_in,sizeof(addr_in)) ;
/* 绑定 socket */
3.2.4 接收数据包
在程序中可使用 recv()函数接收经过的 IP 包。该函数有四个参数,第一个
参数接收操作所用的套接字描述符;第二个参数接收缓冲区的地址;第三个参数
接收缓冲区的大小,也就是所要接收的字节数;第四个参数是一个附加标志,如
果对所发送的数据没特殊要求,直接设为 0。因为 IP 数据包的最大长度是
65535B,因此缓冲区的大小不能小于 65535B。设置缓冲区后,可利用循环来
反复监听接收 IP 包,用 recv()函数实现接收功能。
3.2.5 IP 包的解析
6
解析 IP 包的字段有两种策略。针对长度为 8 位、16 位和 32 位的字段(或子
字段)时,可以利用 IP-HEADER 的成员直接获取。要解析长度不是 8 位倍数的
字段(或子字段)时,可以利用 C 语言中的移位以人、及与、或操作完成。
四、课程设计过程
首先,分析任务,明确该程序需要实现的功能;然后,根据该功能画出相应
的程序流程图;其次,打开 VC,用 C++语言书写源代码,并且进行调试,直到得
出正确的结果,并对程序的最后运行结果进行截图;最后,完成课程设计报告。
4.1 程序流程图如下
开 始
构造程序运行环境
创建原始接字,并初始化
捕获 IP 包
解析 IP 包
解析 IP 包
Ctrl+C(中断)
Y
结 束
图 6 程序流程图
7
N