Commit ea4bf9ef authored by Brickner_cp's avatar Brickner_cp

IPv6

parent 12713caf
using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.Packets.TestUtils;
using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.Test
{
/// <summary>
/// Summary description for IpV6Tests
/// </summary>
[TestClass]
public class IpV6Tests
{
/// <summary>
/// Gets or sets the test context which provides
/// information about and functionality for the current test run.
/// </summary>
public TestContext TestContext { get; set; }
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void RandomIpV6Test()
{
MacAddress ethernetSource = new MacAddress("00:01:02:03:04:05");
MacAddress ethernetDestination = new MacAddress("A0:A1:A2:A3:A4:A5");
const EthernetType EthernetType = EthernetType.IpV6;
EthernetLayer ethernetLayer = new EthernetLayer
{
Source = ethernetSource,
Destination = ethernetDestination,
EtherType = EthernetType
};
Random random = new Random();
for (int i = 0; i != 1000; ++i)
{
IpV6Layer ipV6Layer = random.NextIpV6Layer();
PayloadLayer payloadLayer = random.NextPayloadLayer(random.NextInt(0, 50 * 1024));
Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV6Layer, payloadLayer);
Assert.IsTrue(packet.IsValid, string.Format("IsValid ({0})", ipV6Layer.NextHeader));
// Ethernet
Assert.AreEqual(packet.Length - EthernetDatagram.HeaderLengthValue, packet.Ethernet.PayloadLength, "PayloadLength");
Assert.AreEqual(ethernetLayer, packet.Ethernet.ExtractLayer(), "Ethernet Layer");
// IpV6
Assert.AreEqual(ipV6Layer, packet.Ethernet.IpV6.ExtractLayer(), "IP Layer");
/*
if (packet.Ethernet.IpV6.NextHeader == IpV4Protocol.Tcp)
Assert.IsInstanceOfType(packet.Ethernet.IpV6.Transport, typeof(TcpDatagram));
else if (packet.Ethernet.IpV6.NextHeader == IpV4Protocol.Udp)
Assert.IsInstanceOfType(packet.Ethernet.IpV6.Transport, typeof(UdpDatagram));
else
Assert.IsNull(packet.Ethernet.IpV6.Transport);
*/
// Assert.AreEqual(payloadLayer.Data, packet.Ethernet.IpV6.Payload, "IP Payload");
}
}
}
}
\ No newline at end of file
......@@ -81,6 +81,7 @@
<Compile Include="IgmpTests.cs" />
<Compile Include="IpV4Tests.cs" />
<Compile Include="IpV6AddressTests.cs" />
<Compile Include="IpV6Tests.cs" />
<Compile Include="MacAddressTests.cs" />
<Compile Include="PacketBuilderTests.cs" />
<Compile Include="PacketTests.cs" />
......
......@@ -62,6 +62,11 @@ namespace PcapDotNet.Packets
return array.Compare(offset, other, otherOffset, count) == 0;
}
public static DataSegment SubSegment(this byte[] array, int offset, int length)
{
return new DataSegment(array, offset, length);
}
/// <summary>
/// Returns the first offset in the array where the other array's range sequence of bytes can be found or the length of the array if no match exists.
/// </summary>
......
using PcapDotNet.Packets.Arp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
namespace PcapDotNet.Packets.Ethernet
{
......@@ -83,6 +84,14 @@ namespace PcapDotNet.Packets.Ethernet
get { return PayloadDatagrams.IpV4; }
}
/// <summary>
/// The Ethernet payload as an IPv6 datagram.
/// </summary>
public IpV6Datagram IpV6
{
get { return PayloadDatagrams.IpV6; }
}
/// <summary>
/// The Ethernet payload as an ARP datagram.
/// </summary>
......
using PcapDotNet.Packets.Arp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
namespace PcapDotNet.Packets.Ethernet
{
......@@ -17,6 +18,9 @@ namespace PcapDotNet.Packets.Ethernet
case EthernetType.IpV4:
return IpV4;
case EthernetType.IpV6:
return IpV6;
case EthernetType.Arp:
return Arp;
......@@ -41,6 +45,19 @@ namespace PcapDotNet.Packets.Ethernet
}
}
/// <summary>
/// The Ethernet payload as an IPv6 datagram.
/// </summary>
public IpV6Datagram IpV6
{
get
{
if (_ipV6 == null && _payload != null)
_ipV6 = new IpV6Datagram(_payload.Buffer, _payload.StartOffset, IpV6Datagram.GetTotalLength(_payload));
return _ipV6;
}
}
/// <summary>
/// The Ethernet payload as an ARP datagram.
/// </summary>
......@@ -74,6 +91,7 @@ namespace PcapDotNet.Packets.Ethernet
private readonly Datagram _payload;
private IpV4Datagram _ipV4;
private IpV6Datagram _ipV6;
private ArpDatagram _arp;
private VLanTaggedFrameDatagram _vLanTaggedFrame;
}
......
......@@ -3,9 +3,9 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.Ip
{
internal static class IpOptionQuickStartCommon
public static class IpOptionQuickStartCommon
{
public const int DataLength = 6;
internal const int DataLength = 6;
/// <summary>
/// The maximum value for the rate field.
......@@ -26,7 +26,7 @@ namespace PcapDotNet.Packets.Ip
public const byte Rate = 0x0F;
}
public static void AssertValidParameters(IpV4OptionQuickStartFunction function, byte rate, byte ttl, uint nonce)
internal static void AssertValidParameters(IpV4OptionQuickStartFunction function, byte rate, byte ttl, uint nonce)
{
if (function != IpV4OptionQuickStartFunction.RateRequest &&
function != IpV4OptionQuickStartFunction.RateReport)
......@@ -41,7 +41,7 @@ namespace PcapDotNet.Packets.Ip
throw new ArgumentException("nonce last two bits are reserved and must be zero", "nonce");
}
public static int CalcRateKbps(byte rate)
internal static int CalcRateKbps(byte rate)
{
if (rate == 0)
return 0;
......@@ -49,7 +49,7 @@ namespace PcapDotNet.Packets.Ip
return 40*(1 << rate);
}
public static void ReadData(DataSegment data, out IpV4OptionQuickStartFunction function, out byte rate, out byte ttl, out uint nonce)
internal static void ReadData(DataSegment data, out IpV4OptionQuickStartFunction function, out byte rate, out byte ttl, out uint nonce)
{
function = (IpV4OptionQuickStartFunction)(data[Offset.Function] & Mask.Function);
rate = (byte)(data[Offset.Rate] & Mask.Rate);
......@@ -57,7 +57,7 @@ namespace PcapDotNet.Packets.Ip
nonce = data.ReadUInt(Offset.Nonce, Endianity.Big);
}
public static void WriteData(byte[] buffer, ref int offset, IpV4OptionQuickStartFunction function, byte rate, byte ttl, uint nonce)
internal static void WriteData(byte[] buffer, ref int offset, IpV4OptionQuickStartFunction function, byte rate, byte ttl, uint nonce)
{
buffer[offset + Offset.Function] = (byte)(((byte)function & Mask.Function) | (rate & Mask.Rate));
buffer[offset + Offset.Ttl] = ttl;
......
......@@ -170,19 +170,22 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
Il = 0x28,
/// <summary>
/// IPv6 RFC 2460
/// RFC 2460.
/// IPv6.
/// </summary>
IpV6 = 0x29,
/// <summary>
/// Source Demand Routing Protocol
/// Source Demand Routing Protocol.
/// </summary>
SourceDemandRoutingProtocol = 0x2A,
/// <summary>
/// Routing Header for IPv6 RFC 2460
/// RFC 2460.
/// Routing Header for IPv6.
/// </summary>
IpV6Route = 0x2B,
/// <summary>
/// Fragment Header for IPv6 RFC 2460
/// RFC 2460.
/// Fragment Header for IPv6.
/// </summary>
FragmentHeaderForIpV6 = 0x2C,
/// <summary>
......
......@@ -39,6 +39,8 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public const int HeaderLength = 40;
public const int MaxFlowLabel = 0xFFFFF;
private static class Offset
{
public const int Version = 0;
......@@ -107,7 +109,12 @@ namespace PcapDotNet.Packets.IpV6
public ushort RealPayloadLength
{
get { return (ushort)Math.Min(PayloadLength, Length); }
get
{
if (Length < HeaderLength)
return 0;
return (ushort)Math.Min(PayloadLength, Length - HeaderLength);
}
}
/// <summary>
......@@ -144,7 +151,7 @@ namespace PcapDotNet.Packets.IpV6
get { return ReadIpV6Address(Offset.DestinationAddress, Endianity.Big); }
}
public ReadOnlyCollection<IpV6ExtensionHeader> ExtensionHeaders
public IpV6ExtensionHeaders ExtensionHeaders
{
get
{
......@@ -158,16 +165,17 @@ namespace PcapDotNet.Packets.IpV6
if (_extensionHeaders != null)
return;
List<IpV6ExtensionHeader> extensionHeaders = new List<IpV6ExtensionHeader>();
if (HeaderLength > RealPayloadLength)
if (Length < HeaderLength)
{
_isValid = false;
_extensionHeaders = extensionHeaders.AsReadOnly();
_extensionHeaders = IpV6ExtensionHeaders.Empty;
return;
}
_extensionHeaders = new IpV6ExtensionHeaders(Subsegment(HeaderLength, RealPayloadLength), NextHeader);
/*
int extendedHeaderLength = HeaderLength;
IpV4Protocol? nextHeader = NextHeader;
while (extendedHeaderLength + 8 <= RealPayloadLength && nextHeader.HasValue && IsExtensionHeader(nextHeader.Value))
while (extendedHeaderLength + 8 <= RealPayloadLength && nextHeader.HasValue && IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value))
{
int numBytesRead;
IpV6ExtensionHeader extensionHeader = IpV6ExtensionHeader.CreateInstance(nextHeader.Value,
......@@ -178,27 +186,10 @@ namespace PcapDotNet.Packets.IpV6
nextHeader = extensionHeader.NextHeader;
extendedHeaderLength += numBytesRead;
}
_isValid = (!nextHeader.HasValue || !IsExtensionHeader(nextHeader.Value)) && (HeaderLength + _extensionHeadersLength == PayloadLength);
_extensionHeaders = extensionHeaders.AsReadOnly();
_extensionHeadersLength = extendedHeaderLength - HeaderLength;
}
private static bool IsExtensionHeader(IpV4Protocol nextHeader)
{
switch (nextHeader)
{
case IpV4Protocol.IpV6HopByHopOption: // 0
case IpV4Protocol.IpV6Route: // 43
case IpV4Protocol.FragmentHeaderForIpV6: // 44
case IpV4Protocol.EncapsulatingSecurityPayload: // 50
case IpV4Protocol.AuthenticationHeader: // 51
case IpV4Protocol.IpV6Opts: // 60
case IpV4Protocol.MobilityHeader: // 135
return true;
default:
return false;
}
_extensionHeaders = extensionHeaders.AsReadOnly();
_isValid = (!nextHeader.HasValue || !IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value));
*/
}
/// <summary>
......@@ -206,20 +197,16 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public override ILayer ExtractLayer()
{
return null;
// TODO: Implement.
// return new IpV6Layer
// {
// Version = Version,
// TrafficClass = TrafficClass,
// FlowLabel = FlowLabel,
// PayloadLength = PayloadLength,
// NextHeader = NextHeader,
// HopLimit = HopLimit,
// Source = Source,
// CurrentDestination = CurrentDestination,
// ExtensionHeaders = ExtensionHeaders,
// };
return new IpV6Layer
{
TrafficClass = TrafficClass,
FlowLabel = FlowLabel,
NextHeader = NextHeader,
HopLimit = HopLimit,
Source = Source,
CurrentDestination = CurrentDestination,
ExtensionHeaders = ExtensionHeaders,
};
}
......@@ -228,16 +215,34 @@ namespace PcapDotNet.Packets.IpV6
{
}
internal static int GetTotalLength(Datagram payload)
{
if (payload.Length <= HeaderLength)
return payload.Length;
int totalLength = HeaderLength;
IpV4Protocol? nextHeader = (IpV4Protocol)payload[Offset.NextHeader];
while (nextHeader.HasValue && IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value))
{
int extensionHeaderLength;
IpV6ExtensionHeader.GetNextNextHeaderAndLength(nextHeader.Value, payload.Subsegment(totalLength, payload.Length - totalLength), out nextHeader,
out extensionHeaderLength);
totalLength += extensionHeaderLength;
}
return totalLength;
}
internal static void WriteHeader(byte[] buffer, int offset,
byte version, byte trafficClass, int flowLabel, ushort payloadLength, IpV4Protocol nextHeader, byte hopLimit,
IpV6Address source, IpV6Address currentDestination)
byte trafficClass, int flowLabel, ushort payloadLength, IpV4Protocol nextHeader, byte hopLimit,
IpV6Address source, IpV6Address currentDestination, IpV6ExtensionHeaders extensionHeaders)
{
buffer.Write(offset + Offset.Version, (uint)(((((version << Shift.Version) << 8) | trafficClass) << 16) | flowLabel), Endianity.Big);
buffer.Write(offset + Offset.Version, (uint)(((((DefaultVersion << Shift.Version) << 8) | trafficClass) << 16) | flowLabel), Endianity.Big);
buffer.Write(offset + Offset.PayloadLength, payloadLength, Endianity.Big);
buffer.Write(offset + Offset.NextHeader, (byte)nextHeader);
buffer.Write(offset + Offset.HopLimit, hopLimit);
buffer.Write(offset + Offset.SourceAddress, source, Endianity.Big);
buffer.Write(offset + Offset.DestinationAddress, currentDestination, Endianity.Big);
extensionHeaders.Write(buffer, offset + HeaderLength);
}
protected override bool CalculateIsValid()
......@@ -246,68 +251,8 @@ namespace PcapDotNet.Packets.IpV6
return _isValid;
}
private ReadOnlyCollection<IpV6ExtensionHeader> _extensionHeaders;
private IpV6ExtensionHeaders _extensionHeaders;
private int _extensionHeadersLength;
private bool _isValid;
}
/*
/// <summary>
/// RFC 2460.
/// +-----+-------------+-------------------------+--------------+---------------+
/// | Bit | 0-7 | 8-15 | 16-23 | 24-31 |
/// +-----+-------------+-------------------------+--------------+---------------+
/// | 0 | Next Header | Header Extension Length | Routing Type | Segments Left |
/// +-----+-------------+-------------------------+--------------+---------------+
/// | 32 | type-specific data |
/// | ... | |
/// +-----+----------------------------------------------------------------------+
/// </summary>
public class IpV6ExtensionHeaderRouting : IpV6ExtensionHeader
{
}
/// <summary>
/// RFC 2460.
/// +-----+-------------+----------+-----------------+----------+----+
/// | Bit | 0-7 | 8-15 | 16-28 | 29-30 | 31 |
/// +-----+-------------+----------+-----------------+----------+----+
/// | 0 | Next Header | Reserved | Fragment Offset | Reserved | M |
/// +-----+-------------+----------+-----------------+----------+----+
/// | 32 | Identification |
/// +-----+----------------------------------------------------------+
/// </summary>
public class IpV6ExtensionHeaderFragment : IpV6ExtensionHeader
{
}
/// <summary>
/// RFC 2460.
/// +-----+-------------+-------------------------+
/// | Bit | 0-7 | 8-15 |
/// +-----+-------------+-------------------------+
/// | 0 | Next Header | Header Extension Length |
/// +-----+-------------+-------------------------+
/// | 16 | Options |
/// | ... | |
/// +-----+---------------------------------------+
/// </summary>
public class IpV6ExtensionHeaderDestinationOptions : IpV6ExtensionHeader
{
}
/// <summary>
/// RFC 2402.
/// </summary>
public class IpV6ExtensionHeaderAuthentication : IpV6ExtensionHeader
{
}
/// <summary>
/// RFC 2406.
/// </summary>
public class IpV6ExtensionHeaderEncapsulatingSecurityPayload : IpV6ExtensionHeader
{
}
*/
}
......@@ -92,7 +92,7 @@ namespace PcapDotNet.Packets.IpV6
return null;
}
IpV4Protocol nextHeader = (IpV4Protocol)extensionHeaderData[Offset.NextHeader];
byte payloadLength = extensionHeaderData[Offset.PayloadLength];
int payloadLength = (extensionHeaderData[Offset.PayloadLength] + 2) * 4;
if (extensionHeaderData.Length < Offset.AuthenticationData + payloadLength)
{
numBytesRead = 0;
......@@ -101,10 +101,44 @@ namespace PcapDotNet.Packets.IpV6
uint securityParametersIndex = extensionHeaderData.ReadUInt(Offset.SecurityParametersIndex, Endianity.Big);
uint sequenceNumber = extensionHeaderData.ReadUInt(Offset.SequenceNumber, Endianity.Big);
DataSegment authenticationData = extensionHeaderData.Subsegment(Offset.AuthenticationData, payloadLength);
numBytesRead = Offset.AuthenticationData + payloadLength;
DataSegment authenticationData = extensionHeaderData.Subsegment(Offset.AuthenticationData, payloadLength - Offset.AuthenticationData);
numBytesRead = payloadLength;
return new IpV6ExtensionHeaderAuthentication(nextHeader, securityParametersIndex, sequenceNumber, authenticationData);
}
public static void GetNextNextHeaderAndLength(DataSegment extensionHeader, out IpV4Protocol? nextNextHeader, out int extensionHeaderLength)
{
if (extensionHeader.Length < MinimumLength)
{
nextNextHeader = null;
extensionHeaderLength = extensionHeader.Length;
return;
}
nextNextHeader = (IpV4Protocol)extensionHeader[Offset.NextHeader];
extensionHeaderLength = extensionHeader[Offset.PayloadLength] * 4;
}
public override IpV4Protocol Protocol
{
get { return IpV4Protocol.AuthenticationHeader; }
}
public override int Length
{
get { return MinimumLength + AuthenticationData.Length; }
}
internal override void Write(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.NextHeader, (byte)NextHeader);
int length = Length;
buffer.Write(offset + Offset.PayloadLength, (byte)((length / 4) - 2));
buffer.Write(offset + Offset.SecurityParametersIndex, SecurityParametersIndex, Endianity.Big);
buffer.Write(offset + Offset.SequenceNumber, SequenceNumber, Endianity.Big);
AuthenticationData.Write(buffer, offset + Offset.AuthenticationData);
offset += length;
}
}
}
\ No newline at end of file
......@@ -22,6 +22,11 @@ namespace PcapDotNet.Packets.IpV6
{
}
public override IpV4Protocol Protocol
{
get { return IpV4Protocol.IpV6Opts; }
}
internal static IpV6ExtensionHeaderDestinationOptions ParseData(IpV4Protocol nextHeader, DataSegment data)
{
IpV6Options options = new IpV6Options(data);
......
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
......@@ -62,6 +64,16 @@ namespace PcapDotNet.Packets.IpV6
EncryptedDataAndAuthenticationData = encryptedDataAndAuthenticationData;
}
public override IpV4Protocol Protocol
{
get { return IpV4Protocol.EncapsulatingSecurityPayload; }
}
public override int Length
{
get { return MinimumLength + EncryptedDataAndAuthenticationData.Length; }
}
/// <summary>
/// <para>
/// The SPI is an arbitrary 32-bit value that, in combination with the destination IP address and security protocol (ESP),
......@@ -132,6 +144,12 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public DataSegment EncryptedDataAndAuthenticationData { get; private set; }
internal static void GetNextNextHeaderAndLength(DataSegment extensionHeader, out IpV4Protocol? nextNextHeader, out int extensionHeaderLength)
{
nextNextHeader = null;
extensionHeaderLength = extensionHeader.Length;
}
internal static IpV6ExtensionHeaderEncapsulatingSecurityPayload CreateInstance(DataSegment extensionHeaderData, out int numBytesRead)
{
if (extensionHeaderData.Length < MinimumLength)
......@@ -146,5 +164,13 @@ namespace PcapDotNet.Packets.IpV6
return new IpV6ExtensionHeaderEncapsulatingSecurityPayload(securityParametersIndex, sequenceNumber, encryptedDataAndAuthenticationData);
}
internal override void Write(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.SecurityParametersIndex, SecurityParametersIndex, Endianity.Big);
buffer.Write(offset + Offset.SequenceNumber, SequenceNumber, Endianity.Big);
EncryptedDataAndAuthenticationData.Write(buffer, offset + Offset.PayloadData);
offset += Length;
}
}
}
\ No newline at end of file
......@@ -17,11 +17,16 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public class IpV6ExtensionHeaderHopByHopOptions : IpV6ExtensionHeaderOptions
{
private IpV6ExtensionHeaderHopByHopOptions(IpV4Protocol nextHeader, IpV6Options options)
public IpV6ExtensionHeaderHopByHopOptions(IpV4Protocol nextHeader, IpV6Options options)
: base(nextHeader, options)
{
}
public override IpV4Protocol Protocol
{
get { return IpV4Protocol.IpV6HopByHopOption; }
}
internal static IpV6ExtensionHeaderHopByHopOptions ParseData(IpV4Protocol nextHeader, DataSegment data)
{
IpV6Options options = new IpV6Options(data);
......
......@@ -15,10 +15,20 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+---------------------------------------+
/// </pre>
/// </summary>
public abstract class IpV6ExtensionHeaderOptions : IpV6ExtensionHeader
public abstract class IpV6ExtensionHeaderOptions : IpV6ExtensionHeaderStandard
{
public IpV6Options Options { get; private set; }
internal override sealed int DataLength
{
get { return Options.BytesLength; }
}
internal override void WriteData(byte[] buffer, int offset)
{
Options.Write(buffer, offset);
}
internal IpV6ExtensionHeaderOptions(IpV4Protocol nextHeader, IpV6Options options)
: base(nextHeader)
{
......
......@@ -15,7 +15,7 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+----------------------------------------------------------------------+
/// </pre>
/// </summary>
public abstract class IpV6ExtensionHeaderRouting : IpV6ExtensionHeader
public abstract class IpV6ExtensionHeaderRouting : IpV6ExtensionHeaderStandard
{
private static class DataOffset
{
......@@ -26,6 +26,8 @@ namespace PcapDotNet.Packets.IpV6
public const int DataMinimumLength = DataOffset.TypeSpecificData;
internal abstract int RoutingDataLength { get; }
/// <summary>
/// Identifier of a particular Routing header variant.
/// </summary>
......@@ -36,6 +38,22 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public byte SegmentsLeft { get; private set; }
public override IpV4Protocol Protocol
{
get { return IpV4Protocol.IpV6Route; }
}
internal IpV6ExtensionHeaderRouting(IpV4Protocol nextHeader, byte segmentsLeft)
: base(nextHeader)
{
SegmentsLeft = segmentsLeft;
}
internal override sealed int DataLength
{
get { return DataMinimumLength + RoutingDataLength; }
}
internal static IpV6ExtensionHeaderRouting ParseData(IpV4Protocol nextHeader, DataSegment data)
{
if (data.Length < DataMinimumLength)
......@@ -63,10 +81,13 @@ namespace PcapDotNet.Packets.IpV6
}
}
internal IpV6ExtensionHeaderRouting(IpV4Protocol nextHeader, byte segmentsLeft)
: base(nextHeader)
internal override sealed void WriteData(byte[] buffer, int offset)
{
SegmentsLeft = segmentsLeft;
buffer.Write(offset + DataOffset.RoutingType, (byte)RoutingType);
buffer.Write(offset + DataOffset.SegmentsLeft, SegmentsLeft);
WriteRoutingData(buffer, offset + DataOffset.TypeSpecificData);
}
internal abstract void WriteRoutingData(byte[] buffer, int offset);
}
}
\ No newline at end of file
......@@ -23,11 +23,10 @@ namespace PcapDotNet.Packets.IpV6
{
private static class RoutingDataOffset
{
public const int Reserved = 0;
public const int HomeAddress = Reserved + sizeof(uint);
public const int HomeAddress = sizeof(uint);
}
public const int RoutingDataLength = RoutingDataOffset.HomeAddress + IpV6Address.SizeOf;
public const int ConstRoutingDataLength = RoutingDataOffset.HomeAddress + IpV6Address.SizeOf;
public IpV6ExtensionHeaderRoutingHomeAddress(IpV4Protocol nextHeader, byte segmentsLeft, IpV6Address homeAddress)
: base(nextHeader, segmentsLeft)
......@@ -45,13 +44,23 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public IpV6Address HomeAddress { get; private set; }
internal override int RoutingDataLength
{
get { return ConstRoutingDataLength; }
}
internal static IpV6ExtensionHeaderRoutingHomeAddress ParseRoutingData(IpV4Protocol nextHeader, byte segmentsLeft, DataSegment routingData)
{
if (routingData.Length != RoutingDataLength)
if (routingData.Length != ConstRoutingDataLength)
return null;
IpV6Address homeAddress = routingData.ReadIpV6Address(RoutingDataOffset.HomeAddress, Endianity.Big);
return new IpV6ExtensionHeaderRoutingHomeAddress(nextHeader, segmentsLeft, homeAddress);
}
internal override void WriteRoutingData(byte[] buffer, int offset)
{
buffer.Write(offset + RoutingDataOffset.HomeAddress, HomeAddress, Endianity.Big);
}
}
}
\ No newline at end of file
using System;
using System.Collections.ObjectModel;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
......@@ -14,7 +15,7 @@ namespace PcapDotNet.Packets.IpV6
/// | 0 | Next Header | Header Extension Length | Routing Type | Segments Left |
/// +-----+-------+-------+------+------------------+--------------+---------------+
/// | 32 | CmprI | CmprE | Pad | Reserved |
/// +-----+-------+-------+------+------------------+--------------+---------------+
/// +-----+-------+-------+------+-------------------------------------------------+
/// | 64 | Address[1] |
/// | ... | |
/// +-----+------------------------------------------------------------------------+
......@@ -110,6 +111,18 @@ namespace PcapDotNet.Packets.IpV6
public ReadOnlyCollection<IpV6Address> Addresses { get; private set; }
internal override int RoutingDataLength
{
get
{
return RoutingDataMinimumLength +
(Addresses.Any()
? Addresses.Count * IpV6Address.SizeOf -
(Addresses.Count - 1) * CommonPrefixLengthForNonLastAddresses - CommonPrefixLengthForLastAddress
: 0) + PadSize;
}
}
internal static IpV6ExtensionHeaderRoutingRpl ParseRoutingData(IpV4Protocol nextHeader, byte segmentsLeft, DataSegment routingData)
{
if (routingData.Length < RoutingDataMinimumLength)
......@@ -158,5 +171,25 @@ namespace PcapDotNet.Packets.IpV6
return new IpV6ExtensionHeaderRoutingRpl(nextHeader, segmentsLeft, commonPrefixLengthForNonLastAddresses, commonPrefixLengthForLastAddress, padSize,
addresses);
}
internal override void WriteRoutingData(byte[] buffer, int offset)
{
buffer.Write(offset + RoutingDataOffset.CommonPrefixLengthForNonLastAddresses,
(byte)((CommonPrefixLengthForNonLastAddresses << RoutingDataShift.CommonPrefixLengthForNonLastAddresses) |
CommonPrefixLengthForLastAddress));
buffer.Write(offset + RoutingDataOffset.PadSize, (byte)(PadSize << RoutingDataShift.PadSize));
if (Addresses.Any())
{
int addressOffset = offset + RoutingDataOffset.Addresses;
byte[] addressBytes = new byte[IpV6Address.SizeOf];
for (int i = 0; i != Addresses.Count - 1; ++i)
{
addressBytes.Write(0, Addresses[i], Endianity.Big);
addressBytes.SubSegment(CommonPrefixLengthForNonLastAddresses, IpV6Address.SizeOf - CommonPrefixLengthForNonLastAddresses).Write(buffer, ref addressOffset);
}
addressBytes.Write(0, Addresses[Addresses.Count - 1], Endianity.Big);
addressBytes.SubSegment(CommonPrefixLengthForLastAddress, IpV6Address.SizeOf - CommonPrefixLengthForLastAddress).Write(buffer, ref addressOffset);
}
}
}
}
\ No newline at end of file
......@@ -58,6 +58,11 @@ namespace PcapDotNet.Packets.IpV6
public ReadOnlyCollection<IpV6Address> Addresses { get; private set; }
internal override int RoutingDataLength
{
get { return RoutingDataMinimumLength + Addresses.Count * IpV6Address.SizeOf; }
}
internal static IpV6ExtensionHeaderRoutingSourceRoute ParseRoutingData(IpV4Protocol nextHeader, byte segmentsLeft, DataSegment routingData)
{
if (routingData.Length < RoutingDataMinimumLength)
......@@ -72,5 +77,11 @@ namespace PcapDotNet.Packets.IpV6
addresses[i] = routingData.ReadIpV6Address(RoutingDataOffset.Addresses + i * IpV6Address.SizeOf, Endianity.Big);
return new IpV6ExtensionHeaderRoutingSourceRoute(nextHeader, segmentsLeft, addresses);
}
internal override void WriteRoutingData(byte[] buffer, int offset)
{
for (int i = 0; i != Addresses.Count; ++i)
buffer.Write(offset + RoutingDataOffset.Addresses + i * IpV6Address.SizeOf, Addresses[i], Endianity.Big);
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
/// Represents IPv6 layer.
/// <seealso cref="IpV6Datagram"/>
/// </summary>
public sealed class IpV6Layer : Layer, IEthernetNextLayer, IIpV4NextLayer
{
/// <summary>
/// Creates an IPv6 layer with all zero values.
/// </summary>
public IpV6Layer()
{
ExtensionHeaders = IpV6ExtensionHeaders.Empty;
}
public byte TrafficClass { get; set; }
public int FlowLabel { get; set; }
/// <summary>
/// Identifies the type of header immediately following the IPv6 header.
/// Uses the same values as the IPv4 Protocol field.
/// null means that this value should be calculated according to the next layer.
/// </summary>
public IpV4Protocol? NextHeader { get; set; }
public byte HopLimit { get; set; }
/// <summary>
/// Address of the originator of the packet.
/// </summary>
public IpV6Address Source { get; set; }
/// <summary>
/// Address of the intended recipient of the packet (possibly not the ultimate recipient, if a Routing header is present).
/// </summary>
public IpV6Address CurrentDestination { get; set; }
public IpV6ExtensionHeaders ExtensionHeaders { get; set; }
/// <summary>
/// The Ethernet Type the Ethernet layer should write when this layer is the Ethernet payload.
/// </summary>
public EthernetType PreviousLayerEtherType
{
get { return EthernetType.IpV6; }
}
/// <summary>
/// The protocol that should be written in the previous (IPv4) layer (in this case: IP).
/// </summary>
public IpV4Protocol PreviousLayerProtocol
{
get { return IpV4Protocol.IpV6; }
}
/// <summary>
/// The default MAC Address value when this layer is the Ethernet payload.
/// null means there is no default value.
/// </summary>
public MacAddress? PreviousLayerDefaultDestination
{
get { return null; }
}
/// <summary>
/// The number of bytes this layer will take.
/// </summary>
public override int Length
{
get { return IpV6Datagram.HeaderLength + ExtensionHeaders.Sum(header => header.Length); }
}
/// <summary>
/// Writes the layer to the buffer.
/// </summary>
/// <param name="buffer">The buffer to write the layer to.</param>
/// <param name="offset">The offset in the buffer to start writing the layer at.</param>
/// <param name="payloadLength">The length of the layer's payload (the number of bytes after the layer in the packet).</param>
/// <param name="previousLayer">The layer that comes before this layer. null if this is the first layer.</param>
/// <param name="nextLayer">The layer that comes after this layer. null if this is the last layer.</param>
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
IpV4Protocol nextHeader;
if (NextHeader == null)
{
if (nextLayer == null)
throw new ArgumentException("Can't determine protocol automatically from next layer because there is no next layer");
IIpV4NextLayer ipV4NextLayer = nextLayer as IIpV4NextLayer;
if (ipV4NextLayer == null)
throw new ArgumentException("Can't determine protocol automatically from next layer (" + nextLayer.GetType() + ")");
nextHeader = ipV4NextLayer.PreviousLayerProtocol;
}
else
nextHeader = NextHeader.Value;
IpV6Datagram.WriteHeader(buffer, offset,
TrafficClass, FlowLabel, (ushort)payloadLength, nextHeader, HopLimit, Source, CurrentDestination, ExtensionHeaders);
}
/// <summary>
/// True iff the two IPv4 layers have the same TypeOfService, Identification, Fragmentation, Ttl, Protocol, HeaderChecksum, Source, Destination and Options.
/// </summary>
public bool Equals(IpV6Layer other)
{
return other != null &&
TrafficClass == other.TrafficClass && FlowLabel == other.FlowLabel &&
NextHeader == other.NextHeader && HopLimit == other.HopLimit &&
Source == other.Source && CurrentDestination == other.CurrentDestination &&
ExtensionHeaders.SequenceEqual(other.ExtensionHeaders);
}
/// <summary>
/// True iff the two IPv4 layers have the same TypeOfService, Identification, Fragmentation, Ttl, Protocol, HeaderChecksum, Source, Destination and Options.
/// </summary>
public override bool Equals(Layer other)
{
return Equals(other as IpV6Layer);
}
/// <summary>
/// Returns a hash code for the layer.
/// The hash code is a XOR of the TrafficClass and HopLimit combined and the hash codes of the FlowLabel, Source, CurrentDestination, NextHeader, HeaderChecksum, ExtensionHeaders.
/// </summary>
public override int GetHashCode()
{
return base.GetHashCode() ^
Sequence.GetHashCode(BitSequence.Merge(TrafficClass, HopLimit),
FlowLabel, Source, CurrentDestination, NextHeader) ^ ExtensionHeaders.SequenceGetHashCode();
}
/// <summary>
/// Contains the Source, Destination and Protocol.
/// </summary>
public override string ToString()
{
return Source + " -> " + CurrentDestination + " (" + NextHeader + ")";
}
}
}
\ No newline at end of file
......@@ -30,7 +30,7 @@ namespace PcapDotNet.Packets.IpV6
public class IpV6OptionSmfDpdIpV4 : IpV6OptionSmfDpdSequenceBased
{
public IpV6OptionSmfDpdIpV4(IpV4Address taggerId, DataSegment identifier)
:base(identifier)
: base(identifier)
{
TaggerId = taggerId;
}
......
......@@ -265,7 +265,7 @@ namespace PcapDotNet.Packets.IpV6
/// RFC 5568.
/// Mobility Header IPv6 Address/Prefix.
/// </summary>
MobilityHeaderIpV6AddressPrefix = 0x22,
IpV6AddressPrefix = 0x22,
/// <summary>
/// RFC 5648.
......
......@@ -561,7 +561,7 @@ namespace PcapDotNet.Packets.IpV6
}
}
public enum IpV6MobilityOptionLinkLayerAddressCode : byte
public enum IpV6MobilityLinkLayerAddressCode : byte
{
/// <summary>
/// Wildcard requesting resolution for all nearby access points.
......@@ -637,14 +637,14 @@ namespace PcapDotNet.Packets.IpV6
public const int OptionDataMinimumLength = Offset.LinkLayerAddress;
public IpV6MobilityOptionLinkLayerAddress(IpV6MobilityOptionLinkLayerAddressCode code, DataSegment linkLayerAddress)
public IpV6MobilityOptionLinkLayerAddress(IpV6MobilityLinkLayerAddressCode code, DataSegment linkLayerAddress)
: base(IpV6MobilityOptionType.LinkLayerAddress)
{
Code = code;
LinkLayerAddress = linkLayerAddress;
}
public IpV6MobilityOptionLinkLayerAddressCode Code { get; private set; }
public IpV6MobilityLinkLayerAddressCode Code { get; private set; }
/// <summary>
/// Variable-length link-layer address.
......@@ -656,7 +656,7 @@ namespace PcapDotNet.Packets.IpV6
if (data.Length < OptionDataMinimumLength)
return null;
IpV6MobilityOptionLinkLayerAddressCode code = (IpV6MobilityOptionLinkLayerAddressCode)data[Offset.OptionCode];
IpV6MobilityLinkLayerAddressCode code = (IpV6MobilityLinkLayerAddressCode)data[Offset.OptionCode];
DataSegment linkLayerAddress = data.Subsegment(Offset.LinkLayerAddress, data.Length - Offset.LinkLayerAddress);
return new IpV6MobilityOptionLinkLayerAddress(code, linkLayerAddress);
......@@ -2468,7 +2468,7 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// RFC 5845.
/// </summary>
public enum IpV6MobilityHeaderIpV6AddressPrefixCode : byte
public enum IpV6MobilityIpV6AddressPrefixCode : byte
{
/// <summary>
/// Old Care-of Address.
......@@ -2514,8 +2514,8 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+-----------------------------+
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.MobilityHeaderIpV6AddressPrefix)]
public class IpV6MobilityOptionMobilityHeaderIpV6AddressPrefix : IpV6MobilityOptionComplex
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV6AddressPrefix)]
public class IpV6MobilityOptionIpV6AddressPrefix : IpV6MobilityOptionComplex
{
public const byte MaxPrefixLength = 128;
......@@ -2528,8 +2528,8 @@ namespace PcapDotNet.Packets.IpV6
public const int OptionDataLength = Offset.AddressOrPrefix + IpV6Address.SizeOf;
public IpV6MobilityOptionMobilityHeaderIpV6AddressPrefix(IpV6MobilityHeaderIpV6AddressPrefixCode code, byte prefixLength, IpV6Address addressOrPrefix)
: base(IpV6MobilityOptionType.MobilityHeaderIpV6AddressPrefix)
public IpV6MobilityOptionIpV6AddressPrefix(IpV6MobilityIpV6AddressPrefixCode code, byte prefixLength, IpV6Address addressOrPrefix)
: base(IpV6MobilityOptionType.IpV6AddressPrefix)
{
if (prefixLength > MaxPrefixLength)
throw new ArgumentOutOfRangeException("prefixLength", prefixLength, string.Format("Max value is {0}", MaxPrefixLength));
......@@ -2542,7 +2542,7 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Describes the kind of the address or the prefix.
/// </summary>
public IpV6MobilityHeaderIpV6AddressPrefixCode Code { get; private set; }
public IpV6MobilityIpV6AddressPrefixCode Code { get; private set; }
/// <summary>
/// Indicates the length of the IPv6 Address Prefix.
......@@ -2560,10 +2560,10 @@ namespace PcapDotNet.Packets.IpV6
if (data.Length != OptionDataLength)
return null;
IpV6MobilityHeaderIpV6AddressPrefixCode code = (IpV6MobilityHeaderIpV6AddressPrefixCode)data[Offset.Code];
IpV6MobilityIpV6AddressPrefixCode code = (IpV6MobilityIpV6AddressPrefixCode)data[Offset.Code];
byte prefixLength = data[Offset.PrefixLength];
IpV6Address addressOrPrefix = data.ReadIpV6Address(Offset.AddressOrPrefix, Endianity.Big);
return new IpV6MobilityOptionMobilityHeaderIpV6AddressPrefix(code, prefixLength, addressOrPrefix);
return new IpV6MobilityOptionIpV6AddressPrefix(code, prefixLength, addressOrPrefix);
}
internal override int DataLength
......
......@@ -9,6 +9,12 @@ namespace PcapDotNet.Packets.IpV6
{
public class IpV6Options : Options<IpV6Option>
{
public IpV6Options(IList<IpV6Option> options)
: base(options, true, null)
{
}
public IpV6Options(DataSegment data) : this(Read(data))
{
}
......
......@@ -316,6 +316,7 @@
<Compile Include="Igmp\IgmpRecordType.cs" />
<Compile Include="Igmp\IgmpMessageType.cs" />
<Compile Include="Igmp\IIgmpLayerWithGroupAddress.cs" />
<Compile Include="IpV6\IpV6Layer.cs" />
<Compile Include="IpV6\Options\IpV6CalipsoDomainOfInterpretation.cs" />
<Compile Include="IpV6\IpV6ExtensionHeader.cs" />
<Compile Include="IpV6\IpV6ExtensionHeaderAuthentication.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment