C Language Implementation Linux Network Sniffer 0x01 experiment Introduction
A network sniffer is a program that intercepts incoming and outgoing data through a network interface. So if you are browsing the Internet, the sniffer catches it in the form of a packet and displays it. In this experiment, we implemented a network sniffer using C language.
0X02 program Framework and function description
This program uses the C language programming, realizes the network sniffing function under the Linux environment, and realizes the docking receives the UDP datagram to parse.
0X03 Program code
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"/* Write IP header to log file */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))); 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));} /* Write TCP packets to the log file */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); /* Write the TCP header information to the log file */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"); /* Write user data to log file */Printdata(buf + Iphdrlen + tcph->doff*4, (size-tcph->doff*4-iph->ihl*4), sniffer); fprintf (Sniffer->logfile, "\n###########################################################");} /* Write UDP packet to log file */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); /* Write the UDP header information into the log file */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"); /* Write user data to log file */printdata (buf + iphdrlen + sizeof UDPH, (size-sizeof UDPH-IPH->IHL * 4), sniffer ); fprintf (Sniffer->logfile, "\n###########################################################");} /* Write ICMP packet to log file */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); /* Write the ICMP header information to the log file */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) = = one) 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"); /* Finally write the user data to the log file */printdata (buf + iphdrlen + sizeof (icmph), (size-sizeof (icmph)-IPH->IHL * 4), Sniffer); fprintf (SNIFFER->LOGFIle, "\n###########################################################");} /* Write user data to log file */void printdata (unsigned char *buf, int size, t_sniffer *sniffer) {int i; for (i = 0; i < size; i++) {if (i% = = 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 SNI Ffer.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__); /* Print Date */Initcolor (Green_color); printf ("[%s]", __time__); /* Print time */Initcolor (zero_color);} void getting_started () {clearscreen ();/* Clear screen */display_time_and_date (); PrinTF ("Getting started of the Network sniffer\n\n"); }/* Main Function Entry */int main () {/* Declaration part */INT SD; int res; int saddr_size; int data_size; struct SOCKADDR saddr; unsigned char *buffer; /* Save data for packet */T_sniffer sniffer; /* Save information such as type of packet and log file */Fd_set Fd_read; Buffer = malloc (sizeof (unsigned char *) * 65536); /* Create a log file in the current folder in a writable manner */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 *)); /* Create the original socket, Eth_p_all represents the Ethernet frame that listens for the payload as an IP datagram */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); /* Loop over the Ethernet frame and call the Processpacket function to parse */while (1) {Fd_zero (&Amp;fd_read); Fd_set (0, &fd_read); Fd_set (SD, &fd_read); /* Multiplexing detects readable sockets and standard inputs */RES = SELECT (SD + 1, &fd_read, NULL, NULL, NULL); if (Res < 0) {close (SD); if (errno! = eintr) perror ("Select ()"); return (exit_failure); } else {/* If the standard input is readable, go to the command line handler Command_interpreter, temporarily only support ' quit ' command */IF (Fd_isset (0, &fd_read)) {if (command_interpreter (SD) = = 1) break; }/* If the socket is readable, read the contents of the Ethernet data frame and call the Processpacket function to parse out the type of packet */else if (Fd_isset (SD, &fd_re AD) {/* Read the contents of the Ethernet data frame */saddr_size = sizeof (SADDR); Data_size = recvfrom (SD, buffer, 65536, 0, &saddr, (socklen_t*) &saddr_size); /* Read the contents of the Ethernet data frame */ if (data_size <= 0) {close (SD); Perror ("Recvfrom ():"); return (exit_failure); } processpacket (buffer, data_size, &sniffer); /* Call the Processpacket function to parse out the packet type */}}} close (SD); return (exit_success);} void Processpacket (unsigned char* buffer, int size, T_sniffer *sniffer) {buffer = buffer + 6 + 6 + 2;/* According to the frame structure of the network, the first 6 B is The destination MAC address, followed by the source MAC address, the next 2B is the frame length, the rest is the load (upper IP datagram) */struct IPHDR *iph = (struct iphdr*) buffer; ++sniffer->prot->total; /* Total number of packets plus 1 */* The packet type of the upper layer is judged based on the value of the Protocol field in the IP data header specified by the TCP/IP protocol */switch (IPH->PROTOCOL) { /* 1 means ICMP protocol */Case 1: ++sniffer->prot->icmp; Print_icmp_packet (buffer, size, sniffer); Break /* 2 Represents the IGMP protocol */Case 2: ++sniffer->prot->igmp; Break /* 6 means TCP protocol */Case 6: ++sniffer->prot->tcp; Print_tcp_packet (buffer, size, sniffer); Break /* 17 means UDP protocol */Case: ++sniffer->prot->udp; Print_udp_packet (buffer, size, sniffer); Break Default: ++sniffer->prot->others; Break } display_time_and_date (); /* Show time */* print information in 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, Sniffe R->prot->others, sniffer->prot->total);}
0X04 Data Report Analysis
Take a UDP packet as an example
***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 attached
I think the highlight of this experiment is the use of script control, it is necessary to learn the script programming
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 Language implementation of Linux network sniffer