How to code a Packet Sniffer in C with Linux Sockets – Part 2

By | August 5, 2020

In the previous part we made a simple sniffer which created a raw socket and started receiving on it. But it had few drawbacks :

1. Could sniff only incoming data.
2. Could sniff only TCP or UDP or ICMP or any one protocol packets at a time.
3. Ethernet headers were not available.

In this article we are going to modify the same code to fix the above 3 drawbacks. We shall be using just linux sockets for sniffing.

Sniffing Ethernet headers

The sniffer program shown in this article will sniff the whole packet, such that the ethernet headers will also be available.

To sniff the ethernet headers we just need to create a socket with some special parameters as shown below.

Instead of :

sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);

We do :

sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;
//Optional
//setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , "eth0" , strlen("eth0")+ 1 );

The third parameter htons(ETH_P_ALL) enables the socket to read full packet content including the ethernet headers.

Now it will :

1. Sniff both incoming and outgoing traffic.
2. Sniff ALL ETHERNET FRAMES , which includes all kinds of IP packets and even more if there are any.
3. Provides the Ethernet headers too , which contain the mac addresses.

The setsockopt line is optional.

Its important to provide the correct interface name to setsockopt , eth0 in this case and in most cases.

So may be you would like to present the user with a list of interfaces available and allow him to choose the one to be sniffed.

Full Code

#include<netinet/in.h>
#include<errno.h>
#include<netdb.h>
#include<stdio.h>	//For standard things
#include<stdlib.h>	//malloc
#include<string.h>	//strlen

#include<netinet/ip_icmp.h>	//Provides declarations for icmp header
#include<netinet/udp.h>	//Provides declarations for udp header
#include<netinet/tcp.h>	//Provides declarations for tcp header
#include<netinet/ip.h>	//Provides declarations for ip header
#include<netinet/if_ether.h>	//For ETH_P_ALL
#include<net/ethernet.h>	//For ether_header
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/ioctl.h>
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>

void ProcessPacket(unsigned char* , int);
void print_ip_header(unsigned char* , int);
void print_tcp_packet(unsigned char * , int );
void print_udp_packet(unsigned char * , int );
void print_icmp_packet(unsigned char* , int );
void PrintData (unsigned char* , int);

FILE *logfile;
struct sockaddr_in source,dest;
int tcp=0,udp=0,icmp=0,others=0,igmp=0,total=0,i,j;	

int main()
{
	int saddr_size , data_size;
	struct sockaddr saddr;
		
	unsigned char *buffer = (unsigned char *) malloc(65536); //Its Big!
	
	logfile=fopen("log.txt","w");
	if(logfile==NULL) 
	{
		printf("Unable to create log.txt file.");
	}
	printf("Starting...\n");
	
	int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;
	//setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , "eth0" , strlen("eth0")+ 1 );
	
	if(sock_raw < 0)
	{
		//Print the error with proper message
		perror("Socket Error");
		return 1;
	}
	while(1)
	{
		saddr_size = sizeof saddr;
		//Receive a packet
		data_size = recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , (socklen_t*)&saddr_size);
		if(data_size <0 )
		{
			printf("Recvfrom error , failed to get packets\n");
			return 1;
		}
		//Now process the packet
		ProcessPacket(buffer , data_size);
	}
	close(sock_raw);
	printf("Finished");
	return 0;
}

void ProcessPacket(unsigned char* buffer, int size)
{
	//Get the IP Header part of this packet , excluding the ethernet header
	struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr));
	++total;
	switch (iph->protocol) //Check the Protocol and do accordingly...
	{
		case 1:  //ICMP Protocol
			++icmp;
			print_icmp_packet( buffer , size);
			break;
		
		case 2:  //IGMP Protocol
			++igmp;
			break;
		
		case 6:  //TCP Protocol
			++tcp;
			print_tcp_packet(buffer , size);
			break;
		
		case 17: //UDP Protocol
			++udp;
			print_udp_packet(buffer , size);
			break;
		
		default: //Some Other Protocol like ARP etc.
			++others;
			break;
	}
	printf("TCP : %d   UDP : %d   ICMP : %d   IGMP : %d   Others : %d   Total : %d\r", tcp , udp , icmp , igmp , others , total);
}

