fako1024/slimcap

Support for IPv6 jumbograms

Opened this issue · 5 comments

In #54 I made a few attempts at generating IPv6 Jumbograms (RFC) with an extended Hop-by-hop header, but failed to do so. Some sources I tried to follow:

>>> scapy
send(IPv6(dst=’::1’,src=’fe80::dead:beef’)/IPv6ExtHdrHopByHop(options=Jumbo(jumboplen=2**30)))

Given this feature seems to be very uncommon it seems this doesn't have high priority though.

DoD

  • Find a way to simulate / generate valid IPv6 Jumbograms
  • Inject into sources of slimcap
  • Ensure correct processing of packet direction / length

I finally managed to craft an IPv6 jumbogram using scapy (pip install scapy was all that was needed) based on information found in this publication:

>>> sr1(IPv6(dst='::1',nh=0,plen=0)/IPv6ExtHdrHopByHop(options=[Jumbo(jumboplen=100000)])/Raw(b'A' * 99992))
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
<IPv6  version=6 tc=0 fl=0 plen=0 nh=Hop-by-Hop Option Header hlim=64 src=::1 dst=::1 |<IPv6ExtHdrHopByHop  nh=No Next Header len=0 autopad=On options=[<Jumbo  otype=Jumbo Payload [11: discard+ICMP not mcast, 0: Don't change en-route] optlen=4 jumboplen=100000 |>] |<Raw  load='...' |>>>

In order to be able to send this, the MTU of the lo interface has to be adjusted, e.g.:

ifconfig lo mtu 110000

A corresponding pcap file was obtained (which is parsed by slimcap correctly, including the actual length of the packet): ipv6_jumbogram.pcap.gz

However, this is just half of the story (since it's just a bogus packet without transport layer) - problems might arise once there is an actual TCP/UDP/ICMPv6 payload because the respective header parameters are not stored in their usual location (although slimcap doesn't care about those, so maybe it's moot). So next step would be to craft individual IPv6 jumbograms of all these flavors.

Additional scapy commands for the respective flavors:

TCP
Easy enough, according to the RFC the TCP header can follow directly and without any limitation:

>>> sr1(IPv6(dst='::1',nh=0,plen=0)/IPv6ExtHdrHopByHop(options=[Jumbo(jumboplen=100000)])/TCP(dport=80)/Raw(b'A' * 99992))

ICMPv6
Also trivial:

>>> sr1(IPv6(dst='::1',nh=0,plen=0)/IPv6ExtHdrHopByHop(options=[Jumbo(jumboplen=100000)])/ICMPv6EchoRequest()/Raw(b'A' * 99992))

UDP
The RFC specifies to force the UDP Length field to zero (because it's limited to a maximum value of 65535) and let the application handle it:

>>> sr1(IPv6(dst='::1',nh=0,plen=0)/IPv6ExtHdrHopByHop(options=[Jumbo(jumboplen=100000)])/UDP(sport=10000, dport=10000, len=0)/Raw(b'A' * 99992))

PCAP file containing all four flavors: ipv6_jumbograms.pcap.gz

Capture is confirmed to be working as expected for all four cases using slimcap (showing full first 96 bytes of each case for posterity) in order RAW-TCP-ICMPv6-UDP:

# github.com/fako1024/slimcap/examples/dump# ./dump -d lo
Listening on interface `lo`: lo
Reading 10 packets from wire (copy operation)...
Received packet with Payload on `lo` (total len 100054): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 59 0 194 4 0 1 134 160 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65] (inbound: true)
Received packet with Payload on `lo` (total len 100074): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 6 0 194 4 0 1 134 160 0 20 0 80 0 0 0 0 0 0 0 0 80 2 32 0 244 207 0 0 65 65 65 65 65 65 65 65 65 65 65 65 65 65] (inbound: true)
Received packet with Payload on `lo` (total len 100062): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 58 0 194 4 0 1 134 160 128 0 229 13 0 0 0 0 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65] (inbound: true)
Received packet with Payload on `lo` (total len 100062): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 17 0 194 4 0 1 134 160 39 16 39 16 0 0 23 23 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65 65] (inbound: true)
...

Luckily, the default link.CaptureLengthMinimalIPv6Transport still seems to be sufficient to allow capturing e.g. the relevant TCP / UDP headers (ports / TCP flags):

Received packet with Payload on `lo` (total len 100054): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 59 0 194 4 0 1 134 160 65 65 65 65 65 65] (inbound: true)
Received packet with Payload on `lo` (total len 100074): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 6 0 194 4 0 1 134 160 255 253 255 253 0 0] (inbound: true)
Received packet with Payload on `lo` (total len 100062): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 58 0 194 4 0 1 134 160 128 0 229 13 0 0] (inbound: true)
Received packet with Payload on `lo` (total len 100062): [255 255 255 255 255 255 0 0 0 0 0 0 134 221 96 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 17 0 194 4 0 1 134 160 255 253 255 253 0 0] (inbound: true)

So in conclusion: We're good.

@els0r FYI

Unfortunately I was wrong about one point: In order to successfully parse the TCP flags (needed for e.g. packet direction detection / classification in goProbe the link.CaptureLengthMinimalIPv6Transport is not sufficient, as it is stored several bytes later (initial review shows 8 bytes, TBC)...