msantos / epcap

Erlang packet capture interface using pcap
http://listincomprehension.com/2009/12/erlang-packet-sniffer-using-ei-and.html
BSD 3-Clause "New" or "Revised" License
178 stars 56 forks source link

Immediate_mode and pcap 1.9.1: packets buffered #32

Closed rvd-fr closed 3 years ago

rvd-fr commented 3 years ago

Hi,

First of all, thx for this useful tool.

I'm using epcap over centos 8-stream and libpcp 1.9.1. It looks like the {timeout, immediate} or epcap -t 0 doesn't work as expected. the packet seems to be buffered. if -t option is omitted, it seems to work in immediate mode.

can you please confirm if you can observe the same issue

br rvd

msantos commented 3 years ago

@rvd-fr thanks for the bug report!

I did a quick test on Ubuntu 20.04 with libpcap 1.9.1-3. I didn't see any buffering but that just means I may not bet testing properly.

From what I can see from the code, the effects of setting {timeout, 0} is identical to omitting the timeout option:

optarg({timeout, immediate}) -> switch("t", "0");
optarg({timeout, infinity}) -> switch("t", "-1");
optarg({timeout, Arg}) -> switch("t", maybe_string(Arg));

In the port, immediate mode is the default and the option bit is removed if the timeout > 0:

ep->opt |= EPCAP_OPT_IMMEDIATE;
...
    case 't':
      ep->timeout = strtonum(optarg, INT32_MIN, INT32_MAX, &errstr);
      if (errstr) {
        VERBOSE(0, "%s, invalid timeout (-t) value: %s\n", __progname, errstr);
        exit(errno);
      }
      if (ep->timeout < 0)
        ep->timeout = INT32_MAX;
      if (ep->timeout == 0)
        ep->opt |= EPCAP_OPT_IMMEDIATE;
      else
        ep->opt &= ~EPCAP_OPT_IMMEDIATE;
      break;

To confirm, I changed the code to print out the options before and after the -t switch:

1> epcap:start([{interface, "eth0"}, {timeout, 0}, {filter, "tcp and port 80"}]).
in:opt=16out:opt=16{ok,<0.153.0>}

1> epcap:start([{interface, "eth0"}, {filter, "tcp and port 80"}]).
in:opt=16out:opt=16{ok,<0.153.0>}

So possibly the buffering is occuring for another reason. Do you have some sample code to reproduce the issue?

rvd-fr commented 3 years ago

HI Michael

Thx for the quick answer.

in fact, to debgu i check directly at Linux level with the epcap binary (usign sudo).

my interface is on vswitch: goal is to intercept packet on the lan.

i have a ping permanently sending packet (every sec). I let it run.

here what i'm observing on the capture interface:

