当前位置:文档之家› 计算机网络课程设计

计算机网络课程设计

中南大学计算机网络原理课程设计报告学生姓名奚培指导教师张士庚学院信息科学与工程学院专业班级计算机科学与技术1303班学号 0902130325 实验日期 2015年11月目录第一章概要设计 (2)第二章详细设计 (3)第三章调试与操作说明 (4)第四章总结 (4)参考文献 (4)第一章概要设计一、过程图1.1 libpcap捕包过程图本程序设计libpcap捕包程序包含以下五个过程,如下图:图1.libpcap 捕包过程1.2 数据包处理过程图图2.数据包处理过程二、主要数据结构2.1 Ether头10Mb/s ethernet headerstruct ether_header{u_int8_t ether_dhost[ETH_ALEN]; // destination eth addr u_int8_t ether_shost[ETH_ALEN]; // source ether addru_int16_t ether_type; // packet type ID field} __attribute__ ((__packed__));2.2 ARP/RARP协议头/* ARP header */class sniff_arp{unsigned short int ar_hrd; /* Format of hardware address. */unsigned short int ar_pro; /* Format of protocol address. */unsigned char ar_hln; /* Length of hardware address. */unsigned char ar_pln; /* Length of protocol address. */unsigned short int ar_op; /* ARP opcode (command). */#if 0/* Ethernet looks like this : This bit is variable sizedhowever... */unsigned char __ar_sha[ETH_ALEN]; /* Sender hardware address. */unsigned char __ar_sip[4]; /* Sender IP address. */unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */unsigned char __ar_tip[4]; /* Target IP address. */#endif}2.3 IP头/* IP header */class sniff_ip{u_char ip_vhl; /* version << 4 | header length >> 2 */ u_char ip_tos; /* type of service */u_short ip_len; /* total length */u_short ip_id; /* identification */u_short ip_off; /* fragment offset field */#define IP_RF 0x8000 /* reserved fragment flag */#define IP_DF 0x4000 /* dont fragment flag */#define IP_MF 0x2000 /* more fragments flag */#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */u_char ip_p; /* protocol */u_short ip_sum; /* checksum */struct in_addr ip_src,ip_dst; /* source and dest address */int ip_hl(){ return ip_vhl & 0x0f; }int ip_v(){ return ip_vhl >>4; }}2.4 TCP头/* TCP header */typedef u_int tcp_seq;class sniff_tcp{u_short th_sport; /* source port */u_short th_dport; /* destination port */tcp_seq th_seq; /* sequence number */tcp_seq th_ack; /* acknowledgement number */u_char th_offx2; /* data offset, rsvd *///#define TH_OFF (((th_offx2 & 0xf0) >> 4)u_char th_flags;#define TH_FIN 0x01#define TH_SYN 0x02#define TH_RST 0x04#define TH_PUSH 0x08#define TH_ACK 0x10#define TH_URG 0x20#define TH_ECE 0x40#define TH_CWR 0x80#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)u_short th_win; /* window */u_short th_sum; /* checksum */u_short th_urp; /* urgent pointer */int th_off(){ return ((th_offx2 & 0xf0) >> 4);}int dis_flag(int m){ return (th_flags & m)>>(m-1); }}2.5 UDP头class sniff_udp{u_int16_t uh_sport;u_int16_t uh_dport;u_int16_t uh_len;u_int16_t uh_sum;}三、方法和原理将pcap_open_live(dev,SNAP_LEN,1,1000,errbuf)的第三个参数设为1,即开启混杂模式。

对数据包的分析过程是先通过pcap_loop()传递给回调函数get_packet()一个包头指针packet。

对于10M 以太网来说,Ether header总是14个字节的长度,通过头指针转换成Eher_header类型,可获得Eher header信息。

在判断其负载协议的类型,如果是ARP,就取Apr=(sniff_arp*)(packet+14),来或APR头指针。

类似的,通过指针类型转换和加上偏移量可以获得IP,TCP,UDP的指针。

第二章详细设计一、主要函数说明char * pcap_lookupdev ( char * errbuf );查找本机上的网络接口设备,redhat linux上就返回"eth0"。

参数errbuf为存储出错信息的缓冲区地址。

int pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, char *errbuf);根据网络接口确定网络逻辑地址和子网掩码地址。

第一个参数就是pcap_lookupdev返回的接口名,二三参数都是32位无符号数, 分别是IP网段和掩码,参数ebuf为容错缓冲区地址。

pcap_t *pcap_open_live(const char *device, int snaplen,int promisc, int to_ms, char *errbuf)获得捕捉句柄。

第一个参数为网络接口,第二参数是捕捉的最大字节数,第三个参数为1表示设置混杂模式,为0非混杂模式,第四个参数包传送过程中的超时,第四个参数为容错缓冲区地址。

int pcap_datalink(pcap_t *p);返回你的网络类型,如DLT_EN10MB 就是10M以太网。

