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 @@
<Compile Include="PropertyInfoExtensions.cs" />
<Compile Include="Sequence.cs" />
<Compile Include="SerialNumber32.cs" />
<Compile Include="ShortExtensions.cs" />
<Compile Include="TimeSpanExtensions.cs" />
<Compile Include="TypeExtensions.cs" />
<Compile Include="UInt128.cs" />
......@@ -106,6 +107,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UInt48.cs" />
<Compile Include="UIntExtensions.cs" />
<Compile Include="UShortExtensions.cs" />
</ItemGroup>
<ItemGroup>
<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;
namespace PcapDotNet.Core.Test
{
internal static class MoreIpV4Option
internal static class IpV4OptionExtensions
{
public static string GetWiresharkString(this IpV4Option option)
{
switch (option.OptionType)
{
case IpV4OptionType.EndOfOptionList:
return "EOL";
return "End of Option List (EOL)";
case IpV4OptionType.NoOperation:
return "NOP";
return "No-Operation (NOP)";
case IpV4OptionType.BasicSecurity:
return "Security";
......@@ -152,5 +152,12 @@ namespace PcapDotNet.Core.Test
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
{
public LivePacketDeviceTests()
{
//
// TODO: Add constructor logic here
//
}
/// <summary>
......@@ -135,7 +132,7 @@ namespace PcapDotNet.Core.Test
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, 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);
// Test non blocking
......@@ -155,7 +152,7 @@ namespace PcapDotNet.Core.Test
const int PacketSize = 100;
// 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
TestReceivePackets(NumPacketsToSend, NumPacketsToSend / 2, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend / 2, 0, 0.04);
......@@ -163,7 +160,7 @@ namespace PcapDotNet.Core.Test
// Wait for more packets
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, 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
TestReceivePackets(NumPacketsToSend, NumPacketsToSend, 0, 2, PacketSize, PacketCommunicatorReceiveResult.BreakLoop, 0, 0, 0.027);
......
......@@ -73,8 +73,8 @@
<Compile Include="LivePacketDeviceExtensionsTests.cs" />
<Compile Include="LivePacketDeviceTests.cs" />
<Compile Include="MarshalingServicesTests.cs" />
<Compile Include="MoreIpV4Option.cs" />
<Compile Include="MoreTcpOption.cs" />
<Compile Include="IpV4OptionExtensions.cs" />
<Compile Include="TcpOptionExtensions.cs" />
<Compile Include="WiresharkDatagramComparer.cs" />
<Compile Include="WiresharkDatagramComparerArp.cs" />
<Compile Include="WiresharkDatagramComparerDns.cs" />
......
......@@ -6,17 +6,21 @@ using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Core.Test
{
internal static class MoreTcpOption
internal static class TcpOptionExtensions
{
public static string GetWiresharkString(this TcpOption option)
{
switch (option.OptionType)
{
case TcpOptionType.EndOfOptionList:
return "EOL";
return "End of Option List (EOL)";
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:
return "SACK permitted";
......@@ -37,12 +41,6 @@ namespace PcapDotNet.Core.Test
TcpOptionTimestamp timestampOption = (TcpOptionTimestamp)option;
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:
return "CC: " + ((TcpOptionConnectionCount)option).ConnectionCount;
......@@ -52,12 +50,6 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.ConnectionCountEcho:
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:
return "TCP MD5 signature";
......@@ -81,52 +73,17 @@ namespace PcapDotNet.Core.Test
? string.Empty
: " (with option length = " + option.Length + " bytes; should be 2)");
default:
if (typeof(TcpOptionType).GetEnumValues<TcpOptionType>().Contains(option.OptionType))
throw new InvalidOperationException("Invalid option type " + option.OptionType);
return "Unknown (0x" + ((byte)option.OptionType).ToString("x2") + ") (" + option.Length + " bytes)";
}
}
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;
case TcpOptionType.PartialOrderConnectionPermitted: // 9.
case TcpOptionType.PartialOrderServiceProfile: // 10.
case TcpOptionType.AlternateChecksumRequest: // 14.
case TcpOptionType.AlternateChecksumData: // 15.
case TcpOptionType.Mood: // 25.
return string.Format("Unknown (0x{0}) ({1} bytes)", ((byte)option.OptionType).ToString("x2"), option.Length);
default:
if (typeof(TcpOptionType).GetEnumValues<TcpOptionType>().Contains(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
private const string WiresharkDiretory = @"C:\Program Files\Wireshark\";
private const string WiresharkTsharkPath = WiresharkDiretory + @"tshark.exe";
private const bool IsRetry
// = true;
= false;
private const byte RetryNumber = 27;
private static bool IsRetry
{
get { return RetryNumber != -1; }
}
private const int RetryNumber = -1;
/// <summary>
/// Gets or sets the test context which provides
......@@ -237,10 +238,11 @@ namespace PcapDotNet.Core.Test
UdpLayer udpLayer = random.NextUdpLayer();
DnsLayer dnsLayer = random.NextDnsLayer();
ushort specialPort = (ushort)(random.NextBool() ? 53 : 5355);
if (dnsLayer.IsQuery)
udpLayer.DestinationPort = 53;
udpLayer.DestinationPort = specialPort;
else
udpLayer.SourcePort = 53;
udpLayer.SourcePort = specialPort;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, udpLayer, dnsLayer);
......@@ -256,7 +258,11 @@ namespace PcapDotNet.Core.Test
tcpLayer.DestinationPort = 80;
else
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:
throw new InvalidOperationException();
......@@ -393,6 +399,8 @@ namespace PcapDotNet.Core.Test
if (comparer == null)
return;
currentDatagram = comparer.Compare(layer, currentDatagram);
if (currentDatagram == null)
return;
break;
}
}
......
......@@ -18,7 +18,7 @@ namespace PcapDotNet.Core.Test
switch (field.Name())
{
case "arp.hw.type":
field.AssertShowHex((ushort)arpDatagram.HardwareType);
field.AssertShowDecimal((ushort)arpDatagram.HardwareType);
break;
case "arp.proto.type":
......@@ -34,7 +34,7 @@ namespace PcapDotNet.Core.Test
break;
case "arp.opcode":
field.AssertShowHex((ushort)arpDatagram.Operation);
field.AssertShowDecimal((ushort)arpDatagram.Operation);
break;
case "arp.src.hw":
......
......@@ -45,6 +45,7 @@ namespace PcapDotNet.Core.Test
flagField.AssertShowDecimal((byte)dnsDatagram.OpCode);
break;
case "dns.flags.conflict": // TODO: Support LLMNR.
case "dns.flags.authoritative":
flagField.AssertShowDecimal(dnsDatagram.IsAuthoritativeAnswer);
break;
......@@ -53,6 +54,7 @@ namespace PcapDotNet.Core.Test
flagField.AssertShowDecimal(dnsDatagram.IsTruncated);
break;
case "dns.flags.tentative": // TODO: Support LLMNR.
case "dns.flags.recdesired":
flagField.AssertShowDecimal(dnsDatagram.IsRecursionDesired);
break;
......@@ -141,8 +143,13 @@ namespace PcapDotNet.Core.Test
{
XElement[] resourceRecordFieldsArray= resourceRecordFields.ToArray();
DnsResourceRecord[] resourceRecordsArray = resourceRecords.ToArray();
Assert.AreEqual(resourceRecordFieldsArray.Length, resourceRecordsArray.Length);
for (int i = 0; i != resourceRecordFieldsArray.Length; ++i)
if (resourceRecordFieldsArray.Length != resourceRecordsArray.Length)
{
var queryNameField = resourceRecordFieldsArray[resourceRecordsArray.Length].Fields().First();
Assert.AreEqual("dns.qry.name", queryNameField.Name());
Assert.AreEqual("<Unknown extended label>", queryNameField.Show());
}
for (int i = 0; i != resourceRecordsArray.Length; ++i)
{
ResetRecordFields();
var resourceRecordField = resourceRecordFieldsArray[i];
......@@ -154,23 +161,52 @@ namespace PcapDotNet.Core.Test
case "dns.qry.name":
case "dns.resp.name":
resourceRecordAttributeField.AssertShow(GetWiresharkDomainName(resourceRecord.DomainName));
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.qry.type":
case "dns.resp.type":
resourceRecordAttributeField.AssertShowHex((ushort)resourceRecord.DnsType);
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.qry.class":
case "dns.resp.class":
resourceRecordAttributeField.AssertShowHex((ushort)resourceRecord.DnsClass);
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.resp.ttl":
resourceRecordAttributeField.AssertShowDecimal(resourceRecord.Ttl);
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.resp.len":
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.resp.cache_flush": // TODO: Find out what does this field symbolize.
resourceRecordAttributeField.AssertShowDecimal((ushort)resourceRecord.DnsClass >> 15);
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.srv.service":
Assert.AreEqual(resourceRecord.DnsType, DnsType.ServerSelection);
resourceRecordAttributeField.AssertShow(resourceRecord.DomainName.IsRoot ? "Root>" : resourceRecord.DomainName.ToString().Split('.')[0].Substring(1));
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.srv.proto":
Assert.AreEqual(resourceRecord.DnsType, DnsType.ServerSelection);
resourceRecordAttributeField.AssertShow(resourceRecord.DomainName.ToString().Split('.')[1].Substring(1));
resourceRecordAttributeField.AssertNoFields();
break;
case "dns.srv.name":
Assert.AreEqual(resourceRecord.DnsType, DnsType.ServerSelection);
resourceRecordAttributeField.AssertShow(
resourceRecord.DomainName.ToString().Split(new[] {'.'}, StringSplitOptions.RemoveEmptyEntries).Skip(2).SequenceToString("."));
resourceRecordAttributeField.AssertNoFields();
break;
default:
......@@ -213,9 +249,11 @@ namespace PcapDotNet.Core.Test
break;
case DnsType.Ns:
dataField.AssertName("");
dataField.AssertShow("Name server: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertName("dns.resp.ns");
dataField.AssertShow(GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertNoFields();
break;
case DnsType.Md: // 3.
case DnsType.MailForwarder: // 4.
case DnsType.Mailbox: // 7.
......@@ -223,11 +261,15 @@ namespace PcapDotNet.Core.Test
case DnsType.MailRename: // 9.
dataField.AssertName("");
dataField.AssertShow("Host: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertNoFields();
break;
case DnsType.CName:
dataField.AssertName("");
dataField.AssertShow("Primary name: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertName("dns.resp.primaryname");
dataField.AssertShow(GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertNoFields();
break;
case DnsType.StartOfAuthority:
dataField.AssertName("");
var soaData = (DnsResourceDataStartOfAuthority)data;
......@@ -264,6 +306,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.Wks:
......@@ -288,11 +331,15 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.Ptr:
dataField.AssertName("");
dataField.AssertShow("Domain name: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertNoFields();
break;
case DnsType.HInfo:
dataField.AssertName("");
var hInfoData = (DnsResourceDataHostInformation)data;
......@@ -309,6 +356,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.MInfo:
......@@ -327,6 +375,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.MailExchange:
......@@ -344,12 +393,14 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.Txt: // 16.
case DnsType.Spf: // 99.
var txtData = (DnsResourceDataText)data;
dataField.AssertShow("Text: " + txtData.Text[_txtIndex++].ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
dataField.AssertShow("Text: " + txtData.Text[_txtIndex++].ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false, false));
dataField.AssertNoFields();
break;
case DnsType.ResponsiblePerson:
......@@ -368,6 +419,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.AfsDatabase:
......@@ -387,11 +439,15 @@ namespace PcapDotNet.Core.Test
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.X25:
dataField.AssertName("");
dataField.AssertShow("PSDN-Address: " + ((DnsResourceDataString)data).String.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
dataField.AssertShow("PSDN-Address: " + ((DnsResourceDataString)data).String.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false, false));
dataField.AssertNoFields();
break;
case DnsType.Isdn:
dataField.AssertName("");
var isdnData = (DnsResourceDataIsdn)data;
......@@ -399,19 +455,20 @@ namespace PcapDotNet.Core.Test
{
case "ISDN Address":
dataField.AssertShow(dataFieldShowUntilColon + ": " +
isdnData.IsdnAddress.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
isdnData.IsdnAddress.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false, false));
break;
case "Subaddress":
dataField.AssertShow(dataFieldShowUntilColon + ": " +
isdnData.Subaddress.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
isdnData.Subaddress.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false, false));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.RouteThrough:
dataField.AssertName("");
var rtData = (DnsResourceDataRouteThrough)data;
......@@ -428,7 +485,9 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.NetworkServiceAccessPoint:
var nsapData = (DnsResourceDataNetworkServiceAccessPoint)data;
......@@ -443,11 +502,13 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
dataField.AssertNoFields();
break;
case DnsType.NetworkServiceAccessPointPointer:
dataField.AssertName("");
dataField.AssertShow("Owner: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertNoFields();
break;
case DnsType.Key:
......@@ -515,15 +576,17 @@ namespace PcapDotNet.Core.Test
case "Protocol":
dataField.AssertShow(dataFieldShowUntilColon + ": " + (byte)keyData.Protocol);
dataField.AssertNoFields();
break;
case "Algorithm":
dataField.AssertValue((byte)keyData.Algorithm);
dataField.AssertNoFields();
break;
case "Key id":
// TODO: Remove this once wireshark bug is fixed.
// https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6704
// TODO: Calculate key tag.
dataField.AssertNoFields();
break;
case "Public key":
......@@ -538,6 +601,7 @@ namespace PcapDotNet.Core.Test
flagsExtension.Write(0, keyData.FlagsExtension.Value, Endianity.Big);
}
dataField.AssertValue(flagsExtension.Concat(keyData.PublicKey));
dataField.AssertNoFields();
break;
default:
......@@ -590,6 +654,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.PointerX400:
......@@ -612,6 +677,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.GPos:
......@@ -634,7 +700,9 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.Aaaa:
dataField.AssertName("");
dataField.AssertShow("Addr: " + GetWiresharkIpV6(((DnsResourceDataIpV6)data).Data));
......@@ -653,10 +721,36 @@ namespace PcapDotNet.Core.Test
dataField.AssertShow("Data");
break;
case "Size":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetPrecisionValueString(locData.Size));
break;
case "Horizontal precision":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetPrecisionValueString(locData.HorizontalPrecision));
break;
case "Vertical precision":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetPrecisionValueString(locData.VerticalPrecision));
break;
case "Latitude":
dataField.AssertValue(locData.Latitude);
break;
case "Longitude":
dataField.AssertValue(locData.Longitude);
break;
case "Altitude":
dataField.AssertValue(locData.Altitude);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShowUntilColon);
}
dataField.AssertNoFields();
break;
case DnsType.NextDomain:
dataField.AssertName("");
var nxtData = (DnsResourceDataNextDomain)data;
......@@ -671,14 +765,15 @@ namespace PcapDotNet.Core.Test
DnsType expectedType;
if (!TryGetDnsType(dataFieldShow, out expectedType))
throw new InvalidOperationException(string.Format("Can't parse DNS field {0} : {1}", dataFieldShow, actualType));
else
Assert.AreEqual(expectedType, actualType);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.ServerSelection:
dataField.AssertName("");
var srvData = (DnsResourceDataServerSelection)data;
......@@ -701,8 +796,9 @@ namespace PcapDotNet.Core.Test
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShowUntilColon);
}
dataField.AssertNoFields();
break;
case DnsType.NaPtr:
......@@ -753,7 +849,9 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.KeyExchanger:
dataField.AssertName("");
var kxData = (DnsResourceDataKeyExchanger)data;
......@@ -771,6 +869,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.Cert:
......@@ -797,6 +896,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.A6:
......@@ -818,12 +918,13 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.DName:
dataField.AssertName("");
dataField.AssertShow("Target name: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
dataField.AssertNoFields();
break;
case DnsType.Opt:
......@@ -836,22 +937,38 @@ namespace PcapDotNet.Core.Test
{
case "UDP payload size":
dataField.AssertShow(dataFieldShowUntilColon + ": " + optResourceRecord.SendersUdpPayloadSize);
dataField.AssertNoFields();
break;
case "Higher bits in extended RCODE":
dataField.AssertValue(optResourceRecord.ExtendedReturnCode);
dataField.AssertNoFields();
break;
case "EDNS0 version":
dataField.AssertShow(dataFieldShowUntilColon + ": " + (byte)optResourceRecord.Version);
dataField.AssertNoFields();
break;
case "Z":
dataField.AssertValue((ushort)optResourceRecord.Flags);
ushort flags = (ushort)optResourceRecord.Flags;
dataField.AssertValue(flags);
if (dataField.Fields().Any())
{
dataField.AssertNumFields(2);
dataField.Fields().First().AssertShow("Bit 0 (DO bit): 1 (Accepts DNSSEC security RRs)");
// TODO - uncomment once https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7045 is fixed.
// dataField.Fields().Last().AssertShow("Bits 1-15: 0x" + (flags & 0x7FFF).ToString("x") + " (reserved)");
}
else
{
Assert.AreEqual<ushort>(0, (ushort)optResourceRecord.Flags);
}
break;
case "Data":
Assert.AreEqual(dataField.Value().Length, 2 * optData.Options.Options.Sum(option => option.Length));
dataField.AssertNoFields();
break;
default:
......@@ -861,6 +978,7 @@ namespace PcapDotNet.Core.Test
case "dns.resp.len":
dataField.AssertShow("Data length: " + optData.Options.Options.Sum(option => option.DataLength));
dataField.AssertNoFields();
break;
default:
......@@ -873,10 +991,25 @@ namespace PcapDotNet.Core.Test
switch (dataFieldName)
{
case "":
switch (dataFieldShowUntilColon)
{
case "Address Family":
dataField.AssertValue((ushort)aplData.Items[_aplItemIndex++].AddressFamily);
break;
case "hf.dns.apl.coded.prefix":
case "IPv4 address":
case "IPv6 address":
dataField.AssertValue(aplData.Items[_aplItemIndex - 1].AddressFamilyDependentPart);
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldShowUntilColon);
}
dataField.AssertNoFields();
break;
case "dns.apl.coded.prefix":
dataField.AssertShowDecimal(aplData.Items[_aplItemIndex - 1].PrefixLength);
break;
......@@ -891,6 +1024,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
dataField.AssertNoFields();
break;
case DnsType.DelegationSigner: // 43.
......@@ -918,7 +1052,9 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.SshFingerprint:
var sshFpData = (DnsResourceDataSshFingerprint)data;
switch (dataFieldName)
......@@ -946,6 +1082,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
dataField.AssertNoFields();
break;
case DnsType.IpSecKey:
......@@ -992,6 +1129,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.NSec:
......@@ -1015,6 +1153,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.DnsKey:
......@@ -1054,19 +1193,22 @@ namespace PcapDotNet.Core.Test
case "Protocol":
dataField.AssertShow(dataFieldShowUntilColon + ": " + dnsKeyData.Protocol);
dataField.AssertNoFields();
break;
case "Algorithm":
dataField.AssertValue((byte)dnsKeyData.Algorithm);
dataField.AssertNoFields();
break;
case "Key id":
// TODO: Remove this once wireshark bug is fixed.
// https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6704
// TODO: Calculate key tag.
dataField.AssertNoFields();
break;
case "Public key":
dataField.AssertValue(dnsKeyData.PublicKey);
dataField.AssertNoFields();
break;
default:
......@@ -1084,6 +1226,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS resource data field name " + dataFieldName);
}
dataField.AssertNoFields();
break;
case DnsType.NSec3:
......@@ -1092,6 +1235,7 @@ namespace PcapDotNet.Core.Test
{
case "dns.nsec3.algo":
dataField.AssertShowDecimal((byte)nSec3Data.HashAlgorithm);
dataField.AssertNoFields();
break;
case "dns.nsec3.flags":
......@@ -1113,22 +1257,27 @@ namespace PcapDotNet.Core.Test
case "dns.nsec3.iterations":
dataField.AssertShowDecimal(nSec3Data.Iterations);
dataField.AssertNoFields();
break;
case "dns.nsec3.salt_length":
dataField.AssertShowDecimal(nSec3Data.Salt.Length);
dataField.AssertNoFields();
break;
case "dns.nsec3.salt_value":
dataField.AssertValue(nSec3Data.Salt);
dataField.AssertNoFields();
break;
case "dns.nsec3.hash_length":
dataField.AssertShowDecimal(nSec3Data.NextHashedOwnerName.Length);
dataField.AssertNoFields();
break;
case "dns.nsec3.hash_value":
dataField.AssertValue(nSec3Data.NextHashedOwnerName);
dataField.AssertNoFields();
break;
case "":
......@@ -1140,6 +1289,7 @@ namespace PcapDotNet.Core.Test
Assert.IsTrue(
dataFieldShow.Replace("-", "").StartsWith("RR type in bit map: " + GetWiresharkDnsType(expectedType).Replace("-", "")),
string.Format("{0} : {1}", dataFieldShow, GetWiresharkDnsType(expectedType)));
dataField.AssertNoFields();
break;
default:
......@@ -1174,7 +1324,9 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS resource data field name " + dataFieldName);
}
dataField.AssertNoFields();
break;
case DnsType.Hip:
var hipData = (DnsResourceDataHostIdentityProtocol)data;
switch (dataFieldName)
......@@ -1215,6 +1367,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
dataField.AssertNoFields();
break;
case DnsType.TKey:
......@@ -1261,6 +1414,7 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case DnsType.TransactionSignature:
......@@ -1269,6 +1423,7 @@ namespace PcapDotNet.Core.Test
{
case "dns.tsig.algorithm_name":
dataField.AssertShow(GetWiresharkDomainName(tSigData.Algorithm));
dataField.AssertNoFields();
break;
case "":
......@@ -1281,14 +1436,17 @@ namespace PcapDotNet.Core.Test
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
dataField.AssertNoFields();
break;
case "dns.tsig.fudge":
dataField.AssertShowDecimal(tSigData.Fudge);
dataField.AssertNoFields();
break;
case "dns.tsig.mac_size":
dataField.AssertShowDecimal(tSigData.MessageAuthenticationCode.Length);
dataField.AssertNoFields();
break;
case "dns.tsig.mac":
......@@ -1301,24 +1459,29 @@ namespace PcapDotNet.Core.Test
case "dns.tsig.original_id":
dataField.AssertShowDecimal(tSigData.OriginalId);
dataField.AssertNoFields();
break;
case "dns.tsig.error":
dataField.AssertShowDecimal((ushort)tSigData.Error);
dataField.AssertNoFields();
break;
case "dns.tsig.other_len":
dataField.AssertShowDecimal(tSigData.Other.Length);
dataField.AssertNoFields();
break;
case "dns.tsig.other_data":
dataField.AssertValue(tSigData.Other);
dataField.AssertNoFields();
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.Null: // 10.
case DnsType.EId: // 31.
case DnsType.NimrodLocator: // 32.
......@@ -1343,6 +1506,7 @@ namespace PcapDotNet.Core.Test
default:
dataField.AssertName("");
dataField.AssertShow("Data");
dataField.AssertNoFields();
break;
}
}
......@@ -1423,6 +1587,21 @@ namespace PcapDotNet.Core.Test
return flagField.Show().Replace(" ", "").TakeWhile(c => c == '.').Count();
}
private static string GetPrecisionValueString(ulong value)
{
double resultValue = value / 100.0;
string valueDescription = " m";
if (resultValue >= 1000000)
{
int log = (int)Math.Log10(resultValue);
resultValue /= Math.Pow(10, log);
valueDescription = "e+00" + log + valueDescription;
}
return resultValue + valueDescription;
}
private int _hipRendezvousServersIndex;
private int _wksBitmapIndex;
private int _nxtTypeIndex;
......
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
......@@ -21,146 +22,148 @@ namespace PcapDotNet.Core.Test
GreDatagram greDatagram = (GreDatagram)datagram;
switch (field.Name())
{
case "":
if (field.Show().StartsWith("Flags and version: "))
{
case "gre.flags_and_version":
XElement[] innerFields = field.Fields().ToArray();
bool isEnhanced = greDatagram.ProtocolType == EthernetType.PointToPointProtocol;
Assert.AreEqual(isEnhanced ? 9 : 8, innerFields.Length, "innerFields.Length");
foreach (var innerField in innerFields)
{
innerField.AssertName("");
}
MoreAssert.IsInRange(8, 9, innerFields.Length);
int currentInnerFieldIndex = 0;
innerFields[currentInnerFieldIndex++].AssertShow(string.Format("{0}... .... .... .... = {1}", greDatagram.ChecksumPresent.ToInt(),
(greDatagram.ChecksumPresent ? "Checksum" : "No checksum")));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".{0}.. .... .... .... = {1}", greDatagram.RoutingPresent.ToInt(),
(greDatagram.RoutingPresent ? "Routing" : "No routing")));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format("..{0}. .... .... .... = {1}", greDatagram.KeyPresent.ToInt(),
(greDatagram.KeyPresent ? "Key" : "No key")));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format("...{0} .... .... .... = {1}",
greDatagram.SequenceNumberPresent.ToInt(),
(greDatagram.SequenceNumberPresent
? "Sequence number"
: "No sequence number")));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... {0}... .... .... = {1}", greDatagram.StrictSourceRoute.ToInt(),
(greDatagram.StrictSourceRoute
? "Strict source route"
: "No strict source route")));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .{0} .... .... = Recursion control: {1}",
greDatagram.RecursionControl.ToBits().Skip(5).Select(b => b.ToInt()).
SequenceToString(),
greDatagram.RecursionControl));
if (isEnhanced)
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.ChecksumPresent);
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.RoutingPresent);
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.KeyPresent);
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.SequenceNumberPresent);
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.StrictSourceRoute);
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.RecursionControl);
if (innerFields.Length == 9)
{
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... {0}... .... = {1}",
greDatagram.AcknowledgmentSequenceNumberPresent.ToInt(),
(greDatagram.AcknowledgmentSequenceNumberPresent
? "Acknowledgment number"
: "No acknowledgment number")));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... .{0}... = Flags: {1}",
greDatagram.FutureUseBits.ToBits().Skip(3).Take(4).Select(
b => b.ToInt()).
SequenceToString().
Insert(3, " "),
greDatagram.FutureUseBits));
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.AcknowledgmentSequenceNumberPresent);
innerFields[currentInnerFieldIndex++].AssertShowDecimal(greDatagram.FutureUseBits);
}
else
{
byte fullFlags = (byte)(greDatagram.FutureUseBits | (greDatagram.AcknowledgmentSequenceNumberPresent ? 0x10 : 0x00));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... {0}... = Flags: {1}",
fullFlags.ToBits().Skip(3).Select(b => b.ToInt()).
SequenceToString().
Insert(4, " "),
fullFlags));
}
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... .... .{0} = Version: {1}",
((byte)greDatagram.Version).ToBits().Skip(5).Select(b => b.ToInt()).
SequenceToString(),
(byte)greDatagram.Version));
}
else if (field.Show().StartsWith("Checksum: "))
{
field.AssertValue(greDatagram.Checksum);
}
else if (field.Show().StartsWith("Offset: "))
{
field.AssertValue(greDatagram.RoutingOffset);
}
else if (field.Show().StartsWith("Payload length: "))
{
field.AssertValue(greDatagram.KeyPayloadLength);
}
else if (field.Show().StartsWith("Call ID: "))
{
field.AssertValue(greDatagram.KeyCallId);
}
else if (field.Show().StartsWith("Sequence number: "))
{
field.AssertValue(greDatagram.SequenceNumber);
byte futureUseBitsValue = (byte)((greDatagram.AcknowledgmentSequenceNumberPresent.ToInt() << 4) | greDatagram.FutureUseBits);
innerFields[currentInnerFieldIndex++].AssertShowDecimal(futureUseBitsValue);
}
else if (field.Show().StartsWith("Acknowledgement number: "))
innerFields[currentInnerFieldIndex].AssertShowDecimal((byte)greDatagram.Version);
break;
case "data.len":
field.AssertShowDecimal(
greDatagram.Payload.Length + (greDatagram.AcknowledgmentSequenceNumberPresent &&
(greDatagram.Version != GreVersion.EnhancedGre || !greDatagram.SequenceNumberPresent)
? 4
: 0), "GRE data.len");
field.AssertNoFields();
break;
case "gre.checksum":
field.AssertShowHex(greDatagram.Checksum);
field.AssertNoFields();
break;
case "gre.key.payload_length":
field.AssertShowDecimal(greDatagram.KeyPayloadLength);
field.AssertNoFields();
break;
case "gre.key.call_id":
field.AssertShowDecimal(greDatagram.KeyCallId);
field.AssertNoFields();
break;
case "gre.ack_number":
field.AssertShowDecimal(greDatagram.AcknowledgmentSequenceNumber);
field.AssertNoFields();
break;
case "gre.sequence_number":
field.AssertShowDecimal(greDatagram.SequenceNumber);
field.AssertNoFields();
break;
case "gre.offset":
field.AssertShowDecimal(greDatagram.RoutingOffset);
field.AssertNoFields();
break;
case "gre.routing":
field.AssertShow("");
field.AssertNoFields();
break;
case "gre.routing.address_family":
if (_routingEntryIndex == greDatagram.Routing.Count)
{
field.AssertValue(greDatagram.AcknowledgmentSequenceNumber);
if (SupportedGre(greDatagram))
field.AssertShowDecimal(0);
}
else if (field.Show().StartsWith("Address family: "))
else
field.AssertShowDecimal((ushort)greDatagram.Routing[_routingEntryIndex].AddressFamily);
field.AssertNoFields();
break;
case "gre.routing.sre_offset":
if (_routingEntryIndex == greDatagram.Routing.Count)
{
++_currentEntry;
if (_currentEntry < greDatagram.Routing.Count)
field.AssertValue((ushort)greDatagram.Routing[_currentEntry].AddressFamily);
else if (_currentEntry > greDatagram.Routing.Count)
Assert.IsFalse(greDatagram.IsValid);
if (SupportedGre(greDatagram))
field.AssertShowDecimal(0);
}
else if (field.Show().StartsWith("SRE offset: "))
else
field.AssertShowDecimal(greDatagram.Routing[_routingEntryIndex].PayloadOffset);
field.AssertNoFields();
break;
case "gre.routing.src_length":
if (_routingEntryIndex == greDatagram.Routing.Count)
{
if (_currentEntry < greDatagram.Routing.Count)
field.AssertValue(greDatagram.Routing[_currentEntry].PayloadOffset);
else if (_currentEntry > greDatagram.Routing.Count)
Assert.IsFalse(greDatagram.IsValid);
if (SupportedGre(greDatagram))
field.AssertShowDecimal(0);
}
else if (field.Show().StartsWith("SRE length: "))
else
field.AssertShowDecimal(greDatagram.Routing[_routingEntryIndex].PayloadLength);
field.AssertNoFields();
break;
case "gre.routing.information":
if (_routingEntryIndex == greDatagram.Routing.Count)
{
if (_currentEntry < greDatagram.Routing.Count)
field.AssertValue(greDatagram.Routing[_currentEntry].PayloadLength);
else if (_currentEntry > greDatagram.Routing.Count)
Assert.IsFalse(greDatagram.IsValid);
Assert.IsFalse(SupportedGre(greDatagram));
}
else
{
Assert.Fail("Invalid field " + field.Show());
switch (greDatagram.Routing[_routingEntryIndex].AddressFamily)
{
case GreSourceRouteEntryAddressFamily.IpSourceRoute:
field.AssertValue(((GreSourceRouteEntryIp)greDatagram.Routing[_routingEntryIndex]).Addresses);
break;
case GreSourceRouteEntryAddressFamily.AsSourceRoute:
field.AssertValue(((GreSourceRouteEntryAs)greDatagram.Routing[_routingEntryIndex]).AsNumbers);
break;
default:
field.AssertValue(((GreSourceRouteEntryUnknown)greDatagram.Routing[_routingEntryIndex]).Data);
break;
}
++_routingEntryIndex;
}
field.AssertNoFields();
break;
case "gre.proto":
field.AssertShowHex((ushort)greDatagram.ProtocolType);
field.AssertNoFields();
break;
case "gre.key":
field.AssertShowHex(greDatagram.Key);
field.AssertNoFields();
break;
case "data":
case "data.data":
if (greDatagram.AcknowledgmentSequenceNumberPresent &&
(greDatagram.Version != GreVersion.EnhancedGre || !greDatagram.SequenceNumberPresent))
{
Assert.AreEqual(field.Value().Skip(8).SequenceToString(), greDatagram.Payload.BytesSequenceToHexadecimalString(), "GRE data.data");
}
else
{
field.AssertValue(greDatagram.Payload, "GRE data.data");
}
break;
case "data.len":
field.AssertShowDecimal(
greDatagram.Payload.Length + (greDatagram.AcknowledgmentSequenceNumberPresent &&
(greDatagram.Version != GreVersion.EnhancedGre || !greDatagram.SequenceNumberPresent)
? 4
: 0), "GRE data.len");
if (SupportedGre(greDatagram))
field.AssertDataField(greDatagram.Payload);
break;
default:
......@@ -171,6 +174,14 @@ namespace PcapDotNet.Core.Test
return true;
}
private int _currentEntry = -1;
private static bool SupportedGre(GreDatagram greDatagram)
{
return greDatagram.IsValid &&
(greDatagram.ProtocolType == EthernetType.PointToPointProtocol ||
greDatagram.Version == GreVersion.EnhancedGre ||
!greDatagram.AcknowledgmentSequenceNumberPresent);
}
private int _routingEntryIndex = 0;
}
}
\ No newline at end of file
......@@ -33,14 +33,10 @@ namespace PcapDotNet.Core.Test
if (field.Name() == "data")
field.AssertNoShow();
MoreAssert.AreSequenceEqual(httpDatagram.Take(_data.Length / 2), HexEncoding.Instance.GetBytes(_data.ToString()));
// string previousData = data.ToString();
// for (int i = 0; i != previousData.Length / 2; ++i)
// {
// byte value = Convert.ToByte(previousData.Substring(i * 2, 2), 16);
// Assert.AreEqual(httpDatagram[i], value);
// }
field.AssertValue(httpDatagram.Skip(_data.Length / 2));
MoreAssert.AreSequenceEqual(httpDatagram.Subsegment(0, _data.Length / 2), HexEncoding.Instance.GetBytes(_data.ToString()));
// TODO: Uncomment once https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=7065 is fixed.
// if (!IsBadHttpResponse(httpDatagram))
// field.AssertValue(httpDatagram.Subsegment(_data.Length / 2, httpDatagram.Length - _data.Length / 2));
return false;
}
......@@ -84,8 +80,10 @@ namespace PcapDotNet.Core.Test
if (httpDatagram.Header == null)
{
Assert.IsTrue(httpDatagram.IsRequest);
if (httpDatagram.IsRequest)
Assert.IsNull(httpDatagram.Version);
else
Assert.IsTrue(IsBadHttp(httpDatagram));
break;
}
httpFieldName = fieldShow.Substring(0, colonIndex);
......@@ -131,27 +129,45 @@ namespace PcapDotNet.Core.Test
case "http.content_length_header":
_data.Append(field.Value());
if (!IsBadHttp(httpDatagram))
field.AssertShowDecimal(httpDatagram.Header.ContentLength.ContentLength.Value);
break;
case "http.content_type":
_data.Append(field.Value());
string[] mediaType = fieldShow.Split(new[] {';', ' ', '/'}, StringSplitOptions.RemoveEmptyEntries);
if (!IsBadHttp(httpDatagram))
{
Assert.AreEqual(httpDatagram.Header.ContentType.MediaType, mediaType[0]);
Assert.AreEqual(httpDatagram.Header.ContentType.MediaSubtype, mediaType[1]);
int fieldShowParametersStart = fieldShow.IndexOf(';');
if (fieldShowParametersStart == -1)
Assert.IsFalse(httpDatagram.Header.ContentType.Parameters.Any());
else
Assert.AreEqual(
httpDatagram.Header.ContentType.Parameters.Select(pair => pair.Key + '=' + pair.Value.ToWiresharkLiteral()).SequenceToString(';'),
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;
case "http.transfer_encoding":
_data.Append(field.Value());
if (!IsBadHttp(httpDatagram))
{
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;
default:
......@@ -165,6 +181,7 @@ namespace PcapDotNet.Core.Test
{
foreach (var field in httpFirstLineElement.Fields())
{
field.AssertNoFields();
switch (field.Name())
{
case "http.request.method":
......@@ -179,14 +196,25 @@ namespace PcapDotNet.Core.Test
case "http.request.version":
if (httpDatagram.Version == null)
field.AssertShow(string.Empty);
{
if (field.Show() != string.Empty)
Assert.IsTrue(field.Show().Contains(" "));
}
else
field.AssertShow(httpDatagram.Version.ToString());
break;
case "http.response.code":
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;
default:
......@@ -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();
bool _isFirstEmptyName = true;
}
......
using System;
using System.Text;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test
{
......@@ -20,43 +23,35 @@ namespace PcapDotNet.Core.Test
{
case "icmp.type":
field.AssertShowDecimal((byte)icmpDatagram.MessageType);
field.AssertNoFields();
break;
case "icmp.code":
field.AssertShowDecimal(icmpDatagram.Code);
field.AssertNoFields();
break;
case "icmp.checksum_bad":
field.AssertShowDecimal(!icmpDatagram.IsChecksumCorrect);
field.AssertNoFields();
break;
case "icmp.checksum":
field.AssertShowHex(icmpDatagram.Checksum);
field.AssertNoFields();
break;
case "data":
var casted1 = icmpDatagram as IcmpIpV4HeaderPlus64BitsPayloadDatagram;
if (casted1 != null)
field.AssertValue(casted1.IpV4.Payload);
else
field.AssertValue(icmpDatagram.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);
{
if (casted1.IpV4.Protocol != IpV4Protocol.IpComp) // TODO: Support IpComp.
field.AssertDataField(casted1.IpV4.Payload);
}
else
field.AssertShowDecimal(icmpDatagram.Payload.Length);
{
field.AssertDataField(icmpDatagram.Payload);
}
break;
case "":
......@@ -120,14 +115,18 @@ namespace PcapDotNet.Core.Test
}
break;
}
field.AssertNoFields();
break;
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;
case "icmp.seq":
field.AssertShowDecimal(((IcmpIdentifiedDatagram)icmpDatagram).SequenceNumber);
field.AssertNoFields();
break;
case "icmp.seq_le":
......@@ -135,14 +134,22 @@ namespace PcapDotNet.Core.Test
sequenceNumberBuffer.Write(0, ((IcmpIdentifiedDatagram)icmpDatagram).SequenceNumber, Endianity.Big);
ushort lowerEndianSequenceNumber = sequenceNumberBuffer.ReadUShort(0, Endianity.Small);
field.AssertShowDecimal(lowerEndianSequenceNumber);
field.AssertNoFields();
break;
case "icmp.redir_gw":
field.AssertShow(((IcmpRedirectDatagram)icmpDatagram).GatewayInternetAddress.ToString());
field.AssertNoFields();
break;
case "icmp.mtu":
field.AssertShowDecimal(((IcmpDestinationUnreachableDatagram)icmpDatagram).NextHopMaximumTransmissionUnit);
field.AssertNoFields();
break;
case "l2tp.l2_spec_def":
field.AssertShow("");
field.AssertNoFields();
break;
default:
......
using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Igmp;
......@@ -61,6 +62,10 @@ namespace PcapDotNet.Core.Test
CompareDatagram(field, null, igmpDatagram);
break;
case IgmpMessageType.MulticastTraceRouteResponse:
// todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
break;
default:
if (typeof(IgmpMessageType).GetEnumValues<IgmpMessageType>().Contains(igmpDatagram.MessageType))
throw new InvalidOperationException("Invalid message type " + igmpDatagram.MessageType);
......@@ -97,7 +102,13 @@ namespace PcapDotNet.Core.Test
break;
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.
Assert.AreEqual(IgmpMessageType.MulticastTraceRouteResponse, igmpDatagram.MessageType);
break;
default:
......@@ -109,7 +120,6 @@ namespace PcapDotNet.Core.Test
private static void CompareIgmpGroupRecord(XElement groupRecord, IgmpGroupRecordDatagram groupRecordDatagram)
{
Console.WriteLine(groupRecordDatagram.AuxiliaryData);
int sourceAddressIndex = 0;
foreach (var field in groupRecord.Fields())
{
......
......@@ -84,13 +84,27 @@ namespace PcapDotNet.Core.Test
case "ip.dst":
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;
case "ip.addr":
case "ip.host":
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;
case "":
......
......@@ -70,7 +70,7 @@ namespace PcapDotNet.Core.Test
(ushort)((tcpDatagram.Reserved << 9) |
(((tcpDatagram.ControlBits & TcpControlBits.NonceSum) == TcpControlBits.NonceSum ? 1 : 0) << 8) |
(byte)tcpDatagram.ControlBits);
field.AssertShow("0x" + flags.ToString("x" + 2 * sizeof(byte)));
field.AssertShow("0x" + flags.ToString("x" + 4 * sizeof(byte)));
foreach (var flagField in field.Fields())
{
switch (flagField.Name())
......@@ -116,6 +116,8 @@ namespace PcapDotNet.Core.Test
case "tcp.checksum":
field.AssertShowHex(tcpDatagram.Checksum);
if (!ipV4Datagram.Options.IsBadForWireshark())
{
foreach (var checksumField in field.Fields())
{
switch (checksumField.Name())
......@@ -127,6 +129,11 @@ namespace PcapDotNet.Core.Test
case "tcp.checksum_bad":
checksumField.AssertShowDecimal(!ipV4Datagram.IsTransportChecksumCorrect);
break;
default:
throw new InvalidOperationException("Invalid checksum field name " + checksumField.Name());
}
checksumField.AssertNoFields();
}
}
break;
......@@ -141,6 +148,8 @@ namespace PcapDotNet.Core.Test
case "tcp.stream":
case "tcp.pdu.size":
case "tcp.window_size_value":
case "tcp.window_size_scalefactor":
case "":
break;
......@@ -161,7 +170,9 @@ namespace PcapDotNet.Core.Test
Assert.IsFalse(options.IsValid, "Options IsValid");
Assert.IsTrue(
field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net
field.Show().Contains("bytes says option goes past end of options"), "Options show: " + field.Show());
field.Show().Contains("bytes says option goes past end of options") ||
field.Show().Contains(") (with too-short option length = "),
"Options show: " + field.Show());
Assert.AreEqual(options.Count, currentOptionIndex, "Options Count");
return;
}
......@@ -170,88 +181,170 @@ namespace PcapDotNet.Core.Test
switch (field.Name())
{
case "":
if (option.OptionType == (TcpOptionType)21)
switch (option.OptionType)
{
case TcpOptionType.SelectiveNegativeAcknowledgements: // TODO: Support Selective Negative Acknowledgements.
Assert.IsTrue(field.Show().StartsWith(option.GetWiresharkString()));
else
field.AssertNoFields();
break;
case (TcpOptionType)78: // TODO: Support Riverbed.
break;
default:
field.AssertShow(option.GetWiresharkString());
++currentOptionIndex;
break;
}
case "tcp.options.mss":
field.AssertShowDecimal(option is TcpOptionMaximumSegmentSize);
switch (option.OptionType)
{
case TcpOptionType.WindowScale:
TcpOptionWindowScale windowScale = (TcpOptionWindowScale)option;
foreach (var subField in field.Fields())
{
switch (subField.Name())
{
case "tcp.option_kind":
subField.AssertShowDecimal((byte)windowScale.OptionType);
break;
case "tcp.options.mss_val":
field.AssertShowDecimal(((TcpOptionMaximumSegmentSize)option).MaximumSegmentSize);
case "tcp.option_len":
subField.AssertShowDecimal(windowScale.Length);
break;
case "tcp.options.wscale.shift":
subField.AssertShowDecimal(windowScale.ScaleFactorLog);
break;
case "tcp.options.wscale.multiplier":
subField.AssertShowDecimal(1L << (windowScale.ScaleFactorLog % 32));
break;
default:
throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name());
}
}
break;
case TcpOptionType.SelectiveAcknowledgment:
var selectiveAcknowledgmentOption = (TcpOptionSelectiveAcknowledgment)option;
int blockIndex = 0;
foreach (var subField in field.Fields())
{
switch (subField.Name())
{
case "tcp.options.sack":
subField.AssertShowDecimal(true);
break;
case "tcp.options.sack_le":
subField.AssertShowDecimal(selectiveAcknowledgmentOption.Blocks[blockIndex].LeftEdge);
break;
case "tcp.options.sack_re":
subField.AssertShowDecimal(selectiveAcknowledgmentOption.Blocks[blockIndex].RightEdge);
++blockIndex;
break;
default:
throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name());
}
}
break;
case TcpOptionType.Timestamp:
var timestampOption = (TcpOptionTimestamp)option;
foreach (var subField in field.Fields())
{
switch (subField.Name())
{
case "tcp.option_kind":
subField.AssertShowDecimal((byte)option.OptionType);
break;
case "tcp.option_len":
subField.AssertShowDecimal(option.Length);
break;
case "tcp.options.timestamp.tsval":
subField.AssertShowDecimal(timestampOption.TimestampValue);
break;
case "tcp.options.timestamp.tsecr":
subField.AssertShowDecimal(timestampOption.TimestampEchoReply);
break;
default:
throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name());
}
}
break;
default:
field.AssertNoFields();
break;
}
++currentOptionIndex;
break;
case "tcp.options.wscale":
field.AssertShowDecimal(option is TcpOptionWindowScale);
case "tcp.options.mss":
Assert.AreEqual(TcpOptionType.MaximumSegmentSize, option.OptionType);
field.AssertShowDecimal(true);
field.AssertNoFields();
break;
case "tcp.options.wscale_val":
field.AssertShowDecimal(((TcpOptionWindowScale)option).ScaleFactorLog);
case "tcp.options.mss_val":
field.AssertShowDecimal(((TcpOptionMaximumSegmentSize)option).MaximumSegmentSize);
field.AssertNoFields();
++currentOptionIndex;
break;
case "tcp.options.echo":
Assert.IsTrue(option is TcpOptionEchoReply || option is TcpOptionEcho);
field.AssertShowDecimal(1);
break;
case "tcp.options.time_stamp":
Assert.IsTrue(option is TcpOptionTimestamp);
field.AssertShowDecimal(1);
field.AssertNoFields();
break;
case "tcp.options.cc":
Assert.IsTrue(option is TcpOptionConnectionCountBase);
field.AssertShowDecimal(1);
field.AssertNoFields();
break;
case "tcp.options.scps.vector":
Assert.AreEqual((TcpOptionType)20, option.OptionType);
if (field.Show() == "0")
++currentOptionIndex;
++currentOptionIndex;
break;
case "tcp.options.scps":
Assert.AreEqual((TcpOptionType)20, option.OptionType);
++currentOptionIndex;
Assert.IsFalse(field.Fields().Any());
break;
case "tcp.options.snack":
case "tcp.options.snack": // TODO: Support Selective Negative Acknowledgements.
case "tcp.options.snack.offset":
case "tcp.options.snack.size":
Assert.AreEqual((TcpOptionType)21, option.OptionType);
Assert.AreEqual(TcpOptionType.SelectiveNegativeAcknowledgements, option.OptionType);
field.AssertNoFields();
break;
case "tcp.options.sack_perm":
Assert.AreEqual(TcpOptionType.SelectiveAcknowledgmentPermitted, option.OptionType);
field.AssertNoFields();
++currentOptionIndex;
break;
case "tcp.options.mood":
Assert.AreEqual(TcpOptionType.Mood, option.OptionType);
field.AssertValue(Encoding.ASCII.GetBytes(((TcpOptionMood)option).EmotionString));
break;
case "tcp.options.mood_val":
Assert.AreEqual(TcpOptionType.Mood, option.OptionType);
field.AssertShow(((TcpOptionMood)option).EmotionString);
case "tcp.options.rvbd.probe":
Assert.AreEqual((TcpOptionType)76, option.OptionType);
// TODO: Support Riverbed.
++currentOptionIndex;
break;
default:
throw new InvalidOperationException("Invalid tcp options field " + field.Name());
}
if ((option is TcpOptionUnknown))
continue;
var optionShows = from f in field.Fields() select f.Show();
MoreAssert.AreSequenceEqual(optionShows, option.GetWiresharkSubfieldStrings());
}
}
}
......
......@@ -5,7 +5,7 @@ namespace PcapDotNet.Core.Test
{
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();
for (int i = 0; i != value.Length; ++i)
......@@ -13,7 +13,7 @@ namespace PcapDotNet.Core.Test
char currentChar = value[i];
if (currentChar == '\0')
return result.ToString();
if (putLeadingZerosInHexAndBackslashesBeforeSpecialCharacters)
if (escapeSpecialChars)
{
switch (currentChar)
{
......
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test
{
......@@ -39,6 +41,11 @@ namespace PcapDotNet.Core.Test
return element.GetAttributeValue("show");
}
public static string Showname(this XElement element)
{
return element.GetAttributeValue("showname");
}
public static string Value(this XElement element)
{
return element.GetAttributeValue("value");
......@@ -49,6 +56,16 @@ namespace PcapDotNet.Core.Test
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)
{
Assert.IsNull(element.Attribute("show"));
......@@ -146,6 +163,7 @@ namespace PcapDotNet.Core.Test
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());
}
......@@ -178,5 +196,46 @@ namespace PcapDotNet.Core.Test
{
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
Assert.AreEqual(arpLayer, packet.Ethernet.Arp.ExtractLayer(), "ARP Layer");
Assert.AreNotEqual(arpLayer, random.NextArpLayer(), "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
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);
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, " OK");
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, "OK");
// Response Header
......@@ -564,6 +564,31 @@ namespace PcapDotNet.Packets.Test
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)
{
Datagram expectedBody = expectedBodyString == null ? null : new Datagram(Encoding.ASCII.GetBytes(expectedBodyString));
......
......@@ -471,7 +471,7 @@ namespace PcapDotNet.Packets.Test
Ttl = 1,
Protocol = IpV4Protocol.WidebandExpak,
Source = new IpV4Address(1),
Destination = new IpV4Address(2),
CurrentDestination = new IpV4Address(2),
});
Assert.IsTrue(packet.IsValid);
......
......@@ -179,5 +179,15 @@ namespace PcapDotNet.Packets.Test
{
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,6 +13,11 @@ namespace PcapDotNet.Packets.TestUtils
public static HttpLayer NextHttpLayer(this Random random)
{
if (random.NextBool())
return random.NextHttpRequestLayer();
return random.NextHttpResponseLayer();
}
public static HttpRequestLayer NextHttpRequestLayer(this Random random)
{
HttpRequestLayer httpRequestLayer = new HttpRequestLayer();
if (random.NextBool(10))
......@@ -23,10 +28,11 @@ namespace PcapDotNet.Packets.TestUtils
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
{
Version = random.NextHttpVersion(),
......@@ -34,7 +40,7 @@ namespace PcapDotNet.Packets.TestUtils
};
httpResponseLayer.ReasonPhrase = httpResponseLayer.StatusCode == null ? null : random.NextHttpReasonPhrase();
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;
}
......@@ -304,7 +310,6 @@ namespace PcapDotNet.Packets.TestUtils
httpHeader.ContentType.MediaType == "multipart" &&
httpHeader.ContentType.MediaSubtype == "byteranges" &&
httpHeader.ContentType.Parameters["boundary"] != null)
{
List<byte> boundedBody = new List<byte>(random.NextDatagram(random.Next(1000)));
boundedBody.AddRange(EncodingExtensions.Iso88591.GetBytes("--" + httpHeader.ContentType.Parameters["boundary"] + "--"));
......
......@@ -27,7 +27,7 @@ namespace PcapDotNet.Packets.TestUtils
IgmpMessageType.JoinGroupReplyVersion0, IgmpMessageType.LeaveGroupRequestVersion0,
IgmpMessageType.LeaveGroupReplyVersion0, IgmpMessageType.ConfirmGroupRequestVersion0,
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;
TimeSpan igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(256 * 0.1) - TimeSpan.FromTicks(1));
IpV4Address igmpGroupAddress = random.NextIpV4Address();
......
......@@ -19,7 +19,7 @@ namespace PcapDotNet.Packets.TestUtils
HeaderChecksum = random.NextBool() ? (ushort?)random.NextUShort() : null,
Fragmentation = random.NextBool() ? random.NextIpV4Fragmentation() : IpV4Fragmentation.None,
Source = random.NextIpV4Address(),
Destination = random.NextIpV4Address(),
CurrentDestination = random.NextIpV4Address(),
Options = random.NextIpV4Options()
};
}
......
......@@ -104,6 +104,7 @@ namespace PcapDotNet.Packets.TestUtils
impossibleOptionTypes.Add(TcpOptionType.QuickStartResponse);
impossibleOptionTypes.Add(TcpOptionType.UserTimeout);
impossibleOptionTypes.Add(TcpOptionType.SelectiveNegativeAcknowledgements); // TODO: Support Selective Negative Acknowledgements.
TcpOptionType optionType = random.NextEnum<TcpOptionType>(impossibleOptionTypes);
switch (optionType)
......
......@@ -136,7 +136,11 @@ namespace PcapDotNet.Packets.Arp
public override int 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
{
short value = ReadShort(buffer, offset);
if (IsWrongEndianity(endianity))
value = IPAddress.HostToNetworkOrder(value);
value = value.ReverseEndianity();
return value;
}
......@@ -526,7 +526,7 @@ namespace PcapDotNet.Packets
public static void Write(this byte[] buffer, int offset, short value, Endianity endianity)
{
if (IsWrongEndianity(endianity))
value = IPAddress.HostToNetworkOrder(value);
value = value.ReverseEndianity();
Write(buffer, offset, value);
}
......@@ -763,7 +763,7 @@ namespace PcapDotNet.Packets
/// <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="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)
throw new ArgumentNullException("value");
......
......@@ -347,6 +347,12 @@ namespace PcapDotNet.Packets
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]);
}
}
\ No newline at end of file
......@@ -352,9 +352,10 @@ namespace PcapDotNet.Packets.Gre
/// <returns>true iff the datagram is valid.</returns>
protected override bool CalculateIsValid()
{
if (Length < HeaderMinimumLength || Length < HeaderLength)
return false;
Datagram payloadByProtocolType = PayloadDatagrams.Get(ProtocolType);
return (Length >= HeaderMinimumLength && Length >= HeaderLength &&
IsValidRouting && FutureUseBits == 0 &&
return (IsValidRouting && FutureUseBits == 0 &&
(Version == GreVersion.EnhancedGre || Version == GreVersion.Gre && !AcknowledgmentSequenceNumberPresent) &&
(!ChecksumPresent || IsChecksumCorrect) &&
(payloadByProtocolType == null || payloadByProtocolType.IsValid));
......
......@@ -72,6 +72,13 @@ namespace PcapDotNet.Packets.Http
return Bytes(AsciiBytes.Space);
}
public HttpParser SkipSpaces()
{
while (IsNext(AsciiBytes.Space))
Skip(1);
return this;
}
public HttpParser SkipLws()
{
while (true)
......
......@@ -69,7 +69,7 @@ namespace PcapDotNet.Packets.Http
HttpVersion version;
uint? statusCode;
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
{
Length = length,
......@@ -102,8 +102,6 @@ namespace PcapDotNet.Packets.Http
{
if (statusCode >= 100 && statusCode <= 199 || statusCode == 204 || statusCode == 205 || statusCode == 304)
return false;
// if (IsResponseToHeadRequest)
// return false;
return true;
}
}
......
using System;
using System.Linq;
using PcapDotNet.Base;
namespace PcapDotNet.Packets.Http
......@@ -24,7 +25,20 @@ namespace PcapDotNet.Packets.Http
/// The data of the reason phrase.
/// Example: OK
/// </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>
/// 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
buffer.WriteCarriageReturnLinefeed(ref offset);
}
private DataSegment _reasonPhrase;
}
}
\ No newline at end of file
......@@ -94,9 +94,10 @@ namespace PcapDotNet.Packets.Igmp
{
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)
sourceAddresses[i] = ReadIpV4Address(Offset.SourceAddresses + 4 * i, Endianity.Big);
sourceAddresses[i] = ReadIpV4Address(Offset.SourceAddresses + IpV4Address.SizeOf * i, Endianity.Big);
_sourceAddresses = new ReadOnlyCollection<IpV4Address>(sourceAddresses);
}
......
......@@ -79,5 +79,10 @@ namespace PcapDotNet.Packets.Igmp
/// Multicast Traceroute Response.
/// </summary>
MulticastTraceRouteResponse = 0x1E,
/// <summary>
/// Multicast Traceroute.
/// </summary>
MulticastTraceroute = 0x1F,
}
}
\ No newline at end of file
using System;
using System.Collections.ObjectModel;
using System.Linq;
using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.Igmp;
......@@ -165,19 +167,41 @@ namespace PcapDotNet.Packets.IpV4
}
/// <summary>
/// The destination address.
/// The current destination address.
/// This might not be the final destination when source routing options exist.
/// </summary>
public IpV4Address Destination
public IpV4Address CurrentDestination
{
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>
/// The options field with all the parsed options if any exist.
/// </summary>
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>
......@@ -214,7 +238,7 @@ namespace PcapDotNet.Packets.IpV4
Protocol = Protocol,
HeaderChecksum = HeaderChecksum,
Source = Source,
Destination = Destination,
CurrentDestination = CurrentDestination,
Options = Options,
};
}
......@@ -349,6 +373,24 @@ namespace PcapDotNet.Packets.IpV4
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)
: base(buffer, offset, length)
{
......@@ -382,23 +424,24 @@ namespace PcapDotNet.Packets.IpV4
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 =
checksum == null
? CalculateTransportChecksum(buffer, offset, headerLength, transportLength, transportChecksumOffset, isChecksumOptional)
? CalculateTransportChecksum(buffer, offset, headerLength, transportLength, transportChecksumOffset, isChecksumOptional, destination)
: checksum.Value;
buffer.Write(offset + headerLength + transportChecksumOffset, checksumValue, Endianity.Big);
}
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 +
Sum16Bits(buffer, offset + headerLength, transportChecksumOffset) +
Sum16Bits(buffer, offset + headerLength + transportChecksumOffset + 2, transportLength - transportChecksumOffset - 2);
......@@ -451,6 +494,7 @@ namespace PcapDotNet.Packets.IpV4
return Sum16BitsToChecksum(sum);
}
private IpV4Address? _destination;
private bool? _isHeaderChecksumCorrect;
private bool? _isTransportChecksumCorrect;
private IpV4Options _options;
......
......@@ -22,7 +22,7 @@ namespace PcapDotNet.Packets.IpV4
Protocol = null;
HeaderChecksum = null;
Source = IpV4Address.Zero;
Destination = IpV4Address.Zero;
CurrentDestination = IpV4Address.Zero;
Options = IpV4Options.None;
}
......@@ -64,9 +64,19 @@ namespace PcapDotNet.Packets.IpV4
public IpV4Address Source { get; set; }
/// <summary>
/// The destination address.
/// The current destination address.
/// This might not be the final destination when source routing options exist.
/// </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>
/// The options field with all the parsed options if any exist.
......@@ -132,7 +142,7 @@ namespace PcapDotNet.Packets.IpV4
IpV4Datagram.WriteHeader(buffer, offset,
TypeOfService, Identification, Fragmentation,
Ttl, protocol, HeaderChecksum,
Source, Destination,
Source, CurrentDestination,
Options, payloadLength);
}
......@@ -152,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4
IpV4Datagram.WriteTransportChecksum(buffer, offset, Length, (ushort)payloadLength,
nextTransportLayer.ChecksumOffset, nextTransportLayer.IsChecksumOptional,
nextTransportLayer.Checksum);
nextTransportLayer.Checksum, Destination);
}
/// <summary>
......@@ -165,7 +175,7 @@ namespace PcapDotNet.Packets.IpV4
Fragmentation == other.Fragmentation && Ttl == other.Ttl &&
Protocol == other.Protocol &&
HeaderChecksum == other.HeaderChecksum &&
Source == other.Source && Destination == other.Destination &&
Source == other.Source && CurrentDestination == other.CurrentDestination &&
Options.Equals(other.Options);
}
......@@ -185,7 +195,7 @@ namespace PcapDotNet.Packets.IpV4
{
return base.GetHashCode() ^
Sequence.GetHashCode(BitSequence.Merge(TypeOfService, Identification, Ttl),
Fragmentation, Source, Destination, Options) ^ Protocol.GetHashCode() ^ HeaderChecksum.GetHashCode();
Fragmentation, Source, CurrentDestination, Options) ^ Protocol.GetHashCode() ^ HeaderChecksum.GetHashCode();
}
/// <summary>
......
......@@ -183,7 +183,12 @@ namespace PcapDotNet.Packets.Transport
/// </summary>
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>
......@@ -332,7 +337,7 @@ namespace PcapDotNet.Packets.Transport
/// </summary>
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)
......
......@@ -91,6 +91,11 @@ namespace PcapDotNet.Packets.Transport
/// </summary>
Md5Signature = 19,
/// <summary>
/// Selective Negative Acknowledgements.
/// </summary>
SelectiveNegativeAcknowledgements = 21,
/// <summary>
/// Denote Packet Mood (RFC5841)
/// </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