Commit 343e7103 authored by Brickner_cp's avatar Brickner_cp

Add support for layers over IPv6.

parent e7f558c9
using PcapDotNet.Packets.IpV6;
namespace PcapDotNet.Core.Test
{
internal static class IpV6AddressExtensions
{
public static string GetWiresharkString(this IpV6Address address)
{
string str = address.ToString("x");
if (str.StartsWith("0:0:"))
str = "::" + str.Substring(4);
if (str.EndsWith(":0:0"))
str = str.Substring(0, str.Length - 4) + "::";
str = str.Replace(":0:0:", "::");
return str;
}
}
}
\ No newline at end of file
......@@ -134,6 +134,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BerkeleyPacketFilterTests.cs" />
<Compile Include="IpV6AddressExtensions.cs" />
<Compile Include="LivePacketDeviceExtensionsTests.cs" />
<Compile Include="LivePacketDeviceTests.cs" />
<Compile Include="MarshalingServicesTests.cs" />
......
......@@ -27,7 +27,8 @@ namespace PcapDotNet.Core.Test
if (Ignore(datagram))
return null;
CompareDatagram(layer, datagramParent as Datagram, datagram);
if (!CompareDatagram(layer, datagramParent as Datagram, datagram))
return null;
return datagram;
}
......@@ -40,7 +41,7 @@ namespace PcapDotNet.Core.Test
return false;
}
protected void CompareDatagram(XElement layer, Datagram parentDatagram, Datagram datagram)
protected bool CompareDatagram(XElement layer, Datagram parentDatagram, Datagram datagram)
{
bool success = true;
foreach (var element in layer.Fields())
......@@ -53,6 +54,7 @@ namespace PcapDotNet.Core.Test
}
WiresharkCompareTests.CompareProtocols(datagram, layer, success);
return success;
}
public static WiresharkDatagramComparer GetComparer(string name, int count, bool parentLayerSuccess)
......
......@@ -44,7 +44,8 @@ namespace PcapDotNet.Core.Test
break;
case "igmp.checksum_bad":
field.AssertShowDecimal(!igmpDatagram.IsChecksumCorrect);
if (igmpDatagram.IsValid)
field.AssertShowDecimal(!igmpDatagram.IsChecksumCorrect);
break;
case "igmp.num_grp_recs":
......@@ -59,10 +60,10 @@ namespace PcapDotNet.Core.Test
break;
case IgmpMessageType.MembershipQuery:
CompareDatagram(field, null, igmpDatagram);
break;
return CompareDatagram(field, null, igmpDatagram);
case IgmpMessageType.MulticastTraceRouteResponse:
case IgmpMessageType.MulticastTraceRoute:
// todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
break;
......@@ -108,7 +109,7 @@ namespace PcapDotNet.Core.Test
case "igmp.mtrace.resp_ttl":
case "igmp.mtrace.q_id":
// todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
Assert.AreEqual(IgmpMessageType.MulticastTraceRouteResponse, igmpDatagram.MessageType);
Assert.IsTrue(new[] { IgmpMessageType.MulticastTraceRouteResponse, IgmpMessageType.MulticastTraceRoute }.Contains(igmpDatagram.MessageType));
break;
default:
......
......@@ -86,6 +86,11 @@ namespace PcapDotNet.Core.Test
case "ip.checksum":
field.AssertShowHex(ipV4Datagram.HeaderChecksum);
if (field.Showname().EndsWith(" [not all data available]"))
{
Assert.IsFalse(ipV4Datagram.IsValid);
break;
}
foreach (var checksumField in field.Fields())
{
switch (checksumField.Name())
......
......@@ -72,7 +72,7 @@ namespace PcapDotNet.Core.Test
case "ipv6.src":
case "ipv6.src_host":
field.AssertShow(ipV6Datagram.Source.ToString("x"));
field.AssertShow(ipV6Datagram.Source.GetWiresharkString());
field.AssertNoFields();
break;
......@@ -85,21 +85,34 @@ namespace PcapDotNet.Core.Test
case "ipv6.dst":
case "ipv6.dst_host":
field.AssertShow(ipV6Datagram.CurrentDestination.ToString("x"));
field.AssertShow(ipV6Datagram.CurrentDestination.GetWiresharkString());
field.AssertNoFields();
break;
case "ipv6.addr":
case "ipv6.host":
Assert.IsTrue(field.Show() == ipV6Datagram.Source.ToString("x") ||
field.Show() == ipV6Datagram.CurrentDestination.ToString("x"));
Assert.IsTrue(field.Show() == ipV6Datagram.Source.GetWiresharkString() ||
field.Show() == ipV6Datagram.CurrentDestination.GetWiresharkString());
field.AssertNoFields();
break;
case "ipv6.hop_opt":
IpV6ExtensionHeaderHopByHopOptions hopByHopOptions = (IpV6ExtensionHeaderHopByHopOptions)ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex];
IncrementCurrentExtensionHeaderIndex(ipV6Datagram);
CompareOptions(field, ref optionsIndex, hopByHopOptions);
if (_currentExtensionHeaderIndex >= ipV6Datagram.ExtensionHeaders.Headers.Count)
{
Assert.IsFalse(ipV6Datagram.ExtensionHeaders.IsValid);
int length = int.Parse(
field.Fields().Where(subfield => subfield.Name() == "" && subfield.Show().StartsWith("Length:")).Select(
subfield => subfield.Show().Split(new[] {':', '(', ' '}, StringSplitOptions.RemoveEmptyEntries)[2]).First());
int maxLength = ipV6Datagram.Length - IpV6Datagram.HeaderLength - ipV6Datagram.ExtensionHeaders.BytesLength;
MoreAssert.IsBigger(maxLength, length);
}
else
{
IpV6ExtensionHeaderHopByHopOptions hopByHopOptions =
(IpV6ExtensionHeaderHopByHopOptions)ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex];
IncrementCurrentExtensionHeaderIndex(ipV6Datagram);
CompareOptions(field, ref optionsIndex, hopByHopOptions);
}
break;
case "ipv6.routing_hdr":
......@@ -237,12 +250,14 @@ namespace PcapDotNet.Core.Test
break;
case "ipv6.opt.pad1":
Assert.AreEqual(IpV6OptionType.Pad1, header.Options[optionsIndex++].OptionType);
if (header.Options.IsValid)
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);
if (header.Options.IsValid)
headerField.AssertShowDecimal(header.Options[optionsIndex++].Length);
break;
case "ipv6.mipv6_type":
......@@ -299,7 +314,8 @@ namespace PcapDotNet.Core.Test
break;
case "Length":
Assert.IsTrue(headerFieldShowValue.EndsWith(" (" + header.Length + " bytes)"));
if (header.IsValid)
Assert.IsTrue(headerFieldShowValue.EndsWith(" (" + header.Length + " bytes)"));
break;
case "Router alert":
......
......@@ -29,6 +29,11 @@ namespace PcapDotNet.Core.Test
do
{
++_currentExtensionHeaderIndex;
if (_currentExtensionHeaderIndex >= ipV6Datagram.ExtensionHeaders.Headers.Count)
{
Assert.IsFalse(ipV6Datagram.ExtensionHeaders.IsValid);
return false;
}
} while (ipV6Datagram.ExtensionHeaders[_currentExtensionHeaderIndex].Protocol != IpV4Protocol.AuthenticationHeader);
--_count;
}
......
......@@ -787,7 +787,7 @@ namespace PcapDotNet.Core.Test
break;
case IpV6MobilityOptionType.MobileNodeIdentifier:
optionField.AssertShow("Mobile Node Identifier");
Assert.IsTrue(optionField.Show().StartsWith("Mobile Node Identifier"));
IpV6MobilityOptionMobileNodeIdentifier mobileNodeIdentifier = (IpV6MobilityOptionMobileNodeIdentifier)option;
foreach (XElement optionSubfield in optionField.Fields())
{
......
......@@ -4,6 +4,7 @@ using System.Text;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ip;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils;
......@@ -19,7 +20,7 @@ namespace PcapDotNet.Core.Test
protected override bool CompareField(XElement field, Datagram parentDatagram, Datagram datagram)
{
IpV4Datagram ipV4Datagram = (IpV4Datagram)parentDatagram;
IpDatagram ipDatagram = (IpDatagram)parentDatagram;
TcpDatagram tcpDatagram = (TcpDatagram)datagram;
switch (field.Name())
......@@ -126,7 +127,8 @@ namespace PcapDotNet.Core.Test
case "tcp.checksum":
field.AssertShowHex(tcpDatagram.Checksum);
if (!ipV4Datagram.Options.IsBadForWireshark())
IpV4Datagram ipV4Datagram = ipDatagram as IpV4Datagram;
if (ipV4Datagram != null && !ipV4Datagram.Options.IsBadForWireshark())
{
foreach (var checksumField in field.Fields())
{
......@@ -134,11 +136,11 @@ namespace PcapDotNet.Core.Test
switch (checksumField.Name())
{
case "tcp.checksum_good":
checksumField.AssertShowDecimal(tcpDatagram.Checksum != 0 && ipV4Datagram.IsTransportChecksumCorrect);
checksumField.AssertShowDecimal(tcpDatagram.Checksum != 0 && ipDatagram.IsTransportChecksumCorrect);
break;
case "tcp.checksum_bad":
checksumField.AssertShowDecimal(tcpDatagram.Checksum != 0 && !ipV4Datagram.IsTransportChecksumCorrect);
checksumField.AssertShowDecimal(tcpDatagram.Checksum != 0 && !ipDatagram.IsTransportChecksumCorrect);
break;
default:
......@@ -183,6 +185,7 @@ namespace PcapDotNet.Core.Test
Assert.IsFalse(options.IsValid, "Options IsValid");
Assert.IsTrue(
field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net
field.Show().StartsWith("Echo reply (with option length = ") ||
field.Show().Contains("bytes says option goes past end of options") ||
field.Show().Contains(") (with too-short option length = ") ||
field.Show().EndsWith(" (length byte past end of options)"),
......
......@@ -2,6 +2,7 @@
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ip;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
......@@ -16,7 +17,7 @@ namespace PcapDotNet.Core.Test
protected override bool CompareField(XElement field, Datagram parentDatagram, Datagram datagram)
{
IpV4Datagram ipV4Datagram = (IpV4Datagram)parentDatagram;
IpDatagram ipDatagram = (IpDatagram)parentDatagram;
UdpDatagram udpDatagram = (UdpDatagram)datagram;
switch (field.Name())
......@@ -47,12 +48,12 @@ namespace PcapDotNet.Core.Test
switch (checksumField.Name())
{
case "udp.checksum_good":
checksumField.AssertShowDecimal(ipV4Datagram.IsTransportChecksumCorrect);
checksumField.AssertShowDecimal(ipDatagram.IsTransportChecksumCorrect);
break;
case "udp.checksum_bad":
if (checksumField.Show() == "1")
Assert.IsFalse(ipV4Datagram.IsTransportChecksumCorrect);
Assert.IsFalse(ipDatagram.IsTransportChecksumCorrect);
else
checksumField.AssertShowDecimal(0);
break;
......
......@@ -375,9 +375,29 @@ namespace PcapDotNet.Packets
return sum;
}
internal static uint Sum16Bits(IpV6Address address)
{
return Sum16Bits(address.ToValue());
}
internal static uint Sum16Bits(IpV4Address address)
{
uint value = address.ToValue();
return Sum16Bits(address.ToValue());
}
internal static uint Sum16Bits(UInt128 value)
{
return Sum16Bits((ulong)(value >> 64)) + Sum16Bits((ulong)value);
}
internal static uint Sum16Bits(ulong value)
{
return Sum16Bits((uint)(value >> 32)) + Sum16Bits((uint)value);
}
internal static uint Sum16Bits(uint value)
{
return (value >> 16) + (value & 0xFFFF);
}
......
using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Packets.Ip
{
/// <summary>
/// RFCs 791, 2460.
/// Represents an IP datagram.
/// <pre>
/// +-----+---------+
/// | Bit | 0-3 |
/// +-----+---------+
/// | 0 | Version |
/// +-----+---------+
/// | 4 | |
/// | ... | |
/// +-----+---------+
/// </pre>
/// </summary>
public abstract class IpDatagram : Datagram
{
private static class Offset
{
public const int Version = 0;
}
private static class Mask
{
public const byte Version = 0xF0;
}
private static class Shift
{
public const int Version = 4;
}
/// <summary>
/// Indicates the format of the internet header (Internet Protocol version).
/// </summary>
public byte Version
{
get { return (byte)((this[Offset.Version] & Mask.Version) >> Shift.Version); }
}
public abstract int TotalLength { get; }
/// <summary>
/// Returns whether the TCP or UDP checksum is correct.
/// The protocol must be TCP or UDP.
/// For UDP, the checksum is optional, so 0 checksum is still correct.
/// </summary>
public bool IsTransportChecksumCorrect
{
get
{
if (_isTransportChecksumCorrect == null)
{
ushort transportChecksum = Transport.Checksum;
_isTransportChecksumCorrect = Length >= TotalLength &&
(Transport.IsChecksumOptional && transportChecksum == 0) ||
(CalculateTransportChecksum() == transportChecksum);
}
return _isTransportChecksumCorrect.Value;
}
}
/// <summary>
/// The payload of the datagram.
/// </summary>
public Datagram Payload
{
get
{
if (_payload == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_payload = new Datagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _payload;
}
}
/// <summary>
/// The payload of the datagram as an IPv4 datagram (IP over IP).
/// </summary>
public IpV4Datagram IpV4
{
get
{
if (_ipV4 == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_ipV4 = new IpV4Datagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _ipV4;
}
}
/// <summary>
/// The payload of the datagram as an IPv6 datagram (IP over IP).
/// </summary>
public IpV6Datagram IpV6
{
get
{
if (_ipV6 == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_ipV6 = new IpV6Datagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _ipV6;
}
}
/// <summary>
/// The payload of the datagram as an ICMP datagram.
/// </summary>
public IcmpDatagram Icmp
{
get
{
if (_icmp == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_icmp = IcmpDatagram.CreateDatagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _icmp;
}
}
/// <summary>
/// The payload of the datagram as an IGMP datagram.
/// </summary>
public IgmpDatagram Igmp
{
get
{
if (_igmp == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_igmp = new IgmpDatagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _igmp;
}
}
/// <summary>
/// The payload of the datagram as a TCP datagram.
/// </summary>
public TcpDatagram Tcp
{
get
{
if (_tcp == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_tcp = new TcpDatagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _tcp;
}
}
/// <summary>
/// The payload of the datagram as a GRE datagram.
/// </summary>
public GreDatagram Gre
{
get
{
if (_gre == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_gre = new GreDatagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _gre;
}
}
/// <summary>
/// The payload of the datagram as a UDP datagram.
/// </summary>
public UdpDatagram Udp
{
get
{
if (_udp == null)
{
DataSegment payload = GetPayload();
if (payload != null)
_udp = new UdpDatagram(payload.Buffer, payload.StartOffset, payload.Length);
}
return _udp;
}
}
/// <summary>
/// Returns the Tranposrt Datagram.
/// This is either a TCP Datagram or a UDP Datagram (according to the payload protocol).
/// </summary>
public TransportDatagram Transport
{
get
{
switch (PayloadProtocol)
{
case IpV4Protocol.Tcp:
return Tcp;
case IpV4Protocol.Udp:
return Udp;
default:
return null;
}
}
}
protected abstract ushort CalculateTransportChecksum();
internal IpDatagram(byte[] buffer, int offset, int length)
: base(buffer, offset, length)
{
}
internal abstract IpV4Protocol PayloadProtocol { get; }
internal abstract DataSegment GetPayload();
private bool? _isTransportChecksumCorrect;
private Datagram _payload;
private IpV4Datagram _ipV4;
private IpV6Datagram _ipV6;
private IcmpDatagram _icmp;
private IgmpDatagram _igmp;
private GreDatagram _gre;
private TcpDatagram _tcp;
private UdpDatagram _udp;
}
}
\ No newline at end of file
......@@ -4,13 +4,14 @@ using System.Linq;
using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.Ip;
using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Packets.IpV4
{
/// <summary>
/// RFC 791.
/// Represents an IPv4 datagram.
///
/// <pre>
/// +-----+---------+-----+-----------------+-------+-----------------+
/// | Bit | 0-3 | 4-7 | 8-15 | 16-18 | 19-31 |
......@@ -33,7 +34,7 @@ namespace PcapDotNet.Packets.IpV4
/// +-----+-----------------------------------------------------------+
/// </pre>
/// </summary>
public sealed class IpV4Datagram : Datagram
public sealed class IpV4Datagram : IpDatagram
{
/// <summary>
/// The minimum length of the header in bytes.
......@@ -63,15 +64,7 @@ namespace PcapDotNet.Packets.IpV4
/// <summary>
/// The version (4).
/// </summary>
public const int DefaultVersion = 0x4;
/// <summary>
/// Indicates the format of the internet header.
/// </summary>
public int Version
{
get { return (this[Offset.VersionAndHeaderLength] & 0xF0) >> 4; }
}
public const byte DefaultVersion = 0x4;
/// <summary>
/// The header length in bytes.
......@@ -100,7 +93,7 @@ namespace PcapDotNet.Packets.IpV4
/// <summary>
/// The length of the entire datagram as stated in the total length field.
/// </summary>
public ushort TotalLength
public override int TotalLength
{
get { return ReadUShort(Offset.TotalLength, Endianity.Big); }
}
......@@ -204,26 +197,6 @@ namespace PcapDotNet.Packets.IpV4
}
}
/// <summary>
/// Returns whether the TCP or UDP checksum is correct.
/// The protocol must be TCP or UDP.
/// For UDP, the checksum is optional, so 0 checksum is still correct.
/// </summary>
public bool IsTransportChecksumCorrect
{
get
{
if (_isTransportChecksumCorrect == null)
{
ushort transportChecksum = Transport.Checksum;
_isTransportChecksumCorrect = Length >= TotalLength &&
(Transport.IsChecksumOptional && transportChecksum == 0) ||
(CalculateTransportChecksum() == transportChecksum);
}
return _isTransportChecksumCorrect.Value;
}
}
/// <summary>
/// Creates a Layer that represents the datagram to be used with PacketBuilder.
/// </summary>
......@@ -243,122 +216,16 @@ namespace PcapDotNet.Packets.IpV4
};
}
/// <summary>
/// The payload of the datagram.
/// </summary>
public Datagram Payload
{
get
{
if (_payload == null && Length >= HeaderLength)
_payload = new Datagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _payload;
}
}
/// <summary>
/// The payload of the datagram as an IPv4 datagram (IP over IP).
/// </summary>
public IpV4Datagram IpV4
{
get
{
if (_ipV4 == null && Length >= HeaderLength)
_ipV4 = new IpV4Datagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _ipV4;
}
}
/// <summary>
/// The payload of the datagram as an ICMP datagram.
/// </summary>
public IcmpDatagram Icmp
{
get
{
if (_icmp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_icmp = IcmpDatagram.CreateDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _icmp;
}
}
/// <summary>
/// The payload of the datagram as an IGMP datagram.
/// </summary>
public IgmpDatagram Igmp
{
get
{
if (_igmp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_igmp = new IgmpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _igmp;
}
}
/// <summary>
/// The payload of the datagram as a TCP datagram.
/// </summary>
public TcpDatagram Tcp
{
get
{
if (_tcp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_tcp = new TcpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _tcp;
}
}
/// <summary>
/// The payload of the datagram as a GRE datagram.
/// </summary>
public GreDatagram Gre
internal override IpV4Protocol PayloadProtocol
{
get
{
if (_gre == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_gre = new GreDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _gre;
}
get { return Protocol; }
}
/// <summary>
/// The payload of the datagram as a UDP datagram.
/// </summary>
public UdpDatagram Udp
internal override DataSegment GetPayload()
{
get
{
if (_udp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_udp = new UdpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _udp;
}
}
/// <summary>
/// Returns the Tranposrt Datagram.
/// This is either a TCP Datagram or a UDP Datagram (according to the protocol).
/// </summary>
public TransportDatagram Transport
{
get
{
switch (Protocol)
{
case IpV4Protocol.Tcp:
return Tcp;
case IpV4Protocol.Udp:
return Udp;
default:
return null;
}
}
if (Length < HeaderMinimumLength || Length < HeaderLength)
return null;
return Subsegment(HeaderLength, Length - HeaderLength);
}
internal static int GetTotalLength(Datagram ipV4Datagram)
......@@ -466,6 +333,11 @@ namespace PcapDotNet.Packets.IpV4
}
}
protected override ushort CalculateTransportChecksum()
{
return CalculateTransportChecksum(Buffer, StartOffset, HeaderLength, (ushort)Transport.Length, Transport.ChecksumOffset, Transport.IsChecksumOptional, Destination);
}
private ushort CalculateHeaderChecksum()
{
uint sum = Sum16Bits(Buffer, StartOffset, Math.Min(Offset.HeaderChecksum, Length)) +
......@@ -474,11 +346,6 @@ namespace PcapDotNet.Packets.IpV4
return Sum16BitsToChecksum(sum);
}
private ushort CalculateTransportChecksum()
{
return CalculateTransportChecksum(Buffer, StartOffset, HeaderLength, (ushort)Transport.Length, Transport.ChecksumOffset, Transport.IsChecksumOptional, Destination);
}
private static ushort CalculateTransportChecksum(byte[] buffer, int offset, int headerLength, ushort transportLength, int transportChecksumOffset, bool isChecksumOptional, IpV4Address destination)
{
int offsetAfterChecksum = offset + headerLength + transportChecksumOffset + 2;
......@@ -496,14 +363,6 @@ namespace PcapDotNet.Packets.IpV4
private IpV4Address? _destination;
private bool? _isHeaderChecksumCorrect;
private bool? _isTransportChecksumCorrect;
private IpV4Options _options;
private Datagram _payload;
private IpV4Datagram _ipV4;
private IcmpDatagram _icmp;
private IgmpDatagram _igmp;
private GreDatagram _gre;
private TcpDatagram _tcp;
private UdpDatagram _udp;
}
}
\ No newline at end of file
......@@ -98,30 +98,6 @@ namespace PcapDotNet.Packets.IpV6
}
}
internal static void GetNextNextHeaderAndLength(IpV4Protocol nextHeader, DataSegment data, out IpV4Protocol? nextNextHeader,
out int extensionHeaderLength)
{
if (IpV6ExtensionHeaderStandard.IsStandard(nextHeader))
{
IpV6ExtensionHeaderStandard.GetNextNextHeaderAndLength(data, out nextNextHeader, out extensionHeaderLength);
return;
}
switch (nextHeader)
{
case IpV4Protocol.EncapsulatingSecurityPayload: // 50
IpV6ExtensionHeaderEncapsulatingSecurityPayload.GetNextNextHeaderAndLength(data, out nextNextHeader, out extensionHeaderLength);
break;
case IpV4Protocol.AuthenticationHeader: // 51
IpV6ExtensionHeaderAuthentication.GetNextNextHeaderAndLength(data, out nextNextHeader, out extensionHeaderLength);
break;
default:
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Invalid next header value {0}", nextHeader));
}
}
internal abstract void Write(byte[] buffer, ref int offset);
private static readonly ReadOnlyCollection<IpV4Protocol> _extensionHeaders =
......
......@@ -200,19 +200,6 @@ namespace PcapDotNet.Packets.IpV6
return new IpV6ExtensionHeaderAuthentication(nextHeader, securityParametersIndex, sequenceNumber, authenticationData);
}
internal static void GetNextNextHeaderAndLength(DataSegment extensionHeader, out IpV4Protocol? nextNextHeader, out int extensionHeaderLength)
{
if (extensionHeader.Length < MinimumLength)
{
nextNextHeader = null;
extensionHeaderLength = extensionHeader.Length;
return;
}
nextNextHeader = (IpV4Protocol)extensionHeader[Offset.NextHeader];
extensionHeaderLength = (extensionHeader[Offset.PayloadLength] + 2) * 4;
}
internal override void Write(byte[] buffer, ref int offset)
{
buffer.Write(offset + Offset.NextHeader, (byte)NextHeader);
......
......@@ -209,12 +209,6 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public DataSegment EncryptedDataAndAuthenticationData { get; private set; }
internal static void GetNextNextHeaderAndLength(DataSegment extensionHeader, out IpV4Protocol? nextNextHeader, out int extensionHeaderLength)
{
nextNextHeader = null;
extensionHeaderLength = extensionHeader.Length;
}
internal static IpV6ExtensionHeaderEncapsulatingSecurityPayload CreateInstance(DataSegment extensionHeaderData, out int numBytesRead)
{
if (extensionHeaderData.Length < MinimumLength)
......
......@@ -128,18 +128,6 @@ namespace PcapDotNet.Packets.IpV6
}
}
internal static void GetNextNextHeaderAndLength(DataSegment extensionHeader, out IpV4Protocol? nextNextHeader, out int extensionHeaderLength)
{
if (extensionHeader.Length < MinimumLength)
{
nextNextHeader = null;
extensionHeaderLength = extensionHeader.Length;
return;
}
nextNextHeader = (IpV4Protocol)extensionHeader[Offset.NextHeader];
extensionHeaderLength = Math.Min(extensionHeader.Length / 8 * 8, (extensionHeader[Offset.HeaderExtensionLength] + 1) * 8);
}
internal static ReadOnlyCollection<IpV4Protocol> StandardExtensionHeaders
{
get { return _standardExtensionHeaders; }
......
......@@ -110,6 +110,8 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public ReadOnlyCollection<IpV6ExtensionHeader> Headers { get; private set; }
public int BytesLength { get; private set; }
/// <summary>
/// True iff a parsing issue wasn't encountered when parsing the extension headers.
/// </summary>
......@@ -188,6 +190,7 @@ namespace PcapDotNet.Packets.IpV6
internal IpV6ExtensionHeaders(DataSegment data, IpV4Protocol firstHeader)
{
BytesLength = 0;
IpV4Protocol? nextHeader = firstHeader;
List<IpV6ExtensionHeader> headers = new List<IpV6ExtensionHeader>();
while (data.Length >= 8 && nextHeader.HasValue && IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value))
......@@ -196,6 +199,7 @@ namespace PcapDotNet.Packets.IpV6
IpV6ExtensionHeader extensionHeader = IpV6ExtensionHeader.CreateInstance(nextHeader.Value, data, out numBytesRead);
if (extensionHeader == null)
break;
BytesLength += numBytesRead;
headers.Add(extensionHeader);
nextHeader = extensionHeader.NextHeader;
data = data.Subsegment(numBytesRead, data.Length - numBytesRead);
......
......@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ip;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.IpV6
......@@ -32,7 +33,7 @@ namespace PcapDotNet.Packets.IpV6
/// +-----+-----------------------------------------------------------+
/// </pre>
/// </summary>
public sealed class IpV6Datagram : Datagram
public sealed class IpV6Datagram : IpDatagram
{
/// <summary>
/// The number of bytes the header takes in bytes (not including extension headers).
......@@ -74,14 +75,6 @@ namespace PcapDotNet.Packets.IpV6
/// </summary>
public const int DefaultVersion = 0x6;
/// <summary>
/// Internet Protocol version number.
/// </summary>
public byte Version
{
get { return (byte)((this[Offset.Version] & Mask.Version) >> Shift.Version); }
}
/// <summary>
/// Available for use by originating nodes and/or forwarding routers to identify and distinguish between different classes or priorities of
/// IPv6 packets.
......@@ -170,6 +163,49 @@ namespace PcapDotNet.Packets.IpV6
}
}
public override int TotalLength
{
get { return HeaderLength + PayloadLength; }
}
protected override ushort CalculateTransportChecksum()
{
return CalculateTransportChecksum(Buffer, StartOffset, (ushort)Transport.Length, Transport.ChecksumOffset, Transport.IsChecksumOptional, CurrentDestination);
}
private static ushort CalculateTransportChecksum(byte[] buffer, int offset, ushort transportLength, int transportChecksumOffset, bool isChecksumOptional, IpV6Address destination)
{
int offsetAfterChecksum = offset + HeaderLength + transportChecksumOffset + 2;
uint sum = Sum16Bits(buffer, offset + Offset.SourceAddress, IpV6Address.SizeOf) +
Sum16Bits(destination) +
transportLength + buffer[offset + Offset.NextHeader] +
Sum16Bits(buffer, offset + HeaderLength, transportChecksumOffset) +
Sum16Bits(buffer, offsetAfterChecksum, transportLength - transportChecksumOffset - 2);
ushort checksumResult = Sum16BitsToChecksum(sum);
if (checksumResult == 0 && isChecksumOptional)
return 0xFFFF;
return checksumResult;
}
internal override IpV4Protocol PayloadProtocol
{
get
{
IpV4Protocol? extensionHeadersNextHeader = ExtensionHeaders.NextHeader;
if (extensionHeadersNextHeader != null)
return extensionHeadersNextHeader.Value;
return NextHeader;
}
}
internal override DataSegment GetPayload()
{
if (Length < HeaderLength)
return null;
return Subsegment(HeaderLength + ExtensionHeaders.BytesLength, Length - HeaderLength - ExtensionHeaders.BytesLength);
}
private void ParseExtensionHeaders()
{
if (_extensionHeaders != null)
......@@ -221,16 +257,7 @@ namespace PcapDotNet.Packets.IpV6
if (payload.Length <= HeaderLength)
return payload.Length;
int totalLength = HeaderLength;
IpV4Protocol? nextHeader = (IpV4Protocol)payload[Offset.NextHeader];
while (nextHeader.HasValue && IpV6ExtensionHeader.IsExtensionHeader(nextHeader.Value))
{
int extensionHeaderLength;
IpV6ExtensionHeader.GetNextNextHeaderAndLength(nextHeader.Value, payload.Subsegment(totalLength, payload.Length - totalLength), out nextHeader,
out extensionHeaderLength);
totalLength += extensionHeaderLength;
}
return totalLength;
return Math.Min(payload.Length, HeaderLength + payload.ReadUShort(Offset.PayloadLength, Endianity.Big));
}
internal static void WriteHeader(byte[] buffer, int offset,
......
......@@ -316,6 +316,7 @@
<Compile Include="Igmp\IgmpRecordType.cs" />
<Compile Include="Igmp\IgmpMessageType.cs" />
<Compile Include="Igmp\IIgmpLayerWithGroupAddress.cs" />
<Compile Include="Ip\IpDatagram.cs" />
<Compile Include="IpV6\IpV6BindingAcknowledgementStatus.cs" />
<Compile Include="IpV6\ExtensionHeaders\IpV6BindingErrorStatus.cs" />
<Compile Include="IpV6\ExtensionHeaders\IpV6ExtensionHeaderMobility.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment