예제 #1
0
        /// <summary>
        /// Takes one or more packets as a byte array, validates they match source/destination IP and protocol,
        ///   and stores them for defragmentation processing.
        /// </summary>
        /// <param name="buffer">byte array containing packet data</param>
        /// <param name="size">usable length of byte array - must be less than its allocated length.</param>
        public unsafe void FilterAndStoreData(byte[] buffer, int size)
        {
            int offset = 0;

            if (buffer == null || buffer.Length == 0)
            {
                return;
            }

            if (buffer.Length < size)
            {
                Trace.WriteLine("IPDecoder: Buffer length is less than specified size.  Size=[" + size.ToString() + "], Length=[" + buffer.Length + "]", "DEBUG-MACHINA");
                return;
            }

            fixed(byte *ptr = buffer)
            {
                while (offset < size - sizeof(IPv4Header))
                {
                    // first four bits (network order) of IPv4 and IPv6 is the protocol version
                    byte version = (byte)((ptr + offset)[0] >> 4);
                    if (version == 6)
                    {
                        // TODO: IP6 packets, and mixed IP4/IP6, need to be tested with real-world data.
                        if (offset + sizeof(IPv6Header) > size)
                        {
                            Trace.WriteLine("IPDecoder: IP6 Packet too small for header. offset: " + offset.ToString() + ", size: " + size.ToString(), "DEBUG-MACHINA");
                            return;
                        }

                        IPv6Header header6 = *(IPv6Header *)(ptr + offset);

                        // make sure we have a valid exit condition
                        if (header6.PayloadLength * 8 > buffer.Length - offset - sizeof(IPv6Header))
                        {
                            Trace.WriteLine("IPDecoder: IP6 Packet too small for payload. payload length: " +
                                            (header6.payload_length * 8).ToString() + ", Buffer: " + buffer.Length.ToString() + ", offset: " + offset.ToString(), "DEBUG-MACHINA");
                            return;
                        }

                        offset += sizeof(IPv6Header) + (header6.PayloadLength * 8);

                        continue;
                    }
                    else if (version != 4)
                    {
                        Trace.WriteLine("IPDecoder: IP protocol version is neither 4 nor 6. Version is " + version.ToString(), "DEBUG-MACHINA");
                        return;
                    }

                    IPv4Header ip4Header = *(IPv4Header *)(ptr + offset);

                    int packetLength = ip4Header.Length;

                    // work-around for TCP segment offloading
                    if (packetLength == 0 && ip4Header.Id != 0)
                    {
                        packetLength = size;
                    }

                    // make sure we have a valid exit condition
                    if (packetLength <= 0 & packetLength > 65535)
                    {
                        Trace.WriteLine("IPDecoder: Invalid packet length [" + packetLength.ToString() + "].", "DEBUG-MACHINA");
                        return;
                    }
                    if (packetLength > buffer.Length - offset)
                    {
                        Trace.WriteLine("IPDecoder: buffer too small to hold complete packet.  Packet length is [" + packetLength.ToString() + "], remaining buffer is [" + (buffer.Length - offset).ToString() + "].", "DEBUG-MACHINA");
                        return;
                    }

                    // filter out packets with an incorrect source / destination IP
                    if (_sourceIP == ip4Header.ip_srcaddr &&
                        _destinationIP == ip4Header.ip_destaddr &&
                        _protocol == ip4Header.protocol)
                    {
                        // store payload
                        byte[] ret = new byte[packetLength];
                        Array.Copy(buffer, offset, ret, 0, ret.Length);
                        Fragments.Add(ret);
                    }

                    offset += packetLength;
                }

                // Note: disabled because this seems to occur occasionally for winpcap for no apparent reason.  Packet length is 40 bytes, buffer length is 46.  Eth header is 14 bytes, total payload was 60.

                /*
                 * if (offset != size)
                 * {
                 *  Trace.WriteLine("IPDecoder: Buffer contains extra bytes after processing packets.  Buffer size: [" + size.ToString() + "], final processed length: [" + offset.ToString() + "].");
                 *  Trace.WriteLine(Utility.ByteArrayToHexString(buffer, 0, size));
                 * }
                 */
            }
        }
예제 #2
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);
        }