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