Author: deri
Date: 2010-09-09 11:13:15 +0200 (Thu, 09 Sep 2010)
New Revision: 4358

Modified:
   trunk/PF_RING/kernel/pf_ring.c
Log:
Fix for the bug below courtesy of Dan Kruchinin <[email protected]> 

1) The bug:
libpcap with PF_RING enabled improperly determines type of net device.
It works well with pure ethernet devices but when I give it an
IP-tunnel device it reports that
tunnel has type "EN10MB (Ethernet)" instead of "RAW (Raw IP)".

2) How to reproduce:
I attached a small and simple C application that creates a TUN(using
/dev/net/tun) tunnel device (tun.tar.gz). It takes the only one
argument - the name of tunnel.
% ./tun vtun0 &
Creating tun device...
 tun device vtun0 was successfully created.
Entering main loop. Press Ctrl-D to exit...
% ifconfig vtun0 10.10.0.1 up

So the TUN tunnel should have RAW linktype. Let's ask what type vtun0
actually has:
% tcpdump -i vtun0 -L
Data link types for vtun0 (use option -y to set):
 EN10MB (Ethernet)

An the same command on another machine where libpcap has not PF_RING support:
% tcpdump -i vtun0 -L
Data link types for vtun0 (use option -y to set):
 RAW (Raw IP)

As you can see, tcpdump determines invalid link type of the IP tunnel.
tcpdump uses libpcap which contains an error.

3) The error:
Take a look at userland/libpcap-1.0.0-ring/pcap-linux.c, function
pcap_activate_linux()
There is a chunk of code:
#ifdef HAVE_PF_RING
       if(!getenv("PCAP_NO_PF_RING"))
     handle->ring = pfring_open((char*)device, handle->opt.promisc,
handle->snapshot, 1);
   else
         handle->ring = NULL;

   if(handle->ring != NULL) {
     handle->fd = handle->ring->fd;
     handle->bufsize = handle->snapshot;
     handle->linktype = DLT_EN10MB;
     handle->offset = 2;

     /* printf("Open HAVE_PF_RING(%s)\n", device); */
   } else {
     /* printf("Open HAVE_PF_RING(%s) failed. Fallback to pcap\n",
device); */
#endif
   ...
   here activate_new() function called that asks kernel about
linktype of given device.
   ...
#ifdef HAVE_PF_RING
       }
#endif

As you can see from the code above, libpcap sets linktype to
DLT_EN10MB(ethernet) if pfring_open was called without error. If we
look at
pfring_open and related kernel code at kernel/pf_ring.c we'll find out
that pfring_open fails only if no memory is available for allocation
or if
it receives bad device name. Thus libpcap will set DLT_EN10MB for any
device: for IP tunnel and for ppp device. It's not good because
tcpdump produces invalid output(i.e. calls invalid printer function).
For example if IP tunnel is determined as DLT_EN10MB it dumps
something
like this:
% tcpdump -i vtun0 -pns 0 -XX
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vtun0, link-type EN10MB (Ethernet), capture size 65535 bytes
15:10:21.571132 40:00:40:01:73:54 > 45:00:00:54:00:00, ethertype
Unknown (0xc0a8), length 84:
       0x0000:  4500 0054 0000 4000 4001 7354 c0a8 2802  e.....@[email protected]..(.
       0x0010:  c0a8 1e02 0800 38ec b80f 0000 09cc fd37  ......8........7
       0x0020:  0000 0000 0000 0000 0000 0000 0000 0000  ................
       0x0030:  0000 0000 0000 0000 0000 0000 0000 0000  ................
       0x0040:  0000 0000 0000 0000 0000 0000 0000 0000  ................
       0x0050:  0000 0000                                ....


4) Solution:
The easiest solution I found is to check linktype of device userspace
application is going to bind via PF_RING sockets. If it's type isn't
ARPHRD_ETHER then an error is returned. (I attached the patch:
pf_ring.patch)
It's a quick and dirty solution and I don't think it's the best one.

-- W.B.R. Dan Kruchinin



Index: kernel/pf_ring.c
===================================================================
--- kernel/pf_ring.c    (revision 4357)
+++ kernel/pf_ring.c    (working copy)
@@ -77,6 +77,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/proc_fs.h>
+#include <linux/if_arp.h>
 #include <net/xfrm.h>
 #include <net/sock.h>
 #include <asm/io.h>            /* needed for virt_to_phys() */
@@ -3168,7 +3169,7 @@
 {
   struct ring_opt *pfr = ring_sk(sk);
 
-  if(!dev)
+  if(!dev || (dev->type != ARPHRD_ETHER))
     return(-1);
 
 #if defined(RING_DEBUG



_______________________________________________
Ntop-dev mailing list
[email protected]
http://listgateway.unipi.it/mailman/listinfo/ntop-dev

Reply via email to