/// <summary> /// This returns the next complete payload. This involves defragmenting any fragments /// </summary> /// <returns>byte array containing the IP payload.</returns> public unsafe byte[] GetNextIPPayload() { if (Fragments.Count == 0) { return(null); } List <byte[]> nextFragments; // optimize single packet processing if (Fragments.Count == 1) { nextFragments = Fragments; } else { nextFragments = Fragments.OrderBy(x => Utility.ntohs(BitConverter.ToUInt16(x, 4))) // identification .ThenBy(x => Utility.ntohs(BitConverter.ToUInt16(x, 6)) & 0x1fff) // fragment offset .ToList(); } ushort currentId = 0; ushort fragmentOffset = 0; byte[] payload = null; for (int i = 0; i < nextFragments.Count; i++) { fixed(byte *ptr = nextFragments[i]) { IPv4Header ip4Header = *(IPv4Header *)ptr; // every new ID resets the internal state - we dont need to return in order. if (currentId != ip4Header.Id) { currentId = ip4Header.Id; payload = null; fragmentOffset = 0; } // skip for now if the offset is incorrect, the correct packet may come soon. if (ip4Header.FragmentOffset == fragmentOffset) { int fragmentDataSize; // correction for fragmented packet // note: ip4Header.length may be zero if using hardwre offloading to network card. if (ip4Header.Length == 0 && ip4Header.Id != 0) { fragmentDataSize = nextFragments[i].Length - ip4Header.HeaderLength; } else { fragmentDataSize = ip4Header.Length - ip4Header.HeaderLength; } // resize payload array if (payload == null) { payload = new byte[fragmentDataSize]; } // if this is a fragment, prepare array to accept it and record last fragment time. if (ip4Header.FragmentOffset > 0) { LastIPFragmentTimestamp = DateTime.Now; Array.Resize(ref payload, payload.Length + fragmentDataSize); } // copy packet into payload Array.Copy(nextFragments[i], ip4Header.HeaderLength, payload, fragmentOffset, fragmentDataSize); // add data offset fragmentOffset += (ushort)fragmentDataSize; // return payload if this is the final fragment if ((ip4Header.Flags & (byte)IPFlags.MF) == 0) { // purge current fragments if (Fragments.Count == 1) // optimize single packet processing { Fragments.Clear(); } else { // remove in reverse order to prevent IEnumerable issues. for (int j = Fragments.Count - 1; j >= 0; j--) { if (Utility.ntohs((ushort)BitConverter.ToUInt16(Fragments[j], 4)) == currentId) { Fragments.RemoveAt(j); } else if (Utility.ntohs(BitConverter.ToUInt16(Fragments[j], 4)) < currentId - 99) { //Trace.WriteLine("IP: Old fragment purged. Current ID: [" + currentId.ToString("X4") + "], Old ID: + [" + //IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(Fragments[j], 4)) + "] " + Utility.ByteArrayToHexString(Fragments[j], 0, 50)); Fragments.RemoveAt(j); } } } return(payload); } } } } return(null); }