1.课程设计要求:
1)解析IP数据包
课程设计的目的就是设计一个解析IP数据包的程序,并根据这个程序,说明IP数据包的结构及IP协议的相关问题,从而对IP层的工作原理有更好的理解和认识。本设计的目标是捕获网络中的IP数据包,解析数据包的内容,将结果显示在标准输出上,并同时写入日志文件。
2)解析ARP数据包
课程设计的目的是对网络上的ARP数据包进行分析,从而熟悉ARP数据包的结构,对ARP协议有更好的理解和认识。要求编写一程序,获取网络中的ARP数据包,解析数据包的内容,将结果显示在标准输出上,并同时写入日志文件。
2.设计原理
Ip数据报通过winpcap中的过滤器编译设置后可以直接捕获出来,然后按照其首部不同字节数,利用结构体将IP数据报首部内容分别解析出来,并写入日志文件中。IP数据包首部部分如下所示:
ARP主要作用就是通过IP地址来获取MAC地址。那么怎样获取呢?本机向局域网内主机发送ARP包,ARP包内包含了目的IP,源IP,目的MAC,源MAC,其中目的MAC地址为广播地址,FF-FF-FF-FF-FF-FF,即向局域网内所有主机发送一个ARP请求,那么其他主机收到这个请求之后则会向请求来源返回一个数据包。在这个返回的数据包中包含了自身的MAC地址。那么本机收到这些返回的数据包进行解析之后便会得到局域网内所有主机的MAC地址了。
3.程序设计流程
4.核心代码:
(1)编译和设置过滤器:
if ( pcap_compile ( adhandle, & fcode, packet_filter, 1 , netmask) < 0 )
{
fprintf ( stderr , "\nUnable to compile the packet filter. Check the syntax.\n" ) ;
pcap_freealldevs ( alldevs) ;
return - 1 ;
}
if ( pcap_setfilter ( adhandle, & fcode) < 0 )
{
fprintf ( stderr , "\nError setting the filter.\n" ) ;
pcap_freealldevs ( alldevs) ;
return - 1 ;
}
(2)解析ARP数据包,并写入日志文档
ofstream fout ( argv[ 1 ] , ios:: app) ;
int k= 1 ;
while ( ( res = pcap_next_ex ( adhandle, & header, & pkt_data) ) >= 0 ) {
if ( res == 0 )
continue ;
ArpHeader* arph = ( ArpHeader * ) ( pkt_data + 14 ) ;
printf ( "----------------------------解析到的第%d个ARP数据包-----------------------------\n" , k) ;
fout<< "----------------------------解析到的第" << k<< "个ARP数据包-----------------------------\n" ;
printf ( "报文类型:" ) ;
if ( arph- > op == 256 ) {
printf ( "请求报文\t" ) ;
fout<< "请求报文\t" ;
}
else {
printf ( "应答报文\t" ) ;
fout<< "应答报文\t" ;
}
printf ( "长度(B):%d\t" , header- > len) ;
fout<< "长度(B):" << header- > len<< "\t" ;
local_tv_sec = header- > ts. tv_sec;
ltime = localtime ( & local_tv_sec) ;
strftime ( timestr, sizeof timestr, "%H:%M:%S" , ltime) ;
printf ( "时间:%s\n" , timestr) ;
fout<< "时间:" << timestr<< "\n" ;
printf ( "源IP:" ) ;
for ( i = 0 ; i < 3 ; i++ )
{
printf ( "%d." , arph- > sip[ i] ) ;
fout<< int ( arph- > sip[ i] ) ;
}
printf ( "%d\t" , arph- > sip[ 3 ] ) ;
fout<< "源IP:" << int ( arph- > sip[ 3 ] ) << "\t" ;
printf ( "目的IP:" ) ;
for ( i = 0 ; i < 3 ; i++ )
{
printf ( "%d." , arph- > dip[ i] ) ;
fout<< "目的IP:" << int ( arph- > dip[ i] ) << "." ;
}
printf ( "%d\n" , arph- > dip[ 3 ] ) ;
fout<< int ( arph- > dip[ 2 ] ) << "\n" ;
printf ( "源MAC:" ) ;
for ( i = 0 ; i < 5 ; i++ )
{
printf ( "%02x-" , arph- > smac[ i] ) ;
fout<< int ( arph- > smac[ i] ) << "-" ;
}
printf ( "%02x\t" , arph- > smac[ 5 ] ) ;
fout<< "源MAC:" << int ( arph- > smac[ 5 ] ) << "\t" ;
printf ( "目的MAC:" ) ;
for ( i = 0 ; i < 5 ; i++ )
{
printf ( "%02x-" , * ( pkt_data + i) ) ;
fout<< int ( * ( pkt_data + i) ) << "-" ;
}
printf ( "%02x\n" , * ( pkt_data + 5 ) ) ;
fout<< "目的MAC:" << int ( * ( pkt_data + 5 ) ) << "\n" ;
k++ ;
}
if ( res == - 1 ) {
printf ( "Error reading the packets: %s\n" , pcap_geterr ( adhandle) ) ;
return - 1 ;
}
return 0 ;
}
(3)解析IP数据包:
void ip_protool_packet_callback ( u_char * argument, const struct pcap_pkthdr* packet_header, const u_char* packet_content)
{
struct ip_header * ip_protocol;
u_int header_length = 0 ;
u_int offset;
u_char tos;
u_int16_t checksum;
u_int ip_len;
u_int ip_version;
TcpHeader * tcp;
ip_protocol = ( struct ip_header * ) ( packet_content+ 14 ) ;
ip_len = ( ip_protocol- > Version_HLen & 0xf ) * 4 ;
ip_version = ip_protocol- > Version_HLen>> 4 ;
tcp = ( TcpHeader * ) ( ( u_char * ) ip_protocol+ ip_len) ;
checksum = ntohs ( ip_protocol- > ip_checksum) ;
tos = ip_protocol- > ip_tos;
offset = ntohs ( ip_protocol- > ip_off) ;
printf ( "---------IP协议---------\n" ) ;
printf ( "版本号:%d\n" , ip_version) ;
printf ( "首部长度:%d\n" , ip_len) ;
printf ( "服务质量:%d\n" , tos) ;
printf ( "总长度:%d\n" , ntohs ( ip_protocol- > ip_length) ) ;
printf ( "标识:%d\n" , ntohs ( ip_protocol- > ip_id) ) ;
printf ( "偏移:%d\n" , ( offset & 0x1fff ) * 8 ) ;
printf ( "生存时间:%d\n" , ip_protocol- > ip_ttl) ;
printf ( "协议类型:%d\n" , ip_protocol- > ip_protocol) ;
switch ( ip_protocol- > ip_protocol)
{
case 1 : printf ( "上层协议是ICMP协议\n" ) ; break ;
case 2 : printf ( "上层协议是IGMP协议\n" ) ; break ;
case 6 : printf ( "上层协议是TCP协议\n" ) ; break ;
case 17 : printf ( "上层协议是UDP协议\n" ) ; break ;
default : break ;
}
printf ( "检验和:%d\n" , checksum) ;
printf ( "源IP地址:%s\n" , inet_ntoa ( ip_protocol- > ip_souce_address) ) ;
printf ( "目的地址:%s\n" , inet_ntoa ( ip_protocol- > ip_destination_address) ) ;
}
}
5.结果及分析
1、运行结果:
解析ARP数据包并写入日志文档:
日志文档:
解析IP数据包:
日志文件:
6.完整代码如下:
6.1 解析ARP数据包
#include <fstream.h>
#include <conio.h>
#include "pcap.h"
#include <string>
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"packet.lib")
#pragma comment(lib,"ws2_32.lib")
struct ArpHeader
{
unsigned short hdtyp;
unsigned short protyp;
unsigned char hdsize;
unsigned char prosize;
unsigned short op;
u_char smac[ 6 ] ;
u_char sip[ 4 ] ;
u_char dmac[ 6 ] ;
u_char dip[ 4 ] ;
} ;
int main ( int argc, char * argv[ ] )
{
pcap_if_t * alldevs;
pcap_if_t * d;
int inum;
int i = 0 ;
pcap_t * adhandle;
char errbuf[ PCAP_ERRBUF_SIZE] ;
int res;
u_int netmask;
char packet_filter[ ] = "ether proto \\arp" ;
struct bpf_program fcode;
struct tm * ltime;
char timestr[ 16 ] ;
time_t local_tv_sec;
struct pcap_pkthdr * header;
const u_char * pkt_data;
if ( pcap_findalldevs_ex ( PCAP_SRC_IF_STRING, NULL , & alldevs, errbuf) == - 1 )
{
fprintf ( stderr , "Error in pcap_findalldevs: %s\n" , errbuf) ;
exit ( 1 ) ;
}
for ( d = alldevs; d; d = d- > next)
{
printf ( "%d. %s" , ++ i, d- > name) ;
if ( d- > description)
printf ( " (%s)\n" , d- > description) ;
else
printf ( " (No description available)\n" ) ;
}
if ( i == 0 )
{
printf ( "\nNo interfaces found! Make sure WinPcap is installed.\n" ) ;
return - 1 ;
}
printf ( "Enter the interface number (1-%d):" , i) ;
scanf ( "%d" , & inum) ;
if ( inum < 1 || inum > i)
{
printf ( "\nInterface number out of range.\n" ) ;
pcap_freealldevs ( alldevs) ;
return - 1 ;
}
for ( d = alldevs, i = 0 ; i < inum - 1 ; d = d- > next, i++ ) ;
if ( ( adhandle = pcap_open ( d- > name,
65536 ,
PCAP_OPENFLAG_PROMISCUOUS,
1000 ,
NULL ,
errbuf
) ) == NULL )
{
fprintf ( stderr , "\nUnable to open the adapter. %s is not supported by WinPcap\n" , d- > name) ;
pcap_freealldevs ( alldevs) ;
return - 1 ;
}
if ( pcap_datalink ( adhandle) != DLT_EN10MB)
{
fprintf ( stderr , "\nThis program works only on Ethernet networks.\n" ) ;
pcap_freealldevs ( alldevs) ;
return - 1 ;
}
if ( d- > addresses != NULL )
netmask = ( ( struct sockaddr_in * ) ( d- > addresses- > netmask) ) - > sin_addr. S_un. S_addr;
else
netmask = 0xffffff ;
if ( pcap_compile ( adhandle, & fcode, packet_filter, 1 , netmask) < 0 )
{
fprintf ( stderr , "\nUnable to compile the packet filter. Check the syntax.\n" ) ;
pcap_freealldevs ( alldevs) ;
return - 1 ;
}
if ( pcap_setfilter ( adhandle, & fcode) < 0 )
{
fprintf ( stderr , "\nError setting the filter.\n" ) ;
pcap_freealldevs ( alldevs) ;
return - 1 ;
}
printf ( "\nlistening on %s...\n" , d- > description) ;
pcap_freealldevs ( alldevs) ;
ofstream fout ( argv[ 1 ] , ios:: app) ;
int k= 1 ;
while ( ( res = pcap_next_ex ( adhandle, & header, & pkt_data) ) >= 0 ) {
if ( res == 0 )
continue ;
ArpHeader* arph = ( ArpHeader * ) ( pkt_data + 14 ) ;
printf ( "----------------------------解析到的第%d个ARP数据包-----------------------------\n" , k) ;
fout<< "----------------------------解析到的第" << k<< "个ARP数据包-----------------------------\n" ;
printf ( "报文类型:" ) ;
if ( arph- > op == 256 ) {
printf ( "请求报文\t" ) ;
fout<< "请求报文\t" ;
}
else {
printf ( "应答报文\t" ) ;
fout<< "应答报文\t" ;
}
printf ( "长度(B):%d\t" , header- > len) ;
fout<< "长度(B):" << header- > len<< "\t" ;
local_tv_sec = header- > ts. tv_sec;
ltime = localtime ( & local_tv_sec) ;
strftime ( timestr, sizeof timestr, "%H:%M:%S" , ltime) ;
printf ( "时间:%s\n" , timestr) ;
fout<< "时间:" << timestr<< "\n" ;
printf ( "源IP:" ) ;
for ( i = 0 ; i < 3 ; i++ )
{
printf ( "%d." , arph- > sip[ i] ) ;
fout<< int ( arph- > sip[ i] ) ;
}
printf ( "%d\t" , arph- > sip[ 3 ] ) ;
fout<< "源IP:" << int ( arph- > sip[ 3 ] ) << "\t" ;
printf ( "目的IP:" ) ;
for ( i = 0 ; i < 3 ; i++ )
{
printf ( "%d." , arph- > dip[ i] ) ;
fout<< "目的IP:" << int ( arph- > dip[ i] ) << "." ;
}
printf ( "%d\n" , arph- > dip[ 3 ] ) ;
fout<< int ( arph- > dip[ 2 ] ) << "\n" ;
printf ( "源MAC:" ) ;
for ( i = 0 ; i < 5 ; i++ )
{
printf ( "%02x-" , arph- > smac[ i] ) ;
fout<< int ( arph- > smac[ i] ) << "-" ;
}
printf ( "%02x\t" , arph- > smac[ 5 ] ) ;
fout<< "源MAC:" << int ( arph- > smac[ 5 ] ) << "\t" ;
printf ( "目的MAC:" ) ;
for ( i = 0 ; i < 5 ; i++ )
{
printf ( "%02x-" , * ( pkt_data + i) ) ;
fout<< int ( * ( pkt_data + i) ) << "-" ;
}
printf ( "%02x\n" , * ( pkt_data + 5 ) ) ;
fout<< "目的MAC:" << int ( * ( pkt_data + 5 ) ) << "\n" ;
k++ ;
}
if ( res == - 1 ) {
printf ( "Error reading the packets: %s\n" , pcap_geterr ( adhandle) ) ;
return - 1 ;
}
return 0 ;
}
解析IP数据包
#include "pcap.h"
#include <winsock2.h>
#include <fstream.h>
#pragma comment(lib,"wpcap.lib")
#pragma comment(lib,"packet.lib")
#pragma comment(lib,"ws2_32.lib")
void packet_handler ( u_char * param, const struct pcap_pkthdr * header, const u_char * pcap_data) ;
#define IPTOSBUFFERS 12
void ifprint ( pcap_if_t * d) ;
char * iptos ( u_long in) ;
int i = 0 ;
struct ether_header
{
u_int8_t ether_dhost[ 6 ] ;
u_int8_t ether_shost[ 6 ] ;
u_int16_t ether_type;
} ;
struct ip_header
{
unsigned char Version_HLen;
u_int8_t ip_tos;
u_int16_t ip_length;
u_int16_t ip_id;
u_int16_t ip_off;
u_int8_t ip_ttl;
u_int8_t ip_protocol;
u_int16_t ip_checksum;
struct in_addr ip_souce_address;
struct in_addr ip_destination_address;
} ;
struct TcpHeader
{
unsigned short SrcPort;
unsigned short DstPort;
unsigned int SequenceNum;
unsigned int Acknowledgment;
unsigned char HdrLen;
unsigned char Flags;
unsigned short AdvertisedWindow;
unsigned short Checksum;
unsigned short UrgPtr;
} ;
void ip_protool_packet_callback ( u_char * argument, const struct pcap_pkthdr* packet_header, const u_char* packet_content)
{
struct ip_header * ip_protocol;
u_int header_length = 0 ;
u_int offset;
u_char tos;
u_int16_t checksum;
u_int ip_len;
u_int ip_version;
TcpHeader * tcp;
ip_protocol = ( struct ip_header * ) ( packet_content+ 14 ) ;
ip_len = ( ip_protocol- > Version_HLen & 0xf ) * 4 ;
ip_version = ip_protocol- > Version_HLen>> 4 ;
tcp = ( TcpHeader * ) ( ( u_char * ) ip_protocol+ ip_len) ;
checksum = ntohs ( ip_protocol- > ip_checksum) ;
tos = ip_protocol- > ip_tos;
offset = ntohs ( ip_protocol- > ip_off) ;
ofstream fout;
fout. open ( "解析IP数据包.txt" , ios:: app) ;
printf ( "---------IP协议---------\n" ) ;
fout<< "---------IP协议---------\n" ;
printf ( "版本号:%d\n" , ip_version) ;
fout<< "版本号:" << ip_version<< "\n" ;
printf ( "首部长度:%d\n" , ip_len) ;
fout<< "首部长度:" << ip_len<< "\n" ;
printf ( "服务质量:%d\n" , tos) ;
fout<< "服务质量:" << tos<< "\n" ;
printf ( "总长度:%d\n" , ntohs ( ip_protocol- > ip_length) ) ;
fout<< "总长度:" << ntohs ( ip_protocol- > ip_length) << "\n" ;
printf ( "标识:%d\n" , ntohs ( ip_protocol- > ip_id) ) ;
fout<< "标识:" << ntohs ( ip_protocol- > ip_id) << "\n" ;
printf ( "偏移:%d\n" , ( offset & 0x1fff ) * 8 ) ;
int x;
x= ( offset & 0x1fff ) * 8 ;
fout<< "偏移:" << x<< "\n" ;
printf ( "生存时间:%d\n" , ip_protocol- > ip_ttl) ;
fout<< "生存时间:" << ip_protocol- > ip_ttl<< "\n" ;
printf ( "协议类型:%d\n" , ip_protocol- > ip_protocol) ;
int y;
y= ip_protocol- > ip_protocol;
fout<< "协议类型:" << y<< "\n" ;
switch ( ip_protocol- > ip_protocol)
{
case 1 : printf ( "上层协议是ICMP协议\n" ) ; break ;
case 2 : printf ( "上层协议是IGMP协议\n" ) ; break ;
case 6 : printf ( "上层协议是TCP协议\n" ) ; break ;
case 17 : printf ( "上层协议是UDP协议\n" ) ; break ;
default : break ;
}
printf ( "检验和:%d\n" , checksum) ;
fout<< "检验和:" << checksum<< "\n" ;
printf ( "源IP地址:%s\n" , inet_ntoa ( ip_protocol- > ip_souce_address) ) ;
fout<< "源IP地址:" << inet_ntoa ( ip_protocol- > ip_souce_address) << "\n" ;
printf ( "目的地址:%s\n" , inet_ntoa ( ip_protocol- > ip_destination_address) ) ;
fout<< "目的地址:" << inet_ntoa ( ip_protocol- > ip_destination_address) << "\n" ;
fout. close ( ) ;
}
void ethernet_protocol_packet_callback ( u_char * argument, const struct pcap_pkthdr* packet_header, const u_char* packet_content)
{
u_short ethernet_type;
struct ether_header * ethernet_protocol;
u_char * mac_string;
static int packet_number = 1 ;
ethernet_protocol= ( struct ether_header* ) packet_content;
ethernet_type= ntohs ( ethernet_protocol- > ether_type) ;
if ( ethernet_type== 0x0800 )
{
ip_protool_packet_callback ( argument, packet_header, packet_content) ;
}
packet_number++ ;
}
int main ( int argc, char * argv[ ] )
{
pcap_if_t * alldevs;
pcap_if_t * d;
int inum;
pcap_t * adhandle;
char errbuf[ PCAP_ERRBUF_SIZE] ;
if ( pcap_findalldevs ( & alldevs, errbuf) == - 1 )
{
exit ( 1 ) ;
}
for ( d= alldevs; d != NULL ; d= d- > next)
{
ifprint ( d) ;
}
if ( i== 0 )
{
printf ( "\nNo interfaces found!Make sure WinPcap is installed.\n" ) ;
char c = getchar ( ) ;
return - 1 ;
}
printf ( "Enter the interface number (1-%d):" , i) ;
scanf ( "%d" , & inum) ;
if ( inum < 1 || inum > i)
{
printf ( "\nInterface number out of range.\n" ) ;
pcap_freealldevs ( alldevs) ;
char c = getchar ( ) ;
return - 1 ;
}
for ( d = alldevs, i= 0 ; i < inum- 1 ; d= d- > next, i++ ) ;
if ( ( adhandle= pcap_open_live ( d- > name, 65536 , 1 , 1000 , errbuf) ) == NULL )
{
fprintf ( stderr , "\nUnable to open the adapter.%s is not supported by WinPcap\n" ) ;
pcap_freealldevs ( alldevs) ;
char c = getchar ( ) ;
return - 1 ;
}
printf ( "\nlistening on %s...\n" , d- > description) ;
pcap_freealldevs ( alldevs) ;
pcap_loop ( adhandle, 0 , ethernet_protocol_packet_callback, NULL ) ;
char c = getchar ( ) ;
return 0 ;
}
void ifprint ( pcap_if_t * d)
{
pcap_addr_t * a;
printf ( "%d.%s" , ++ i, d- > name) ;
if ( d- > description)
{
printf ( "\tDescription:(%s)\n" , d- > description) ;
} else {
printf ( "\t(No description available)\n" ) ;
}
printf ( "\tLoopback:%s\n" , ( d- > flags & PCAP_IF_LOOPBACK) ? "yes" : "no" ) ;
for ( a= d- > addresses; a != NULL ; a= a- > next)
{
printf ( "\tAddress Family:#%d\n" , a- > addr- > sa_family) ;
switch ( a- > addr- > sa_family)
{
case AF_INET:
printf ( "\tAddress Family Name:AF_INET\n" ) ;
if ( a- > addr)
{
printf ( "\tAddress:%s\n" , iptos ( ( ( struct sockaddr_in * ) a- > addr) - > sin_addr. s_addr) ) ;
}
if ( a- > netmask)
{
printf ( "\tNetmask:%s\n" , iptos ( ( ( struct sockaddr_in * ) a- > netmask) - > sin_addr. s_addr) ) ;
}
if ( a- > broadaddr)
{
printf ( "\tBroadcast Address:%s\n" , iptos ( ( ( struct sockaddr_in * ) a- > broadaddr) - > sin_addr. s_addr) ) ;
}
if ( a- > dstaddr)
{
printf ( "\tDestination Address:%s\n" , iptos ( ( ( struct sockaddr_in * ) a- > dstaddr) - > sin_addr. s_addr) ) ;
}
break ;
default :
printf ( "\tAddressFamilyName:Unknown\n" ) ;
break ;
}
}
}
char * iptos ( u_long in)
{
static char output[ IPTOSBUFFERS] [ 3 * 4 + 3 + 1 ] ;
static short which;
u_char * p;
p = ( u_char * ) & in;
which= ( which+ 1 == IPTOSBUFFERS? 0 : which+ 1 ) ;
sprintf ( output[ which] , "%d.%d.%d.%d" , p[ 0 ] , p[ 1 ] , p[ 2 ] , p[ 3 ] ) ;
return output[ which] ;
}
void packet_handler ( u_char * param, const struct pcap_pkthdr * header, const u_char * pcap_data)
{
struct tm * ltime;
char timestr[ 16 ] ;
ltime = localtime ( & header- > ts. tv_sec) ;
strftime ( timestr, sizeof ( timestr) , "%H:%M:%S" , ltime) ;
printf ( "%s, %.6d len:%d\n" , timestr, header- > ts. tv_usec, header- > len) ;
}