实验4 IP包流量分析
实验要求:
(1)掌握IP数据报格式和报头各字段含义;
(2)基于RAW Socket和wincap(或lipcap)实现IP数据包的捕获;
(3)掌握分析与统计IP数据包信息的基本方法。
实验目的
设计一个解析IP数据包的程序,并根据这个程序,
说明
关于失联党员情况说明岗位说明总经理岗位说明书会计岗位说明书行政主管岗位说明书
IP数据包的结构及IP
协议
离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载
的相关问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
,从而对IP层的工作原理有更好的理解和认识。
实验环境(设备)
windows XP
Microsoft Visual C++6.0
实验原理
1、简介:
网络层是TCP/IP协议参考模型中关键的部分。IP协议把运输层送来的消息组装成IP数据包,并把IP数据包传递给数据链路层。IP协议在TCP/IP协议族中处于核心地位,IP协议制定了统一的IP数据包格式,用于消除通信子网间的差异,从而为信息发送方和接收方提供了透明的传输通道。编制本程序前,首先要对IP包的格式有一定的了解。
IP数据包的第一个字段是版本字段(4位),表示所使用的IP协议的版本。目前的版本是IPv4,版本,那么IPv6的版本字段自然就是值为6啦。
2.IP数据包的格式:
如上图所示,下面解析一下IP数据包的各个字段的内容:
①版本:占4位,指IP协议的版本。通信双方使用的
IP协议版本必须一致。日前广泛使用的 IP协议版本号为 4 (即 IPv4)。
IPv6 目前还处于起步阶段。
②首部长度:占 4 位,可表示的最大十进制数值是 15。请注意,
这个字段所表示数的单位是32位字 ( 1 个32位字长是4 字节),
因此,当 IP 的首部长度为 1111 时 (即十进制的 15),
首部长度就达到 60字节。当 IP 分组的首部长度不是4字节的整数倍时,
必须利用最后的填充字段加以填充。
因此数据部分永远在 4字节的整数倍开始,
这样在实现 IP协议时较为方便。
首部长度限制为 60字节的缺点是有时可能不够用。
这样做的目的是希望用户尽量减少开销。
最常用的首部长度就是 20 字节 (即首部长度为 0101),
这时不使用任何选项。
③服务:占 8 位,用来获得更好的服务。
这个字段在旧标准中叫做服务类型,但实际上一直没有被使用过。
1998年IETF把这个字段改名为区分服务 DS (DifferentiatedServices)。
只有在使用区分服务时,这个字段才起作用。该字段长度由4位服务类型子域组成,1位为保留位,该字段的结构如下图所示:
b7 b6 b5 b4 b3 b2 b1 b0
优先级
D
T
R
C
0
其中:b4 、b3 、b2 、b1分别表示D(延迟)、T(吞吐量)、 R(可靠性 ) 、 C(成本)
优先级共有8种,优先级越高表明数据包越是重要。
④总长度:总长度指首都及数据之和的长度,单位为字节。
因为总长度字段为 16位,所以数据报的最大长度为 216-1=65 535字节。 在IP层下面的每一种数据链路层都有自己的帧格式,其中包括帧格式中的数据字段的最大长度,即最大传送单元 MTU (Maximum Transfer Unit)。当一个数据报封装成链路层的帧时,此数据报的总长度 (即首部加上数据部分)一定不能超过下面的数据链路层的MTU值。
⑤标识 (Identification):占 16位。
IP软件在存储器中维持一个计数器,每产生一个数据报,
计数器就加 1,并将此值赋给标识字段。但这个“标识”并不是序号,
因为 IP是无连接的服务,数据报不存在按序接收的问题。
当数据报由于长度超过网络的 MTU 而必须分片时,
这个标识字段的值就被复制到所有的数据报的标识字段中。
相同的标识字段的值使分片后的各数据报片最后能正确地重装成为
原来的数据报。
⑥标志 (Flag):占3 位,但目前只有2位有意义。
标志字段中的最低位记为 MF (More Fragment)。
MF=1即表示后面“还有分片”的数据报。MF=0表示这已是若干数据报片
中的最后一个。
标志字段中间的一位记为 DF(Don't Fragment),
意思是“不能分片”。只有当 DF=0时才允许分片。
⑦片偏移:占 13位。较长的分组在分片后,
某片在原分组中的相对位置。也就是说,相对用户数据字段的起点,
该片从何处开始。片偏移以 8个字节为偏移单位。
这就是说,每个分片的长度一定是 8字节 (64位)的整数倍。
⑧生存时间:占 8位,生存时间字段常用的英文缩写是
TTL (Time To Live),其表明数据报在网络中的寿命。
由发出数据报的源点设置这个字段。
其目的是防止无法交付的数据报无限制地在因特网中兜围子,
因而白白消耗网络资源。最初的设计是以秒作为 TTL的单位。
每经过一个路由器时,就把TTL减去数据报在路由器消耗掉的一段时间。
若数据报在路由器消耗的时间小于 1 秒,就把TTL值减 1。
当 TTL值为 0时,就丢弃这个数据报。
⑨协议:占 8 位,协议字段指出此数据报携带的数据是使用何种协议,以便使目的主机的IP层知道应将数据部分上交给哪个处理过程。
⑩首部检验和:占 16位。这个字段只检验数据报的首部,
但不包括数据部分。这是因为数据报每经过一个路由器,都要重新计算一下首都检验和 (一些字段,如生存时间、标志、片偏移等都可能发生变化)。不检验数据部分可减少计算的工作量。
⑾源地址:占32位。
⑿目的地址:占 32位。
下面就IP包的具体协议及报文结构类型进行相关介绍分析。
1. UDP是一个非常简单的协议,除了运输层协议能够做的最少的工作,除了提供进程到进程之间的通信,几乎没对IP增加任何东西。数据报的长度是指包括报头和数据部分在内的总字节数。因为报头的长度是固定的,所以该域主要被用来计算可变长度的数据部分。数据报的最大长度根据操作环境的不同而各异。
2. 传输控制协议(TCP,Transmission Control Protocol)就是为了在不可靠的互联网上提供一个可靠的端到端、面向字节流连接设计的。它提供了面向连接的服务、全双工服务和字节流传递服务。应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP和UDP都具有端口号,而且它们对端口号的使用是彼此独立的。这就是说,同一个端口号可以用两种不同的用途。其中TCP建立连接之后,通信双方都同时可以进行数据的传输,其次,他是全双工的;在保证可靠性上,采用超时重传和捎带确认机制。TCP报文是TCP层传输的数据单元,也称为报文段。
课程设计分析
实现IP数据包接收和判断功能的核心代码如下:
/ 定义IP头部
typedef struct IPHeader
{
unsigned char Version_HeaderLength; // 版本(4位)+首部长度(4位)
unsigned char TypeOfService; // 服务类型
unsigned short TotalLength; // 总长度
unsigned short Identification; // 标识
unsigned short Flags_FragmentOffset; // 标志(3位)+分片偏移(13位)
unsigned char TimeToLive; // 生存时间
unsigned char Protocal; // 协议
unsigned short HeaderChecksum; // 首部校验和
unsigned long SourceAddress; // 源IP地址
unsigned long DestAddress; // 目的IP地址
};
#defie BUFFER_SIZE 65535
Char buffer[BUFFER_SIZE];
CNodelist IpList;
While(捕获时间没有结束)
{
Int npacketsize=recv(sock,buffer,BURRER_SIZE,0);
If(npacktsize>0)
{
IPHEADR * PIPHDR;
PIPHdr=(IPHEADER*) buffer;
If (PIPHdr->SourceAddress==addr_in.sin_addr.s_un.s_addr
||PIPHdr->DestAddress==addr_in.sin_addr.s_un.s_addr)
{
IPList.addNode(PIPHdr->sourceAddress,
PIPHdr->DestAddress,PIPHdr->protocol);
}
}
定义一个结合类CIPNOde,存放IP包的源地址,目的地址,协议类型和不同那个源,目的主机之间不同类型的IP数据包的数量
class CIPNode
{
private:
unsigned long m_dwSourIPAddr; // 源IP地址
unsigned long m_dwDestIPAddr; // 目的IP地址
unsigned char m_chProtocol; // IP包的协议类型
unsigned long m_dwCouter; // 数据包的数量
public:
CIPNode * pNext; // 指向下一类IP结点
CIPNode::CIPNode(unsigned long dwSourIP,unsigned long dwDestIP,unsigned char chPro)
{
m_dwSourIPAddr = dwSourIP;
m_dwDestIPAddr = dwDestIP;
m_chProtocol = chPro;
m_dwCouter = 1; // 初始化数据包个数为1
}
// 增加数据包的数量
void CIPNode::addCount()
{
m_dwCouter++;
}
// 取得数据包数量
unsigned long CIPNode::getCount()
{
return m_dwCouter;
}
// 取得源IP地址
unsigned long CIPNode::getSourIPAddr()
{
return m_dwSourIPAddr;
}
// 取得目的IP地址
unsigned long CIPNode::getDestIPAddr()
{
return m_dwDestIPAddr;
}
// 取得协议类型
unsigned char CIPNode::getProtocol()
{
return m_chProtocol;
}
定义一个结合链表类CNOdelist,存储所捕获的所有数据报信息。
Class CNOdelist
{
Private:
CIPNOde*PHead;
CIPNOde*PTAil;
Public:
CNodeList(){pHead=PTail=NULL;}
~CNodeList()
{
// 删除链表中所有结点
if (pHead != NULL)
{
CIPNode * pTemp = pHead;
pHead = pHead->pNext;
delete pTemp;
}
}
// 把新捕获的IP数据包加入链表
void CNodeList::addNode(unsigned long dwSourIP,unsigned long dwDestIP,unsigned char chPro)
{
if (pHead == NULL) // 链表空
{
pTail = new CIPNode(dwSourIP,dwDestIP,chPro);
pHead = pTail;
pTail->pNext = NULL;
}
else // 链表不空时
{
CIPNode * pTemp;
for(pTemp = pHead; pTemp; pTemp = pTemp->pNext)
{
// 如果链表中已存在该类型的IP包,则数据包个数加1
if (pTemp->getSourIPAddr() == dwSourIP &&
pTemp->getDestIPAddr() == dwDestIP &&
pTemp->getProtocol() == chPro)
{
// 数据包个数加1
pTemp->addCount();
break;
}
}
// 如果链表中不存在该类型的IP包,则创建新的结点加入链表
if (pTemp == NULL)
{
pTail->pNext = new CIPNode(dwSourIP,dwDestIP,chPro);
pTail = pTail->pNext;
pTail->pNext = NULL;
}
}
}
整个程序核心代码:
void main(int argc,char * argv[])
{
// 判断输入的命令行格式是否正确
if (argc != 2)
{
cout << "请按以下格式输入命令行: IPMonitor duration_time"
<< endl << " 其中duration_time为监控时间, 单位为秒"<
h_addr_list[0]; // 设定IP地址
addr_in.sin_family = AF_INET; // 设定地址类型
addr_in.sin_port = htons(8000); // 设定端口
// 把原始套接字绑定到本机地址上
if(bind(sock,(PSOCKADDR)&addr_in,sizeof(addr_in)) == SOCKET_ERROR)
{
cout << "Bind failed!" << endl;
return;
}
// 把网卡设置为混杂模式,以便接收所有的IP包
#define IO_RCVALL _WSAIOW(IOC_VENDOR,1)
unsigned long pBufferLen[10];
unsigned long dwBufferInLen = 1;
unsigned long dwBytesReturned = 0;
if ((WSAIoctl(sock, IO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), &pBufferLen,
sizeof(pBufferLen), &dwBytesReturned, NULL, NULL)) == SOCKET_ERROR)
{
cout<<"Ioctlsocket failed!"<= dwDuration)
{
break;
}
// 捕获经过网卡的IP数据包
int nPacketSize = recv(sock,pBuffer,BURRER_SIZE,0);
if (nPacketSize > 0)
{
IPHEADER * pIpHdr;
// 通过指针把缓冲区中的内容强制转换为IPHEADER数据结构
pIpHdr = (IPHEADER *)pBuffer;
// 判断IP包的源IP地址或目的IP地址是否为本地主机的IP地址
if (pIpHdr->SourceAddress == addr_in.sin_addr.S_un.S_addr
|| pIpHdr->DestAddress == addr_in.sin_addr.S_un.S_addr)
{
// 如果源IP地址或目的IP地址是本机IP,则将该IP数据包加入链表
IpList.addNode(pIpHdr->SourceAddress, pIpHdr->DestAddress, pIpHdr->Protocal);
}
}
}
// 输出统计结果
cout << "IP数据包统计结果: (" << dwDuration << " 秒)"<< endl << endl;
IpList.print(cout);
cout << endl;
return;
}
// Default constructor
CIPNode::CIPNode()
{
}
// Default destructor
CIPNode::~CIPNode()
{
}
CIPNode::CIPNode(unsigned long dwSourIP,unsigned long dwDestIP,unsigned char chPro)
{
m_dwSourIPAddr = dwSourIP;
m_dwDestIPAddr = dwDestIP;
m_chProtocol = chPro;
m_dwCouter = 1; // 初始化数据包个数为1
}
// 增加数据包的数量
void CIPNode::addCount()
{
m_dwCouter++;
}
// 取得数据包数量
unsigned long CIPNode::getCount()
{
return m_dwCouter;
}
// 取得源IP地址
unsigned long CIPNode::getSourIPAddr()
{
return m_dwSourIPAddr;
}
// 取得目的IP地址
unsigned long CIPNode::getDestIPAddr()
{
return m_dwDestIPAddr;
}
// 取得协议类型
unsigned char CIPNode::getProtocol()
{
return m_chProtocol;
}
// 取得协议名称
char * CIPNode::getProtocol_String()
{
switch(m_chProtocol)
{
case 1:
return "ICMP";
break;
case 2:
return "IGMP";
break;
case 4:
return "IP in IP";
break;
case 6:
return "TCP";
break;
case 8:
return "EGP";
break;
case 17:
return "UDP";
break;
case 41:
return "IPv6";
break;
case 46:
return "RSVP";
break;
case 89:
return "OSPF";
break;
default:
return "UNKNOWN";
}
}
// Default constructor
CNodeList::CNodeList()
{
pHead = pTail = NULL;
}
// Default destructor
CNodeList::~CNodeList()
{
// 删除链表中所有结点
if (pHead != NULL)
{
CIPNode * pTemp = pHead;
pHead = pHead->pNext;
delete pTemp;
}
}
// 把新捕获的IP数据包加入链表
void CNodeList::addNode(unsigned long dwSourIP,unsigned long dwDestIP,unsigned char chPro)
{
if (pHead == NULL) // 链表空
{
pTail = new CIPNode(dwSourIP,dwDestIP,chPro);
pHead = pTail;
pTail->pNext = NULL;
}
else // 链表不空时
{
CIPNode * pTemp;
for(pTemp = pHead; pTemp; pTemp = pTemp->pNext)
{
// 如果链表中已存在该类型的IP包,则数据包个数加1
if (pTemp->getSourIPAddr() == dwSourIP &&
pTemp->getDestIPAddr() == dwDestIP &&
pTemp->getProtocol() == chPro)
{
// 数据包个数加1
pTemp->addCount();
break;
}
}
// 如果链表中不存在该类型的IP包,则创建新的结点加入链表
if (pTemp == NULL)
{
pTail->pNext = new CIPNode(dwSourIP,dwDestIP,chPro);
pTail = pTail->pNext;
pTail->pNext = NULL;
}
}
}
// 输出链表
ostream& CNodeList::print(ostream & out)
{
CIPNode * pTemp;
if(pHead == NULL)
{
out << "没有捕获到IP数据包!" << endl;
}
else
{
out << "源地址 " << '\t' << "目的地址" << '\t' << "协议类型 " << "数据包数量" <pNext)
{
unsigned long dwSourTemp = pTemp->getSourIPAddr();
unsigned long dwDestTemp = pTemp->getDestIPAddr();
out << inet_ntoa(*(in_addr *)&(dwSourTemp)) << '\t';
out << inet_ntoa(*(in_addr *)&(dwDestTemp)) << '\t';
out << resetiosflags(ios::right) << setiosflags(ios::left)
<< setfill(' ') << setw(10) << pTemp->getProtocol_String()
<< resetiosflags(ios::left) << setiosflags(ios::right);
out << pTemp->getCount() << endl;
}
}
return out;
}
主程序
流程
快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计
图:
IP包的捕获
通过对IP数据包的分析,我们可以从中得知IP数据包捕获的相关信息,包括捕获时间、IP地址信息、协议类型及数据包相关信息。这些信息是我们进行数据包分析所必需的,在了解了这些信息后,就可以从容的面对网络实际运行状况。
实验结果:
程序运行:
捕获;
===========================================================================
指导教师评语及成绩
【评语】
【成绩】 指导教师签名: 日期: 年 月 日