void print_ethernet_header(unsigned char* Buffer, int Size)
{
	struct ethhdr *eth = (struct ethhdr *)Buffer;
	
	fprintf(logfile , "\n");
	fprintf(logfile , "Ethernet Header\n");
	fprintf(logfile , "   |-Destination Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_dest[0] , eth->h_dest[1] , eth->h_dest[2] , eth->h_dest[3] , eth->h_dest[4] , eth->h_dest[5] );
	fprintf(logfile , "   |-Source Address      : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_source[0] , eth->h_source[1] , eth->h_source[2] , eth->h_source[3] , eth->h_source[4] , eth->h_source[5] );
	fprintf(logfile , "   |-Protocol            : %u \n",(unsigned short)eth->h_proto);
}

void print_ip_header(unsigned char* Buffer, int Size)
{
	print_ethernet_header(Buffer , Size);
  
	unsigned short iphdrlen;
		
	struct iphdr *iph = (struct iphdr *)(Buffer  + sizeof(struct ethhdr) );
	iphdrlen =iph->ihl*4;
	
	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(logfile , "\n");
	fprintf(logfile , "IP Header\n");
	fprintf(logfile , "   |-IP Version        : %d\n",(unsigned int)iph->version);
	fprintf(logfile , "   |-IP Header Length  : %d DWORDS or %d Bytes\n",(unsigned int)iph->ihl,((unsigned int)(iph->ihl))*4);
	fprintf(logfile , "   |-Type Of Service   : %d\n",(unsigned int)iph->tos);
	fprintf(logfile , "   |-IP Total Length   : %d  Bytes(Size of Packet)\n",ntohs(iph->tot_len));
	fprintf(logfile , "   |-Identification    : %d\n",ntohs(iph->id));
	//fprintf(logfile , "   |-Reserved ZERO Field   : %d\n",(unsigned int)iphdr->ip_reserved_zero);
	//fprintf(logfile , "   |-Dont Fragment Field   : %d\n",(unsigned int)iphdr->ip_dont_fragment);
	//fprintf(logfile , "   |-More Fragment Field   : %d\n",(unsigned int)iphdr->ip_more_fragment);
	fprintf(logfile , "   |-TTL      : %d\n",(unsigned int)iph->ttl);
	fprintf(logfile , "   |-Protocol : %d\n",(unsigned int)iph->protocol);
	fprintf(logfile , "   |-Checksum : %d\n",ntohs(iph->check));
	fprintf(logfile , "   |-Source IP        : %s\n",inet_ntoa(source.sin_addr));
	fprintf(logfile , "   |-Destination IP   : %s\n",inet_ntoa(dest.sin_addr));
}

void print_tcp_packet(unsigned char* Buffer, int Size)
{
	unsigned short iphdrlen;
	
	struct iphdr *iph = (struct iphdr *)( Buffer  + sizeof(struct ethhdr) );
	iphdrlen = iph->ihl*4;
	
	struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr));
			
	int header_size =  sizeof(struct ethhdr) + iphdrlen + tcph->doff*4;
	
	fprintf(logfile , "\n\n***********************TCP Packet*************************\n");	
		
	print_ip_header(Buffer,Size);
		
	fprintf(logfile , "\n");
	fprintf(logfile , "TCP Header\n");
	fprintf(logfile , "   |-Source Port      : %u\n",ntohs(tcph->source));
	fprintf(logfile , "   |-Destination Port : %u\n",ntohs(tcph->dest));
	fprintf(logfile , "   |-Sequence Number    : %u\n",ntohl(tcph->seq));
	fprintf(logfile , "   |-Acknowledge Number : %u\n",ntohl(tcph->ack_seq));
	fprintf(logfile , "   |-Header Length      : %d DWORDS or %d BYTES\n" ,(unsigned int)tcph->doff,(unsigned int)tcph->doff*4);
	//fprintf(logfile , "   |-CWR Flag : %d\n",(unsigned int)tcph->cwr);
	//fprintf(logfile , "   |-ECN Flag : %d\n",(unsigned int)tcph->ece);
	fprintf(logfile , "   |-Urgent Flag          : %d\n",(unsigned int)tcph->urg);
	fprintf(logfile , "   |-Acknowledgement Flag : %d\n",(unsigned int)tcph->ack);
	fprintf(logfile , "   |-Push Flag            : %d\n",(unsigned int)tcph->psh);
	fprintf(logfile , "   |-Reset Flag           : %d\n",(unsigned int)tcph->rst);
	fprintf(logfile , "   |-Synchronise Flag     : %d\n",(unsigned int)tcph->syn);
	fprintf(logfile , "   |-Finish Flag          : %d\n",(unsigned int)tcph->fin);
	fprintf(logfile , "   |-Window         : %d\n",ntohs(tcph->window));
	fprintf(logfile , "   |-Checksum       : %d\n",ntohs(tcph->check));
	fprintf(logfile , "   |-Urgent Pointer : %d\n",tcph->urg_ptr);
	fprintf(logfile , "\n");
	fprintf(logfile , "                        DATA Dump                         ");
	fprintf(logfile , "\n");
		
	fprintf(logfile , "IP Header\n");
	PrintData(Buffer,iphdrlen);
		
	fprintf(logfile , "TCP Header\n");
	PrintData(Buffer+iphdrlen,tcph->doff*4);
		
	fprintf(logfile , "Data Payload\n");	
	PrintData(Buffer + header_size , Size - header_size );
						
	fprintf(logfile , "\n###########################################################");
}

