资源描述
学 院
信息科学与工程学院
专 业
计算机科学与技术
姓 名
XXX
学 号
题 目
监控IP包流量
内容及要求:
编制程序,监控网络,捕获一段时间内网络上的IP数据包,按IP数据包的源地址统计出该源地址在该时间段内发出的IP包的个数,将其写入日志文件或用图形表示出来(建议用图形表示统计结果)。
程序的具体要求如下:
用命令行运行:IPstatistic time logfile
其中,IPstatistics是程序名,time是设定的时间间隔(单位为分钟,比如,2表示2分钟);logfile表示统计结果写入的日志文件名(若用图形表示统计结果则可以不选这个参数)
Windows Xp,CodeBlocks 10.05
进度安排:
第16周
星期一:设计任务分析和总体设计
星期二:软件算法和流程设计
星期三,四,五:软件编码实现
第17周
周一:软件总体调试
周二:软件运行分析
周三:答辩,验收程序
周四:答辩,验收程序
周五:书写课程设计报告,提交
指导教师(签字):
年 月 日
学院院长(签字):
年 月 日
课程设计任务书
目 录
1 题目内容及设计要求 1
2 总体设计 1
2.1 总体功能框图 1
2.2 类的设计说明 1
2.3 主要算法流程图 3
3 程序清单及注释 3
4 运行结果与分析 10
5 总结 12
6 参考文献 12
1 题目内容及设计要求
题目8监控IP包流量
编制程序,监控网络,捕获一段时间内网络上的IP数据包,按IP数据包的源地址统计出该源地址在该时间段内发出的IP包的个数,将其写入日志文件或用图形表示出来(建议用图形表示统计结果)。
程序的具体要求如下:
用命令行运行:IPstatistic time logfile
其中,IPstatistics是程序名,time是设定的时间间隔(单位为分钟,比如,2表示2分钟);logfile表示统计结果写入的日志文件名(若用图形表示统计结果则可以不选这个参数)。
2 总体设计
2.1 总体功能
1.课程设计中的重点及难点
1)程序中会用到Winpcap,Wiinpcap的介绍请参阅附录B.
2 ) 列出网卡列表,让用户进行选择可用的网卡。
3)注意过滤器的使用,只需捕获IP包,别的包都过滤掉。
2.参考算法
1)取得当前网络设备列表(在标准输出上显示,以让用户进行选择)。
2)将用户选择的Ethernet卡以混杂模式打开,以接收到所有的数据包。
3)设置过滤器,此处的过滤器“IP”。
3 ) 捕获IP包并按包的源地址进行统计(用链表结构进行实现)。
2.2 类的设计说明
IP包头部结构:
Struct ip_header
{
unsigned char ver_ihl; //版本号(4位)+头部长度(4位)
unsigned char tos; //服务类型
unsigned short tlen; //总长度
unsigned short flag_fo; //标志+片偏移
unsigned char ttl; //生存时间
unsigned char proto; //协议
unsigned short crc; //校验和
DOWORD saddr; //源地址
DOWORD daddr; //目的地址
unsigned char int op_pad; //选项+填充
};
1) 选择网卡。
//选择一个Enthernet卡
for(d=alldevs;d;d=d->name)
{ If(d->addresses!=NULL)
{ i++; if(head==NULL) head=d; }
}
2) 给出网卡列表,让用户选择。
for(d=alldevs;d;d=d->next) //列出网卡列表,让用户进行选择
{ cout<<++j<<”:”<<d->name;
if(d->description) cout<<” ”<<d->description<<endl;
}
3) 以混杂模式打开网卡。
if((fp=pcap_open_live(head->name,1000,1,1000,erbuff))==NULL)
{ cout<<”\n Unable to open the adapter.”<<endl;
pcap_freealldevs(alldevs); return;
}
4) 编译过滤器并设置过滤器。
if(pcap_compile(fp,&fcode,packet_filter,1,netmask)<0)
{ cout<<”\n Unable to compile the packet filter.Check the syntax.\n”<<endl;
pcap_freealldevs(alldevs); return;
}
5) 在给定的时间内循环捕获IP数据包,并将该包的源地址加入链表。
while((res=pcap_next_ex(fp,&fcode))>=0)
{ time (&end); //获取系统时间
if(end->beg>=min*60) //计算统计时间
if(res==0) continue; //超时
ip_header *ih; //找到IP头的位置
ih=(ip_header *) (pkt_data+14); //14为Enthernet头的长度
link.addNode(ih->saddr); //将源IP地址加入链表
}
6)输出链表的内容。
2.3 主要算法流程图
主要算法流程图如图2-4所示。
获取网卡列表
选择Ethernet网卡
打开网卡(混杂模式)
编译设置过滤器
捕获IP包
将IP包源地址加入链表
超时否?
输出链表内容
结束
开始
Y
N
图2-4程序流程图
3 程序清单及注释
#ifndef IPNODELIST_H_INCLUDED
#define IPNODELIST_H_INCLUDED
#endif // IPNODELIST_H_INCLUDED
//(1)程序中使用的链表(以头文件IPNodeList.h的形式给出):
//IP结点类,存放IP包的源IP地址和其发送的数据包个数
class IPNode
{
private:
long m_lIPAddress; //IP地址
long m_lCount; //发送数据包数
public:
IPNode *pNext; //指向下一个IP结点
IPNode(long sourceIP) //构造函数
{
m_lIPAddress=sourceIP;
m_lCount=1; //初始化数据包个数为1
} //数据包个数加1
void addCount()
{
m_lCount++;
} //返回数据包个数
long getCount()
{
return m_lCount;
}
//返回IP地址
long getIPAddress()
{
return m_lIPAddress;
}
};
//结点链表
class NodeList
{
IPNode *pHead; //链表头
IPNode *pTail; //链表尾
public:
NodeList()
{
pHead=pTail=NULL;
}
~NodeList()
{
if(pHead!=NULL)
{
IPNode *pTemp=pHead;
pHead=pHead->pNext;
delete pTemp;
}
}
//IP结点加入链表
void addNode(long sourceIP)
{
if(pHead==NULL) //当链表为空时
{
pTail=new IPNode(sourceIP);
pHead=pTail;
pTail->pNext=NULL;
}
else //不为空时
{
for(IPNode *pTemp=pHead;pTemp;pTemp=pTemp->pNext)
{
//如果链表中存在此IP,发送数据包个数加1
if(pTemp->getIPAddress()==sourceIP)
{
pTemp->addCount();
break;
}
}
//如果链表中没有此IP,则加入链表
if(pTemp==NULL)
{
pTail->pNext=new IPNode(sourceIP);
pTail=pTail->pNext;
pTail->pNext=NULL;
}
}
}
//输出IP结点,即IP地址和其发送的IP包个数
ostream& print(ostream & out)
{
for(IPNode* pTemp=pHead;pTemp;pTemp=pTemp->pNext)
{
long lTemp=pTemp->getIPAddress();
out<<inet_ntoa(*(in_addr*)&(lTemp))<<'\t';
out<<pTemp->getCount()<<endl;
}
return out;
}
};
//主程序如下:
#include<iostream>
#include<iomanip>
#include<fstream>
#include<stdlib.h>
#include<stdio.h>
#include<conio.h>
#include "pcap.h"
#include "IPNodeList.h"
#pragma comment(lib,"Wpcap.lib")
#pragma comment(lib,"Ws2_32.lib")
//IP包的头部结构
struct ip_header
{
unsigned char ver_ihl; //版本号(4位)+头部长度(4位)
unsigned char tos; //服务类型
unsigned short tlen; //总长度
unsigned short identification; //标识
unsigned short flags_fo; //标志+片偏移
unsigned char ttl; //生存时间
unsigned char proto; //协议
unsigned short crc; //校验和
DWORD saddr; //源地址
DWORD daddr; //目的地址
unsigned int op_pad; //选项+填充
};
void main(int argc,char *argv[])
{
if(argc!=3) //判断参数是否正确
{
cout<<"Usage:IPStatistic time logfile"<<endl;
cout<<"Press any key to continue..."<<endl;
_getch();
return;
}
double min=atof(argv[1]);
pcap_if_t *alldevs; //网络设备结构
pcap_if_t *d,*head=NULL;
pcap_t *fp; //网卡描述
char errbuf[PCAP_ERRBUF_SIZE]; //错误信息
unsigned int netmask; //子网掩码
char packet_filter[]="ip"; //过滤,选择IP协议
struct bpf_program fcode;
struct pcap_pkthdr *header;
const unsigned char *pkt_data;
//获取网络设备列表
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
cout<<"Error in pcap_findalldevs:"<<errbuf;
return;
}
int i=0; //网卡数
if(i==0) //无设备
{
cout<<"\nNO interfaces found! Make sure WinPcap is installed.\n";
return;
}
if(i>=1)
{
int j=0;
for(d=alldevs;d;d=d->next) //列出网卡列表,让用户进行选择
{
cout<<++j<<":"<<d->name;
if(d->description)
cout<<" "<<d->description<<endl;
}
cout<<"\nEnter the interface number (1-"<<j<<"):";
int k;
cin>>k;
if(k<1||k>j)
{
cout<<"out of range"<<endl;
return;
}
for(d=alldevs,i=1;i<k;d=d->next,i++); //找到选择的网卡
head=d;
} //以混杂模式方式打开网卡
if((fp=pcap_open_live(head->name,1000,1,1000,errbuf))==NULL)
{
cout<<"\nUnable to open the adapter."<<endl;
pcap_freealldevs(alldevs);
return;
} //获得子网掩码
if(head->addresses != NULL)
netmask=((struct sockaddr_in*)
(head->addresses->netmask))->sin_addr.S_un.S_addr;
else //没有地址则假设为C类地址
netmask=0xffffff; //编译过滤器
if(pcap_compile(fp, &fcode,packet_filter,1,netmask)<0)
{
cout<<"\nUnable to compile the packet filter.Cheak the syntex.\n";
pcap_freealldevs(alldevs);
return;
} //设置过滤器
if(pcap_setfilter(fp,&fcode)<0)
{
cout<<"\nError setting the filter.\n";
pcap_freealldevs(alldevs);
return;
} //显示提示信息及每项含义
cout<<"\t\tlistening on "<<head->description<<"..."<<endl<<endl;
ofstream fout(argv[2],ios::app); //日志记录文件
fout<<"\tIP Statistic:("<<min<<" minutes)"<<endl;
time_t tmp=time(NULL);
fout<<ctime(&tmp);fout<<"\tIP Statistic:("<<min<<" minutes)"<<endl;
fout<<"IP Statistic:("<<min<<" minutes)"<<endl;
fout<<" Sour IP "<<"\tpacket numbers"<<endl;
//释放设备列表
pcap_freealldevs(alldevs);
NodeList link; //存储数据用链表
int res;
time_t beg;
time_t end;
time(&beg); //获得当前时间
while((res=pcap_next_ex(fp, &header, &pkt_data)) >=0)
{
time(&end); //获得系统时间
if(end-beg>=min*60) //计算系统时间
break;
if(res==0)
continue; //超时
ip_header *ih; //找到IP头的位置
ih = (ip_header *) (pkt_data+14); //14为以太头的长度
link.addNode(ih->saddr); //将源IP地址加入链表
}
cout<<"Sour IP "<<'\t'<<"packet numbers"<<endl;
link.print(cout); //输出到屏幕
link.print(fout); //输出到日志文件
fout<<endl;
}
4 运行结果与分析
图4-2 运行结果图
5 总结
随着Internet技术的发展,基于IP协议的网络应用成为网络技术研究与软件开发的一个重要基础,因此学习网络层的基本概念,了解IP协议的基本内容,对于掌握TCP/IP协议的主要内容和学习网络课程是十分重要的。通过本实验课程设计,有助于熟悉IP包格式和加深对IP协议的理解。
6 参考文献
[1]李爱华,程磊著. 面向对象程序设计(C++语言) 北京:清华大学出版社,2010
[2]钱能. C++程序设计教程.第二版. 北京: 清华大学出版社,2005
[3]宋凯,刘念著. 计算机网络 北京:清华大学出版社,2010
展开阅读全文