Monday 15 June 2015

Re-assembling IP Fragments in PCAP Files

Some time ago I created "stripe", a tool for stripping back layers of encapsulation headers from PCAP files leaving plain payload (typically IP) over Ethernet. "stripe" works with a variety of encapsulation types, from simple VLAN tags up to GRE and GTP, however one thing that stripe couldn't handle was if packets were fragmented after being encapsulated.

One user, LisbethS, suggested that I should build in IP fragment reassembly capabilities into stripe, however my first thought was that the two should be separate utilities. As I thought about it more, though, I realised that the two functions (decapsulation and re-assembly) were actually intertwined - if you treat them as separate processes then you can't re-assemble IP that is encapsulated within something else, nor can you decapsulate GRE or GTP that has been fragmented. The key, then, was to do both re-assembly and decapsulation as part of the same process.

Reassembling Packet Fragments


RFC 815 describes a minimal way to re-assemble IP fragments which is not that complex in principle, so I thought I'd add the functionality. I soon realised it wasn't quite as straightforward as I thought and you have to be very careful about the order of operations.

For example, if you have a packet that gets encapsulated then subsequently fragmented, then trying to decapsulate without reassembling first will fail (the first fragment decapsulates to a partial frame, then the subsequent fragment(s) fail to decapsulate). On the other hand, if you re-assemble first then decapsulate then you don't catch the case where a packet is fragmented before encapsulation. Neither approach can catch the case where a packet is fragmented, then encapsulated, then subsequently fragmented again.

To cut a long story short, the answer appears to be that you need to iteratively re-assemble, decapsulate until fragments are found, re-assemble again, decapsulate again... until there are no more fragments and everything is fully decapsulated.

Anyway, stripe now does both decapsulation and IP fragment re-assembly, meaning that it can take a pcap file containing fragmented and / or encapsulated packets, strip off all the encapsulation and re-assemble the fragments and write out the result to a new pcap file.

Download


The latest version is available for download at https://github.com/theclam/stripe - it is available as source code (compiles without dependancies in almost any Linux distro) and there are also Mac and Windows binaries for easy download.

UPDATE:

I've managed to recreate some of the SEGFAULTs that people have been kindly reporting to me. It turns out there was a typo / n00b mistake (I'm not sure which, most of this is coded way too late at night) which I have now corrected. If you tried before and got an error, it may be fixed now. The memory leaks have also been reduced from "raging" to "moderate" :)

11 comments:

  1. Hi
    Thank you for a good job.
    I have tested your program for my pcap file and I have gotten segmentation fault.
    I dont know what the problem is.
    My pcap file has GRE and other headers that you mentioned here along with fragment packets which is fragmented after GRE header encapsulation and before GRE header encapsulation.
    I should say all the possible states exist in my pcap file.
    How can I found the reasons of the problem

    ReplyDelete
    Replies
    1. Hi,

      Does the SEGFAULT still occur if you disable re-assembly (-f)? Using verbose (-v) output may assist in finding which particular frame is upsetting it.

      Are you able to share the pcap file? If not then you would really have to run it in a debugger and figure out what's wrong with my code, or generate a sample pcap file which triggers the issue that you *can* share. If you can provide that then I'll take a look.

      Thanks,

      Foeh

      Delete
    2. Hi,
      Thank u for the answer.
      At the first time I'll try to gather required information to send it to you.
      it just occurred after reassembly mode enable.
      Lets correct me if I am wrong, does the reassembly mode just reassemble the first layer of the captures packets ?
      If we have fragmentation in the inner protocols like GRE-IP, the program simply reassembled the first layered and then decapsulates all the GRE, MPLS, etc. headers of the packets and does not consider fragmentation in inner layers, for example think we have gre-ip->ip-tcp and fragmentation occurred in ip-tcp header.
      Please correct me if I am wrong.

      Delete
    3. Hi,

      No, it re-assembles at all layers where it finds fragments. It starts by doing a re-assembly pass, then it does a decapsulation pass but the recursive decapsulation stops at any layer where an IP fragment is found. Then it repeats the re-assembly / decapsulation passes until no further re-assembly or decapsulation can be performed. In theory it should re-assemble fragments anywhere and everywhere.

      I've tested GRE with fragments inside which has also then been fragmented after encapsulation so I'm a little surprised that it breaks for you, however I don't have many real-world pcap files and more are always welcome!

      Thanks for the feedback, I look forward to hearing from you.

      Foeh

      Delete
    4. Hi I'm getting an error unable to write temporary file. What am I doing wrong?

      Delete
  2. I know this is a really old post on a blog that hasn't been updated in several years, but I'd just thought I'd leave a comment anyway. I really appreciate you creating this script. That Mac binary worked for me and there was only one little issue. After reassembling the fragmented packets, the resulting pcap has the incorrect value in the IP header for "Total Length". Wireshark did give an error on this "IPv4 total length exceeds packet length", so it detected the issue and was able to give me the correct total length.

    ReplyDelete
    Replies
    1. Hi, Frank.

      I'm glad it proved useful to you! I still get notified of comments, even if I don't really have time to blog these days :) I'm wondering if it's a byte order bug - do you know what the IPv4 total length *should* be vs. what it is?

      Thanks!

      Delete
    2. Aloha Foeh,

      The Total Length should be 1509 (05E5), but the value in the reassembled packet is 53509 (D105).

      Mahalo,
      Frank

      Delete
    3. Thanks, Frank. That looks like it's byte flipped and calculated incorrectly... go, me! I believe I can see where the byte flip is happening but I've long forgotten how the lengths in the header are (meant to be) calculated so I'll have to do a bit of reading.

      Delete
    4. Thanks for providing that data, led me straight to the fault. A lazy memcpy causing a byte flip and I'd forgotten to add the IP header length back in to the total length. Looks like the fix was fairly simple so I've updated the github (the binary is now called stripe-binary-Mac-Intel) - do you fancy checking that against your pcap?

      Delete
    5. Aloha Foeh,

      That worked!! The Length now shows up correctly. I'm glad we could work together to get that fixed.

      Have a great day!
      Frank

      Delete