void print_udp_packet(unsigned char *Buffer , int Size)
{
	
	unsigned short iphdrlen;
	
	struct iphdr *iph = (struct iphdr *)(Buffer +  sizeof(struct ethhdr));
	iphdrlen = iph->ihl*4;
	
	struct udphdr *udph = (struct udphdr*)(Buffer + iphdrlen  + sizeof(struct ethhdr));
	
	int header_size =  sizeof(struct ethhdr) + iphdrlen + sizeof udph;
	
	fprintf(logfile , "\n\n***********************UDP Packet*************************\n");
	
	print_ip_header(Buffer,Size);			
	
	fprintf(logfile , "\nUDP Header\n");
	fprintf(logfile , "   |-Source Port      : %d\n" , ntohs(udph->source));
	fprintf(logfile , "   |-Destination Port : %d\n" , ntohs(udph->dest));
	fprintf(logfile , "   |-UDP Length       : %d\n" , ntohs(udph->len));
	fprintf(logfile , "   |-UDP Checksum     : %d\n" , ntohs(udph->check));
	
	fprintf(logfile , "\n");
	fprintf(logfile , "IP Header\n");
	PrintData(Buffer , iphdrlen);
		
	fprintf(logfile , "UDP Header\n");
	PrintData(Buffer+iphdrlen , sizeof udph);
		
	fprintf(logfile , "Data Payload\n");	
	
	//Move the pointer ahead and reduce the size of string
	PrintData(Buffer + header_size , Size - header_size);
	
	fprintf(logfile , "\n###########################################################");
}

void print_icmp_packet(unsigned char* Buffer , int Size)
{
	unsigned short iphdrlen;
	
	struct iphdr *iph = (struct iphdr *)(Buffer  + sizeof(struct ethhdr));
	iphdrlen = iph->ihl * 4;
	
	struct icmphdr *icmph = (struct icmphdr *)(Buffer + iphdrlen  + sizeof(struct ethhdr));
	
	int header_size =  sizeof(struct ethhdr) + iphdrlen + sizeof icmph;
	
	fprintf(logfile , "\n\n***********************ICMP Packet*************************\n");	
	
	print_ip_header(Buffer , Size);
			
	fprintf(logfile , "\n");
		
	fprintf(logfile , "ICMP Header\n");
	fprintf(logfile , "   |-Type : %d",(unsigned int)(icmph->type));
			
	if((unsigned int)(icmph->type) == 11)
	{
		fprintf(logfile , "  (TTL Expired)\n");
	}
	else if((unsigned int)(icmph->type) == ICMP_ECHOREPLY)
	{
		fprintf(logfile , "  (ICMP Echo Reply)\n");
	}
	
	fprintf(logfile , "   |-Code : %d\n",(unsigned int)(icmph->code));
	fprintf(logfile , "   |-Checksum : %d\n",ntohs(icmph->checksum));
	//fprintf(logfile , "   |-ID       : %d\n",ntohs(icmph->id));
	//fprintf(logfile , "   |-Sequence : %d\n",ntohs(icmph->sequence));
	fprintf(logfile , "\n");

	fprintf(logfile , "IP Header\n");
	PrintData(Buffer,iphdrlen);
		
	fprintf(logfile , "UDP Header\n");
	PrintData(Buffer + iphdrlen , sizeof icmph);
		
	fprintf(logfile , "Data Payload\n");	
	
	//Move the pointer ahead and reduce the size of string
	PrintData(Buffer + header_size , (Size - header_size) );
	
	fprintf(logfile , "\n###########################################################");
}

