网络安全程序设计报告.docx

上传人:b****6 文档编号:7582563 上传时间:2023-01-25 格式:DOCX 页数:19 大小:323.93KB
下载 相关 举报
网络安全程序设计报告.docx_第1页
第1页 / 共19页
网络安全程序设计报告.docx_第2页
第2页 / 共19页
网络安全程序设计报告.docx_第3页
第3页 / 共19页
网络安全程序设计报告.docx_第4页
第4页 / 共19页
网络安全程序设计报告.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

网络安全程序设计报告.docx

《网络安全程序设计报告.docx》由会员分享,可在线阅读,更多相关《网络安全程序设计报告.docx(19页珍藏版)》请在冰豆网上搜索。

网络安全程序设计报告.docx

网络安全程序设计报告

基于原始Socket的网络嗅探器

1.概述

本程序使用原始Socket来捕获网络内的数据包,通过将本机的网卡设置为混杂模式,来使得网卡接收网络内的所有数据包,从而将其捕获。

然后,将捕获到的数据包进行拆解,得到数据包内部的信息。

本系统目前支持TCP、UDP、ICMP包的解析。

1.1程序的开发环境

使用的编程语言:

C++

使用的开发工具:

VisualC++6.0

1.2小组成员及分工

2.背景知识

2.1网卡的混杂模式

网卡的工作模式有正常模式和混杂模式两种。

在正常模式下,网卡只接收目的地址是本机的数据包,其他的数据包全部丢弃。

而网卡在混杂模式下,则接收所有经过网卡是数据包。

也就是说,混杂模式时网卡接收所有通过它的数据流,不论是什么格式,什么地址。

具体的地址转发则是在接收到数据后由MAC层来进行。

通常在设计捕获数据包的程序时,均需要将网卡设置为混杂模式。

2.2常用数据报的格式

2.2.1IP数据报

IP数据报是分布于网络层的数据包,提高对网络中主机的地址定位操作。

其中包含了重要的数据信息,包括发送数据包的主机,即源IP地址,接收数据包的主机,即目的IP地址。

以及其他一些IP地址相关的的附加信息。

IP数据报的格式如下:

版本

报文长度

服务类型

总长度

标识符

标志

片偏移

生存时间

协议

报头校验和

源IP地址

目的IP地址

IP选项

2.2.2TCP数据报

TCP向应用程序提供可靠的数据传输服务。

TCP数据报由TCP首部和TCP数据部分组成。

其TCP首部的格式如下:

2.2.3UDP数据报

UDP向应用程式提供无连接的数据传输。

虽然UDP是数据传输可靠性不如TCP,但其资源占用少,传输速度快,使得其在某些场合使用十分适合。

例如,传输零星数据,简单的文本传输等。

UDP数据报的首部仅仅有4个16位的字段,它们分别是UDP源端口,UDP目的端口,UDP数据报长度及校验和。

UDP头部格式:

UDP源端口号(16位)

UDP目的端口号(16位)

UDP长度(16位)

UDP校验和(16位)

2.2.4ICMP数据报

ICMP是传输控制信息的报文,例如差错信息控制,目的地是否可达的信息等。

标准的ICMP报文只有4个字节,但是在其多种控制报文中又有4个字节的控制信息,因此在ICMP的报文头部中应该加入该字段。

ICMP头部的格式

类型(8位)

代码(8位)

校验和(16位)

控制信息(32位)

3.程序流程图

3.1程序总体流程图

图3.1程序主体流程图

3.2程序创建套接字部分流程图

图3.2创建套接字流程图

3.3程序拆包部分流程图

图3.3拆包部分流程图

4.程序实现

4.1程序中的重要函数

4.1.1创建原始套接字

m_Sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);

socket()函数用于创建原始套接字,其中相关的参数说明如下:

AF_INET:

设置套接字地址家族为TCP/IP地址家族

SOCK_RAW:

设置套接字为原始套接字

IPPROTP_IP:

设置套接字接收数据包,为IP层的数据包

4.1.2设置套接字的工作方式,为混杂模式

