Network tools like wireshark, tcpdump, etc, are fairly popular for packet sniffing. This article provides a basic overview of the libpcap library which forms the base of packet sniffing for many network monitoring tools including wireshark, tcpdump, snort, etc.
What is Packet Sniffing and How it Works?
Packet sniffing is a technique through which the network data to and from your computer can be monitored easily. The data travels on network in form of packets and a packet sniffing tool can easily capture these packets. Mostly packet sniffers are used by network administrators and developers working on network tools. But, overall packet sniffers are handy for debugging network related problems and can be used by anyone who has the required privileges.
Packet sniffers work by sniffing on an interface device like eth0 etc. A list of interfaces can be obtained by the command ifconfig. Once the interface is selected, there can be some options through which one can filter out the packets based on protocol, source port, destination port etc. Choosing a filter option is not necessary. Thereon the packet capture is started.
To understand packet capture and display filters, refer to our tutorial on wireshark. For command line tool, refer to tcpdump, which also does packet sniffing but produces output on the command line.
The libpcap library
Libpcap is the underlying library used for packet sniffing by many of the popular network monitoring tools. To understand the use of this library, one requires basic understanding of C programming language.
Here is how libpcap works :
- Choose the network interface device on which the packet sniffing is to be done. For example ‘eth0’ , ‘wlan0’ etc on Linux.
- Once the device is chosen, initialize the pcap library with this device.
- Next, we can apply filter options for cases like if we want to sniff only TCP/IP packets or if we want to specify that sniff packets only from a particular source or destination port etc. This filter is compiled and then applied using a set of libpcap library functions.
- Next the pcap library enters into its packet capturing loop where it captures number of packets as set by the program.
- Once a packet is captures, a callback function is called in which whole of the packet is available to print its details or use it an any other way
The above mentioned four steps are the basic steps to start a packet capture through libpcap.
An example
The code below makes use of the libpcap functions to achieve a basic packet capture. After capturing the packets, inside the callback function, the length of each packet is printed on stdout.
#include <pcap.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/if_ether.h> #include <netinet/tcp.h> #include <netinet/ip.h> #include <string.h> void callback(u_char *useless,const struct pcap_pkthdr* pkthdr,const u_char* packet) { static int count = 1; printf("\nPacket number [%d], length of this packet is: %d\n", count++, pkthdr->len); } int main(int argc,char **argv) { char *dev; char errbuf[PCAP_ERRBUF_SIZE]; pcap_t* descr; struct bpf_program fp; /* to hold compiled program */ bpf_u_int32 pMask; /* subnet mask */ bpf_u_int32 pNet; /* ip address*/ pcap_if_t *alldevs, *d; char dev_buff[64] = {0}; int i =0; // Check if sufficient arguments were supplied if(argc != 3) { printf("\nUsage: %s [protocol][number-of-packets]\n",argv[0]); return 0; } // Prepare a list of all the devices if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } // Print the list to user // so that a choice can be // made printf("\nHere is a list of available devices on your system:\n\n"); for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (Sorry, No description available for this device)\n"); } // Ask user to provide the interface name printf("\nEnter the interface name on which you want to run the packet sniffer : "); fgets(dev_buff, sizeof(dev_buff)-1, stdin); // Clear off the trailing newline that // fgets sets dev_buff[strlen(dev_buff)-1] = ''; // Check if something was provided // by user if(strlen(dev_buff)) { dev = dev_buff; printf("\n ---You opted for device [%s] to capture [%d] packets---\n\n Starting capture...",dev, (atoi)(argv[2])); } // If something was not provided // return error. if(dev == NULL) { printf("\n[%s]\n", errbuf); return -1; } // fetch the network address and network mask pcap_lookupnet(dev, &pNet, &pMask, errbuf); // Now, open device for sniffing descr = pcap_open_live(dev, BUFSIZ, 0,-1, errbuf); if(descr == NULL) { printf("pcap_open_live() failed due to [%s]\n", errbuf); return -1; } // Compile the filter expression if(pcap_compile(descr, &fp, argv[1], 0, pNet) == -1) { printf("\npcap_compile() failed\n"); return -1; } // Set the filter compiled above if(pcap_setfilter(descr, &fp) == -1) { printf("\npcap_setfilter() failed\n"); exit(1); } // For every packet received, call the callback function // For now, maximum limit on number of packets is specified // by user. pcap_loop(descr,atoi(argv[2]), callback, NULL); printf("\nDone with packet sniffing!\n"); return 0; }
In the code above :
- The function pcap_findalldevs() is used to fetch a list of all available interface devices. This list can be shown to the user so that the intended interface can be selected to sniff packets on. Please note that these is exists a function pcap_lookupdev() that also returns an interface device but the problem with this function is that it returns the first available non loop-back device. So in case I am using wireless network connection and the interface device for my connection is ‘wlan0’ but pcap_lookupdev() function would still return ‘eth0’ as it encounters this interface first. So using pcap_findalldevs() is a better option as it produces a list of interface devices to choose from.
- The list returned by the function pcap_findalldevs() is given to user and the user’s input is taken from stdin.
- Then the function pcap_lookupnet() is used to fetch the ip address and network mask.
- Through the function pcap_open_live() the pcap library is initialized with the interface device selected.
- Through pcap_compile() function , we can compile any filter on protocol etc set by the user.
- Through pcap_setfilter(), this filter is applied.
- Finally through function pcap_loop() the library starts packet capture on the selected device with the filter applied and with every relevant packet captured, the callback function is called.
Here is the output of above program :
$ sudo ./pcap tcp 10 [sudo] password for himanshu: Here is a list of available devices on your system: 1. eth0 (Sorry, No description available for this device) 2. wlan0 (Sorry, No description available for this device) 3. usbmon1 (USB bus number 1) 4. usbmon2 (USB bus number 2) 5. usbmon3 (USB bus number 3) 6. usbmon4 (USB bus number 4) 7. usbmon5 (USB bus number 5) 8. usbmon6 (USB bus number 6) 9. usbmon7 (USB bus number 7) 10. any (Pseudo-device that captures on all interfaces) 11. lo (Sorry, No description available for this device) Enter the interface name on which you want to run the packet sniffer : wlan0 ---You opted for device [wlan0] to capture [10] packets--- Starting capture... Packet number [1], length of this packet is: 496 Packet number [2], length of this packet is: 66 Packet number [3], length of this packet is: 357 Packet number [4], length of this packet is: 66 Packet number [5], length of this packet is: 238 Packet number [6], length of this packet is: 66 Packet number [7], length of this packet is: 403 Packet number [8], length of this packet is: 66 Packet number [9], length of this packet is: 121 Packet number [10], length of this packet is: 66 Done with packet sniffing!
If you are not executing the above program as root, you should use sudo to run the program as the actions done by libpcap library requires super user privileges.
Comments on this entry are closed.
Wow, great article!!! I always wondered how this was done and now I know. Keep up the great work!!!
Really a nice article.
I have used wireshark and tcpdump. But i have not thought about how those tools works.
Good work!!!
HELP!! why I failed when I run out on the terminal>> sniffer.c: 66:36: error: empty character constant
pcap_open_live() fails for eth1 which is actually the active interface in my machine. Error is- the device does not exist. Can you please help me to fix this problem?
To avoid the empty character constant problem, write
dev_buff[strlen(dev_buff)-1] =”;
Select the root for compiling file testing.c
gcc testing.c -lpcap -o testing
For Execution write
./testing tcp 10
Missing zero digit for initilizing in ….dev_buff[strlen(dev_buff)-1] =’0′;
The dev_buff[strlen(dev_buff)-1] should be initialized with zero (=’0′) to eliminate or clear off the trailing newline that fgets sets, like dev_buff[strlen(dev_buff)-1] =’0′
Instead of:
dev_buff[strlen(dev_buff)-1] =’0′;
Try:
dev_buff[strlen(dev_buff)-1] =”;
It works for me.
Correction:
========
Instead of:
dev_buff[strlen(dev_buff)-1] =’0′;
Try:
dev_buff[strlen(dev_buff)-1] =’\’;
It works for me.
Typo correction 2:
==============
Instead of:
dev_buff[strlen(dev_buff)-1] =’0′;
Try:
dev_buff[strlen(dev_buff)-1] ='(anti-slash character)0′;
It works for me.
Remember this: ‘0’ != 0
So the solution is here:
dev_buff[strlen(dev_buff)-1] = 0;
Otherwise, the device will be affected by the assigned char.
Hi all,
Help —> Have tried all the given solutions by the people above me and none of it works..
^^ Sasha- Have u got urs working .. I tried your solution and dint work as well..
Yes, it works for me. Con you compile the code with this command?
gcc testing.c -lpcap -o testing
Thanks a lot Sasha.. got compiled .. but i still get this error when i run it
sudo ./testing tcp 10
Here is a list of available devices on your system:
1. eth0 (Sorry, No description available for this device)
2. wlan0 (Sorry, No description available for this device)
3. any (Pseudo-device that captures on all interfaces)
4. lo (Sorry, No description available for this device)
Enter the interface name on which you want to run the packet sniffer : 3
—You opted for device [3] to capture [10] packets—
Starting capture…pcap_open_live() failed due to [3: No such device exists (SIOCGIFHWADDR: No such device)]
It is the case for all 4 interfaces that i tried… It will be great if you could help out
Thanks
silly of me to do that … should have entered interface name.. even then i get a pcap_compile failed error..
Works perfectly fine in an another system.. Thanks a lot Sasha
Hello, Thanks for great information.
I want to use libpcap to capture the MAC addresses of all station which are connected or not connected to a AP. Could you please help me? Should I put my wlan0 on monitor mode? What should I add to this code to do this.
I want to compile the code on a router linux operation system to detect MAC addresses of the devices with time stamp.