参数*p为pcap_t *pcap_open_live()获得的捕捉句柄。

i nt pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask);编译过滤规则,返回值-1表示出错。

第一个参数为捕捉句柄,第二个参数为过滤器指针,第三个参数为过滤器字符串表示,第三个参数标志是否优化,第四个参数为网络地址。

int pcap_setfilter(pcap_t *p, struct bpf_program *fp);设置过滤器。

第一个参数为捕捉句柄,第二个参数为过滤器结构。

int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)循环捕包,并调用callback回调函数对包进行处理。

第一个参数为捕捉句柄,第二个参数为回调函数指针,第三个参数为传递给回调函数的参数,一般设置为NULL。

其中回调函数的格式为:void my_callback(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char* packet);第一个参数为pcap_loop()传递过来的指针,第二参数为libpcap处理过后的数据头指针,第三个指针为包的数据指针。

它们其实都是在pcap_loop()隐含传递给my_callback()的。

二、关键代码1.程序主文件main.cpp#include "sniffer.h"#include <iostream>using namespace std;int main(int argv,char** argc){Sniffer sniff;//参数处理if( argv==2 ){if( *(argc[1])=='?' )cout<<"./sniff [key] [num] [filter]"<<endl;else{sniff.str_key=argc[1];}}else if( argv==3 ){sniff.str_key=argc[1];sniff.num_packets=atoi(argc[2]);}else if( argv>3 ){sniff.str_key=argc[1];sniff.num_packets=atoi(argc[2]);sniff.filter_exp="";for(int i=3;i<argv;i++){string str=argc[i];if( i != (argv-1) )str+=" ";sniff.filter_exp+=str;}}sniff.init();sniff.run();}2.协议文件protocol.h,包含ARP/RARP,IP,TCP,UDP等头部结构的定义#ifndef PROTOCOL_H#define PROTOCOL_H#include <netinet/in.h> //for struct in_addr#include <iostream>#include <cstdio>#include <arpa/inet.h>#include <netinet/in.h>using std::cout;using std::endl;/* ARP header */class sniff_arp{unsigned short int ar_hrd; /* Format of hardware address. */ unsigned short int ar_pro; /* Format of protocol address. */unsigned char ar_hln; /* Length of hardware address. */unsigned char ar_pln; /* Length of protocol address. */unsigned short int ar_op; /* ARP opcode (command). */#if 0/* Ethernet looks like this : This bit is variable sizedhowever... */unsigned char __ar_sha[ETH_ALEN];/* Sender hardware address. */ unsigned char __ar_sip[4]; /* Sender IP address. */unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */ unsigned char __ar_tip[4]; /* Target IP address. */#endifpublic:void display(){cout<<"------ARP/RARP:"<<endl;cout<<" Format of hardware address = "<<ntohs(ar_hrd);if( ntohs(ar_hrd)==1 ) cout<<" (10Mb Ethernet)"<<endl;printf(" Format of protocol address = %x",ntohs(ar_pro));if( ntohs(ar_pro)==0x800 ) cout<<" (IP)"<<endl;cout<<" Length of hardware address = "<<int(ar_hln)<<endl;cout<<" Length of protocol address = "<<int(ar_pln)<<endl;cout<<" ARP opcode (comand) = "<<ntohs(ar_op);switch( ntohs(ar_op) ){case 1:cout<<" (ARP request)"<<endl;break;case 2:cout<<" (ARP reply)"<<endl;break;case 3:cout<<" (RARP request)"<<endl;break;case 4:cout<<" (RARP reply)"<<endl;break;default:cout<<" (ARP?)"<<endl;}}};/* IP header */class sniff_ip{u_char ip_vhl; /* version << 4 | header length >> 2 */u_char ip_tos; /* type of service */u_short ip_len; /* total length */u_short ip_id; /* identification */u_short ip_off; /* fragment offset field */#define IP_RF 0x8000 /* reserved fragment flag */#define IP_DF 0x4000 /* dont fragment flag */#define IP_MF 0x2000 /* more fragments flag */#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */u_char ip_p; /* protocol */u_short ip_sum; /* checksum */struct in_addr ip_src,ip_dst; /* source and dest address */int ip_hl(){ return ip_vhl & 0x0f; }int ip_v(){ return ip_vhl >>4; }public:u_short get_len(){ return ip_len; }int display(){cout<<" ----IP:"<<endl;int size_ip=ip_hl()*4;if( size_ip<20 ){cout<<" Invalid IP header length: "<<size_ip<<endl;exit(1);}cout<<" Version = "<<ip_v()<<", header length = "<<size_ip<<" bytes"<<endl;cout<<" Type of service = "<<ntohs(ip_tos)<<endl;cout<<" Total length = "<<ntohs(ip_len)<<endl;cout<<" Identification = "<<ntohs(ip_id)<<endl;cout<<" Flags = "<<ntohs(ip_off)<<endl;cout<<" Time to live = "<<ntohs(ip_ttl)<<endl;cout<<" Protocol = ";switch( ip_p ){case IPPROTO_TCP:cout<<"TCP"<<endl;break;case IPPROTO_UDP:cout<<"UDP"<<endl;break;case IPPROTO_ICMP:cout<<"ICMP"<<endl;break;case IPPROTO_IP:cout<<"IP"<<endl;break;default:cout<<"Unknown"<<endl;exit(1);}cout<<" Checksum = "<<ip_sum<<endl;cout<<" From = "<<inet_ntoa(ip_src)<<endl;cout<<" To = "<<inet_ntoa(ip_dst)<<endl;return size_ip;}u_char get_protocol(){ return ip_p; }};/* TCP header */typedef u_int tcp_seq;class sniff_tcp{u_short th_sport; /* source port */u_short th_dport; /* destination port */tcp_seq th_seq; /* sequence number */tcp_seq th_ack; /* acknowledgement number */ u_char th_offx2; /* data offset, rsvd *///#define TH_OFF (((th_offx2 & 0xf0) >> 4)u_char th_flags;#define TH_FIN 0x01#define TH_SYN 0x02#define TH_RST 0x04#define TH_PUSH 0x08#define TH_ACK 0x10#define TH_URG 0x20#define TH_ECE 0x40#define TH_CWR 0x80#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) u_short th_win; /* window */u_short th_sum; /* checksum */u_short th_urp; /* urgent pointer */int th_off(){ return ((th_offx2 & 0xf0) >> 4);}int dis_flag(int m){ return (th_flags & m)>>(m-1); }public:int display(){cout<<" ----TCP:"<<endl;int size_tcp = th_off()*4;if (size_tcp < 20){printf(" * Invalid TCP header length: %u bytes\n", size_tcp);exit(1);}cout<<" Src port = "<<ntohs(th_sport)<<endl;cout<<" Dst port = "<<ntohs(th_dport)<<endl;cout<<" Sequence number = "<<ntohs(th_seq)<<endl;cout<<" Acknowledgement = "<<ntohs(th_ack)<<endl;cout<<" Data offset = "<<int(th_offx2)<<endl;cout<<" Flags = "<<int(th_flags)<<endl;cout<<" ......."<<dis_flag(TH_FIN)<<" = FIN"<<endl;cout<<" ......"<<dis_flag(TH_SYN)<<". = SYN"<<endl;cout<<" ....."<<dis_flag(TH_RST)<<".. = RST"<<endl;cout<<" ...."<<dis_flag(TH_PUSH)<<"... = PUSH"<<endl;cout<<" ..."<<dis_flag(TH_ACK)<<".... = ACK"<<endl;cout<<" .."<<dis_flag(TH_URG)<<"..... = URG"<<endl;cout<<" ."<<dis_flag(TH_ECE)<<"...... = ECE"<<endl;cout<<" "<<dis_flag(TH_CWR)<<"....... = CWR"<<endl;cout<<" Windows num = "<<ntohs(th_win)<<endl;cout<<" Checksum = "<<ntohs(th_sum)<<endl;cout<<" Urgent pointer = "<<ntohs(th_urp)<<endl;return size_tcp;}};/* UDP header */class sniff_udp{u_int16_t uh_sport;u_int16_t uh_dport;u_int16_t uh_len;u_int16_t uh_sum;public:int display(){cout<<" ----UDP:"<<endl;cout<<" Source port = "<<ntohs(uh_sport)<<endl;cout<<" Destination port= "<<ntohs(uh_dport)<<endl;cout<<" Udp length = "<<ntohs(uh_len)<<endl;cout<<" Check sum = "<<ntohs(uh_sum)<<endl;return uh_len;}};#endif //protocol.h3.嗅探器实现类的头文件,sniffer.h#ifndef SNIFFER_H#define SNIFFER_Hextern "C" {#include <pcap.h>}#include <iostream>#include <cstdlib>#include <string>#include <vector>#define EXP_LEN 20class 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.h4.嗅探器实现,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 filtersif( 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 closepcap_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_REV ARP: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);/* vector<string>::iterator it;for( it=keywords.begin();it!=keywords.end();it++ ){int k=0;u_char* p=(u_char*)ch;while( p && k<(int)it->length() && *p==it->at(k) ){p++;i++;}//whileif( k==(int)it->length() ){string f_str;while( *p<123 && *p>79 )f_str+=(*p);out<<(*it)<<f_str<<endl;}}*/int k=0;u_char* p=(u_char*)ch;while( p && k<(int)str_key.length() && (*p)==str_key.at(k) ) {p++;k++;}//whileif( k==(int)str_key.length() ){string f_str;while( p && (*p)>32 && (*p)<123 ){f_str+=(*p);p++;}out<<str_key<<f_str<<endl;}}elseprintf(".");ch++;}printf("\n");return;}第三章调试与操作说明一、调试说明代码修改后要用makefile重新编译连接。

相关主题