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" />
......
using System;
using System.Collections.Generic;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ip;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.TestUtils;
......@@ -10,5 +15,533 @@ namespace PcapDotNet.Packets.TestUtils
{
return new IpV6Address(random.NextUInt128());
}
public static IpV6Address[] NextIpV6AddressArray(this Random random, int count)
{
return ((Func<IpV6Address>)(random.NextIpV6Address)).GenerateArray(count);
}
public static IpV6Layer NextIpV6Layer(this Random random)
{
IpV6ExtensionHeaders extensionHeaders = random.NextIpV6ExtensionHeaders(random.NextInt(0, 10));
IpV4Protocol nextHeader = extensionHeaders.FirstHeader ?? random.NextEnum<IpV4Protocol>(IpV6ExtensionHeader.ExtensionHeaders);
return new IpV6Layer
{
TrafficClass = random.NextByte(),
FlowLabel = random.NextInt(0, IpV6Datagram.MaxFlowLabel + 1),
NextHeader = nextHeader,
HopLimit = random.NextByte(),
Source = random.NextIpV6Address(),
CurrentDestination = random.NextIpV6Address(),
ExtensionHeaders = random.NextIpV6ExtensionHeaders(random.NextInt(0, 10)),
};
}
public static IpV6ExtensionHeaders NextIpV6ExtensionHeaders(this Random random, int count)
{
if (count == 0)
return IpV6ExtensionHeaders.Empty;
IpV4Protocol nextHeader = random.NextEnum<IpV4Protocol>(IpV6ExtensionHeader.ExtensionHeaders);
IpV6ExtensionHeader[] headers = new IpV6ExtensionHeader[count];
for (int i = headers.Length - 1; i >= 0; --i)
{
headers[i] = random.NextIpV6ExtensionHeader(nextHeader);
nextHeader = headers[i].Protocol;
}
return new IpV6ExtensionHeaders(headers);
}
public static IpV6ExtensionHeader NextIpV6ExtensionHeader(this Random random, IpV4Protocol nextHeader)
{
IpV4Protocol extensionHeaderType = random.NextValue(IpV6ExtensionHeader.ExtensionHeaders);
switch (extensionHeaderType)
{
case IpV4Protocol.IpV6HopByHopOption: // 0
return new IpV6ExtensionHeaderHopByHopOptions(nextHeader, random.NextIpV6Options());
case IpV4Protocol.IpV6Route: // 43
IpV6RoutingType routingType = random.NextEnum(IpV6RoutingType.Nimrod);
switch (routingType)
{
case IpV6RoutingType.SourceRoute:
return new IpV6ExtensionHeaderRoutingSourceRoute(nextHeader, random.NextByte(), random.NextIpV6AddressArray(random.NextInt(0, 10)));
case IpV6RoutingType.Type2RoutingHeader:
return new IpV6ExtensionHeaderRoutingHomeAddress(nextHeader, random.NextByte(), random.NextIpV6Address());
case IpV6RoutingType.RplSourceRouteHeader:
return new IpV6ExtensionHeaderRoutingRpl(nextHeader, random.NextByte(),
random.NextByte(IpV6ExtensionHeaderRoutingRpl.MaxCommonPrefixLength + 1),
random.NextByte(IpV6ExtensionHeaderRoutingRpl.MaxCommonPrefixLength + 1),
random.NextByte(IpV6ExtensionHeaderRoutingRpl.MaxPadSize + 1),
random.NextIpV6AddressArray(random.NextInt(0, 10)));
default:
throw new InvalidOperationException(string.Format("Invalid routingType value {0}", routingType));
}
case IpV4Protocol.FragmentHeaderForIpV6: // 44
return new IpV6ExtensionHeaderFragmentData(nextHeader, random.NextUShort(IpV6ExtensionHeaderFragmentData.MaxFragmentOffset + 1),
random.NextBool(), random.NextUInt());
case IpV4Protocol.IpV6Opts: // 60
return new IpV6ExtensionHeaderDestinationOptions(nextHeader, random.NextIpV6Options());
case IpV4Protocol.MobilityHeader: // 135
return random.NextIpV6ExtensionHeaderMobility(nextHeader);
case IpV4Protocol.EncapsulatingSecurityPayload: // 50
return new IpV6ExtensionHeaderEncapsulatingSecurityPayload(random.NextUInt(), random.NextUInt(), random.NextDataSegment(random.Next(100)));
case IpV4Protocol.AuthenticationHeader: // 51
return new IpV6ExtensionHeaderAuthentication(nextHeader, random.NextUInt(), random.NextUInt(), random.NextDataSegment(random.Next(100)));
default:
throw new InvalidOperationException(string.Format("Invalid extensionHeaderType value {0}", extensionHeaderType));
}
}
public static IpV6ExtensionHeaderMobility NextIpV6ExtensionHeaderMobility(this Random random, IpV4Protocol nextHeader)
{
IpV6MobilityHeaderType mobilityHeaderType = random.NextEnum<IpV6MobilityHeaderType>();
ushort checksum = random.NextUShort();
switch (mobilityHeaderType)
{
case IpV6MobilityHeaderType.BindingRefreshRequest: // 0
return new IpV6ExtensionHeaderMobilityBindingRefreshRequest(nextHeader, checksum, random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.HomeTestInit: // 1
return new IpV6ExtensionHeaderMobilityHomeTestInit(nextHeader, checksum, random.NextULong(), random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.CareOfTestInit: // 2
return new IpV6ExtensionHeaderMobilityCareOfTestInit(nextHeader, checksum, random.NextULong(), random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.HomeTest: // 3
return new IpV6ExtensionHeaderMobilityHomeTest(nextHeader, checksum, random.NextUShort(), random.NextULong(), random.NextULong(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.CareOfTest: // 4
return new IpV6ExtensionHeaderMobilityCareOfTest(nextHeader, checksum, random.NextUShort(), random.NextULong(), random.NextULong(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.BindingUpdate: // 5
return new IpV6ExtensionHeaderMobilityBindingUpdate(nextHeader, checksum, random.NextUShort(), random.NextBool(), random.NextBool(),
random.NextBool(), random.NextBool(), random.NextUShort(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.BindingAcknowledgement: // 6
return new IpV6ExtensionHeaderMobilityBindingAcknowledgement(nextHeader, checksum, random.NextEnum<IpV6BindingAcknowledgementStatus>(),
random.NextBool(), random.NextUShort(), random.NextUShort(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.BindingError: // 7
return new IpV6ExtensionHeaderMobilityBindingError(nextHeader, checksum, random.NextEnum<IpV6BindingErrorStatus>(), random.NextIpV6Address(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.FastBindingUpdate: // 8
return new IpV6ExtensionHeaderMobilityFastBindingUpdate(nextHeader, checksum, random.NextUShort(), random.NextBool(), random.NextBool(),
random.NextBool(), random.NextBool(), random.NextUShort(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.FastBindingAcknowledgement: // 9
return new IpV6ExtensionHeaderMobilityFastBindingAcknowledgement(nextHeader, checksum, random.NextEnum<IpV6BindingAcknowledgementStatus>(),
random.NextBool(), random.NextUShort(), random.NextUShort(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.FastNeighborAdvertisement: // 10
return new IpV6ExtensionHeaderMobilityFastNeighborAdvertisement(nextHeader, checksum, random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.Experimental: // 11
return new IpV6ExtensionHeaderMobilityExperimental(nextHeader, checksum, random.NextDataSegment(random.Next(100)));
case IpV6MobilityHeaderType.HomeAgentSwitchMessage: // 12
return new IpV6ExtensionHeaderMobilityHomeAgentSwitchMessage(nextHeader, checksum, random.NextIpV6AddressArray(random.NextInt(0, 10)),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.HeartbeatMessage: // 13
return new IpV6ExtensionHeaderMobilityHeartbeatMessage(nextHeader, checksum, random.NextBool(), random.NextBool(), random.NextUInt(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.HandoverInitiateMessage: // 14
return new IpV6ExtensionHeaderMobilityHandoverInitiateMessage(nextHeader, checksum, random.NextUShort(), random.NextBool(),
random.NextBool(), random.NextEnum<IpV6HandoverInitiateMessageCode>(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.HandoverAcknowledgeMessage: // 15
return new IpV6ExtensionHeaderMobilityHandoverAcknowledgeMessage(nextHeader, checksum, random.NextUShort(),
random.NextEnum<IpV6MobilityHandoverAcknowledgeCode>(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.BindingRevocationMessage: // 16
IpV6MobilityBindingRevocationType bindingRevocationType = random.NextEnum<IpV6MobilityBindingRevocationType>();
byte revocationTriggerOrStatus = random.NextByte();
ushort sequenceNumber = random.NextUShort();
bool proxyBinding = random.NextBool();
bool ipV4HomeAddressBindingOnly = random.NextBool();
bool global = random.NextBool();
IpV6MobilityOptions options = random.NextIpV6MobilityOptions();
switch (bindingRevocationType)
{
case IpV6MobilityBindingRevocationType.BindingRevocationIndication:
return new IpV6ExtensionHeaderMobilityBindingRevocationIndicationMessage(
nextHeader, checksum, (Ipv6MobilityBindingRevocationTrigger)revocationTriggerOrStatus, sequenceNumber, proxyBinding,
ipV4HomeAddressBindingOnly, global, options);
case IpV6MobilityBindingRevocationType.BindingRevocationAcknowledgement:
return new IpV6ExtensionHeaderMobilityBindingRevocationAcknowledgementMessage(
nextHeader, checksum, (Ipv6MobilityBindingRevocationStatus)revocationTriggerOrStatus, sequenceNumber, proxyBinding,
ipV4HomeAddressBindingOnly, global, options);
default:
throw new InvalidOperationException(string.Format("Invalid bindingRevocationType value {0}", bindingRevocationType));
}
case IpV6MobilityHeaderType.LocalizedRoutingInitiation: // 17
return new IpV6ExtensionHeaderMobilityLocalizedRoutingInitiation(nextHeader, checksum, random.NextUShort(), random.NextUShort(),
random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.LocalizedRoutingAcknowledgement: // 18
return new IpV6ExtensionHeaderMobilityLocalizedRoutingAcknowledgement(nextHeader, checksum, random.NextUShort(), random.NextBool(),
random.NextUShort(), random.NextIpV6MobilityOptions());
default:
throw new InvalidOperationException(string.Format("Invalid mobilityHeaderType value {0}", mobilityHeaderType));
}
}
public static IpV6Options NextIpV6Options(this Random random)
{
return new IpV6Options(((Func<IpV6Option>)(random.NextIpV6Option)).GenerateArray(random.NextInt(0, 10)));
}
public static IpV6Option NextIpV6Option(this Random random)
{
IpV6OptionType optionType = random.NextEnum<IpV6OptionType>();
switch (optionType)
{
case IpV6OptionType.Pad1:
return new IpV6OptionPad1();
case IpV6OptionType.PadN:
return new IpV6OptionPadN(random.Next(10));
case IpV6OptionType.JumboPayload:
return new IpV6OptionJumboPayload(random.NextUInt());
case IpV6OptionType.TunnelEncapsulationLimit:
return new IpV6OptionTunnelEncapsulationLimit(random.NextByte());
case IpV6OptionType.RouterAlert:
return new IpV6OptionRouterAlert(random.NextEnum<IpV6RouterAlertType>());
case IpV6OptionType.QuickStart:
return new IpV6OptionQuickStart(random.NextEnum<IpV4OptionQuickStartFunction>(),
random.NextByte(IpOptionQuickStartCommon.RateMaximumValue + 1), random.NextByte(),
random.NextUInt() & 0xFFFFFFFC);
case IpV6OptionType.Calipso:
return new IpV6OptionCalipso(random.NextEnum<IpV6CalipsoDomainOfInterpretation>(), random.NextByte(), random.NextUShort(),
random.NextDataSegment(random.NextByte() * sizeof(int)));
case IpV6OptionType.SmfDpd:
if (random.NextBool())
return new IpV6OptionSmfDpdSequenceHashAssistValue(random.NextDataSegment(random.NextInt(0, 100)));
IpV6TaggerIdType taggerIdType = random.NextEnum<IpV6TaggerIdType>();
DataSegment identifier = random.NextDataSegment(random.NextInt(0, 100));
switch (taggerIdType)
{
case IpV6TaggerIdType.Null:
return new IpV6OptionSmfDpdNull(identifier);
case IpV6TaggerIdType.Default:
return new IpV6OptionSmfDpdDefault(random.NextDataSegment(random.NextInt(0, 100)), identifier);
case IpV6TaggerIdType.IpV4:
return new IpV6OptionSmfDpdIpV4(random.NextIpV4Address(), identifier);
case IpV6TaggerIdType.IpV6:
return new IpV6OptionSmfDpdIpV6(random.NextIpV6Address(), identifier);
default:
throw new InvalidOperationException(string.Format("Invalid taggerIdType value {0}", taggerIdType));
}
case IpV6OptionType.HomeAddress:
return new IpV6OptionHomeAddress(random.NextIpV6Address());
case IpV6OptionType.EndpointIdentification:
return new IpV6OptionEndpointIdentification(random.NextDataSegment(random.Next(10)), random.NextDataSegment(random.Next(10)));
case IpV6OptionType.RplOption:
return new IpV6OptionRoutingProtocolLowPowerAndLossyNetworks(random.NextBool(), random.NextBool(), random.NextBool(), random.NextByte(),
random.NextUShort(), random.NextDataSegment(random.Next(10)));
case IpV6OptionType.IlnpNonce:
return new IpV6OptionIlnpNonce(random.NextDataSegment(random.Next(10)));
case IpV6OptionType.LineIdentification:
return new IpV6OptionLineIdentificationDestination(random.NextDataSegment(random.Next(10)));
default:
throw new InvalidOperationException(string.Format("Invalid optionType value {0}", optionType));
}
}
public static IpV6MobilityOptions NextIpV6MobilityOptions(this Random random)
{
return new IpV6MobilityOptions(((Func<IpV6MobilityOption>)(random.NextIpV6MobilityOption)).GenerateArray(random.NextInt(0, 10)));
}
public static IpV6MobilityOption NextIpV6MobilityOption(this Random random)
{
IpV6MobilityOptionType optionType = random.NextEnum<IpV6MobilityOptionType>();
switch (optionType)
{
case IpV6MobilityOptionType.Pad1:
return new IpV6MobilityOptionPad1();
case IpV6MobilityOptionType.PadN:
return new IpV6MobilityOptionPadN(random.NextInt(0, 10));
case IpV6MobilityOptionType.BindingRefreshAdvice:
return new IpV6MobilityOptionBindingRefreshAdvice(random.NextUShort());
case IpV6MobilityOptionType.AlternateCareOfAddress:
return new IpV6MobilityOptionAlternateCareOfAddress(random.NextIpV6Address());
case IpV6MobilityOptionType.NonceIndices:
return new IpV6MobilityOptionNonceIndices(random.NextUShort(), random.NextUShort());
case IpV6MobilityOptionType.BindingAuthorizationData:
return new IpV6MobilityOptionBindingAuthorizationData(random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.MobileNetworkPrefix:
return new IpV6MobilityOptionMobileNetworkPrefix(random.NextByte(), random.NextIpV6Address());
case IpV6MobilityOptionType.LinkLayerAddress:
return new IpV6MobilityOptionLinkLayerAddress(random.NextEnum<IpV6MobilityLinkLayerAddressCode>(),
random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.MobileNodeIdentifier:
return new IpV6MobilityOptionMobileNodeIdentifier(random.NextEnum<IpV6MobileNodeIdentifierSubtype>(),
random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.Authentication:
return new IpV6MobilityOptionAuthentication(random.NextEnum<IpV6AuthenticationSubtype>(), random.NextUInt(),
random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.ReplayProtection:
return new IpV6MobilityOptionReplayProtection(random.NextULong());
case IpV6MobilityOptionType.CgaParametersRequest:
return new IpV6MobilityOptionCgaParametersRequest();
case IpV6MobilityOptionType.CgaParameters:
return new IpV6MobilityOptionCgaParameters(random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.Signature:
return new IpV6MobilityOptionSignature(random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.PermanentHomeKeygenToken:
return new IpV6MobilityOptionPermanentHomeKeygenToken(random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.CareOfTestInit:
return new IpV6MobilityOptionCareOfTest(random.NextULong());
case IpV6MobilityOptionType.CareOfTest:
return new IpV6MobilityOptionCareOfTest(random.NextULong());
case IpV6MobilityOptionType.DnsUpdate:
return new IpV6MobilityOptionDnsUpdate(random.NextEnum<IpV6DnsUpdateStatus>(), random.NextBool(),
random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.Experimental:
return new IpV6MobilityOptionExperimental(random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.VendorSpecific:
return new IpV6MobilityOptionVendorSpecific(random.NextUInt(), random.NextByte(), random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.ServiceSelection:
return new IpV6MobilityOptionServiceSelection(random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.BindingAuthorizationDataForFmIpV6:
return new IpV6MobilityOptionBindingAuthorizationDataForFmIpV6(random.NextUInt(), random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.HomeNetworkPrefix:
return new IpV6MobilityOptionHomeNetworkPrefix(random.NextByte(), random.NextIpV6Address());
case IpV6MobilityOptionType.HandoffIndicator:
return new IpV6MobilityOptionHandoffIndicator(random.NextEnum<IpV6HandoffIndicator>());
case IpV6MobilityOptionType.AccessTechnologyType:
return new IpV6MobilityOptionAccessTechnologyType(random.NextEnum<IpV6AccessTechnologyType>());
case IpV6MobilityOptionType.MobileNodeLinkLayerIdentifier:
return new IpV6MobilityOptionMobileNodeLinkLayerIdentifier(random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.LinkLocalAddress:
return new IpV6MobilityOptionLinkLocalAddress(random.NextIpV6Address());
case IpV6MobilityOptionType.Timestamp:
return new IpV6MobilityOptionTimestamp(random.NextULong());
case IpV6MobilityOptionType.RestartCounter:
return new IpV6MobilityOptionRestartCounter(random.NextUInt());
case IpV6MobilityOptionType.IpV4HomeAddress:
return new IpV6MobilityOptionIpV4HomeAddress(random.NextByte(), random.NextBool(), random.NextIpV4Address());
case IpV6MobilityOptionType.IpV4AddressAcknowledgement:
return new IpV6MobilityOptionIpV4AddressAcknowledgement(random.NextEnum<IpV6AddressAcknowledgementStatus>(),
random.NextByte(IpV6MobilityOptionIpV4AddressAcknowledgement.MaxPrefixLength + 1),
random.NextIpV4Address());
case IpV6MobilityOptionType.NatDetection:
return new IpV6MobilityOptionNatDetection(random.NextBool(), random.NextUInt());
case IpV6MobilityOptionType.IpV4CareOfAddress:
return new IpV6MobilityOptionIpV4CareOfAddress(random.NextIpV4Address());
case IpV6MobilityOptionType.GreKey:
return new IpV6MobilityOptionGreKey(random.NextUInt());
case IpV6MobilityOptionType.IpV6AddressPrefix:
return new IpV6MobilityOptionIpV6AddressPrefix(random.NextEnum<IpV6MobilityIpV6AddressPrefixCode>(),
random.NextByte(IpV6MobilityOptionIpV6AddressPrefix.MaxPrefixLength + 1),
random.NextIpV6Address());
case IpV6MobilityOptionType.BindingIdentifier:
ushort bindingId = random.NextUShort();
IpV6BindingAcknowledgementStatus status = random.NextEnum<IpV6BindingAcknowledgementStatus>();
bool simultaneousHomeAndForeignBinding = random.NextBool();
byte priority = random.NextByte(IpV6MobilityOptionBindingIdentifier.MaxPriority + 1);
if (random.NextBool(3))
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, priority);
if (random.NextBool())
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, priority, random.NextIpV4Address());
return new IpV6MobilityOptionBindingIdentifier(bindingId, status, simultaneousHomeAndForeignBinding, priority, random.NextIpV6Address());
case IpV6MobilityOptionType.IpV4HomeAddressRequest:
return new IpV6MobilityOptionIpV4HomeAddressRequest(random.NextByte(IpV6MobilityOptionIpV4HomeAddressRequest.MaxPrefixLength + 1),
random.NextIpV4Address());
case IpV6MobilityOptionType.IpV4HomeAddressReply:
return new IpV6MobilityOptionIpV4HomeAddressReply(random.NextEnum<IpV6IpV4HomeAddressReplyStatus>(),
random.NextByte(IpV6MobilityOptionIpV4HomeAddressReply.MaxPrefixLength + 1),
random.NextIpV4Address());
case IpV6MobilityOptionType.IpV4DefaultRouterAddress:
return new IpV6MobilityOptionIpV4DefaultRouterAddress(random.NextIpV4Address());
case IpV6MobilityOptionType.IpV4DhcpSupportMode:
return new IpV6MobilityOptionIpV4DhcpSupportMode(random.NextBool());
case IpV6MobilityOptionType.ContextRequest:
return
new IpV6MobilityOptionContextRequest(
((Func<IpV6MobilityOptionContextRequestEntry>)(() => new IpV6MobilityOptionContextRequestEntry(
random.NextByte(), random.NextDataSegment(random.NextInt(0, 100))))).
GenerateArray(random.NextInt(0, 10)));
case IpV6MobilityOptionType.LocalMobilityAnchorAddress:
if (random.NextBool())
return new IpV6MobilityOptionLocalMobilityAnchorAddress(random.NextIpV4Address());
return new IpV6MobilityOptionLocalMobilityAnchorAddress(random.NextIpV6Address());
case IpV6MobilityOptionType.MobileNodeLinkLocalAddressInterfaceIdentifier:
return new IpV6MobilityOptionMobileNodeLinkLocalAddressInterfaceIdentifier(random.NextULong());
case IpV6MobilityOptionType.TransientBinding:
return new IpV6MobilityOptionTransientBinding(random.NextBool(), random.NextByte());
case IpV6MobilityOptionType.FlowSummary:
return new IpV6MobilityOptionFlowSummary(((Func<ushort>)(random.NextUShort)).GenerateArray(random.NextInt(1, 10)));
case IpV6MobilityOptionType.FlowIdentification:
return new IpV6MobilityOptionFlowIdentification(random.NextUShort(), random.NextUShort(), random.NextEnum<IpV6FlowIdentificationStatus>(),
random.NextIpV6FlowIdentificationSubOptions());
case IpV6MobilityOptionType.RedirectCapability:
return new IpV6MobilityOptionRedirectCapability();
case IpV6MobilityOptionType.Redirect:
if (random.NextBool())
return new IpV6MobilityOptionRedirect(random.NextIpV4Address());
return new IpV6MobilityOptionRedirect(random.NextIpV6Address());
case IpV6MobilityOptionType.LoadInformation:
return new IpV6MobilityOptionLoadInformation(random.NextUShort(), random.NextUInt(), random.NextUInt(), random.NextUInt(), random.NextUInt());
case IpV6MobilityOptionType.AlternateIpV4CareOfAddress:
return new IpV6MobilityOptionAlternateIpV4CareOfAddress(random.NextIpV4Address());
case IpV6MobilityOptionType.MobileNodeGroupIdentifier:
return new IpV6MobilityOptionMobileNodeGroupIdentifier(random.NextEnum<IpV6MobileNodeGroupIdentifierSubType>(), random.NextUInt());
case IpV6MobilityOptionType.MobileAccessGatewayIpV6Address:
return new IpV6MobilityOptionMobileAccessGatewayIpV6Address(random.NextIpV6Address());
case IpV6MobilityOptionType.AccessNetworkIdentifier:
return new IpV6MobilityOptionAccessNetworkIdentifier(random.NextIpV6AccessNetworkIdentifierSubOptions());
default:
throw new InvalidOperationException(string.Format("Invalid optionType value {0}", optionType));
}
}
public static IpV6FlowIdentificationSubOptions NextIpV6FlowIdentificationSubOptions(this Random random)
{
return new IpV6FlowIdentificationSubOptions(((Func<IpV6FlowIdentificationSubOption>)(random.NextIpV6FlowIdentificationSubOption)).GenerateArray(random.NextInt(0, 10)));
}
public static IpV6FlowIdentificationSubOption NextIpV6FlowIdentificationSubOption(this Random random)
{
IpV6FlowIdentificationSubOptionType optionType = random.NextEnum<IpV6FlowIdentificationSubOptionType>();
switch (optionType)
{
case IpV6FlowIdentificationSubOptionType.Pad1:
return new IpV6FlowIdentificationSubOptionPad1();
case IpV6FlowIdentificationSubOptionType.PadN:
return new IpV6FlowIdentificationSubOptionPadN(random.NextInt(0, 10));
case IpV6FlowIdentificationSubOptionType.BindingReference:
return new IpV6FlowIdentificationSubOptionBindingReference(((Func<ushort>)(random.NextUShort)).GenerateArray(random.NextInt(0, 10)));
case IpV6FlowIdentificationSubOptionType.TrafficSelector:
return new IpV6FlowIdentificationSubOptionTrafficSelector(random.NextEnum<IpV6FlowIdentificationTrafficSelectorFormat>(), random.NextDataSegment(random.NextInt(0, 100)));
default:
throw new InvalidOperationException(string.Format("Invalid optionType value {0}", optionType));
}
}
public static IpV6AccessNetworkIdentifierSubOptions NextIpV6AccessNetworkIdentifierSubOptions(this Random random)
{
return new IpV6AccessNetworkIdentifierSubOptions(((Func<IpV6AccessNetworkIdentifierSubOption>)(random.NextIpV6AccessNetworkIdentifierSubOption)).GenerateArray(random.NextInt(0, 10)));
}
public static IpV6AccessNetworkIdentifierSubOption NextIpV6AccessNetworkIdentifierSubOption(this Random random)
{
IpV6AccessNetworkIdentifierSubOptionType optionType = random.NextEnum<IpV6AccessNetworkIdentifierSubOptionType>();
switch (optionType)
{
case IpV6AccessNetworkIdentifierSubOptionType.NetworkIdentifier:
return new IpV6AccessNetworkIdentifierSubOptionNetworkIdentifier(random.NextBool(), random.NextDataSegment(random.NextInt(0, 100)),
random.NextDataSegment(random.NextInt(0, 100)));
case IpV6AccessNetworkIdentifierSubOptionType.GeoLocation:
return new IpV6AccessNetworkIdentifierSubOptionGeoLocation(random.NextUInt24(), random.NextUInt24());
case IpV6AccessNetworkIdentifierSubOptionType.OperatorIdentifier:
return new IpV6AccessNetworkIdentifierSubOptionOperatorIdentifier(random.NextEnum<IpV6AccessNetworkIdentifierOperatorIdentifierType>(),
random.NextDataSegment(random.NextInt(0, 100)));
default:
throw new InvalidOperationException(string.Format("Invalid optionType value {0}", optionType));
}
}
}
}
\ No newline at end of file
......@@ -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
{
}
*/
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
/// RFC 2460.
/// For IpV6HopByHopOption, IpV6Route and FragmentHeaderForIpV6 we use the following format:
/// <pre>
/// +-----+-------------+-------------------------+
/// | Bit | 0-7 | 8-15 |
......@@ -17,48 +22,51 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+---------------------------------------+
/// </pre>
/// </summary>
public abstract class IpV6ExtensionHeader
public abstract class IpV6ExtensionHeaderStandard : IpV6ExtensionHeader
{
private static class Offset
{
public const int NextHeader = 0;
public const int HeaderExtensionLength = 1;
public const int Data = 2;
public const int HeaderExtensionLength = NextHeader + sizeof(byte);
public const int Data = HeaderExtensionLength + sizeof(byte);
}
public const int MinimumLength = 8;
public IpV4Protocol? NextHeader { get; private set; }
internal IpV6ExtensionHeaderStandard(IpV4Protocol nextHeader)
: base(nextHeader)
{
}
protected IpV6ExtensionHeader(IpV4Protocol? nextHeader)
internal override sealed void Write(byte[] buffer, ref int offset)
{
NextHeader = nextHeader;
buffer.Write(offset + Offset.NextHeader, (byte)NextHeader);
int length = Length;
buffer.Write(offset + Offset.HeaderExtensionLength, (byte)((length / 8) - 1));
WriteData(buffer, offset + Offset.Data);
offset += length;
}
internal static IpV6ExtensionHeader CreateInstance(IpV4Protocol nextHeader, DataSegment extensionHeaderData, out int numBytesRead)
internal abstract void WriteData(byte[] buffer, int offset);
public override sealed int Length { get { return MinimumLength + DataLength; } }
internal abstract int DataLength { get; }
internal static bool IsStandard(IpV4Protocol nextHeader)
{
switch (nextHeader)
{
case IpV4Protocol.IpV6HopByHopOption: // 0
case IpV4Protocol.IpV6Route: // 43
case IpV4Protocol.IpV6HopByHopOption: // 0
case IpV4Protocol.IpV6Route: // 43
case IpV4Protocol.FragmentHeaderForIpV6: // 44
case IpV4Protocol.IpV6Opts: // 60
case IpV4Protocol.MobilityHeader: // 135
return CreateStandardInstance(nextHeader, extensionHeaderData, out numBytesRead);
case IpV4Protocol.EncapsulatingSecurityPayload: // 50
return IpV6ExtensionHeaderEncapsulatingSecurityPayload.CreateInstance(extensionHeaderData, out numBytesRead);
case IpV4Protocol.AuthenticationHeader: // 51
return IpV6ExtensionHeaderAuthentication.CreateInstance(extensionHeaderData, out numBytesRead);
case IpV4Protocol.IpV6Opts: // 60
case IpV4Protocol.MobilityHeader: // 135
return true;
default:
throw new InvalidOperationException("Invalid nextHeader value" + nextHeader);
return false;
}
}
private static IpV6ExtensionHeader CreateStandardInstance(IpV4Protocol nextHeader, DataSegment extensionHeaderData, out int numBytesRead)
internal static IpV6ExtensionHeader CreateInstanceStandard(IpV4Protocol nextHeader, DataSegment extensionHeaderData, out int numBytesRead)
{
numBytesRead = 0;
if (extensionHeaderData.Length < MinimumLength)
......@@ -81,7 +89,7 @@ namespace PcapDotNet.Packets.IpV6
case IpV4Protocol.FragmentHeaderForIpV6: // 44
return IpV6ExtensionHeaderFragmentData.ParseData(nextNextHeader, data);
case IpV4Protocol.IpV6Opts: // 60
return IpV6ExtensionHeaderDestinationOptions.ParseData(nextNextHeader, data);
......@@ -92,5 +100,216 @@ namespace PcapDotNet.Packets.IpV6
throw new InvalidOperationException("Invalid nextHeader value" + nextHeader);
}
}
internal 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.HeaderExtensionLength] * 8;
}
internal static ReadOnlyCollection<IpV4Protocol> StandardExtensionHeaders
{
get { return _standardExtensionHeaders; }
}
private static readonly ReadOnlyCollection<IpV4Protocol> _standardExtensionHeaders =
new[]
{
IpV4Protocol.IpV6HopByHopOption,
IpV4Protocol.IpV6Route,
IpV4Protocol.FragmentHeaderForIpV6,
IpV4Protocol.IpV6Opts,
IpV4Protocol.MobilityHeader
}.AsReadOnly();
}
/// <summary>
/// RFC 2460.
/// </summary>
public abstract class IpV6ExtensionHeader
{
public abstract IpV4Protocol Protocol { get; }
public IpV4Protocol? NextHeader { get; private set; }
public abstract int Length { get; }
public static ReadOnlyCollection<IpV4Protocol> ExtensionHeaders
{
get { return _extensionHeaders; }
}
internal static bool IsExtensionHeader(IpV4Protocol nextHeader)
{
if (IpV6ExtensionHeaderStandard.IsStandard(nextHeader))
return true;
switch (nextHeader)
{
case IpV4Protocol.EncapsulatingSecurityPayload: // 50
case IpV4Protocol.AuthenticationHeader: // 51
return true;
default:
return false;
}
}
internal IpV6ExtensionHeader(IpV4Protocol? nextHeader)
{
NextHeader = nextHeader;
}
internal static IpV6ExtensionHeader CreateInstance(IpV4Protocol nextHeader, DataSegment extensionHeaderData, out int numBytesRead)
{
if (IpV6ExtensionHeaderStandard.IsStandard(nextHeader))
return IpV6ExtensionHeaderStandard.CreateInstanceStandard(nextHeader, extensionHeaderData, out numBytesRead);
switch (nextHeader)
{
case IpV4Protocol.EncapsulatingSecurityPayload: // 50
return IpV6ExtensionHeaderEncapsulatingSecurityPayload.CreateInstance(extensionHeaderData, out numBytesRead);
case IpV4Protocol.AuthenticationHeader: // 51
return IpV6ExtensionHeaderAuthentication.CreateInstance(extensionHeaderData, out numBytesRead);
default:
throw new InvalidOperationException("Invalid nextHeader value" + nextHeader);
}
}
internal static void GetNextNextHeaderAndLength(IpV4Protocol nextHeader, DataSegment data, out IpV4Protocol? nextNextHeader,
out int extensionHeaderLength)
{
if (IpV6ExtensionHeaderStandard.IsStandard(nextHeader))
{
IpV6ExtensionHeaderStandard.GetNextNextHeaderAndLength(data, out nextNextHeader, out extensionHeaderLength);
return;
}
switch (nextHeader)
{
case IpV4Protocol.EncapsulatingSecurityPayload: // 50
IpV6ExtensionHeaderEncapsulatingSecurityPayload.GetNextNextHeaderAndLength(data, out nextNextHeader, out extensionHeaderLength);
break;
case IpV4Protocol.AuthenticationHeader: // 51
IpV6ExtensionHeaderAuthentication.GetNextNextHeaderAndLength(data, out nextNextHeader, out extensionHeaderLength);
break;
default:
throw new InvalidOperationException(string.Format("Invalid nextHeader value {0}", nextHeader));
}
}
internal abstract void Write(byte[] buffer, ref int offset);
private static readonly ReadOnlyCollection<IpV4Protocol> _extensionHeaders =
IpV6ExtensionHeaderStandard.StandardExtensionHeaders.Concat(
new[]
{
IpV4Protocol.EncapsulatingSecurityPayload,
IpV4Protocol.AuthenticationHeader
}).
ToArray().AsReadOnly();
}
public class IpV6ExtensionHeaders : IEnumerable<IpV6ExtensionHeader>
{
public IpV6ExtensionHeaders(ReadOnlyCollection<IpV6ExtensionHeader> extensionHeaders)
{
Headers = extensionHeaders;
IsValid = true;
}
public IpV6ExtensionHeaders(params IpV6ExtensionHeader[] extensionHeaders)
: this(extensionHeaders.AsReadOnly())
{
}
public IpV6ExtensionHeaders(IList<IpV6ExtensionHeader> extensionHeaders)
: this(extensionHeaders.AsReadOnly())
{
}
public IpV6ExtensionHeaders(IEnumerable<IpV6ExtensionHeader> extensionHeaders)
: this(extensionHeaders.ToArray())
{
}
public IEnumerator<IpV6ExtensionHeader> GetEnumerator()
{
return Headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IpV6ExtensionHeader this[int index]
{
get { return Headers[index]; }
}
public ReadOnlyCollection<IpV6ExtensionHeader> Headers { get; private set; }
public bool IsValid { get; private set; }
public IpV4Protocol? FirstHeader
{
get
{
if (!Headers.Any())
return null;
return Headers[0].Protocol;
}
}
public IpV4Protocol? NextHeader
{
get
{
if (!Headers.Any())
return null;
return Headers[Headers.Count - 1].Protocol;
}
}
public static IpV6ExtensionHeaders Empty
{
get { return _empty; }
}
internal IpV6ExtensionHeaders(DataSegment data, IpV4Protocol firstHeader)
{
IpV4Protocol? nextHeader = firstHeader;
List<IpV6ExtensionHeader> headers = new List<IpV6ExtensionHeader>();
while (data.Length >= 8 && nextHeader.HasValue && IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value))
{
int numBytesRead;
IpV6ExtensionHeader extensionHeader = IpV6ExtensionHeader.CreateInstance(nextHeader.Value, data, out numBytesRead);
if (extensionHeader == null)
break;
headers.Add(extensionHeader);
nextHeader = extensionHeader.NextHeader;
data = data.Subsegment(numBytesRead, data.Length - numBytesRead);
}
Headers = headers.AsReadOnly();
IsValid = (!nextHeader.HasValue || !IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value));
}
private static readonly IpV6ExtensionHeaders _empty = new IpV6ExtensionHeaders();
public void Write(byte[] buffer, int offset)
{
foreach (IpV6ExtensionHeader extensionHeader in this)
extensionHeader.Write(buffer, ref offset);
}
}
}
......@@ -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
......@@ -18,7 +18,7 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+----------------------------------------------------------------------+
/// </pre>
/// </summary>
public class IpV6ExtensionHeaderFragmentData : IpV6ExtensionHeader
public class IpV6ExtensionHeaderFragmentData : IpV6ExtensionHeaderStandard
{
private static class DataOffset
{
......@@ -38,7 +38,7 @@ namespace PcapDotNet.Packets.IpV6
public const int FragmentOffset = 3;
}
public const int DataLength = DataOffset.Identification + sizeof(uint);
public const int ExtensionHeaderDataLength = DataOffset.Identification + sizeof(uint);
public const ushort MaxFragmentOffset = 0x1FFF;
......@@ -70,9 +70,19 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public uint Identification { get; private set; }
public override IpV4Protocol Protocol
{
get { return IpV4Protocol.FragmentHeaderForIpV6; }
}
internal override int DataLength
{
get { return ExtensionHeaderDataLength; }
}
internal static IpV6ExtensionHeaderFragmentData ParseData(IpV4Protocol nextHeader, DataSegment data)
{
if (data.Length != DataLength)
if (data.Length != ExtensionHeaderDataLength)
return null;
ushort fragmentOffset = (ushort)((data.ReadUShort(DataOffset.FragmentOffset, Endianity.Big) & DataMask.FragmentOffset) >> DataShift.FragmentOffset);
......@@ -81,6 +91,16 @@ namespace PcapDotNet.Packets.IpV6
return new IpV6ExtensionHeaderFragmentData(nextHeader, fragmentOffset, moreFragments, identification);
}
internal override void WriteData(byte[] buffer, int offset)
{
ushort fragmentOffsetAndMoreFragments = (ushort)(FragmentOffset << DataShift.FragmentOffset);
if (MoreFragments)
fragmentOffsetAndMoreFragments |= DataMask.MoreFragments;
buffer.Write(offset + DataOffset.FragmentOffset, fragmentOffsetAndMoreFragments, Endianity.Big);
buffer.Write(offset + DataOffset.Identification, Identification, Endianity.Big);
}
}
public enum IpV6MobilityHeaderType : byte
......@@ -199,8 +219,12 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+---------------------------------------+
/// </pre>
/// </summary>
public abstract class IpV6ExtensionHeaderMobility : IpV6ExtensionHeader
public abstract class IpV6ExtensionHeaderMobility : IpV6ExtensionHeaderStandard
{
public override IpV4Protocol Protocol
{
get { return IpV4Protocol.MobilityHeader; }
}
private static class DataOffset
{
public const int MobilityHeaderType = 0;
......@@ -216,7 +240,14 @@ namespace PcapDotNet.Packets.IpV6
Checksum = checksum;
MobilityOptions = mobilityOptions;
}
internal override sealed int DataLength
{
get { return MinimumDataLength + MessageDataLength; }
}
internal abstract int MessageDataLength { get; }
/// <summary>
/// Identifies the particular mobility message in question.
/// An unrecognized MH Type field causes an error indication to be sent.
......@@ -327,6 +358,15 @@ namespace PcapDotNet.Packets.IpV6
return null;
}
}
internal override sealed void WriteData(byte[] buffer, int offset)
{
buffer.Write(offset + DataOffset.MobilityHeaderType, (byte)MobilityHeaderType);
buffer.Write(offset + DataOffset.Checksum, Checksum, Endianity.Big);
WriteMessageData(buffer, offset + DataOffset.MessageData);
}
internal abstract void WriteMessageData(byte[] buffer, int offset);
}
/// <summary>
......@@ -362,6 +402,11 @@ namespace PcapDotNet.Packets.IpV6
{
}
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
/// <summary>
/// Identifies the particular mobility message in question.
/// An unrecognized MH Type field causes an error indication to be sent.
......@@ -379,6 +424,11 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityBindingRefreshRequest(nextHeader, checksum, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -435,6 +485,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ulong HomeInitCookie { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityHomeTestInit ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -444,6 +499,12 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityHomeTestInit(nextHeader, checksum, homeInitCookie, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.HomeInitCookie, HomeInitCookie, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -500,6 +561,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ulong CareOfInitCookie { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityCareOfTestInit ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -509,6 +575,12 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityCareOfTestInit(nextHeader, checksum, careOfInitCookie, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.CareOfInitCookie, CareOfInitCookie, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -585,6 +657,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ulong HomeKeygenToken { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityHomeTest ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -596,6 +673,14 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityHomeTest(nextHeader, checksum, homeNonceIndex, homeInitCookie, homeKeygenToken, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.HomeNonceIndex, HomeNonceIndex, Endianity.Big);
buffer.Write(offset + MessageDataOffset.HomeInitCookie, HomeInitCookie, Endianity.Big);
buffer.Write(offset + MessageDataOffset.HomeKeygenToken, HomeKeygenToken, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -672,6 +757,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ulong CareOfKeygenToken { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityCareOfTest ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -683,6 +773,14 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityCareOfTest(nextHeader, checksum, careOfNonceIndex, careOfInitCookie, careOfKeygenToken, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.CareOfNonceIndex, CareOfNonceIndex, Endianity.Big);
buffer.Write(offset + MessageDataOffset.CareOfInitCookie, CareOfInitCookie, Endianity.Big);
buffer.Write(offset + MessageDataOffset.CareOfKeygenToken, CareOfKeygenToken, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -789,6 +887,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ushort Lifetime { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static bool ParseMessageDataToFields(DataSegment messageData, out ushort sequenceNumber,
out bool acknowledge, out bool homeRegistration, out bool linkLocalAddressCompatibility,
out bool keyManagementMobilityCapability, out ushort lifetime, out IpV6MobilityOptions options)
......@@ -815,6 +918,25 @@ namespace PcapDotNet.Packets.IpV6
options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return true;
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.SequenceNumber, SequenceNumber, Endianity.Big);
byte flags = 0;
if (Acknowledge)
flags |= MessageDataMask.Acknowledge;
if (HomeRegistration)
flags |= MessageDataMask.HomeRegistration;
if (LinkLocalAddressCompatibility)
flags |= MessageDataMask.LinkLocalAddressCompatibility;
if (KeyManagementMobilityCapability)
flags |= MessageDataMask.KeyManagementMobilityCapability;
buffer.Write(offset + MessageDataOffset.Acknowledge, flags);
buffer.Write(offset + MessageDataOffset.Lifetime, Lifetime, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -1255,6 +1377,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ushort Lifetime { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static bool ParseMessageDataFields(DataSegment messageData, out IpV6BindingAcknowledgementStatus status,
out bool keyManagementMobilityCapability, out ushort sequenceNumber, out ushort lifetime,
out IpV6MobilityOptions options)
......@@ -1278,6 +1405,16 @@ namespace PcapDotNet.Packets.IpV6
options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return true;
}
internal override sealed void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.Status, (byte)Status);
if (KeyManagementMobilityCapability)
buffer.Write(offset + MessageDataOffset.KeyManagementMobilityCapability, MessageDataMask.KeyManagementMobilityCapability);
buffer.Write(offset + MessageDataOffset.SequenceNumber, SequenceNumber, Endianity.Big);
buffer.Write(offset + MessageDataOffset.Lifetime, Lifetime, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -1416,6 +1553,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public IpV6Address HomeAddress { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityBindingError ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -1426,6 +1568,13 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityBindingError(nextHeader, checksum, status, homeAddress, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.Status, (byte)Status);
buffer.Write(offset + MessageDataOffset.HomeAddress, HomeAddress, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -1586,6 +1735,11 @@ namespace PcapDotNet.Packets.IpV6
get { return IpV6MobilityHeaderType.FastNeighborAdvertisement; }
}
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityFastNeighborAdvertisement ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -1594,6 +1748,11 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityFastNeighborAdvertisement(nextHeader, checksum, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -1635,10 +1794,20 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public DataSegment MessageData { get; private set; }
internal override int MessageDataLength
{
get { return MessageData.Length; }
}
internal static IpV6ExtensionHeaderMobilityExperimental ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
return new IpV6ExtensionHeaderMobilityExperimental(nextHeader, checksum, messageData);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
MessageData.Write(buffer, offset);
}
}
/// <summary>
......@@ -1699,6 +1868,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ReadOnlyCollection<IpV6Address> HomeAgentAddresses { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + HomeAgentAddresses.Count * IpV6Address.SizeOf + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityHomeAgentSwitchMessage ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -1717,6 +1891,14 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(optionsOffset, messageData.Length - optionsOffset));
return new IpV6ExtensionHeaderMobilityHomeAgentSwitchMessage(nextHeader, checksum, homeAgentAddresses, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.NumberOfAddresses, (byte)HomeAgentAddresses.Count);
for (int i = 0; i != HomeAgentAddresses.Count; ++i)
buffer.Write(offset + MessageDataOffset.HomeAgentAddresses + i * IpV6Address.SizeOf, HomeAgentAddresses[i], Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.HomeAgentAddresses + HomeAgentAddresses.Count * IpV6Address.SizeOf);
}
}
/// <summary>
......@@ -1794,6 +1976,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public uint SequenceNumber { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityHeartbeatMessage ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -1805,6 +1992,19 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.MobilityOptions, messageData.Length - MessageDataOffset.MobilityOptions));
return new IpV6ExtensionHeaderMobilityHeartbeatMessage(nextHeader, checksum, isUnsolicitedHeartbeatResponse, isResponse, sequenceNumber, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
byte isUnsolicitedHeartbeatResponseAndIsResponse = 0;
if (IsUnsolicitedHeartbeatResponse)
isUnsolicitedHeartbeatResponseAndIsResponse |= MessageDataMask.IsUnsolicitedHeartbeatResponse;
if (IsResponse)
isUnsolicitedHeartbeatResponseAndIsResponse |= MessageDataMask.IsResponse;
buffer.Write(MessageDataOffset.IsUnsolicitedHeartbeatResponse, isUnsolicitedHeartbeatResponseAndIsResponse);
buffer.Write(offset + MessageDataOffset.SequenceNumber, SequenceNumber, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.MobilityOptions);
}
}
public enum IpV6HandoverInitiateMessageCode : byte
......@@ -1842,7 +2042,7 @@ namespace PcapDotNet.Packets.IpV6
public const int AssignedAddressConfiguration = SequenceNumber + sizeof(ushort);
public const int Buffer = AssignedAddressConfiguration;
public const int Code = Buffer + sizeof(byte);
public const int MobilityOptions = Code + sizeof(byte);
public const int Options = Code + sizeof(byte);
}
private static class MessageDataMask
......@@ -1851,7 +2051,7 @@ namespace PcapDotNet.Packets.IpV6
public const byte Buffer = 0x40;
}
public const int MinimumMessageDataLength = MessageDataOffset.MobilityOptions;
public const int MinimumMessageDataLength = MessageDataOffset.Options;
public IpV6ExtensionHeaderMobilityHandoverInitiateMessage(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool assignedAddressConfiguration,
bool buffer, IpV6HandoverInitiateMessageCode code,
......@@ -1896,6 +2096,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public IpV6HandoverInitiateMessageCode Code { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityHandoverInitiateMessage ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -1906,9 +2111,24 @@ namespace PcapDotNet.Packets.IpV6
MessageDataMask.AssignedAddressConfiguration);
bool buffer = messageData.ReadBool(MessageDataOffset.Buffer, MessageDataMask.Buffer);
IpV6HandoverInitiateMessageCode code = (IpV6HandoverInitiateMessageCode)messageData[MessageDataOffset.Code];
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.MobilityOptions, messageData.Length - MessageDataOffset.MobilityOptions));
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityHandoverInitiateMessage(nextHeader, checksum, sequenceNumber, assignedAddressConfiguration, buffer, code, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.SequenceNumber, SequenceNumber, Endianity.Big);
byte assignedAddressConfigurationAndBuffer = 0;
if (AssignedAddressConfiguration)
assignedAddressConfigurationAndBuffer |= MessageDataMask.AssignedAddressConfiguration;
if (Buffer)
assignedAddressConfigurationAndBuffer |= MessageDataMask.Buffer;
buffer.Write(offset + MessageDataOffset.AssignedAddressConfiguration, assignedAddressConfigurationAndBuffer);
buffer.Write(offset + MessageDataOffset.Code, (byte)Code);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
public enum IpV6MobilityHandoverAcknowledgeCode : byte
......@@ -1981,10 +2201,10 @@ namespace PcapDotNet.Packets.IpV6
{
public const int SequenceNumber = 0;
public const int Code = SequenceNumber + sizeof(ushort) + sizeof(byte);
public const int MobilityOptions = Code + sizeof(byte);
public const int Options = Code + sizeof(byte);
}
public const int MinimumMessageDataLength = MessageDataOffset.MobilityOptions;
public const int MinimumMessageDataLength = MessageDataOffset.Options;
public IpV6ExtensionHeaderMobilityHandoverAcknowledgeMessage(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber,
IpV6MobilityHandoverAcknowledgeCode code, IpV6MobilityOptions options)
......@@ -2014,6 +2234,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public IpV6MobilityHandoverAcknowledgeCode Code { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityHandoverAcknowledgeMessage ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -2021,9 +2246,16 @@ namespace PcapDotNet.Packets.IpV6
ushort sequenceNumber = messageData.ReadUShort(MessageDataOffset.SequenceNumber, Endianity.Big);
IpV6MobilityHandoverAcknowledgeCode code = (IpV6MobilityHandoverAcknowledgeCode)messageData[MessageDataOffset.Code];
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.MobilityOptions, messageData.Length - MessageDataOffset.MobilityOptions));
IpV6MobilityOptions options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return new IpV6ExtensionHeaderMobilityHandoverAcknowledgeMessage(nextHeader, checksum, sequenceNumber, code, options);
}
internal override void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.SequenceNumber, SequenceNumber, Endianity.Big);
buffer.Write(offset + MessageDataOffset.Code, (byte)Code);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
public enum IpV6MobilityBindingRevocationType : byte
......@@ -2072,10 +2304,10 @@ namespace PcapDotNet.Packets.IpV6
public const int ProxyBinding = SequenceNumber + sizeof(ushort);
public const int IpV4HomeAddressBindingOnly = ProxyBinding;
public const int Global = IpV4HomeAddressBindingOnly;
public const int MobilityOptions = Global + sizeof(byte) + sizeof(byte);
public const int Options = Global + sizeof(byte) + sizeof(byte);
}
public const int MinimumMessageDataLength = MessageDataOffset.MobilityOptions;
public const int MinimumMessageDataLength = MessageDataOffset.Options;
private static class MessageDataMask
{
......@@ -2139,6 +2371,13 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public bool Global { get; private set; }
internal abstract byte RevocationTriggerOrStatus { get; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static IpV6ExtensionHeaderMobilityBindingRevocationMessage ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -2151,7 +2390,7 @@ namespace PcapDotNet.Packets.IpV6
bool ipV4HomeAddressBindingOnly = messageData.ReadBool(MessageDataOffset.IpV4HomeAddressBindingOnly, MessageDataMask.IpV4HomeAddressBindingOnly);
bool global = messageData.ReadBool(MessageDataOffset.Global, MessageDataMask.Global);
IpV6MobilityOptions options =
new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.MobilityOptions, messageData.Length - MessageDataOffset.MobilityOptions));
new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
switch (bindingRevocationType)
{
case IpV6MobilityBindingRevocationType.BindingRevocationIndication:
......@@ -2168,6 +2407,24 @@ namespace PcapDotNet.Packets.IpV6
return null;
}
}
internal override sealed void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.BindingRevocationType, (byte)BindingRevocationType);
buffer.Write(offset + MessageDataOffset.RevocationTriggerOrStatus, RevocationTriggerOrStatus);
buffer.Write(offset + MessageDataOffset.SequenceNumber, SequenceNumber, Endianity.Big);
byte flags = 0;
if (ProxyBinding)
flags |= MessageDataMask.ProxyBinding;
if (IpV4HomeAddressBindingOnly)
flags |= MessageDataMask.IpV4HomeAddressBindingOnly;
if (Global)
flags |= MessageDataMask.Global;
buffer.Write(offset + MessageDataOffset.ProxyBinding, flags);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......@@ -2278,6 +2535,11 @@ namespace PcapDotNet.Packets.IpV6
/// Indicating the event that triggered the initiator to send the BRI message.
/// </summary>
public Ipv6MobilityBindingRevocationTrigger RevocationTrigger { get; private set; }
internal override byte RevocationTriggerOrStatus
{
get { return (byte)RevocationTrigger; }
}
}
/// <summary>
......@@ -2383,6 +2645,11 @@ namespace PcapDotNet.Packets.IpV6
/// Indicating the result of processing the Binding Revocation Indication message by the responder.
/// </summary>
public Ipv6MobilityBindingRevocationStatus Status { get; private set; }
internal override byte RevocationTriggerOrStatus
{
get { return (byte)Status; }
}
}
/// <summary>
......@@ -2399,7 +2666,7 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+---------------------------------------+
/// | 48 | Sequence # |
/// +-----+---------------------------------------+
/// | 64 | |
/// | 64 | Reserved |
/// +-----+---------------------------------------+
/// | 80 | Lifetime |
/// +-----+---------------------------------------+
......@@ -2419,10 +2686,10 @@ namespace PcapDotNet.Packets.IpV6
{
public const int SequenceNumber = 0;
public const int Lifetime = SequenceNumber + sizeof(ushort) + sizeof(ushort);
public const int MobilityOptions = Lifetime + sizeof(ushort);
public const int Options = Lifetime + sizeof(ushort);
}
public const int MinimumMessageDataLength = MessageDataOffset.MobilityOptions;
public const int MinimumMessageDataLength = MessageDataOffset.Options;
public IpV6ExtensionHeaderMobilityLocalizedRouting(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, ushort lifetime,
IpV6MobilityOptions options)
......@@ -2447,6 +2714,11 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ushort Lifetime { get; private set; }
internal override int MessageDataLength
{
get { return MinimumMessageDataLength + MobilityOptions.BytesLength; }
}
internal static bool ParseMessageDataToFields(DataSegment messageData, out ushort sequenceNumber, out ushort lifetime, out IpV6MobilityOptions options)
{
if (messageData.Length < MinimumMessageDataLength)
......@@ -2459,9 +2731,16 @@ namespace PcapDotNet.Packets.IpV6
sequenceNumber = messageData.ReadUShort(MessageDataOffset.SequenceNumber, Endianity.Big);
lifetime = messageData.ReadUShort(MessageDataOffset.Lifetime, Endianity.Big);
options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.MobilityOptions, messageData.Length - MessageDataOffset.MobilityOptions));
options = new IpV6MobilityOptions(messageData.Subsegment(MessageDataOffset.Options, messageData.Length - MessageDataOffset.Options));
return true;
}
internal override sealed void WriteMessageData(byte[] buffer, int offset)
{
buffer.Write(offset + MessageDataOffset.SequenceNumber, SequenceNumber, Endianity.Big);
buffer.Write(offset + MessageDataOffset.Lifetime, Lifetime, Endianity.Big);
MobilityOptions.Write(buffer, offset + MessageDataOffset.Options);
}
}
/// <summary>
......
......@@ -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