Split packet (fragmentation)

Mar 4, 2014 at 2:34 PM
i try to split packet:
    private IEnumerable<Packet> SplitPacket(Packet packet, int numberOfFragments)
            {
                IpV4Datagram ipV4Datagram = packet.Ethernet.IpV4;
    
                if (ipV4Datagram.Protocol == IpV4Protocol.Tcp || ipV4Datagram.Protocol == IpV4Protocol.Udp)
                {
                    EthernetLayer ethernet = (EthernetLayer)packet.Ethernet.ExtractLayer();
                    ILayer layer = packet.Ethernet.IpV4.ExtractLayer();
                    TcpLayer tcpLayer = (TcpLayer)packet.Ethernet.IpV4.Tcp.ExtractLayer();
                    tcpLayer.Checksum = null;
                    IpV4Layer ipV4Layer = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
                    ipV4Layer.HeaderChecksum = null;
                    DateTime packetTimestamp = packet.Timestamp;
                    PayloadLayer payload = (PayloadLayer)packet.Ethernet.IpV4.Payload.ExtractLayer(); //extract the data
                    int totalLength = payload.Length;
                    int partialLength = totalLength / numberOfFragments; //split data into smaller segments
                    partialLength = (partialLength / 8) * 8; //make sure it's divisible with 8
                    //(http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly)
                    ushort offset = 0; //send one by one
    
                    while (offset < totalLength)
                    {
                        int fragmentLength = partialLength; //get length for this fragment
                        IpV4FragmentationOptions options = IpV4FragmentationOptions.MoreFragments;
    
                        if (offset + fragmentLength >= totalLength) //is this the last fragment ? trim length if needed
                        {
                            options = IpV4FragmentationOptions.None;
                            fragmentLength = totalLength - offset;
                        }
    
                        byte[] newBuffer = ipV4Datagram.Payload.ToArray(); //copy the actual data into a new buffer
                        PayloadLayer newPayload = new PayloadLayer { Data = new Datagram(newBuffer, offset, fragmentLength) };
                        ipV4Layer.Fragmentation = new IpV4Fragmentation(options, offset); //change IP layer fragmentation options
                        yield return PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, tcpLayer, newPayload); //return
                        offset += (ushort)fragmentLength; //next offset
                    }
                }
            }
The problem is that after play this file i can see the same number of packets like in the original Wireshark file so it mean that something not working and the protocol field in Wiresahrk recognized this packet as IPV4 and this is how this packet looks (i think i have build this packet in invalid way):

Image
Coordinator
Mar 7, 2014 at 10:18 AM
Hi psptst1,

Can you try and debug the code and see where it goes and where it doesn't?
I think it would be easier this way than just looking at the code.

Boaz.
Mar 19, 2014 at 12:11 PM
Edited Mar 20, 2014 at 12:31 PM
Hi Boaz,

after split Pcap file, every packet split into IPv4 packet(s) and the original protocol packet, and it seems that this packet has bad TCP checksum,, you can find the new file here

Please see my new code:
        private IEnumerable<Packet> SplitPacket(Packet packet, int numberOfFragments)
        {
            IpV4Datagram ipV4Datagram = packet.Ethernet.IpV4;

            if (ipV4Datagram.Protocol == IpV4Protocol.Tcp || ipV4Datagram.Protocol == IpV4Protocol.Udp)
            {
                EthernetLayer ethernet = (EthernetLayer)packet.Ethernet.ExtractLayer();
                ILayer layer = packet.Ethernet.IpV4.ExtractLayer();
                IpV4Layer ipV4Layer = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
                ipV4Layer.HeaderChecksum = null;
                DateTime packetTimestamp = packet.Timestamp;
                PayloadLayer payload = (PayloadLayer)packet.Ethernet.IpV4.Payload.ExtractLayer(); //extract the data
                int totalLength = payload.Length;
                int partialLength = totalLength / numberOfFragments; //split data into smaller segments
                partialLength = (partialLength / 8) * 8; //make sure it's divisible with 8
                if (partialLength == 0)
                    partialLength = 8;
                //(http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly)
                ushort offset = 0; //send one by one

                while (offset < totalLength)
                {
                    int fragmentLength = partialLength; //get length for this fragment
                    IpV4FragmentationOptions options = IpV4FragmentationOptions.MoreFragments;

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

                    byte[] newBuffer = ipV4Datagram.Payload.ToArray(); //copy the actual data into a new buffer
                    PayloadLayer newPayload = new PayloadLayer { Data = new Datagram(newBuffer, offset, fragmentLength) };
                    ipV4Layer.Fragmentation = new IpV4Fragmentation(options, offset); //change IP layer fragmentation options
                    Packet newPacket = null;

                    if (packet.Ethernet.IpV4.Protocol == IpV4Protocol.Tcp)
                    {
                        TcpLayer tcpLayer = (TcpLayer)packet.Ethernet.IpV4.Tcp.ExtractLayer();
                        tcpLayer.Checksum = null;
                        newPacket = PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, tcpLayer, newPayload);
                    }
                    else if (packet.Ethernet.IpV4.Protocol == IpV4Protocol.Udp)
                    {
                        UdpLayer udpLayer = (UdpLayer)packet.Ethernet.IpV4.Udp.ExtractLayer();
                        udpLayer.Checksum = null;
                        newPacket = PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, udpLayer, newPayload);
                    }

                    yield return newPacket;
                    //yield return PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, tcpLayer, newPayload); //return
                    offset += (ushort)fragmentLength; //next offset
                }
            }
        }
i added:
                if (partialLength == 0)
                    partialLength = 8;
because if partialLength = 0 i get endless loop.

But it seems that TCP packets comes with bad TCP checksum (see my file example link) but UDP packet received OK
Any ideas why ?
Coordinator
Mar 28, 2014 at 6:27 AM
Looking at the first 2 packets in you .pcap file I see that the first packet has offset of 0 with 48 bytes payload and the second packet has offset of 16 with another 48 bytes offset.
Why do you set offset of 16?
Mar 28, 2014 at 8:37 AM
Can you show me please what i was doing wrong and how to fix it ?
Coordinator
Mar 29, 2014 at 6:32 AM
For me it looks like the second packet should have an offset of 48 instead of 16.
I'm not sure, but you should look at the packets and consider what offset each should have.
Mar 29, 2014 at 11:34 AM
Can you please elaborate about offset and what i need to do ?
Coordinator
Apr 4, 2014 at 2:13 PM
Apr 4, 2014 at 3:17 PM
Can you please give me an example with my code to test it and see if it's works ?
Coordinator
Apr 12, 2014 at 8:14 AM
I don't understand, what example are you looking for?
Apr 12, 2014 at 10:11 AM
What to change in order it will work, you gave me link but i didn't understand this
Coordinator
Apr 12, 2014 at 11:14 AM
I didn't debug your code.
I suggest you first understand how does IPv4 fragmentation and reassembly works.
It's not trivial and in my opinion it would be quite hard to write the code to do that without understanding how this work.