標籤:get gnu 嗅探 lag rebuild stdio.h 讀取 port ted
C語言實現Linux網路嗅探器0x01 實驗簡介
網路嗅探器是攔截通過網路介面流入和流出的資料的程式。所以,如果你正在瀏覽的互連網,嗅探器以資料包的形式抓到它並且顯示。在本實驗中,我們用 C 語言實現了一個網路嗅探器。
0x02程式架構和功能描述
本程式使用c語言編程,實現linux環境下網路嗅探的功能,並實現對接收到的UDP資料報進行解析。
0x03程式碼
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_sniffer{ 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_date();void getting_started();void signal_white_now(int);#endif
tools.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
tools.c
#include <signal.h>#include <stdio.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; (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," |-IP Total Length : %d Bytes(size of Packet)\n",ntohs(iph->tot_len)); 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));}/* 寫 TCP 資料包到記錄檔 */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); print_ip_header(buf, size, sniffer); /* 把 tcp 頭資訊寫入記錄檔中 */ 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->seq)); fprintf(sniffer->logfile," |-Acknowledge Number : %u\n",ntohl(tcph->ack_seq)); 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 "); fprintf(sniffer->logfile,"\n"); fprintf(sniffer->logfile,"IP Header\n"); PrintData(buf, iphdrlen, sniffer); fprintf(sniffer->logfile,"TCP Header\n"); PrintData(buf+iphdrlen, tcph->doff*4, sniffer); fprintf(sniffer->logfile,"Data Payload\n"); /* 把使用者資料寫入記錄檔 */ PrintData(buf + iphdrlen + tcph->doff*4, (size - tcph->doff*4-iph->ihl*4), sniffer ); fprintf(sniffer->logfile,"\n###########################################################");}/* 寫 UDP 資料包到記錄檔 */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); /* 把 udp 頭資訊寫入記錄檔中 */ 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###########################################################");}/* 寫 ICMP 資料包到記錄檔 */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); /* 把 icmp 頭資訊寫入記錄檔中 */ 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",(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){ 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"); }}
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 0x0800int 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_date(){ INITCOLOR(RED_COLOR); printf("[%s]", __DATE__); /* 列印日期 */ INITCOLOR(GREEN_COLOR); printf("[%s] ", __TIME__); /* 列印時間 */ INITCOLOR(ZERO_COLOR);}void getting_started(){ CLEARSCREEN(); /* 清空螢幕 */ display_time_and_date(); 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 資料報的乙太網路幀 */ 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); /* 迴圈偵聽乙太網路幀,並調用 ProcessPacket 函數解析 */ 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 { /* 如果是標準輸入可讀,進入命令列處理常式 command_interpreter,暫時只支援 ‘quit‘ 命令 */ 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("recvfrom(): "); return (EXIT_FAILURE); } ProcessPacket(buffer, data_size, &sniffer); /* 調用 ProcessPacket 函數解析出資料包的類型 */ } } } close(sd); return (EXIT_SUCCESS);}void ProcessPacket(unsigned char* buffer, int size, t_sniffer *sniffer){ buffer = buffer + 6 + 6 + 2; /* 根據太網幀結構,前 6B 是目的 MAC 位址,接下來的是源 MAC 位址,接下來 2B 是幀長度,其餘的是負載(上層的 IP 資料報) */ struct iphdr *iph = (struct iphdr*)buffer; ++sniffer->prot->total; /* 資料包總數加 1 */ /* 根據 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_date(); /* 顯示時間 */ /* 列印 sniffer 中的資訊 */ 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);}
0x04資料報分析
以一個UDP資料包為例
***LOGFILE(Dec 14 2017 - 21:41:38)**************************UDP Packet*************************IP Header |-IP Version : 4 |-IP Header Length : 5 DWORDS or 20 Bytes |-Type Of Service : 0 |-IP Total Length : 213 Bytes(size of Packet) |-Identification : 6639 |-TTL : 64 |-Protocol : 17 |-Checksum : 31927 |-Source IP : 172.16.69.82 |-Destination IP : 172.16.69.255UDP Header |-Source Port : 138 |-Destination Port : 138 |-UDP Length : 193 |-UDP Checksum : 26258IP Header保護隱私,這部分我刪除了 AC 10 45 FFUDP Header保護隱私,這部分我刪除了Data Payload保護隱私,這部分我刪除了###########################################################
0x05附
我認為本實驗的亮點在於使用指令碼控制,有必要好好學習下指令碼編程
launcher.sh
#!/bin/shsigint(){ printf ‘\nQUIT !\n‘ exit 1}main(){ clear printf "\t\t\t\t\tWelcome to Sniffer Project r\n\n" while [ 1 ]; do printf "Select option: \n\n" printf "1 : Build Project\n" printf "2 : Launch Project\n" printf "3 : Remove Object files\n" printf "4 : Rebuild\n" printf "0 : Exit\n" printf "\nYou choose: " read option if [ $option = 0 ] then exit fi if [ $option -ge 1 ] && [ $option -le 4 ] then if [ $option = 1 ] then make "network_sniffer" fi if [ $option = 2 ] then "./network_sniffer" fi if [ $option = 3 ] then make clean fi if [ $option = 4 ] then make re fi else printf "This option does not exist\n" fi done}trap ‘sigint‘ 2main
C語言實現Linux網路嗅探器