diff --git a/PacketDotNet/EthernetPacket.cs b/PacketDotNet/EthernetPacket.cs index f4b2e434..3956334f 100644 --- a/PacketDotNet/EthernetPacket.cs +++ b/PacketDotNet/EthernetPacket.cs @@ -236,6 +236,9 @@ internal static PacketOrByteArraySegment ParseEncapsulatedBytes(ByteArraySegment case EthernetPacketType.WakeOnLan: payloadPacketOrData.ThePacket = new WakeOnLanPacket(payload); break; + case EthernetPacketType.VLanTaggedFrame: + payloadPacketOrData.ThePacket = new Ieee8021QPacket(payload); + break; default: // consider the sub-packet to be a byte array payloadPacketOrData.TheByteArraySegment = payload; break; diff --git a/PacketDotNet/Ieee8021QFields.cs b/PacketDotNet/Ieee8021QFields.cs new file mode 100644 index 00000000..00d4a01c --- /dev/null +++ b/PacketDotNet/Ieee8021QFields.cs @@ -0,0 +1,42 @@ +/* +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 2013 Chris Morgan + */ +namespace PacketDotNet +{ + /// 802.1Q fields + public class Ieee8021QFields + { + /// Length of the ethertype value in bytes. + public readonly static int TypeLength = 2; + /// Length of the tag control information in bytes. + public readonly static int TagControlInformationLength = 2; + /// Position of the tag control information + public readonly static int TagControlInformationPosition = 0; + /// Position of the type field + public readonly static int TypePosition; + /// Length in bytes of a Ieee8021Q header. + public readonly static int HeaderLength; // 4 + + static Ieee8021QFields() + { + TypePosition = TagControlInformationPosition + TagControlInformationLength; + HeaderLength = TypePosition + TypeLength; + } + } +} diff --git a/PacketDotNet/Ieee8021QPacket.cs b/PacketDotNet/Ieee8021QPacket.cs new file mode 100644 index 00000000..4019754e --- /dev/null +++ b/PacketDotNet/Ieee8021QPacket.cs @@ -0,0 +1,226 @@ +/* +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 2013 Chris Morgan + */ +using System; +using System.Collections.Generic; +using System.Text; +using MiscUtil.Conversion; +using PacketDotNet.Utils; + +namespace PacketDotNet +{ + /// + /// 802.1Q vlan packet + /// http://en.wikipedia.org/wiki/IEEE_802.1Q + /// + [Serializable] + public class Ieee8021QPacket : InternetPacket + { + /// + /// Type of packet that this vlan packet encapsulates + /// + public virtual EthernetPacketType Type + { + get + { + return (EthernetPacketType)EndianBitConverter.Big.ToInt16(header.Bytes, + header.Offset + Ieee8021QFields.TypePosition); + } + + set + { + Int16 val = (Int16)value; + EndianBitConverter.Big.CopyBytes(val, + header.Bytes, + header.Offset + Ieee8021QFields.TypePosition); + } + } + + /// + /// Gets or sets the priority control point. + /// + /// + /// The priority control point. + /// + public IeeeP8021PPriorities PriorityControlPoint + { + get + { + var tci = TagControlInformation; + tci >>= (16 - 3); // priority is the upper 3 bits + return (IeeeP8021PPriorities)tci; + } + + set + { + var tci = TagControlInformation; + + // mask the existing Priority off and then back in from value + ushort val = (ushort)value; + tci = (ushort)((tci & 0x1FFF) | ((val & 0x7) << (16 - 3))); + TagControlInformation = tci; + } + } + + /// + /// Gets or sets a value indicating whether this instance canonical format indicator. + /// + /// + /// true if the mac address is in non-canonical format false if otherwise. + /// + public bool CanonicalFormatIndicator + { + get + { + var tci = TagControlInformation; + tci >>= 12; + return ((tci & 0x1) == 1) ? true : false; + } + + set + { + var tci = TagControlInformation; + + // mask the existing CFI off and then back in from value + int val = ((value == true) ? 1 : 0); + tci = (ushort)((tci & 0xEFFF) | (val << 12)); + TagControlInformation = tci; + } + } + + /// + /// Gets or sets the VLAN identifier. + /// + /// + /// The VLAN identifier. + /// + public ushort VLANIdentifier + { + get + { + var tci = TagControlInformation; + return (ushort)(tci & 0xFFF); + } + + set + { + var tci = TagControlInformation; + + // mask the existing vlan id off + tci = (ushort)((tci & 0xF000) | (value & 0xFFF)); + TagControlInformation = tci; + } + } + + private ushort TagControlInformation + { + get + { + return (ushort)EndianBitConverter.Big.ToInt16(header.Bytes, + header.Offset + Ieee8021QFields.TagControlInformationPosition); + } + + set + { + Int16 val = (Int16)value; + EndianBitConverter.Big.CopyBytes(val, + header.Bytes, + header.Offset + Ieee8021QFields.TagControlInformationPosition); + } + } + + /// Fetch ascii escape sequence of the color associated with this packet type. + override public System.String Color + { + get + { + return AnsiEscapeSequences.LightCyan; + } + } + + /// + /// Constructor + /// + /// + /// A + /// + public Ieee8021QPacket(ByteArraySegment bas) + { + // set the header field, header field values are retrieved from this byte array + header = new ByteArraySegment(bas); + header.Length = Ieee8021QFields.HeaderLength; + + // parse the payload via an EthernetPacket method + payloadPacketOrData = EthernetPacket.ParseEncapsulatedBytes(header, + Type); + } + + /// + 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}[Ieee8021QPacket: PriorityControlPoint={2}, CanonicalFormatIndicator={3}, Type={4}]{1}", + color, + colorEscape, + PriorityControlPoint, + CanonicalFormatIndicator, + Type); + } + + if(outputFormat == StringOutputType.Verbose || outputFormat == StringOutputType.VerboseColored) + { + // collect the properties and their value + Dictionary properties = new Dictionary(); + properties.Add("priority", PriorityControlPoint + " (0x" + PriorityControlPoint.ToString("x") + ")"); + properties.Add("canonical format indicator", CanonicalFormatIndicator.ToString()); + properties.Add("type", Type.ToString() + " (0x" + Type.ToString("x") + ")"); + properties.Add ("VLANIdentifier", VLANIdentifier.ToString () + " (0x" + VLANIdentifier.ToString ("x") + ")"); + + // 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("Ieee802.1Q: ******* Ieee802.1Q - \"VLan tag\" - offset=? length=" + TotalPacketLength); + buffer.AppendLine("Ieee802.1Q:"); + foreach (var property in properties) + { + buffer.AppendLine("Ieee802.1Q: " + property.Key.PadLeft(padLength) + " = " + property.Value); + } + buffer.AppendLine("Ieee802.1Q:"); + } + + // append the base string output + buffer.Append(base.ToString(outputFormat)); + + return buffer.ToString(); + } + } +} diff --git a/PacketDotNet/IeeeP8021PPriorities.cs b/PacketDotNet/IeeeP8021PPriorities.cs new file mode 100644 index 00000000..de5d3ba1 --- /dev/null +++ b/PacketDotNet/IeeeP8021PPriorities.cs @@ -0,0 +1,63 @@ +/* +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 2013 Chris Morgan + */ +using System; + +namespace PacketDotNet +{ + /// + /// Ieee p8021 P priorities. + /// http://en.wikipedia.org/wiki/IEEE_802.1p + /// + public enum IeeeP8021PPriorities : byte + { + /// + /// Background + /// + Background_0 = 1, + /// + /// Best effort + /// + BestEffort_1 = 0, + /// + /// Excellent effort + /// + ExcellentEffort_2 = 2, + /// + /// Critical application + /// + CriticalApplications_3 = 3, + /// + /// Video, < 100ms latency and jitter + /// + Video_4 = 4, + /// + /// Voice, < 10ms latency and jitter + /// + Voice_5 = 5, + /// + /// Internetwork control + /// + InternetworkControl_6 = 6, + /// + /// Network control + /// + NetworkControl_7 = 7 + } +} \ No newline at end of file diff --git a/PacketDotNet/PacketDotNet.csproj b/PacketDotNet/PacketDotNet.csproj index 307d17e7..80488a14 100644 --- a/PacketDotNet/PacketDotNet.csproj +++ b/PacketDotNet/PacketDotNet.csproj @@ -187,6 +187,9 @@ + + + @@ -194,7 +197,7 @@ - + diff --git a/Test/CaptureFiles/802.1q_vlan_ipv4_tcp.pcap b/Test/CaptureFiles/802.1q_vlan_ipv4_tcp.pcap new file mode 100644 index 00000000..0f8ed14e Binary files /dev/null and b/Test/CaptureFiles/802.1q_vlan_ipv4_tcp.pcap differ diff --git a/Test/PacketType/Vlan802_1QTest.cs b/Test/PacketType/Vlan802_1QTest.cs new file mode 100644 index 00000000..7fc1ba8f --- /dev/null +++ b/Test/PacketType/Vlan802_1QTest.cs @@ -0,0 +1,59 @@ +/* +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 2013 Chris Morgan + */ + +using System; +using NUnit.Framework; +using PacketDotNet; +using PacketDotNet.Utils; +using SharpPcap; +using SharpPcap.LibPcap; + +namespace Test.PacketType +{ + [TestFixture] + public class Vlan802_1QTest + { + /// + /// Test that a vlan packet can be properly parsed + /// + [Test] + public void ParsingVlanPacket() + { + Console.WriteLine("Loading the sample capture file"); + var dev = new CaptureFileReaderDevice("../../CaptureFiles/802.1q_vlan_ipv4_tcp.pcap"); + dev.Open(); + + Console.WriteLine("Reading packet data"); + var rawCapture = dev.GetNextPacket(); + + Console.WriteLine("Parsing"); + var p = Packet.ParsePacket(rawCapture.LinkLayerType, rawCapture.Data); + + Console.WriteLine("Printing human readable string"); + Console.WriteLine(p.ToString(StringOutputType.Verbose)); + + var vlanTag = (Ieee8021QPacket)p.Extract(typeof(Ieee8021QPacket)); + Assert.AreEqual(IeeeP8021PPriorities.BestEffort_1, vlanTag.PriorityControlPoint); + var tagId = 102; + Assert.AreEqual(tagId, vlanTag.VLANIdentifier); + Assert.AreEqual(false, vlanTag.CanonicalFormatIndicator); + } + } +} diff --git a/Test/Test.csproj b/Test/Test.csproj index 98c479ba..828a8e01 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -105,6 +105,7 @@ +