I'm writing a simple packet capture program which captures three packets using pcap functions. But it crashes with a segmentation fault. Below is the source code for the program.
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
#include "dump.h"
void pcap_fatal(const char *failed_in, const char *errbuf){
printf("Fata Error in %s: %s\n", failed_in, errbuf);
exit(1);
}
int main(){
struct pcap_pkthdr *header;
const u_char *packet;
char errbuf[PCAP_ERRBUF_SIZE];
char *device;
pcap_t *pcap_handle;
int i;
/*look for a device to capture packets*/
device = pcap_lookupdev(errbuf);
if(device == NULL)
pcap_fatal("pcap_lookupdev", errbuf);
printf("Sniffing on device %s\n", device);
/*opens the packet capturing device*/
pcap_handle = pcap_open_live(device, 4096, 1, 0, errbuf);
if(pcap_handle < 0){
perror("ERROR: while opening pcap device");
exit(1);
}
for(i=0;i<3;i ){
printf("\n===packet %d===\n", i 1);
packet = pcap_next(pcap_handle, header);
printf("Got a %d bute packet\n", header->len);
dump(packet, header->len);
}
pcap_close(pcap_handle);
}
Can you figure out what is going on ??
CodePudding user response:
Regarding condition if(pcap_handle < 0)
: the API documentation here,
https://www.tcpdump.org/manpages/pcap.3pcap.html, indicates that function "pcap_open_live()
returns a pcap_t *
on success and NULL
on failure. The error check should probably be if(pcap_handle == NULL)
in this case.
In the current program, if pcap_open_live()
were to return NULL
indicating a failure, then I would expect line packet = pcap_next(pcap_handle, header);
to set header
to NULL or else leave it in its uninitialized state.
On the following line, header
is dereferenced, and if uninitialized or NULL
would likely result in a segmentation fault.
So to summarize see the comments added below:
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
#include "dump.h"
void pcap_fatal(const char *failed_in, const char *errbuf){
printf("Fata Error in %s: %s\n", failed_in, errbuf);
exit(1);
}
int main(){
struct pcap_pkthdr *header;
const u_char *packet;
char errbuf[PCAP_ERRBUF_SIZE];
char *device;
pcap_t *pcap_handle;
int i;
/*look for a device to capture packets*/
device = pcap_lookupdev(errbuf);
if(device == NULL)
pcap_fatal("pcap_lookupdev", errbuf);
printf("Sniffing on device %s\n", device);
/*opens the packet capturing device*/
pcap_handle = pcap_open_live(device, 4096, 1, 0, errbuf); // << Fails and returns NULL.
if(pcap_handle < 0){ // << Passes since value is NULL (typically zero).
perror("ERROR: while opening pcap device");
exit(1);
}
for(i=0;i<3;i ){
printf("\n===packet %d===\n", i 1);
packet = pcap_next(pcap_handle, header); // << Sets header to NULL or leaves uninitialized.
printf("Got a %d bute packet\n", header->len); // << Dereferences pointer to nothing causing segmentation fault.
dump(packet, header->len);
}
pcap_close(pcap_handle);
}
I would recommend the following replacement code with a few extra checks for added protection:
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
#include "dump.h"
void pcap_fatal(const char *failed_in, const char *errbuf){
printf("Fata Error in %s: %s\n", failed_in, errbuf);
exit(1);
}
int main(){
struct pcap_pkthdr *header;
const u_char *packet;
char errbuf[PCAP_ERRBUF_SIZE];
char *device;
pcap_t *pcap_handle;
int i;
/*look for a device to capture packets*/
device = pcap_lookupdev(errbuf);
if(device == NULL)
pcap_fatal("pcap_lookupdev", errbuf);
printf("Sniffing on device %s\n", device);
/*opens the packet capturing device*/
pcap_handle = pcap_open_live(device, 4096, 1, 0, errbuf);
if(pcap_handle == NULL){
perror("ERROR: while opening pcap device");
exit(1);
}
for(i=0;i<3;i ){
printf("\n===packet %d===\n", i 1);
packet = pcap_next(pcap_handle, header);
if((packet != NULL) && (header != NULL)){
printf("Got a %d bute packet\n", header->len);
dump(packet, header->len);
}
}
pcap_close(pcap_handle);
}