예제 #1
0
        /// <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);
        }