网络嗅探器
该项目相关知识点已经放到“网络嗅探器”标签中
下面是相关头文件
/* sniffer.h */ #ifndef __SNIFFER_H__ #define __SNIFFER_H__ typedef struct s_protocol { int tcp; int udp; int icmp; int igmp; int others; int total; }t_protocol; typedef struct s_sinffer { FILE *logfile; t_protocol *prot; }t_sniffer; void ProcessPacket(unsigned char *, int, t_sniffer *); void print_ip_header(unsigned char *, int, t_sniffer *); void print_tcp_packet(unsigned char *, int, t_sniffer *); void print_udp_packet(unsigned char *, int, t_sniffer *); void print_icmp_packet(unsigned char *, int, t_sniffer *); void PrintData(unsigned char *, int, t_sniffer*); void display_time_and_data(); void getting_started(); void signal_white_now(int); #endif
输出颜色定义
/* tool.h */ #ifndef __COLOR_H__ #define __COLOR_H__ #include<stdio.h> #define CLEARSCREEN() printf("\033[H\033[2J") #define INITCOLOR(color) printf("\033[%sm",color) #define RED_COLOR "31" #define GREEN_COLOR "32" #define YELLOW_COLOR "33" #define BLUE_COLOR "34" #define ZERO_COLOR "0" #endif
暂停或退出的信号处理
/* tool.c */ #include<stdio.h> #include<signal.h> void signal_white_now(int signum) { printf("Bye Bye !\n"); }
数据包 分解打印
/* show_data.c */ #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<netinet/ip_icmp.h> #include<netinet/udp.h> #include<netinet/tcp.h> #include<netinet/ip.h> #include<sys/socket.h> #include<arpa/inet.h> #include"sniffer.h" #include"tools.h" //将ip头部信息解析出来输出到文件中 void print_ip_header(unsigned char *buf,int size, t_sniffer *sniffer) { unsigned short iphdrlen; struct iphdr *iph; struct sockaddr_in source; struct sockaddr_in dest; iph = (struct iphdr *)buf; iphdrlen = iph->ihl*4; //iph->ihl首部长度,乘以4是因为是以4字节为单位 (void)iphdrlen; (void)size; memset(&source, 0, sizeof(source)); source.sin_addr.s_addr = iph->saddr; memset(&dest, 0, sizeof(dest)); dest.sin_addr.s_addr = iph->daddr; fprintf(sniffer->logfile,"\n"); fprintf(sniffer->logfile,"IP Header\n"); fprintf(sniffer->logfile," |-IP Version :%d\n",(unsigned int)iph->version); fprintf(sniffer->logfile," |-IP Header Length :%d DWORDS or %d Bytes\n",(unsigned int)iph->ihl,((unsigned int)(iph->ihl)) * 4); fprintf(sniffer->logfile," |-Type Of Service :%d\n",(unsigned int)iph->tos); fprintf(sniffer->logfile," |-Identification :%d\n",ntohs(iph->id)); fprintf(sniffer->logfile," |-TTL :%d\n",(unsigned int)iph->ttl); fprintf(sniffer->logfile," |-Protocol :%d\n",(unsigned int)iph->protocol); fprintf(sniffer->logfile," |-Checksum :%d\n",ntohs(iph->check)); fprintf(sniffer->logfile," |-Source IP :%s\n",inet_ntoa(source.sin_addr)); fprintf(sniffer->logfile," |-Destination IP :%s\n",inet_ntoa(dest.sin_addr)); } void print_tcp_packet(unsigned char *buf, int size , t_sniffer *sniffer) { unsigned short iphdrlen; struct iphdr *iph; struct tcphdr *tcph; iph = (struct iphdr *)buf; iphdrlen = iph->ihl * 4; tcph = (struct tcphdr*)(buf + iphdrlen); //跳过ip头部,就是tcp数据内存。buf里存储就是ip头部字节数 print_ip_header(buf, size, sniffer); //传过去的size是整个接收数据的长度,但是使用时都截取了相应的长度 fprintf(sniffer->logfile,"\n"); fprintf(sniffer->logfile,"TCP Header\n"); fprintf(sniffer->logfile," |-Source Port :%u\n",ntohs(tcph->source)); fprintf(sniffer->logfile," |-Destination Port :%u\n",ntohs(tcph->dest)); fprintf(sniffer->logfile," |-Sequence Number :%u\n",ntohl(tcph->dest)); fprintf(sniffer->logfile," |-Acknowledge Number :%u\n",ntohl(tcph->dest)); fprintf(sniffer->logfile," |-Header Length :%d DWORDS or %d Bytes\n",(unsigned int)tcph->doff,((unsigned int)(tcph->doff)) * 4); fprintf(sniffer->logfile," |-Urgent Flag :%d\n",(unsigned int)tcph->urg); fprintf(sniffer->logfile," |-Acknowledgement Flag :%d\n",(unsigned int)tcph->ack); fprintf(sniffer->logfile," |-Push Flag :%d\n",(unsigned int)tcph->psh); fprintf(sniffer->logfile," |-Reset Flag :%d\n",(unsigned int)tcph->rst); fprintf(sniffer->logfile," |-Synchronise Flag :%d\n",(unsigned int)tcph->syn); fprintf(sniffer->logfile," |-Finish Flag :%d\n",(unsigned int)tcph->fin); fprintf(sniffer->logfile," |-Window :%d\n",ntohs(tcph->window)); fprintf(sniffer->logfile," |-Checksum :%d\n",ntohs(tcph->check)); fprintf(sniffer->logfile," |-Urgent Pointer :%d\n",(tcph->urg_ptr)); fprintf(sniffer->logfile,"\n"); fprintf(sniffer->logfile," DATA Dump \n"); fprintf(sniffer->logfile,"IP Header\n"); PrintData(buf, iphdrlen, sniffer); //将ip头部信息按照16进制的方式输入到日志中 fprintf(sniffer->logfile,"TCP Header\n"); PrintData(buf+iphdrlen, tcph->doff*4, sniffer); fprintf(sniffer->logfile,"Data Payload\n"); //将tcp数据报中的存储的内容按16进制输出到日志中 PrintData(buf+iphdrlen+tcph->doff*4, (size - tcph->doff*4 - iph->ihl*4),sniffer); fprintf(sniffer->logfile,"################################################\n"); } void print_udp_packet(unsigned char *buf, int size, t_sniffer * sniffer) { unsigned short iphdrlen; struct iphdr *iph; struct udphdr *udph; iph = (struct iphdr *)buf; iphdrlen = iph->ihl * 4; udph = (struct udphdr*)(buf + iphdrlen); fprintf(sniffer->logfile,"\n\n************************UDP Packet********************\n"); print_ip_header(buf, size, sniffer); fprintf(sniffer->logfile,"\nUDP Header\n"); fprintf(sniffer->logfile," |-Source Port :%d\n",ntohs(udph->source)); fprintf(sniffer->logfile," |-Destination Port :%d\n",ntohs(udph->dest)); fprintf(sniffer->logfile," |-UDP Length :%d\n",ntohs(udph->len)); fprintf(sniffer->logfile," |-UDP Checksum :%d\n",ntohs(udph->check)); fprintf(sniffer->logfile,"\n"); fprintf(sniffer->logfile,"IP Header\n"); PrintData(buf, iphdrlen, sniffer); fprintf(sniffer->logfile,"UDP Header\n"); PrintData(buf+iphdrlen,sizeof(udph), sniffer); fprintf(sniffer->logfile,"Data Payload\n"); PrintData(buf+iphdrlen+sizeof(udph), (size - sizeof(udph) - iph->ihl*4),sniffer); fprintf(sniffer->logfile,"################################################\n"); } void print_icmp_packet(unsigned char * buf, int size, t_sniffer * sniffer) { unsigned short iphdrlen; struct iphdr *iph; struct icmphdr *icmph; iph = (struct iphdr *)buf; iphdrlen = iph->ihl * 4; icmph = (struct icmphdr *)(buf + iphdrlen); fprintf(sniffer->logfile,"\n\n************************ICMP Packet********************\n"); print_ip_header(buf, size, sniffer); fprintf(sniffer->logfile,"\n"); fprintf(sniffer->logfile,"ICMP Header\n"); fprintf(sniffer->logfile," |-Type :%d\n",(unsigned int)icmph->type); if((unsigned int)(icmph->type) == 11) { fprintf(sniffer->logfile,"(TTL Expired)\n"); } else if((unsigned int)(icmph->type) == ICMP_ECHOREPLY) { fprintf(sniffer->logfile,"(ICMP Echo Reply)\n"); } fprintf(sniffer->logfile," |-Code :%d\n",(unsigned int)icmph->code); fprintf(sniffer->logfile," |-Checksum :%d\n",ntohs(icmph->checksum)); fprintf(sniffer->logfile,"\n"); fprintf(sniffer->logfile,"IP Header\n"); PrintData(buf, iphdrlen, sniffer); fprintf(sniffer->logfile,"UDP Header\n"); PrintData(buf+iphdrlen,sizeof(icmph), sniffer); fprintf(sniffer->logfile,"Data Payload\n"); PrintData(buf+iphdrlen+sizeof(icmph), (size - sizeof(icmph) - iph->ihl*4),sniffer); fprintf(sniffer->logfile,"################################################\n"); } void PrintData(unsigned char * buf, int size, t_sniffer *sniffer) { #if 1 int i; for(i = 0; i < size; i++) { if(i % 16 == 0) { fprintf(sniffer->logfile,"\n"); } fprintf(sniffer->logfile," %02X",(unsigned int)buf[i]); if(i == size - 1) fprintf(sniffer->logfile,"\n"); } #else int i; for(i = 0 ; i < size ; i++) { if(i % 16 == 0) fprintf(sniffer->logfile, "\n"); fprintf(sniffer->logfile, " %02X",(unsigned int)buf[i]); if( i == size - 1) fprintf(sniffer->logfile, "\n"); } #endif }
主函数
/* main.c */ #include<signal.h> #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<netinet/ip.h> #include<sys/socket.h> #include<sys/select.h> #include<fcntl.h> #include<sys/types.h> #include<sys/time.h> #include<errno.h> #include"sniffer.h" #include"tools.h" #define ETH_P_IP 0x0800 int exec_cmd(char *buffer, int len) { if(strncmp(buffer,"quit",4) == 0) { return 1; } return 0; } int command_interpreter(int sd) { int len; char buf[512]; len = read(0,buf,512); if(len > 0) { if(exec_cmd(buf,len) == 1) { return 1; } } return 0; } void display_time_and_data() { INITCOLOR(RED_COLOR); printf("[%s]",__DATE__); INITCOLOR(GREEN_COLOR); printf("[%s] ", __TIME__); INITCOLOR(ZERO_COLOR); } void getting_started() { CLEARSCREEN(); display_time_and_data(); printf("Getting started of NetWork sniffer\n\n"); } int main() { int sd; int res; int saddr_size; int data_size; struct sockaddr saddr; unsigned char *buffer; //保存数据包中的数据 t_sniffer sniffer; //保存数据包的类型和日志文件等信息 fd_set fd_read; buffer = malloc(sizeof(unsigned char *) * 65536); //创建日志文件 sniffer.logfile = fopen("log.txt","w"); fprintf(sniffer.logfile,"***LOGFILE(%s - %s)***\n",__DATE__,__TIME__); if(sniffer.logfile == NULL) { perror("fopen(): "); return (EXIT_FAILURE); } sniffer.prot = malloc(sizeof(t_protocol *)); //创建原始套接字,ETH_P_ALL表示侦听负载为IP数据报的以太网帧 //返回一个int型数字作为文件描述符,用来表示创建成功的socket文件描述符 sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); if(sd < 0) { perror("socket() :"); return (EXIT_FAILURE); } getting_started(); signal(SIGINT, &signal_white_now); signal(SIGQUIT, &signal_white_now); while(1) { FD_ZERO(&fd_read); FD_SET(0,&fd_read); FD_SET(sd,&fd_read); //多路复用检测可读的套接字和标准输入 res = select(sd+1,&fd_read,NULL,NULL,NULL); if(res < 0) { close(sd); if(errno != EINTR) { perror("select() "); } return (EXIT_FAILURE); } else { //如果是标准输入可读,进入命令行处理程序 if(FD_ISSET(0,&fd_read)) { if(command_interpreter(sd) == 1) { break; } } //如果是套接字可读,则读取以太网数据帧内容,并调用ProcessPacket函数解析数据包类型 else if(FD_ISSET(sd,&fd_read)) { //读取以太网数据帧的内容 saddr_size = sizeof(saddr); data_size = recvfrom(sd,buffer,65536,0,&saddr,(socklen_t*)&saddr_size); if(data_size <= 0) { close(sd); perror("rcvfrom(): "); return (EXIT_FAILURE); } ProcessPacket(buffer, data_size, &sniffer); } } } close(sd); return (EXIT_SUCCESS); } void ProcessPacket(unsigned char * buffer,int size, t_sniffer *sniffer) { //根据以太网帧结构,前6B是目的MAC地址,然后是6B的源MAC地址,接下来是2B的帧长度,然后是ip层数据作为负载 buffer = buffer + 6 + 6 + 2; struct iphdr *iph = (struct iphdr*)buffer; ++sniffer->prot->total; //根据TCP/IP协议规定的IP数据包头部的protocol字段的值,判断上层数据包类型 switch(iph->protocol) { //1 表示icmp协议 case 1: ++sniffer->prot->icmp; print_icmp_packet(buffer,size,sniffer); break; //2表示igmp协议 case 2: ++sniffer->prot->igmp; break; //6表示tcp协议 case 6: ++sniffer->prot->tcp; print_tcp_packet(buffer,size,sniffer); break; //17表示udp协议 case 17: ++sniffer->prot->udp; print_udp_packet(buffer,size,sniffer); break; default: ++sniffer->prot->others; break; } display_time_and_data(); printf("TCP :%d UDP :%d ICMP :%d IGMP :%d others:%d total:%d\n", sniffer->prot->tcp,sniffer->prot->udp, sniffer->prot->icmp,sniffer->prot->igmp, sniffer->prot->others,sniffer->prot->total); }
makefile
NAME = network_sniffer SRCS = main.c \ tools.c \ show_data.c OBJS = $(SRCS:.c=.o) CC = gcc -o CFLAGS = -W -Wall RM = rm -rf $(NAME) : $(OBJS) $(CC) $(NAME) -I./ $(CFLAGS) $(OBJS) all : $(NAME) clean : $(RM) $(OBJS) fclean : clean $(RM) $(NAME) re : fclean all