/// ************************************************************************
/// 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 System.Net.NetworkInformation;
using SharpPcap.Packets.Util;
using ArrayHelper = SharpPcap.Packets.Util.ArrayHelper;
using Timeval = SharpPcap.Packets.Util.Timeval;
namespace SharpPcap.Packets
{
/// An ethernet packet.
///
/// Contains link-level header and data payload encapsulated by an ethernet
/// packet.
///
/// There are currently two subclasses. IP and ARP protocols are supported.
/// IPPacket extends with ip header and data information.
/// ARPPacket extends with hardware and protocol addresses.
///
///
[Serializable]
public class EthernetPacket : Packet, EthernetFields
{
/// Code constants for well-defined ethernet protocols.
///
/// Taken from linux/if_ether.h and tcpdump/ethertype.h
///
///
public struct EtherType
{
/// IP protocol.
public const int IP = 0x0800;
/// Address resolution protocol.
public const int ARP = 0x0806;
/// Reverse address resolution protocol.
public const int RARP = 0x8035;
/// Ethernet Loopback packet
public const int LOOP = 0x0060;
/// Ethernet Echo packet
public const int ECHO = 0x0200;
/// Xerox PUP packet
public const int PUP = 0x0400;
/// CCITT X.25
public const int X25 = 0x0805;
/// G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ]
public const int BPQ = 0x08FF;
/// DEC Assigned proto
public const int DEC = 0x6000;
/// DEC DNA Dump/Load
public const int DNA_DL = 0x6001;
/// DEC DNA Remote Console
public const int DNA_RC = 0x6002;
/// DEC DNA Routing
public const int DNA_RT = 0x6003;
/// DEC LAT
public const int LAT = 0x6004;
/// DEC Diagnostics
public const int DIAG = 0x6005;
/// DEC Customer use
public const int CUST = 0x6006;
/// DEC Systems Comms Arch
public const int SCA = 0x6007;
/// Appletalk DDP
public const int ATALK = 0x809B;
/// Appletalk AARP
public const int AARP = 0x80F3;
/// IPX over DIX
public const int IPX = 0x8137;
/// IPv6 over bluebook
public const int IPV6 = 0x86DD;
/// Dummy type for 802.3 frames
public const int N802_3 = 0x0001;
/// Dummy protocol id for AX.25
public const int AX25 = 0x0002;
/// Every packet.
public const int ALL = 0x0003;
/// 802.2 frames
public const int N802_2 = 0x0004;
/// Internal only
public const int SNAP = 0x0005;
/// DEC DDCMP: Internal only
public const int DDCMP = 0x0006;
/// Dummy type for WAN PPP frames
public const int WAN_PPP = 0x0007;
/// Dummy type for PPP MP frames
public const int PPP_MP = 0x0008;
/// Localtalk pseudo type
public const int LOCALTALK = 0x0009;
/// Dummy type for Atalk over PPP
public const int PPPTALK = 0x0010;
/// 802.2 frames
public const int TR_802_2 = 0x0011;
/// Mobitex (kaz@cafe.net)
public const int MOBITEX = 0x0015;
/// Card specific control frames
public const int CONTROL = 0x0016;
/// Linux/IR
public const int IRDA = 0x0017;
// others not yet documented..
public const int NS = 0x0600;
public const int SPRITE = 0x0500;
public const int TRAIL = 0x1000;
public const int LANBRIDGE = 0x8038;
public const int DECDNS = 0x803c;
public const int DECDTS = 0x803e;
public const int VEXP = 0x805b;
public const int VPROD = 0x805c;
public const int N8021Q = 0x8100;
public const int PPP = 0x880b;
public const int PPPOED = 0x8863;
public const int PPPOES = 0x8864;
public const int LOOPBACK = 0x9000;
// spanning tree bridge protocol
public const int STBPDU = 0x0026;
// intel adapter fault tolerance heartbeats
public const int INFTH = 0x886d;
/// Ethernet protocol mask.
public const int MASK = 0xffff;
}
/// Extract the protocol type field from packet data.
///
/// The type field indicates what type of data is contained in the
/// packet's data block.
///
/// packet bytes.
///
/// the ethernet type code. i.e. 0x800 signifies IP datagram.
///
public static int extractProtocol(byte[] packetBytes)
{
// convert the bytes that contain the type code into a value..
return packetBytes[EthernetFields_Fields.ETH_CODE_POS] << 8 | packetBytes[EthernetFields_Fields.ETH_CODE_POS + 1];
}
/// Fetch the ethernet header length in bytes.
virtual public int EthernetHeaderLength
{
get
{
return _ethernetHeaderLength;
}
}
/// Fetch the packet ethernet header length.
virtual public int HeaderLength
{
get
{
return EthernetHeaderLength;
}
}
/// Fetch the ethernet header as a byte array.
virtual public byte[] EthernetHeader
{
get
{
return PacketEncoding.extractHeader(0, EthernetHeaderLength, _bytes);
}
}
/// Fetch the ethernet header as a byte array.
override public byte[] Header
{
get
{
return EthernetHeader;
}
}
/// Fetch the ethernet data as a byte array.
virtual public byte[] EthernetData
{
get
{
return PacketEncoding.extractData(0, EthernetHeaderLength, _bytes);
}
}
/// Fetch the ethernet protocol.
/// Sets the ethernet protocol.
virtual public int EthernetProtocol
{
get
{
return ArrayHelper.extractInteger(_bytes, EthernetFields_Fields.ETH_CODE_POS, EthernetFields_Fields.ETH_CODE_LEN);
}
set
{
ArrayHelper.insertLong(_bytes, value, EthernetFields_Fields.ETH_CODE_POS, EthernetFields_Fields.ETH_CODE_LEN);
}
}
///
/// should be overriden by upper classes
///
public virtual void OnOffsetChanged()
{
if(PcapHeader!=null)
{
PcapHeader = new PcapHeader(PcapHeader.Seconds,
PcapHeader.MicroSeconds,
(uint)_bytes.Length,
(uint)_bytes.Length);
}
}
/// Fetch the timeval containing the time the packet arrived on the
/// device where it was captured.
///
override public Timeval Timeval
{
get
{
return _timeval;
}
}
/// Fetch ascii escape sequence of the color associated with this packet type.
override public System.String Color
{
get
{
return AnsiEscapeSequences_Fields.DARK_GRAY;
}
}
override public byte[] Bytes
{
get
{
return _bytes;
}
protected set
{
_bytes = value;
}
}
// store the data here, all subclasses can offset into this
private byte[] _bytes;
// offset from beginning of byte array where the data payload
// (i.e. IP packet) starts. The size of the ethernet frame header.
protected internal int _ethOffset;
// time that the packet was captured off the wire
protected internal Timeval _timeval;
/// Construct a new ethernet packet.
///
/// For the purpose of jpcap, when the type of ethernet packet is
/// recognized as a protocol for which a class exists network library,
/// then a more specific class like IPPacket or ARPPacket is instantiated.
/// The subclass can always be cast into a more generic form.
///
public EthernetPacket(int lLen, byte[] bytes)
{
_bytes = bytes;
_ethernetHeaderLength = lLen;
_ethOffset = lLen;
}
/// Construct a new ethernet packet, including the capture time.
public EthernetPacket(int lLen, byte[] bytes, Timeval tv)
: this(lLen, bytes)
{
this._timeval = tv;
}
// set in constructor
private int _ethernetHeaderLength;
/// Fetch the ethernet data as a byte array.
public override byte[] Data
{
get
{
return EthernetData;
}
}
private static int macAddressLength = 6;
/// Fetch the MAC address of the host where the packet originated from.
public virtual PhysicalAddress SourceHwAddress
{
get
{
byte[] hwAddress = new byte[macAddressLength];
Array.Copy(_bytes, EthernetFields_Fields.ETH_SRC_POS,
hwAddress, 0, hwAddress.Length);
return new PhysicalAddress(hwAddress);
}
set
{
byte[] hwAddress = value.GetAddressBytes();
if(hwAddress.Length != macAddressLength)
{
throw new System.InvalidOperationException("address length " + hwAddress.Length
+ " not equal to the expected length of "
+ macAddressLength);
}
Array.Copy(hwAddress, 0, _bytes, EthernetFields_Fields.ETH_SRC_POS,
hwAddress.Length);
}
}
/// Fetch the MAC address of the host where the packet originated from.
public virtual PhysicalAddress DestinationHwAddress
{
get
{
byte[] hwAddress = new byte[macAddressLength];
Array.Copy(_bytes, EthernetFields_Fields.ETH_DST_POS,
hwAddress, 0, hwAddress.Length);
return new PhysicalAddress(hwAddress);
}
set
{
byte[] hwAddress = value.GetAddressBytes();
if(hwAddress.Length != macAddressLength)
{
throw new System.InvalidOperationException("address length " + hwAddress.Length
+ " not equal to the expected length of "
+ macAddressLength);
}
Array.Copy(hwAddress, 0, _bytes, EthernetFields_Fields.ETH_DST_POS,
hwAddress.Length);
}
}
/// Convert this ethernet packet to a readable string.
public override System.String ToString()
{
return ToColoredString(false);
}
/// Generate string with contents describing this ethernet 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();
buffer.Append('[');
if (colored)
buffer.Append(Color);
buffer.Append("EthernetPacket");
if (colored)
buffer.Append(AnsiEscapeSequences_Fields.RESET);
buffer.Append(": ");
buffer.Append(SourceHwAddress + " -> " + DestinationHwAddress);
buffer.Append(" proto=0x" + System.Convert.ToString(EthernetProtocol, 16));
buffer.Append(" l=" + EthernetHeaderLength); // + "," + data.length);
buffer.Append(']');
// append the base output
buffer.Append(base.ToColoredString(colored));
return buffer.ToString();
}
/// Convert this IP packet to a more verbose string.
public override System.String ToColoredVerboseString(bool colored)
{
//TODO: just output the colored output for now
return ToColoredString(colored);
}
}
}