pcap_next 导致分段错误
pcap_next causes a segmentation fault
我正在编写一个简单的数据包捕获程序,它使用 pcap 函数捕获三个数据包。但它因分段错误而崩溃。下面是程序的源代码。
#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);
}
你能弄清楚这是怎么回事吗??
关于条件 if(pcap_handle < 0)
:此处的 API 文档,
https://www.tcpdump.org/manpages/pcap.3pcap.html,表示函数“pcap_open_live()
return成功时为pcap_t *
,失败时为NULL
。错误检查应该是if(pcap_handle == NULL)
案例.
在当前程序中,如果 pcap_open_live()
到 return NULL
指示失败,那么我预计第 packet = pcap_next(pcap_handle, header);
行会因 [=37 而崩溃=] 被设置为 NULL,或将 header
设置为 NULL
,或者通过将 pcap_handle
设置为 NULL
识别为错误而使其处于未初始化状态。
在下一行中,header
被取消引用,如果未初始化或 NULL
可能会导致分段错误。
总结一下,请参阅下面添加的评论:
#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); // << Crashes due to pcap_handle being NULL, 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);
}
我建议使用以下替换代码并进行一些额外检查以增加保护:
#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);
}
正如 Jonathan S. 所说,您对 pcap_open_live()
的测试是错误的。
你应该做
/*opens the packet capturing device*/
pcap_handle = pcap_open_live(device, 4096, 1, 0, errbuf);
if(pcap_handle == NULL){
fprintf(stderr, "ERROR: while opening pcap device %s: %s\n", device, errbuf);
exit(1);
}
因为:
pcap_open_live()
return 错误时的空指针 - 它不是 return 负数,因为它 return 不是数字;
- 错误指示不是 errno 值,所以
perror()
不会正确报告错误 - errbuf
包含一个描述错误的字符串,所以你想打印它以便你知道 为什么 失败了;
- 您还应该报告设备名称,因为这也可能有助于确定
pcap_open_live()
失败的原因。
另请注意,在大多数 UN*X 平台(Linux、*BSD、macOS 等)上,您可能需要 运行 您的程序具有提升的权限,例如 root 权限,为了打开一个网络接口进行捕获,所以如果你的程序在你修复它以使用上面的代码后报告权限错误,请尝试运行以root身份运行它。
我正在编写一个简单的数据包捕获程序,它使用 pcap 函数捕获三个数据包。但它因分段错误而崩溃。下面是程序的源代码。
#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);
}
你能弄清楚这是怎么回事吗??
关于条件 if(pcap_handle < 0)
:此处的 API 文档,
https://www.tcpdump.org/manpages/pcap.3pcap.html,表示函数“pcap_open_live()
return成功时为pcap_t *
,失败时为NULL
。错误检查应该是if(pcap_handle == NULL)
案例.
在当前程序中,如果 pcap_open_live()
到 return NULL
指示失败,那么我预计第 packet = pcap_next(pcap_handle, header);
行会因 [=37 而崩溃=] 被设置为 NULL,或将 header
设置为 NULL
,或者通过将 pcap_handle
设置为 NULL
识别为错误而使其处于未初始化状态。
在下一行中,header
被取消引用,如果未初始化或 NULL
可能会导致分段错误。
总结一下,请参阅下面添加的评论:
#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); // << Crashes due to pcap_handle being NULL, 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);
}
我建议使用以下替换代码并进行一些额外检查以增加保护:
#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);
}
正如 Jonathan S. 所说,您对 pcap_open_live()
的测试是错误的。
你应该做
/*opens the packet capturing device*/
pcap_handle = pcap_open_live(device, 4096, 1, 0, errbuf);
if(pcap_handle == NULL){
fprintf(stderr, "ERROR: while opening pcap device %s: %s\n", device, errbuf);
exit(1);
}
因为:
pcap_open_live()
return 错误时的空指针 - 它不是 return 负数,因为它 return 不是数字;- 错误指示不是 errno 值,所以
perror()
不会正确报告错误 -errbuf
包含一个描述错误的字符串,所以你想打印它以便你知道 为什么 失败了; - 您还应该报告设备名称,因为这也可能有助于确定
pcap_open_live()
失败的原因。
另请注意,在大多数 UN*X 平台(Linux、*BSD、macOS 等)上,您可能需要 运行 您的程序具有提升的权限,例如 root 权限,为了打开一个网络接口进行捕获,所以如果你的程序在你修复它以使用上面的代码后报告权限错误,请尝试运行以root身份运行它。