/// ************************************************************************ /// Copyright (C) 2001, Patrick Charles and Jonas Lehmann * /// Distributed under the Mozilla Public License * /// http://www.mozilla.org/NPL/MPL-1.1.txt * /// ************************************************************************* /// using System; using AnsiEscapeSequences_Fields = SharpPcap.Packets.Util.AnsiEscapeSequences_Fields; using ArrayHelper = SharpPcap.Packets.Util.ArrayHelper; using Timeval = SharpPcap.Packets.Util.Timeval; namespace SharpPcap.Packets { /// An IP protocol packet. ///

/// Extends an ethernet packet, adding IP header information and an IP /// data payload. /// ///

[Serializable] public class IPPacket : EthernetPacket { /// Code constants for internet protocol versions. /// /// public enum IPVersions { /// Internet protocol version 4. IPv4 = 4, /// Internet protocol version 6. IPv6 = 6 } public IPv4Packet ipv4; public IPv6Packet ipv6; // offset from beginning of byte array where IP header ends (i.e., // size of ethernet frame header and IP header protected internal int _ipOffset; /// Create a new IP packet. public IPPacket(int lLen, byte[] bytes, IPVersions version) : base(lLen, bytes) { IPVersion = version; } /// Create a new IP packet. public IPPacket(int lLen, byte[] bytes) : base(lLen, bytes) { InitIPPacket(IPVersion); } /// Create a new IP packet. public IPPacket(int lLen, byte[] bytes, Timeval tv) : this(lLen, bytes) { this._timeval = tv; } /// Create a new IP packet. public IPPacket(int lLen, byte[] bytes, Timeval tv, IPVersions version) : this(lLen, bytes, version) { this._timeval = tv; } private void InitIPPacket(IPVersions version) { ipv4 = null; ipv6 = null; if (version == IPVersions.IPv4) { ipv4 = new IPv4Packet(EthernetHeaderLength, Bytes); _ipOffset = _ethOffset + IPv4Fields_Fields.IP_HEADER_LEN; } else if (version == IPVersions.IPv6) { ipv6 = new IPv6Packet(EthernetHeaderLength, Bytes); _ipOffset = _ethOffset + IPv6Fields_Fields.IPv6_HEADER_LEN; } else { //lame default _ipOffset = _ethOffset; } } public override byte[] Bytes { get { return base.Bytes; } protected set { base.Bytes = value; InitIPPacket(IPVersion); } } /// /// should be overriden by upper classes /// public override void OnOffsetChanged() { base.OnOffsetChanged(); InitIPPacket(IPVersion); } /// Get the IP version code. virtual public IPVersions IPVersion { get { return (IPVersions)((ArrayHelper.extractInteger(Bytes, _ethOffset + IPv4Fields_Fields.IP_VER_POS, IPv4Fields_Fields.IP_VER_LEN) >> 4) & 0xf); } set { Bytes[_ethOffset + IPv4Fields_Fields.IP_VER_POS] &= (byte)(0x0f); Bytes[_ethOffset + IPv4Fields_Fields.IP_VER_POS] |= (byte)((((int)value << 4) & 0xf0)); //version had changed, reinit packet InitIPPacket(IPVersion); } } /// Fetch ascii escape sequence of the color associated with this packet type. override public System.String Color { get { return AnsiEscapeSequences_Fields.WHITE; } } /// Returns the payload length of the packet public int IPPayloadLength { get { if(ipv4 != null) return ipv4.IPPayloadLength; else if(ipv6 != null) return ipv6.IPPayloadLength; else throw new System.InvalidOperationException(); } set { if (ipv4 != null) ipv4.IPTotalLength = value + IPv4Fields_Fields.IP_HEADER_LEN; else if (ipv6 != null) ipv6.IPPayloadLength = value; else throw new System.InvalidOperationException(); } } /// Convert this IP packet to a readable string. public override System.String ToString() { return ToColoredString(false); } /// Generate string with contents describing this IP packet. /// whether or not the string should contain ansi /// color escape sequences. /// public override System.String ToColoredString(bool colored) { System.Text.StringBuilder buffer = new System.Text.StringBuilder(); if(ipv4 != null) buffer.Append(ipv4.ToColoredString(colored)); else if (ipv6 != null) buffer.Append(ipv6.ToColoredString(colored)); else { //unknown version buffer.Append('['); if (colored) buffer.Append(Color); buffer.Append("IPPacket (Unknown Version)"); if (colored) buffer.Append(AnsiEscapeSequences_Fields.RESET); } return buffer.ToString(); } /// Convert this IP packet to a more verbose string. public override System.String ToColoredVerboseString(bool colored) { System.Text.StringBuilder buffer = new System.Text.StringBuilder(); buffer.Append('['); if (colored) buffer.Append(Color); buffer.Append("IPPacket"); if (colored) buffer.Append(AnsiEscapeSequences_Fields.RESET); if(ipv4 != null) buffer.Append(ipv4.ToColoredVerboseString(colored)); else if(ipv6 != null) buffer.Append(ipv6.ToColoredVerboseString(colored)); return buffer.ToString(); } public static System.Net.IPAddress GetIPAddress(System.Net.Sockets.AddressFamily ipType, int fieldOffset, byte[] bytes) { byte[] address; if(ipType == System.Net.Sockets.AddressFamily.InterNetwork) // ipv4 { address = new byte[4]; } else if(ipType == System.Net.Sockets.AddressFamily.InterNetworkV6) { address = new byte[16]; } else { throw new System.InvalidOperationException("ipType " + ipType + " unknown"); } System.Array.Copy(bytes, fieldOffset, address, 0, address.Length); return new System.Net.IPAddress(address); } // some convience mapping methods since there are fields that match exactly between // ipv4 and ipv6 /// Fetch the IP address of the host where the packet originated from. virtual public System.Net.IPAddress SourceAddress { get { if(ipv4 != null) { return ipv4.SourceAddress; } else if(ipv6 != null) { return ipv6.SourceAddress; } else { throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } set { if(IPVersion == IPVersions.IPv4) { ipv4.SourceAddress = value; } else if(IPVersion == IPVersions.IPv6) { ipv6.SourceAddress = value; } else { throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } } /// Fetch the IP address of the host where the packet is destined. virtual public System.Net.IPAddress DestinationAddress { get { if(ipv4 != null) { return ipv4.DestinationAddress; } else if(ipv6 != null) { return ipv6.DestinationAddress; } else { throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } set { if(ipv4 != null) { ipv4.DestinationAddress = value; } else if(ipv6 != null) { ipv6.DestinationAddress = value; } else { throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } } // HopLimit(IPv6) and TimeToLive(IPv4) have the same meaning public int HopLimit { get { return TimeToLive; } set { TimeToLive = value; } } public int TimeToLive { get { if(ipv4 != null) return ipv4.TimeToLive; else if(ipv6 != null) return ipv6.HopLimit; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } set { if(ipv4 != null) ipv4.TimeToLive = value; else if(ipv6 != null) ipv6.HopLimit = value; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } // NextHeader(IPv6) and IPProtocol(IPv4) have the same meaning public IPProtocol.IPProtocolType NextHeader { get { return IPProtocol; } set { IPProtocol = value; } } public IPProtocol.IPProtocolType IPProtocol { get { if(ipv4 != null) return ipv4.IPProtocol; else if(ipv6 != null) return ipv6.NextHeader; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } set { if(ipv4 != null) ipv4.IPProtocol = value; else if(ipv6 != null) ipv6.NextHeader = value; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } /// Fetch the header checksum. public virtual int GetTransportLayerChecksum(int pos) { return ArrayHelper.extractInteger(Bytes, pos, 2); } protected internal virtual void SetTransportLayerChecksum(int cs, int csPos) { SetChecksum(cs, _ipOffset + csPos); } public virtual bool IsValidTransportLayerChecksum(bool pseudoIPHeader) { byte[] upperLayer = IPData; if (pseudoIPHeader) upperLayer = AttachPseudoIPHeader(upperLayer); int onesSum = ChecksumUtils.OnesSum(upperLayer); return (onesSum == 0xffff); } /// Sets the IP header checksum. protected internal virtual void SetChecksum(int cs, int checkSumOffset) { ArrayHelper.insertLong(Bytes, cs, checkSumOffset, 2); } /// /// Returns the IP data. /// virtual public byte[] IPData { get { if (ipv4 != null) return ipv4.IPData; else if (ipv6 != null) return ipv6.IPData; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } protected internal virtual byte[] AttachPseudoIPHeader(byte[] origHeader) { if (ipv4 != null) return ipv4.AttachPseudoIPHeader(origHeader); else if (ipv6 != null) return ipv6.AttachPseudoIPHeader(origHeader); else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } public int ComputeTransportLayerChecksum(int checksumOffset, bool update, bool pseudoIPHeader) { // copy the tcp section with data byte[] dataToChecksum = IPData; // reset the checksum field (checksum is calculated when this field is // zeroed) ArrayHelper.insertLong(dataToChecksum, 0, checksumOffset, 2); if (pseudoIPHeader) dataToChecksum = AttachPseudoIPHeader(dataToChecksum); // compute the one's complement sum of the tcp header int cs = ChecksumUtils.OnesComplementSum(dataToChecksum); if (update) { SetTransportLayerChecksum(cs, checksumOffset); } return cs; } /// Same as computeIPChecksum(true); /// /// /// The computed IP checksum value. /// public int ComputeIPChecksum() { return ComputeIPChecksum(true); } /// Computes the IP checksum, optionally updating the IP checksum header. /// /// /// Specifies whether or not to update the IP checksum /// header after computing the checksum. A value of true indicates /// the header should be updated, a value of false indicates it /// should not be updated. /// /// The computed IP checksum. /// public int ComputeIPChecksum(bool update) { if (ipv4 != null) return ipv4.ComputeIPChecksum(update); else if (ipv6 != null) return 0; // ipv6 packets don't contain a checksum else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } /// Check if the IP packet is valid, checksum-wise. virtual public bool ValidChecksum { get { return ValidIPChecksum; } } /// Check if the IP packet is valid, checksum-wise. virtual public bool ValidIPChecksum { get { if (ipv4 != null) return ipv4.ValidIPChecksum; else if (ipv6 != null) return true; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } /// Fetch the header a byte array. virtual public byte[] IPHeader { get { if(ipv4 != null) return ipv4.IPHeader; else if(ipv6 != null) return ipv6.IPv6Header; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } /// Fetch the UDP header as a byte array. override public byte[] Header { get { return IPHeader; } } /// Fetch the IP header length in bytes. /// Sets 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. /// /// /// The length of the IP header in 32-bit words. /// virtual public int IPHeaderLength { get { if (ipv4 != null) return ipv4.IPHeaderLength; else if (ipv6 != null) return IPv6Fields_Fields.IPv6_HEADER_LEN; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } set { if (ipv4 != null) ipv4.IPHeaderLength = value; else if (ipv6 != null) throw new System.InvalidOperationException("can't set IPHeaderLength on ipv6 packet"); else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } /// Fetches the packet header length. override public int HeaderLength { get { return IPHeaderLength; } } /// Fetch the IP length in bytes. public virtual int IPTotalLength { get { if (ipv4 != null) return ipv4.IPTotalLength; else if (ipv6 != null) return IPv6Fields_Fields.IPv6_HEADER_LEN + ipv6.IPPayloadLength; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } set { if (ipv4 != null) ipv4.IPTotalLength = value; else if (ipv6 != null) ipv6.IPPayloadLength = value - IPv6Fields_Fields.IPv6_HEADER_LEN; else throw new System.InvalidOperationException("ipv4 and ipv6 are both null"); } } } }