Libpcap is a packet capture library which can be used to sniff packets or network traffic over a network interface. Pcap Documentation gives a description of the methods and data structures available in the libpcap library.
To install libpcap on your linux distro you can either download the source from the website and compile it and install. Or if you are on a distro like ubuntu then it can be installed from synaptic package manager. In the list of packages in Synaptic Package Manager look for 2 packages named as libpcap0.8 and libpcap0.8-dev. Install both of them.
To start with the C program the simple steps would be :
1. Find all available devices – find_alldevs()
find_alldevs() is the function which can be used to get a list of all available network devices or interfaces present on the machine or which can be opened by pcap_open_live() for sniffing purpose.
The prototype is as :
int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
where alldevsp is a pointer to an array of of pcap_if_t structures and errbuf is a character pointer and will contain any error message that occured during the function call.
2. Select a device for sniffing data – pcap_open_live()
pcap_open_live() is the function to get a packet capture descriptor or a handle to a device which has been opened up for sniffing. The protoype is as :
pcap_t *pcap_open_live(const char *device, int snaplen,int promisc, int to_ms, char *errbuf)
device – is the name of the device as obtained from the call to pcap_findalldevs.
snaplen – is the maximum amount of data to be captured. 65536 should be sufficient length.
promisc – 0 or 1 to indicate whether to open the device in promiscuous mode.
to_ms – the timeout in milliseconds , 0 for no timeout
errbuf – buffer to contain any error message
It returns a device handler in the form of the structure pcap_t which can be used by pcap_loop() to capture data from.
3. Start sniffing the device – pcap_loop()
4. Process the sniffed packet – user defined callback method
Code :
/*
Packet sniffer using libpcap library
*/
#include<pcap.h>
#include<stdio.h>
#include<stdlib.h> // for exit()
#include<string.h> //for memset
#include<sys/socket.h>
#include<arpa/inet.h> // for inet_ntoa()
#include<net/ethernet.h>
#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
void
process_packet(u_char *,
const
struct
pcap_pkthdr *,
const
u_char *);
void
process_ip_packet(
const
u_char * ,
int
);
void
print_ip_packet(
const
u_char * ,
int
);
void
print_tcp_packet(
const
u_char * ,
int
);
void
print_udp_packet(
const
u_char * ,
int
);
void
print_icmp_packet(
const
u_char * ,
int
);
void
PrintData (
const
u_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()
{
pcap_if_t *alldevsp , *device;
pcap_t *handle;
//Handle of the device that shall be sniffed
char
errbuf[100] , *devname , devs[100][100];
int
count = 1 , n;
//First get the list of available devices
printf
(
"Finding available devices ... "
);
if
( pcap_findalldevs( &alldevsp , errbuf) )
{
printf
(
"Error finding devices : %s"
, errbuf);
exit
(1);
}
printf
(
"Done"
);
//Print the available devices
printf
(
"\nAvailable Devices are :\n"
);
for
(device = alldevsp ; device != NULL ; device = device->next)
{
printf
(
"%d. %s - %s\n"
, count , device->name , device->description);
if
(device->name != NULL)
{
strcpy
(devs[count] , device->name);
}
count++;
}
//Ask user which device to sniff
printf
(
"Enter the number of the device you want to sniff : "
);
scanf
(
"%d"
, &n);
devname = devs[n];
//Open the device for sniffing
printf
(
"Opening device %s for sniffing ... "
, devname);
handle = pcap_open_live(devname , 65536 , 1 , 0 , errbuf);
if
(handle == NULL)
{
fprintf
(stderr,
"Couldn't open device %s : %s\n"
, devname , errbuf);
exit
(1);
}
printf
(
"Done\n"
);
logfile=
fopen
(
"log.txt"
,
"w"
);
if
(logfile==NULL)
{
printf
(
"Unable to create file."
);
}
//Put the device in sniff loop
pcap_loop(handle , -1 , process_packet , NULL);
return
0;
}
void
process_packet(u_char *args,
const
struct
pcap_pkthdr *header,
const
u_char *buffer)
{
int
size = header->len;
//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(
const
u_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(
const
u_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(
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;
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(
const
u_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(
const
u_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 (
const
u_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"
);
}
}
}
|
Compile :
1 |
$ gcc lsniffer.c -lpcap -o lsniffer |
The output on the terminal would be like this :
1 |
$ sudo ./lsniffer |
2 |
Finding available devices ... Done |
3 |
Available Devices are : |
4 |
1. eth0 - (null) |
5 |
2. usbmon1 - USB bus number 1 |
6 |
3. usbmon2 - USB bus number 2 |
7 |
4. usbmon3 - USB bus number 3 |
8 |
5. usbmon4 - USB bus number 4 |
9 |
6. usbmon5 - USB bus number 5 |
10 |
7. usbmon6 - USB bus number 6 |
11 |
8. usbmon7 - USB bus number 7 |
12 |
9. any - Pseudo-device that captures on all interfaces |
13 |
10. lo - (null) |
14 |
Enter the number of the device you want to sniff : 1 |
15 |
Opening device eth0 for sniffing ... Done |
16 |
TCP : 57 UDP : 17 ICMP : 16 IGMP : 1 Others : 0 Total : 90 |
The logfile would look like this :
1 |
***********************UDP Packet************************* |
2 |
3 |
Ethernet Header |
4 |
|-Destination Address : 00-1C-C0-F8-79-EE |
5 |
|-Source Address : 00-1E-58-B8-D4-69 |
6 |
|-Protocol : 8 |
7 |
8 |
IP Header |
9 |
|-IP Version : 4 |
10 |
|-IP Header Length : 5 DWORDS or 20 Bytes |
11 |
|-Type Of Service : 0 |
12 |
|-IP Total Length : 257 Bytes(Size of Packet) |
13 |
|-Identification : 13284 |
14 |
|-TTL : 63 |
15 |
|-Protocol : 17 |
16 |
|-Checksum : 55095 |
17 |
|-Source IP : 208.67.222.222 |
18 |
|-Destination IP : 192.168.0.6 |
19 |
20 |
UDP Header |
21 |
|-Source Port : 53 |
22 |
|-Destination Port : 33247 |
23 |
|-UDP Length : 237 |
24 |
|-UDP Checksum : 30099 |
25 |
26 |
IP Header |
27 |
00 1C C0 F8 79 EE 00 1E 58 B8 D4 69 08 00 45 00 ....y...X..i..E. |
28 |
01 01 33 E4 ..3. |
29 |
UDP Header |
30 |
00 00 3F 11 D7 37 D0 43 ..?..7.C |
31 |
Data Payload |
32 |
AF BD 81 80 00 01 00 01 00 04 00 04 02 31 36 03 ...?.........16. |
33 |
32 33 35 03 31 32 35 02 37 34 07 69 6E 2D 61 64 235.125.74.in-ad |
34 |
64 72 04 61 72 70 61 00 00 0C 00 01 C0 0C 00 0C dr.arpa......... |
35 |
00 01 00 01 4F E5 00 1B 0F 73 69 6E 30 31 73 30 ....O....sin01s0 |
36 |
34 2D 69 6E 2D 66 31 36 05 31 65 31 30 30 03 6E 4-in-f16.1e100.n |
37 |
65 74 00 C0 13 00 02 00 01 00 01 42 28 00 10 03 et.........B(... |
38 |
4E 53 31 06 47 4F 4F 47 4C 45 03 43 4F 4D 00 C0 NS1.GOOGLE.COM.. |
39 |
13 00 02 00 01 00 01 42 28 00 06 03 4E 53 33 C0 .......B(...NS3. |
40 |
63 C0 13 00 02 00 01 00 01 42 28 00 06 03 4E 53 c........B(...NS |
41 |
34 C0 63 C0 13 00 02 00 01 00 01 42 28 00 06 03 4.c........B(... |
42 |
4E 53 32 C0 63 C0 5F 00 01 00 01 00 02 7E 59 00 NS2.c._......~Y. |
43 |
04 D8 EF 20 0A C0 9F 00 01 00 01 00 02 7E 59 00 ... .........~Y. |
44 |
04 D8 EF 22 0A C0 7B 00 01 00 01 00 03 81 F3 00 ..."..{......... |
45 |
04 D8 EF 24 0A C0 8D 00 01 00 01 00 02 A1 AA 00 ...$............ |
46 |
04 D8 EF 26 0A ...&. |
47 |
48 |
########################################################### |
49 |
50 |
***********************TCP Packet************************* |
51 |
52 |
Ethernet Header |
53 |
|-Destination Address : 00-1E-58-B8-D4-69 |
54 |
|-Source Address : 00-1C-C0-F8-79-EE |
55 |
|-Protocol : 8 |
56 |
57 |
IP Header |
58 |
|-IP Version : 4 |
59 |
|-IP Header Length : 5 DWORDS or 20 Bytes |
60 |
|-Type Of Service : 0 |
61 |
|-IP Total Length : 57 Bytes(Size of Packet) |
62 |
|-Identification : 45723 |
63 |
|-TTL : 64 |
64 |
|-Protocol : 6 |
65 |
|-Checksum : 12762 |
66 |
|-Source IP : 192.168.0.6 |
67 |
|-Destination IP : 130.239.18.172 |
68 |
69 |
TCP Header |
70 |
|-Source Port : 57319 |
71 |
|-Destination Port : 6667 |
72 |
|-Sequence Number : 2867385066 |
73 |
|-Acknowledge Number : 443542543 |
74 |
|-Header Length : 5 DWORDS or 20 BYTES |
75 |
|-Urgent Flag : 0 |
76 |
|-Acknowledgement Flag : 1 |
77 |
|-Push Flag : 1 |
78 |
|-Reset Flag : 0 |
79 |
|-Synchronise Flag : 0 |
80 |
|-Finish Flag : 0 |
81 |
|-Window : 62780 |
82 |
|-Checksum : 22133 |
83 |
|-Urgent Pointer : 0 |
84 |
85 |
DATA Dump |
86 |
IP Header |
87 |
00 1E 58 B8 D4 69 00 1C C0 F8 79 EE 08 00 45 00 ..X..i....y...E. |
88 |
00 39 B2 9B .9.. |
89 |
TCP Header |
90 |
40 00 40 06 31 DA C0 A8 00 06 82 EF 12 AC DF E7 @.@.1........... |
91 |
1A 0B AA E8 .... |
92 |
Data Payload |
93 |
50 49 4E 47 20 31 33 32 33 32 37 30 35 36 36 0D PING 1323270566. |
94 |
0A . |
95 |
96 |
########################################################### |
The program requires superuser or root privileges to be able to sniff the packets.
Wireshark(previously ethereal) and tcpdump are examples of applications which use the libpcap library on linux to capture packet data.
==============================================================================