Commit ca31c6f5 authored by Brickner_cp's avatar Brickner_cp

IpV4OptionComplex refactoring.

parent 3d7eb78d
......@@ -31,7 +31,8 @@ namespace PcapDotNet.Packets.IpV4
/// LEVEL AUTHORITY
/// FLAGS
/// </summary>
public class IpV4OptionBasicSecurity : IpV4OptionComplex, IEquatable<IpV4OptionBasicSecurity>
[IpV4OptionTypeRegistration(IpV4OptionType.BasicSecurity)]
public class IpV4OptionBasicSecurity : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionBasicSecurity>
{
/// <summary>
/// The minimum number of bytes this option take.
......@@ -74,6 +75,26 @@ namespace PcapDotNet.Packets.IpV4
_length = length;
}
/// <summary>
/// Create the security option with only classification level.
/// </summary>
/// <param name="classificationLevel">
/// This field specifies the (U.S.) classification level at which the datagram must be protected.
/// The information in the datagram must be protected at this level.
/// </param>
public IpV4OptionBasicSecurity(IpV4OptionSecurityClassificationLevel classificationLevel)
: this(classificationLevel, IpV4OptionSecurityProtectionAuthority.None, OptionMinimumLength)
{
}
/// <summary>
/// Creates unclassified security option.
/// </summary>
public IpV4OptionBasicSecurity()
: this(IpV4OptionSecurityClassificationLevel.Unclassified)
{
}
/// <summary>
/// This field specifies the (U.S.) classification level at which the datagram must be protected.
/// The information in the datagram must be protected at this level.
......@@ -141,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4
((((byte)ClassificationLevel) << 16) | (((byte)ProtectionAuthority) << 8) | Length).GetHashCode();
}
internal static IpV4OptionBasicSecurity ReadOptionSecurity(byte[] buffer, ref int offset, byte valueLength)
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength)
return null;
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace PcapDotNet.Packets.IpV4
{
internal class IpV4OptionTypeRegistrationAttribute : Attribute
{
public IpV4OptionTypeRegistrationAttribute(IpV4OptionType optionType)
{
OptionType = optionType;
}
public IpV4OptionType OptionType { get; set; }
}
internal interface IIpv4OptionComplexFactory
{
IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength);
}
/// <summary>
/// Represents a complex IPv4 option.
/// Complex option means that it contains data and not just the type.
/// </summary>
public abstract class IpV4OptionComplex : IpV4Option
{
private static readonly Dictionary<IpV4OptionType, IIpv4OptionComplexFactory> _complexOptions;
static IpV4OptionComplex()
{
var complexOptions =
from type in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IIpv4OptionComplexFactory).IsAssignableFrom(type) &&
GetRegistrationAttribute(type) != null
select new
{
GetRegistrationAttribute(type).OptionType,
Option = (IIpv4OptionComplexFactory)Activator.CreateInstance(type)
};
_complexOptions = complexOptions.ToDictionary(option => option.OptionType, option => option.Option);
}
private static IpV4OptionTypeRegistrationAttribute GetRegistrationAttribute(Type type)
{
var registraionAttributes = type.GetCustomAttributes(typeof(IpV4OptionTypeRegistrationAttribute), false);
if (registraionAttributes.Length == 0)
return null;
return ((IpV4OptionTypeRegistrationAttribute)registraionAttributes[0]);
}
/// <summary>
/// The header length in bytes for the option (type and size).
/// </summary>
......@@ -18,36 +64,13 @@ namespace PcapDotNet.Packets.IpV4
byte optionLength = buffer[offset++];
if (length + 1 < optionLength)
return null;
byte optionValueLength = (byte)(optionLength - OptionHeaderLength);
switch (optionType)
{
case IpV4OptionType.BasicSecurity:
return IpV4OptionBasicSecurity.ReadOptionSecurity(buffer, ref offset, optionValueLength);
case IpV4OptionType.LooseSourceRouting:
return IpV4OptionLooseSourceRouting.ReadOptionLooseSourceRouting(buffer, ref offset, optionValueLength);
case IpV4OptionType.StrictSourceRouting:
return IpV4OptionStrictSourceRouting.ReadOptionStrictSourceRouting(buffer, ref offset, optionValueLength);
case IpV4OptionType.RecordRoute:
return IpV4OptionRecordRoute.ReadOptionRecordRoute(buffer, ref offset, optionValueLength);
case IpV4OptionType.StreamIdentifier:
return IpV4OptionStreamIdentifier.ReadOptionStreamIdentifier(buffer, ref offset, optionValueLength);
case IpV4OptionType.InternetTimestamp:
return IpV4OptionTimestamp.ReadOptionTimestamp(buffer, ref offset, optionValueLength);
case IpV4OptionType.TraceRoute:
return IpV4OptionTraceRoute.ReadOptionTraceRoute(buffer, ref offset, optionValueLength);
default:
return null;
IIpv4OptionComplexFactory prototype;
if (!_complexOptions.TryGetValue(optionType, out prototype))
return null;
}
return prototype.CreateInstance(buffer, ref offset, optionValueLength);
}
internal override void Write(byte[] buffer, ref int offset)
......
......@@ -42,7 +42,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// </summary>
public class IpV4OptionLooseSourceRouting : IpV4OptionRoute
[IpV4OptionTypeRegistration(IpV4OptionType.LooseSourceRouting)]
public class IpV4OptionLooseSourceRouting : IpV4OptionRoute, IIpv4OptionComplexFactory
{
/// <summary>
/// Constructs the option from the given values.
......@@ -54,7 +55,15 @@ namespace PcapDotNet.Packets.IpV4
{
}
internal static IpV4OptionLooseSourceRouting ReadOptionLooseSourceRouting(byte[] buffer, ref int offset, byte valueLength)
/// <summary>
/// Empty loose source routing.
/// </summary>
public IpV4OptionLooseSourceRouting()
: this(new IpV4Address[]{}, 0)
{
}
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
IpV4Address[] addresses;
byte pointedAddressIndex;
......
......@@ -39,7 +39,8 @@ namespace PcapDotNet.Packets.IpV4
/// Not copied on fragmentation, goes in first fragment only.
/// Appears at most once in a datagram.
/// </summary>
public class IpV4OptionRecordRoute : IpV4OptionRoute
[IpV4OptionTypeRegistration(IpV4OptionType.RecordRoute)]
public class IpV4OptionRecordRoute : IpV4OptionRoute, IIpv4OptionComplexFactory
{
/// <summary>
/// Constructs the option from the given values.
......@@ -61,7 +62,15 @@ namespace PcapDotNet.Packets.IpV4
{
}
internal static IpV4OptionRecordRoute ReadOptionRecordRoute(byte[] buffer, ref int offset, byte valueLength)
/// <summary>
/// Constructs an empty record route option.
/// </summary>
public IpV4OptionRecordRoute()
: this(0)
{
}
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
IpV4Address[] addresses;
byte pointedAddressIndex;
......
......@@ -14,7 +14,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// </summary>
public class IpV4OptionStreamIdentifier : IpV4OptionComplex, IEquatable<IpV4OptionStreamIdentifier>
[IpV4OptionTypeRegistration(IpV4OptionType.StreamIdentifier)]
public class IpV4OptionStreamIdentifier : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionStreamIdentifier>
{
/// <summary>
/// The number of bytes this option take.
......@@ -87,7 +88,15 @@ namespace PcapDotNet.Packets.IpV4
Identifier.GetHashCode();
}
internal static IpV4OptionStreamIdentifier ReadOptionStreamIdentifier(byte[] buffer, ref int offset, byte valueLength)
/// <summary>
/// Creates a 0 stream identifier
/// </summary>
public IpV4OptionStreamIdentifier()
: this(0)
{
}
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionHeaderLength)
return null;
......
......@@ -43,7 +43,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// </summary>
public class IpV4OptionStrictSourceRouting : IpV4OptionRoute
[IpV4OptionTypeRegistration(IpV4OptionType.StrictSourceRouting)]
public class IpV4OptionStrictSourceRouting : IpV4OptionRoute, IIpv4OptionComplexFactory
{
/// <summary>
/// Create the option according to the given values.
......@@ -53,7 +54,15 @@ namespace PcapDotNet.Packets.IpV4
{
}
internal static IpV4OptionStrictSourceRouting ReadOptionStrictSourceRouting(byte[] buffer, ref int offset, byte valueLength)
/// <summary>
/// Creates an empty strict source routing option.
/// </summary>
public IpV4OptionStrictSourceRouting()
: this(new List<IpV4Address>(), 0)
{
}
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
IpV4Address[] addresses;
byte pointedAddressIndex;
......
......@@ -52,6 +52,41 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
public abstract class IpV4OptionTimestamp : IpV4OptionComplex, IEquatable<IpV4OptionTimestamp>
{
[IpV4OptionTypeRegistration(IpV4OptionType.InternetTimestamp)]
internal class IpV4OptionTimestampFactory : IIpv4OptionComplexFactory
{
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength || valueLength % 4 != 2)
return null;
byte pointer = buffer[offset++];
if (pointer % 4 != 1 || pointer < 5)
return null;
byte pointedIndex = (byte)(pointer / 4 - 1);
byte overflow = buffer[offset++];
IpV4OptionTimestampType timestampType = (IpV4OptionTimestampType)(overflow & 0x0F);
overflow >>= 4;
int numValues = valueLength / 4;
switch (timestampType)
{
case IpV4OptionTimestampType.TimestampOnly:
return IpV4OptionTimestampOnly.Read(overflow, pointedIndex, buffer, ref offset, numValues);
case IpV4OptionTimestampType.AddressAndTimestamp:
case IpV4OptionTimestampType.AddressPrespecified:
return IpV4OptionTimestampAndAddress.Read(timestampType, overflow, pointedIndex, buffer, ref offset, numValues);
default:
return null;
}
}
}
/// <summary>
/// The minimum length in bytes for the option (type, length, pointer, overflow and flags).
/// </summary>
......@@ -154,37 +189,6 @@ namespace PcapDotNet.Packets.IpV4
PointedIndex.GetHashCode();
}
internal static IpV4OptionTimestamp ReadOptionTimestamp(byte[] buffer, ref int offset, int valueLength)
{
if (valueLength < OptionValueMinimumLength || valueLength % 4 != 2)
return null;
byte pointer = buffer[offset++];
if (pointer % 4 != 1 || pointer < 5)
return null;
byte pointedIndex = (byte)(pointer / 4 - 1);
byte overflow = buffer[offset++];
IpV4OptionTimestampType timestampType = (IpV4OptionTimestampType)(overflow & 0x0F);
overflow >>= 4;
int numValues = valueLength / 4;
switch (timestampType)
{
case IpV4OptionTimestampType.TimestampOnly:
return IpV4OptionTimestampOnly.Read(overflow, pointedIndex, buffer, ref offset, numValues);
case IpV4OptionTimestampType.AddressAndTimestamp:
case IpV4OptionTimestampType.AddressPrespecified:
return IpV4OptionTimestampAndAddress.Read(timestampType, overflow, pointedIndex, buffer, ref offset, numValues);
default:
return null;
}
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
......
......@@ -24,7 +24,8 @@ namespace PcapDotNet.Packets.IpV4
/// C (class): 2 (Debugging & Measurement)
/// Number: 18 (F+C+Number = 82)
/// </summary>
public class IpV4OptionTraceRoute : IpV4OptionComplex, IEquatable<IpV4OptionTraceRoute>
[IpV4OptionTypeRegistration(IpV4OptionType.TraceRoute)]
public class IpV4OptionTraceRoute : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionTraceRoute>
{
/// <summary>
/// The number of bytes this option take.
......@@ -66,6 +67,14 @@ namespace PcapDotNet.Packets.IpV4
_originatorIpAddress = originatorIpAddress;
}
/// <summary>
/// Creates empty trace route option.
/// </summary>
public IpV4OptionTraceRoute()
: this(0, 0, 0, IpV4Address.Zero)
{
}
/// <summary>
/// An arbitrary number used by the originator of the Outbound Packet to identify the ICMP Traceroute messages.
/// It is NOT related to the ID number in the IP header.
......@@ -157,7 +166,7 @@ namespace PcapDotNet.Packets.IpV4
}
internal static IpV4OptionTraceRoute ReadOptionTraceRoute(byte[] buffer, ref int offset, byte valueLength)
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionValueLength)
return null;
......
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