WSAIoctl(m_Sock,SIO_RCVALL,&inBuffer,sizeof(inBuffer),&outBuffer,sizeof(outBuffer),&reValue,NULL,NULL)

WSAIoctl()函数用于设置网卡的工作模式位混杂模式,在此模式下网卡可以接受所经过网卡的数据包。

WSAIoctl()函数的相关参数说明如下:

m_Sock:

传入参数,标识一个套接字

SIO_RCVALL:

网卡的工作模式,混杂模式

&inBuffer:

设置输入的缓冲区

Sizeof(inBuffer):

输入缓冲区的大小

&outBuffer:

设置输出缓冲区

Sizeof(outBuffer):

输出缓冲区的大小

&revalue:

传出参数,指向函数实际返回的字节数的地址

NULL:

传入参数,WSAOVERLAPPED结构的地址

NULL:

传入参数,一个指向操作结束调用的例程指针。

4.1.3接收数据包

ret=recv(pDlg->m_Sock,buffer,1000,0)

recv()函数用于接收经过网卡的数据包。

其相关参数说明如下:

pDlg->m_Sock:

接收使用的特定套接字

buffer:

缓冲区

1000:

缓冲区的大小

0:

其接收模式为正常接收

4.2程序中的重要数据结构

4.2.1IP头部结构

typedefstructHeadIP{

unsignedcharheaderlen:

4;

unsignedcharversion:

4;

unsignedcharservertype;

unsignedshorttotallen;

unsignedshortid;

unsignedshortidoff;

unsignedcharttl;

unsignedcharproto;

unsignedshortchecksum;

unsignedintsourceIP;

unsignedintdestIP;

}HEADIP;

相关参数说明如下:

headerlen:

首部长度,占4位

version:

版本号,占4位

severtype:

服务类型,占8位

totallen:

总长度,占16位

id:

标识

idoff:

与上面的id共同构成标识,共占16位

ttl:

生存时间,占8位

proto:

协议,占8位

checksum:

首部校验和,占16位

sourceIP:

源IP地址,占32位

destIP:

目的IP地址,占32位

4.2.2TCP头部结构

typedefstructHeadTCP{

WORDSourcePort;

WORDDePort;

DWORDSequenceNo;

DWORDConfirmNo;

BYTEHeadLen;

BYTEFlag;

WORDWndSize;

WORDCheckSum;

WORDUrgPtr;

}HEADTCP;

相关参数说明如下:

SourcePort:

源端口号,占16位

DePort:

目的端口号,占16位

SequenceNO:

序号,占32位

ConfirmNO:

确认序号,32位

HeadLen:

首部长度

Flag:

与HeadLen组成一个部分,占16位

WndSize:

窗口大小,占16位

Checksum:

校验和,占16位

UrgPtr:

紧急指针,占16位

4.2.3UDP头部结构

typedefstructHeadUDP{

WORDSourcePort;

WORDDePort;

WORDLen;

WORDChkSum;

}HEADUDP;

相关参数说明如下:

SourcePort:

源端口号,占16位

DePort:

目的端口号,占16位

Len:

UDP长度,占16位

Chksum:

UDP校验和,占16位

4.2.4ICMP头部结构

typedefstructHeadICMP{

BYTEType;

BYTECode;

WORDChkSum;

IntControl;

}HEADICMP;

相关参数说明:

Type:

类型,占8位

Code:

代码,占8位

Chksum:

校验和,占16位

Control:

控制信息,占32位

4.2.5协议封装结构

structPROTONAME{

intvalue;

char*protoname;

};

相关参数说明如下:

Value:

协议对于的常量值

Protoname:

协议的名称

5.程序界面

5.1程序主界面

图5.1程序主界面

程序主界面上显示了如下信息:

一个列表框,显示了如下内容:

协议名称,源IP地址,目的IP地址,源端口,目的端口,数据包大小,以及数据。

两个按钮:

开始监听按钮:

单击按钮开始监听网卡上的数据包

取消按钮:

单击按钮停止监听,并推出程序

5.2程序运行界面

图5.2程序运行界面

6.程序功能结构图

图6.1程序功能结构图

7.程序主体函数

