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 @@ ...@@ -58,6 +58,7 @@
<Compile Include="MoreIEnumerable.cs" /> <Compile Include="MoreIEnumerable.cs" />
<Compile Include="MoreIList.cs" /> <Compile Include="MoreIList.cs" />
<Compile Include="MorePropertyInfo.cs" /> <Compile Include="MorePropertyInfo.cs" />
<Compile Include="MoreType.cs" />
<Compile Include="Tuple.cs" /> <Compile Include="Tuple.cs" />
<Compile Include="UInt24.cs" /> <Compile Include="UInt24.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
......
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
...@@ -59,5 +62,12 @@ namespace PcapDotNet.Core.Test ...@@ -59,5 +62,12 @@ namespace PcapDotNet.Core.Test
{ {
Assert.IsTrue(Regex.IsMatch(actualValue, expectedPattern), "Expected pattern: <" + expectedPattern + ">. Actual value: <" + actualValue + ">."); 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4; using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
...@@ -70,8 +73,15 @@ namespace PcapDotNet.Core.Test ...@@ -70,8 +73,15 @@ namespace PcapDotNet.Core.Test
return quickStartWireshark.ToString(); 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: 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 ...@@ -138,7 +148,9 @@ namespace PcapDotNet.Core.Test
case IpV4OptionType.BasicSecurity: case IpV4OptionType.BasicSecurity:
default: 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; ...@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport; using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
...@@ -45,8 +44,30 @@ namespace PcapDotNet.Core.Test ...@@ -45,8 +44,30 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.PartialOrderConnectionPermitted: case TcpOptionType.PartialOrderConnectionPermitted:
return "Unknown (0x09) (2 bytes)"; 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: 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 ...@@ -79,7 +100,9 @@ namespace PcapDotNet.Core.Test
break; break;
default: 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 ...@@ -77,7 +77,7 @@ namespace PcapDotNet.Core.Test
[TestMethod] [TestMethod]
public void ComparePacketsToWiresharkTest() public void ComparePacketsToWiresharkTest()
{ {
for (int i = 0; i != 100; ++i) for (int i = 0; i != 1000; ++i)
{ {
// Create packets // Create packets
List<Packet> packets = new List<Packet>(CreateRandomPackets(100)); List<Packet> packets = new List<Packet>(CreateRandomPackets(100));
...@@ -425,6 +425,7 @@ namespace PcapDotNet.Core.Test ...@@ -425,6 +425,7 @@ namespace PcapDotNet.Core.Test
field.Show().StartsWith("Unknown") || field.Show().StartsWith("Unknown") ||
field.Show().StartsWith("Security") || field.Show().StartsWith("Security") ||
field.Show().StartsWith("Router Alert (with option length = ") || field.Show().StartsWith("Router Alert (with option length = ") ||
field.Show().StartsWith("Stream identifier (with option length = ") ||
field.Show().Contains("with too") || field.Show().Contains("with too") ||
field.Show().Contains(" bytes says option goes past end of options") || 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()); 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 ...@@ -438,9 +439,12 @@ namespace PcapDotNet.Core.Test
continue; // Wireshark doesn't support continue; // Wireshark doesn't support
} }
field.AssertShow(option.GetWiresharkString()); 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,6 +607,9 @@ namespace PcapDotNet.Core.Test ...@@ -603,6 +607,9 @@ namespace PcapDotNet.Core.Test
switch (field.Name()) switch (field.Name())
{ {
case "": case "":
if (option.OptionType == (TcpOptionType)21)
Assert.IsTrue(field.Show().StartsWith(option.GetWiresharkString()));
else
field.AssertShow(option.GetWiresharkString()); field.AssertShow(option.GetWiresharkString());
++currentOptionIndex; ++currentOptionIndex;
break; break;
...@@ -633,12 +640,23 @@ namespace PcapDotNet.Core.Test ...@@ -633,12 +640,23 @@ namespace PcapDotNet.Core.Test
field.AssertShowDecimal(option is TcpOptionTimeStamp); field.AssertShowDecimal(option is TcpOptionTimeStamp);
break; 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: default:
throw new InvalidOperationException(field.Name()); throw new InvalidOperationException(field.Name());
} }
var optionShows = from f in field.Fields() select f.Show(); 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 ...@@ -87,11 +87,30 @@ namespace PcapDotNet.Packets.TestUtils
return new IpV4OptionTimeOfDay(random.NextUInt()); 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) public static IpV4Option NextIpV4Option(this Random random, int maximumOptionLength)
{ {
if (maximumOptionLength == 0) if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive"); 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>(); List<IpV4OptionType> impossibleOptionTypes = new List<IpV4OptionType>();
if (maximumOptionLength < IpV4OptionBasicSecurity.OptionMinimumLength) if (maximumOptionLength < IpV4OptionBasicSecurity.OptionMinimumLength)
impossibleOptionTypes.Add(IpV4OptionType.BasicSecurity); impossibleOptionTypes.Add(IpV4OptionType.BasicSecurity);
...@@ -231,11 +250,30 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -231,11 +250,30 @@ namespace PcapDotNet.Packets.TestUtils
return new IpV4Options(options); 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) public static TcpOption NextTcpOption(this Random random, int maximumOptionLength)
{ {
if (maximumOptionLength == 0) if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive"); 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>(); List<TcpOptionType> impossibleOptionTypes = new List<TcpOptionType>();
if (maximumOptionLength < TcpOptionMaximumSegmentSize.OptionLength) if (maximumOptionLength < TcpOptionMaximumSegmentSize.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.MaximumSegmentSize); 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 ...@@ -18,17 +18,30 @@ namespace PcapDotNet.Packets
if (length < 1) if (length < 1)
return null; return null;
byte optionLength = buffer[offset++]; byte optionLength = buffer[offset++];
if (length + 1 < optionLength) if (optionLength < OptionHeaderLength || length + 1 < optionLength)
return null; return null;
byte optionValueLength = (byte)(optionLength - OptionHeaderLength); byte optionValueLength = (byte)(optionLength - OptionHeaderLength);
IOptionComplexFactory prototype; IOptionComplexFactory prototype;
if (!_complexOptions.TryGetValue(optionType, out prototype)) if (!_complexOptions.TryGetValue(optionType, out prototype))
return null; return _unkownFactoryOptionPrototype.CreateInstance(optionType, buffer, ref offset, optionValueLength);
return prototype.CreateInstance(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() private static Dictionary<TOptionType, IOptionComplexFactory> InitializeComplexOptions()
{ {
var complexOptions = var complexOptions =
...@@ -58,5 +71,6 @@ namespace PcapDotNet.Packets ...@@ -58,5 +71,6 @@ namespace PcapDotNet.Packets
} }
private static readonly Dictionary<TOptionType, IOptionComplexFactory> _complexOptions = InitializeComplexOptions(); 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 @@ ...@@ -68,6 +68,8 @@
<Compile Include="Ethernet\EthernetType.cs" /> <Compile Include="Ethernet\EthernetType.cs" />
<Compile Include="Ethernet\MacAddress.cs" /> <Compile Include="Ethernet\MacAddress.cs" />
<Compile Include="IDataLink.cs" /> <Compile Include="IDataLink.cs" />
<Compile Include="IOptionUnkownFactory.cs" />
<Compile Include="IpV4\IpV4OptionUnknown.cs" />
<Compile Include="Option.cs" /> <Compile Include="Option.cs" />
<Compile Include="IOptionComplexFactory.cs" /> <Compile Include="IOptionComplexFactory.cs" />
<Compile Include="IpV4\IIpv4OptionComplexFactory.cs" /> <Compile Include="IpV4\IIpv4OptionComplexFactory.cs" />
...@@ -122,6 +124,7 @@ ...@@ -122,6 +124,7 @@
<Compile Include="Transport\TcpOptionSimple.cs" /> <Compile Include="Transport\TcpOptionSimple.cs" />
<Compile Include="Transport\TcpOptionTimeStamp.cs" /> <Compile Include="Transport\TcpOptionTimeStamp.cs" />
<Compile Include="Transport\TcpOptionType.cs" /> <Compile Include="Transport\TcpOptionType.cs" />
<Compile Include="Transport\TcpOptionUnknown.cs" />
<Compile Include="Transport\TcpOptionWindowScale.cs" /> <Compile Include="Transport\TcpOptionWindowScale.cs" />
<Compile Include="Transport\TransportDatagram.cs" /> <Compile Include="Transport\TransportDatagram.cs" />
<Compile Include="Transport\UdpDatagram.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 ...@@ -100,7 +100,7 @@ namespace PcapDotNet.TestUtils
if (!type.IsEnum) if (!type.IsEnum)
throw new ArgumentException("T must be an Enum"); 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) if (enumValues.Count == 0)
throw new ArgumentException("T is an enum with no values", "T"); 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