Commit ab9ff77a authored by Brickner_cp's avatar Brickner_cp

Upgraded Wireshark comparing tests to Wireshark 1.6.6.

Fixed IPv4 destination, to be according to source routing options when they exist. Also fix transport checksum calculation to use it.
Added IgmpMessageTypeMulticastTraceroute.
Added TcpOptionType.SelectiveNegativeAcknowledgements.
Improved ArpLayer.GetHashCode().

Malformed packets improvements:
* Support for more than one space between status code and reason phrase in HTTP response (even though it's not according to HTTP RFCs).
* Better handling of malformed IPv4.
* Better handling of malformed TCP.
* Better handling of malformed GRE.
* Better handling of malformed IGMP.
parent 8cc01e4a
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
<Compile Include="PropertyInfoExtensions.cs" /> <Compile Include="PropertyInfoExtensions.cs" />
<Compile Include="Sequence.cs" /> <Compile Include="Sequence.cs" />
<Compile Include="SerialNumber32.cs" /> <Compile Include="SerialNumber32.cs" />
<Compile Include="ShortExtensions.cs" />
<Compile Include="TimeSpanExtensions.cs" /> <Compile Include="TimeSpanExtensions.cs" />
<Compile Include="TypeExtensions.cs" /> <Compile Include="TypeExtensions.cs" />
<Compile Include="UInt128.cs" /> <Compile Include="UInt128.cs" />
...@@ -106,6 +107,7 @@ ...@@ -106,6 +107,7 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UInt48.cs" /> <Compile Include="UInt48.cs" />
<Compile Include="UIntExtensions.cs" /> <Compile Include="UIntExtensions.cs" />
<Compile Include="UShortExtensions.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\PcapDotNet.snk" /> <None Include="..\PcapDotNet.snk" />
......
using System.Net;
namespace PcapDotNet.Base
{
/// <summary>
/// Extension method for Short structure.
/// </summary>
public static class ShortExtensions
{
public static short ReverseEndianity(this short value)
{
return IPAddress.HostToNetworkOrder(value);
}
}
}
\ No newline at end of file
using System;
namespace PcapDotNet.Base
{
/// <summary>
/// Extension method for UShort structure.
/// </summary>
public static class UShortExtensions
{
public static ushort ReverseEndianity(this ushort value)
{
return (ushort)((short)value).ReverseEndianity();
}
}
}
\ No newline at end of file
...@@ -7,17 +7,17 @@ using PcapDotNet.Packets.IpV4; ...@@ -7,17 +7,17 @@ using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
internal static class MoreIpV4Option internal static class IpV4OptionExtensions
{ {
public static string GetWiresharkString(this IpV4Option option) public static string GetWiresharkString(this IpV4Option option)
{ {
switch (option.OptionType) switch (option.OptionType)
{ {
case IpV4OptionType.EndOfOptionList: case IpV4OptionType.EndOfOptionList:
return "EOL"; return "End of Option List (EOL)";
case IpV4OptionType.NoOperation: case IpV4OptionType.NoOperation:
return "NOP"; return "No-Operation (NOP)";
case IpV4OptionType.BasicSecurity: case IpV4OptionType.BasicSecurity:
return "Security"; return "Security";
...@@ -152,5 +152,12 @@ namespace PcapDotNet.Core.Test ...@@ -152,5 +152,12 @@ namespace PcapDotNet.Core.Test
break; break;
} }
} }
public static bool IsBadForWireshark(this IpV4Options options)
{
// TODO: This shouldn't be a factor once https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7043 is fixed.
return options.OptionsCollection.Any(option => option.OptionType == IpV4OptionType.InternetTimestamp && option.Length < 5 ||
option.OptionType == IpV4OptionType.BasicSecurity && option.Length != 11);
}
} }
} }
\ No newline at end of file
...@@ -21,9 +21,6 @@ namespace PcapDotNet.Core.Test ...@@ -21,9 +21,6 @@ namespace PcapDotNet.Core.Test
{ {
public LivePacketDeviceTests() public LivePacketDeviceTests()
{ {
//
// TODO: Add constructor logic here
//
} }
/// <summary> /// <summary>
...@@ -135,7 +132,7 @@ namespace PcapDotNet.Core.Test ...@@ -135,7 +132,7 @@ namespace PcapDotNet.Core.Test
TestReceiveSomePackets(0, 0, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, 0, 1, 1.06); TestReceiveSomePackets(0, 0, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, 0, 1, 1.06);
TestReceiveSomePackets(NumPacketsToSend, NumPacketsToSend, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.02); TestReceiveSomePackets(NumPacketsToSend, NumPacketsToSend, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.02);
TestReceiveSomePackets(NumPacketsToSend, 0, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.02); TestReceiveSomePackets(NumPacketsToSend, 0, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.02);
TestReceiveSomePackets(NumPacketsToSend, -1, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.02); TestReceiveSomePackets(NumPacketsToSend, -1, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.028);
TestReceiveSomePackets(NumPacketsToSend, NumPacketsToSend + 1, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.031); TestReceiveSomePackets(NumPacketsToSend, NumPacketsToSend + 1, int.MaxValue, PacketSize, false, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.031);
// Test non blocking // Test non blocking
...@@ -155,7 +152,7 @@ namespace PcapDotNet.Core.Test ...@@ -155,7 +152,7 @@ namespace PcapDotNet.Core.Test
const int PacketSize = 100; const int PacketSize = 100;
// Normal // Normal
TestReceivePackets(NumPacketsToSend, NumPacketsToSend, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.063); TestReceivePackets(NumPacketsToSend, NumPacketsToSend, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.12);
// Wait for less packets // Wait for less packets
TestReceivePackets(NumPacketsToSend, NumPacketsToSend / 2, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend / 2, 0, 0.04); TestReceivePackets(NumPacketsToSend, NumPacketsToSend / 2, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend / 2, 0, 0.04);
...@@ -163,7 +160,7 @@ namespace PcapDotNet.Core.Test ...@@ -163,7 +160,7 @@ namespace PcapDotNet.Core.Test
// Wait for more packets // Wait for more packets
TestReceivePackets(NumPacketsToSend, 0, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.None, NumPacketsToSend, 2, 2.45); TestReceivePackets(NumPacketsToSend, 0, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.None, NumPacketsToSend, 2, 2.45);
TestReceivePackets(NumPacketsToSend, -1, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.None, NumPacketsToSend, 2, 2.3); TestReceivePackets(NumPacketsToSend, -1, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.None, NumPacketsToSend, 2, 2.3);
TestReceivePackets(NumPacketsToSend, NumPacketsToSend + 1, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.None, NumPacketsToSend, 2, 2.12); TestReceivePackets(NumPacketsToSend, NumPacketsToSend + 1, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.None, NumPacketsToSend, 2, 2.16);
// Break loop // Break loop
TestReceivePackets(NumPacketsToSend, NumPacketsToSend, 0, 2, PacketSize, PacketCommunicatorReceiveResult.BreakLoop, 0, 0, 0.027); TestReceivePackets(NumPacketsToSend, NumPacketsToSend, 0, 2, PacketSize, PacketCommunicatorReceiveResult.BreakLoop, 0, 0, 0.027);
......
...@@ -73,8 +73,8 @@ ...@@ -73,8 +73,8 @@
<Compile Include="LivePacketDeviceExtensionsTests.cs" /> <Compile Include="LivePacketDeviceExtensionsTests.cs" />
<Compile Include="LivePacketDeviceTests.cs" /> <Compile Include="LivePacketDeviceTests.cs" />
<Compile Include="MarshalingServicesTests.cs" /> <Compile Include="MarshalingServicesTests.cs" />
<Compile Include="MoreIpV4Option.cs" /> <Compile Include="IpV4OptionExtensions.cs" />
<Compile Include="MoreTcpOption.cs" /> <Compile Include="TcpOptionExtensions.cs" />
<Compile Include="WiresharkDatagramComparer.cs" /> <Compile Include="WiresharkDatagramComparer.cs" />
<Compile Include="WiresharkDatagramComparerArp.cs" /> <Compile Include="WiresharkDatagramComparerArp.cs" />
<Compile Include="WiresharkDatagramComparerDns.cs" /> <Compile Include="WiresharkDatagramComparerDns.cs" />
......
...@@ -6,17 +6,21 @@ using PcapDotNet.Packets.Transport; ...@@ -6,17 +6,21 @@ using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
internal static class MoreTcpOption internal static class TcpOptionExtensions
{ {
public static string GetWiresharkString(this TcpOption option) public static string GetWiresharkString(this TcpOption option)
{ {
switch (option.OptionType) switch (option.OptionType)
{ {
case TcpOptionType.EndOfOptionList: case TcpOptionType.EndOfOptionList:
return "EOL"; return "End of Option List (EOL)";
case TcpOptionType.NoOperation: case TcpOptionType.NoOperation:
return "NOP"; return "No-Operation (NOP)";
case TcpOptionType.WindowScale:
byte scaleFactorLog = ((TcpOptionWindowScale)option).ScaleFactorLog;
return string.Format("Window scale: {0} (multiply by {1})", scaleFactorLog, (1L << (scaleFactorLog % 32)));
case TcpOptionType.SelectiveAcknowledgmentPermitted: case TcpOptionType.SelectiveAcknowledgmentPermitted:
return "SACK permitted"; return "SACK permitted";
...@@ -37,12 +41,6 @@ namespace PcapDotNet.Core.Test ...@@ -37,12 +41,6 @@ namespace PcapDotNet.Core.Test
TcpOptionTimestamp timestampOption = (TcpOptionTimestamp)option; TcpOptionTimestamp timestampOption = (TcpOptionTimestamp)option;
return "Timestamps: TSval " + timestampOption.TimestampValue + ", TSecr " + timestampOption.TimestampEchoReply; return "Timestamps: TSval " + timestampOption.TimestampValue + ", TSecr " + timestampOption.TimestampEchoReply;
case TcpOptionType.PartialOrderServiceProfile:
return "Unknown (0x0a) (3 bytes)";
case TcpOptionType.PartialOrderConnectionPermitted:
return "Unknown (0x09) (2 bytes)";
case TcpOptionType.ConnectionCount: case TcpOptionType.ConnectionCount:
return "CC: " + ((TcpOptionConnectionCount)option).ConnectionCount; return "CC: " + ((TcpOptionConnectionCount)option).ConnectionCount;
...@@ -52,12 +50,6 @@ namespace PcapDotNet.Core.Test ...@@ -52,12 +50,6 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.ConnectionCountEcho: case TcpOptionType.ConnectionCountEcho:
return "CC.ECHO: " + ((TcpOptionConnectionCountEcho)option).ConnectionCount; return "CC.ECHO: " + ((TcpOptionConnectionCountEcho)option).ConnectionCount;
case TcpOptionType.AlternateChecksumRequest:
return "Unknown (0x0e) (3 bytes)";
case TcpOptionType.AlternateChecksumData:
return "Unknown (0x0f) (" + option.Length + " bytes)";
case TcpOptionType.Md5Signature: case TcpOptionType.Md5Signature:
return "TCP MD5 signature"; return "TCP MD5 signature";
...@@ -81,52 +73,17 @@ namespace PcapDotNet.Core.Test ...@@ -81,52 +73,17 @@ namespace PcapDotNet.Core.Test
? string.Empty ? string.Empty
: " (with option length = " + option.Length + " bytes; should be 2)"); : " (with option length = " + option.Length + " bytes; should be 2)");
default: case TcpOptionType.PartialOrderConnectionPermitted: // 9.
if (typeof(TcpOptionType).GetEnumValues<TcpOptionType>().Contains(option.OptionType)) case TcpOptionType.PartialOrderServiceProfile: // 10.
throw new InvalidOperationException("Invalid option type " + option.OptionType); case TcpOptionType.AlternateChecksumRequest: // 14.
return "Unknown (0x" + ((byte)option.OptionType).ToString("x2") + ") (" + option.Length + " bytes)"; case TcpOptionType.AlternateChecksumData: // 15.
} case TcpOptionType.Mood: // 25.
} return string.Format("Unknown (0x{0}) ({1} bytes)", ((byte)option.OptionType).ToString("x2"), option.Length);
public static IEnumerable<string> GetWiresharkSubfieldStrings(this TcpOption option)
{
switch (option.OptionType)
{
case TcpOptionType.EndOfOptionList:
case TcpOptionType.NoOperation:
case TcpOptionType.MaximumSegmentSize:
case TcpOptionType.WindowScale:
case TcpOptionType.SelectiveAcknowledgmentPermitted:
case TcpOptionType.Echo:
case TcpOptionType.EchoReply:
case TcpOptionType.Timestamp:
case TcpOptionType.PartialOrderServiceProfile:
case TcpOptionType.PartialOrderConnectionPermitted:
case TcpOptionType.ConnectionCount:
case TcpOptionType.ConnectionCountNew:
case TcpOptionType.ConnectionCountEcho:
case TcpOptionType.AlternateChecksumRequest:
case TcpOptionType.AlternateChecksumData:
case TcpOptionType.Md5Signature:
case TcpOptionType.Mood:
break;
case TcpOptionType.SelectiveAcknowledgment:
var blocks = ((TcpOptionSelectiveAcknowledgment)option).Blocks;
if (blocks.Count() == 0)
break;
yield return "1";
foreach (TcpOptionSelectiveAcknowledgmentBlock block in blocks)
{
yield return block.LeftEdge.ToString();
yield return block.RightEdge.ToString();
}
break;
default: default:
if (typeof(TcpOptionType).GetEnumValues<TcpOptionType>().Contains(option.OptionType)) if (typeof(TcpOptionType).GetEnumValues<TcpOptionType>().Contains(option.OptionType))
throw new InvalidOperationException("Invalid option type " + option.OptionType); throw new InvalidOperationException("Invalid option type " + option.OptionType);
break; return string.Format("Unknown (0x{0}) ({1} bytes)", ((byte)option.OptionType).ToString("x2"), option.Length);
} }
} }
} }
......
...@@ -28,10 +28,11 @@ namespace PcapDotNet.Core.Test ...@@ -28,10 +28,11 @@ namespace PcapDotNet.Core.Test
private const string WiresharkDiretory = @"C:\Program Files\Wireshark\"; private const string WiresharkDiretory = @"C:\Program Files\Wireshark\";
private const string WiresharkTsharkPath = WiresharkDiretory + @"tshark.exe"; private const string WiresharkTsharkPath = WiresharkDiretory + @"tshark.exe";
private const bool IsRetry private static bool IsRetry
// = true; {
= false; get { return RetryNumber != -1; }
private const byte RetryNumber = 27; }
private const int RetryNumber = -1;
/// <summary> /// <summary>
/// Gets or sets the test context which provides /// Gets or sets the test context which provides
...@@ -237,10 +238,11 @@ namespace PcapDotNet.Core.Test ...@@ -237,10 +238,11 @@ namespace PcapDotNet.Core.Test
UdpLayer udpLayer = random.NextUdpLayer(); UdpLayer udpLayer = random.NextUdpLayer();
DnsLayer dnsLayer = random.NextDnsLayer(); DnsLayer dnsLayer = random.NextDnsLayer();
ushort specialPort = (ushort)(random.NextBool() ? 53 : 5355);
if (dnsLayer.IsQuery) if (dnsLayer.IsQuery)
udpLayer.DestinationPort = 53; udpLayer.DestinationPort = specialPort;
else else
udpLayer.SourcePort = 53; udpLayer.SourcePort = specialPort;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, udpLayer, dnsLayer); return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, udpLayer, dnsLayer);
...@@ -256,7 +258,11 @@ namespace PcapDotNet.Core.Test ...@@ -256,7 +258,11 @@ namespace PcapDotNet.Core.Test
tcpLayer.DestinationPort = 80; tcpLayer.DestinationPort = 80;
else else
tcpLayer.SourcePort = 80; tcpLayer.SourcePort = 80;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, tcpLayer, random.NextHttpLayer()); if (random.NextBool())
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, tcpLayer, httpLayer);
HttpLayer httpLayer2 = httpLayer.IsRequest ? (HttpLayer)random.NextHttpRequestLayer() : random.NextHttpResponseLayer();
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, tcpLayer, httpLayer, httpLayer2);
default: default:
throw new InvalidOperationException(); throw new InvalidOperationException();
...@@ -393,6 +399,8 @@ namespace PcapDotNet.Core.Test ...@@ -393,6 +399,8 @@ namespace PcapDotNet.Core.Test
if (comparer == null) if (comparer == null)
return; return;
currentDatagram = comparer.Compare(layer, currentDatagram); currentDatagram = comparer.Compare(layer, currentDatagram);
if (currentDatagram == null)
return;
break; break;
} }
} }
......
...@@ -18,7 +18,7 @@ namespace PcapDotNet.Core.Test ...@@ -18,7 +18,7 @@ namespace PcapDotNet.Core.Test
switch (field.Name()) switch (field.Name())
{ {
case "arp.hw.type": case "arp.hw.type":
field.AssertShowHex((ushort)arpDatagram.HardwareType); field.AssertShowDecimal((ushort)arpDatagram.HardwareType);
break; break;
case "arp.proto.type": case "arp.proto.type":
...@@ -34,7 +34,7 @@ namespace PcapDotNet.Core.Test ...@@ -34,7 +34,7 @@ namespace PcapDotNet.Core.Test
break; break;
case "arp.opcode": case "arp.opcode":
field.AssertShowHex((ushort)arpDatagram.Operation); field.AssertShowDecimal((ushort)arpDatagram.Operation);
break; break;
case "arp.src.hw": case "arp.src.hw":
......
...@@ -33,14 +33,10 @@ namespace PcapDotNet.Core.Test ...@@ -33,14 +33,10 @@ namespace PcapDotNet.Core.Test
if (field.Name() == "data") if (field.Name() == "data")
field.AssertNoShow(); field.AssertNoShow();
MoreAssert.AreSequenceEqual(httpDatagram.Take(_data.Length / 2), HexEncoding.Instance.GetBytes(_data.ToString())); MoreAssert.AreSequenceEqual(httpDatagram.Subsegment(0, _data.Length / 2), HexEncoding.Instance.GetBytes(_data.ToString()));
// string previousData = data.ToString(); // TODO: Uncomment once https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7065 is fixed.
// for (int i = 0; i != previousData.Length / 2; ++i) // if (!IsBadHttpResponse(httpDatagram))
// { // field.AssertValue(httpDatagram.Subsegment(_data.Length / 2, httpDatagram.Length - _data.Length / 2));
// byte value = Convert.ToByte(previousData.Substring(i * 2, 2), 16);
// Assert.AreEqual(httpDatagram[i], value);
// }
field.AssertValue(httpDatagram.Skip(_data.Length / 2));
return false; return false;
} }
...@@ -84,8 +80,10 @@ namespace PcapDotNet.Core.Test ...@@ -84,8 +80,10 @@ namespace PcapDotNet.Core.Test
if (httpDatagram.Header == null) if (httpDatagram.Header == null)
{ {
Assert.IsTrue(httpDatagram.IsRequest); if (httpDatagram.IsRequest)
Assert.IsNull(httpDatagram.Version); Assert.IsNull(httpDatagram.Version);
else
Assert.IsTrue(IsBadHttp(httpDatagram));
break; break;
} }
httpFieldName = fieldShow.Substring(0, colonIndex); httpFieldName = fieldShow.Substring(0, colonIndex);
...@@ -131,27 +129,45 @@ namespace PcapDotNet.Core.Test ...@@ -131,27 +129,45 @@ namespace PcapDotNet.Core.Test
case "http.content_length_header": case "http.content_length_header":
_data.Append(field.Value()); _data.Append(field.Value());
field.AssertShowDecimal(httpDatagram.Header.ContentLength.ContentLength.Value); if (!IsBadHttp(httpDatagram))
field.AssertShowDecimal(httpDatagram.Header.ContentLength.ContentLength.Value);
break; break;
case "http.content_type": case "http.content_type":
_data.Append(field.Value()); _data.Append(field.Value());
string[] mediaType = fieldShow.Split(new[] {';', ' ', '/'}, StringSplitOptions.RemoveEmptyEntries); string[] mediaType = fieldShow.Split(new[] {';', ' ', '/'}, StringSplitOptions.RemoveEmptyEntries);
Assert.AreEqual(httpDatagram.Header.ContentType.MediaType, mediaType[0]); if (!IsBadHttp(httpDatagram))
Assert.AreEqual(httpDatagram.Header.ContentType.MediaSubtype, mediaType[1]); {
int fieldShowParametersStart = fieldShow.IndexOf(';'); Assert.AreEqual(httpDatagram.Header.ContentType.MediaType, mediaType[0]);
if (fieldShowParametersStart == -1) Assert.AreEqual(httpDatagram.Header.ContentType.MediaSubtype, mediaType[1]);
Assert.IsFalse(httpDatagram.Header.ContentType.Parameters.Any()); int fieldShowParametersStart = fieldShow.IndexOf(';');
else if (fieldShowParametersStart == -1)
Assert.AreEqual( Assert.IsFalse(httpDatagram.Header.ContentType.Parameters.Any());
httpDatagram.Header.ContentType.Parameters.Select(pair => pair.Key + '=' + pair.Value.ToWiresharkLiteral()).SequenceToString(';'), else
fieldShow.Substring(fieldShowParametersStart + 1)); {
string expected =
httpDatagram.Header.ContentType.Parameters.Select(pair => pair.Key + '=' + pair.Value.ToWiresharkLiteral()).
SequenceToString(';');
if (expected.Contains(@"\;"))
expected = expected.Split(new[] {@"\;"}, StringSplitOptions.None)[0] + @"\";
if (expected.Contains(@"\r"))
expected = expected.Split(new[] {@"\r"}, StringSplitOptions.None)[0];
Assert.AreEqual(expected, fieldShow.Substring(fieldShowParametersStart + 1));
}
}
break; break;
case "http.transfer_encoding": case "http.transfer_encoding":
_data.Append(field.Value()); _data.Append(field.Value());
Assert.AreEqual(fieldShow.ToWiresharkLowerLiteral(), if (!IsBadHttp(httpDatagram))
httpDatagram.Header.TransferEncoding.TransferCodings.SequenceToString(',').ToWiresharkLiteral()); {
Assert.AreEqual(fieldShow.ToWiresharkLowerLiteral(),
httpDatagram.Header.TransferEncoding.TransferCodings.SequenceToString(',').ToWiresharkLiteral());
}
break;
case "http.request.full_uri":
Assert.AreEqual(fieldShow, ("http://" + httpDatagram.Header["Host"].ValueString + ((HttpRequestDatagram)httpDatagram).Uri).ToWiresharkLiteral());
break; break;
default: default:
...@@ -165,6 +181,7 @@ namespace PcapDotNet.Core.Test ...@@ -165,6 +181,7 @@ namespace PcapDotNet.Core.Test
{ {
foreach (var field in httpFirstLineElement.Fields()) foreach (var field in httpFirstLineElement.Fields())
{ {
field.AssertNoFields();
switch (field.Name()) switch (field.Name())
{ {
case "http.request.method": case "http.request.method":
...@@ -179,14 +196,25 @@ namespace PcapDotNet.Core.Test ...@@ -179,14 +196,25 @@ namespace PcapDotNet.Core.Test
case "http.request.version": case "http.request.version":
if (httpDatagram.Version == null) if (httpDatagram.Version == null)
field.AssertShow(string.Empty); {
if (field.Show() != string.Empty)
Assert.IsTrue(field.Show().Contains(" "));
}
else else
field.AssertShow(httpDatagram.Version.ToString()); field.AssertShow(httpDatagram.Version.ToString());
break; break;
case "http.response.code": case "http.response.code":
Assert.IsTrue(httpDatagram.IsResponse, field.Name() + " IsResponse"); Assert.IsTrue(httpDatagram.IsResponse, field.Name() + " IsResponse");
field.AssertShowDecimal(((HttpResponseDatagram)httpDatagram).StatusCode.Value); field.AssertShowDecimal(IsBadHttp(httpDatagram) ? 0 : ((HttpResponseDatagram)httpDatagram).StatusCode.Value);
break;
case "http.response.phrase":
Datagram reasonPhrase = ((HttpResponseDatagram)httpDatagram).ReasonPhrase;
if (reasonPhrase == null)
Assert.IsTrue(IsBadHttp(httpDatagram));
else
field.AssertValue(reasonPhrase);
break; break;
default: default:
...@@ -195,6 +223,27 @@ namespace PcapDotNet.Core.Test ...@@ -195,6 +223,27 @@ namespace PcapDotNet.Core.Test
} }
} }
private static bool IsBadHttp(HttpDatagram httpDatagram)
{
if (httpDatagram.IsResponse)
{
HttpResponseDatagram httpResponseDatagram = (HttpResponseDatagram)httpDatagram;
if (httpResponseDatagram.StatusCode == null)
{
Assert.IsNull(httpResponseDatagram.Header);
return true;
}
}
else
{
HttpRequestDatagram httpRequestDatagram = (HttpRequestDatagram)httpDatagram;
if (httpRequestDatagram.Version == null)
return true;
}
return false;
}
readonly StringBuilder _data = new StringBuilder(); readonly StringBuilder _data = new StringBuilder();
bool _isFirstEmptyName = true; bool _isFirstEmptyName = true;
} }
......
using System; using System;
using System.Text; using System.Text;
using System.Xml.Linq; using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets; using PcapDotNet.Packets;
using PcapDotNet.Packets.Icmp; using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
...@@ -20,43 +23,35 @@ namespace PcapDotNet.Core.Test ...@@ -20,43 +23,35 @@ namespace PcapDotNet.Core.Test
{ {
case "icmp.type": case "icmp.type":
field.AssertShowDecimal((byte)icmpDatagram.MessageType); field.AssertShowDecimal((byte)icmpDatagram.MessageType);
field.AssertNoFields();
break; break;
case "icmp.code": case "icmp.code":
field.AssertShowDecimal(icmpDatagram.Code); field.AssertShowDecimal(icmpDatagram.Code);
field.AssertNoFields();
break; break;
case "icmp.checksum_bad": case "icmp.checksum_bad":
field.AssertShowDecimal(!icmpDatagram.IsChecksumCorrect); field.AssertShowDecimal(!icmpDatagram.IsChecksumCorrect);
field.AssertNoFields();
break; break;
case "icmp.checksum": case "icmp.checksum":
field.AssertShowHex(icmpDatagram.Checksum); field.AssertShowHex(icmpDatagram.Checksum);
field.AssertNoFields();
break; break;
case "data": case "data":
var casted1 = icmpDatagram as IcmpIpV4HeaderPlus64BitsPayloadDatagram; var casted1 = icmpDatagram as IcmpIpV4HeaderPlus64BitsPayloadDatagram;
if (casted1 != null) if (casted1 != null)
field.AssertValue(casted1.IpV4.Payload); {
else if (casted1.IpV4.Protocol != IpV4Protocol.IpComp) // TODO: Support IpComp.
field.AssertValue(icmpDatagram.Payload); field.AssertDataField(casted1.IpV4.Payload);
break; }
case "data.data":
var casted2 = icmpDatagram as IcmpIpV4HeaderPlus64BitsPayloadDatagram;
if (casted2 != null)
field.AssertShow(casted2.IpV4.Payload);
else
field.AssertShow(icmpDatagram.Payload);
break;
case "data.len":
var casted3 = icmpDatagram as IcmpIpV4HeaderPlus64BitsPayloadDatagram;
if (casted3 != null)
field.AssertShowDecimal(casted3.IpV4.Payload.Length);
else else
field.AssertShowDecimal(icmpDatagram.Payload.Length); {
field.AssertDataField(icmpDatagram.Payload);
}
break; break;
case "": case "":
...@@ -120,14 +115,18 @@ namespace PcapDotNet.Core.Test ...@@ -120,14 +115,18 @@ namespace PcapDotNet.Core.Test
} }
break; break;
} }
field.AssertNoFields();
break; break;
case "icmp.ident": case "icmp.ident":
field.AssertShowHex(((IcmpIdentifiedDatagram)icmpDatagram).Identifier); ushort identifier = ((IcmpIdentifiedDatagram)icmpDatagram).Identifier;
field.AssertShowDecimal(field.Showname().StartsWith("Identifier (BE): ") ? identifier : identifier.ReverseEndianity());
field.AssertNoFields();
break; break;
case "icmp.seq": case "icmp.seq":
field.AssertShowDecimal(((IcmpIdentifiedDatagram)icmpDatagram).SequenceNumber); field.AssertShowDecimal(((IcmpIdentifiedDatagram)icmpDatagram).SequenceNumber);
field.AssertNoFields();
break; break;
case "icmp.seq_le": case "icmp.seq_le":
...@@ -135,14 +134,22 @@ namespace PcapDotNet.Core.Test ...@@ -135,14 +134,22 @@ namespace PcapDotNet.Core.Test
sequenceNumberBuffer.Write(0, ((IcmpIdentifiedDatagram)icmpDatagram).SequenceNumber, Endianity.Big); sequenceNumberBuffer.Write(0, ((IcmpIdentifiedDatagram)icmpDatagram).SequenceNumber, Endianity.Big);
ushort lowerEndianSequenceNumber = sequenceNumberBuffer.ReadUShort(0, Endianity.Small); ushort lowerEndianSequenceNumber = sequenceNumberBuffer.ReadUShort(0, Endianity.Small);
field.AssertShowDecimal(lowerEndianSequenceNumber); field.AssertShowDecimal(lowerEndianSequenceNumber);
field.AssertNoFields();
break; break;
case "icmp.redir_gw": case "icmp.redir_gw":
field.AssertShow(((IcmpRedirectDatagram)icmpDatagram).GatewayInternetAddress.ToString()); field.AssertShow(((IcmpRedirectDatagram)icmpDatagram).GatewayInternetAddress.ToString());
field.AssertNoFields();
break; break;
case "icmp.mtu": case "icmp.mtu":
field.AssertShowDecimal(((IcmpDestinationUnreachableDatagram)icmpDatagram).NextHopMaximumTransmissionUnit); field.AssertShowDecimal(((IcmpDestinationUnreachableDatagram)icmpDatagram).NextHopMaximumTransmissionUnit);
field.AssertNoFields();
break;
case "l2tp.l2_spec_def":
field.AssertShow("");
field.AssertNoFields();
break; break;
default: default:
......
using System; using System;
using System.Linq; using System.Linq;
using System.Xml.Linq; using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets; using PcapDotNet.Packets;
using PcapDotNet.Packets.Igmp; using PcapDotNet.Packets.Igmp;
...@@ -61,6 +62,10 @@ namespace PcapDotNet.Core.Test ...@@ -61,6 +62,10 @@ namespace PcapDotNet.Core.Test
CompareDatagram(field, null, igmpDatagram); CompareDatagram(field, null, igmpDatagram);
break; break;
case IgmpMessageType.MulticastTraceRouteResponse:
// todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
break;
default: default:
if (typeof(IgmpMessageType).GetEnumValues<IgmpMessageType>().Contains(igmpDatagram.MessageType)) if (typeof(IgmpMessageType).GetEnumValues<IgmpMessageType>().Contains(igmpDatagram.MessageType))
throw new InvalidOperationException("Invalid message type " + igmpDatagram.MessageType); throw new InvalidOperationException("Invalid message type " + igmpDatagram.MessageType);
...@@ -97,7 +102,13 @@ namespace PcapDotNet.Core.Test ...@@ -97,7 +102,13 @@ namespace PcapDotNet.Core.Test
break; break;
case "igmp.mtrace.max_hops": case "igmp.mtrace.max_hops":
case "igmp.mtrace.saddr":
case "igmp.mtrace.raddr":
case "igmp.mtrace.rspaddr":
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. // todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
Assert.AreEqual(IgmpMessageType.MulticastTraceRouteResponse, igmpDatagram.MessageType);
break; break;
default: default:
...@@ -109,7 +120,6 @@ namespace PcapDotNet.Core.Test ...@@ -109,7 +120,6 @@ namespace PcapDotNet.Core.Test
private static void CompareIgmpGroupRecord(XElement groupRecord, IgmpGroupRecordDatagram groupRecordDatagram) private static void CompareIgmpGroupRecord(XElement groupRecord, IgmpGroupRecordDatagram groupRecordDatagram)
{ {
Console.WriteLine(groupRecordDatagram.AuxiliaryData);
int sourceAddressIndex = 0; int sourceAddressIndex = 0;
foreach (var field in groupRecord.Fields()) foreach (var field in groupRecord.Fields())
{ {
......
...@@ -84,13 +84,27 @@ namespace PcapDotNet.Core.Test ...@@ -84,13 +84,27 @@ namespace PcapDotNet.Core.Test
case "ip.dst": case "ip.dst":
case "ip.dst_host": case "ip.dst_host":
field.AssertShow(ipV4Datagram.Destination.ToString()); if (field.Show() != ipV4Datagram.Destination.ToString())
{
// TODO: Remove this fallback once https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7043 is fixed.
field.AssertShow(ipV4Datagram.CurrentDestination.ToString());
Assert.IsTrue(ipV4Datagram.Options.IsBadForWireshark(),
string.Format("Expected destination: {0}. Destination: {1}. Current destination: {2}.", field.Show(),
ipV4Datagram.Destination, ipV4Datagram.CurrentDestination));
}
break; break;
case "ip.addr": case "ip.addr":
case "ip.host": case "ip.host":
Assert.IsTrue(field.Show() == ipV4Datagram.Source.ToString() || Assert.IsTrue(field.Show() == ipV4Datagram.Source.ToString() ||
field.Show() == ipV4Datagram.Destination.ToString()); field.Show() == ipV4Datagram.Destination.ToString() ||
// TODO: Remove this fallback once https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7043 is fixed.
field.Show() == ipV4Datagram.CurrentDestination.ToString() && ipV4Datagram.Options.IsBadForWireshark(),
string.Format("Expected ip: {0}. ", field.Show()) +
(ipV4Datagram.IsValid
? string.Format("Source: {0}. Destination: {1}. Current destination: {2}.", ipV4Datagram.Source,
ipV4Datagram.Destination, ipV4Datagram.CurrentDestination)
: ""));
break; break;
case "": case "":
......
...@@ -5,7 +5,7 @@ namespace PcapDotNet.Core.Test ...@@ -5,7 +5,7 @@ namespace PcapDotNet.Core.Test
{ {
public static class WiresharkStringExtensions public static class WiresharkStringExtensions
{ {
public static string ToWiresharkLiteral(this string value, bool putLeadingZerosInHexAndBackslashesBeforeSpecialCharacters = true) public static string ToWiresharkLiteral(this string value, bool putLeadingZerosInHexAndBackslashesBeforeSpecialCharacters = true, bool escapeSpecialChars = true)
{ {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
for (int i = 0; i != value.Length; ++i) for (int i = 0; i != value.Length; ++i)
...@@ -13,7 +13,7 @@ namespace PcapDotNet.Core.Test ...@@ -13,7 +13,7 @@ namespace PcapDotNet.Core.Test
char currentChar = value[i]; char currentChar = value[i];
if (currentChar == '\0') if (currentChar == '\0')
return result.ToString(); return result.ToString();
if (putLeadingZerosInHexAndBackslashesBeforeSpecialCharacters) if (escapeSpecialChars)
{ {
switch (currentChar) switch (currentChar)
{ {
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using System.Text; using System.Text;
using System.Xml.Linq; using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
...@@ -39,6 +41,11 @@ namespace PcapDotNet.Core.Test ...@@ -39,6 +41,11 @@ namespace PcapDotNet.Core.Test
return element.GetAttributeValue("show"); return element.GetAttributeValue("show");
} }
public static string Showname(this XElement element)
{
return element.GetAttributeValue("showname");
}
public static string Value(this XElement element) public static string Value(this XElement element)
{ {
return element.GetAttributeValue("value"); return element.GetAttributeValue("value");
...@@ -49,6 +56,16 @@ namespace PcapDotNet.Core.Test ...@@ -49,6 +56,16 @@ namespace PcapDotNet.Core.Test
Assert.AreEqual(element.Name(), expectedName); Assert.AreEqual(element.Name(), expectedName);
} }
public static void AssertNoFields(this XElement element)
{
Assert.IsFalse(element.Fields().Any(), string.Format("Element {0} has {1} fields.", element.Name(), element.Fields().Count()));
}
public static void AssertNumFields(this XElement element, int expectedNumFields)
{
Assert.AreEqual(expectedNumFields, element.Fields().Count());
}
public static void AssertNoShow(this XElement element) public static void AssertNoShow(this XElement element)
{ {
Assert.IsNull(element.Attribute("show")); Assert.IsNull(element.Attribute("show"));
...@@ -146,6 +163,7 @@ namespace PcapDotNet.Core.Test ...@@ -146,6 +163,7 @@ namespace PcapDotNet.Core.Test
public static void AssertValue(this XElement element, string expectedValue, string message = null) public static void AssertValue(this XElement element, string expectedValue, string message = null)
{ {
Assert.AreEqual(expectedValue.Length, element.Value().Length, message ?? element.Name());
Assert.AreEqual(expectedValue, element.Value(), message ?? element.Name()); Assert.AreEqual(expectedValue, element.Value(), message ?? element.Name());
} }
...@@ -178,5 +196,46 @@ namespace PcapDotNet.Core.Test ...@@ -178,5 +196,46 @@ namespace PcapDotNet.Core.Test
{ {
element.AssertValue(expectedValue.Value); element.AssertValue(expectedValue.Value);
} }
public static void AssertValue(this XElement element, IEnumerable<string> expectedValue)
{
element.AssertValue(expectedValue.SequenceToString());
}
public static void AssertValue(this XElement element, IEnumerable<ushort> expectedValue)
{
element.AssertValue(expectedValue.Select(value => value.ToString("x4")));
}
public static void AssertValue(this XElement element, IEnumerable<uint> expectedValue)
{
element.AssertValue(expectedValue.Select(value => value.ToString("x8")));
}
public static void AssertValue(this XElement element, IEnumerable<IpV4Address> expectedValue)
{
element.AssertValue(expectedValue.Select(ip => ip.ToValue()));
}
public static void AssertDataField(this XElement element, string expectedValue)
{
element.AssertName("data");
element.AssertValue(expectedValue);
element.AssertNumFields(2);
var dataData = element.Fields().First();
dataData.AssertName("data.data");
dataData.AssertValue(expectedValue);
var dataLen = element.Fields().Last();
dataLen.AssertName("data.len");
dataLen.AssertShowDecimal(expectedValue.Length / 2);
}
public static void AssertDataField(this XElement element, IEnumerable<byte> expectedValue)
{
element.AssertDataField(expectedValue.BytesSequenceToHexadecimalString());
}
} }
} }
\ No newline at end of file
...@@ -74,7 +74,8 @@ namespace PcapDotNet.Packets.Test ...@@ -74,7 +74,8 @@ namespace PcapDotNet.Packets.Test
Assert.AreEqual(arpLayer, packet.Ethernet.Arp.ExtractLayer(), "ARP Layer"); Assert.AreEqual(arpLayer, packet.Ethernet.Arp.ExtractLayer(), "ARP Layer");
Assert.AreNotEqual(arpLayer, random.NextArpLayer(), "ARP Layer"); Assert.AreNotEqual(arpLayer, random.NextArpLayer(), "ARP Layer");
Assert.AreEqual(arpLayer.GetHashCode(), packet.Ethernet.Arp.ExtractLayer().GetHashCode(), "ARP Layer"); Assert.AreEqual(arpLayer.GetHashCode(), packet.Ethernet.Arp.ExtractLayer().GetHashCode(), "ARP Layer");
Assert.AreNotEqual(arpLayer.GetHashCode(), random.NextArpLayer().GetHashCode(), "ARP Layer"); ArpLayer differentArpLayer = random.NextArpLayer();
Assert.AreNotEqual(arpLayer.GetHashCode(), differentArpLayer.GetHashCode(), "ARP Layer");
} }
} }
......
...@@ -270,7 +270,7 @@ namespace PcapDotNet.Packets.Test ...@@ -270,7 +270,7 @@ namespace PcapDotNet.Packets.Test
TestHttpResponse("HTTP/1.0 200 OK", HttpVersion.Version10, 200, "OK"); TestHttpResponse("HTTP/1.0 200 OK", HttpVersion.Version10, 200, "OK");
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, "OK"); TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, "OK");
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11); TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11);
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, " OK"); TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, "OK");
// Response Header // Response Header
...@@ -564,6 +564,31 @@ namespace PcapDotNet.Packets.Test ...@@ -564,6 +564,31 @@ namespace PcapDotNet.Packets.Test
Assert.AreEqual("/D%C3%BCrst/?A", ((HttpRequestDatagram)packet.Ethernet.IpV4.Tcp.Http).Uri); Assert.AreEqual("/D%C3%BCrst/?A", ((HttpRequestDatagram)packet.Ethernet.IpV4.Tcp.Http).Uri);
} }
[TestMethod]
public void MultipleHttpLayersTest()
{
var httpLayer1 = new HttpResponseLayer
{
Version = HttpVersion.Version11,
StatusCode = 200,
ReasonPhrase = new DataSegment(Encoding.ASCII.GetBytes("OK")),
Header = new HttpHeader(new HttpContentLengthField(10)),
Body = new Datagram(new byte[10])
};
var httpLayer2 = new HttpResponseLayer
{
Version = HttpVersion.Version11,
StatusCode = 201,
ReasonPhrase = new DataSegment(Encoding.ASCII.GetBytes("MOVED")),
Header = new HttpHeader(new HttpContentLengthField(20)),
Body = new Datagram(new byte[20])
};
Packet packet = PacketBuilder.Build(DateTime.Now, new EthernetLayer(), new IpV4Layer(), new TcpLayer(), httpLayer1, httpLayer2);
Assert.AreEqual(2, packet.Ethernet.IpV4.Tcp.HttpCollection.Count);
Assert.AreEqual(httpLayer1, packet.Ethernet.IpV4.Tcp.Http.ExtractLayer());
Assert.AreEqual(httpLayer2, packet.Ethernet.IpV4.Tcp.HttpCollection[1].ExtractLayer());
}
private static void TestHttpResponse(string httpString, HttpVersion expectedVersion = null, uint? expectedStatusCode = null, string expectedReasonPhrase = null, HttpHeader expectedHeader = null, string expectedBodyString = null) private static void TestHttpResponse(string httpString, HttpVersion expectedVersion = null, uint? expectedStatusCode = null, string expectedReasonPhrase = null, HttpHeader expectedHeader = null, string expectedBodyString = null)
{ {
Datagram expectedBody = expectedBodyString == null ? null : new Datagram(Encoding.ASCII.GetBytes(expectedBodyString)); Datagram expectedBody = expectedBodyString == null ? null : new Datagram(Encoding.ASCII.GetBytes(expectedBodyString));
......
...@@ -471,7 +471,7 @@ namespace PcapDotNet.Packets.Test ...@@ -471,7 +471,7 @@ namespace PcapDotNet.Packets.Test
Ttl = 1, Ttl = 1,
Protocol = IpV4Protocol.WidebandExpak, Protocol = IpV4Protocol.WidebandExpak,
Source = new IpV4Address(1), Source = new IpV4Address(1),
Destination = new IpV4Address(2), CurrentDestination = new IpV4Address(2),
}); });
Assert.IsTrue(packet.IsValid); Assert.IsTrue(packet.IsValid);
......
...@@ -179,5 +179,15 @@ namespace PcapDotNet.Packets.Test ...@@ -179,5 +179,15 @@ namespace PcapDotNet.Packets.Test
{ {
Assert.IsNotNull(new TcpOptionMood((TcpOptionMoodEmotion)202).EmotionString); Assert.IsNotNull(new TcpOptionMood((TcpOptionMoodEmotion)202).EmotionString);
} }
[TestMethod]
public void TcpChecksumTest()
{
Packet packet = Packet.FromHexadecimalString(
"72ad58bae3b13638b5e35a3f08004a6c0055fd5400000e0622f341975faa3bfb25ed83130cb2e02103adfc7efbac1c2bb0f402e64800bb641bc8de8fa185e8ff716b60faf864bfe85901040205021ceec26d916419de400347f33fcca9ad44e9ffae8f",
DateTime.Now, DataLinkKind.Ethernet);
Assert.IsFalse(packet.Ethernet.IpV4.IsTransportChecksumCorrect);
}
} }
} }
\ No newline at end of file
...@@ -13,28 +13,34 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -13,28 +13,34 @@ namespace PcapDotNet.Packets.TestUtils
public static HttpLayer NextHttpLayer(this Random random) public static HttpLayer NextHttpLayer(this Random random)
{ {
if (random.NextBool()) if (random.NextBool())
{ return random.NextHttpRequestLayer();
HttpRequestLayer httpRequestLayer = new HttpRequestLayer(); return random.NextHttpResponseLayer();
if (random.NextBool(10)) }
{
httpRequestLayer.Method = random.NextHttpRequestMethod();
httpRequestLayer.Uri = httpRequestLayer.Method == null ? null : random.NextHttpUri();
httpRequestLayer.Version = httpRequestLayer.Uri == null || random.NextBool(10) ? null : random.NextHttpVersion();
httpRequestLayer.Header = httpRequestLayer.Version == null ? null : random.NextHttpHeader();
httpRequestLayer.Body = httpRequestLayer.Header == null ? null : random.NextHttpBody(true, null, httpRequestLayer.Header);
}
return httpRequestLayer; public static HttpRequestLayer NextHttpRequestLayer(this Random random)
{
HttpRequestLayer httpRequestLayer = new HttpRequestLayer();
if (random.NextBool(10))
{
httpRequestLayer.Method = random.NextHttpRequestMethod();
httpRequestLayer.Uri = httpRequestLayer.Method == null ? null : random.NextHttpUri();
httpRequestLayer.Version = httpRequestLayer.Uri == null || random.NextBool(10) ? null : random.NextHttpVersion();
httpRequestLayer.Header = httpRequestLayer.Version == null ? null : random.NextHttpHeader();
httpRequestLayer.Body = httpRequestLayer.Header == null ? null : random.NextHttpBody(true, null, httpRequestLayer.Header);
} }
return httpRequestLayer;
}
public static HttpResponseLayer NextHttpResponseLayer(this Random random)
{
HttpResponseLayer httpResponseLayer = new HttpResponseLayer HttpResponseLayer httpResponseLayer = new HttpResponseLayer
{ {
Version = random.NextHttpVersion(), Version = random.NextHttpVersion(),
StatusCode = random.NextBool(10) ? null : (uint?)random.NextUInt(100, 999), StatusCode = random.NextBool(10) ? null : (uint?)random.NextUInt(100, 999),
}; };
httpResponseLayer.ReasonPhrase = httpResponseLayer.StatusCode == null ? null : random.NextHttpReasonPhrase(); httpResponseLayer.ReasonPhrase = httpResponseLayer.StatusCode == null ? null : random.NextHttpReasonPhrase();
httpResponseLayer.Header = httpResponseLayer.ReasonPhrase == null ? null : random.NextHttpHeader(); httpResponseLayer.Header = httpResponseLayer.ReasonPhrase == null ? null : random.NextHttpHeader();
httpResponseLayer.Body = httpResponseLayer.Header == null ? null : random.NextHttpBody(false , httpResponseLayer.StatusCode, httpResponseLayer.Header); httpResponseLayer.Body = httpResponseLayer.Header == null ? null : random.NextHttpBody(false, httpResponseLayer.StatusCode, httpResponseLayer.Header);
return httpResponseLayer; return httpResponseLayer;
} }
...@@ -304,7 +310,6 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -304,7 +310,6 @@ namespace PcapDotNet.Packets.TestUtils
httpHeader.ContentType.MediaType == "multipart" && httpHeader.ContentType.MediaType == "multipart" &&
httpHeader.ContentType.MediaSubtype == "byteranges" && httpHeader.ContentType.MediaSubtype == "byteranges" &&
httpHeader.ContentType.Parameters["boundary"] != null) httpHeader.ContentType.Parameters["boundary"] != null)
{ {
List<byte> boundedBody = new List<byte>(random.NextDatagram(random.Next(1000))); List<byte> boundedBody = new List<byte>(random.NextDatagram(random.Next(1000)));
boundedBody.AddRange(EncodingExtensions.Iso88591.GetBytes("--" + httpHeader.ContentType.Parameters["boundary"] + "--")); boundedBody.AddRange(EncodingExtensions.Iso88591.GetBytes("--" + httpHeader.ContentType.Parameters["boundary"] + "--"));
......
...@@ -27,7 +27,7 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -27,7 +27,7 @@ namespace PcapDotNet.Packets.TestUtils
IgmpMessageType.JoinGroupReplyVersion0, IgmpMessageType.LeaveGroupRequestVersion0, IgmpMessageType.JoinGroupReplyVersion0, IgmpMessageType.LeaveGroupRequestVersion0,
IgmpMessageType.LeaveGroupReplyVersion0, IgmpMessageType.ConfirmGroupRequestVersion0, IgmpMessageType.LeaveGroupReplyVersion0, IgmpMessageType.ConfirmGroupRequestVersion0,
IgmpMessageType.ConfirmGroupReplyVersion0, IgmpMessageType.ConfirmGroupReplyVersion0,
IgmpMessageType.MulticastTraceRouteResponse); // todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt. IgmpMessageType.MulticastTraceRouteResponse, IgmpMessageType.MulticastTraceroute); // todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
IgmpQueryVersion igmpQueryVersion = IgmpQueryVersion.None; IgmpQueryVersion igmpQueryVersion = IgmpQueryVersion.None;
TimeSpan igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(256 * 0.1) - TimeSpan.FromTicks(1)); TimeSpan igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(256 * 0.1) - TimeSpan.FromTicks(1));
IpV4Address igmpGroupAddress = random.NextIpV4Address(); IpV4Address igmpGroupAddress = random.NextIpV4Address();
......
...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.TestUtils
HeaderChecksum = random.NextBool() ? (ushort?)random.NextUShort() : null, HeaderChecksum = random.NextBool() ? (ushort?)random.NextUShort() : null,
Fragmentation = random.NextBool() ? random.NextIpV4Fragmentation() : IpV4Fragmentation.None, Fragmentation = random.NextBool() ? random.NextIpV4Fragmentation() : IpV4Fragmentation.None,
Source = random.NextIpV4Address(), Source = random.NextIpV4Address(),
Destination = random.NextIpV4Address(), CurrentDestination = random.NextIpV4Address(),
Options = random.NextIpV4Options() Options = random.NextIpV4Options()
}; };
} }
......
...@@ -104,6 +104,7 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -104,6 +104,7 @@ namespace PcapDotNet.Packets.TestUtils
impossibleOptionTypes.Add(TcpOptionType.QuickStartResponse); impossibleOptionTypes.Add(TcpOptionType.QuickStartResponse);
impossibleOptionTypes.Add(TcpOptionType.UserTimeout); impossibleOptionTypes.Add(TcpOptionType.UserTimeout);
impossibleOptionTypes.Add(TcpOptionType.SelectiveNegativeAcknowledgements); // TODO: Support Selective Negative Acknowledgements.
TcpOptionType optionType = random.NextEnum<TcpOptionType>(impossibleOptionTypes); TcpOptionType optionType = random.NextEnum<TcpOptionType>(impossibleOptionTypes);
switch (optionType) switch (optionType)
......
...@@ -136,7 +136,11 @@ namespace PcapDotNet.Packets.Arp ...@@ -136,7 +136,11 @@ namespace PcapDotNet.Packets.Arp
public override int GetHashCode() public override int GetHashCode()
{ {
return base.GetHashCode() ^ return base.GetHashCode() ^
BitSequence.Merge((ushort)ProtocolType, (ushort)Operation).GetHashCode(); BitSequence.Merge((ushort)ProtocolType, (ushort)Operation).GetHashCode() ^
SenderHardwareAddress.BytesSequenceGetHashCode() ^
SenderProtocolAddress.BytesSequenceGetHashCode() ^
TargetHardwareAddress.BytesSequenceGetHashCode() ^
TargetProtocolAddress.BytesSequenceGetHashCode();
} }
} }
} }
\ No newline at end of file
...@@ -186,7 +186,7 @@ namespace PcapDotNet.Packets ...@@ -186,7 +186,7 @@ namespace PcapDotNet.Packets
{ {
short value = ReadShort(buffer, offset); short value = ReadShort(buffer, offset);
if (IsWrongEndianity(endianity)) if (IsWrongEndianity(endianity))
value = IPAddress.HostToNetworkOrder(value); value = value.ReverseEndianity();
return value; return value;
} }
...@@ -526,7 +526,7 @@ namespace PcapDotNet.Packets ...@@ -526,7 +526,7 @@ namespace PcapDotNet.Packets
public static void Write(this byte[] buffer, int offset, short value, Endianity endianity) public static void Write(this byte[] buffer, int offset, short value, Endianity endianity)
{ {
if (IsWrongEndianity(endianity)) if (IsWrongEndianity(endianity))
value = IPAddress.HostToNetworkOrder(value); value = value.ReverseEndianity();
Write(buffer, offset, value); Write(buffer, offset, value);
} }
...@@ -763,7 +763,7 @@ namespace PcapDotNet.Packets ...@@ -763,7 +763,7 @@ namespace PcapDotNet.Packets
/// <param name="buffer">The buffer to write the value to.</param> /// <param name="buffer">The buffer to write the value to.</param>
/// <param name="offset">The offset in the buffer to start writing.</param> /// <param name="offset">The offset in the buffer to start writing.</param>
/// <param name="value">The value to write.</param> /// <param name="value">The value to write.</param>
public static void Write(this byte[] buffer, ref int offset, Datagram value) public static void Write(this byte[] buffer, ref int offset, DataSegment value)
{ {
if (value == null) if (value == null)
throw new ArgumentNullException("value"); throw new ArgumentNullException("value");
......
...@@ -347,6 +347,12 @@ namespace PcapDotNet.Packets ...@@ -347,6 +347,12 @@ namespace PcapDotNet.Packets
return sum; return sum;
} }
internal static uint Sum16Bits(IpV4Address address)
{
uint value = address.ToValue();
return (value >> 16) + (value & 0xFFFF);
}
private static readonly DataSegment _empty = new DataSegment(new byte[0]); private static readonly DataSegment _empty = new DataSegment(new byte[0]);
} }
} }
\ No newline at end of file
...@@ -352,9 +352,10 @@ namespace PcapDotNet.Packets.Gre ...@@ -352,9 +352,10 @@ namespace PcapDotNet.Packets.Gre
/// <returns>true iff the datagram is valid.</returns> /// <returns>true iff the datagram is valid.</returns>
protected override bool CalculateIsValid() protected override bool CalculateIsValid()
{ {
if (Length < HeaderMinimumLength || Length < HeaderLength)
return false;
Datagram payloadByProtocolType = PayloadDatagrams.Get(ProtocolType); Datagram payloadByProtocolType = PayloadDatagrams.Get(ProtocolType);
return (Length >= HeaderMinimumLength && Length >= HeaderLength && return (IsValidRouting && FutureUseBits == 0 &&
IsValidRouting && FutureUseBits == 0 &&
(Version == GreVersion.EnhancedGre || Version == GreVersion.Gre && !AcknowledgmentSequenceNumberPresent) && (Version == GreVersion.EnhancedGre || Version == GreVersion.Gre && !AcknowledgmentSequenceNumberPresent) &&
(!ChecksumPresent || IsChecksumCorrect) && (!ChecksumPresent || IsChecksumCorrect) &&
(payloadByProtocolType == null || payloadByProtocolType.IsValid)); (payloadByProtocolType == null || payloadByProtocolType.IsValid));
......
...@@ -249,7 +249,7 @@ namespace PcapDotNet.Packets.Http ...@@ -249,7 +249,7 @@ namespace PcapDotNet.Packets.Http
} }
internal static Datagram ParseBody(byte[] buffer, int offset, int length, internal static Datagram ParseBody(byte[] buffer, int offset, int length,
bool isBodyPossible, HttpHeader header) bool isBodyPossible, HttpHeader header)
{ {
if (!isBodyPossible) if (!isBodyPossible)
return Empty; return Empty;
......
...@@ -72,6 +72,13 @@ namespace PcapDotNet.Packets.Http ...@@ -72,6 +72,13 @@ namespace PcapDotNet.Packets.Http
return Bytes(AsciiBytes.Space); return Bytes(AsciiBytes.Space);
} }
public HttpParser SkipSpaces()
{
while (IsNext(AsciiBytes.Space))
Skip(1);
return this;
}
public HttpParser SkipLws() public HttpParser SkipLws()
{ {
while (true) while (true)
......
...@@ -69,7 +69,7 @@ namespace PcapDotNet.Packets.Http ...@@ -69,7 +69,7 @@ namespace PcapDotNet.Packets.Http
HttpVersion version; HttpVersion version;
uint? statusCode; uint? statusCode;
Datagram reasonPhrase; Datagram reasonPhrase;
parser.Version(out version).Space().DecimalNumber(3, out statusCode).Space().ReasonPhrase(out reasonPhrase).CarriageReturnLineFeed(); parser.Version(out version).Space().DecimalNumber(3, out statusCode).Space().SkipSpaces().ReasonPhrase(out reasonPhrase).CarriageReturnLineFeed();
ParseInfo parseInfo = new ParseInfo ParseInfo parseInfo = new ParseInfo
{ {
Length = length, Length = length,
...@@ -102,8 +102,6 @@ namespace PcapDotNet.Packets.Http ...@@ -102,8 +102,6 @@ namespace PcapDotNet.Packets.Http
{ {
if (statusCode >= 100 && statusCode <= 199 || statusCode == 204 || statusCode == 205 || statusCode == 304) if (statusCode >= 100 && statusCode <= 199 || statusCode == 204 || statusCode == 205 || statusCode == 304)
return false; return false;
// if (IsResponseToHeadRequest)
// return false;
return true; return true;
} }
} }
......
using System; using System;
using System.Linq;
using PcapDotNet.Base; using PcapDotNet.Base;
namespace PcapDotNet.Packets.Http namespace PcapDotNet.Packets.Http
...@@ -24,7 +25,20 @@ namespace PcapDotNet.Packets.Http ...@@ -24,7 +25,20 @@ namespace PcapDotNet.Packets.Http
/// The data of the reason phrase. /// The data of the reason phrase.
/// Example: OK /// Example: OK
/// </summary> /// </summary>
public Datagram ReasonPhrase { get; set; } public DataSegment ReasonPhrase
{
get { return _reasonPhrase; }
set
{
if (value == null)
{
_reasonPhrase = null;
return;
}
int numSpacesAtStart = value.TakeWhile(byteValue => byteValue == AsciiBytes.Space).Count();
_reasonPhrase = value.Subsegment(numSpacesAtStart, value.Length - numSpacesAtStart);
}
}
/// <summary> /// <summary>
/// Two HTTP response layers are equal iff they have the same version, header, body, status code and reason phrase. /// Two HTTP response layers are equal iff they have the same version, header, body, status code and reason phrase.
...@@ -83,5 +97,7 @@ namespace PcapDotNet.Packets.Http ...@@ -83,5 +97,7 @@ namespace PcapDotNet.Packets.Http
buffer.WriteCarriageReturnLinefeed(ref offset); buffer.WriteCarriageReturnLinefeed(ref offset);
} }
private DataSegment _reasonPhrase;
} }
} }
\ No newline at end of file
...@@ -94,9 +94,10 @@ namespace PcapDotNet.Packets.Igmp ...@@ -94,9 +94,10 @@ namespace PcapDotNet.Packets.Igmp
{ {
if (_sourceAddresses == null) if (_sourceAddresses == null)
{ {
IpV4Address[] sourceAddresses = new IpV4Address[NumberOfSources]; int actualNumberOfSource = Math.Min(NumberOfSources, (Length - Offset.SourceAddresses) / IpV4Address.SizeOf);
IpV4Address[] sourceAddresses = new IpV4Address[actualNumberOfSource];
for (int i = 0; i != sourceAddresses.Length; ++i) for (int i = 0; i != sourceAddresses.Length; ++i)
sourceAddresses[i] = ReadIpV4Address(Offset.SourceAddresses + 4 * i, Endianity.Big); sourceAddresses[i] = ReadIpV4Address(Offset.SourceAddresses + IpV4Address.SizeOf * i, Endianity.Big);
_sourceAddresses = new ReadOnlyCollection<IpV4Address>(sourceAddresses); _sourceAddresses = new ReadOnlyCollection<IpV4Address>(sourceAddresses);
} }
......
...@@ -79,5 +79,10 @@ namespace PcapDotNet.Packets.Igmp ...@@ -79,5 +79,10 @@ namespace PcapDotNet.Packets.Igmp
/// Multicast Traceroute Response. /// Multicast Traceroute Response.
/// </summary> /// </summary>
MulticastTraceRouteResponse = 0x1E, MulticastTraceRouteResponse = 0x1E,
/// <summary>
/// Multicast Traceroute.
/// </summary>
MulticastTraceroute = 0x1F,
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.ObjectModel;
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;
...@@ -165,19 +167,41 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -165,19 +167,41 @@ namespace PcapDotNet.Packets.IpV4
} }
/// <summary> /// <summary>
/// The destination address. /// The current destination address.
/// This might not be the final destination when source routing options exist.
/// </summary> /// </summary>
public IpV4Address Destination public IpV4Address CurrentDestination
{ {
get { return ReadIpV4Address(Offset.Destination, Endianity.Big); } get { return ReadIpV4Address(Offset.Destination, Endianity.Big); }
} }
/// <summary>
/// The final destination address.
/// Takes into account the current destination and source routing options if they exist.
/// </summary>
public IpV4Address Destination
{
get
{
if (_destination == null)
_destination = CalculateDestination(CurrentDestination, Options);
return _destination.Value;
}
}
/// <summary> /// <summary>
/// The options field with all the parsed options if any exist. /// The options field with all the parsed options if any exist.
/// </summary> /// </summary>
public IpV4Options Options public IpV4Options Options
{ {
get { return _options ?? (_options = new IpV4Options(Buffer, StartOffset + Offset.Options, RealHeaderLength - HeaderMinimumLength)); } get
{
if (_options == null && RealHeaderLength >= HeaderMinimumLength)
_options = new IpV4Options(Buffer, StartOffset + Offset.Options, RealHeaderLength - HeaderMinimumLength);
return _options;
}
} }
/// <summary> /// <summary>
...@@ -214,7 +238,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -214,7 +238,7 @@ namespace PcapDotNet.Packets.IpV4
Protocol = Protocol, Protocol = Protocol,
HeaderChecksum = HeaderChecksum, HeaderChecksum = HeaderChecksum,
Source = Source, Source = Source,
Destination = Destination, CurrentDestination = CurrentDestination,
Options = Options, Options = Options,
}; };
} }
...@@ -349,6 +373,24 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -349,6 +373,24 @@ namespace PcapDotNet.Packets.IpV4
return totalLength; return totalLength;
} }
internal static IpV4Address CalculateDestination(IpV4Address currentDestination, IpV4Options options)
{
if (options == null)
return currentDestination;
IpV4OptionRoute destinationControllerRouteOption =
(IpV4OptionRoute)options.OptionsCollection.FirstOrDefault(option => option.OptionType == IpV4OptionType.LooseSourceRouting ||
option.OptionType == IpV4OptionType.StrictSourceRouting);
if (destinationControllerRouteOption != null)
{
ReadOnlyCollection<IpV4Address> route = destinationControllerRouteOption.Route;
if (destinationControllerRouteOption.PointedAddressIndex < route.Count)
return route[route.Count - 1];
}
return currentDestination;
}
internal IpV4Datagram(byte[] buffer, int offset, int length) internal IpV4Datagram(byte[] buffer, int offset, int length)
: base(buffer, offset, length) : base(buffer, offset, length)
{ {
...@@ -382,23 +424,24 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -382,23 +424,24 @@ namespace PcapDotNet.Packets.IpV4
buffer.Write(offset + Offset.HeaderChecksum, headerChecksumValue, Endianity.Big); buffer.Write(offset + Offset.HeaderChecksum, headerChecksumValue, Endianity.Big);
} }
internal static void WriteTransportChecksum(byte[] buffer, int offset, int headerLength, ushort transportLength, int transportChecksumOffset, bool isChecksumOptional, ushort? checksum) internal static void WriteTransportChecksum(byte[] buffer, int offset, int headerLength, ushort transportLength, int transportChecksumOffset, bool isChecksumOptional, ushort? checksum, IpV4Address destination)
{ {
ushort checksumValue = ushort checksumValue =
checksum == null checksum == null
? CalculateTransportChecksum(buffer, offset, headerLength, transportLength, transportChecksumOffset, isChecksumOptional) ? CalculateTransportChecksum(buffer, offset, headerLength, transportLength, transportChecksumOffset, isChecksumOptional, destination)
: checksum.Value; : checksum.Value;
buffer.Write(offset + headerLength + transportChecksumOffset, checksumValue, Endianity.Big); buffer.Write(offset + headerLength + transportChecksumOffset, checksumValue, Endianity.Big);
} }
private ushort CalculateTransportChecksum() private ushort CalculateTransportChecksum()
{ {
return CalculateTransportChecksum(Buffer, StartOffset, HeaderLength, (ushort)(TotalLength - HeaderLength), Transport.ChecksumOffset, Transport.IsChecksumOptional); return CalculateTransportChecksum(Buffer, StartOffset, HeaderLength, (ushort)(TotalLength - HeaderLength), Transport.ChecksumOffset, Transport.IsChecksumOptional, Destination);
} }
private static ushort CalculateTransportChecksum(byte[] buffer, int offset, int headerLength, ushort transportLength, int transportChecksumOffset, bool isChecksumOptional) private static ushort CalculateTransportChecksum(byte[] buffer, int offset, int headerLength, ushort transportLength, int transportChecksumOffset, bool isChecksumOptional, IpV4Address destination)
{ {
uint sum = Sum16Bits(buffer, offset + Offset.Source, 2 * IpV4Address.SizeOf) + uint sum = Sum16Bits(buffer, offset + Offset.Source, IpV4Address.SizeOf) +
Sum16Bits(destination) +
buffer[offset + Offset.Protocol] + transportLength + buffer[offset + Offset.Protocol] + transportLength +
Sum16Bits(buffer, offset + headerLength, transportChecksumOffset) + Sum16Bits(buffer, offset + headerLength, transportChecksumOffset) +
Sum16Bits(buffer, offset + headerLength + transportChecksumOffset + 2, transportLength - transportChecksumOffset - 2); Sum16Bits(buffer, offset + headerLength + transportChecksumOffset + 2, transportLength - transportChecksumOffset - 2);
...@@ -451,6 +494,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -451,6 +494,7 @@ namespace PcapDotNet.Packets.IpV4
return Sum16BitsToChecksum(sum); return Sum16BitsToChecksum(sum);
} }
private IpV4Address? _destination;
private bool? _isHeaderChecksumCorrect; private bool? _isHeaderChecksumCorrect;
private bool? _isTransportChecksumCorrect; private bool? _isTransportChecksumCorrect;
private IpV4Options _options; private IpV4Options _options;
......
...@@ -22,7 +22,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -22,7 +22,7 @@ namespace PcapDotNet.Packets.IpV4
Protocol = null; Protocol = null;
HeaderChecksum = null; HeaderChecksum = null;
Source = IpV4Address.Zero; Source = IpV4Address.Zero;
Destination = IpV4Address.Zero; CurrentDestination = IpV4Address.Zero;
Options = IpV4Options.None; Options = IpV4Options.None;
} }
...@@ -64,9 +64,19 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -64,9 +64,19 @@ namespace PcapDotNet.Packets.IpV4
public IpV4Address Source { get; set; } public IpV4Address Source { get; set; }
/// <summary> /// <summary>
/// The destination address. /// The current destination address.
/// This might not be the final destination when source routing options exist.
/// </summary> /// </summary>
public IpV4Address Destination { get; set; } public IpV4Address CurrentDestination { get; set; }
/// <summary>
/// The final destination address.
/// Takes into account the current destination and source routing options if they exist.
/// </summary>
public IpV4Address Destination
{
get { return IpV4Datagram.CalculateDestination(CurrentDestination, Options); }
}
/// <summary> /// <summary>
/// The options field with all the parsed options if any exist. /// The options field with all the parsed options if any exist.
...@@ -132,7 +142,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -132,7 +142,7 @@ namespace PcapDotNet.Packets.IpV4
IpV4Datagram.WriteHeader(buffer, offset, IpV4Datagram.WriteHeader(buffer, offset,
TypeOfService, Identification, Fragmentation, TypeOfService, Identification, Fragmentation,
Ttl, protocol, HeaderChecksum, Ttl, protocol, HeaderChecksum,
Source, Destination, Source, CurrentDestination,
Options, payloadLength); Options, payloadLength);
} }
...@@ -152,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -152,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4
IpV4Datagram.WriteTransportChecksum(buffer, offset, Length, (ushort)payloadLength, IpV4Datagram.WriteTransportChecksum(buffer, offset, Length, (ushort)payloadLength,
nextTransportLayer.ChecksumOffset, nextTransportLayer.IsChecksumOptional, nextTransportLayer.ChecksumOffset, nextTransportLayer.IsChecksumOptional,
nextTransportLayer.Checksum); nextTransportLayer.Checksum, Destination);
} }
/// <summary> /// <summary>
...@@ -165,7 +175,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -165,7 +175,7 @@ namespace PcapDotNet.Packets.IpV4
Fragmentation == other.Fragmentation && Ttl == other.Ttl && Fragmentation == other.Fragmentation && Ttl == other.Ttl &&
Protocol == other.Protocol && Protocol == other.Protocol &&
HeaderChecksum == other.HeaderChecksum && HeaderChecksum == other.HeaderChecksum &&
Source == other.Source && Destination == other.Destination && Source == other.Source && CurrentDestination == other.CurrentDestination &&
Options.Equals(other.Options); Options.Equals(other.Options);
} }
...@@ -185,7 +195,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -185,7 +195,7 @@ namespace PcapDotNet.Packets.IpV4
{ {
return base.GetHashCode() ^ return base.GetHashCode() ^
Sequence.GetHashCode(BitSequence.Merge(TypeOfService, Identification, Ttl), Sequence.GetHashCode(BitSequence.Merge(TypeOfService, Identification, Ttl),
Fragmentation, Source, Destination, Options) ^ Protocol.GetHashCode() ^ HeaderChecksum.GetHashCode(); Fragmentation, Source, CurrentDestination, Options) ^ Protocol.GetHashCode() ^ HeaderChecksum.GetHashCode();
} }
/// <summary> /// <summary>
......
...@@ -183,7 +183,12 @@ namespace PcapDotNet.Packets.Transport ...@@ -183,7 +183,12 @@ namespace PcapDotNet.Packets.Transport
/// </summary> /// </summary>
public TcpOptions Options public TcpOptions Options
{ {
get { return _options ?? (_options = new TcpOptions(Buffer, StartOffset + Offset.Options, RealHeaderLength - HeaderMinimumLength)); } get
{
if (_options == null && Length >= HeaderMinimumLength && HeaderLength >= HeaderMinimumLength)
_options = new TcpOptions(Buffer, StartOffset + Offset.Options, RealHeaderLength - HeaderMinimumLength);
return _options;
}
} }
/// <summary> /// <summary>
...@@ -332,7 +337,7 @@ namespace PcapDotNet.Packets.Transport ...@@ -332,7 +337,7 @@ namespace PcapDotNet.Packets.Transport
/// </summary> /// </summary>
protected override bool CalculateIsValid() protected override bool CalculateIsValid()
{ {
return Length >= HeaderMinimumLength && Length >= HeaderLength && Options.IsValid; return Length >= HeaderMinimumLength && Length >= HeaderLength && HeaderLength >= HeaderMinimumLength && Options.IsValid;
} }
internal TcpDatagram(byte[] buffer, int offset, int length) internal TcpDatagram(byte[] buffer, int offset, int length)
......
...@@ -91,6 +91,11 @@ namespace PcapDotNet.Packets.Transport ...@@ -91,6 +91,11 @@ namespace PcapDotNet.Packets.Transport
/// </summary> /// </summary>
Md5Signature = 19, Md5Signature = 19,
/// <summary>
/// Selective Negative Acknowledgements.
/// </summary>
SelectiveNegativeAcknowledgements = 21,
/// <summary> /// <summary>
/// Denote Packet Mood (RFC5841) /// Denote Packet Mood (RFC5841)
/// </summary> /// </summary>
......
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