7.1初始化套接字AfxSocketInit()

WSADATAdata;

AfxSocketInit(&data);

AfxSocketInit()函数加载套接字,可以在程序推出时,自动关闭套接字。

7.2监听函数OnBeginlisten()

voidCSniffAppDlg:

:

OnBeginlisten()

{

//创建套接字,原始套接字

m_Sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);

charname[128];

memset(name,0,128);

hostent*phostent;//hostent标识主机信息的结构体,gethostbyname的返回值类型

phostent=gethostbyname(name);

DWORDip;

ip=inet_addr(inet_ntoa(*(in_addr*)phostent->h_addr_list[0]));//inet_addr将点分十进制的IP转换为网络字节序

//inet_ntoa将网络字节序的IP转换为点分十进制的IP,

inttimeout=4000;//超时4秒

//设置接收数据的超时时间

setsockopt(m_Sock,SOL_SOCKET,SO_RCVTIMEO,(constchar*)&timeout,sizeof(timeout));

sockaddr_inskaddr;

skaddr.sin_family=AF_INET;

skaddr.sin_port=htons(700);

skaddr.sin_addr.S_un.S_addr=ip;

//绑定地址

if(bind(m_Sock,(sockaddr*)&skaddr,sizeof(skaddr))==SOCKET_ERROR)

{

MessageBox("地址绑定错误");

return;

}

DWORDinBuffer=1;

DWORDoutBuffer[10];

DWORDreValue=0;

//WSAIoctl设置套接口的工作方式,SIO_RCVALL为混杂模式

if(WSAIoctl(m_Sock,SIO_RCVALL,&inBuffer,sizeof(inBuffer),&outBuffer,sizeof(outBuffer),&reValue,NULL,NULL)==SOCKET_ERROR)

{

MessageBox("设置缓冲区错误.");

closesocket(m_Sock);

return;

}

else

m_pThread=AfxBeginThread(ThreadFun,(void*)this);//启动接收线程

}

OnBeginListen()函数响应“开始监听”按钮的消息,执行监听功能。

7.3拆包线程函数ThreadFun()

UINTThreadFun(LPVOIDpParam)

{

CSniffAppDlg*pDlg=static_cast(pParam);

MSGmsg;//PeekMessage消息的参数

charbuffer[1000],sourceip[32],*tempbuf;//设置缓冲区和源iP

char*ptemp;

BYTE*pData=NULL;//实际数据报中的数据

UINTsourceport;

UINTdeport;//增加的目的端口

CStringstr;//向列表中增加数据时,格式化非法数据

HEADIP*pHeadIP;

HEADICMP*pHeadICMP;

HEADUDP*pHeadUDP;

HEADTCP*pHeadTCP;

in_addraddr;//该结构体表示一个32位的IP地址

intret;//错误检测函数的返回值

while(TRUE)

{

pData=NULL;

//接收主窗体发来的消息,来退出死循环

if(PeekMessage(&msg,pDlg->m_hWnd,WM_CLOSE,WM_CLOSE,PM_NOREMOVE))

{

closesocket(pDlg->m_Sock);

break;

}

memset(buffer,0,1000);

 

ret=recv(pDlg->m_Sock,buffer,1000,0);//recv为有连接的接收数据函数,0为接收模式,正常接收

if(ret==SOCKET_ERROR)

{

continue;

}

else//接收到数据

{

tempbuf=buffer;

pHeadIP=(HEADIP*)tempbuf;//提取IP头信息

//获取数据报总长度

//WORDlen=ntohs(pHeadIP->totallen);//2字节网络字节序转化为主机字节序

//获取源IP

pDlg->m_List.InsertItem(pDlg->m_List.GetItemCount(),"");

addr.S_un.S_addr=pHeadIP->sourceIP;

ptemp=inet_ntoa(addr);

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,1,ptemp);

//获取目的IP

addr.S_un.S_addr=pHeadIP->destIP;

ptemp=inet_ntoa(addr);

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,2,ptemp);

//获取协议名称

ptemp=get_protoname(pHeadIP->proto);

strcpy(sourceip,ptemp);

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,0,sourceip);