$sudo ./epcap -i ens256 -t 0 -P -Q inout ▒hwepcapwreadyPuTTYPuTTY^C[

==> no packet are visible until aroung 70 sec. then after a batch of info are sent.

$ sudo ./epcap -i ens256  -P -Q inout ▒hwepcapwreadyPuTTYPuTTY▒▒hwpacketahb\b ▒b▒NazmzPV▒p▒PV▒qEl?/▒N▒1▒ET~▒@?▒▒"▒"▒zd$jYaj1234567▒▒hwpacketahb\b ▒b▒azmzPV▒q▒PV▒pEl?/▒N▒3▒ET▒▒?H▒▒"▒zd$jYaj1234567PuTTYPuTTY▒▒hwpacketahb\b ▒"▒▒zzd%kYan1234567▒▒hwpacketahb\b ▒b▒ azmzPV▒q▒PV▒pEl?/▒N▒3▒ET▒w?D5▒*▒"▒zzd%kYan1234567PuTTYPuTTY▒▒hwpacketahb\b ▒hazmzPV▒p▒PV▒qEl?/▒N▒1▒ET▒e@?

packets are visible immediatly

The upper layer is after doing its job when packet are sent. The issue seems to be at the C module level

with a -t 1 it is working fine.

It is possible that I use badly the cli but I don't see exactly where.

Here the info on the libpcap:

updatedb

locate libpcap

/usr/lib64/libpcap.so /usr/lib64/libpcap.so.1 /usr/lib64/libpcap.so.1.9.1 /usr/lib64/pkgconfig/libpcap.pc /usr/share/doc/libpcap /usr/share/doc/libpcap/CHANGES /usr/share/doc/libpcap/CREDITS /usr/share/doc/libpcap/README.md /usr/share/licenses/libpcap /usr/share/licenses/libpcap/LICENSE

Let me know if i can help by providing any info.

thx a lot for support

René

rvd-fr commented 3 years ago

Hi

i don't  see the issue with a Debian and libpcap 1.8.1.6

PRETTY_NAME="Debian GNU/Linux 10 (buster)" NAME="Debian GNU/Linux" VERSION_ID="10" VERSION="10 (buster)" VERSION_CODENAME=buster ID=debian HOME_URL="https://www.debian.org/" SUPPORT_URL="https://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/"

Package: libpcap-dev Version: 1.8.1-6 Priority: optional Section: libdevel Source: libpcap Maintainer: Romain Francoise @.***> Installed-Size: 34,8 kB Depends: libpcap0.8-dev Homepage: http://www.tcpdump.org/ Tag: devel::library, implemented-in::c, role::devel-lib Download-Size: 25,9 kB APT-Manual-Installed: yes APT-Sources: http://deb.debian.org/debian buster/main amd64 Packages Description: development library for libpcap (transitional package)  Empty package to facilitate upgrades, can be safely removed.

this is working fine for example

/usr/bin/sudo /xxx/priv/epcap -Q inout -d /xxx/priv/tmp -i lo -t 0 -P

br

rené

rvd-fr commented 3 years ago

Found that on the subject if it can helps: https://github.com/royhills/arp-scan/issues/42

msantos commented 3 years ago

@rvd-fr thanks for the analysis!

Does this patch fix it?

diff --git a/c_src/epcap.c b/c_src/epcap.c
index 827456c..4a52444 100644
--- a/c_src/epcap.c
+++ b/c_src/epcap.c
@@ -425,7 +425,8 @@ static int epcap_open(EPCAP_STATE *ep) {
     (void)pcap_set_snaplen(ep->p, ep->snaplen);
     (void)pcap_set_promisc(ep->p, ep->opt & EPCAP_OPT_PROMISC);
     (void)pcap_set_immediate_mode(ep->p, ep->opt & EPCAP_OPT_IMMEDIATE);
-    (void)pcap_set_timeout(ep->p, ep->timeout);
+    if (ep->timeout > 0)
+      (void)pcap_set_timeout(ep->p, ep->timeout);

     if (ep->bufsz > 0)
       (void)pcap_set_buffer_size(ep->p, ep->bufsz);
rvd-fr commented 3 years ago

Hi Michael,

Thank you for the patch&support.

Unfortunately: no change with patch

br

msantos commented 3 years ago

I didn't read pcap_set_timeout(3PCAP) carefully enough:

   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 recommend always setting the timeout to  a  non-zero
   value unless immediate mode is set, in which case the timeout has no effect.

Could you try this patch? Thanks for your patience. I tried reproducing with libpcap git, so far with no luck.

index 827456c..974ebd0 100644
--- a/c_src/epcap.c
+++ b/c_src/epcap.c
@@ -177,8 +177,10 @@ int main(int argc, char *argv[]) {
       }
       if (ep->timeout < 0)
         ep->timeout = INT32_MAX;
-      if (ep->timeout == 0)
+      if (ep->timeout == 0) {
         ep->opt |= EPCAP_OPT_IMMEDIATE;
+        ep->timeout = TIMEOUT;
+      }
       else
         ep->opt &= ~EPCAP_OPT_IMMEDIATE;
       break;
rvd-fr commented 3 years ago

Looks good now ! :) (with the 2 fixes)

tested only on centos 8 / pcap 1.9.1 but behavior is now correct:

i will make a check on debian too just in case

thx a lot

rvd-fr commented 3 years ago

still good on PRETTY_NAME="Debian GNU/Linux 10 (buster)" NAME="Debian GNU/Linux" VERSION_ID="10" VERSION="10 (buster)"

and pcap Version: 1.8.1-6