/* 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 . */ /* * Copyright 2010 Chris Morgan */ using System; using System.Net; using PacketDotNet.Utils; using MiscUtil.Conversion; namespace PacketDotNet { /// /// Base class for IPv4 and IPv6 packets that exports the common /// functionality that both of these classes has in common /// public abstract class IpPacket : InternetPacket { // 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 /// /// The default time to live value for Ip packets being constructed /// protected int DefaultTimeToLive = 64; /// /// Payload packet, overridden to set the NextHeader/Protocol based /// on the type of payload packet when the payload packet is set /// public override Packet PayloadPacket { get { return base.PayloadPacket; } set { base.PayloadPacket = value; // set NextHeader (Protocol) based on the type of this packet if(value is TcpPacket) { NextHeader = IPProtocolType.TCP; } else if(value is UdpPacket) { NextHeader = IPProtocolType.UDP; } else if(value is ICMPv6Packet) { NextHeader = IPProtocolType.ICMPV6; } else if(value is ICMPv4Packet) { NextHeader = IPProtocolType.ICMP; } else if(value is IGMPv2Packet) { NextHeader = IPProtocolType.IGMP; } else // NOTE: new checks go here { NextHeader = IPProtocolType.NONE; } // update the payload length based on the size // of the payload packet var newPayloadLength = (ushort)base.PayloadPacket.Bytes.Length; log.DebugFormat("newPayloadLength {0}", newPayloadLength); PayloadLength = newPayloadLength; } } /// /// The destination address /// public abstract IPAddress DestinationAddress { get; set; } /// /// The source address /// public abstract IPAddress SourceAddress { get; set; } /// /// The IP version /// public abstract IpVersion Version { get; set; } /// /// The protocol of the ip packet's payload /// Named 'Protocol' in IPv4 /// Named 'NextHeader' in IPv6' /// public abstract IPProtocolType Protocol { get; set; } /// /// The protocol of the ip packet's payload /// Included along side Protocol for user convienence /// public virtual IPProtocolType NextHeader { get { return Protocol; } set { Protocol = value; } } /// /// The number of hops remaining before this packet is discarded /// Named 'TimeToLive' in IPv4 /// Named 'HopLimit' in IPv6 /// public abstract int TimeToLive { get; set; } /// /// The number of hops remaining for this packet /// Included along side of TimeToLive for user convienence /// public virtual int HopLimit { get { return TimeToLive; } set { TimeToLive = value; } } /// /// ipv4 header length field, calculated for ipv6 packets /// NOTE: This field is the number of 32bit words in the ip header, /// ie. the number of bytes is 4x this value /// public abstract int HeaderLength { get; set; } /// /// ipv4 total number of bytes in the ipv4 header + payload, /// ipv6 PayloadLength + IPv6Fields.HeaderLength /// public abstract int TotalLength { get; set; } /// /// ipv6 payload length in bytes, /// calculate from ipv4.TotalLength - (ipv4.HeaderLength * 4) /// public abstract ushort PayloadLength { get; set; } /// /// Adds a pseudo ip header to a given packet. Used to generate the full /// byte array required to generate a udp or tcp checksum. /// /// /// A /// /// /// A /// internal abstract byte[] AttachPseudoIPHeader(byte[] origHeader); /// /// Convert an ip address from a byte[] /// /// /// A /// /// /// A /// /// /// A /// /// /// A /// 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[IPv4Fields.AddressLength]; } else if(ipType == System.Net.Sockets.AddressFamily.InterNetworkV6) { address = new byte[IPv6Fields.AddressLength]; } else { throw new System.InvalidOperationException("ipType " + ipType + " unknown"); } System.Array.Copy(bytes, fieldOffset, address, 0, address.Length); return new System.Net.IPAddress(address); } /// /// IpPacket constructor /// public IpPacket() {} /// /// Called by IPv4 and IPv6 packets to parse their packet payload /// /// /// A /// /// /// A /// /// /// A /// /// /// A /// internal static PacketOrByteArraySegment ParseEncapsulatedBytes(ByteArraySegment payload, IPProtocolType ProtocolType, Packet ParentPacket) { log.DebugFormat("payload: {0}, ParentPacket.GetType() {1}", payload, ParentPacket.GetType()); var payloadPacketOrData = new PacketOrByteArraySegment(); switch(ProtocolType) { case IPProtocolType.TCP: payloadPacketOrData.ThePacket = new TcpPacket(payload, ParentPacket); break; case IPProtocolType.UDP: payloadPacketOrData.ThePacket = new UdpPacket(payload, ParentPacket); break; case IPProtocolType.ICMP: payloadPacketOrData.ThePacket = new ICMPv4Packet(payload, ParentPacket); break; case IPProtocolType.ICMPV6: payloadPacketOrData.ThePacket = new ICMPv6Packet(payload, ParentPacket); break; case IPProtocolType.IGMP: payloadPacketOrData.ThePacket = new IGMPv2Packet(payload, ParentPacket); break; // NOTE: new payload parsing entries go here default: payloadPacketOrData.TheByteArraySegment = payload; break; } return payloadPacketOrData; } /// /// Returns the IpPacket inside of the Packet p or null if /// there is no encapsulated packet /// /// /// A /// /// /// A /// [Obsolete("Use Packet.Extract() instead")] public static IpPacket GetEncapsulated(Packet p) { log.Debug(""); if(p is InternetLinkLayerPacket) { var payload = InternetLinkLayerPacket.GetInnerPayload((InternetLinkLayerPacket)p); if(payload is IpPacket) { return (IpPacket)payload; } } return null; } /// /// Generate a random packet of a specific ip version /// /// /// A /// /// /// A /// public static IpPacket RandomPacket(IpVersion version) { log.DebugFormat("version {0}", version); if(version == IpVersion.IPv4) { return IPv4Packet.RandomPacket(); } else if(version == IpVersion.IPv6) { return IPv6Packet.RandomPacket(); } else { throw new System.InvalidOperationException("Unknown version of " + version); } } } }