void PrintData (unsigned char* data , int Size)
{
	int i , j;
	for(i=0 ; i < Size ; i++)
	{
		if( i!=0 && i%16==0)   //if one line of hex printing is complete...
		{
			fprintf(logfile , "         ");
			for(j=i-16 ; j<i ; j++)
			{
				if(data[j]>=32 && data[j]<=128)
					fprintf(logfile , "%c",(unsigned char)data[j]); //if its a number or alphabet
				
				else fprintf(logfile , "."); //otherwise print a dot
			}
			fprintf(logfile , "\n");
		} 
		
		if(i%16==0) fprintf(logfile , "   ");
			fprintf(logfile , " %02X",(unsigned int)data[i]);
				
		if( i==Size-1)  //print the last spaces
		{
			for(j=0;j<15-i%16;j++) 
			{
			  fprintf(logfile , "   "); //extra spaces
			}
			
			fprintf(logfile , "         ");
			
			for(j=i-i%16 ; j<=i ; j++)
			{
				if(data[j]>=32 && data[j]<=128) 
				{
				  fprintf(logfile , "%c",(unsigned char)data[j]);
				}
				else 
				{
				  fprintf(logfile , ".");
				}
			}
			
			fprintf(logfile ,  "\n" );
		}
	}
}

The log file will looks somewhat like this :

***********************TCP Packet*************************

Ethernet Header
   |-Destination Address : 00-25-5E-1A-3D-F1 
   |-Source Address      : 00-1C-C0-F8-79-EE 
   |-Protocol            : 8 

IP Header
   |-IP Version        : 4
   |-IP Header Length  : 5 DWORDS or 20 Bytes
   |-Type Of Service   : 0
   |-IP Total Length   : 141  Bytes(Size of Packet)
   |-Identification    : 13122
   |-TTL      : 64
   |-Protocol : 6
   |-Checksum : 45952
   |-Source IP        : 192.168.1.6
   |-Destination IP   : 74.125.71.125

TCP Header
   |-Source Port      : 33655
   |-Destination Port : 5222
   |-Sequence Number    : 78458457
   |-Acknowledge Number : 2427066746
   |-Header Length      : 5 DWORDS or 20 BYTES
   |-Urgent Flag          : 0
   |-Acknowledgement Flag : 1
   |-Push Flag            : 1
   |-Reset Flag           : 0
   |-Synchronise Flag     : 0
   |-Finish Flag          : 0
   |-Window         : 62920
   |-Checksum       : 21544
   |-Urgent Pointer : 0

                        DATA Dump                         
IP Header
    00 25 5E 1A 3D F1 00 1C C0 F8 79 EE 08 00 45 00         .%^.=.....y...E.
    00 8D 33 42                                             ..3B
TCP Header
    40 00 40 06 B3 80 C0 A8 01 06 4A 7D 47 7D 83 77         @.@..?....J}G}.w
    14 66 04 AD                                             .f..
Data Payload
    17 03 01 00 60 A0 9C 5D 14 A1 25 AB CE 8B 7C EB         ....`..]..%...|.
    1A A4 43 A6 60 DD E8 6B 6E 43 C1 94 6A D2 25 23         ..C.`..knC..j.%#
    03 98 59 67 1A 2C 07 D3 7E B2 B8 9F 83 38 4C 69         ..Yg.,..~....8Li
    D3 3A 8E 0D 9E F0 6B CE 9E 6B F4 E1 BD 9E 50 53         .:....k..k....PS
    6D F6 AB 11 05 D6 41 82 F0 03 0C A6 E2 48 2B 71         m.....A......H+q
    16 81 FF 5B DF 50 D4 5B AD 90 04 5E 4C 94 E7 9B         ...[.P.[...^L...
    0B 72 7E 32 88                                          .r~2.

###########################################################

In the above log we can see the ethernet headers being printed. They show the source and destination mac address along with the packet protocol. 8 means IP protocol

Note :

1. If you want to sniff only IP and ARP packets for example then you can try this :
sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_IP|ETH_P_ARP)) ;

The complete list of protocols is found in /usr/include/linux/if_ether.h

/*
 *	These are the defined Ethernet Protocol ID's.
 */

#define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
#define ETH_P_PUP	0x0200		/* Xerox PUP packet		*/
#define ETH_P_PUPAT	0x0201		/* Xerox PUP Addr Trans packet	*/
#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
#define ETH_P_X25	0x0805		/* CCITT X.25			*/
#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
#define	ETH_P_BPQ	0x08FF		/* G8BPQ AX.25 Ethernet Packet	[ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_IEEEPUP	0x0a00		/* Xerox IEEE802.3 PUP packet */
#define ETH_P_IEEEPUPAT	0x0a01		/* Xerox IEEE802.3 PUP Addr Trans packet */
#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
#define ETH_P_LAT       0x6004          /* DEC LAT                      */
#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
#define ETH_P_CUST      0x6006          /* DEC Customer use             */
#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
#define ETH_P_TEB	0x6558		/* Trans Ether Bridging		*/
#define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
#define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
#define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
#define ETH_P_8021Q	0x8100          /* 802.1Q VLAN Extended Header  */
#define ETH_P_IPX	0x8137		/* IPX over DIX			*/
#define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
#define ETH_P_PAUSE	0x8808		/* IEEE Pause frames. See 802.3 31B */
#define ETH_P_SLOW	0x8809		/* Slow Protocol. See 802.3ad 43B */
#define ETH_P_WCCP	0x883E		/* Web-cache coordination protocol
					 * defined in draft-wilson-wrec-wccp-v2-00.txt */
