I'm trying to filter on some parts of the payload, for an IPv6 packet with extension headers (for instance Destination Options).
ip6tables works fine with conditions like --proto udp
or --dport
109
, even when the packet has extension headers. Netfilter clearly knows how to jump over Destination Options to
find the UDP header.
Now, I would like to use the u32 module to match a byte in the
payload (say "I want the third byte of the payload to be 42). If the packet has no extension headers something like --u32
"48&0x0000ff00=0x2800"̀
(48 = 40 bytes for the IPv6 header + 8 for the UDP header) works fine, If the packet has a Destination Options, it no
longer matches. I would like to write a rule that will work whether
the packet has Destination Options or not.
I do not find a way to tell Netfilter to parse until the UDP header
(something that it is able to do, otherwise --dport
109
would not work) then to leave u32 parse the rest.
I'm looking for a simple way, otherwise, as BatchyX mentions, I could write a kernel module doing what I want.
Answer is focusing on resolving problem in case of IPv4 packet and does not address problem of (multiple) extension headers that need to be accounted for before proper offset is calculated to get to real data part.
Following rule is comprised of 2 parts
6&0xFF=17
0>>22&0x3C@7&0xFF=0x2A
iptables -I INPUT -m u32 --u32 "6&0xFF=17&&0>>22&0x3C@7&0xFF=0x2A" -m comment --comment "Match udp packet with 3rd data byte set to 42" -j LOG
Checking 3rd byte is tricky since you need to dynamically position in UDP header. UDP Header starts after IP header;
check this header model to get better idea what is where.
As you can see 20 bytes is min length of IP header, but then if there are options of any data it can be more than 20 bytes so you need to dynamically position your self to start of UDP header.
Possition reading from first 4 bytes ( 32 bits / u32)
quote from:
To get the header length, we need the first byte: "0>>24", but we need to only grab the lower nibble and we need to multiply that number by 4 to get the actual number of bytes in the header. To do the multiply, we'll right shift 22 instead of 24. With this shift, we'll need to use a mask of 0x3C instead of the 0x0F we would have used. The expression so far is: "0>>22&0x3C".
Now that we have offset where UDP header starts ( 0>>22&0x3C ) we can just possition our selves to read bytes 7,8,9,10 ( where data bytes are 8,9,10) and cut off with mask 0xFF last of 4 (3rd data byte). "7&0xFF"
I ran into the same problem and patched the u32-module. I have two patches for the 2.6.30 Kernel, one for the kernel and one for the user land, They probably won't handle fragmented payloads any better than the original u32 matcher, but it worked for my problem.
Kernel Patch:
User land patch: