653 lines
25 KiB
C#
653 lines
25 KiB
C#
|
|
/*
|
||
|
|
This file is part of PacketDotNet
|
||
|
|
|
||
|
|
PacketDotNet is free software: you can redistribute it and/or modify
|
||
|
|
it under the terms of the GNU Lesser General Public License as published by
|
||
|
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
|
(at your option) any later version.
|
||
|
|
|
||
|
|
PacketDotNet is distributed in the hope that it will be useful,
|
||
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
GNU Lesser General Public License for more details.
|
||
|
|
|
||
|
|
You should have received a copy of the GNU Lesser General Public License
|
||
|
|
along with PacketDotNet. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
*/
|
||
|
|
/*
|
||
|
|
* Copyright 2009 Chris Morgan <chmorgan@gmail.com>
|
||
|
|
*/
|
||
|
|
|
||
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Text;
|
||
|
|
using MiscUtil.Conversion;
|
||
|
|
using PacketDotNet.Utils;
|
||
|
|
|
||
|
|
namespace PacketDotNet
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// IPv4 packet
|
||
|
|
/// See http://en.wikipedia.org/wiki/IPv4 for into
|
||
|
|
/// </summary>
|
||
|
|
public class IPv4Packet : IpPacket
|
||
|
|
{
|
||
|
|
// NOTE: No need to warn about lack of use, the compiler won't
|
||
|
|
// put any calls to 'log' here but we need 'log' to exist to compile
|
||
|
|
#pragma warning disable 0169, 0649
|
||
|
|
private static readonly ILogInactive log;
|
||
|
|
#pragma warning restore 0169, 0649
|
||
|
|
|
||
|
|
/// <value>
|
||
|
|
/// Number of bytes in the smallest valid ipv4 packet
|
||
|
|
/// </value>
|
||
|
|
public const int HeaderMinimumLength = 20;
|
||
|
|
|
||
|
|
/// <summary> Type of service code constants for IP. Type of service describes
|
||
|
|
/// how a packet should be handled.
|
||
|
|
/// <p>
|
||
|
|
/// TOS is an 8-bit record in an IP header which contains a 3-bit
|
||
|
|
/// precendence field, 4 TOS bit fields and a 0 bit.
|
||
|
|
/// </p>
|
||
|
|
/// <p>
|
||
|
|
/// The following constants are bit masks which can be logically and'ed
|
||
|
|
/// with the 8-bit IP TOS field to determine what type of service is set.
|
||
|
|
/// </p>
|
||
|
|
/// <p>
|
||
|
|
/// Taken from TCP/IP Illustrated V1 by Richard Stevens, p34.
|
||
|
|
/// </p>
|
||
|
|
/// </summary>
|
||
|
|
public struct TypesOfService_Fields
|
||
|
|
{
|
||
|
|
#pragma warning disable 1591
|
||
|
|
public readonly static int MINIMIZE_DELAY = 0x10;
|
||
|
|
public readonly static int MAXIMIZE_THROUGHPUT = 0x08;
|
||
|
|
public readonly static int MAXIMIZE_RELIABILITY = 0x04;
|
||
|
|
public readonly static int MINIMIZE_MONETARY_COST = 0x02;
|
||
|
|
public readonly static int UNUSED = 0x01;
|
||
|
|
#pragma warning restore 1591
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <value>
|
||
|
|
/// Version number of the IP protocol being used
|
||
|
|
/// </value>
|
||
|
|
public static IpVersion ipVersion = IpVersion.IPv4;
|
||
|
|
|
||
|
|
/// <summary> Get the IP version code.</summary>
|
||
|
|
public override IpVersion Version
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return (IpVersion)((header.Bytes[header.Offset + IPv4Fields.VersionAndHeaderLengthPosition] >> 4) & 0x0F);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
// read the original value
|
||
|
|
var theByte = header.Bytes[header.Offset + IPv4Fields.VersionAndHeaderLengthPosition];
|
||
|
|
|
||
|
|
// mask in the version bits
|
||
|
|
theByte = (byte)((theByte & 0x0F) | (((byte)value << 4) & 0xF0));
|
||
|
|
|
||
|
|
// write back the modified value
|
||
|
|
header.Bytes[header.Offset + IPv4Fields.VersionAndHeaderLengthPosition] = theByte;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <value>
|
||
|
|
/// Forwards compatibility IPv6.PayloadLength property
|
||
|
|
/// </value>
|
||
|
|
public override ushort PayloadLength
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return (ushort)(TotalLength - (HeaderLength * 4));
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
TotalLength = value + (HeaderLength * 4);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The IP header length field. At most, this can be a
|
||
|
|
/// four-bit value. The high order bits beyond the fourth bit
|
||
|
|
/// will be ignored.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="length">The length of the IP header in 32-bit words.
|
||
|
|
/// </param>
|
||
|
|
public override int HeaderLength
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return (header.Bytes[header.Offset + IPv4Fields.VersionAndHeaderLengthPosition]) & 0x0F;
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
// read the original value
|
||
|
|
var theByte = header.Bytes[header.Offset + IPv4Fields.VersionAndHeaderLengthPosition];
|
||
|
|
|
||
|
|
// mask in the header length bits
|
||
|
|
theByte = (byte)((theByte & 0xF0) | (((byte)value) & 0x0F));
|
||
|
|
|
||
|
|
// write back the modified value
|
||
|
|
header.Bytes[header.Offset + IPv4Fields.VersionAndHeaderLengthPosition] = theByte;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The unique ID of this IP datagram. The ID normally
|
||
|
|
/// increments by one each time a datagram is sent by a host.
|
||
|
|
/// A 16-bit unsigned integer.
|
||
|
|
/// </summary>
|
||
|
|
virtual public ushort Id
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return EndianBitConverter.Big.ToUInt16(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.IdPosition);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
EndianBitConverter.Big.CopyBytes(value,
|
||
|
|
header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.IdPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Fragmentation offset
|
||
|
|
/// The offset specifies a number of octets (i.e., bytes).
|
||
|
|
/// A 13-bit unsigned integer.
|
||
|
|
/// </summary>
|
||
|
|
virtual public int FragmentOffset
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
var fragmentOffsetAndFlags = EndianBitConverter.Big.ToInt16(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.FragmentOffsetAndFlagsPosition);
|
||
|
|
|
||
|
|
// mask off the high flag bits
|
||
|
|
return (fragmentOffsetAndFlags & 0x1FFF);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
// retrieve the value
|
||
|
|
var fragmentOffsetAndFlags = EndianBitConverter.Big.ToInt16(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.FragmentOffsetAndFlagsPosition);
|
||
|
|
|
||
|
|
// mask the fragementation offset in
|
||
|
|
fragmentOffsetAndFlags = (short)((fragmentOffsetAndFlags & 0xE000) | (value & 0x1FFF));
|
||
|
|
|
||
|
|
EndianBitConverter.Big.CopyBytes(fragmentOffsetAndFlags,
|
||
|
|
header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.FragmentOffsetAndFlagsPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch the IP address of the host where the packet originated from.</summary>
|
||
|
|
public override System.Net.IPAddress SourceAddress
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return IpPacket.GetIPAddress(System.Net.Sockets.AddressFamily.InterNetwork,
|
||
|
|
header.Offset + IPv4Fields.SourcePosition, header.Bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
byte[] address = value.GetAddressBytes();
|
||
|
|
Array.Copy(address, 0,
|
||
|
|
header.Bytes, header.Offset + IPv4Fields.SourcePosition,
|
||
|
|
address.Length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch the IP address of the host where the packet is destined.</summary>
|
||
|
|
public override System.Net.IPAddress DestinationAddress
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return IpPacket.GetIPAddress(System.Net.Sockets.AddressFamily.InterNetwork,
|
||
|
|
header.Offset + IPv4Fields.DestinationPosition, header.Bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
byte[] address = value.GetAddressBytes();
|
||
|
|
Array.Copy(address, 0,
|
||
|
|
header.Bytes, header.Offset + IPv4Fields.DestinationPosition,
|
||
|
|
address.Length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch the header checksum.</summary>
|
||
|
|
virtual public ushort Checksum
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return EndianBitConverter.Big.ToUInt16(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.ChecksumPosition);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
var val = (UInt16)value;
|
||
|
|
EndianBitConverter.Big.CopyBytes(val,
|
||
|
|
header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.ChecksumPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Check if the IP packet is valid, checksum-wise.</summary>
|
||
|
|
virtual public bool ValidChecksum
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return ValidIPChecksum;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Check if the IP packet header is valid, checksum-wise.
|
||
|
|
/// </summary>
|
||
|
|
public bool ValidIPChecksum
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
log.Debug("");
|
||
|
|
|
||
|
|
// first validate other information about the packet. if this stuff
|
||
|
|
// is not true, the packet (and therefore the checksum) is invalid
|
||
|
|
// - ip_hl >= 5 (ip_hl is the length in 4-byte words)
|
||
|
|
if (Header.Length < IPv4Fields.HeaderLength)
|
||
|
|
{
|
||
|
|
log.DebugFormat("invalid length, returning false");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var headerOnesSum = ChecksumUtils.OnesSum(Header);
|
||
|
|
log.DebugFormat(HexPrinter.GetString(Header, 0, Header.Length));
|
||
|
|
const int expectedHeaderOnesSum = 0xffff;
|
||
|
|
var retval = (headerOnesSum == expectedHeaderOnesSum);
|
||
|
|
log.DebugFormat("headerOnesSum: {0}, expectedHeaderOnesSum {1}, returning {2}",
|
||
|
|
headerOnesSum,
|
||
|
|
expectedHeaderOnesSum,
|
||
|
|
retval);
|
||
|
|
log.DebugFormat("Header.Length {0}", Header.Length);
|
||
|
|
return retval;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch ascii escape sequence of the color associated with this packet type.</summary>
|
||
|
|
override public System.String Color
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return AnsiEscapeSequences.White;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch the type of service. </summary>
|
||
|
|
public int DifferentiatedServices
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return header.Bytes[header.Offset + IPv4Fields.DifferentiatedServicesPosition];
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
header.Bytes[header.Offset + IPv4Fields.DifferentiatedServicesPosition] = (byte)value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <value>
|
||
|
|
/// Renamed to DifferentiatedServices in IPv6 but present here
|
||
|
|
/// for backwards compatibility
|
||
|
|
/// </value>
|
||
|
|
public int TypeOfService
|
||
|
|
{
|
||
|
|
get { return DifferentiatedServices; }
|
||
|
|
set { DifferentiatedServices = value; }
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <value>
|
||
|
|
/// The entire datagram size including header and data
|
||
|
|
/// </value>
|
||
|
|
public override int TotalLength
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return EndianBitConverter.Big.ToUInt16(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.TotalLengthPosition);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
var theValue = (UInt16)value;
|
||
|
|
EndianBitConverter.Big.CopyBytes(theValue,
|
||
|
|
header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.TotalLengthPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch fragment flags.</summary>
|
||
|
|
/// <param name="flags">A 3-bit unsigned integer.</param>
|
||
|
|
public virtual int FragmentFlags
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
var fragmentOffsetAndFlags = EndianBitConverter.Big.ToInt16(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.FragmentOffsetAndFlagsPosition);
|
||
|
|
|
||
|
|
// shift off the fragment offset bits
|
||
|
|
return fragmentOffsetAndFlags >> (16 - 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
// retrieve the value
|
||
|
|
var fragmentOffsetAndFlags = EndianBitConverter.Big.ToInt16(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.FragmentOffsetAndFlagsPosition);
|
||
|
|
|
||
|
|
// mask the flags in
|
||
|
|
fragmentOffsetAndFlags = (short)((fragmentOffsetAndFlags & 0x1FFF) | ((value & 0x07) << (16 - 3)));
|
||
|
|
|
||
|
|
EndianBitConverter.Big.CopyBytes(fragmentOffsetAndFlags,
|
||
|
|
header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.FragmentOffsetAndFlagsPosition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch the time to live. TTL sets the upper limit on the number of
|
||
|
|
/// routers through which this IP datagram is allowed to pass.
|
||
|
|
/// Originally intended to be the number of seconds the packet lives it is now decremented
|
||
|
|
/// by one each time a router passes the packet on
|
||
|
|
///
|
||
|
|
/// 8-bit value
|
||
|
|
/// </summary>
|
||
|
|
public override int TimeToLive
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return header.Bytes[header.Offset + IPv4Fields.TtlPosition];
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
header.Bytes[header.Offset + IPv4Fields.TtlPosition] = (byte)value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary> Fetch the code indicating the type of protocol embedded in the IP</summary>
|
||
|
|
/// <seealso cref="IPProtocolType">
|
||
|
|
/// </seealso>
|
||
|
|
public override IPProtocolType Protocol
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
return (IPProtocolType)header.Bytes[header.Offset + IPv4Fields.ProtocolPosition];
|
||
|
|
}
|
||
|
|
|
||
|
|
set
|
||
|
|
{
|
||
|
|
header.Bytes[header.Offset + IPv4Fields.ProtocolPosition] = (byte)value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Calculates the IP checksum, optionally updating the IP checksum header.
|
||
|
|
/// </summary>
|
||
|
|
/// <returns> The calculated IP checksum.
|
||
|
|
/// </returns>
|
||
|
|
public ushort CalculateIPChecksum()
|
||
|
|
{
|
||
|
|
//copy the ip header
|
||
|
|
var theHeader = Header;
|
||
|
|
byte[] ip = new byte[theHeader.Length];
|
||
|
|
Array.Copy(theHeader, ip, theHeader.Length);
|
||
|
|
|
||
|
|
//reset the checksum field (checksum is calculated when this field is zeroed)
|
||
|
|
var theValue = (UInt16)0;
|
||
|
|
EndianBitConverter.Big.CopyBytes(theValue, ip, IPv4Fields.ChecksumPosition);
|
||
|
|
|
||
|
|
//calculate the one's complement sum of the ip header
|
||
|
|
int cs = ChecksumUtils.OnesComplementSum(ip, 0, ip.Length);
|
||
|
|
|
||
|
|
return (ushort)cs;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Update the checksum value
|
||
|
|
/// </summary>
|
||
|
|
public void UpdateIPChecksum ()
|
||
|
|
{
|
||
|
|
this.Checksum = CalculateIPChecksum();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Prepend to the given byte[] origHeader the portion of the IPv6 header used for
|
||
|
|
/// generating an tcp checksum
|
||
|
|
///
|
||
|
|
/// http://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_checksum_using_IPv4
|
||
|
|
/// http://tools.ietf.org/html/rfc793
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="origHeader">
|
||
|
|
/// A <see cref="System.Byte"/>
|
||
|
|
/// </param>
|
||
|
|
/// <returns>
|
||
|
|
/// A <see cref="System.Byte"/>
|
||
|
|
/// </returns>
|
||
|
|
internal override byte[] AttachPseudoIPHeader(byte[] origHeader)
|
||
|
|
{
|
||
|
|
log.DebugFormat("origHeader.Length {0}",
|
||
|
|
origHeader.Length);
|
||
|
|
|
||
|
|
bool odd = origHeader.Length % 2 != 0;
|
||
|
|
int numberOfBytesFromIPHeaderUsedToGenerateChecksum = 12;
|
||
|
|
int headerSize = numberOfBytesFromIPHeaderUsedToGenerateChecksum + origHeader.Length;
|
||
|
|
if (odd)
|
||
|
|
headerSize++;
|
||
|
|
|
||
|
|
byte[] headerForChecksum = new byte[headerSize];
|
||
|
|
// 0-7: ip src+dest addr
|
||
|
|
Array.Copy(header.Bytes,
|
||
|
|
header.Offset + IPv4Fields.SourcePosition,
|
||
|
|
headerForChecksum,
|
||
|
|
0,
|
||
|
|
IPv4Fields.AddressLength * 2);
|
||
|
|
// 8: always zero
|
||
|
|
headerForChecksum[8] = 0;
|
||
|
|
// 9: ip protocol
|
||
|
|
headerForChecksum[9] = (byte)Protocol;
|
||
|
|
// 10-11: header+data length
|
||
|
|
var length = (Int16)origHeader.Length;
|
||
|
|
EndianBitConverter.Big.CopyBytes(length, headerForChecksum,
|
||
|
|
10);
|
||
|
|
|
||
|
|
// prefix the pseudoHeader to the header+data
|
||
|
|
Array.Copy(origHeader, 0,
|
||
|
|
headerForChecksum, numberOfBytesFromIPHeaderUsedToGenerateChecksum,
|
||
|
|
origHeader.Length);
|
||
|
|
|
||
|
|
//if not even length, pad with a zero
|
||
|
|
if (odd)
|
||
|
|
headerForChecksum[headerForChecksum.Length - 1] = 0;
|
||
|
|
|
||
|
|
return headerForChecksum;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Construct an instance by values
|
||
|
|
/// </summary>
|
||
|
|
public IPv4Packet(System.Net.IPAddress SourceAddress,
|
||
|
|
System.Net.IPAddress DestinationAddress)
|
||
|
|
{
|
||
|
|
// allocate memory for this packet
|
||
|
|
int offset = 0;
|
||
|
|
int length = IPv4Fields.HeaderLength;
|
||
|
|
var headerBytes = new byte[length];
|
||
|
|
header = new ByteArraySegment(headerBytes, offset, length);
|
||
|
|
|
||
|
|
// set some default values to make this packet valid
|
||
|
|
PayloadLength = 0;
|
||
|
|
HeaderLength = (HeaderMinimumLength / 4); // NOTE: HeaderLength is the number of 32bit words in the header
|
||
|
|
TimeToLive = DefaultTimeToLive;
|
||
|
|
|
||
|
|
// set instance values
|
||
|
|
this.SourceAddress = SourceAddress;
|
||
|
|
this.DestinationAddress = DestinationAddress;
|
||
|
|
this.Version = ipVersion;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Constructor
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bas">
|
||
|
|
/// A <see cref="ByteArraySegment"/>
|
||
|
|
/// </param>
|
||
|
|
public IPv4Packet(ByteArraySegment bas)
|
||
|
|
{
|
||
|
|
log.Debug("");
|
||
|
|
|
||
|
|
header = new ByteArraySegment(bas);
|
||
|
|
RandomUtils.EnsurePacketLength(this, IPv4Fields.HeaderLength, header.Length);
|
||
|
|
|
||
|
|
// TOS? See http://en.wikipedia.org/wiki/TCP_offload_engine
|
||
|
|
if (TotalLength == 0)
|
||
|
|
{
|
||
|
|
TotalLength = header.Length;
|
||
|
|
}
|
||
|
|
|
||
|
|
// update the header length with the correct value
|
||
|
|
// NOTE: we take care to convert from 32bit words into bytes
|
||
|
|
// NOTE: we do this *after* setting header because we need header to be valid
|
||
|
|
// before we can retrieve the HeaderLength property
|
||
|
|
|
||
|
|
RandomUtils.EnsurePacketLength(this, HeaderLength * 4, header.Length);
|
||
|
|
header.Length = HeaderLength * 4;
|
||
|
|
|
||
|
|
log.DebugFormat("IPv4Packet HeaderLength {0}", HeaderLength);
|
||
|
|
log.DebugFormat("header {0}", header);
|
||
|
|
|
||
|
|
// parse the payload
|
||
|
|
var payload = header.EncapsulatedBytes(PayloadLength);
|
||
|
|
payloadPacketOrData = IpPacket.ParseEncapsulatedBytes(payload,
|
||
|
|
NextHeader,
|
||
|
|
this);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary cref="Packet.ToString(StringOutputType)" />
|
||
|
|
public override string ToString(StringOutputType outputFormat)
|
||
|
|
{
|
||
|
|
var buffer = new StringBuilder();
|
||
|
|
string color = "";
|
||
|
|
string colorEscape = "";
|
||
|
|
|
||
|
|
if(outputFormat == StringOutputType.Colored || outputFormat == StringOutputType.VerboseColored)
|
||
|
|
{
|
||
|
|
color = Color;
|
||
|
|
colorEscape = AnsiEscapeSequences.Reset;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(outputFormat == StringOutputType.Normal || outputFormat == StringOutputType.Colored)
|
||
|
|
{
|
||
|
|
// build the output string
|
||
|
|
buffer.AppendFormat("{0}[IPv4Packet: SourceAddress={2}, DestinationAddress={3}, HeaderLength={4}, Protocol={5}, TimeToLive={6}]{1}",
|
||
|
|
color,
|
||
|
|
colorEscape,
|
||
|
|
SourceAddress,
|
||
|
|
DestinationAddress,
|
||
|
|
HeaderLength,
|
||
|
|
Protocol,
|
||
|
|
TimeToLive);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(outputFormat == StringOutputType.Verbose || outputFormat == StringOutputType.VerboseColored)
|
||
|
|
{
|
||
|
|
// collect the properties and their value
|
||
|
|
Dictionary<string,string> properties = new Dictionary<string,string>();
|
||
|
|
properties.Add("version", Version.ToString());
|
||
|
|
// FIXME: Header length output is incorrect
|
||
|
|
properties.Add("header length", HeaderLength + " bytes");
|
||
|
|
string diffServices = Convert.ToString(DifferentiatedServices, 2).PadLeft(8, '0').Insert(4, " ");
|
||
|
|
properties.Add("differentiated services", "0x" + DifferentiatedServices.ToString("x").PadLeft(2, '0'));
|
||
|
|
properties.Add("", diffServices.Substring(0, 7) + ".. = [" + (DifferentiatedServices >> 2) + "] code point");
|
||
|
|
properties.Add(" ",".... .." + diffServices[6] + ". = [" + diffServices[6] + "] ECN");
|
||
|
|
properties.Add(" ",".... ..." + diffServices[7] + " = [" + diffServices[7] + "] ECE");
|
||
|
|
properties.Add("total length", TotalLength.ToString());
|
||
|
|
properties.Add("identification", "0x" + Id.ToString("x") + " (" + Id + ")");
|
||
|
|
string flags = Convert.ToString(FragmentFlags, 2).PadLeft(8, '0').Substring(5, 3);
|
||
|
|
properties.Add("flags", "0x" + FragmentFlags.ToString("x").PadLeft(2, '0'));
|
||
|
|
properties.Add(" ", flags[0] + ".. = [" + flags[0] + "] reserved");
|
||
|
|
properties.Add(" ", "." + flags[1] + ". = [" + flags[1] + "] don't fragment");
|
||
|
|
properties.Add(" ", ".." + flags[2] + " = [" + flags[2] + "] more fragments");
|
||
|
|
properties.Add("fragment offset", FragmentOffset.ToString());
|
||
|
|
properties.Add("time to live", TimeToLive.ToString());
|
||
|
|
properties.Add("protocol", Protocol.ToString() + " (0x" + Protocol.ToString("x") + ")");
|
||
|
|
properties.Add("header checksum", "0x" + Checksum.ToString("x") + " [" + (ValidChecksum ? "valid" : "invalid") + "]");
|
||
|
|
properties.Add("source", SourceAddress.ToString());
|
||
|
|
properties.Add("destination", DestinationAddress.ToString());
|
||
|
|
|
||
|
|
// calculate the padding needed to right-justify the property names
|
||
|
|
int padLength = Utils.RandomUtils.LongestStringLength(new List<string>(properties.Keys));
|
||
|
|
|
||
|
|
// build the output string
|
||
|
|
buffer.AppendLine("IP: ******* IPv4 - \"Internet Protocol (Version 4)\" - offset=? length=" + TotalPacketLength);
|
||
|
|
buffer.AppendLine("IP:");
|
||
|
|
foreach(var property in properties)
|
||
|
|
{
|
||
|
|
if(property.Key.Trim() != "")
|
||
|
|
{
|
||
|
|
buffer.AppendLine("IP: " + property.Key.PadLeft(padLength) + " = " + property.Value);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
buffer.AppendLine("IP: " + property.Key.PadLeft(padLength) + " " + property.Value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
buffer.AppendLine("IP:");
|
||
|
|
}
|
||
|
|
|
||
|
|
// append the base class output
|
||
|
|
buffer.Append(base.ToString(outputFormat));
|
||
|
|
|
||
|
|
return buffer.ToString();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Generate a random packet
|
||
|
|
/// </summary>
|
||
|
|
/// <returns>
|
||
|
|
/// A <see cref="Packet"/>
|
||
|
|
/// </returns>
|
||
|
|
public static IPv4Packet RandomPacket()
|
||
|
|
{
|
||
|
|
var srcAddress = RandomUtils.GetIPAddress(ipVersion);
|
||
|
|
var dstAddress = RandomUtils.GetIPAddress(ipVersion);
|
||
|
|
return new IPv4Packet(srcAddress, dstAddress);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Update the length and checksum fields
|
||
|
|
/// </summary>
|
||
|
|
public override void UpdateCalculatedValues ()
|
||
|
|
{
|
||
|
|
|
||
|
|
// update the length field based on the length of this packet header
|
||
|
|
// plus the length of all of the packets it contains
|
||
|
|
TotalLength = TotalPacketLength;
|
||
|
|
|
||
|
|
UpdateIPChecksum();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|