//获取IP数据报总长度

WORDipSumLen=ntohs(pHeadIP->totallen);

//IP数据报头总长度

intipHeadLen=20;//IP头定义为20字节

//获得去除IP层数据的长度

WORDnetlen=ipSumLen-ipHeadLen;

//根据不同大协议获得不同协议的数据

switch(pHeadIP->proto)

{

caseIPPROTO_ICMP:

{

pHeadICMP=(HEADICMP*)(tempbuf+20);//Ip头为20字节

pData=(BYTE*)(pHeadICMP)+4;//ICMP数据报头共4个字节

//获取数据的长度

netlen-=4;

break;

}

caseIPPROTO_UDP:

{

pHeadUDP=(HEADUDP*)(tempbuf+20);

pData=(BYTE*)pHeadUDP+8;//UDP数据报头共8个字节

sourceport=ntohs(pHeadUDP->SourcePort);

str.Format("%d",sourceport);

//设置源端口

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,3,str);

str.Empty();

deport=ntohs(pHeadUDP->DePort);

str.Format("%d",deport);

//设置目的端口

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,4,str);

str.Empty();

netlen-=8;

break;

}

caseIPPROTO_TCP:

{

pHeadTCP=(HEADTCP*)(tempbuf+20);

sourceport=ntohs(pHeadTCP->SourcePort);

pData=(BYTE*)pHeadTCP+20;//TCP数据报头共20个字节

str.Format("%d",sourceport);

//设置源端口

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,3,str);

str.Empty();

str.Format("%d",deport);

//设置目的端口

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,4,str);

str.Empty();

netlen-=20;

break;

}

}

//设置数据大小

str.Format("%d",netlen);

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,5,str);

str.Empty();

//设置数据

if(pData!

=NULL)

{

str.Format("%s",pData);

pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,6,str);

}

str.Empty();

pDlg->ShowInfo();

}

}

return0;

ThreadFun()函数用于接收网卡上的数据包,并进行拆包,将其中的消息提取出来。

以显示在列表框中。

7.4获取协议函数get_protoname()

PROTONAMEprotos[11]={

{IPPROTO_IP,"IP"},

{IPPROTO_ICMP,"ICMP"},

{IPPROTO_IGMP,"IGMP"},

{IPPROTO_GGP,"GGP"},

{IPPROTO_TCP,"TCP"},

{IPPROTO_PUP,"PUP"},

{IPPROTO_UDP,"UDP"},

{IPPROTO_IDP,"IDP"},

{IPPROTO_ND,"ND"},

{IPPROTO_RAW,"RAW"},

{IPPROTO_MAX,"MAX"}

};

char*get_protoname(intprotoID)

{

for(inti=0;i<11;i++)

if(protoID==protos[i].value)

{

returnprotos[i].protoname;

}

return"";

}

get_protoname()函数用于获取数据包协议的名称,从而按照特定的方式解析协议。

而protos[]数组则是封装了常见的网络协议。

包括IP、TCP、UDP、ICMP等。

 

8.程序设计心得

本次程序设计是一个简单的网络嗅探器。

这个嗅探器是基于原始套接字的。

其能捕获网络层的数据包,并且通过拆包来获取其中的包内容信息。

程序设计的过程中,遇到了一下困难,其中一个就是拆包部分的问题。

数据指针如何提取数据包中的数据,又如何从控制数据指针的移动,找到相应的数据包的其他部分的信息。

后来,通过对该部分进行一下合理的算法设计,得到了一个好的拆包方法。

这样这个问题才得到解决。

此外,还遇到了其他许多问题,在小组成员的共同努力下,问题都最终得到了解决。

当然,程序中还是存在很多不足,例如,执行拆包功能的线程不能随时终止,要停线程,必须退出程序。

可能,其中还存在有未知的bug和问题,这些待进一步的完善。

另外,程序的功能上还是不够。

可以进一步的扩充,例如增加对其他数据包解析的支持,增加解析数据的保持功能,增加对数据的分析功能等。

总之,程序还是完成了基本的功能,其中的不足待在进一步的学习中来提高和完善。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 生产经营管理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1