题目: 网络嗅探器的设计与实现: 基本要求捕获本网段的数据包,将报文结构显示出来.进一步要求进行数据包协议分析,可以按报头进行统计,提取部分关键信息,如捕获登陆信息,破解登陆密码等。
本程序实现功能: 1.能对局域网内广播数据包和自己的数据包进行捕获; 2.能将报文从DLC到TCP(UDP)分层显示出来; 3.支持一个关键字的,从数据包中相关信息捕获;
程序运行结果如下(命令行的): Net: 192.168.1.0 Mask: 255.255.255.0 /*--------------------input values--------------------*/ Please set the follow values key: (the key word you want to get) num : (how many packets you want to grab, filter: (the packet filter,such as ip) such as -1,which means infinite. ------------------------------------------------------- Find keyword: name num of packets: 10 Filter: tcp and port 80
Packet number: 1 --DLC: Ether_shost = 0:4:61:7a:c6:eb Ether_dhost = 0:8:5c:e:96:d2 Ether_type = IP ----IP: Version = 4, header length = 20 bytes Type of service = 0 Total length = 60 Identification = 55082 Flags = 16384 Time to live = 16384 Protocol = TCP Checksum = 27740 From = 192.168.1.11 To = 72.14.253.99 ----TCP: Src port = 52328 Dst port = 80 Sequence number = 65068 Acknowledgement = 0 Data offset = 160 Flags = 2 .......0 = FIN ......1. = SYN .....0.. = RST ....0... = PUSH ...0.... = ACK ..0..... = URG .0...... = ECE 0....... = CWR Windows num = 5840 Checksum = 17890 Urgent pointer = 0 Payload length: 40 bytes: 00000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................ 00016 00 00 00 00 0a 00 00 00 00 00 00 00 ff ff ff ff ................ 00032 ff ff ff ff ff ff ff ff ........
程序: libpcap是c语言写的,但由于个人比较了c++的面向对象思维。对在main()函数里弄一大堆函数,这个函数调用那个,那个调用这个,感到很反感。最后实在弄不下去了,除了将各个协议头重新写成类的形式(在protocol.h中),并添加display()方法来显示之外,重新把整个嗅探器实现封装成了一个Sniffer类: //部分函数直接copy www.tcpdum.org 的示例。
嗅探器实现类的头文件,sniffer.h #ifndef SNIFFER_H #define SNIFFER_H extern
"
C
"
...
{ #include < pcap.h > }
#include
<
iostream
>
#include
<
cstdlib
>
#include
<
string
>
#include
<
vector
>
#define EXP_LEN
20
class Sniffer
...
{ private: char * dev; char errbuf[PCAP_ERRBUF_SIZE]; bpf_u_int32 net; bpf_u_int32 mask; pcap_t * handle; struct bpf_program fp; void display_net(); static void display_ether(const u_char * ); static void display_arp(const u_char * ); static void display_ip(const u_char * ); static void display_tcp(const u_char * , int offset); static void display_udp(const u_char * , int offset); static void display_payload(const u_char * , int ); static void print_hex_ascii_line(const u_char * , int , int ); void get_input(); std::vector < std::string > slip_str(std::string); public: static std::string str_key; int num_packets; std::string filter_exp; public: Sniffer(); void init(); void run(); void err(const char * msg) ... { std::cerr << msg << std::endl; exit( 1 ); } static void getpacket(u_char * args, const struct pcap_pkthdr * header, const u_char * packet); }
; #endif
//
sinffer.h
4
.嗅探器实现,sniffer.cpp #include
"
sniffer.h
"
#include
"
protocol.h
"
#include
<
sys
/
socket.h
>
#include
<
arpa
/
inet.h
>
//
for inet_ntoa(),inet_aton()
#include
<
netinet
/
in
.h
>
//
for htons()
#include
<
netinet
/
if_ether.h
>
#include
<
netinet
/
ether.h
>
//
for ether_header
#include
<
cstdio
>
#include
<
cstring
>
#include
<
fstream
>
using namespace std; const
int
SIZE_ETHER
=
14
; const
int
CW
=
25
; const
int
SNAP_LEN
=
1518
; ofstream out(
"
find.txt
"
);
//
vector<string> keywords;
string Sniffer::str_key
=
"
name
"
; Sniffer::Sniffer():net(
0
),mask(
0
)
...
{ filter_exp = " ip " ; num_packets =- 1 ; }
void
Sniffer::display_net()
...
{ struct in_addr a1; // struct in_addr a2; a1.s_addr = net; // a2.s_addr=mask; cout << " Net device: " << dev << endl << " Net: " << inet_ntoa(a1) << endl; a1.s_addr = mask; cout << " Mask: " << inet_ntoa(a1) << endl; }
void
Sniffer::get_input()
...
{ cout << " /*--------------------input values--------------------*/ " << endl; cout << " Please set the follow values " << endl << " key: (the key word you want to get) " << endl << " num : (how many packets you want to grab, " << endl << " filter: (the packet filter,such as ip) " << endl << " such as -1,which means infinite. " << endl << " ------------------------------------------------------- " << endl; // string str_key; cout << " Find keyword: " << str_key << endl; cout << " num of packets: " << num_packets << endl; cout << " Filter: " << filter_exp << endl; // getline(cin,filter_exp); // cin>>num_packets; // cin>>str_key; // getline(cin,str_key); // keywords=slip_str(str_key); cout << endl; }
vector
<
string
>
Sniffer::slip_str(string str)
...
{ int i = 0 ; vector < string > keywords; while ( i < ( int )str.length() ) ... { int k = i; string temp; while ( str.at(i) != ' ' && i < ( int )str.length() ) ... { ++ i; temp += str.at(i); } if ( k < i ) keywords.push_back(temp); ++ i; } return keywords; }
void
Sniffer::init()
...
{ dev = pcap_lookupdev(errbuf); if ( dev == NULL ) ... { cout << " Error:Couldn't find default device: " << errbuf << endl; exit( 1 ); } if ( pcap_lookupnet(dev, & net, & mask,errbuf) ==- 1 ) ... { cout << " Error:Couldn't get netmask: " << errbuf << endl; net = 0 ; mask = 0 ; exit( 1 ); } display_net(); get_input(); }
void
Sniffer::run()
...
{ handle = pcap_open_live(dev,SNAP_LEN, 1 , 1000 ,errbuf); if ( handle == NULL ) ... { cout << " Error:Couldn't open device: " << dev << endl; exit( 1 ); } if ( pcap_datalink(handle) != DLT_EN10MB ) ... { cout << " Error: " << dev << " isn't an Ether " << endl; exit( 1 ); } // set filters if ( pcap_compile(handle, & fp,filter_exp.c_str(), 0 ,net) ==- 1 ) ... { cout << " Error:Couldn't parse filter " << filter_exp << pcap_geterr(handle) << endl; exit( 1 ); } if ( pcap_setfilter(handle, & fp) ==- 1 ) ... { cout << " Error:Couldn't install filter " << filter_exp << pcap_geterr(handle) << endl; exit( 1 ); } // get packets and post them to getpacket() pcap_loop(handle,num_packets,getpacket,NULL); // clean and close pcap_freecode( & fp); pcap_close(handle); }
void
Sniffer::getpacket( u_char
*
args, const struct pcap_pkthdr
*
header, const u_char
*
packet)
...
{ static int count = 0 ; /**/ /* packet counter */ cout<< " Packet number: " <<++ count << endl; display_ether(packet); cout << endl; }
/**/
/* 10Mb/s ethernet header *struct ether_header *{ * u_int8_t ether_dhost[ETH_ALEN]; // destination eth addr * u_int8_t ether_shost[ETH_ALEN]; // source ether addr * u_int16_t ether_type; // packet type ID field *} __attribute__ ((__packed__)); */
void
Sniffer::display_ether(const u_char
*
packet)
...
{ cout << " --DLC: " << endl; struct ether_header * e_header; e_header = (struct ether_header * )packet; ether_addr addr; u_int8_t * p1 = addr.ether_addr_octet; u_int8_t * p2 = e_header -> ether_shost; for ( int i = 0 ;i < ETH_ALEN;i ++ ,p1 ++ ,p2 ++ ) ... { * p1 =* p2; } cout<< " Ether_shost = " << ether_ntoa( & addr) << endl; p1 = addr.ether_addr_octet; p2 = e_header -> ether_dhost; for ( int i = 0 ;i < ETH_ALEN;i ++ ,p1 ++ ,p2 ++ ) ... { * p1 =* p2; } cout<< " Ether_dhost = " << ether_ntoa( & addr) << endl; cout << " Ether_type = " ; switch ( ntohs(e_header -> ether_type) ) ... { case ETHERTYPE_ARP: cout << " ARP " << endl; display_arp(packet); break ; case ETHERTYPE_IP: cout << " IP " << endl; display_ip(packet); break ; case ETHERTYPE_REVARP: cout << " RARP " << endl; display_arp(packet); break ; default : cout << " Unknown " << endl; exit( 1 ); } }
void
Sniffer::display_arp(const u_char
*
packet)
...
{ sniff_arp * arp_header; arp_header = (sniff_arp * )(packet + SIZE_ETHER); arp_header -> display(); }
void
Sniffer::display_ip(const u_char
*
packet)
...
{ sniff_ip * ip_header; ip_header = (sniff_ip * )(packet + SIZE_ETHER); int size_ip = ip_header -> display(); switch ( ip_header -> get_protocol() ) ... { case IPPROTO_TCP: display_tcp(packet,size_ip + SIZE_ETHER); break ; case IPPROTO_UDP: display_udp(packet,size_ip + SIZE_ETHER); break ; case IPPROTO_ICMP:cout << " ----ICMP " << endl; break ; case IPPROTO_IP:cout << " ----IP " << endl; break ; default : cout << " ----Unknown " << endl; exit( 1 ); } }
void
Sniffer::display_tcp(const u_char
*
packet,
int
offset)
...
{ sniff_tcp * tcp_header; tcp_header = (sniff_tcp * )(packet + offset); int size_tcp = tcp_header -> display(); u_char * payload = (u_char * )(packet + offset + size_tcp); sniff_ip * ip_header; ip_header = (sniff_ip * )(packet + SIZE_ETHER); int size_payload = ntohs(ip_header -> get_len()) - (offset - SIZE_ETHER); if ( size_payload > 0 ) ... { cout << " Payload length: " << size_payload << " bytes: " << endl; display_payload(payload,size_payload); } }
void
Sniffer::display_udp(const u_char
*
packet,
int
offset)
...
{ sniff_udp * udp_header; udp_header = (sniff_udp * )(packet + offset); udp_header -> display(); }
void
Sniffer::display_payload(const u_char
*
payload,
int
len)
...
{ int len_rem = len; int line_width = 16 ; /**/ /* number of bytes per line */ int line_len; int offset = 0 ; /**/ /* zero-based offset counter */ const u_char * ch = payload; if (len <= 0 ) return ; /**/ /* data fits on one line */ if (len <= line_width) ... { print_hex_ascii_line(ch, len, offset); return ; } /**/ /* data spans multiple lines */ for ( ;; ) ... { /**/ /* compute current line length */ line_len = line_width % len_rem; /**/ /* print line */ print_hex_ascii_line(ch, line_len, offset); /**/ /* compute total remaining */ len_rem = len_rem - line_len; /**/ /* shift pointer to remaining bytes to print */ ch = ch + line_len; /**/ /* add offset */ offset = offset + line_width; /**/ /* check if we have line width chars or less */ if (len_rem <= line_width) ... { /**/ /* print last line and get out */ print_hex_ascii_line(ch, len_rem, offset); break ; } } }
/**/
/* * print data in rows of 16 bytes: offset hex ascii * * 00000 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1.. */
void
Sniffer::print_hex_ascii_line (const u_char
*
payload,
int
len,
int
offset)
...
{ int i; int gap; const u_char * ch; /**/ /* offset */ printf(" %05d " , offset); /**/ /* hex */ ch = payload; for (i = 0 ; i < len; i ++ ) ... { printf( " %02x " , * ch); ch ++ ; /**/ /* print extra space after 8th byte for visual aid */ if (i == 7 ) printf( " " ); } /**/ /* print space to handle line less than 8 bytes */ if (len < 8 ) printf( " " ); /**/ /* fill hex gap with spaces if not full line */ if (len < 16 ) ... { gap = 16 - len; for (i = 0 ; i < gap; i ++ ) ... { printf( " " ); } } printf(" " ); /**/ /* ascii (if printable) */ ch = payload; for (i = 0 ; i < len; i ++ ) ... { if (isprint( * ch)) ... { printf( " %c " , * ch); int k = 0 ; u_char * p = (u_char * )ch; while ( p && k < ( int )str_key.length() && ( * p) == str_key.at(k) ) ... { p ++ ; k ++ ; } // while if ( k == ( int )str_key.length() ) ... { string f_str; while ( p && ( * p) > 32 && ( * p) < 123 ) ... { f_str += ( * p); p ++ ; } out<< str_key << f_str << endl; } } else printf(" . " ); ch ++ ; } printf(" " ); return ; }
源程序下载地址(包含实验报告,写的更详细):http://download.youkuaiyun.com/source/205883