Commit 136c0df1 authored by Brickner_cp's avatar Brickner_cp

IPv6

parent 931704eb
...@@ -85,6 +85,9 @@ ...@@ -85,6 +85,9 @@
<Compile Include="WiresharkDatagramComparerIcmp.cs" /> <Compile Include="WiresharkDatagramComparerIcmp.cs" />
<Compile Include="WiresharkDatagramComparerIgmp.cs" /> <Compile Include="WiresharkDatagramComparerIgmp.cs" />
<Compile Include="WiresharkDatagramComparerIpV4.cs" /> <Compile Include="WiresharkDatagramComparerIpV4.cs" />
<Compile Include="WiresharkDatagramComparerIpV6.cs" />
<Compile Include="WiresharkDatagramComparerIpV6AuthenticationHeader.cs" />
<Compile Include="WiresharkDatagramComparerIpV6MobilityHeader.cs" />
<Compile Include="WiresharkDatagramComparerSimple.cs" /> <Compile Include="WiresharkDatagramComparerSimple.cs" />
<Compile Include="WiresharkDatagramComparerTcp.cs" /> <Compile Include="WiresharkDatagramComparerTcp.cs" />
<Compile Include="WiresharkDatagramComparerUdp.cs" /> <Compile Include="WiresharkDatagramComparerUdp.cs" />
......
...@@ -14,6 +14,7 @@ using PcapDotNet.Packets.Gre; ...@@ -14,6 +14,7 @@ using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Http; using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.Icmp; using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.IpV4; using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.Packets.TestUtils; using PcapDotNet.Packets.TestUtils;
using PcapDotNet.Packets.Transport; using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils; using PcapDotNet.TestUtils;
...@@ -233,7 +234,7 @@ namespace PcapDotNet.Core.Test ...@@ -233,7 +234,7 @@ namespace PcapDotNet.Core.Test
} }
ethernetBaseLayer.EtherType = EthernetType.None; ethernetBaseLayer.EtherType = EthernetType.None;
switch (random.NextInt(0, 5)) switch (random.NextInt(0, 7))
{ {
case 0: // VLanTaggedFrame. case 0: // VLanTaggedFrame.
case 1: case 1:
...@@ -253,7 +254,14 @@ namespace PcapDotNet.Core.Test ...@@ -253,7 +254,14 @@ namespace PcapDotNet.Core.Test
case 4: case 4:
IpV4Layer ipV4Layer = random.NextIpV4Layer(); IpV4Layer ipV4Layer = random.NextIpV4Layer();
layers.Add(ipV4Layer); 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; return;
default: default:
...@@ -261,8 +269,16 @@ namespace PcapDotNet.Core.Test ...@@ -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)) if (random.NextBool(20))
{ {
// Finish with payload. // Finish with payload.
...@@ -271,44 +287,55 @@ namespace PcapDotNet.Core.Test ...@@ -271,44 +287,55 @@ namespace PcapDotNet.Core.Test
return; return;
} }
ipV4Layer.Protocol = null; IpV4Layer ipV4Layer = ipLayer as IpV4Layer;
if (random.NextBool()) if (ipV4Layer != null)
ipV4Layer.Fragmentation = IpV4Fragmentation.None; {
ipV4Layer.Protocol = null;
if (random.NextBool())
ipV4Layer.Fragmentation = IpV4Fragmentation.None;
}
switch (random.Next(0, 9)) switch (random.Next(0, 11))
{ {
case 0: // IpV4. case 0: // IpV4.
case 1: case 1:
IpV4Layer innerIpV4Layer = random.NextIpV4Layer(); IpV4Layer innerIpV4Layer = random.NextIpV4Layer();
layers.Add(innerIpV4Layer); 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; return;
case 2: // Igmp. case 4: // Igmp.
layers.Add(random.NextIgmpLayer()); layers.Add(random.NextIgmpLayer());
return; return;
case 3: // Icmp. case 5: // Icmp.
IcmpLayer icmpLayer = random.NextIcmpLayer(); IcmpLayer icmpLayer = random.NextIcmpLayer();
layers.Add(icmpLayer); layers.Add(icmpLayer);
layers.AddRange(random.NextIcmpPayloadLayers(icmpLayer)); layers.AddRange(random.NextIcmpPayloadLayers(icmpLayer));
return; return;
case 4: // Gre. case 6: // Gre.
GreLayer greLayer = random.NextGreLayer(); GreLayer greLayer = random.NextGreLayer();
layers.Add(greLayer); layers.Add(greLayer);
CreateRandomEthernetPayload(random, greLayer, layers); CreateRandomEthernetPayload(random, greLayer, layers);
return; return;
case 5: // Udp. case 7: // Udp.
case 6: case 8:
UdpLayer udpLayer = random.NextUdpLayer(); UdpLayer udpLayer = random.NextUdpLayer();
layers.Add(udpLayer); layers.Add(udpLayer);
CreateRandomUdpPayload(random, udpLayer, layers); CreateRandomUdpPayload(random, udpLayer, layers);
return; return;
case 7: // Tcp. case 9: // Tcp.
case 8: case 10:
TcpLayer tcpLayer = random.NextTcpLayer(); TcpLayer tcpLayer = random.NextTcpLayer();
layers.Add(tcpLayer); layers.Add(tcpLayer);
CreateRandomTcpPayload(random, tcpLayer, layers); CreateRandomTcpPayload(random, tcpLayer, layers);
...@@ -438,7 +465,7 @@ namespace PcapDotNet.Core.Test ...@@ -438,7 +465,7 @@ namespace PcapDotNet.Core.Test
try try
{ {
Compare(XDocument.Load(fixedDocumentFilename,LoadOptions.None), packets); Compare(XDocument.Load(fixedDocumentFilename, LoadOptions.None), packets);
} }
catch (AssertFailedException exception) catch (AssertFailedException exception)
{ {
...@@ -482,14 +509,20 @@ namespace PcapDotNet.Core.Test ...@@ -482,14 +509,20 @@ namespace PcapDotNet.Core.Test
private static void ComparePacket(Packet packet, XElement documentPacket) private static void ComparePacket(Packet packet, XElement documentPacket)
{ {
object currentDatagram = packet; 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()) 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 "geninfo":
case "raw": case "raw":
...@@ -500,7 +533,7 @@ namespace PcapDotNet.Core.Test ...@@ -500,7 +533,7 @@ namespace PcapDotNet.Core.Test
break; break;
default: default:
var comparer = WiresharkDatagramComparer.GetComparer(layer.Name()); var comparer = WiresharkDatagramComparer.GetComparer(layer.Name(), layerNameToCount[layerName], parentLayerSuccess);
if (comparer == null) if (comparer == null)
return; return;
currentDatagram = comparer.Compare(layer, currentDatagram); currentDatagram = comparer.Compare(layer, currentDatagram);
......
using System.Reflection; using System;
using System.Reflection;
using System.Xml.Linq; using System.Xml.Linq;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets; using PcapDotNet.Packets;
...@@ -9,11 +10,20 @@ namespace PcapDotNet.Core.Test ...@@ -9,11 +10,20 @@ namespace PcapDotNet.Core.Test
{ {
public Datagram Compare(XElement layer, object datagramParent) public Datagram Compare(XElement layer, object datagramParent)
{ {
PropertyInfo property = datagramParent.GetType().GetProperty(PropertyName); Datagram datagram;
if (property == null) if (PropertyName == "")
return null; {
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)) if (Ignore(datagram))
return null; return null;
...@@ -32,16 +42,20 @@ namespace PcapDotNet.Core.Test ...@@ -32,16 +42,20 @@ namespace PcapDotNet.Core.Test
protected void CompareDatagram(XElement layer, Datagram parentDatagram, Datagram datagram) 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; 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) switch (name)
{ {
...@@ -57,6 +71,17 @@ namespace PcapDotNet.Core.Test ...@@ -57,6 +71,17 @@ namespace PcapDotNet.Core.Test
case "ip": case "ip":
return new WiresharkDatagramComparerIpV4(); 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": case "igmp":
return new WiresharkDatagramComparerIgmp(); return new WiresharkDatagramComparerIgmp();
......
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Core.Test
{
internal class WiresharkDatagramComparerIpV6 : WiresharkDatagramComparerSimple
{
public WiresharkDatagramComparerIpV6()
{
}
protected override string PropertyName
{
get { return "IpV6"; }
}
protected override bool CompareField(XElement field, Datagram datagram)
{
IpV6Datagram ipV6Datagram = (IpV6Datagram)datagram;
SkipAuthenticationHeaders(ipV6Datagram);
int optionsIndex = 0;
switch (field.Name())
{
case "ipv6.version":
field.AssertShowDecimal(ipV6Datagram.Version);
foreach (XElement subfield in field.Fields())
{
switch (subfield.Name())
{
case "ip.version":
subfield.AssertShowDecimal(ipV6Datagram.Version);
break;
default:
throw new InvalidOperationException(string.Format("Invalid ipv6 version subfield {0}", subfield.Name()));
}
}
break;
case "ipv6.class":
field.AssertShowHex((uint)ipV6Datagram.TrafficClass);
//field.AssertNoFields();
break;
case "ipv6.flow":
field.AssertShowHex((uint)ipV6Datagram.FlowLabel);
field.AssertNoFields();
break;
case "ipv6.plen":
field.AssertShowDecimal(ipV6Datagram.PayloadLength);
field.AssertNoFields();
break;
case "ipv6.nxt":
field.AssertShowHex((byte)ipV6Datagram.NextHeader);
field.AssertNoFields();
break;
case "ipv6.hlim":
field.AssertShowDecimal(ipV6Datagram.HopLimit);
field.AssertNoFields();
break;
case "ipv6.src":
case "ipv6.src_host":
field.AssertShow(ipV6Datagram.Source.ToString("x"));
field.AssertNoFields();
break;
case "ipv6.src_6to4_gw_ipv4":
case "ipv6.src_6to4_sla_id":
case "ipv6.6to4_gw_ipv4":
case "ipv6.6to4_sla_id":
field.AssertNoFields();
break;
case "ipv6.dst":
case "ipv6.dst_host":
field.AssertShow(ipV6Datagram.CurrentDestination.ToString("x"));
field.AssertNoFields();
break;
case "ipv6.addr":
case "ipv6.host":
Assert.IsTrue(field.Show() == ipV6Datagram.Source.ToString("x") ||
field.Show() == ipV6Datagram.CurrentDestination.ToString("x"));
field.AssertNoFields();
break;
case "ipv6.hop_opt":
IpV6ExtensionHeaderHopByHopOptions hopByHopOptions = (IpV6ExtensionHeaderHopByHopOptions)ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex];
IncrementCurrentExtensionHeaderIndex(ipV6Datagram);
CompareOptions(field, ref optionsIndex, hopByHopOptions);
break;
case "ipv6.routing_hdr":
if (!ipV6Datagram.IsValid)
return false;
IpV6ExtensionHeaderRouting routing = (IpV6ExtensionHeaderRouting)ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex];
IncrementCurrentExtensionHeaderIndex(ipV6Datagram);
int sourceRouteAddressIndex = 0;
foreach (var headerField in field.Fields())
{
headerField.AssertNoFields();
switch (headerField.Name())
{
case "":
ValidateExtensionHeaderUnnamedField(routing, headerField);
break;
case "ipv6.routing_hdr.type":
headerField.AssertShowDecimal((byte)routing.RoutingType);
break;
case "ipv6.routing_hdr.left":
headerField.AssertShowDecimal(routing.SegmentsLeft);
break;
case "ipv6.mipv6_home_address":
IpV6ExtensionHeaderRoutingHomeAddress routingHomeAddress = (IpV6ExtensionHeaderRoutingHomeAddress)routing;
headerField.AssertShow(routingHomeAddress.HomeAddress.ToString("x"));
break;
case "ipv6.routing_hdr.addr":
IpV6ExtensionHeaderRoutingSourceRoute routingSourceRoute = (IpV6ExtensionHeaderRoutingSourceRoute)routing;
headerField.AssertShow(routingSourceRoute.Addresses[sourceRouteAddressIndex++].ToString("x"));
break;
default:
throw new InvalidOperationException("Invalid IPv6 routing source route field " + headerField.Name());
}
}
break;
case "ipv6.dst_opt":
if (_currentExtensionHeaderIndex >= ipV6Datagram.ExtensionHeaders.Headers.Count)
{
int expectedExtensionHeaderLength = (int.Parse(field.Fields().Skip(1).First().Value(), NumberStyles.HexNumber) + 1) * 8;
int actualMaxPossibleLength = ipV6Datagram.RealPayloadLength -
ipV6Datagram.ExtensionHeaders.Take(_currentExtensionHeaderIndex).Sum(
extensionHeader => extensionHeader.Length);
MoreAssert.IsSmaller(expectedExtensionHeaderLength, actualMaxPossibleLength);
return false;
}
IpV6ExtensionHeaderDestinationOptions destinationOptions = (IpV6ExtensionHeaderDestinationOptions)ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex];
IncrementCurrentExtensionHeaderIndex(ipV6Datagram);
CompareOptions(field, ref optionsIndex, destinationOptions);
break;
case "ipv6.shim6":
// TODO: Fix according to https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9995
IpV4Protocol nextHeader = _currentExtensionHeaderIndex > 0
? ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex - 1].NextHeader.Value
: ipV6Datagram.NextHeader;
Assert.AreEqual(IpV4Protocol.AnyHostInternal, nextHeader);
return false;
case "ipv6.unknown_hdr":
Assert.AreEqual(ipV6Datagram.ExtensionHeaders.Count(), _currentExtensionHeaderIndex);
// TODO: Fix according to https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9996
return false;
case "":
switch (field.Show())
{
case "Fragmentation Header":
if (_currentExtensionHeaderIndex >= ipV6Datagram.ExtensionHeaders.Headers.Count && !ipV6Datagram.IsValid)
return false;
IpV6ExtensionHeaderFragmentData fragmentData =
(IpV6ExtensionHeaderFragmentData)ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex];
IncrementCurrentExtensionHeaderIndex(ipV6Datagram);
foreach (var headerField in field.Fields())
{
switch (headerField.Name())
{
case "":
headerField.AssertValue((byte)fragmentData.NextHeader.Value);
break;
case "ipv6.fragment.offset":
headerField.AssertShowDecimal(fragmentData.FragmentOffset);
break;
case "ipv6.fragment.more":
headerField.AssertShowDecimal(fragmentData.MoreFragments);
break;
case "ipv6.framgent.id":
headerField.AssertShowHex(fragmentData.Identification);
break;
default:
throw new InvalidOperationException("Invalid ipv6 fragmentation field " + headerField.Name());
}
}
break;
default:
throw new InvalidOperationException(string.Format("Invalid ipv6 field {0}", field.Show()));
}
break;
default:
throw new InvalidOperationException(string.Format("Invalid ipv6 field {0}", field.Name()));
}
return true;
}
private void CompareOptions(XElement field, ref int optionsIndex, IpV6ExtensionHeaderOptions header)
{
foreach (var headerField in field.Fields())
{
headerField.AssertNoFields();
switch (headerField.Name())
{
case "":
ValidateExtensionHeaderUnnamedField(header, headerField, ref optionsIndex);
break;
case "ipv6.opt.pad1":
Assert.AreEqual(IpV6OptionType.Pad1, header.Options[optionsIndex++].OptionType);
break;
case "ipv6.opt.padn":
Assert.AreEqual(IpV6OptionType.PadN, header.Options[optionsIndex].OptionType);
headerField.AssertShowDecimal(header.Options[optionsIndex++].Length);
break;
case "ipv6.mipv6_type":
Assert.AreEqual(IpV6OptionType.HomeAddress, header.Options[optionsIndex].OptionType);
break;
case "ipv6.mipv6_length":
headerField.AssertShowDecimal(header.Options[optionsIndex].Length - 2);
break;
case "ipv6.mipv6_home_address":
IpV6OptionHomeAddress homeAddress = (IpV6OptionHomeAddress)header.Options[optionsIndex++];
headerField.AssertShow(homeAddress.HomeAddress.ToString("x"));
break;
default:
throw new InvalidOperationException("Invalid ipv6 options field " + headerField.Name());
}
}
}
private void IncrementCurrentExtensionHeaderIndex(IpV6Datagram ipV6Datagram)
{
++_currentExtensionHeaderIndex;
SkipAuthenticationHeaders(ipV6Datagram);
}
private void SkipAuthenticationHeaders(IpV6Datagram ipV6Datagram)
{
while (_currentExtensionHeaderIndex < ipV6Datagram.ExtensionHeaders.Headers.Count &&
ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex].Protocol == IpV4Protocol.AuthenticationHeader)
{
++_currentExtensionHeaderIndex;
}
}
private void ValidateExtensionHeaderUnnamedField(IpV6ExtensionHeader header, XElement headerField)
{
int optionIndex = -1;
ValidateExtensionHeaderUnnamedField(header, headerField, ref optionIndex);
}
private void ValidateExtensionHeaderUnnamedField(IpV6ExtensionHeader header, XElement headerField, ref int optionsIndex)
{
IpV6ExtensionHeaderOptions headerOptions = header as IpV6ExtensionHeaderOptions;
string[] headerFieldShowParts = headerField.Show().Split(':');
string headerFieldShowName = headerFieldShowParts[0];
string headerFieldShowValue = headerFieldShowParts[1];
switch (headerFieldShowName)
{
case "Next header":
headerField.AssertValue((byte)header.NextHeader.Value);
break;
case "Length":
Assert.IsTrue(headerFieldShowValue.EndsWith(" (" + header.Length + " bytes)"));
break;
case "Router alert":
IpV6OptionRouterAlert routerAlert = (IpV6OptionRouterAlert)headerOptions.Options[optionsIndex++];
switch (headerFieldShowValue)
{
case " MLD (4 bytes)":
Assert.AreEqual(IpV6RouterAlertType.MulticastListenerDiscovery, routerAlert.RouterAlertType);
break;
case " RSVP (4 bytes)":
Assert.AreEqual(IpV6RouterAlertType.Rsvp, routerAlert.RouterAlertType);
break;
case " Unknown (4 bytes)":
MoreAssert.IsInRange((ushort)IpV6RouterAlertType.ActiveNetwork, (ushort)IpV6RouterAlertType.NsisNatfwNslp, (ushort)routerAlert.RouterAlertType);
headerField.AssertValueInRange(0x05020002, 0x05020044);
break;
default:
throw new InvalidOperationException("Invalid ipv6 header route Router alert value " + headerFieldShowValue);
}
break;
case "Jumbo payload":
IpV6OptionJumboPayload jumboPayload = (IpV6OptionJumboPayload)headerOptions.Options[optionsIndex++];
Assert.AreEqual(" " + jumboPayload.JumboPayloadLength + " (6 bytes)", headerFieldShowValue);
break;
default:
throw new InvalidOperationException("Invalid ipv6 header unnamed field show name " + headerFieldShowName);
}
}
private int _currentExtensionHeaderIndex;
}
}
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
using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
namespace PcapDotNet.Core.Test
{
internal class WiresharkDatagramComparerIpV6MobilityHeader : WiresharkDatagramComparerSimple
{
public WiresharkDatagramComparerIpV6MobilityHeader()
{
}
protected override string PropertyName
{
get { return ""; }
}
protected override bool CompareField(XElement field, Datagram datagram)
{
IpV6Datagram ipV6Datagram = datagram as IpV6Datagram;
if (ipV6Datagram == null)
return true;
if (ipV6Datagram.NextHeader == IpV4Protocol.Cftp ||
ipV6Datagram.ExtensionHeaders.Any(extensionHeader => extensionHeader.NextHeader == IpV4Protocol.Cftp))
return false;
// TODO: Remove after https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9996 is fixed.
if (ipV6Datagram.ExtensionHeaders.Select(extensionHeader => extensionHeader.NextHeader).Concat(ipV6Datagram.NextHeader).Any(
protocol => protocol == IpV4Protocol.WidebandMonitoring ||
protocol == IpV4Protocol.SunNd ||
protocol == IpV4Protocol.Swipe ||
protocol == IpV4Protocol.AnyHostInternal ||
protocol == IpV4Protocol.SourceDemandRoutingProtocol ||
protocol == IpV4Protocol.MobileInternetworkingControlProtocol ||
protocol == IpV4Protocol.IsoIp ||
protocol == IpV4Protocol.Kryptolan ||
protocol == IpV4Protocol.LArp ||
protocol == IpV4Protocol.SecureVersatileMessageTransactionProtocol ||
protocol == IpV4Protocol.WangSpanNetwork ||
protocol == IpV4Protocol.Cbt ||
protocol == IpV4Protocol.Visa ||
protocol == IpV4Protocol.SimpleMessageProtocol ||
protocol == IpV4Protocol.InternetPacketCoreUtility ||
protocol == IpV4Protocol.BbnRccMonitoring ||
protocol == IpV4Protocol.IpIp ||
protocol == IpV4Protocol.FibreChannel ||
protocol == IpV4Protocol.ServiceSpecificConnectionOrientedProtocolInAMultilinkAndConnectionlessEnvironment ||
protocol == IpV4Protocol.SitaraNetworksProtocol ||
protocol == IpV4Protocol.Fire ||
protocol == IpV4Protocol.Leaf1 ||
protocol == IpV4Protocol.IpsilonFlowManagementProtocol ||
protocol == IpV4Protocol.CompaqPeer ||
protocol == IpV4Protocol.InterDomainPolicyRoutingProtocolControlMessageTransportProtocol ||
protocol == IpV4Protocol.BulkDataTransferProtocol ||
protocol == IpV4Protocol.SemaphoreCommunicationsSecondProtocol ||
protocol == IpV4Protocol.Mobile ||
protocol == IpV4Protocol.HostMonitoringProtocol ||
protocol == IpV4Protocol.Chaos ||
protocol == IpV4Protocol.DiiDataExchange ||
protocol == IpV4Protocol.Emcon ||
protocol == IpV4Protocol.ThirdPartyConnect ||
protocol == IpV4Protocol.Aris ||
protocol == IpV4Protocol.NetworkVoice ||
protocol == IpV4Protocol.AnyPrivateEncryptionScheme ||
protocol == IpV4Protocol.PacketVideoProtocol ||
protocol == IpV4Protocol.PacketRadioMeasurement ||
protocol == IpV4Protocol.AnyLocalNetwork ||
protocol == IpV4Protocol.Qnx ||
protocol == IpV4Protocol.Tcf ||
protocol == IpV4Protocol.Ttp ||
protocol == IpV4Protocol.ScheduleTransferProtocol ||
protocol == IpV4Protocol.TransportLayerSecurityProtocol ||
protocol == IpV4Protocol.Ax25 ||
protocol == IpV4Protocol.CombatRadioTransportProtocol ||
protocol == IpV4Protocol.RemoteVirtualDiskProtocol))
return false;
int currentExtensionHeaderIndex = ipV6Datagram.ExtensionHeaders.TakeWhile(extensionHeader => extensionHeader.Protocol != IpV4Protocol.MobilityHeader).Count();
if (currentExtensionHeaderIndex >= ipV6Datagram.ExtensionHeaders.Headers.Count && !ipV6Datagram.IsValid)
return false;
IpV6ExtensionHeaderMobility mobilityHeader = (IpV6ExtensionHeaderMobility)ipV6Datagram.ExtensionHeaders[currentExtensionHeaderIndex];
switch (field.Name())
{
case "mip6.proto":
field.AssertShowDecimal((byte)mobilityHeader.NextHeader);
field.AssertNoFields();
break;
case "mip6.hlen":
if (mobilityHeader.IsValid)
field.AssertShowDecimal(mobilityHeader.Length / 8 - 1);
field.AssertNoFields();
break;
case "mip6.mhtype":
field.AssertShowDecimal((byte)mobilityHeader.MobilityHeaderType);
break;
case "mip6.reserved":
field.AssertShowHex((byte)0);
field.AssertNoFields();
break;
case "mip6.csum":
field.AssertShowHex(mobilityHeader.Checksum);
break;
case "":
switch (field.Show())
{
case "Binding Refresh Request":
Assert.AreEqual(IpV6MobilityHeaderType.BindingRefreshRequest, mobilityHeader.MobilityHeaderType);
field.AssertNoFields();
break;
case "Heartbeat":
IpV6ExtensionHeaderMobilityHeartbeatMessage heartbeatMessage = (IpV6ExtensionHeaderMobilityHeartbeatMessage)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.hb.u_flag":
subfield.AssertShowDecimal(heartbeatMessage.IsUnsolicitedHeartbeatResponse);
break;
case "mip6.hb.r_flag":
subfield.AssertShowDecimal(heartbeatMessage.IsResponse);
break;
case "mip6.hb.seqnr":
subfield.AssertShowDecimal(heartbeatMessage.SequenceNumber);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Heartbeat mobility header field {0}", subfield.Name()));
}
}
break;
case "Binding Revocation Indication":
IpV6ExtensionHeaderMobilityBindingRevocationIndicationMessage bindingRevocationIndicationMessage = (IpV6ExtensionHeaderMobilityBindingRevocationIndicationMessage)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.bri_br.type":
subfield.AssertShowDecimal((byte)bindingRevocationIndicationMessage.BindingRevocationType);
break;
case "mip6.bri_r.trigger":
subfield.AssertShowDecimal((byte)bindingRevocationIndicationMessage.RevocationTrigger);
break;
case "mip6._bri_seqnr":
subfield.AssertShowDecimal(bindingRevocationIndicationMessage.SequenceNumber);
break;
case "mip6.bri_ip":
subfield.AssertShowDecimal(bindingRevocationIndicationMessage.ProxyBinding);
break;
case "mip6.bri_ia":
// TODO: Should be named differently. See https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10015
subfield.AssertShowDecimal(bindingRevocationIndicationMessage.IpV4HomeAddressBindingOnly);
break;
case "mip6.bri_ig":
subfield.AssertShowDecimal(bindingRevocationIndicationMessage.Global);
break;
case "mip6.bri_res":
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Binding Revocation Acknowledgement Message mobility header field {0}", subfield.Name()));
}
}
break;
case "Binding Revocation Acknowledge":
IpV6ExtensionHeaderMobilityBindingRevocationAcknowledgementMessage bindingRevocationAcknowledgementMessage = (IpV6ExtensionHeaderMobilityBindingRevocationAcknowledgementMessage)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.bri_br.type":
subfield.AssertShowDecimal((byte)bindingRevocationAcknowledgementMessage.BindingRevocationType);
break;
case "mip6.bri_status":
subfield.AssertShowDecimal((byte)bindingRevocationAcknowledgementMessage.Status);
break;
case "mip6._bri_seqnr":
subfield.AssertShowDecimal(bindingRevocationAcknowledgementMessage.SequenceNumber);
break;
case "mip6.bri_ap":
subfield.AssertShowDecimal(bindingRevocationAcknowledgementMessage.ProxyBinding);
break;
case "mip6.bri_ag":
// TODO: Fix after https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10007 is fixed.
subfield.AssertShowDecimal(bindingRevocationAcknowledgementMessage.IpV4HomeAddressBindingOnly);
break;
case "mip6.bri_res":
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Binding Revocation Acknowledgement Message mobility header field {0}", subfield.Name()));
}
}
break;
case "Care-of Test Init":
IpV6ExtensionHeaderMobilityCareOfTestInit careOfTestInit = (IpV6ExtensionHeaderMobilityCareOfTestInit)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.coti.cookie":
subfield.AssertShowHex(careOfTestInit.CareOfInitCookie);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Care Of Test Init mobility header field {0}", subfield.Name()));
}
}
break;
case "Care-of Test":
IpV6ExtensionHeaderMobilityCareOfTest careOfTest = (IpV6ExtensionHeaderMobilityCareOfTest)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.cot.nindex":
subfield.AssertShowDecimal(careOfTest.CareOfNonceIndex);
break;
case "mip6.cot.cookie":
subfield.AssertShowHex(careOfTest.CareOfInitCookie);
break;
case "mip6.hot.token":
subfield.AssertShowHex(careOfTest.CareOfKeygenToken);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Care Of Test mobility header field {0}", subfield.Name()));
}
}
break;
case "Fast Binding Acknowledgement":
IpV6ExtensionHeaderMobilityFastBindingAcknowledgement fastBindingAcknowledgement = (IpV6ExtensionHeaderMobilityFastBindingAcknowledgement)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "fmip6.fback.status":
subfield.AssertShowDecimal((byte)fastBindingAcknowledgement.Status);
break;
case "fmip6.fback.k_flag":
subfield.AssertShowDecimal(fastBindingAcknowledgement.KeyManagementMobilityCapability);
break;
case "fmip6.fback.seqnr":
subfield.AssertShowDecimal(fastBindingAcknowledgement.SequenceNumber);
break;
case "fmip6.fback.lifetime":
subfield.AssertShowDecimal(fastBindingAcknowledgement.Lifetime);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Fast Binding Acknowledgement mobility header field {0}", subfield.Name()));
}
}
break;
case "Binding Error":
IpV6ExtensionHeaderMobilityBindingError bindingError = (IpV6ExtensionHeaderMobilityBindingError)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.be.status":
subfield.AssertShowDecimal((byte)bindingError.Status);
break;
case "mip6.be.haddr":
subfield.AssertShow(bindingError.HomeAddress.ToString("x"));
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Binding Error mobility header field {0}", subfield.Name()));
}
}
break;
case "Fast Neighbor Advertisement":
Assert.AreEqual(IpV6MobilityHeaderType.FastNeighborAdvertisement, mobilityHeader.MobilityHeaderType);
field.AssertNoFields();
break;
case "Home Test":
IpV6ExtensionHeaderMobilityHomeTest homeTest = (IpV6ExtensionHeaderMobilityHomeTest)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.hot.nindex":
subfield.AssertShowDecimal(homeTest.HomeNonceIndex);
break;
case "mip6.hot.cookie":
subfield.AssertShowHex(homeTest.HomeInitCookie);
break;
case "mip6.hot.token":
subfield.AssertShowHex(homeTest.HomeKeygenToken);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Home Test mobility header field {0}", subfield.Name()));
}
}
break;
case "Home Test Init":
IpV6ExtensionHeaderMobilityHomeTestInit homeTestInit = (IpV6ExtensionHeaderMobilityHomeTestInit)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.hoti.cookie":
subfield.AssertShowHex(homeTestInit.HomeInitCookie);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Home Test Init mobility header field {0}", subfield.Name()));
}
}
break;
case "Binding Update":
IpV6ExtensionHeaderMobilityBindingUpdate bindingUpdate = (IpV6ExtensionHeaderMobilityBindingUpdate)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.bu.seqnr":
subfield.AssertShowDecimal(bindingUpdate.SequenceNumber);
break;
case "mip6.bu.a_flag":
subfield.AssertShowDecimal(bindingUpdate.Acknowledge);
break;
case "mip6.bu.h_flag":
subfield.AssertShowDecimal(bindingUpdate.HomeRegistration);
break;
case "mip6.bu.l_flag":
subfield.AssertShowDecimal(bindingUpdate.LinkLocalAddressCompatibility);
break;
case "mip6.bu.k_flag":
subfield.AssertShowDecimal(bindingUpdate.KeyManagementMobilityCapability);
break;
case "mip6.bu.m_flag":
subfield.AssertShowDecimal(bindingUpdate.MapRegistration);
break;
case "mip6.nemo.bu.r_flag":
subfield.AssertShowDecimal(bindingUpdate.MobileRouter);
break;
case "mip6.bu.p_flag":
subfield.AssertShowDecimal(bindingUpdate.ProxyRegistrationFlag);
break;
case "mip6.bu.f_flag":
subfield.AssertShowDecimal(bindingUpdate.ForcingUdpEncapsulation);
break;
case "mip6.bu.t_flag":
subfield.AssertShowDecimal(bindingUpdate.TlvHeaderFormat);
break;
case "mip6.bu.lifetime":
subfield.AssertShowDecimal(bindingUpdate.Lifetime);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Binding Update mobility header field {0}", subfield.Name()));
}
}
break;
case "Binding Acknowledgement":
IpV6ExtensionHeaderMobilityBindingAcknowledgement bindingAcknowledgement = (IpV6ExtensionHeaderMobilityBindingAcknowledgement)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.ba.status":
subfield.AssertShowDecimal((byte)bindingAcknowledgement.Status);
break;
case "mip6.ba.k_flag":
subfield.AssertShowDecimal(bindingAcknowledgement.KeyManagementMobilityCapability);
break;
case "mip6.nemo.ba.r_flag":
subfield.AssertShowDecimal(bindingAcknowledgement.MobileRouter);
break;
case "mip6.ba.p_flag":
subfield.AssertShowDecimal(bindingAcknowledgement.ProxyRegistration);
break;
case "mip6.ba.t_flag":
subfield.AssertShowDecimal(bindingAcknowledgement.TlvHeaderFormat);
break;
case "mip6.ba.seqnr":
subfield.AssertShowDecimal(bindingAcknowledgement.SequenceNumber);
break;
case "mip6.ba.lifetime":
subfield.AssertShowDecimal(bindingAcknowledgement.Lifetime);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Binding Acknowledgement mobility header field {0}", subfield.Name()));
}
}
break;
case "Fast Binding Update":
IpV6ExtensionHeaderMobilityFastBindingUpdate fastBindingUpdate = (IpV6ExtensionHeaderMobilityFastBindingUpdate)mobilityHeader;
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "fmip6.fbu.seqnr":
subfield.AssertShowDecimal(fastBindingUpdate.SequenceNumber);
break;
case "fmip6.fbu.a_flag":
subfield.AssertShowDecimal(fastBindingUpdate.Acknowledge);
break;
case "fmip6.fbu.h_flag":
subfield.AssertShowDecimal(fastBindingUpdate.HomeRegistration);
break;
case "fmip6.fbu.l_flag":
subfield.AssertShowDecimal(fastBindingUpdate.LinkLocalAddressCompatibility);
break;
case "fmip6.fbu.k_flag":
subfield.AssertShowDecimal(fastBindingUpdate.KeyManagementMobilityCapability);
break;
case "fmip6.fbu.lifetime":
subfield.AssertShowDecimal(fastBindingUpdate.Lifetime);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Fast Binding Update mobility header field {0}", subfield.Name()));
}
}
break;
case "Mobility Options":
int optionIndex = 0;
foreach (XElement optionField in field.Fields())
{
IpV6MobilityOption option = mobilityHeader.MobilityOptions[optionIndex];
switch (optionField.Name())
{
case "mip6..mobility_opt":
optionField.AssertShowDecimal((byte)option.OptionType);
optionField.AssertNoFields();
break;
case "mip6.bra.interval":
optionField.AssertShowDecimal(((IpV6MobilityOptionBindingRefreshAdvice)option).RefreshInterval);
optionField.AssertNoFields();
++optionIndex;
break;
case "mip6.gre_key":
optionField.AssertShowDecimal(((IpV6MobilityOptionGreKey)option).GreKeyIdentifier);
optionField.AssertNoFields();
++optionIndex;
break;
case "mip6.acoa.acoa":
optionField.AssertShow(((IpV6MobilityOptionAlternateCareOfAddress)option).AlternateCareOfAddress.ToString("x"));
optionField.AssertNoFields();
++optionIndex;
break;
case "mip6.rc":
optionField.AssertShowDecimal(((IpV6MobilityOptionRestartCounter)option).RestartCounter);
optionField.AssertNoFields();
++optionIndex;
break;
case "mip6.timestamp":
IpV6MobilityOptionTimestamp timestamp = (IpV6MobilityOptionTimestamp)option;
optionField.AssertValue(timestamp.Timestamp);
Assert.AreEqual(IpV6MobilityOptionType.Timestamp, option.OptionType);
// TODO: Fix this after https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10008 is fixed.
// if (optionField.Show() != "Not representable")
// optionField.AssertShow(timestamp.TimestampDateTime.ToString());
optionField.AssertNoFields();
++optionIndex;
break;
case "mip6.att":
optionField.AssertShowDecimal((byte)((IpV6MobilityOptionAccessTechnologyType)option).AccessTechnologyType);
optionField.AssertNoFields();
++optionIndex;
break;
case "mip6.hi":
optionField.AssertShowDecimal((byte)((IpV6MobilityOptionHandoffIndicator)option).HandoffIndicator);
optionField.AssertNoFields();
++optionIndex;
break;
case "":
switch (option.OptionType)
{
case IpV6MobilityOptionType.LinkLayerAddress:
optionField.AssertShow("Mobility Header Link-Layer Address option");
IpV6MobilityOptionLinkLayerAddress linkLayerAddress = (IpV6MobilityOptionLinkLayerAddress)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.lla.optcode":
optionSubfield.AssertShowDecimal((byte)linkLayerAddress.Code);
break;
case "":
// TODO: Fix when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10006 is fixed.
// optionSubfield.AssertValue(linkLayerAddress.LinkLayerAddress);
return false;
default:
throw new InvalidOperationException(string.Format(
"Invalid IPv6 Link Layer Address option field {0}", optionSubfield.Name()));
}
}
// TODO: Remove once https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10043 is fixed.
if (linkLayerAddress.LinkLayerAddress.Length == 0)
return false;
break;
case IpV6MobilityOptionType.IpV4DefaultRouterAddress:
optionField.AssertShow("IPv4 Default-Router Address");
IpV6MobilityOptionIpV4DefaultRouterAddress ipV4DefaultRouterAddress =
(IpV6MobilityOptionIpV4DefaultRouterAddress)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.ipv4dra.dra":
optionSubfield.AssertShow(ipV4DefaultRouterAddress.DefaultRouterAddress.ToString());
break;
default:
throw new InvalidOperationException(
string.Format("Invalid IPv6 IPv4 Default Router Address option field {0}", optionSubfield.Name()));
}
}
break;
case IpV6MobilityOptionType.Pad1:
optionField.AssertShow("Pad1");
optionField.AssertNoFields();
break;
case IpV6MobilityOptionType.PadN:
optionField.AssertShow(string.Format("PadN: {0} bytes", option.Length));
optionField.AssertNoFields();
break;
case IpV6MobilityOptionType.IpV4HomeAddressReply:
optionField.AssertShow("IPv4 Home Address Reply");
IpV6MobilityOptionIpV4HomeAddressReply ipV4HomeAddressReply = (IpV6MobilityOptionIpV4HomeAddressReply)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.ipv4aa.sts":
optionSubfield.AssertShowDecimal((byte)ipV4HomeAddressReply.Status);
break;
default:
ValidateIpV6MobilityOptionIpV4HomeAddressField(optionSubfield, ipV4HomeAddressReply);
break;
}
}
break;
case IpV6MobilityOptionType.IpV4HomeAddressRequest:
optionField.AssertShow("IPv4 Home Address Request");
IpV6MobilityOptionIpV4HomeAddressRequest ipV4HomeAddressRequest =
(IpV6MobilityOptionIpV4HomeAddressRequest)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
ValidateIpV6MobilityOptionIpV4HomeAddressField(optionSubfield, ipV4HomeAddressRequest);
}
break;
case IpV6MobilityOptionType.IpV4AddressAcknowledgement:
optionField.AssertShow("IPv4 Address Acknowledgement");
IpV6MobilityOptionIpV4AddressAcknowledgement ipV4AddressAcknowledgement =
(IpV6MobilityOptionIpV4AddressAcknowledgement)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.ipv4aa.sts":
optionSubfield.AssertShowDecimal((byte)ipV4AddressAcknowledgement.Status);
break;
default:
ValidateIpV6MobilityOptionIpV4HomeAddressField(optionSubfield, ipV4AddressAcknowledgement);
break;
}
}
break;
case IpV6MobilityOptionType.MobileNetworkPrefix:
optionField.AssertShow("Mobile Network Prefix");
IpV6MobilityOptionMobileNetworkPrefix mobileNetworkPrefix = (IpV6MobilityOptionMobileNetworkPrefix)option;
ValidateNetworkPrefixOption(mobileNetworkPrefix, optionField);
break;
case IpV6MobilityOptionType.HomeNetworkPrefix:
optionField.AssertShow("Home Network Prefix");
IpV6MobilityOptionHomeNetworkPrefix homeNetworkPrefix = (IpV6MobilityOptionHomeNetworkPrefix)option;
ValidateNetworkPrefixOption(homeNetworkPrefix, optionField);
break;
case IpV6MobilityOptionType.VendorSpecific:
optionField.AssertShow("Vendor Specific Mobility");
IpV6MobilityOptionVendorSpecific vendorSpecific = (IpV6MobilityOptionVendorSpecific)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.vsm.vendorId":
optionSubfield.AssertShowDecimal(vendorSpecific.VendorId);
break;
case "mip6.vsm.subtype":
optionSubfield.AssertShowDecimal(vendorSpecific.SubType);
break;
case "":
optionSubfield.AssertValue(vendorSpecific.Data);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Vendor Specific option field {0}",
optionSubfield.Name()));
}
}
break;
case IpV6MobilityOptionType.NonceIndices:
optionField.AssertShow("Nonce Indices");
IpV6MobilityOptionNonceIndices nonceIndices = (IpV6MobilityOptionNonceIndices)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.ni.hni":
optionSubfield.AssertShowDecimal(nonceIndices.HomeNonceIndex);
break;
case "mip6.ni.cni":
optionSubfield.AssertShowDecimal(nonceIndices.CareOfNonceIndex);
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Nonce Indices option field {0}",
optionSubfield.Name()));
}
}
break;
case IpV6MobilityOptionType.LinkLocalAddress:
optionField.AssertShow("Link-local Address");
IpV6MobilityOptionLinkLocalAddress linkLocalAddress = (IpV6MobilityOptionLinkLocalAddress)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.lila_lla":
optionSubfield.AssertShow(linkLocalAddress.LinkLocalAddress.ToString("x"));
break;
default:
throw new InvalidOperationException(string.Format(
"Invalid IPv6 Link-local Address option field {0}", optionSubfield.Name()));
}
}
break;
case IpV6MobilityOptionType.MobileNodeIdentifier:
optionField.AssertShow("Mobile Node Identifier");
IpV6MobilityOptionMobileNodeIdentifier mobileNodeIdentifier = (IpV6MobilityOptionMobileNodeIdentifier)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.mnid.subtype":
optionSubfield.AssertShowDecimal((byte)mobileNodeIdentifier.Subtype);
break;
case "":
optionSubfield.AssertValue(mobileNodeIdentifier.Identifier);
break;
default:
throw new InvalidOperationException(
string.Format("Invalid IPv6 Mobile Node Identifier option field {0}", optionSubfield.Name()));
}
}
break;
case IpV6MobilityOptionType.BindingAuthorizationData:
optionField.AssertShow("Authorization Data");
IpV6MobilityOptionBindingAuthorizationData authorizationData =
(IpV6MobilityOptionBindingAuthorizationData)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.bad.auth":
optionSubfield.AssertValue(authorizationData.Authenticator);
break;
default:
throw new InvalidOperationException(string.Format(
"Invalid IPv6 Authorization Data option field {0}", optionSubfield.Name()));
}
}
break;
case IpV6MobilityOptionType.IpV4HomeAddress:
optionField.AssertShow("IPv4 Home Address");
IpV6MobilityOptionIpV4HomeAddress ipV4HomeAddress = (IpV6MobilityOptionIpV4HomeAddress)option;
foreach (XElement optionSubfield in optionField.Fields())
{
optionSubfield.AssertNoFields();
switch (optionSubfield.Name())
{
case "mip6.ipv4ha.p_flag":
optionSubfield.AssertShowDecimal(ipV4HomeAddress.RequestPrefix);
break;
default:
ValidateIpV6MobilityOptionIpV4HomeAddressField(optionSubfield, ipV4HomeAddress);
break;
}
}
break;
case IpV6MobilityOptionType.ServiceSelection:
IpV6MobilityOptionServiceSelection serviceSelection = (IpV6MobilityOptionServiceSelection)option;
// TODO: Get rid of that when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10045 is fixed.
if (serviceSelection.Identifier.Length == 1)
{
optionField.AssertShow("Service Selection Mobility (with option length = 1 byte; should be >= 2)");
break;
}
optionField.AssertValue(serviceSelection.Identifier);
optionField.AssertNoFields();
break;
case IpV6MobilityOptionType.FlowSummary:
case IpV6MobilityOptionType.CgaParametersRequest:
case IpV6MobilityOptionType.Redirect:
case IpV6MobilityOptionType.IpV4CareOfAddress:
case IpV6MobilityOptionType.Signature:
case IpV6MobilityOptionType.MobileNodeGroupIdentifier:
case IpV6MobilityOptionType.MobileNodeLinkLayerIdentifier:
case IpV6MobilityOptionType.Authentication:
case IpV6MobilityOptionType.RedirectCapability:
case IpV6MobilityOptionType.CgaParameters:
case IpV6MobilityOptionType.ContextRequest:
case IpV6MobilityOptionType.IpV6AddressPrefix:
case IpV6MobilityOptionType.FlowIdentification:
case IpV6MobilityOptionType.TransientBinding:
case IpV6MobilityOptionType.LocalMobilityAnchorAddress:
case IpV6MobilityOptionType.PermanentHomeKeygenToken:
case IpV6MobilityOptionType.AccessNetworkIdentifier:
case IpV6MobilityOptionType.BindingIdentifier:
case IpV6MobilityOptionType.DnsUpdate:
case IpV6MobilityOptionType.CareOfTest:
case IpV6MobilityOptionType.IpV4DhcpSupportMode:
case IpV6MobilityOptionType.AlternateIpV4CareOfAddress:
case IpV6MobilityOptionType.MobileNodeLinkLocalAddressInterfaceIdentifier:
case IpV6MobilityOptionType.LoadInformation:
case IpV6MobilityOptionType.BindingAuthorizationDataForFmIpV6:
case IpV6MobilityOptionType.NatDetection:
case IpV6MobilityOptionType.MobileAccessGatewayIpV6Address:
case IpV6MobilityOptionType.ReplayProtection:
case IpV6MobilityOptionType.CareOfTestInit:
case IpV6MobilityOptionType.Experimental:
optionField.AssertShow("IE data not dissected yet");
optionField.AssertNoFields();
break;
default:
throw new InvalidOperationException(string.Format("Unsupported IPv6 mobility option type {0}", option.OptionType));
}
++optionIndex;
break;
default:
throw new InvalidOperationException(string.Format("Invalid ipv6 mobility header option field {0}", optionField.Name()));
}
}
break;
default:
field.AssertShow("Unknown MH Type");
Assert.IsTrue(mobilityHeader.MobilityHeaderType == IpV6MobilityHeaderType.Experimental ||
mobilityHeader.MobilityHeaderType == IpV6MobilityHeaderType.HandoverAcknowledgeMessage ||
mobilityHeader.MobilityHeaderType == IpV6MobilityHeaderType.HomeAgentSwitchMessage ||
mobilityHeader.MobilityHeaderType == IpV6MobilityHeaderType.LocalizedRoutingInitiation ||
mobilityHeader.MobilityHeaderType == IpV6MobilityHeaderType.LocalizedRoutingAcknowledgement ||
mobilityHeader.MobilityHeaderType == IpV6MobilityHeaderType.HandoverInitiateMessage);
field.AssertNoFields();
break;
}
break;
default:
throw new InvalidOperationException(string.Format("Invalid ipv6 mobility header field {0}", field.Name()));
}
return true;
}
private static void ValidateNetworkPrefixOption(IpV6MobilityOptionNetworkPrefix networkPrefix, XElement field)
{
foreach (XElement subfield in field.Fields())
{
subfield.AssertNoFields();
switch (subfield.Name())
{
case "mip6.nemo.mnp.pfl":
subfield.AssertShowDecimal(networkPrefix.PrefixLength);
break;
case "mip6.nemo.mnp.mnp":
subfield.AssertShow(networkPrefix.NetworkPrefix.ToString("x"));
break;
default:
throw new InvalidOperationException(string.Format("Invalid IPv6 Network Prefix option field {0}", subfield.Name()));
}
}
}
private void ValidateIpV6MobilityOptionIpV4HomeAddressField(XElement field, IIpV6MobilityOptionIpV4HomeAddress ipV4HomeAddress)
{
switch (field.Name())
{
case "mip6.ipv4ha.preflen":
field.AssertShowDecimal(ipV4HomeAddress.PrefixLength);
break;
case "mip6.ipv4ha.ha":
field.AssertShow(ipV4HomeAddress.HomeAddress.ToString());
break;
default:
throw new InvalidOperationException(string.Format("Invalid IpV6 IpV4 Home Address option field {0}", field.Name()));
}
}
}
}
\ No newline at end of file
...@@ -10,6 +10,6 @@ namespace PcapDotNet.Core.Test ...@@ -10,6 +10,6 @@ namespace PcapDotNet.Core.Test
return CompareField(field, datagram); 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; ...@@ -7,6 +7,7 @@ using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4; using PcapDotNet.Packets.IpV4;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
...@@ -167,6 +168,11 @@ namespace PcapDotNet.Core.Test ...@@ -167,6 +168,11 @@ namespace PcapDotNet.Core.Test
Assert.AreEqual(expectedValue, element.Value(), message ?? element.Name()); 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) public static void AssertValue(this XElement element, IEnumerable<byte> expectedValue, string message = null)
{ {
element.AssertValue(expectedValue.BytesSequenceToHexadecimalString(), message); element.AssertValue(expectedValue.BytesSequenceToHexadecimalString(), message);
...@@ -187,11 +193,21 @@ namespace PcapDotNet.Core.Test ...@@ -187,11 +193,21 @@ namespace PcapDotNet.Core.Test
element.AssertValue(expectedValue.ToString("x8")); 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) public static void AssertValue(this XElement element, UInt48 expectedValue)
{ {
element.AssertValue(expectedValue.ToString("x12")); 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) public static void AssertValue(this XElement element, SerialNumber32 expectedValue)
{ {
element.AssertValue(expectedValue.Value); element.AssertValue(expectedValue.Value);
......
...@@ -143,13 +143,14 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -143,13 +143,14 @@ namespace PcapDotNet.Packets.TestUtils
case IpV6MobilityHeaderType.BindingUpdate: // 5 case IpV6MobilityHeaderType.BindingUpdate: // 5
return new IpV6ExtensionHeaderMobilityBindingUpdate(nextHeader, checksum, random.NextUShort(), random.NextBool(), random.NextBool(), return new IpV6ExtensionHeaderMobilityBindingUpdate(nextHeader, checksum, random.NextUShort(), random.NextBool(), random.NextBool(),
random.NextBool(), random.NextBool(), random.NextUShort(), random.NextBool(), random.NextBool(), random.NextBool(), random.NextBool(),
random.NextIpV6MobilityOptions()); random.NextBool(), random.NextBool(), random.NextBool(), random.NextBool(),
random.NextUShort(), random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.BindingAcknowledgement: // 6 case IpV6MobilityHeaderType.BindingAcknowledgement: // 6
return new IpV6ExtensionHeaderMobilityBindingAcknowledgement(nextHeader, checksum, random.NextEnum<IpV6BindingAcknowledgementStatus>(), return new IpV6ExtensionHeaderMobilityBindingAcknowledgement(nextHeader, checksum, random.NextEnum<IpV6BindingAcknowledgementStatus>(),
random.NextBool(), random.NextUShort(), random.NextUShort(), random.NextBool(), random.NextBool(), random.NextBool(), random.NextBool(),
random.NextIpV6MobilityOptions()); random.NextUShort(), random.NextUShort(), random.NextIpV6MobilityOptions());
case IpV6MobilityHeaderType.BindingError: // 7 case IpV6MobilityHeaderType.BindingError: // 7
return new IpV6ExtensionHeaderMobilityBindingError(nextHeader, checksum, random.NextEnum<IpV6BindingErrorStatus>(), random.NextIpV6Address(), return new IpV6ExtensionHeaderMobilityBindingError(nextHeader, checksum, random.NextEnum<IpV6BindingErrorStatus>(), random.NextIpV6Address(),
...@@ -343,8 +344,11 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -343,8 +344,11 @@ namespace PcapDotNet.Packets.TestUtils
random.NextDataSegment(random.NextInt(0, 100))); random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.MobileNodeIdentifier: case IpV6MobilityOptionType.MobileNodeIdentifier:
return new IpV6MobilityOptionMobileNodeIdentifier(random.NextEnum<IpV6MobileNodeIdentifierSubtype>(), IpV6MobileNodeIdentifierSubtype mobileNodeIdentifierSubtype = random.NextEnum<IpV6MobileNodeIdentifierSubtype>();
random.NextDataSegment(random.NextInt(0, 100))); return new IpV6MobilityOptionMobileNodeIdentifier(
mobileNodeIdentifierSubtype,
random.NextDataSegment(random.NextInt(mobileNodeIdentifierSubtype == IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier ? 1 : 0,
100)));
case IpV6MobilityOptionType.Authentication: case IpV6MobilityOptionType.Authentication:
return new IpV6MobilityOptionAuthentication(random.NextEnum<IpV6AuthenticationSubtype>(), random.NextUInt(), return new IpV6MobilityOptionAuthentication(random.NextEnum<IpV6AuthenticationSubtype>(), random.NextUInt(),
...@@ -382,7 +386,7 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -382,7 +386,7 @@ namespace PcapDotNet.Packets.TestUtils
return new IpV6MobilityOptionVendorSpecific(random.NextUInt(), random.NextByte(), random.NextDataSegment(random.NextInt(0, 100))); return new IpV6MobilityOptionVendorSpecific(random.NextUInt(), random.NextByte(), random.NextDataSegment(random.NextInt(0, 100)));
case IpV6MobilityOptionType.ServiceSelection: case IpV6MobilityOptionType.ServiceSelection:
return new IpV6MobilityOptionServiceSelection(random.NextDataSegment(random.NextInt(0, 100))); return new IpV6MobilityOptionServiceSelection(random.NextDataSegment(random.NextInt(1, 100)));
case IpV6MobilityOptionType.BindingAuthorizationDataForFmIpV6: case IpV6MobilityOptionType.BindingAuthorizationDataForFmIpV6:
return new IpV6MobilityOptionBindingAuthorizationDataForFmIpV6(random.NextUInt(), random.NextDataSegment(random.NextInt(0, 100))); return new IpV6MobilityOptionBindingAuthorizationDataForFmIpV6(random.NextUInt(), random.NextDataSegment(random.NextInt(0, 100)));
...@@ -530,7 +534,7 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -530,7 +534,7 @@ namespace PcapDotNet.Packets.TestUtils
return new IpV6FlowIdentificationSubOptionBindingReference(((Func<ushort>)(random.NextUShort)).GenerateArray(random.NextInt(0, 10))); return new IpV6FlowIdentificationSubOptionBindingReference(((Func<ushort>)(random.NextUShort)).GenerateArray(random.NextInt(0, 10)));
case IpV6FlowIdentificationSubOptionType.TrafficSelector: 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: default:
throw new InvalidOperationException(string.Format("Invalid optionType value {0}", optionType)); throw new InvalidOperationException(string.Format("Invalid optionType value {0}", optionType));
......
...@@ -221,7 +221,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -221,7 +221,7 @@ namespace PcapDotNet.Packets.IpV4
/// </summary> /// </summary>
IntegratedNetLayerSecurityProtocol = 0x34, IntegratedNetLayerSecurityProtocol = 0x34,
/// <summary> /// <summary>
/// IP with Encryption /// IP with Encryption.
/// </summary> /// </summary>
Swipe = 0x35, Swipe = 0x35,
/// <summary> /// <summary>
......
...@@ -3,35 +3,52 @@ using PcapDotNet.Packets.IpV4; ...@@ -3,35 +3,52 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6 namespace PcapDotNet.Packets.IpV6
{ {
/// <summary> /// <summary>
/// RFC 6275. /// RFC 3963, 5213, 5845, 6275.
/// <pre> /// <pre>
/// +-----+-------------+---+---------------------+ /// +-----+-------------+---+---+----+----+---------+
/// | Bit | 0-7 | 8 | 9-15 | /// | Bit | 0-7 | 8 | 9 | 10 | 11 | 12-15 |
/// +-----+-------------+---+---------------------+ /// +-----+-------------+---+---+----+----+---------+
/// | 0 | Next Header | Header Extension Length | /// | 0 | Next Header | Header Extension Length |
/// +-----+-------------+-------------------------+ /// +-----+-------------+---------------------------+
/// | 16 | MH Type | Reserved | /// | 16 | MH Type | Reserved |
/// +-----+-------------+-------------------------+ /// +-----+-------------+---------------------------+
/// | 32 | Checksum | /// | 32 | Checksum |
/// +-----+-------------+---+---------------------+ /// +-----+-------------+---+---+---+----+----------+
/// | 48 | Status | K | Reserved | /// | 48 | Status | K | R | P | T | Reserved |
/// +-----+-------------+---+---------------------+ /// +-----+-------------+---+---+---+----+----------+
/// | 64 | Sequence # | /// | 64 | Sequence # |
/// +-----+---------------------------------------+ /// +-----+-----------------------------------------+
/// | 80 | Lifetime | /// | 80 | Lifetime |
/// +-----+---------------------------------------+ /// +-----+-----------------------------------------+
/// | 96 | Mobility Options | /// | 96 | Mobility Options |
/// | ... | | /// | ... | |
/// +-----+---------------------------------------+ /// +-----+-----------------------------------------+
/// </pre> /// </pre>
/// </summary> /// </summary>
public sealed class IpV6ExtensionHeaderMobilityBindingAcknowledgement : IpV6ExtensionHeaderMobilityBindingAcknowledgementBase 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, public IpV6ExtensionHeaderMobilityBindingAcknowledgement(IpV4Protocol nextHeader, ushort checksum, IpV6BindingAcknowledgementStatus status,
bool keyManagementMobilityCapability, ushort sequenceNumber, ushort lifetime, bool keyManagementMobilityCapability, bool mobileRouter, bool proxyRegistration,
IpV6MobilityOptions options) bool tlvHeaderFormat, ushort sequenceNumber, ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, status, keyManagementMobilityCapability, sequenceNumber, lifetime, options) : base(nextHeader, checksum, status, keyManagementMobilityCapability, sequenceNumber, lifetime, options)
{ {
MobileRouter = mobileRouter;
ProxyRegistration = proxyRegistration;
TlvHeaderFormat = tlvHeaderFormat;
} }
/// <summary> /// <summary>
...@@ -43,6 +60,23 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -43,6 +60,23 @@ namespace PcapDotNet.Packets.IpV6
get { return IpV6MobilityHeaderType.BindingAcknowledgement; } 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) internal static IpV6ExtensionHeaderMobilityBindingAcknowledgement ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{ {
IpV6BindingAcknowledgementStatus status; IpV6BindingAcknowledgementStatus status;
...@@ -53,8 +87,12 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -53,8 +87,12 @@ namespace PcapDotNet.Packets.IpV6
if (!ParseMessageDataFields(messageData, out status, out keyManagementMobilityCapability, out sequenceNumber, out lifetime, out options)) if (!ParseMessageDataFields(messageData, out status, out keyManagementMobilityCapability, out sequenceNumber, out lifetime, out options))
return null; return null;
return new IpV6ExtensionHeaderMobilityBindingAcknowledgement(nextHeader, checksum, status, keyManagementMobilityCapability, sequenceNumber, lifetime, bool mobileRouter = messageData.ReadBool(MessageDataOffset.MobileRouter, MessageDataMask.MobileRouter);
options); 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 ...@@ -39,7 +39,7 @@ namespace PcapDotNet.Packets.IpV6
/// <summary> /// <summary>
/// Defines the type of the Binding Revocation Message. /// Defines the type of the Binding Revocation Message.
/// </summary> /// </summary>
public override sealed IpV6MobilityBindingRevocationType BindingRevocationType public override IpV6MobilityBindingRevocationType BindingRevocationType
{ {
get { return IpV6MobilityBindingRevocationType.BindingRevocationIndication; } get { return IpV6MobilityBindingRevocationType.BindingRevocationIndication; }
} }
......
...@@ -3,36 +3,63 @@ using PcapDotNet.Packets.IpV4; ...@@ -3,36 +3,63 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6 namespace PcapDotNet.Packets.IpV6
{ {
/// <summary> /// <summary>
/// RFC 6275. /// RFCs 3963, 4140, 5213, 5380, 5555, 5845, 6275, 6602.
/// <pre> /// <pre>
/// +-----+---+---+---+---+-----+-------------------------+ /// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | Bit | 0 | 1 | 2 | 3 | 4-7 | 8-15 | /// | Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10-15 |
/// +-----+---+---+---+---+-----+-------------------------+ /// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | 0 | Next Header | Header Extension Length | /// | 0 | Next Header | Header Extension Length |
/// +-----+---------------------+-------------------------+ /// +-----+-------------------------------+-------------------------+
/// | 16 | MH Type | Reserved | /// | 16 | MH Type | Reserved |
/// +-----+---------------------+-------------------------+ /// +-----+-------------------------------+-------------------------+
/// | 32 | Checksum | /// | 32 | Checksum |
/// +-----+-----------------------------------------------+ /// +-----+---------------------------------------------------------+
/// | 48 | Sequence # | /// | 48 | Sequence # |
/// +-----+---+---+---+---+-------------------------------+ /// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | 64 | A | H | L | K | Reserved | /// | 64 | A | H | L | K | M | R | P | F | T | B | Reserved |
/// +-----+---+---+---+---+-------------------------------+ /// +-----+---+---+---+---+---+---+---+---+---+---+-----------------+
/// | 80 | Lifetime | /// | 80 | Lifetime |
/// +-----+-----------------------------------------------+ /// +-----+---------------------------------------------------------+
/// | 96 | Mobility Options | /// | 96 | Mobility Options |
/// | ... | | /// | ... | |
/// +-----+-----------------------------------------------+ /// +-----+---------------------------------------------------------+
/// </pre> /// </pre>
/// </summary> /// </summary>
public sealed class IpV6ExtensionHeaderMobilityBindingUpdate : IpV6ExtensionHeaderMobilityBindingUpdateBase 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, public IpV6ExtensionHeaderMobilityBindingUpdate(IpV4Protocol nextHeader, ushort checksum, ushort sequenceNumber, bool acknowledge, bool homeRegistration,
bool linkLocalAddressCompatibility, bool keyManagementMobilityCapability, ushort lifetime, bool linkLocalAddressCompatibility, bool keyManagementMobilityCapability, bool mapRegistration,
IpV6MobilityOptions options) bool mobileRouter, bool proxyRegistrationFlag, bool forcingUdpEncapsulation, bool tlvHeaderFormat,
bool bulkBindingUpdate, ushort lifetime, IpV6MobilityOptions options)
: base(nextHeader, checksum, sequenceNumber, acknowledge, homeRegistration, linkLocalAddressCompatibility, keyManagementMobilityCapability, : base(nextHeader, checksum, sequenceNumber, acknowledge, homeRegistration, linkLocalAddressCompatibility, keyManagementMobilityCapability,
lifetime, options) lifetime, options)
{ {
MapRegistration = mapRegistration;
MobileRouter = mobileRouter;
ProxyRegistrationFlag = proxyRegistrationFlag;
ForcingUdpEncapsulation = forcingUdpEncapsulation;
TlvHeaderFormat = tlvHeaderFormat;
BulkBindingUpdate = bulkBindingUpdate;
} }
/// <summary> /// <summary>
...@@ -44,6 +71,45 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -44,6 +71,45 @@ namespace PcapDotNet.Packets.IpV6
get { return IpV6MobilityHeaderType.BindingUpdate; } 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) internal static IpV6ExtensionHeaderMobilityBindingUpdate ParseMessageData(IpV4Protocol nextHeader, ushort checksum, DataSegment messageData)
{ {
ushort sequenceNumber; ushort sequenceNumber;
...@@ -59,8 +125,17 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -59,8 +125,17 @@ namespace PcapDotNet.Packets.IpV6
return null; 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, 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 ...@@ -15,7 +15,9 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+-------------+-------------------------+ /// +-----+-------------+-------------------------+
/// | 32 | Checksum | /// | 32 | Checksum |
/// +-----+---------------------------------------+ /// +-----+---------------------------------------+
/// | 48 | Mobility Options | /// | 48 | Reserved |
/// +-----+---------------------------------------+
/// | 64 | Mobility Options |
/// | ... | | /// | ... | |
/// +-----+---------------------------------------+ /// +-----+---------------------------------------+
/// </pre> /// </pre>
...@@ -24,7 +26,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -24,7 +26,7 @@ namespace PcapDotNet.Packets.IpV6
{ {
private static class MessageDataOffset private static class MessageDataOffset
{ {
public const int Options = 0; public const int Options = sizeof(ushort);
} }
public const int MinimumMessageDataLength = MessageDataOffset.Options; public const int MinimumMessageDataLength = MessageDataOffset.Options;
......
...@@ -117,7 +117,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -117,7 +117,7 @@ namespace PcapDotNet.Packets.IpV6
return; return;
} }
nextNextHeader = (IpV4Protocol)extensionHeader[Offset.NextHeader]; 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 internal static ReadOnlyCollection<IpV4Protocol> StandardExtensionHeaders
......
...@@ -84,7 +84,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -84,7 +84,7 @@ namespace PcapDotNet.Packets.IpV6
{ {
if (!Headers.Any()) if (!Headers.Any())
return null; return null;
return Headers[Headers.Count - 1].Protocol; return Headers[Headers.Count - 1].NextHeader;
} }
} }
......
...@@ -143,6 +143,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -143,6 +143,7 @@ namespace PcapDotNet.Packets.IpV6
/// </summary> /// </summary>
public override string ToString() public override string ToString()
{ {
return ToString(CultureInfo.InvariantCulture);
string valueString = _value.ToString("X33", CultureInfo.InvariantCulture).Substring(1); string valueString = _value.ToString("X33", CultureInfo.InvariantCulture).Substring(1);
StringBuilder stringBuilder = new StringBuilder(39); StringBuilder stringBuilder = new StringBuilder(39);
for (int i = 0; i != 8; ++i) for (int i = 0; i != 8; ++i)
...@@ -155,6 +156,31 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -155,6 +156,31 @@ namespace PcapDotNet.Packets.IpV6
return stringBuilder.ToString(); 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 readonly UInt128 _value;
private static readonly IpV6Address _zero = new IpV6Address(0); private static readonly IpV6Address _zero = new IpV6Address(0);
private static readonly IpV6Address _maxValue = new IpV6Address(UInt128.MaxValue); private static readonly IpV6Address _maxValue = new IpV6Address(UInt128.MaxValue);
......
...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre> /// </pre>
/// </summary> /// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4AddressAcknowledgement)] [IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4AddressAcknowledgement)]
public sealed class IpV6MobilityOptionIpV4AddressAcknowledgement : IpV6MobilityOptionComplex public sealed class IpV6MobilityOptionIpV4AddressAcknowledgement : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{ {
public const byte MaxPrefixLength = 0x3F; public const byte MaxPrefixLength = 0x3F;
......
...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre> /// </pre>
/// </summary> /// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddress)] [IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddress)]
public sealed class IpV6MobilityOptionIpV4HomeAddress : IpV6MobilityOptionComplex public sealed class IpV6MobilityOptionIpV4HomeAddress : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{ {
public const byte MaxPrefixLength = 0x3F; public const byte MaxPrefixLength = 0x3F;
......
...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre> /// </pre>
/// </summary> /// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddressReply)] [IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddressReply)]
public sealed class IpV6MobilityOptionIpV4HomeAddressReply : IpV6MobilityOptionComplex public sealed class IpV6MobilityOptionIpV4HomeAddressReply : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{ {
public const byte MaxPrefixLength = 0x3F; public const byte MaxPrefixLength = 0x3F;
......
...@@ -3,6 +3,15 @@ using PcapDotNet.Packets.IpV4; ...@@ -3,6 +3,15 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6 namespace PcapDotNet.Packets.IpV6
{ {
/// <summary>
/// RFC 5844.
/// </summary>
public interface IIpV6MobilityOptionIpV4HomeAddress
{
byte PrefixLength { get; }
IpV4Address HomeAddress { get; }
}
/// <summary> /// <summary>
/// RFC 5844. /// RFC 5844.
/// <pre> /// <pre>
...@@ -19,7 +28,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -19,7 +28,7 @@ namespace PcapDotNet.Packets.IpV6
/// </pre> /// </pre>
/// </summary> /// </summary>
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddressRequest)] [IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.IpV4HomeAddressRequest)]
public sealed class IpV6MobilityOptionIpV4HomeAddressRequest : IpV6MobilityOptionComplex public sealed class IpV6MobilityOptionIpV4HomeAddressRequest : IpV6MobilityOptionComplex, IIpV6MobilityOptionIpV4HomeAddress
{ {
public const byte MaxPrefixLength = 0x3F; public const byte MaxPrefixLength = 0x3F;
......
using System;
namespace PcapDotNet.Packets.IpV6 namespace PcapDotNet.Packets.IpV6
{ {
/// <summary> /// <summary>
...@@ -20,6 +22,8 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -20,6 +22,8 @@ namespace PcapDotNet.Packets.IpV6
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.MobileNodeIdentifier)] [IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.MobileNodeIdentifier)]
public sealed class IpV6MobilityOptionMobileNodeIdentifier : IpV6MobilityOptionComplex public sealed class IpV6MobilityOptionMobileNodeIdentifier : IpV6MobilityOptionComplex
{ {
public const int MinNetworkAccessIdentifierLength = 1;
private static class Offset private static class Offset
{ {
public const int Subtype = 0; public const int Subtype = 0;
...@@ -31,6 +35,10 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -31,6 +35,10 @@ namespace PcapDotNet.Packets.IpV6
public IpV6MobilityOptionMobileNodeIdentifier(IpV6MobileNodeIdentifierSubtype subtype, DataSegment identifier) public IpV6MobilityOptionMobileNodeIdentifier(IpV6MobileNodeIdentifierSubtype subtype, DataSegment identifier)
: base(IpV6MobilityOptionType.MobileNodeIdentifier) : 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; Subtype = subtype;
Identifier = identifier; Identifier = identifier;
} }
...@@ -52,6 +60,8 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -52,6 +60,8 @@ namespace PcapDotNet.Packets.IpV6
IpV6MobileNodeIdentifierSubtype subtype = (IpV6MobileNodeIdentifierSubtype)data[Offset.Subtype]; IpV6MobileNodeIdentifierSubtype subtype = (IpV6MobileNodeIdentifierSubtype)data[Offset.Subtype];
DataSegment identifier = data.Subsegment(Offset.Identifier, data.Length - Offset.Identifier); DataSegment identifier = data.Subsegment(Offset.Identifier, data.Length - Offset.Identifier);
if (subtype == IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier && identifier.Length < MinNetworkAccessIdentifierLength)
return null;
return new IpV6MobilityOptionMobileNodeIdentifier(subtype, identifier); return new IpV6MobilityOptionMobileNodeIdentifier(subtype, identifier);
} }
...@@ -74,7 +84,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -74,7 +84,7 @@ namespace PcapDotNet.Packets.IpV6
} }
private IpV6MobilityOptionMobileNodeIdentifier() private IpV6MobilityOptionMobileNodeIdentifier()
: this(IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier, DataSegment.Empty) : this(IpV6MobileNodeIdentifierSubtype.NetworkAccessIdentifier, new DataSegment(new byte[1]))
{ {
} }
......
...@@ -25,8 +25,8 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -25,8 +25,8 @@ namespace PcapDotNet.Packets.IpV6
{ {
private static class Offset private static class Offset
{ {
public const int PrefixLength = sizeof(ushort); public const int PrefixLength = sizeof(byte);
public const int NetworkPrefix = PrefixLength + sizeof(ushort); public const int NetworkPrefix = PrefixLength + sizeof(byte);
} }
public const int OptionDataLength = Offset.NetworkPrefix + IpV6Address.SizeOf; public const int OptionDataLength = Offset.NetworkPrefix + IpV6Address.SizeOf;
......
using System;
namespace PcapDotNet.Packets.IpV6 namespace PcapDotNet.Packets.IpV6
{ {
/// <summary> /// <summary>
...@@ -16,9 +18,16 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -16,9 +18,16 @@ namespace PcapDotNet.Packets.IpV6
[IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.ServiceSelection)] [IpV6MobilityOptionTypeRegistration(IpV6MobilityOptionType.ServiceSelection)]
public sealed class IpV6MobilityOptionServiceSelection : IpV6MobilityOptionSingleDataSegmentField public sealed class IpV6MobilityOptionServiceSelection : IpV6MobilityOptionSingleDataSegmentField
{ {
public const int MinIdentifierLength = 1;
public const int MaxIdentifierLength = 255;
public IpV6MobilityOptionServiceSelection(DataSegment data) public IpV6MobilityOptionServiceSelection(DataSegment data)
: base(IpV6MobilityOptionType.ServiceSelection, 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> /// <summary>
...@@ -37,11 +46,14 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -37,11 +46,14 @@ namespace PcapDotNet.Packets.IpV6
internal override IpV6MobilityOption CreateInstance(DataSegment data) internal override IpV6MobilityOption CreateInstance(DataSegment data)
{ {
if (data.Length < MinIdentifierLength || data.Length > MaxIdentifierLength)
return null;
return new IpV6MobilityOptionServiceSelection(data); return new IpV6MobilityOptionServiceSelection(data);
} }
private IpV6MobilityOptionServiceSelection() private IpV6MobilityOptionServiceSelection()
: this(DataSegment.Empty) : this(new DataSegment(new byte[1]))
{ {
} }
} }
......
using System;
namespace PcapDotNet.Packets.IpV6 namespace PcapDotNet.Packets.IpV6
{ {
/// <summary> /// <summary>
...@@ -33,6 +35,22 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -33,6 +35,22 @@ namespace PcapDotNet.Packets.IpV6
get { return Value; } 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) internal override IpV6MobilityOption CreateInstance(DataSegment data)
{ {
ulong timestamp; ulong timestamp;
...@@ -46,5 +64,7 @@ namespace PcapDotNet.Packets.IpV6 ...@@ -46,5 +64,7 @@ namespace PcapDotNet.Packets.IpV6
: this(0) : 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