#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
#define ETH_P_MPLS_UC	0x8847		/* MPLS Unicast traffic		*/
#define ETH_P_MPLS_MC	0x8848		/* MPLS Multicast traffic	*/
#define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
#define ETH_P_LINK_CTL	0x886c		/* HPNA, wlan link local tunnel */
#define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
					 * over Ethernet
					 */
#define ETH_P_PAE	0x888E		/* Port Access Entity (IEEE 802.1X) */
#define ETH_P_AOE	0x88A2		/* ATA over Ethernet		*/
#define ETH_P_TIPC	0x88CA		/* TIPC 			*/
#define ETH_P_1588	0x88F7		/* IEEE 1588 Timesync */
#define ETH_P_FCOE	0x8906		/* Fibre Channel over Ethernet  */
#define ETH_P_FIP	0x8914		/* FCoE Initialization Protocol */
#define ETH_P_EDSA	0xDADA		/* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */

/*
 *	Non DIX types. Won't clash for 1500 types.
 */

#define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
#define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
#define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
#define ETH_P_802_2	0x0004		/* 802.2 frames 		*/
#define ETH_P_SNAP	0x0005		/* Internal only		*/
#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
#define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type 	*/
#define ETH_P_CAN	0x000C		/* Controller Area Network      */
#define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
#define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
#define ETH_P_MOBITEX	0x0015		/* Mobitex ([email protected])	*/
#define ETH_P_CONTROL	0x0016		/* Card specific control frames */
#define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
#define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
#define ETH_P_HDLC	0x0019		/* HDLC frames			*/
#define ETH_P_ARCNET	0x001A		/* 1A for ArcNet :-)            */
#define ETH_P_DSA	0x001B		/* Distributed Switch Arch.	*/
#define ETH_P_TRAILER	0x001C		/* Trailer switch tagging	*/
#define ETH_P_PHONET	0x00F5		/* Nokia Phonet frames          */
#define ETH_P_IEEE802154 0x00F6		/* IEEE802.15.4 frame		*/
#define ETH_P_CAIF	0x00F7		/* ST-Ericsson CAIF protocol	*/

Enjoy!!

About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

71 Comments

