Libpcap - Capture Packets from All Interfaces

C - pcap does not work when sniffing packets from all interfaces (with any)

If you filter for specific bytes filter string should be "ether[12:2]==0x88cc".
However as you want to filter for specific ether type i would use "ether proto 0x88cc".
This also works for capturing device "any".

Let me say that i also was surprised that your first filter string didn't work for device "any" and because of that i captured frames with wireshark on specific device as well as on device "any".
The frames captured on device "any" use a different destination MAC address and there are two zero bytes inserted before ether type. That's why your filter string won't match.
Up to now i didn't find an answer within documentation for this specific frame format for device "any" captures.

Maybe anybody else could shed some light on that.

Frame specific device: fc f8 ae 59 32 3d f0 c8 50 5b cc 3f 08 00 45 00

Frame device "any": 00 00 00 01 00 06 f0 c8 50 5b cc 3f 00 00 08 00 45

LibPCap pcap_loop() does not return any packets

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.

To quote the pcap(3PCAP) man page:

   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().

and the pcap_set_timeout(3PCAP) man page:

   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.

You haven't called pcap_set_timeout(); on some platforms, that can cause pcap_loop() to wait until it gets an entire buffer full of packet, which could take a significant amount of time.

Set the timeout to 100, which means 100 milliseconds or a tenth of a second.

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.

To quote the fgets(3) man page (this is on macOS, and you're probably working on Linux, given the "eth0" name, but all of the stuff I'm quoting from the man pages applies to macOS, Linux, and other 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 `\0' character is appended to end the string.

The important part here is "The newline, if any, is retained." - this means that, if the user types "eth0" and then hits the Return key, the string read in will be "eth0\n", complete with a newline character. The name of the interface is "eth0", not "eth0\n"; you will have to remove any trailing newline from the string before using it.

Querying Interfaces to find device with libpcap

In non-blocking mode, pcap_next_ex() will return 0 if there are no packets available to read, and will NOT return any packet information, so, if it returned 0, you should not look at anything that header or packet_data points to.

I.e., do

while ((res = pcap_next_ex(fp, &header, &pkt_data)) >=0) {
if (res != 0) {
struct iphdr *iph = (struct iphdr *)(pkt_data + sizeof(struct ethhdr));
struct udphdr *udph = (struct udphdr*)(pkt_data + (iph->ihl*4) + sizeof(struct ethhdr));
u_int destPort = ntohs(udph->dest);

if (destPort==TYPE1_DATA_PORT || destPort==TYPE1_GPS_PORT) {
detectedScanners->type1 = true;
} else if (destPort==TYPE2_DATA_PORT || destPort==TYPE2_STATUS_PORT || destPort==TYPE2_NMEA_PORT) {
detectedScanners->type2 = true;
}

if (++packetCounter > FIND_DEVICE_PACKET_LIMIT) {
break;
}
}
}

Note, however, that your program will continuously spin, consuming CPU, in that loop, forever. This means that you'll never look past the first device.

What you probably really want to do is:

  • open all the devices, putting their pcap_t *s into an array, and put them into non-blocking mode;
  • for each of the devices, call pcap_get_selectable_fd() on UN*X and pcap_getevent() on Windows, and save the result of that call into an array (you can have parallel arrays, or an array of structures with the pcap_t * and the int or HANDLE as members);
  • in the loop, use select() or poll() on all of the ints from pcap_get_selectable_fd() on UN*X or WaitForMultipleObjects() on all of the HANDLEs from pcap_getevent() on Windows and, when select()/poll()/WaitForMultipleObjects() returns, try reading a packet from each of the pcap_t *s using pcap_next_ex(), and process it if you get a packet.

That way, you scan on all devices in parallel, and don't spin the CPU.

Issue sniffing PCAP

When I sniff ethernet the bytes that I receive are shifted by 2 bytes

You're not sniffing Ethernet, you're sniffing the "any" device. That will capture on all interfaces, whether they're Ethernet interfaces or not; even if they are all Ethernet interfaces, that doesn't make a difference.

In order to make this work, a link-layer header type other than Ethernet is used on the "any" device. On Linux, that's a special header; here's what that header looks like.

ALL programs that use libpcap to capture network traffic or to read a capture file must, after opening the capture device (pcap_activate(), pcap_open_live(), pcap_open()) or the capture file (pcap_open_offline()), call pcap_datalink() to determine the link-layer header type from the device or the file.

That function returns a value that can be found in the link-layer header types list; it will be one of the values with a name that begins with DLT_. Do not check for the numerical values given there; check for the DLT_ values.



Related Topics



Leave a reply



Submit