Commit 97e00f11 authored by Brickner_cp's avatar Brickner_cp

TCP and IPv4

parent 12ccada5
using System;
using System.Collections.Generic;
namespace PcapDotNet.Base
{
public static class MoreType
{
public static IEnumerable<T> GetEnumValues<T>(this Type type)
{
return (IEnumerable<T>)Enum.GetValues(type);
}
}
}
\ No newline at end of file
......@@ -58,6 +58,7 @@
<Compile Include="MoreIEnumerable.cs" />
<Compile Include="MoreIList.cs" />
<Compile Include="MorePropertyInfo.cs" />
<Compile Include="MoreType.cs" />
<Compile Include="Tuple.cs" />
<Compile Include="UInt24.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
namespace PcapDotNet.Core.Test
{
......@@ -59,5 +62,12 @@ namespace PcapDotNet.Core.Test
{
Assert.IsTrue(Regex.IsMatch(actualValue, expectedPattern), "Expected pattern: <" + expectedPattern + ">. Actual value: <" + actualValue + ">.");
}
public static void AreSequenceEqual<T>(IEnumerable<T> expectedSequence, IEnumerable<T> actualSequence)
{
Assert.IsTrue(expectedSequence.SequenceEqual(actualSequence),
"Expected sequence: <" + expectedSequence.SequenceToString(",") + ">. Actual sequence: <" +
actualSequence.SequenceToString(",") + ">.");
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test
......@@ -70,8 +73,15 @@ namespace PcapDotNet.Core.Test
return quickStartWireshark.ToString();
case (IpV4OptionType)134:
return "Commercial IP security option" + (option.Length >= 10
? string.Empty
: " (with option length = " + option.Length + " bytes; should be >= 10)");
default:
throw new InvalidOperationException("Illegal option type " + option.OptionType);
if (typeof(IpV4OptionType).GetEnumValues<IpV4OptionType>().Contains(option.OptionType))
throw new InvalidOperationException("Invalid option type " + option.OptionType);
return "Unknown (0x" + ((byte)option.OptionType).ToString("x2") + ") (" + option.Length + " bytes)";
}
}
......@@ -138,7 +148,9 @@ namespace PcapDotNet.Core.Test
case IpV4OptionType.BasicSecurity:
default:
throw new InvalidOperationException("Illegal option type " + option.OptionType);
if (typeof(IpV4OptionType).GetEnumValues<IpV4OptionType>().Contains(option.OptionType))
throw new InvalidOperationException("Invalid option type " + option.OptionType);
break;
}
}
}
......
......@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Core.Test
......@@ -45,8 +44,30 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.PartialOrderConnectionPermitted:
return "Unknown (0x09) (2 bytes)";
case (TcpOptionType)20:
return "SCPS capabilities" + (option.Length >= 4
? string.Empty
: " (with option length = " + option.Length + " bytes; should be >= 4)");
case (TcpOptionType)21:
return "Selective Negative Acknowledgement" + (option.Length == 6
? string.Empty
: " (with option length = " + option.Length + " bytes; should be 6)");
case (TcpOptionType)22:
return "SCPS record boundary" + (option.Length == 2
? string.Empty
: " (with option length = " + option.Length + " bytes; should be 2)");
case (TcpOptionType)23:
return "SCPS corruption experienced" + (option.Length == 2
? string.Empty
: " (with option length = " + option.Length + " bytes; should be 2)");
default:
throw new InvalidOperationException("Illegal option type " + option.OptionType);
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)";
}
}
......@@ -79,7 +100,9 @@ namespace PcapDotNet.Core.Test
break;
default:
throw new InvalidOperationException("Illegal option type " + option.OptionType);
if (typeof(TcpOptionType).GetEnumValues<TcpOptionType>().Contains(option.OptionType))
throw new InvalidOperationException("Invalid option type " + option.OptionType);
break;
}
}
}
......
......@@ -77,7 +77,7 @@ namespace PcapDotNet.Core.Test
[TestMethod]
public void ComparePacketsToWiresharkTest()
{
for (int i = 0; i != 100; ++i)
for (int i = 0; i != 1000; ++i)
{
// Create packets
List<Packet> packets = new List<Packet>(CreateRandomPackets(100));
......@@ -425,6 +425,7 @@ namespace PcapDotNet.Core.Test
field.Show().StartsWith("Unknown") ||
field.Show().StartsWith("Security") ||
field.Show().StartsWith("Router Alert (with option length = ") ||
field.Show().StartsWith("Stream identifier (with option length = ") ||
field.Show().Contains("with too") ||
field.Show().Contains(" bytes says option goes past end of options") ||
field.Fields().Where(value => value.Show() == "(suboption would go past end of option)").Count() != 0, field.Show());
......@@ -438,9 +439,12 @@ namespace PcapDotNet.Core.Test
continue; // Wireshark doesn't support
}
field.AssertShow(option.GetWiresharkString());
var optionShows = from f in field.Fields() select f.Show();
Assert.IsTrue(optionShows.SequenceEqual(option.GetWiresharkSubfieldStrings()));
if ((option is IpV4OptionUnknown))
continue;
var optionShows = from f in field.Fields() select f.Show();
MoreAssert.AreSequenceEqual(optionShows, option.GetWiresharkSubfieldStrings());
}
}
......@@ -603,7 +607,10 @@ namespace PcapDotNet.Core.Test
switch (field.Name())
{
case "":
field.AssertShow(option.GetWiresharkString());
if (option.OptionType == (TcpOptionType)21)
Assert.IsTrue(field.Show().StartsWith(option.GetWiresharkString()));
else
field.AssertShow(option.GetWiresharkString());
++currentOptionIndex;
break;
......@@ -633,12 +640,23 @@ namespace PcapDotNet.Core.Test
field.AssertShowDecimal(option is TcpOptionTimeStamp);
break;
case "tcp.options.scps.vector":
Assert.AreEqual((TcpOptionType)20, option.OptionType);
++currentOptionIndex;
break;
case "tcp.options.snack":
case "tcp.options.snack.offset":
case "tcp.options.snack.size":
Assert.AreEqual((TcpOptionType)21, option.OptionType);
break;
default:
throw new InvalidOperationException(field.Name());
}
var optionShows = from f in field.Fields() select f.Show();
Assert.IsTrue(optionShows.SequenceEqual(option.GetWiresharkSubfieldStrings()));
MoreAssert.AreSequenceEqual(optionShows, option.GetWiresharkSubfieldStrings());
}
}
}
......
......@@ -87,11 +87,30 @@ namespace PcapDotNet.Packets.TestUtils
return new IpV4OptionTimeOfDay(random.NextUInt());
}
public static IpV4OptionUnknown NextIpV4OptionUnknown(this Random random, int maximumOptionLength)
{
IpV4OptionType unknownOptionType;
byte unknownOptionTypeValue;
do
{
unknownOptionTypeValue = random.NextByte();
unknownOptionType = (IpV4OptionType)unknownOptionTypeValue;
} while (unknownOptionType.ToString() != unknownOptionTypeValue.ToString());
Byte[] unknownOptionData = new byte[random.Next(maximumOptionLength - IpV4OptionUnknown.OptionMinimumLength + 1)];
random.NextBytes(unknownOptionData);
return new IpV4OptionUnknown(unknownOptionType, unknownOptionData);
}
public static IpV4Option NextIpV4Option(this Random random, int maximumOptionLength)
{
if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive");
if (maximumOptionLength >= IpV4OptionUnknown.OptionMinimumLength && random.Next(100) > 90)
return random.NextIpV4OptionUnknown(maximumOptionLength);
List<IpV4OptionType> impossibleOptionTypes = new List<IpV4OptionType>();
if (maximumOptionLength < IpV4OptionBasicSecurity.OptionMinimumLength)
impossibleOptionTypes.Add(IpV4OptionType.BasicSecurity);
......@@ -231,11 +250,30 @@ namespace PcapDotNet.Packets.TestUtils
return new IpV4Options(options);
}
public static TcpOptionUnknown NextTcpOptionUnknown(this Random random, int maximumOptionLength)
{
TcpOptionType unknownOptionType;
byte unknownOptionTypeValue;
do
{
unknownOptionTypeValue = random.NextByte();
unknownOptionType = (TcpOptionType)unknownOptionTypeValue;
} while (unknownOptionType.ToString() != unknownOptionTypeValue.ToString());
Byte[] unknownOptionData = new byte[random.Next(maximumOptionLength - TcpOptionUnknown.OptionMinimumLength + 1)];
random.NextBytes(unknownOptionData);
return new TcpOptionUnknown(unknownOptionType, unknownOptionData);
}
public static TcpOption NextTcpOption(this Random random, int maximumOptionLength)
{
if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive");
if (maximumOptionLength >= TcpOptionUnknown.OptionMinimumLength && random.Next(100) > 90)
return random.NextTcpOptionUnknown(maximumOptionLength);
List<TcpOptionType> impossibleOptionTypes = new List<TcpOptionType>();
if (maximumOptionLength < TcpOptionMaximumSegmentSize.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.MaximumSegmentSize);
......
namespace PcapDotNet.Packets
{
public interface IOptionUnkownFactory<TOptionType>
{
Option CreateInstance(TOptionType optionType, byte[] buffer, ref int offset, byte valueLength);
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using PcapDotNet.Base;
namespace PcapDotNet.Packets.IpV4
{
public class IpV4OptionUnknown : IpV4OptionComplex, IOptionUnkownFactory<IpV4OptionType>, IEquatable<IpV4OptionUnknown>
{
/// <summary>
/// The minimum number of bytes this option take.
/// </summary>
public const int OptionMinimumLength = 2;
/// <summary>
/// The minimum number of bytes this option's value take.
/// </summary>
public const int OptionValueMinimumLength = OptionMinimumLength - OptionHeaderLength;
public IpV4OptionUnknown(IpV4OptionType optionType, IList<byte> data)
: base(optionType)
{
Data = new ReadOnlyCollection<byte>(data);
}
public IpV4OptionUnknown()
: this((IpV4OptionType)255, new byte[] {})
{
}
public ReadOnlyCollection<byte> Data { get; private set; }
/// <summary>
/// The number of bytes this option will take.
/// </summary>
public override int Length
{
get { return OptionMinimumLength + Data.Count; }
}
/// <summary>
/// True iff this option may appear at most once in a datagram.
/// </summary>
public override bool IsAppearsAtMostOnce
{
get { return false; }
}
public bool Equals(IpV4OptionUnknown other)
{
if (other == null)
return false;
return OptionType == other.OptionType &&
Data.SequenceEqual(other.Data);
}
public override bool Equals(IpV4Option other)
{
return Equals(other as IpV4OptionUnknown);
}
public override int GetHashCode()
{
return base.GetHashCode() ^ Data.BytesSequenceGetHashCode();
}
public Option CreateInstance(IpV4OptionType optionType, byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength)
return null;
byte[] data = new byte[valueLength];
buffer.BlockCopy(offset, data, 0, valueLength);
offset += valueLength;
return new IpV4OptionUnknown(optionType, data);
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
foreach (byte value in Data)
buffer.Write(ref offset, value);
}
}
}
\ No newline at end of file
......@@ -18,17 +18,30 @@ namespace PcapDotNet.Packets
if (length < 1)
return null;
byte optionLength = buffer[offset++];
if (length + 1 < optionLength)
if (optionLength < OptionHeaderLength || length + 1 < optionLength)
return null;
byte optionValueLength = (byte)(optionLength - OptionHeaderLength);
IOptionComplexFactory prototype;
if (!_complexOptions.TryGetValue(optionType, out prototype))
return null;
return _unkownFactoryOptionPrototype.CreateInstance(optionType, buffer, ref offset, optionValueLength);
return prototype.CreateInstance(buffer, ref offset, optionValueLength);
}
private static IOptionUnkownFactory<TOptionType> InitializeUnkownOptionPrototype()
{
var unkownOptions =
from type in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IOptionUnkownFactory<TOptionType>).IsAssignableFrom(type)
select (IOptionUnkownFactory<TOptionType>)Activator.CreateInstance(type);
if (unkownOptions.Count() != 1)
throw new InvalidOperationException("Must be only one unkown option for option type " + typeof(TOptionType));
return unkownOptions.First();
}
private static Dictionary<TOptionType, IOptionComplexFactory> InitializeComplexOptions()
{
var complexOptions =
......@@ -58,5 +71,6 @@ namespace PcapDotNet.Packets
}
private static readonly Dictionary<TOptionType, IOptionComplexFactory> _complexOptions = InitializeComplexOptions();
private static readonly IOptionUnkownFactory<TOptionType> _unkownFactoryOptionPrototype = InitializeUnkownOptionPrototype();
}
}
\ No newline at end of file
......@@ -68,6 +68,8 @@
<Compile Include="Ethernet\EthernetType.cs" />
<Compile Include="Ethernet\MacAddress.cs" />
<Compile Include="IDataLink.cs" />
<Compile Include="IOptionUnkownFactory.cs" />
<Compile Include="IpV4\IpV4OptionUnknown.cs" />
<Compile Include="Option.cs" />
<Compile Include="IOptionComplexFactory.cs" />
<Compile Include="IpV4\IIpv4OptionComplexFactory.cs" />
......@@ -122,6 +124,7 @@
<Compile Include="Transport\TcpOptionSimple.cs" />
<Compile Include="Transport\TcpOptionTimeStamp.cs" />
<Compile Include="Transport\TcpOptionType.cs" />
<Compile Include="Transport\TcpOptionUnknown.cs" />
<Compile Include="Transport\TcpOptionWindowScale.cs" />
<Compile Include="Transport\TransportDatagram.cs" />
<Compile Include="Transport\UdpDatagram.cs" />
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using PcapDotNet.Base;
namespace PcapDotNet.Packets.Transport
{
public class TcpOptionUnknown : TcpOptionComplex, IOptionUnkownFactory<TcpOptionType>, IEquatable<TcpOptionUnknown>
{
/// <summary>
/// The minimum number of bytes this option take.
/// </summary>
public const int OptionMinimumLength = 2;
/// <summary>
/// The minimum number of bytes this option's value take.
/// </summary>
public const int OptionValueMinimumLength = OptionMinimumLength - OptionHeaderLength;
public TcpOptionUnknown(TcpOptionType optionType, IList<byte> data)
: base(optionType)
{
Data = new ReadOnlyCollection<byte>(data);
}
public TcpOptionUnknown()
: this((TcpOptionType)255, new byte[] { })
{
}
public ReadOnlyCollection<byte> Data { get; private set; }
/// <summary>
/// The number of bytes this option will take.
/// </summary>
public override int Length
{
get { return OptionMinimumLength + Data.Count; }
}
/// <summary>
/// True iff this option may appear at most once in a datagram.
/// </summary>
public override bool IsAppearsAtMostOnce
{
get { return false; }
}
public bool Equals(TcpOptionUnknown other)
{
if (other == null)
return false;
return OptionType == other.OptionType &&
Data.SequenceEqual(other.Data);
}
public override bool Equals(TcpOption other)
{
return Equals(other as TcpOptionUnknown);
}
public override int GetHashCode()
{
return base.GetHashCode() ^ Data.BytesSequenceGetHashCode();
}
public Option CreateInstance(TcpOptionType optionType, byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength)
return null;
byte[] data = new byte[valueLength];
buffer.BlockCopy(offset, data, 0, valueLength);
offset += valueLength;
return new TcpOptionUnknown(optionType, data);
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
foreach (byte value in Data)
buffer.Write(ref offset, value);
}
}
}
\ No newline at end of file
......@@ -100,7 +100,7 @@ namespace PcapDotNet.TestUtils
if (!type.IsEnum)
throw new ArgumentException("T must be an Enum");
IList<T> enumValues = new List<T>(((IEnumerable<T>)Enum.GetValues(type)).Except(valuesToIgnore));
IList<T> enumValues = new List<T>(type.GetEnumValues<T>().Except(valuesToIgnore));
if (enumValues.Count == 0)
throw new ArgumentException("T is an enum with no values", "T");
......
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