How to code a Packet Sniffer in C with Linux Sockets – Part 2
  1. Rick

    Hi… Thank you for the Excellent Tutorials and practical program examples.
    I was trying to sniff only ARP/RARP and DHCP (or if needed BootP) packets on my network, because it is a mix of DHCP and static IP configurations. I was wondering what would be the values in the third option of the socket(…,…,???) function?
    Help would be greatly appreciated.
    Thanks..

  2. Alisson Oliveira Chaves

    “1. Sniff both incoming and outgoing traffic.”

    Outgoing is only in ETH_P_ALL option? or can i set custom protocol and filter outgoing traffic ?

  3. Riku

    Hey there !
    First up: Thank you mate, you helped me alot.
    But I got one question: Are you sure:

    sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_IP|ETH_P_ARP)) ;

    works this way ? I Tried to filter IPV4 (0x8000) and a fieldbus protocol (0x8892) but I cant seem to make it work. For some reason it only detects the fieldbus protocol. I tested each protocol seperatly and it works fine. My line of code looks like this:

    sock_raw = socket( AF_PACKET , SOCK_RAW , htons(0x8000|0x8892)) ;

    Maybe you got an idea.

  4. novice

    Hi

    I am struggling to use source code (part 2). Unfortunately I don’t have experience how to use source code, so what I did was copied the code into a file using
    vi capture-
    then saved the file and issued
    chmod u+x capture-

    [root@server ~]# ./capture-
    ./capture-code: line 21: syntax error near unexpected token `(‘
    ./capture-code: line 21: `void ProcessPacket(unsigned char* , int);’

    Please advise how to get this working. More over can I save the captured data in a format to be opened with Wireshark ?

    Thanks

  5. crob

    good example, learned!
    i come here as libpcap drop udp packet, after some google, they tell me the pcap_setuserbuf not implement for linux, so I have to use raw sock, you showed a good sample code.
    thank you.
    my website is http://www.crobsoft.com

  6. ricky

    Hi, I think the hyperlink “previous part” is not working! I wanted to write a C/C++ program that make use of divert sockets (FreeBSD) which will block all incoming icmp packets. Any clue on how to do that ? Thanks in advance.

  7. Narendra

    Hi,

    I want to capture a random tcp packet.
    The program has to run as an ordinary user.
    Any idea, how this can be done?
    If it is not possible to capture tcp packet, is it possible to capture a http packet or any other protocol packet?
    Please suggest.

    Thanks,
    Narendra

  8. Jason Chien

    this code works on my centos 6.8 i386, but I also did some fixes.

    if you just copy & paste on your platform, it may show compile error.
    you have to refer to your include files to fix those issues.
    there are a lot of different in the struct.

  9. Nick

    Will this work on other distributions? I’m about to install kali and I use this as a guide for my project so that information will be helpful to me a lot

  10. lilington

    just to tell i notice an error in your code for all Print functions you forgot to shift before writting data.

    fprintf(stdout,”IP Header\n”);
    Print_data((pkt + sizeof(struct ethhdr)),s_iph);

    fprintf(stdout,”TCP Header\n”);
    Print_data(pkt + sizeof(struct ethhdr) + s_iph,tcph->doff * 4);

    fprintf(stdout,”Data Payload\n”);
    Print_data(pkt + sizeof(struct ethhdr) + s_iph + tcph->doff * 4, (s_pkt – tcph->doff * 4 – s_iph – sizeof(struct ethhdr)));

  11. Rick

    Very nice piece of code. One question – If I want to read UDP only from a single interface (eth1), but I want the full ethernet frame passed along, is that possible?

  12. chintan prajapati

    thank you for this.

    when i compile your code in my mac book early pro it will show these errors

    sniff.c:44:28: error: use of undeclared identifier ‘AF_PACKET’

    int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;

    ^

    sniff.c:44:57: error: use of undeclared identifier ‘ETH_P_ALL’

    int sock_raw = socket( AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ;

  13. Mahesh Kumar

    Hi… Is it possible to capture wireless packets using the above code?? How to specify the interface in which the packets captured??

    I changed the piece of code as below, but it is not capturing the packets coming from wireless interface.
    It is capturing the packets from other interfaces, but not specifically on wlan0

    setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , “wlan0” , strlen(“wlan0”)+ 1 );

  14. Maurice

    Hi dude, first, thank you so much for this very clean, elegant and simple approach. I have a question, how can filter LLC packets? Yes, I’ve read that the ETH_P_802_2 variable aids to do this work, but I want to know, if existe a type (like 0x0800) for this type of protocol. Merci beaucoup!

  15. Anumod

    Is it possible to capture all the packets in the network through raw sockets like libpcap.
    With this code able to capture all the packets with source/destination as our IP, but not capturing packets with out our Ip. please help.

  16. RoboSpud

    Thanks so much for this! I’ve been hassling with Python to get raw packets for weeks now. This is more my element.

    1. Silver Moon

      the code actually captures all ethernet packets including arp packets.
      In case of ARP packets the protocol field of the ethernet header would contain the value 0x0806

      So you can check like this
      if( ntohs(eth->h_proto) == 0x0806 ) { // arp packet, process }

      thats the basic idea, you would need to parse the arp packet according to its packet structure, details of which can found on google.

  17. ben_schneider

    Hello,

    Thank you for the code.

    In my application I try to sniff all the incoming data.

    My application run correctly only if wireshark run in the same time !

    Could you help me to find some clues ?

  18. Shishira s r

    thank you for the code which will help me a lot. My question is These received packets are saved in a text file. but i want to know infact my project is about saving the captured packets in a binary file. how do i do this ? i checked with your code and replaced fprintf to ‘fwrite’ . but i am not able to find the solution sir

  19. Anes P.A

    Dear Moon,
    As part of academic lab program , I had a lab content “Working with sniffer for monitoring network communication(Ethereal)” . Tell me , your code will work on Windows Turbo C environment ? Is that code satisfy
    our requirement . please advise fast

    Thanks,
    Anes

  20. Chirag modi

    Thanks for providing this code. This helps to me a lot. I have a one question? How to extract and print vlan_id and vlan_tag from the vlan tagged packets? or which modification in this code are needed to do the same? Please help me for providing proper answer.

    Thanks in advance.

  21. Anuar

    Based on my understanding reading the raw socket document, basically all the known type of packets for example (TCP/IP) will be passed to the kernel stack and a copy is sent to the raw socket. Is there a way not to send any packets to the kernel stack and only send to the raw socket? I want to controll all the incoming and out going packet through the raw socket application. Thank in advance. Anuar.

  22. Saviour

    void convrt(const u_char * Buffer, int Size)
    {
    unsigned short iphdrlen;
    struct iphdr *iph = (struct iphdr *)( Buffer + sizeof(struct ethhdr) );
    iphdrlen = iph->ihl*4;
    struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr));
    int header_size = sizeof(struct ethhdr) + iphdrlen + tcph->doff*4;
    char typ[65536];
    //typ = Buffer + header_size;
    //strncpy(typ, Buffer + header_size, Size – header_size);

    int i,j;
    for(i=0;i <= Size – header_size; i++)
    {
    typ[i] = *(Buffer+header_size+i);
    }
    for(j=0;j<= Size-header_size; j++)
    {
    printf("%c",(unsigned int)typ[j]);
    }
    }

    i wrote this additional function and i call it in the program, want to return whatever the printf() is diplaying as a char* but whenever i try to do that i guess there is some UB and the program just closes. how can i acomplish that?? plz. or how can i make this function return a string??

  23. Pablognu

    Hello, i’m trying to adapt your code to analyze an IP packet captured with a breakout on a serial port. I capture a PPP packet and after analyze it i extract the IP packet i need to obtain the data into it.

    For example, this is a PPP packet: ff 03 21 45 00 00 3d 04 46 40 00 7c 06 f7 6b 0a 1f ed ce 0a 08 01 14 10 14 42 69 92 a2 cd 08 9a 49 56 38 50 18 44 70 10 80 00 00 68 0f 0f 68 c4 14 01 c9 01 06 00 14 01 fc f8 c7 51 01 14 df 16 ca 4e

    After analyze it i have the TCP: 45 00 00 3d 04 46 40 00 7c 06 f7 6b 0a 1f ed ce 0a 08 01 14 10 14 42 69 92 a2 cd 08 9a 49 56 38 50 18 44 70 10 80 00 00 68 0f 0f 68 c4 14 01 c9 01 06 00 14 01 fc f8 c7 51 01 14 df 16

    And thats the buffer that i want to use with your code. But with out modification, when i try to compile your original code i got this errors: http://pastebin.com/SQKxMEUH.

    Please if you can help me.

    Thanks and sorry for my bad english.

  24. Adam

    okay i am capturing the packets using this code i ahve made specific changes suitable for my use, i wanted to ask in the first response packet that contains the headers of the response i want to extract the values of Content-Length and the Content-type fields from the buffer. i tried strstr but it is no use because of nulls. any suggestions. i will be very grateful if somone can share a small function to do so.

    1. Silver Moon

      in the functions print_icmp_packet, print_tcp_packet and print_udp_packet the payload can be extracted as follows

      char *payload = Buffer + header_size;
      int payload_size = Size – header_size;

      buffer is the full packet content. removing the headers from the buffer will give the payload.

  25. QmQ

    Ah, I forgot. Also in processing UDP you’ve made a subtle mistake of using sizeof(udph) instead of sizeof(udphdr).
    udph is of pointer type so the sizeof is 4 on 32bit OSes and 8 on 64bit OSes
    The size of the UDP header is 8 bytes. So by pure mistake people who compile and use this as 64 bit code won’t be surprised. On 32 bits – they might be ;)

  26. QmQ

    I didn’t read all the comments so maybe someone has pointed this out already but there’s a mistake in the raw data dumping part. There’s no place where buffer is incremented so it points to the Ethernet header. But you dump it as the IP header – you directly pass Buffer instead of Buffer+sizeof(ethhdr). And it’s wrong all the way up/down the stack.

    Please fix it as this is the most popular sniffer example and people will get confused :)

    1. lilington

      Look’s like he let it like this on purpose to be useful only to those who are not just copying the code.
      If you wrote it yourself you will notice and correct it.

  27. codingrox

    Hello,

    How can we get all the packets from a single download and get the total byte count and reassemble these packets?

  28. ken

    it is really great code!!!

    I want to what is benefit by using pure linux socket not pcap libray

    and the important one

    how to output .pcap with this code

    thanks~

        1. Silver Moon Post author

          speed difference might not be that noticeable, and I am not sure of how it effects.
          But using pcap makes the program more portable and removes the need to use sockets in the code.

  29. Shyam

    Can u please explain the below part clearly???

    struct iphdr *iph = (struct iphdr *)( Buffer + sizeof(struct ethhdr) );
    iphdrlen = iph->ihl*4
    struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr));

    1. Silver Moon Post author

      struct iphdr *iph = (struct iphdr *)( Buffer + sizeof(struct ethhdr) );

      — the above line gets the pointer to the ip header in the structure ‘iphdr’ which can be used to access individual fields of the header

      iphdrlen = iph->ihl*4

      — the above computes the length of the ip header using the ‘ihl’ field of the ip header. the ihl field contains the ip header length in total bytes/4.

      struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr));

      — the above line gets the pointer to the tcp header in the structure ‘tcphdr’ which can be used to access the individual fields of the tcp header.

      Its all pointers and structures.

      1. Shyam

        Hi thanks for your quick reply.. But why are you adding buffer also.. The whole packet including all layer headers will be there in the buffer rite.. am i right??? if it is so, adding buffer(65536) will move the pointer away from buffer right?

        1. Silver Moon Post author

          Buffer is the pointer to the first character of the whole packet, so adding to it moves inside the buffer.

          1. Shyam

            nice nice.. got it.. Am new to socket programming. Asking silly questions. Can we further go beyond and find what is the corresponding application layer protocol of the packet

          2. Silver Moon Post author

            To find the application layer protocol (like wireshark does) will require studying various applications and find what rules they have.
            For example a udp packet with destination port 53 is a dns query packet. And a packet with destination port 80 is very likely an “http” packet.

            So properties like port number and protocol combinations have to be checked and then the application layer protocol can be detected.

      1. Mayank

        I wish to know the SSID , association request / reply frames and other MAC layer frames. This deals mostly with the network layer.

  30. Tedre191

    Very nice !
    But is it normal that I can’t reveive ARP broadcast packet when the ARP request is for my PC ?

    Ex :
    Linux Server : 192.168.0.100
    MyLaptop : 192.168.0.150

    When I’m doing an ARP request to 192.168.0. with arping on my server, I reveive the packet on my laptop with your exemple but when I’m doing an arping 192.168.0.150, your exemple don’t catch it .. why ?

    Both exemple send an arp packet to broadcast so why i’m not getting it when the request is for the computer running the code ?
    When i’m using Wireshark, i’m seeing the arp request and the arp response packet.

    Thanks

  31. sebaz

    Thanks for this really useful article! Nicely explained but I have still one question regarding the binding to an interface. I want only to sniff the packets from my fixed network interface, but not from my WLAN interface. So I uncommented the setsockopt line and changed the name of the interface to eth0. But still I see packets from both network interfaces (I used wireshark to compare the results).

    I also tried the following code, but it seems not to work too.

    struct ifreq Interface;
    memset(&Interface, 0, sizeof(Interface));
    strncpy(Interface.ifr_ifrn.ifrn_name, “eth1”, IFNAMSIZ);
    setsockopt(sock_raw, SOL_SOCKET, SO_BINDTODEVICE, &Interface,sizeof(Interface))

    Any ideas what I’m doing wrong?

  32. Adane

    hello Sir,
    thank you for the post and it is clear to understand the steps. is it possible to create some sort of GUI for the code so that users can initiate the sniffing by clicking instead of writing a command and also so that users can see easily what is being captured? if possible where should i get started?

    Best Regards,
    Adane

    1. Binary Tides Post author

      Yes , its possible to write a gui application that uses the above code to sniff data.
      You need to choose a gui library. I would suggest wxwidgets.
      It is a cross platform c/c++ library for creating gui apps.

  33. kingsmasher1

    Dear Binary Tides, it’s so simple and easy to understand. Thanks for the code. I compiled and run fine. Just one confusion. In the `printData( )` function, line number 292 baffles me. If you have already progressed upto say i = x, then printing data[j] prints a character which is already printed since you are taking j = i – 16.

    Can you please help me to explain me the alphanumeric printing of code? Rest of the parts are clear.

    Thanks in advance.

  34. raj

    Hello Sir,
    I try to run the code in ubuntu 11.04 terminal and i am getting an error as follows:

    ~$ gcc packetsniffr2c.c
    packetsniffr2c.c: In function ‘main’:
    packetsniffr2c.c:59:3: warning: passing argument 5 of ‘recvfrom’ from incompatible pointer type
    /usr/include/sys/socket.h:166:16: note: expected ‘struct sockaddr * __restrict__’ but argument is of type ‘struct sockaddr_in *’

    So, please help me out to correct this error. I will be thank full to you.

    Regrads,
    Raj

Leave a Reply

Your email address will not be published. Required fields are marked *