Package: libpcap0.8
Version: 1.8.1-6
Severity: important
Tags: patch

Dear maintainer,


since Linux kernel 3.4, the outer vlan tag is no longer transparently
passed to userspace. Instead, libpcap and others needs to access ancillary
data in BPF [1], [2]. libpcap does this starting with 1.8, although
incorrectly.

The kernel returns the full TCI (16-bit), which includes the IEEE 802.1p
"COS" value. However libcap expects the 12-bit VLANID verbatim, meaning
that when the incoming frame has a non-null priority field, vlan matching
fails.

This has finally been fixed upstream in libpcap-1.9 branch (after the 1.9.0
release) and master, see [3] and [4].


This can be reproduced by generating such a frame via scapy on loopback:

$ sudo scapy
>>> sendp(Ether(src="00:11:22:33:44:55",dst="00:00:aa:bb:cc:dd")/\
Dot1Q(vlan=100,prio=2)/IP(src="1.2.3.4",dst="2.1.3.4")/\
UDP(sport=9999,dport=9999),iface="lo",count=1)


and tcpdumping it with a filter for vlan 100:

$ sudo tcpdump -nxxevi lo vlan 100
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel
$

Filter fails because of the nun-null dot1P field.


In fact the generated BPF code doesn't mask the 16-bit TCI with 0xfff:

$ sudo tcpdump -nxxevi lo vlan 100 -d
(000) ldb      [-4048]
(001) jeq      #0x1             jt 2    jf 5
(002) ldb      [-4052]
(003) jeq      #0x64            jt 4    jf 5
(004) ret      #262144
(005) ret      #0
$


As we apply the patch for this issue - which diverges from upstream fixes
because the 1.8 tree is different - a 0xfff mask is applied to the TCI field:

$ sudo tcpdump -nxxevi lo vlan 100 -d
(000) ldb      [-4048]
(001) jeq      #0x1             jt 2    jf 6
(002) ldb      [-4052]
(003) and      #0xfff
(004) jeq      #0x64            jt 5    jf 6
(005) ret      #262144
(006) ret      #0
$


and the capture works flawlessly:

$ sudo tcpdump -nxxevi lo vlan 100
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
19:16:12.020500 00:11:22:33:44:55 > 00:00:aa:bb:cc:dd, ethertype 802.1Q 
(0x8100), length 46: vlan 100, p 2, ethertype IPv4, (tos 0x0, ttl 64, id 1, 
offset 0, flags [none], proto UDP (17), length 28)
    1.2.3.4.9999 > 2.1.3.4.9999: UDP, length 0
        0x0000:  0000 aabb ccdd 0011 2233 4455 8100 4064
        0x0010:  0800 4500 001c 0001 0000 4011 71c6 0102
        0x0020:  0304 0201 0304 270f 270f 0008 a8b5
^C
1 packet captured
1 packet received by filter
0 packets dropped by kernel
$


Please consider applying this patch to the libpcap0.8 package in Debian Stretch.



Thanks,

-lukas



[1] https://www.spinics.net/lists/netdev/msg244673.html
[2] 
https://github.com/torvalds/linux/blob/6f0d349d922ba44e4348a17a78ea51b7135965b1/include/uapi/linux/filter.h#L60
[3] https://github.com/the-tcpdump-group/libpcap/issues/461
[4] 
https://github.com/the-tcpdump-group/libpcap/commit/b525a0863466ba863630c0450926044230b447e8




-- System Information:
Debian Release: 9.5
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 4.9.0-7-amd64 (SMP w/1 CPU core)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages libpcap0.8 depends on:
ii  libc6  2.24-11+deb9u3

libpcap0.8 recommends no packages.

libpcap0.8 suggests no packages.

-- no debconf information
diff --git a/gencode.c b/gencode.c
index a887f27..ba095a5 100644
--- a/gencode.c
+++ b/gencode.c
@@ -7952,7 +7952,7 @@ static struct block *
 gen_vlan_bpf_extensions(compiler_state_t *cstate, int vlan_num)
 {
         struct block *b0, *b1;
-        struct slist *s;
+        struct slist *s, *s2;

         /* generate new filter code based on extracting packet
          * metadata */
@@ -7967,6 +7967,11 @@ gen_vlan_bpf_extensions(compiler_state_t *cstate, int 
vlan_num)
                 s = new_stmt(cstate, BPF_LD|BPF_B|BPF_ABS);
                 s->s.k = SKF_AD_OFF + SKF_AD_VLAN_TAG;

+                /* mask TCI field with 0xfff to extract VLANID */
+                s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
+                s2->s.k = 0xfff;
+                sappend(s, s2);
+
                 b1 = new_block(cstate, JMP(BPF_JEQ));
                 b1->stmts = s;
                 b1->s.k = (bpf_int32) vlan_num;

Reply via email to