expression rejects all packets for IPv6 upper-layer protocol
yiyuandao opened this issue ยท 20 comments
Hi,
I tried to run following command:
tcpdump -i em1 'ip6 and udp[10]&1 !=0'
and got the following:
tcpdump: expression rejects all packets
I checked the document pcap-filter.
and in the section 'expr relop expr':
Note that tcp,
udp and other upper-layer protocol types only apply to IPv4, not
IPv6 (this will be fixed in the future)
I wonder is there any plan to add this filter for IPv6?
Thanks.
@yiyuandao wanted to follow up on your filtering question for IPv6
; You could try using running your UDP
filter wide open and then using grep
to capture everything coming across as IP6.
tcpdump -i em1 udp and 'udp[10] & 1!=0' -vvv | grep -i 'IP6'
This issue still exists (in tcp/udp). Is there a reason the syntax ought not to work? Since something like ip6 and tcp port 80
works fine.
If we do want syntax like ip6 and tcp[1] = 0x5
to work, do we want only tcp[1] = 0x5
to look for IPv6 in addition to IPv4? Or leave it as only IPv4?
tcp port 80
Checks for both so there is a little inconsistency.
What is the desired behaviour? I was thinking of making a PR with these changes but I'm not sure what would be preferred.
As the pcap-filter(7) man page explains it:
To access data inside the packet, use the following syntax:
proto [ expr : size ]
Note that tcp, udp and other upper-layer protocol types only apply to IPv4, not IPv6 (this will be fixed in the future).
Closing as resolved (not a bug, but an improvement that remains to be made).
Should this issue be left open to track it as an enhancement request?
Alright, let's keep it reopened for a while longer.
Is somebody working on this issue? What is to be implemented? If the compiler can generate instructions to find TCP port after IPv6 header, it should work for anything else inside the TCP header, shouldn't it?
This is an old known problem, nobody is working on it now, as far as I am aware. Competent volunteers are welcome to contribute a solution. Ideally it would be best to discuss the solution in sufficient detail before spending time on the code.
I agree. If it is not too complex, I believe I can provide some development capacity from my team. We would really like this thing to work, however, we have no experience with libpcap internals.
What can be some next step?
That might turn out a deeper rabbit hole than it seems because this problem is not to extend an existing dual-stack mapping of another packet data accessor onto UDP, but to introduce dual-stack mapping of packet data accessors for the first time.
In any case, it should be helpful to study this and this documents, then you can have a look at scanner.l
, grammar.y
and gencode.c
and try to think what a good solution would look like. After that it would be a good time to confirm your findings here or on the mailing list before committing into the implementation.
Hopefully that's good enough a starting point.
The second link (https://sharkfestus.wireshark.org/sharkfest.11/presentations/McCanne-Sharkfest'11_Keynote_Address.pdf) gives me HTTP 404.
I think the Wireshark web sites are being reworked. Down link reported on Discord.
The keynote itself can still be found on YouTube though: https://www.youtube.com/watch?v=XHlqIqPvKw8
A copy of the PDF is here.
Thank you for raising this, www.tcpdump.org is now using the copy for the documentation reference.
A possible work-around until a more robust solution is available: ip6 and (ip6[6] = 17) and ((ip6[40 + 8 + 2] & 1) != 0)
. Of course this only works if there are no IPv6 extension headers present, and I didn't combine the offsets intentionally so it's more obvious that we're skipping the standard 40 bytes of the IPv6 header, the 8 bytes of the UDP header and 2 additional bytes.
I think the Wireshark web sites are being reworked.
They are indeed being reworked, and a recent change inadvertently broke some links. https://sharkfestus.wireshark.org/sharkfest.11/presentations/McCanne-Sharkfest'11_Keynote_Address.pdf should be working again.
I did a quick research about the topic and performed some very basic experiments.
Here is bytecode for IPv4/TCP with dst port 80...
$ tcpdump -d 'ip and tcp dst port 80'
Warning: assuming Ethernet
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 10
(002) ldb [23]
(003) jeq #0x6 jt 4 jf 10
(004) ldh [20]
(005) jset #0x1fff jt 10 jf 6
(006) ldxb 4*([14]&0xf)
(007) ldh [x + 16] ; loading dst port
(008) jeq #0x50 jt 9 jf 10 ; testing for TCP dst port 80
(009) ret #262144
(010) ret #0
Bytecode for IPv4/TCP flags (currently same result as with tcp[tcpflags] & 2 != 0
):
$ tcpdump -d 'ip and tcp[tcpflags] & 2 != 0'
Warning: assuming Ethernet
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 10
(002) ldb [23]
(003) jeq #0x6 jt 4 jf 10
(004) ldh [20]
(005) jset #0x1fff jt 10 jf 6
(006) ldxb 4*([14]&0xf)
(007) ldb [x + 27] ; loading TCP flags
(008) jset #0x2 jt 9 jf 10 ; testing for TCP flags SYN
(009) ret #262144
(010) ret #0
Here is bytecode for IPv6/TCP with dst port 80... It ignores IPv6 extension headers.
$ tcpdump -d 'ip6 and tcp dst port 80'
Warning: assuming Ethernet
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 7
(002) ldb [20]
(003) jeq #0x6 jt 4 jf 7
(004) ldh [56] ; loading dst port
(005) jeq #0x50 jt 6 jf 7 ; testing for TCP dst port 80
(006) ret #262144
(007) ret #0
And for IPv6/TCP flags, it something like fails:
$ tcpdump -d 'ip6 and tcp[tcpflags] & 2 != 0'
Warning: assuming Ethernet
tcpdump: expression rejects all packets
I do not see any reason why the last expression would not give something like this:
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 7
(002) ldb [20]
(003) jeq #0x6 jt 4 jf 7
(004) ldh [69] ; loading TCP flags
(005) jset #0x2 jt 6 jf 7 ; testing for TCP flags SYN
(006) ret #262144
(007) ret #0
And expression tcp[tcpflags] & 2 != 0
should take advantage of such improvement as well and consider both IPv4 and IPv6. I think, generating such code would be the goal of this issue. I believe that the logic to be updated is in this switch case: https://github.com/the-tcpdump-group/libpcap/blob/master/gencode.c#L7483.
After that, the much more difficult part would be to parse IPv6 extension headers... But I consider it to be another story.
Loading of ports is regardless of L3 layer is done via gen_load_a()
, the IPv6 case is here https://github.com/the-tcpdump-group/libpcap/blob/master/gencode.c#L1865. Thus, I assume that this logic can be somehow refactored/merged or something.
When you study the bytecode, it helps to remember that by default you see the optimized version. You could use BPF Exam to get a slightly better view of what comes out of gencode.c
and what how it changes in optimize.c
.