Commit 136c0df1 authored by Brickner_cp's avatar Brickner_cp

IPv6

parent 931704eb
......@@ -85,6 +85,9 @@
<Compile Include="WiresharkDatagramComparerIcmp.cs" />
<Compile Include="WiresharkDatagramComparerIgmp.cs" />
<Compile Include="WiresharkDatagramComparerIpV4.cs" />
<Compile Include="WiresharkDatagramComparerIpV6.cs" />
<Compile Include="WiresharkDatagramComparerIpV6AuthenticationHeader.cs" />
<Compile Include="WiresharkDatagramComparerIpV6MobilityHeader.cs" />
<Compile Include="WiresharkDatagramComparerSimple.cs" />
<Compile Include="WiresharkDatagramComparerTcp.cs" />
<Compile Include="WiresharkDatagramComparerUdp.cs" />
......
......@@ -14,6 +14,7 @@ using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.Packets.TestUtils;
using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils;
......@@ -233,7 +234,7 @@ namespace PcapDotNet.Core.Test
}
ethernetBaseLayer.EtherType = EthernetType.None;
switch (random.NextInt(0, 5))
switch (random.NextInt(0, 7))
{
case 0: // VLanTaggedFrame.
case 1:
......@@ -253,7 +254,14 @@ namespace PcapDotNet.Core.Test
case 4:
IpV4Layer ipV4Layer = random.NextIpV4Layer();
layers.Add(ipV4Layer);
CreateRandomIpV4Payload(random, ipV4Layer, layers);
CreateRandomIpPayload(random, ipV4Layer, layers);
return;
case 5: // IPv6
case 6:
IpV6Layer ipV6Layer = random.NextIpV6Layer();
layers.Add(ipV6Layer);
CreateRandomIpPayload(random, ipV6Layer, layers);
return;
default:
......@@ -261,8 +269,16 @@ namespace PcapDotNet.Core.Test
}
}
private static void CreateRandomIpV4Payload(Random random, IpV4Layer ipV4Layer, List<ILayer> layers)
private static void CreateRandomIpPayload(Random random, Layer ipLayer, List<ILayer> layers)
{
IpV6Layer ipV6Layer = ipLayer as IpV6Layer;
if (ipV6Layer != null)
{
var headers = ipV6Layer.ExtensionHeaders.Headers;
if (headers.Any() && headers.Last().Protocol == IpV4Protocol.EncapsulatingSecurityPayload)
return;
}
if (random.NextBool(20))
{
// Finish with payload.
......@@ -271,44 +287,55 @@ namespace PcapDotNet.Core.Test
return;
}
ipV4Layer.Protocol = null;
if (random.NextBool())
ipV4Layer.Fragmentation = IpV4Fragmentation.None;
IpV4Layer ipV4Layer = ipLayer as IpV4Layer;
if (ipV4Layer != null)
{
ipV4Layer.Protocol = null;
if (random.NextBool())
ipV4Layer.Fragmentation = IpV4Fragmentation.None;
}
switch (random.Next(0, 9))
switch (random.Next(0, 11))
{
case 0: // IpV4.
case 1:
IpV4Layer innerIpV4Layer = random.NextIpV4Layer();
layers.Add(innerIpV4Layer);
CreateRandomIpV4Payload(random, innerIpV4Layer, layers);
CreateRandomIpPayload(random, innerIpV4Layer, layers);
return;
case 2: // IpV6.
case 3:
IpV6Layer innerIpV6Layer = random.NextIpV6Layer();
layers.Add(innerIpV6Layer);
CreateRandomIpPayload(random, innerIpV6Layer, layers);
return;
case 2: // Igmp.
case 4: // Igmp.
layers.Add(random.NextIgmpLayer());
return;
case 3: // Icmp.
case 5: // Icmp.
IcmpLayer icmpLayer = random.NextIcmpLayer();
layers.Add(icmpLayer);
layers.AddRange(random.NextIcmpPayloadLayers(icmpLayer));
return;
case 4: // Gre.
case 6: // Gre.
GreLayer greLayer = random.NextGreLayer();
layers.Add(greLayer);
CreateRandomEthernetPayload(random, greLayer, layers);
return;
case 5: // Udp.
case 6:
case 7: // Udp.
case 8:
UdpLayer udpLayer = random.NextUdpLayer();
layers.Add(udpLayer);
CreateRandomUdpPayload(random, udpLayer, layers);
return;
case 7: // Tcp.
case 8:
case 9: // Tcp.
case 10:
TcpLayer tcpLayer = random.NextTcpLayer();
layers.Add(tcpLayer);
CreateRandomTcpPayload(random, tcpLayer, layers);
......@@ -438,7 +465,7 @@ namespace PcapDotNet.Core.Test
try
{
Compare(XDocument.Load(fixedDocumentFilename,LoadOptions.None), packets);
Compare(XDocument.Load(fixedDocumentFilename, LoadOptions.None), packets);
}
catch (AssertFailedException exception)
{
......@@ -482,14 +509,20 @@ namespace PcapDotNet.Core.Test
private static void ComparePacket(Packet packet, XElement documentPacket)
{
object currentDatagram = packet;
CompareProtocols(currentDatagram, documentPacket);
CompareProtocols(currentDatagram, documentPacket, true);
}
internal static void CompareProtocols(object currentDatagram, XElement layersContainer)
internal static void CompareProtocols(object currentDatagram, XElement layersContainer, bool parentLayerSuccess)
{
Dictionary<string, int> layerNameToCount = new Dictionary<string, int>();
foreach (var layer in layersContainer.Protocols())
{
switch (layer.Name())
string layerName = layer.Name();
if (!layerNameToCount.ContainsKey(layerName))
layerNameToCount[layerName] = 1;
else
++layerNameToCount[layerName];
switch (layerName)
{
case "geninfo":
case "raw":
......@@ -500,7 +533,7 @@ namespace PcapDotNet.Core.Test
break;
default:
var comparer = WiresharkDatagramComparer.GetComparer(layer.Name());
var comparer = WiresharkDatagramComparer.GetComparer(layer.Name(), layerNameToCount[layerName], parentLayerSuccess);
if (comparer == null)
return;
currentDatagram = comparer.Compare(layer, currentDatagram);
......
using System.Reflection;
using System;
using System.Reflection;
using System.Xml.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets;
......@@ -9,11 +10,20 @@ namespace PcapDotNet.Core.Test
{
public Datagram Compare(XElement layer, object datagramParent)
{
PropertyInfo property = datagramParent.GetType().GetProperty(PropertyName);
if (property == null)
return null;
Datagram datagram;
if (PropertyName == "")
{
datagram = (Datagram)datagramParent;
datagramParent = null;
}
else
{
PropertyInfo property = datagramParent.GetType().GetProperty(PropertyName);
if (property == null)
return null;
Datagram datagram = (Datagram)property.GetValue(datagramParent);
datagram = (Datagram)property.GetValue(datagramParent);
}
if (Ignore(datagram))
return null;
......@@ -32,16 +42,20 @@ namespace PcapDotNet.Core.Test
protected void CompareDatagram(XElement layer, Datagram parentDatagram, Datagram datagram)
{
foreach (var field in layer.Fields())
bool success = true;
foreach (var element in layer.Fields())
{
if (!CompareField(field, parentDatagram, datagram))
if (!CompareField(element, parentDatagram, datagram))
{
success = false;
break;
}
}
WiresharkCompareTests.CompareProtocols(datagram, layer);
WiresharkCompareTests.CompareProtocols(datagram, layer, success);
}
public static WiresharkDatagramComparer GetComparer(string name)
public static WiresharkDatagramComparer GetComparer(string name, int count, bool parentLayerSuccess)
{
switch (name)
{
......@@ -57,6 +71,17 @@ namespace PcapDotNet.Core.Test
case "ip":
return new WiresharkDatagramComparerIpV4();
case "ipv6":
return new WiresharkDatagramComparerIpV6();
case "ah":
if (parentLayerSuccess)
return new WiresharkDatagramComparerIpV6AuthenticationHeader(count);
return null;
case "mipv6":
return new WiresharkDatagramComparerIpV6MobilityHeader();
case "igmp":
return new WiresharkDatagramComparerIgmp();
......
using System;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
namespace PcapDotNet.Core.Test
{
internal class WiresharkDatagramComparerIpV6AuthenticationHeader : WiresharkDatagramComparerSimple
{
public WiresharkDatagramComparerIpV6AuthenticationHeader(int count)
{
_count = count;
}
protected override string PropertyName
{
get { return ""; }
}
protected override bool CompareField(XElement field, Datagram datagram)
{
IpV6Datagram ipV6Datagram = datagram as IpV6Datagram;
if (ipV6Datagram == null)
return true;
while (_count > 0)
{
do
{
++_currentExtensionHeaderIndex;
} while (ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex].Protocol != IpV4Protocol.AuthenticationHeader);
--_count;
}
IpV6ExtensionHeaderAuthentication authenticationHeader = (IpV6ExtensionHeaderAuthentication)ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex];
switch (field.Name())
{
case "":
string[] headerFieldShowParts = field.Show().Split(':');
string headerFieldShowName = headerFieldShowParts[0];
string headerFieldShowValue = headerFieldShowParts[1];
switch (headerFieldShowName)
{
case "Next Header":
field.AssertValue((byte)authenticationHeader.NextHeader.Value);
break;
case "Length":
Assert.AreEqual(string.Format(" {0}", authenticationHeader.Length), headerFieldShowValue);
break;
default:
throw new InvalidOperationException("Invalid ipv6 authentication header unnamed field show name " + headerFieldShowName);
}
break;
case "ah.spi":
field.AssertShowHex(authenticationHeader.SecurityParametersIndex);
break;
case "ah.sequence":
field.AssertShowDecimal(authenticationHeader.SequenceNumber);
break;
case "ah.icv":
field.AssertValue(authenticationHeader.AuthenticationData);
break;
default:
throw new InvalidOperationException(string.Format("Invalid ipv6 authentication header field {0}", field.Name()));
}
return true;
}
private int _currentExtensionHeaderIndex = -1;
private int _count;
}
}
\ No newline at end of file
......@@ -10,6 +10,6 @@ namespace PcapDotNet.Core.Test
return CompareField(field, datagram);
}
protected abstract bool CompareField(XElement field, Datagram parentDatagram);
protected abstract bool CompareField(XElement field, Datagram datagram);
}
}
\ No newline at end of file
......@@ -7,6 +7,7 @@ using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Core.Test
{
......@@ -167,6 +168,11 @@ namespace PcapDotNet.Core.Test
Assert.AreEqual(expectedValue, element.Value(), message ?? element.Name());
}
public static void AssertValueInRange(this XElement element, string expectedMinimumValue, string expectedMaximumValue)
{
MoreAssert.IsInRange(expectedMinimumValue, expectedMaximumValue, element.Value());
}
public static void AssertValue(this XElement element, IEnumerable<byte> expectedValue, string message = null)
{
element.AssertValue(expectedValue.BytesSequenceToHexadecimalString(), message);
......@@ -187,11 +193,21 @@ namespace PcapDotNet.Core.Test
element.AssertValue(expectedValue.ToString("x8"));
}
public static void AssertValueInRange(this XElement element, uint expectedMinimumValue, uint expectedMaximumValue)
{
element.AssertValueInRange(expectedMinimumValue.ToString("x8"), expectedMaximumValue.ToString("x8"));
}
public static void AssertValue(this XElement element, UInt48 expectedValue)
{
element.AssertValue(expectedValue.ToString("x12"));
}
public static void AssertValue(this XElement element, ulong expectedValue)
{
element.AssertValue(expectedValue.ToString("x16"));
}
public static void AssertValue(this XElement element, SerialNumber32 expectedValue)
{
element.AssertValue(expectedValue.Value);
......
......@@ -143,13 +143,14 @@ namespace PcapDotNet.Packets.TestUtils
case IpV6MobilityHeaderType.BindingUpdate: // 5
return new IpV6ExtensionHeaderMobilityBindingUpdate(nextHeader, checksum, random.NextUShort(), random.NextBool(), random.NextBool(),
random.NextBool(), random.NextBool(), random.NextUShort(),
random.NextIpV6MobilityOptions());
random.NextBool(), random.NextBool(), random.NextBool(), random.NextBool(),
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());
random.NextBool(), random.NextBool(), random.NextBool(), random.NextBool(),
random.NextUShort(), random.NextUShort(), random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.BindingError: // 7
return new IpV6ExtensionHeaderMobilityBindingError(nextHeader, checksum, random.NextEnum<IpV6BindingErrorStatus>(), random.NextIpV6Address(),
......@@ -343,8 +344,11 @@ namespace PcapDotNet.Packets.TestUtils
random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.MobileNodeIdentifier:
return new IpV6MobilityOptionMobileNodeIdentifier(random.NextEnum<IpV6MobileNodeIdentifierSubtype>(),
random.NextDataSegment(random.NextInt(0, 100)));
IpV6MobileNodeIdentifierSubtype mobileNodeIdentifierSubtype = random.NextEnum<IpV6MobileNodeIdentifierSubtype>();
return new IpV6MobilityOptionMobileNodeIdentifier(
mobileNodeIdentifierSubtype,
random.NextDataSegment(random.NextInt(mobileNodeIdentifierSubtype == IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier ? 1 : 0,
100)));
case IpV6MobilityOptionType.Authentication:
return new IpV6MobilityOptionAuthentication(random.NextEnum<IpV6AuthenticationSubtype>(), random.NextUInt(),
......@@ -382,7 +386,7 @@ namespace PcapDotNet.Packets.TestUtils
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)));
return new IpV6MobilityOptionServiceSelection(random.NextDataSegment(random.NextInt(1, 100)));
case IpV6MobilityOptionType.BindingAuthorizationDataForFmIpV6:
return new IpV6MobilityOptionBindingAuthorizationDataForFmIpV6(random.NextUInt(), random.NextDataSegment(random.NextInt(0, 100)));
......@@ -530,7 +534,7 @@ namespace PcapDotNet.Packets.TestUtils
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, 50)));
return new IpV6FlowIdentificationSubOptionTrafficSelector(random.NextEnum<IpV6FlowIdentificationTrafficSelectorFormat>(), random.NextDataSegment(random.NextInt(0, 40)));
default:
throw new InvalidOperationException(string.Format("Invalid optionType value {0}", optionType));
......
......@@ -221,7 +221,7 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
IntegratedNetLayerSecurityProtocol = 0x34,
/// <summary>
/// IP with Encryption
/// IP with Encryption.
/// </summary>
Swipe = 0x35,
/// <summary>
......
......@@ -3,35 +3,52 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
/// RFC 6275.
/// RFC 3963, 5213, 5845, 6275.
/// <pre>
/// +-----+-------------+---+---------------------+
/// | Bit | 0-7 | 8 | 9-15 |
/// +-----+-------------+---+---------------------+
/// | 0 | Next Header | Header Extension Length |
/// +-----+-------------+-------------------------+
/// | 16 | MH Type | Reserved |
/// +-----+-------------+-------------------------+
/// | 32 | Checksum |
/// +-----+-------------+---+---------------------+
/// | 48 | Status | K | Reserved |
/// +-----+-------------+---+---------------------+
/// | 64 | Sequence # |
/// +-----+---------------------------------------+
/// | 80 | Lifetime |
/// +-----+---------------------------------------+
/// | 96 | Mobility Options |
/// | ... | |
/// +-----+---------------------------------------+
/// +-----+-------------+---+---+----+----+---------+
/// | Bit | 0-7 | 8 | 9 | 10 | 11 | 12-15 |
/// +-----+-------------+---+---+----+----+---------+
/// | 0 | Next Header | Header Extension Length |
/// +-----+-------------+---------------------------+
/// | 16 | MH Type | Reserved |
/// +-----+-------------+---------------------------+
/// | 32 | Checksum |
/// +-----+-------------+---+---+---+----+----------+
/// | 48 | Status | K | R | P | T | Reserved |
/// +-----+-------------+---+---+---+----+----------+
/// | 64 | Sequence # |
/// +-----+-----------------------------------------+
/// | 80 | Lifetime |
/// +-----+-----------------------------------------+
/// | 96 | Mobility Options |
/// | ... | |
/// +-----+-----------------------------------------+
/// </pre>
/// </summary>
public sealed class IpV6ExtensionHeaderMobilityBindingAcknowledgement : IpV6ExtensionHeaderMobilityBindingAcknowledgementBase
{
private static class MessageDataOffset
{
public const int MobileRouter = sizeof(byte);
public const int ProxyRegistration = MobileRouter;
public const int TlvHeaderFormat = ProxyRegistration;
}
private static class MessageDataMask
{
public const byte MobileRouter = 0x40;
public const byte ProxyRegistration = 0x20;
public const byte TlvHeaderFormat = 0x10;
}
public IpV6ExtensionHeaderMobilityBindingAcknowledgement(IpV4Protocol nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
bool keyManagementMobilityCapability, ushort sequenceNumber, ushort lifetime,
IpV6MobilityOptions options)
bool keyManagementMobilityCapability, bool mobileRouter, bool proxyRegistration,
bool tlvHeaderFormat, ushort sequenceNumber, ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, status, keyManagementMobilityCapability, sequenceNumber, lifetime, options)
{
MobileRouter = mobileRouter;
ProxyRegistration = proxyRegistration;
TlvHeaderFormat = tlvHeaderFormat;
}
/// <summary>
......@@ -43,6 +60,23 @@ namespace PcapDotNet.Packets.IpV6
get { return IpV6MobilityHeaderType.BindingAcknowledgement; }
}
/// <summary>
/// Indicates that the Home Agent that processed the Binding Update supports Mobile Routers.
/// True only if the corresponding Binding Update had the Mobile Router set to true.
/// </summary>
public bool MobileRouter { get; private set; }
/// <summary>
/// Indicates that the local mobility anchor that processed the corresponding Proxy Binding Update message supports proxy registrations.
/// True only if the corresponding Proxy Binding Update had the Proxy Registration set to true.
/// </summary>
public bool ProxyRegistration { get; private set; }
/// <summary>
/// Indicates that the sender of the Proxy Binding Acknowledgement, the LMA, supports tunneling IPv6-or-IPv4 in IPv4 using TLV-header format.
/// </summary>
public bool TlvHeaderFormat { get; private set; }
internal static IpV6ExtensionHeaderMobilityBindingAcknowledgement ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
IpV6BindingAcknowledgementStatus status;
......@@ -53,8 +87,12 @@ namespace PcapDotNet.Packets.IpV6
if (!ParseMessageDataFields(messageData, out status, out keyManagementMobilityCapability, out sequenceNumber, out lifetime, out options))
return null;
return new IpV6ExtensionHeaderMobilityBindingAcknowledgement(nextHeader, checksum, status, keyManagementMobilityCapability, sequenceNumber, lifetime,
options);
bool mobileRouter = messageData.ReadBool(MessageDataOffset.MobileRouter, MessageDataMask.MobileRouter);
bool proxyRegistration = messageData.ReadBool(MessageDataOffset.ProxyRegistration, MessageDataMask.ProxyRegistration);
bool tlvHeaderFormat = messageData.ReadBool(MessageDataOffset.TlvHeaderFormat, MessageDataMask.TlvHeaderFormat);
return new IpV6ExtensionHeaderMobilityBindingAcknowledgement(nextHeader, checksum, status, keyManagementMobilityCapability, mobileRouter,
proxyRegistration, tlvHeaderFormat, sequenceNumber, lifetime, options);
}
}
}
\ No newline at end of file
......@@ -39,7 +39,7 @@ namespace PcapDotNet.Packets.IpV6
/// <summary>
/// Defines the type of the Binding Revocation Message.
/// </summary>
public override sealed IpV6MobilityBindingRevocationType BindingRevocationType
public override IpV6MobilityBindingRevocationType BindingRevocationType
{
get { return IpV6MobilityBindingRevocationType.BindingRevocationIndication; }
}
......
......@@ -3,36 +3,63 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
/// RFC 6275.
/// RFCs 3963, 4140, 5213, 5380, 5555, 5845, 6275, 6602.
/// <pre>
/// +-----+---+---+---+---+-----+-------------------------+
/// | Bit | 0 | 1 | 2 | 3 | 4-7 | 8-15 |
/// +-----+---+---+---+---+-----+-------------------------+
/// | 0 | Next Header | Header Extension Length |
/// +-----+---------------------+-------------------------+
/// | 16 | MH Type | Reserved |
/// +-----+---------------------+-------------------------+
/// | 32 | Checksum |
/// +-----+-----------------------------------------------+
/// | 48 | Sequence # |
/// +-----+---+---+---+---+-------------------------------+
/// | 64 | A | H | L | K | Reserved |
/// +-----+---+---+---+---+-------------------------------+
/// | 80 | Lifetime |
/// +-----+-----------------------------------------------+
/// | 96 | Mobility Options |
/// | ... | |
/// +-----+-----------------------------------------------+
/// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10-15 |
/// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | 0 | Next Header | Header Extension Length |
/// +-----+-------------------------------+-------------------------+
/// | 16 | MH Type | Reserved |
/// +-----+-------------------------------+-------------------------+
/// | 32 | Checksum |
/// +-----+---------------------------------------------------------+
/// | 48 | Sequence # |
/// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | 64 | A | H | L | K | M | R | P | F | T | B | Reserved |
/// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | 80 | Lifetime |
/// +-----+---------------------------------------------------------+
/// | 96 | Mobility Options |
/// | ... | |
/// +-----+---------------------------------------------------------+
/// </pre>
/// </summary>
public sealed class IpV6ExtensionHeaderMobilityBindingUpdate : IpV6ExtensionHeaderMobilityBindingUpdateBase
{
private static class MessageDataOffset
{
public const int MapRegistration = sizeof(ushort);
public const int MobileRouter = MapRegistration;
public const int ProxyRegistrationFlag = MobileRouter;
public const int ForcingUdpEncapsulation = ProxyRegistrationFlag;
public const int TlvHeaderFormat = ForcingUdpEncapsulation + sizeof(byte);
public const int BulkBindingUpdate = TlvHeaderFormat;
}
private static class MessageDataMask
{
public const byte MapRegistration = 0x08;
public const byte MobileRouter = 0x04;
public const byte ProxyRegistrationFlag = 0x02;
public const byte ForcingUdpEncapsulation = 0x01;
public const byte TlvHeaderFormat = 0x80;
public const byte BulkBindingUpdate = 0x40;
}
public IpV6ExtensionHeaderMobilityBindingUpdate(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge, bool homeRegistration,
bool linkLocalAddressCompatibility, bool keyManagementMobilityCapability, ushort lifetime,
IpV6MobilityOptions options)
bool linkLocalAddressCompatibility, bool keyManagementMobilityCapability, bool mapRegistration,
bool mobileRouter, bool proxyRegistrationFlag, bool forcingUdpEncapsulation, bool tlvHeaderFormat,
bool bulkBindingUpdate, ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, sequenceNumber, acknowledge, homeRegistration, linkLocalAddressCompatibility, keyManagementMobilityCapability,
lifetime, options)
{
MapRegistration = mapRegistration;
MobileRouter = mobileRouter;
ProxyRegistrationFlag = proxyRegistrationFlag;
ForcingUdpEncapsulation = forcingUdpEncapsulation;
TlvHeaderFormat = tlvHeaderFormat;
BulkBindingUpdate = bulkBindingUpdate;
}
/// <summary>
......@@ -44,6 +71,45 @@ namespace PcapDotNet.Packets.IpV6
get { return IpV6MobilityHeaderType.BindingUpdate; }
}
/// <summary>
/// Indicates MAP registration.
/// When a mobile node registers with the MAP, the MapRegistration and Acknowledge must be set to distinguish this registration
/// from a Binding Update being sent to the Home Agent or a correspondent node.
/// </summary>
public bool MapRegistration { get; private set; }
/// <summary>
/// Indicates to the Home Agent that the Binding Update is from a Mobile Router.
/// If false, the Home Agent assumes that the Mobile Router is behaving as a Mobile Node,
/// and it must not forward packets destined for the Mobile Network to the Mobile Router.
/// </summary>
public bool MobileRouter { get; private set; }
/// <summary>
/// Indicates to the local mobility anchor that the Binding Update message is a proxy registration.
/// Must be true for proxy registrations and must be false direct registrations sent by a mobile node.
/// </summary>
public bool ProxyRegistrationFlag { get; private set; }
/// <summary>
/// Indicates a request for forcing UDP encapsulation regardless of whether a NAT is present on the path between the mobile node and the home agent.
/// May be set by the mobile node if it is required to use UDP encapsulation regardless of the presence of a NAT.
/// </summary>
public bool ForcingUdpEncapsulation { get; private set; }
/// <summary>
/// Indicates that the mobile access gateway requests the use of the TLV header for encapsulating IPv6 or IPv4 packets in IPv4.
/// </summary>
public bool TlvHeaderFormat { get; private set; }
/// <summary>
/// If true, it informs the local mobility anchor to enable bulk binding update support for the mobility session associated with this message.
/// If false, the local mobility anchor must exclude the mobility session associated with this message from any bulk-binding-related operations
/// and any binding update, or binding revocation operations with bulk-specific scope will not be relevant to that mobility session.
/// This flag is relevant only for Proxy Mobile IPv6 and therefore must be set to false when the ProxyRegistrationFlag is false.
/// </summary>
public bool BulkBindingUpdate { get; private set; }
internal static IpV6ExtensionHeaderMobilityBindingUpdate ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{
ushort sequenceNumber;
......@@ -59,8 +125,17 @@ namespace PcapDotNet.Packets.IpV6
return null;
}
bool mapRegistration = messageData.ReadBool(MessageDataOffset.MapRegistration, MessageDataMask.MapRegistration);
bool mobileRouter = messageData.ReadBool(MessageDataOffset.MobileRouter, MessageDataMask.MobileRouter);
bool proxyRegistrationFlag = messageData.ReadBool(MessageDataOffset.ProxyRegistrationFlag, MessageDataMask.ProxyRegistrationFlag);
bool forcingUdpEncapsulation = messageData.ReadBool(MessageDataOffset.ForcingUdpEncapsulation, MessageDataMask.ForcingUdpEncapsulation);
bool tlvHeaderFormat = messageData.ReadBool(MessageDataOffset.TlvHeaderFormat, MessageDataMask.TlvHeaderFormat);
bool bulkBindingUpdate = messageData.ReadBool(MessageDataOffset.BulkBindingUpdate, MessageDataMask.BulkBindingUpdate);
return new IpV6ExtensionHeaderMobilityBindingUpdate(nextHeader, checksum, sequenceNumber, acknowledge, homeRegistration,
linkLocalAddressCompatibility, keyManagementMobilityCapability, lifetime, options);
linkLocalAddressCompatibility, keyManagementMobilityCapability, mapRegistration, mobileRouter,
proxyRegistrationFlag, forcingUdpEncapsulation, tlvHeaderFormat, bulkBindingUpdate, lifetime,
options);
}
}
}
\ No newline at end of file
......@@ -15,7 +15,9 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+-------------+-------------------------+
/// | 32 | Checksum |
/// +-----+---------------------------------------+
/// | 48 | Mobility Options |
/// | 48 | Reserved |
/// +-----+---------------------------------------+
/// | 64 | Mobility Options |
/// | ... | |
/// +-----+---------------------------------------+
/// </pre>
......@@ -24,7 +26,7 @@ namespace PcapDotNet.Packets.IpV6
{
private static class MessageDataOffset
{
public const int Options = 0;
public const int Options = sizeof(ushort);
}
public const int MinimumMessageDataLength = MessageDataOffset.Options;
......
......@@ -117,7 +117,7 @@ namespace PcapDotNet.Packets.IpV6
return;
}
nextNextHeader = (IpV4Protocol)extensionHeader[Offset.NextHeader];
extensionHeaderLength = (extensionHeader[Offset.HeaderExtensionLength] + 1) * 8;
extensionHeaderLength = Math.Min(extensionHeader.Length / 8 * 8, (extensionHeader[Offset.HeaderExtensionLength] + 1) * 8);
}
internal static ReadOnlyCollection<IpV4Protocol> StandardExtensionHeaders
......
......@@ -84,7 +84,7 @@ namespace PcapDotNet.Packets.IpV6
{
if (!Headers.Any())
return null;
return Headers[Headers.Count - 1].Protocol;
return Headers[Headers.Count - 1].NextHeader;
}
}
......
......@@ -143,6 +143,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public override string ToString()
{
return ToString(CultureInfo.InvariantCulture);
string valueString = _value.ToString("X33", CultureInfo.InvariantCulture).Substring(1);
StringBuilder stringBuilder = new StringBuilder(39);
for (int i = 0; i != 8; ++i)
......@@ -155,6 +156,31 @@ namespace PcapDotNet.Packets.IpV6
return stringBuilder.ToString();
}
public string ToString(string format)
{
return ToString(format, CultureInfo.InvariantCulture);
}
public string ToString(IFormatProvider provider)
{
return ToString("X4", CultureInfo.InvariantCulture);
}
public string ToString(string format, IFormatProvider provider)
{
StringBuilder stringBuilder = new StringBuilder(39);
for (int i = 0; i != 8; ++i)
{
if (i != 0)
stringBuilder.Append(':');
ushort part = (ushort)(_value >> (16 * (7 - i)));
stringBuilder.Append(part.ToString(format, provider));
}
return stringBuilder.ToString();
}
private readonly UInt128 _value;
private static readonly IpV6Address _zero = new IpV6Address(0);
private static readonly IpV6Address _maxValue = new IpV6Address(UInt128.MaxValue);
......
......@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4AddressAcknowledgement)]
public sealed class IpV6MobilityOptionIpV4AddressAcknowledgement : IpV6MobilityOptionComplex
public sealed class IpV6MobilityOptionIpV4AddressAcknowledgement : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{
public const byte MaxPrefixLength = 0x3F;
......
......@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddress)]
public sealed class IpV6MobilityOptionIpV4HomeAddress : IpV6MobilityOptionComplex
public sealed class IpV6MobilityOptionIpV4HomeAddress : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{
public const byte MaxPrefixLength = 0x3F;
......
......@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddressReply)]
public sealed class IpV6MobilityOptionIpV4HomeAddressReply : IpV6MobilityOptionComplex
public sealed class IpV6MobilityOptionIpV4HomeAddressReply : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{
public const byte MaxPrefixLength = 0x3F;
......
......@@ -3,6 +3,15 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
/// RFC 5844.
/// </summary>
public interface IIpV6MobilityOptionIpV4HomeAddress
{
byte PrefixLength { get; }
IpV4Address HomeAddress { get; }
}
/// <summary>
/// RFC 5844.
/// <pre>
......@@ -19,7 +28,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre>
/// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddressRequest)]
public sealed class IpV6MobilityOptionIpV4HomeAddressRequest : IpV6MobilityOptionComplex
public sealed class IpV6MobilityOptionIpV4HomeAddressRequest : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{
public const byte MaxPrefixLength = 0x3F;
......
using System;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
......@@ -20,6 +22,8 @@ namespace PcapDotNet.Packets.IpV6
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.MobileNodeIdentifier)]
public sealed class IpV6MobilityOptionMobileNodeIdentifier : IpV6MobilityOptionComplex
{
public const int MinNetworkAccessIdentifierLength = 1;
private static class Offset
{
public const int Subtype = 0;
......@@ -31,6 +35,10 @@ namespace PcapDotNet.Packets.IpV6
public IpV6MobilityOptionMobileNodeIdentifier(IpV6MobileNodeIdentifierSubtype subtype, DataSegment identifier)
: base(IpV6MobilityOptionType.MobileNodeIdentifier)
{
if (subtype == IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier && identifier.Length < MinNetworkAccessIdentifierLength)
throw new ArgumentOutOfRangeException("identifier", identifier,
string.Format("Network Access Identifier must be at least {0} bytes long.",
MinNetworkAccessIdentifierLength));
Subtype = subtype;
Identifier = identifier;
}
......@@ -52,6 +60,8 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobileNodeIdentifierSubtype subtype = (IpV6MobileNodeIdentifierSubtype)data[Offset.Subtype];
DataSegment identifier = data.Subsegment(Offset.Identifier, data.Length - Offset.Identifier);
if (subtype == IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier && identifier.Length < MinNetworkAccessIdentifierLength)
return null;
return new IpV6MobilityOptionMobileNodeIdentifier(subtype, identifier);
}
......@@ -74,7 +84,7 @@ namespace PcapDotNet.Packets.IpV6
}
private IpV6MobilityOptionMobileNodeIdentifier()
: this(IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier, DataSegment.Empty)
: this(IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier, new DataSegment(new byte[1]))
{
}
......
......@@ -25,8 +25,8 @@ namespace PcapDotNet.Packets.IpV6
{
private static class Offset
{
public const int PrefixLength = sizeof(ushort);
public const int NetworkPrefix = PrefixLength + sizeof(ushort);
public const int PrefixLength = sizeof(byte);
public const int NetworkPrefix = PrefixLength + sizeof(byte);
}
public const int OptionDataLength = Offset.NetworkPrefix + IpV6Address.SizeOf;
......
using System;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
......@@ -16,9 +18,16 @@ namespace PcapDotNet.Packets.IpV6
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.ServiceSelection)]
public sealed class IpV6MobilityOptionServiceSelection : IpV6MobilityOptionSingleDataSegmentField
{
public const int MinIdentifierLength = 1;
public const int MaxIdentifierLength = 255;
public IpV6MobilityOptionServiceSelection(DataSegment data)
: base(IpV6MobilityOptionType.ServiceSelection, data)
{
if (data.Length < MinIdentifierLength || data.Length > MaxIdentifierLength)
throw new ArgumentOutOfRangeException("data", data,
string.Format("Identifier length must be at least {0} bytes long and at most {1} bytes long.",
MinIdentifierLength, MaxIdentifierLength));
}
/// <summary>
......@@ -37,11 +46,14 @@ namespace PcapDotNet.Packets.IpV6
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
if (data.Length < MinIdentifierLength || data.Length > MaxIdentifierLength)
return null;
return new IpV6MobilityOptionServiceSelection(data);
}
private IpV6MobilityOptionServiceSelection()
: this(DataSegment.Empty)
: this(new DataSegment(new byte[1]))
{
}
}
......
using System;
namespace PcapDotNet.Packets.IpV6
{
/// <summary>
......@@ -33,6 +35,22 @@ namespace PcapDotNet.Packets.IpV6
get { return Value; }
}
public double TimestampSeconds
{
get { return (Timestamp >> 16) + (Timestamp & 0xFFFF) / 65536.0; }
}
public DateTime TimestampDateTime
{
get
{
double seconds = TimestampSeconds;
if (seconds >= MaxSecondsSinceEpcohTimeForDateTime)
return DateTime.MaxValue;
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds);
}
}
internal override IpV6MobilityOption CreateInstance(DataSegment data)
{
ulong timestamp;
......@@ -46,5 +64,7 @@ namespace PcapDotNet.Packets.IpV6
: this(0)
{
}
private static readonly double MaxSecondsSinceEpcohTimeForDateTime = (DateTime.MaxValue - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
}
}
\ No newline at end of file
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