LibPCap pcap_loop() 不 return 任何数据包
LibPCap pcap_loop() does not return any packets
我的 C 程序有问题,在我开始捕获数据包之前一切正常。它应该记录,但 pcap_loop() 中的处理程序 void 不是。此外,当第 98 行的 fgets 中的输入被传递到 pcap create void 时,我还有另一个问题,它将无法通过名称找到接口。当我对字符串进行硬编码时它起作用了。
/*
Compile and run it using GCC ->
gcc main.c -o output -L/usr/include -lpcap && ./output
*/
#include <stdio.h>
#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define __NEWLINE__ "\r\r\n"
#define __SEPARATOR__ "------------------------"
/*
Print all flags in human readable string
instead of hexadecimal number
*/
char* get_interface_flags(bpf_u_int32* decimal_flags) {
char* flag_string = (char*)malloc(sizeof(char) * 30);
strcpy(flag_string, "[=12=]");
const int flag_names[9] = {
PCAP_IF_LOOPBACK,
PCAP_IF_UP,
PCAP_IF_RUNNING,
PCAP_IF_WIRELESS
};
const char* flag_values[9] = {
"LOOPBACK",
"UP",
"RUNNING",
"WIRELESS"
};
for (size_t i = 0; i < (sizeof(flag_names) / sizeof(flag_names[0])); i++)
{
if(flag_names[i] & *decimal_flags) {
if(strlen(flag_string) != 0) strcat(flag_string, ", ");
strcat(flag_string, flag_values[i]);
}
}
return flag_string;
}
/*
Print available information about network interface
This recursive function can be called again
if there is more than one interface present
*/
void print_interface(pcap_if_t* device) {
// Device parameters
bpf_u_int32* flags = &device->flags;
char* device_name = device->name;
char* device_desc = device->description;
char* flags_string = get_interface_flags(flags);
// Device addresses
pcap_addr_t* addr = device->addresses;
// We'll print devices with only 1 flag or more to avoid interfaces that aren't up
if(strlen(flags_string) != 0) {
fprintf(stdout, "%s: FLAGS(%lu)<%s>%s", device_name, strlen(flags_string), flags_string, __NEWLINE__);
fprintf(stdout, "%s%s", device_desc, __NEWLINE__);
fprintf(stdout, "%s%s", __SEPARATOR__, __NEWLINE__);
}
// Check if there is another device to print, if so call the recursive function again
if(device[0].next != NULL) print_interface(device->next);
free(flags_string);
}
// Let user select the network interface that will capture packets
char* get_selected_interface() {
char* selected_interface = (char*)malloc(sizeof(char) * 20);
char* device_name;
char* ip_addr;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t* alldevs;
// Get all available network interfaces, returns PCAP_ERROR on failure or 0 on success
int devices_succefully_returned = pcap_findalldevs(&alldevs, errbuf);
// If there was an error while fetching interfaces, return empty char
if(devices_succefully_returned == PCAP_ERROR) {
printf("%s", errbuf);
return '[=12=]';
}
print_interface(alldevs);
fprintf(stdout, "Name of the network interface to use: ");
fgets(selected_interface, 20, stdin);
return selected_interface;
}
void captured_packet(u_char *args, const struct pcap_pkthdr *hdr, const u_char *pkt) {
fprintf(stdout, "log");
}
void capture(char* device) {
char* errbuf[PCAP_ERRBUF_SIZE];
/*
Will create a packet capture handle
Returns NULL if handle can't be created, in this case
we'll print out the error buffer and exit the program with 1 status code
*/
pcap_t* created = pcap_create("eth0", *errbuf);
if(created == NULL) {
fprintf(stderr, "%s%s", *errbuf, __NEWLINE__);
return exit(EXIT_FAILURE);
};
int activation_status = pcap_activate(created);
if(activation_status == PCAP_ERROR || activation_status != 0) {
fprintf(stderr, "%s", pcap_geterr(created));
exit(EXIT_FAILURE);
}
/*
Interface was activated so start capturing incoming packets
capture_packet will handle incoming packets.
We'll capture infinite amount of packets unless user provides a count
*/
fprintf(stdout, "Interface activated!%s", __NEWLINE__);
int loop_status = pcap_loop(created, -1, captured_packet, NULL);
switch (loop_status)
{
case PCAP_ERROR_BREAK:
fprintf(stderr, "Loop was finished beacause of breakloop that was called.");
break;
case PCAP_ERROR_NOT_ACTIVATED:
fprintf(stderr, "Device wasn't activated before it started capturing.");
break;
case 0:
fprintf(stderr, "Loop was terminated due to exhaustion of count");
break;
default:
fprintf(stderr, "Some error happened while trying to loop through packets -> %s", pcap_geterr(created));
break;
}
// Program was successfully closed, exit..
pcap_close(created);
exit(0);
}
int main(int argc, char **argv) {
if(getuid() != 0) {
fprintf(stderr, "Please make sure to run this tool as root!%s", __NEWLINE__);
return 1;
}
char* selected = get_selected_interface();
capture(selected);
free(selected);
return 0;
}
我尝试了所有方法,它应该在“eth0”接口上记录无限数量的数据包,但没有任何反应。
I have problem with my C program, everything is fine until I start capturing packets. It should log, but the handler void in pcap_loop() isn't.
引用 pcap(3PCAP) 手册页:
packet buffer timeout
If, when capturing, packets are delivered as soon as they
arrive, the application capturing the packets will be woken up
for each packet as it arrives, and might have to make one or
more calls to the operating system to fetch each packet.
If, instead, packets are not delivered as soon as they arrive,
but are delivered after a short delay (called a "packet buffer
timeout"), more than one packet can be accumulated before the
packets are delivered, so that a single wakeup would be done for
multiple packets, and each set of calls made to the operating
system would supply multiple packets, rather than a single
packet. This reduces the per-packet CPU overhead if packets are
arriving at a high rate, increasing the number of packets per
second that can be captured.
The packet buffer timeout is required so that an application
won't wait for the operating system's capture buffer to fill up
before packets are delivered; if packets are arriving slowly,
that wait could take an arbitrarily long period of time.
Not all platforms support a packet buffer timeout; on platforms
that don't, the packet buffer timeout is ignored. A zero value
for the timeout, on platforms that support a packet buffer time-
out, will cause a read to wait forever to allow enough packets
to arrive, with no timeout. A negative value is invalid; the
result of setting the timeout to a negative value is unpre-
dictable.
NOTE: the packet buffer timeout cannot be used to cause calls
that read packets to return within a limited period of time,
because, on some platforms, the packet buffer timeout isn't sup-
ported, and, on other platforms, the timer doesn't start until
at least one packet arrives. This means that the packet buffer
timeout should NOT be used, for example, in an interactive
application to allow the packet capture loop to ``poll'' for
user input periodically, as there's no guarantee that a call
reading packets will return after the timeout expires even if no
packets have arrived.
The packet buffer timeout is set with pcap_set_timeout().
和 pcap_set_timeout(3PCAP) 手册页:
pcap_set_timeout() sets the packet buffer timeout that will be used on
a capture handle when the handle is activated to to_ms, which is in
units of milliseconds. (See pcap(3PCAP) for an explanation of the
packet buffer timeout.)
The behavior, if the timeout isn't specified, is undefined, as is the
behavior if the timeout is set to zero or to a negative value. We rec-
ommend always setting the timeout to a non-zero value unless immediate
mode is set, in which case the timeout has no effect.
你还没有打电话pcap_set_timeout()
;在某些平台上,这可能会导致 pcap_loop()
等待直到它获得一个充满数据包的整个缓冲区,这可能会花费大量时间。
将超时设置为 100,即 100 毫秒或十分之一秒。
Also I have another problem with the input in fgets on line 98 when it gets passed into the pcap create void it will not find the interface by the name. When I hardcode the string it works.
引用 fgets(3) 手册页(这是在 macOS 上,您可能正在使用 Linux,给定“eth0”名称,但我引用的所有内容手册页适用于 macOS、Linux 和其他 UN*Xes):
The fgets() function reads at most one less than the number of characters
specified by size from the given stream and stores them in the string
str. Reading stops when a newline character is found, at end-of-file or
error. The newline, if any, is retained. If any characters are read and
there is no error, a `[=12=]' character is appended to end the string.
此处的重要部分是“保留换行符(如果有)”。 - 这意味着,如果用户键入“eth0”然后按下 Return 键,读入的字符串将是“eth0\n”,带有换行符[=30] =].接口的名称是“eth0”,而不是“eth0\n”;在使用它之前,您必须从字符串中删除任何尾随的换行符。
我的 C 程序有问题,在我开始捕获数据包之前一切正常。它应该记录,但 pcap_loop() 中的处理程序 void 不是。此外,当第 98 行的 fgets 中的输入被传递到 pcap create void 时,我还有另一个问题,它将无法通过名称找到接口。当我对字符串进行硬编码时它起作用了。
/*
Compile and run it using GCC ->
gcc main.c -o output -L/usr/include -lpcap && ./output
*/
#include <stdio.h>
#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define __NEWLINE__ "\r\r\n"
#define __SEPARATOR__ "------------------------"
/*
Print all flags in human readable string
instead of hexadecimal number
*/
char* get_interface_flags(bpf_u_int32* decimal_flags) {
char* flag_string = (char*)malloc(sizeof(char) * 30);
strcpy(flag_string, "[=12=]");
const int flag_names[9] = {
PCAP_IF_LOOPBACK,
PCAP_IF_UP,
PCAP_IF_RUNNING,
PCAP_IF_WIRELESS
};
const char* flag_values[9] = {
"LOOPBACK",
"UP",
"RUNNING",
"WIRELESS"
};
for (size_t i = 0; i < (sizeof(flag_names) / sizeof(flag_names[0])); i++)
{
if(flag_names[i] & *decimal_flags) {
if(strlen(flag_string) != 0) strcat(flag_string, ", ");
strcat(flag_string, flag_values[i]);
}
}
return flag_string;
}
/*
Print available information about network interface
This recursive function can be called again
if there is more than one interface present
*/
void print_interface(pcap_if_t* device) {
// Device parameters
bpf_u_int32* flags = &device->flags;
char* device_name = device->name;
char* device_desc = device->description;
char* flags_string = get_interface_flags(flags);
// Device addresses
pcap_addr_t* addr = device->addresses;
// We'll print devices with only 1 flag or more to avoid interfaces that aren't up
if(strlen(flags_string) != 0) {
fprintf(stdout, "%s: FLAGS(%lu)<%s>%s", device_name, strlen(flags_string), flags_string, __NEWLINE__);
fprintf(stdout, "%s%s", device_desc, __NEWLINE__);
fprintf(stdout, "%s%s", __SEPARATOR__, __NEWLINE__);
}
// Check if there is another device to print, if so call the recursive function again
if(device[0].next != NULL) print_interface(device->next);
free(flags_string);
}
// Let user select the network interface that will capture packets
char* get_selected_interface() {
char* selected_interface = (char*)malloc(sizeof(char) * 20);
char* device_name;
char* ip_addr;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t* alldevs;
// Get all available network interfaces, returns PCAP_ERROR on failure or 0 on success
int devices_succefully_returned = pcap_findalldevs(&alldevs, errbuf);
// If there was an error while fetching interfaces, return empty char
if(devices_succefully_returned == PCAP_ERROR) {
printf("%s", errbuf);
return '[=12=]';
}
print_interface(alldevs);
fprintf(stdout, "Name of the network interface to use: ");
fgets(selected_interface, 20, stdin);
return selected_interface;
}
void captured_packet(u_char *args, const struct pcap_pkthdr *hdr, const u_char *pkt) {
fprintf(stdout, "log");
}
void capture(char* device) {
char* errbuf[PCAP_ERRBUF_SIZE];
/*
Will create a packet capture handle
Returns NULL if handle can't be created, in this case
we'll print out the error buffer and exit the program with 1 status code
*/
pcap_t* created = pcap_create("eth0", *errbuf);
if(created == NULL) {
fprintf(stderr, "%s%s", *errbuf, __NEWLINE__);
return exit(EXIT_FAILURE);
};
int activation_status = pcap_activate(created);
if(activation_status == PCAP_ERROR || activation_status != 0) {
fprintf(stderr, "%s", pcap_geterr(created));
exit(EXIT_FAILURE);
}
/*
Interface was activated so start capturing incoming packets
capture_packet will handle incoming packets.
We'll capture infinite amount of packets unless user provides a count
*/
fprintf(stdout, "Interface activated!%s", __NEWLINE__);
int loop_status = pcap_loop(created, -1, captured_packet, NULL);
switch (loop_status)
{
case PCAP_ERROR_BREAK:
fprintf(stderr, "Loop was finished beacause of breakloop that was called.");
break;
case PCAP_ERROR_NOT_ACTIVATED:
fprintf(stderr, "Device wasn't activated before it started capturing.");
break;
case 0:
fprintf(stderr, "Loop was terminated due to exhaustion of count");
break;
default:
fprintf(stderr, "Some error happened while trying to loop through packets -> %s", pcap_geterr(created));
break;
}
// Program was successfully closed, exit..
pcap_close(created);
exit(0);
}
int main(int argc, char **argv) {
if(getuid() != 0) {
fprintf(stderr, "Please make sure to run this tool as root!%s", __NEWLINE__);
return 1;
}
char* selected = get_selected_interface();
capture(selected);
free(selected);
return 0;
}
我尝试了所有方法,它应该在“eth0”接口上记录无限数量的数据包,但没有任何反应。
I have problem with my C program, everything is fine until I start capturing packets. It should log, but the handler void in pcap_loop() isn't.
引用 pcap(3PCAP) 手册页:
packet buffer timeout
If, when capturing, packets are delivered as soon as they
arrive, the application capturing the packets will be woken up
for each packet as it arrives, and might have to make one or
more calls to the operating system to fetch each packet.
If, instead, packets are not delivered as soon as they arrive,
but are delivered after a short delay (called a "packet buffer
timeout"), more than one packet can be accumulated before the
packets are delivered, so that a single wakeup would be done for
multiple packets, and each set of calls made to the operating
system would supply multiple packets, rather than a single
packet. This reduces the per-packet CPU overhead if packets are
arriving at a high rate, increasing the number of packets per
second that can be captured.
The packet buffer timeout is required so that an application
won't wait for the operating system's capture buffer to fill up
before packets are delivered; if packets are arriving slowly,
that wait could take an arbitrarily long period of time.
Not all platforms support a packet buffer timeout; on platforms
that don't, the packet buffer timeout is ignored. A zero value
for the timeout, on platforms that support a packet buffer time-
out, will cause a read to wait forever to allow enough packets
to arrive, with no timeout. A negative value is invalid; the
result of setting the timeout to a negative value is unpre-
dictable.
NOTE: the packet buffer timeout cannot be used to cause calls
that read packets to return within a limited period of time,
because, on some platforms, the packet buffer timeout isn't sup-
ported, and, on other platforms, the timer doesn't start until
at least one packet arrives. This means that the packet buffer
timeout should NOT be used, for example, in an interactive
application to allow the packet capture loop to ``poll'' for
user input periodically, as there's no guarantee that a call
reading packets will return after the timeout expires even if no
packets have arrived.
The packet buffer timeout is set with pcap_set_timeout().
和 pcap_set_timeout(3PCAP) 手册页:
pcap_set_timeout() sets the packet buffer timeout that will be used on
a capture handle when the handle is activated to to_ms, which is in
units of milliseconds. (See pcap(3PCAP) for an explanation of the
packet buffer timeout.)
The behavior, if the timeout isn't specified, is undefined, as is the
behavior if the timeout is set to zero or to a negative value. We rec-
ommend always setting the timeout to a non-zero value unless immediate
mode is set, in which case the timeout has no effect.
你还没有打电话pcap_set_timeout()
;在某些平台上,这可能会导致 pcap_loop()
等待直到它获得一个充满数据包的整个缓冲区,这可能会花费大量时间。
将超时设置为 100,即 100 毫秒或十分之一秒。
Also I have another problem with the input in fgets on line 98 when it gets passed into the pcap create void it will not find the interface by the name. When I hardcode the string it works.
引用 fgets(3) 手册页(这是在 macOS 上,您可能正在使用 Linux,给定“eth0”名称,但我引用的所有内容手册页适用于 macOS、Linux 和其他 UN*Xes):
The fgets() function reads at most one less than the number of characters
specified by size from the given stream and stores them in the string
str. Reading stops when a newline character is found, at end-of-file or
error. The newline, if any, is retained. If any characters are read and
there is no error, a `[=12=]' character is appended to end the string.
此处的重要部分是“保留换行符(如果有)”。 - 这意味着,如果用户键入“eth0”然后按下 Return 键,读入的字符串将是“eth0\n”,带有换行符[=30] =].接口的名称是“eth0”,而不是“eth0\n”;在使用它之前,您必须从字符串中删除任何尾随的换行符。