0

How can I split a packet into two packets using pcapdotnet? This is what I tried, but I don't know whether it's correct:

    public IEnumerable<Packet> splitPacket(Packet packet)
    {
        EthernetLayer ethernet = (EthernetLayer)packet.Ethernet.ExtractLayer();
        IpV4Layer ipV4Layer = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
        DateTime packetTimestamp = packet.Timestamp;
        ILayer payload = packet.Ethernet.IpV4.Payload.ExtractLayer();
        IpV4Fragmentation.Equals(packet, packet);

        yield return PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, payload);
    }
user1269592
  • 691
  • 3
  • 12
  • 24
  • Not sure how you want to split it, but your method's signature returns a single `Packet`, so I am guessing you are only creating a single one. You might want to return a list-of-packets, probably? Or `IEnumerable`? – vgru Nov 07 '12 at 15:23
  • yes, this is mistake but my question is if the rest OK ? – user1269592 Nov 07 '12 at 15:43
  • Well, you are building a single packet, and returning a single one. I don't know what you meant by "splitting the packet". Split it how? – vgru Nov 07 '12 at 15:46
  • i update my code, but i don't know how to build and return IEnumerable, and i am split the packet with IpV4Fragmentation property – user1269592 Nov 07 '12 at 15:53
  • But what does `IpV4Fragmentation.Equals` do? Doesn't this only return true if two packets are equal? What are you trying to do with these packets anyway, send them both immediately? – vgru Nov 07 '12 at 15:57
  • Oh, wait, `IpV4Fragmentation.Equals` doesn't even exists. It's doing nothing at all (it not implemented as a method in `IpV4Fragmentation`, so you are actually calling `object.Equals`, which compares the same reference to itself and returns `true`). – vgru Nov 07 '12 at 15:59
  • from API: IpV4Fragmentation.Equals(obj A, obj B) objA = the first object to compate – user1269592 Nov 07 '12 at 16:05
  • Well, two things: 1. I looked at the [source code](http://pcapdotnet.codeplex.com/SourceControl/changeset/view/69631#981329), and couldn't find the static method (only the instance method, which you would call like `a.Equals(b)`, and 2. it still seems like a method which simply returns `true` if two objects are equal (and in this case you are comparing `packet` to `packet`). – vgru Nov 07 '12 at 16:10
  • You could simply write `yield return` twice, but I don't see why you don't simply use the same `packet` twice? E.g. `yield return packet; yield return packet;` would work, but what's the point of such method? – vgru Nov 07 '12 at 16:12
  • read here: http://pcapdotnet.codeplex.com/discussions/350211 – user1269592 Nov 07 '12 at 16:14
  • Could you explain why and how you want to split it? I am not fully understanding what you're trying to do (but then again, I'm no expert for IP layers). And the person in that forum stated that you should modify **`ipV4Layer.Fragmentation`** (maybe set it to a different instance of `IpV4Fragmentation` or something, like `ipV4layer.Fragmentation = new IpV4Fragmentation(...)`. But, if I am not mistaken, this property's values are used only to *describe* the way packet is split (simply modifying this property will **not** modify the data inside the packet). – vgru Nov 07 '12 at 22:34
  • You should explain *what* you are trying to do, that would help. E.g. "I want to split the packet which contains 50 bytes of data into two packets of 25 bytes each". – vgru Nov 07 '12 at 22:35
  • i want to split the data of the packet, all other packet details should remain the same so my device that receive this 2 packets (after the split) would know to merge them – user1269592 Nov 08 '12 at 05:03

1 Answers1

1

I have never used Pcap.Net, so I am not sure if this will work, but the general idea is to split the data (the "payload layer") into several chunks and then send it. To make sure the fragments can be reassembled, you also need to add some info about the position (offset) of each fragment.

In Pcap.Net, the IpV4Fragmentation class contains two properties which define this:

  • IpV4Fragmentation.Options:
    • for all fragments except tha last one, it should be set to IpV4FragmentationOptions.MoreFragments,
    • for the last fragment, it should be set to IpV4FragmentationOptions.None
  • IpV4Fragmentation.Offset:
    • contains the offset of the fragment (which must be divisible by 8). This offset is zero for the first fragment.

With this in mind, I would write something like this:

(Disclaimer: this was written in Notepad, I have no clue if it even compiles, let alone works as it should):

public IEnumerable<Packet> Split(Packet packet, int numberOfFragments)
{
    // get original layers
    var ethernet = (EthernetLayer)packet.Ethernet.ExtractLayer();
    var ipV4 = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
    var time = packet.Timestamp;

    // extract the data
    var payload = (PayloadLayer)packet.Ethernet.IpV4.Payload.ExtractLayer();
    var totalLength = payload.Length;

    // split data into smaller segments
    var partialLength = totalLength / numberOfFragments;

    // make sure it's divisible with 8
    // (see http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly)
    partialLength = (partialLength / 8) * 8;

    // send one by one
    var offset = 0;
    while (offset < totalLength)
    {
        // get length for this fragment
        var fragmentLength = partialLength;
        var options = IpV4FragmentationOptions.MoreFragments;            

        // is this the last fragment? trim length if needed
        if (offset + fragmentLength >= totalLength) 
        {
            options = IpV4FragmentationOptions.None;
            fragmentLength = totalLength - offset;
        }

        // copy the actual data into a new buffer
        var newBuffer = payload.ReadBytes(offset, fragmentLength);
        var newPayload = new PayloadLayer() { Data = newBuffer };

        // change IP layer fragmentation options
        ipV4.Fragmentation = new IpV4Fragmentation(options, offset);

        // return it
        yield return PacketBuilder.Build(time, ethernet, ipV4, newPayload);

        // next offset
        offset += fragmentLength;
    }
}

[Updated with @brickner's suggestions]

vgru
  • 49,838
  • 16
  • 120
  • 201
  • Indeed looks like a good start. You should probably put MoreFragments on all segments *but* the last one. Also, it seems this won't cover the entire original packet because of rounding issues, but this can be debugged and fixed easily. – brickner Nov 10 '12 at 17:54
  • @brickner: thanks, I presumed there would be bugs in that code. I've just updated the code to fix these two issues. I believe the more appropriate input for this method should be fragment length rather than number of fragments anyway, so OP might want to tweak it further. – vgru Nov 13 '12 at 14:06