Commit 8dcb5280 authored by Brickner_cp's avatar Brickner_cp

Fixed ICMP message types values for AddressMaskRequest and AddressMaskReply.

Added IGMP message type MulticastTracerouteResponse.
Added automatic IP ethernet type if IPv4 layer comes after Ethernet layer.
Code Coverage 95.25%
parent 3c7a3d78
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace PcapDotNet.Base.Test
{
/// Summary description for DictionaryExtensionsTests
/// </summary>
[TestClass]
// ReSharper disable InconsistentNaming
public class IDictionaryExtensionsTests
// ReSharper restore InconsistentNaming
{
/// <summary>
/// Gets or sets the test context which provides
/// information about and functionality for the current test run.
/// </summary>
public TestContext TestContext { get; set; }
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void DictionaryEqualsTest()
{
// Both null
Dictionary<int, int> dic1 = null;
Dictionary<int, int> dic2 = null;
Assert.IsTrue(dic1.DictionaryEquals(dic2));
Assert.IsTrue(dic2.DictionaryEquals(dic1));
// One null
dic1 = new Dictionary<int, int>();
Assert.IsFalse(dic1.DictionaryEquals(dic2));
Assert.IsFalse(dic2.DictionaryEquals(dic1));
// Both empty
dic2 = new Dictionary<int, int>();
Assert.IsTrue(dic1.DictionaryEquals(dic2));
Assert.IsTrue(dic2.DictionaryEquals(dic1));
// Different count
dic1.Add(1,1);
Assert.IsFalse(dic1.DictionaryEquals(dic2));
Assert.IsFalse(dic2.DictionaryEquals(dic1));
// Different key
dic2.Add(2, 1);
Assert.IsFalse(dic1.DictionaryEquals(dic2));
Assert.IsFalse(dic2.DictionaryEquals(dic1));
// Different value
dic1.Add(2, 1);
dic2.Add(1, 2);
Assert.IsFalse(dic1.DictionaryEquals(dic2));
Assert.IsFalse(dic2.DictionaryEquals(dic1));
}
}
}
\ No newline at end of file
......@@ -67,6 +67,7 @@
<Reference Include="System.Numerics" />
</ItemGroup>
<ItemGroup>
<Compile Include="IDictionaryExtensionsTests.cs" />
<Compile Include="FuncExtensionsTest.cs" />
<Compile Include="IEnumerableExtensionsTests.cs" />
<Compile Include="MemberInfoExtensionsTests.cs" />
......
......@@ -6,8 +6,11 @@ namespace PcapDotNet.Base
{
public static bool DictionaryEquals<TKey, TValue>(this IDictionary<TKey, TValue> dictionary1, IDictionary<TKey, TValue> dictionary2, IEqualityComparer<TValue> valueComparer)
{
if (ReferenceEquals(dictionary1, dictionary2))
return true;
if (dictionary1 == null || dictionary2 == null)
return dictionary1 == null && dictionary2 == null;
return false;
if (dictionary1.Count != dictionary2.Count)
return false;
......
......@@ -158,7 +158,7 @@ namespace PcapDotNet.Core.Test
TestReceivePackets(NumPacketsToSend, NumPacketsToSend, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend, 0, 0.063);
// Wait for less packets
TestReceivePackets(NumPacketsToSend, NumPacketsToSend / 2, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend / 2, 0, 0.02);
TestReceivePackets(NumPacketsToSend, NumPacketsToSend / 2, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.Ok, NumPacketsToSend / 2, 0, 0.027);
// Wait for more packets
TestReceivePackets(NumPacketsToSend, 0, int.MaxValue, 2, PacketSize, PacketCommunicatorReceiveResult.None, NumPacketsToSend, 2, 2.14);
......
......@@ -35,7 +35,7 @@ namespace PcapDotNet.Core.Test
private const bool IsRetry
// = true;
= false;
private const byte RetryNumber = 101;
private const byte RetryNumber = 61;
/// <summary>
/// Gets or sets the test context which provides
......@@ -68,10 +68,17 @@ namespace PcapDotNet.Core.Test
[TestMethod]
public void ComparePacketsToWiresharkTest()
{
if (IsRetry)
{
ComparePacketsToWireshark(null);
return;
}
Random random = new Random();
for (int i = 0; i != 10; ++i)
{
// Create packets
List<Packet> packets = new List<Packet>(CreateRandomPackets(200));
List<Packet> packets = new List<Packet>(CreateRandomPackets(random, 200));
// Compare packets to wireshark
ComparePacketsToWireshark(packets);
......@@ -125,6 +132,7 @@ namespace PcapDotNet.Core.Test
Ethernet,
Arp,
IpV4,
IpV4OverIpV4,
Igmp,
Icmp,
Gre,
......@@ -145,18 +153,25 @@ namespace PcapDotNet.Core.Test
PayloadLayer payloadLayer = random.NextPayloadLayer(random.Next(100));
switch (random.NextEnum<PacketType>())
// switch (PacketType.Http)
// switch (PacketType.IpV4OverIpV4)
{
case PacketType.Ethernet:
return PacketBuilder.Build(DateTime.Now, ethernetLayer, payloadLayer);
case PacketType.Arp:
ethernetLayer.EtherType = EthernetType.None;
ethernetLayer.Destination = MacAddress.Zero;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, random.NextArpLayer());
case PacketType.IpV4:
ethernetLayer.EtherType = EthernetType.None;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, payloadLayer);
case PacketType.IpV4OverIpV4:
ethernetLayer.EtherType = EthernetType.None;
ipV4Layer.Protocol = null;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, random.NextIpV4Layer(), payloadLayer);
case PacketType.Igmp:
ethernetLayer.EtherType = EthernetType.None;
ipV4Layer.Protocol = null;
......@@ -208,9 +223,8 @@ namespace PcapDotNet.Core.Test
}
}
private static IEnumerable<Packet> CreateRandomPackets(int numPackets)
private static IEnumerable<Packet> CreateRandomPackets(Random random, int numPackets)
{
Random random = new Random();
for (int i = 0; i != numPackets; ++i)
yield return CreateRandomPacket(random);
}
......@@ -770,6 +784,10 @@ namespace PcapDotNet.Core.Test
// todo support IGMP version 0 and IGMP identifier.
break;
case "igmp.mtrace.max_hops":
// todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
break;
default:
throw new InvalidOperationException("Invalid igmp field " + field.Name());
}
......@@ -1052,18 +1070,24 @@ namespace PcapDotNet.Core.Test
else if (field.Show().StartsWith("Address family: "))
{
++currentEntry;
if (currentEntry != greDatagram.Routing.Count)
if (currentEntry < greDatagram.Routing.Count)
field.AssertValue((ushort)greDatagram.Routing[currentEntry].AddressFamily);
else if (currentEntry > greDatagram.Routing.Count)
Assert.IsFalse(greDatagram.IsValid);
}
else if (field.Show().StartsWith("SRE offset: "))
{
if (currentEntry != greDatagram.Routing.Count)
if (currentEntry < greDatagram.Routing.Count)
field.AssertValue(greDatagram.Routing[currentEntry].PayloadOffset);
else if (currentEntry > greDatagram.Routing.Count)
Assert.IsFalse(greDatagram.IsValid);
}
else if (field.Show().StartsWith("SRE length: "))
{
if (currentEntry != greDatagram.Routing.Count)
if (currentEntry < greDatagram.Routing.Count)
field.AssertValue(greDatagram.Routing[currentEntry].PayloadLength);
else if (currentEntry > greDatagram.Routing.Count)
Assert.IsFalse(greDatagram.IsValid);
}
else
{
......@@ -1175,7 +1199,14 @@ namespace PcapDotNet.Core.Test
switch (field.Name())
{
case "tcp.len":
field.AssertShowDecimal(tcpDatagram.Payload.Length);
if (tcpDatagram.Payload == null)
{
// todo seems like a bug in tshark https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5235
break;
field.AssertShowDecimal(tcpDatagram.Length);
}
else
field.AssertShowDecimal(tcpDatagram.Payload.Length);
break;
case "tcp.srcport":
......@@ -1297,12 +1328,8 @@ namespace PcapDotNet.Core.Test
if (currentOptionIndex >= options.Count)
{
Assert.IsFalse(options.IsValid, "Options IsValid");
// if (field.Show().StartsWith("Unknown ("))
// {
// int.Parse()
// }
Assert.IsTrue(
// field.Show().StartsWith("Unknown (") || // Unknown in Wireshark but known (and invalid) in Pcap.Net
field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net
field.Show().Contains("bytes says option goes past end of options"), "Options show: " + field.Show());
Assert.AreEqual(options.Count, currentOptionIndex, "Options Count");
return;
......
......@@ -97,12 +97,12 @@ namespace PcapDotNet.Packets.Test
if (httpLayer.Header != null)
{
foreach (var field in httpLayer.Header)
Assert.AreNotEqual<object>("abc", field);
Assert.IsFalse(field.Equals("abc"));
if (httpLayer.Header.ContentType != null)
{
var parameters = httpLayer.Header.ContentType.Parameters;
Assert.AreEqual(parameters.Count, parameters.OfType<KeyValuePair<string, string>>().Count());
Assert.IsNotNull(((IEnumerable)parameters).GetEnumerator());
Assert.AreEqual<object>(parameters, httpDatagram.Header.ContentType.Parameters);
int maxParameterNameLength = parameters.Any() ? parameters.Max(pair => pair.Key.Length) : 0;
Assert.IsNull(parameters[new string('a', maxParameterNameLength + 1)]);
......@@ -495,6 +495,23 @@ namespace PcapDotNet.Packets.Test
Assert.AreEqual(Datagram.Empty, ((HttpResponseDatagram)packet.Ethernet.IpV4.Tcp.Http).ReasonPhrase, "ReasonPhrase");
}
[TestMethod]
public void HttpRequestWithoutUriTest()
{
PacketBuilder builder = new PacketBuilder(new EthernetLayer(),
new IpV4Layer(),
new TcpLayer(),
new HttpRequestLayer
{
Method = new HttpRequestMethod("UnknownMethod")
});
Packet packet = builder.Build(DateTime.Now);
Assert.IsNotNull(((HttpRequestDatagram)packet.Ethernet.IpV4.Tcp.Http).Method);
Assert.AreEqual(HttpRequestKnownMethod.Unknown, ((HttpRequestDatagram)packet.Ethernet.IpV4.Tcp.Http).Method.KnownMethod);
Assert.AreEqual(string.Empty, ((HttpRequestDatagram)packet.Ethernet.IpV4.Tcp.Http).Uri, "Uri");
}
[TestMethod]
public void HttpBadTransferCodingsRegexTest()
{
......
......@@ -171,5 +171,12 @@ namespace PcapDotNet.Packets.Test
Assert.IsNotNull(new TcpOptionMd5Signature(null));
Assert.Fail();
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void TcpOptionMoodBadEmotionStringTest()
{
Assert.IsNotNull(new TcpOptionMood((TcpOptionMoodEmotion)202).EmotionString);
}
}
}
\ No newline at end of file
......@@ -533,7 +533,8 @@ namespace PcapDotNet.Packets.TestUtils
IgmpMessageType.CreateGroupReplyVersion0, IgmpMessageType.JoinGroupRequestVersion0,
IgmpMessageType.JoinGroupReplyVersion0, IgmpMessageType.LeaveGroupRequestVersion0,
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.
IgmpQueryVersion igmpQueryVersion = IgmpQueryVersion.None;
TimeSpan igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(256 * 0.1) - TimeSpan.FromTicks(1));
IpV4Address igmpGroupAddress = random.NextIpV4Address();
......
......@@ -659,12 +659,12 @@ namespace PcapDotNet.Packets
buffer.Write(ref offset, value.MillisecondsSinceMidnightUniversalTime, endianity);
}
public static void WriteCarriageReturnLineFeed(this byte[] buffer, int offset)
{
buffer.Write(ref offset, AsciiBytes.CarriageReturn);
buffer.Write(offset, AsciiBytes.LineFeed);
}
// public static void WriteCarriageReturnLineFeed(this byte[] buffer, int offset)
// {
// buffer.Write(ref offset, AsciiBytes.CarriageReturn);
// buffer.Write(offset, AsciiBytes.LineFeed);
// }
//
public static void WriteCarriageReturnLineFeed(this byte[] buffer, ref int offset)
{
buffer.Write(ref offset, AsciiBytes.CarriageReturn);
......
......@@ -5,6 +5,24 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
public enum IcmpMessageType : byte
{
/// <summary>
/// RFC 792.
/// <para>
/// The data received in the echo message must be returned in the echo reply message.
/// </para>
///
/// <para>
/// The identifier and sequence number may be used by the echo sender to aid in matching the replies with the echo requests.
/// For example, the identifier might be used like a port in TCP or UDP to identify a session, and the sequence number might be incremented on each echo request sent.
/// The echoer returns these same values in the echo reply.
/// </para>
///
/// <para>
/// Code 0 may be received from a gateway or a host.
/// </para>
/// </summary>
EchoReply = 0x00,
/// <summary>
/// RFC 792
///
......@@ -33,43 +51,6 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
DestinationUnreachable = 0x03,
/// <summary>
/// RFC 792.
///
/// <para>
/// If the gateway processing a datagram finds the time to live field is zero it must discard the datagram.
/// The gateway may also notify the source host via the time exceeded message.
/// </para>
///
/// <para>
/// If a host reassembling a fragmented datagram cannot complete the reassembly due to missing fragments within its time limit it discards the datagram,
/// and it may send a time exceeded message.
/// If fragment zero is not available then no time exceeded need be sent at all.
/// </para>
///
/// <para>
/// Code 0 may be received from a gateway.
/// Code 1 may be received from a host.
/// </para>
/// </summary>
TimeExceeded = 0x0B,
/// <summary>
/// RFC 792.
///
/// <para>
/// If the gateway or host processing a datagram finds a problem with the header parameters such that it cannot complete processing the datagram it must discard the datagram.
/// One potential source of such a problem is with incorrect arguments in an option.
/// The gateway or host may also notify the source host via the parameter problem message.
/// This message is only sent if the error caused the datagram to be discarded.
/// </para>
///
/// <para>
/// Code 0 may be received from a gateway or a host.
/// </para>
/// </summary>
ParameterProblem = 0x0C,
/// <summary>
/// RFC 792.
///
......@@ -136,23 +117,52 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
Echo = 0x08,
/// <summary>
/// RFC 1256.
/// </summary>
RouterAdvertisement = 0x09,
/// <summary>
/// RFC 1256.
/// </summary>
RouterSolicitation = 0x0A,
/// <summary>
/// RFC 792.
///
/// <para>
/// The data received in the echo message must be returned in the echo reply message.
/// If the gateway processing a datagram finds the time to live field is zero it must discard the datagram.
/// The gateway may also notify the source host via the time exceeded message.
/// </para>
///
/// <para>
/// The identifier and sequence number may be used by the echo sender to aid in matching the replies with the echo requests.
/// For example, the identifier might be used like a port in TCP or UDP to identify a session, and the sequence number might be incremented on each echo request sent.
/// The echoer returns these same values in the echo reply.
/// If a host reassembling a fragmented datagram cannot complete the reassembly due to missing fragments within its time limit it discards the datagram,
/// and it may send a time exceeded message.
/// If fragment zero is not available then no time exceeded need be sent at all.
/// </para>
///
/// <para>
/// Code 0 may be received from a gateway.
/// Code 1 may be received from a host.
/// </para>
/// </summary>
TimeExceeded = 0x0B,
/// <summary>
/// RFC 792.
///
/// <para>
/// If the gateway or host processing a datagram finds a problem with the header parameters such that it cannot complete processing the datagram it must discard the datagram.
/// One potential source of such a problem is with incorrect arguments in an option.
/// The gateway or host may also notify the source host via the parameter problem message.
/// This message is only sent if the error caused the datagram to be discarded.
/// </para>
///
/// <para>
/// Code 0 may be received from a gateway or a host.
/// </para>
/// </summary>
EchoReply = 0x00,
ParameterProblem = 0x0C,
/// <summary>
/// RFC 792
......@@ -242,16 +252,6 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
InformationReply = 0x10,
/// <summary>
/// RFC 1256.
/// </summary>
RouterAdvertisement = 0x09,
/// <summary>
/// RFC 1256.
/// </summary>
RouterSolicitation = 0x0A,
/// <summary>
/// RFC 950.
///
......@@ -267,7 +267,7 @@ namespace PcapDotNet.Packets.Icmp
/// The "Identifier" and "Sequence Number" fields can be ignored.
/// </para>
/// </summary>
AddressMaskRequest = 0xA1,
AddressMaskRequest = 0x11,
/// <summary>
/// RFC 950.
......@@ -284,7 +284,7 @@ namespace PcapDotNet.Packets.Icmp
/// The "Identifier" and "Sequence Number" fields can be ignored.
/// </para>
/// </summary>
AddressMaskReply = 0xA2,
AddressMaskReply = 0x12,
/// <summary>
/// RFC 1393.
......@@ -310,7 +310,6 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
DomainNameReply = 0x26,
/// <summary>
/// RFC 2521.
/// </summary>
......
......@@ -439,7 +439,8 @@ namespace PcapDotNet.Packets.Igmp
{
if (_sourceAddresses == null)
{
IpV4Address[] sourceAddresses = new IpV4Address[NumberOfSources];
int actualNumberOfSources = Math.Min(NumberOfSources, (Length - Offset.SourceAddresses) / IpV4Address.SizeOf);
IpV4Address[] sourceAddresses = new IpV4Address[actualNumberOfSources];
for (int i = 0; i != sourceAddresses.Length; ++i)
sourceAddresses[i] = ReadIpV4Address(Offset.SourceAddresses + IpV4Address.SizeOf * i, Endianity.Big);
_sourceAddresses = new ReadOnlyCollection<IpV4Address>(sourceAddresses);
......
......@@ -73,6 +73,8 @@ namespace PcapDotNet.Packets.Igmp
/// <summary>
/// Version 2 Leave Group (RFC2236).
/// </summary>
LeaveGroupVersion2 = 0x17
LeaveGroupVersion2 = 0x17,
MulticastTracerouteResponse = 0x1E,
}
}
\ No newline at end of file
......@@ -7,7 +7,7 @@ namespace PcapDotNet.Packets.IpV4
/// Represents IPv4 layer.
/// <seealso cref="IpV4Datagram"/>
/// </summary>
public class IpV4Layer : Layer, IEthernetNextLayer
public class IpV4Layer : Layer, IEthernetNextLayer, IIpV4NextLayer
{
/// <summary>
/// Creates an IPv4 layer with all zero values.
......@@ -80,6 +80,11 @@ namespace PcapDotNet.Packets.IpV4
get { return EthernetType.IpV4; }
}
public IpV4Protocol PreviousLayerProtocol
{
get { return IpV4Protocol.Ip; }
}
/// <summary>
/// The default MAC Address value when this layer is the Ethernet payload.
/// null means there is no default value.
......
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