/* 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 2011 Chris Morgan */ using System; using System.Collections.Generic; using System.Net.NetworkInformation; using System.Text; using MiscUtil.Conversion; using PacketDotNet.Utils; namespace PacketDotNet { /// /// An ARP protocol packet. /// public class ARPPacket : InternetLinkLayerPacket { // 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 /// /// Also known as HardwareType /// virtual public LinkLayers HardwareAddressType { get { return (LinkLayers)EndianBitConverter.Big.ToUInt16(header.Bytes, header.Offset + ARPFields.HardwareAddressTypePosition); } set { var theValue = (UInt16)value; EndianBitConverter.Big.CopyBytes(theValue, header.Bytes, header.Offset + ARPFields.HardwareAddressTypePosition); } } /// /// Also known as ProtocolType /// virtual public EthernetPacketType ProtocolAddressType { get { return (EthernetPacketType)EndianBitConverter.Big.ToUInt16(header.Bytes, header.Offset + ARPFields.ProtocolAddressTypePosition); } set { var theValue = (UInt16)value; EndianBitConverter.Big.CopyBytes(theValue, header.Bytes, header.Offset + ARPFields.ProtocolAddressTypePosition); } } /// /// Hardware address length field /// virtual public int HardwareAddressLength { get { return header.Bytes[header.Offset + ARPFields.HardwareAddressLengthPosition]; } set { header.Bytes[header.Offset + ARPFields.HardwareAddressLengthPosition] = (byte)value; } } /// /// Protocol address length field /// virtual public int ProtocolAddressLength { get { return header.Bytes[header.Offset + ARPFields.ProtocolAddressLengthPosition]; } set { header.Bytes[header.Offset + ARPFields.ProtocolAddressLengthPosition] = (byte)value; } } /// Fetch the operation code. /// Usually one of ARPFields.{ARP_OP_REQ_CODE, ARP_OP_REP_CODE}. /// /// Sets the operation code. /// Usually one of ARPFields.{ARP_OP_REQ_CODE, ARP_OP_REP_CODE}. /// virtual public ARPOperation Operation { get { return (ARPOperation)EndianBitConverter.Big.ToInt16(header.Bytes, header.Offset + ARPFields.OperationPosition); } set { var theValue = (Int16)value; EndianBitConverter.Big.CopyBytes(theValue, header.Bytes, header.Offset + ARPFields.OperationPosition); } } /// /// Upper layer protocol address of the sender, arp is used for IPv4, IPv6 uses NDP /// virtual public System.Net.IPAddress SenderProtocolAddress { get { return IpPacket.GetIPAddress(System.Net.Sockets.AddressFamily.InterNetwork, header.Offset + ARPFields.SenderProtocolAddressPosition, header.Bytes); } set { // check that the address family is ipv4 if (value.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) throw new System.InvalidOperationException("Family != IPv4, ARP is used for IPv4, NDP for IPv6"); byte[] address = value.GetAddressBytes(); Array.Copy(address, 0, header.Bytes, header.Offset + ARPFields.SenderProtocolAddressPosition, address.Length); } } /// /// Upper layer protocol address of the target, arp is used for IPv4, IPv6 uses NDP /// virtual public System.Net.IPAddress TargetProtocolAddress { get { return IpPacket.GetIPAddress(System.Net.Sockets.AddressFamily.InterNetwork, header.Offset + ARPFields.TargetProtocolAddressPosition, header.Bytes); } set { // check that the address family is ipv4 if (value.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) throw new System.InvalidOperationException("Family != IPv4, ARP is used for IPv4, NDP for IPv6"); byte[] address = value.GetAddressBytes(); Array.Copy(address, 0, header.Bytes, header.Offset + ARPFields.TargetProtocolAddressPosition, address.Length); } } /// /// Sender hardware address, usually an ethernet mac address /// public virtual PhysicalAddress SenderHardwareAddress { get { //FIXME: this code is broken because it assumes that the address position is // a fixed position byte[] hwAddress = new byte[HardwareAddressLength]; Array.Copy(header.Bytes, header.Offset + ARPFields.SenderHardwareAddressPosition, hwAddress, 0, hwAddress.Length); return new PhysicalAddress(hwAddress); } set { byte[] hwAddress = value.GetAddressBytes(); // for now we only support ethernet addresses even though the arp protocol // makes provisions for varying length addresses if(hwAddress.Length != EthernetFields.MacAddressLength) { throw new System.InvalidOperationException("expected physical address length of " + EthernetFields.MacAddressLength + " but it was " + hwAddress.Length); } Array.Copy(hwAddress, 0, header.Bytes, header.Offset + ARPFields.SenderHardwareAddressPosition, hwAddress.Length); } } /// /// Target hardware address, usually an ethernet mac address /// public virtual PhysicalAddress TargetHardwareAddress { get { //FIXME: this code is broken because it assumes that the address position is // a fixed position byte[] hwAddress = new byte[HardwareAddressLength]; Array.Copy(header.Bytes, header.Offset + ARPFields.TargetHardwareAddressPosition, hwAddress, 0, hwAddress.Length); return new PhysicalAddress(hwAddress); } set { byte[] hwAddress = value.GetAddressBytes(); // for now we only support ethernet addresses even though the arp protocol // makes provisions for varying length addresses if(hwAddress.Length != EthernetFields.MacAddressLength) { throw new System.InvalidOperationException("expected physical address length of " + EthernetFields.MacAddressLength + " but it was " + hwAddress.Length); } Array.Copy(hwAddress, 0, header.Bytes, header.Offset + ARPFields.TargetHardwareAddressPosition, hwAddress.Length); } } /// Fetch ascii escape sequence of the color associated with this packet type. override public System.String Color { get { return AnsiEscapeSequences.Purple; } } /// /// Create an ARPPacket from values /// /// /// A /// /// /// A /// /// /// A /// /// /// A /// /// /// A /// public ARPPacket(ARPOperation Operation, PhysicalAddress TargetHardwareAddress, System.Net.IPAddress TargetProtocolAddress, PhysicalAddress SenderHardwareAddress, System.Net.IPAddress SenderProtocolAddress) { log.Debug(""); // allocate memory for this packet int offset = 0; int length = ARPFields.HeaderLength; var headerBytes = new byte[length]; header = new ByteArraySegment(headerBytes, offset, length); this.Operation = Operation; this.TargetHardwareAddress = TargetHardwareAddress; this.TargetProtocolAddress = TargetProtocolAddress; this.SenderHardwareAddress = SenderHardwareAddress; this.SenderProtocolAddress = SenderProtocolAddress; // set some internal properties to fully define the packet this.HardwareAddressType = LinkLayers.Ethernet; this.HardwareAddressLength = EthernetFields.MacAddressLength; this.ProtocolAddressType = EthernetPacketType.IpV4; this.ProtocolAddressLength = IPv4Fields.AddressLength; } /// /// Constructor /// /// /// A /// public ARPPacket(ByteArraySegment bas) { header = new ByteArraySegment(bas); RandomUtils.EnsurePacketLength(this, ARPFields.HeaderLength, header.Length); header.Length = ARPFields.HeaderLength; // NOTE: no need to set the payloadPacketOrData field, arp packets have // no payload } /// 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}[ARPPacket: Operation={2}, SenderHardwareAddress={3}, TargetHardwareAddress={4}, SenderProtocolAddress={5}, TargetProtocolAddress={6}]{1}", color, colorEscape, Operation, HexPrinter.PrintMACAddress(SenderHardwareAddress), HexPrinter.PrintMACAddress(TargetHardwareAddress), SenderProtocolAddress, TargetProtocolAddress); } if(outputFormat == StringOutputType.Verbose || outputFormat == StringOutputType.VerboseColored) { // collect the properties and their value Dictionary properties = new Dictionary(); properties.Add("hardware type", HardwareAddressType.ToString() + " (0x" + HardwareAddressType.ToString("x") + ")"); properties.Add("protocol type", ProtocolAddressType.ToString() + " (0x" + ProtocolAddressType.ToString("x") + ")"); properties.Add("operation", Operation.ToString() + " (0x" + Operation.ToString("x") + ")"); properties.Add("source hardware address", HexPrinter.PrintMACAddress(SenderHardwareAddress)); properties.Add("destination hardware address", HexPrinter.PrintMACAddress(TargetHardwareAddress)); properties.Add("source protocol address", SenderProtocolAddress.ToString()); properties.Add("destination protocol address", TargetProtocolAddress.ToString()); // calculate the padding needed to right-justify the property names int padLength = Utils.RandomUtils.LongestStringLength(new List(properties.Keys)); // build the output string buffer.AppendLine("ARP: ******* ARP - \"Address Resolution Protocol\" - offset=? length=" + TotalPacketLength); buffer.AppendLine("ARP:"); foreach(var property in properties) { buffer.AppendLine("ARP: " + property.Key.PadLeft(padLength) + " = " + property.Value); } buffer.AppendLine("ARP:"); } // append the base string output buffer.Append(base.ToString(outputFormat)); return buffer.ToString(); } /// /// Returns the encapsulated ARPPacket of the Packet p or null if /// there is no encapsulated packet /// /// /// A /// /// /// A /// [Obsolete("Use Packet.Extract() instead")] public static ARPPacket GetEncapsulated(Packet p) { if(p is InternetLinkLayerPacket) { var payload = InternetLinkLayerPacket.GetInnerPayload((InternetLinkLayerPacket)p); if(payload is ARPPacket) { return (ARPPacket)payload; } } return null; } } }