Commit ca31c6f5 authored by Brickner_cp's avatar Brickner_cp

IpV4OptionComplex refactoring.

parent 3d7eb78d
...@@ -31,7 +31,8 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -31,7 +31,8 @@ namespace PcapDotNet.Packets.IpV4
/// LEVEL AUTHORITY /// LEVEL AUTHORITY
/// FLAGS /// FLAGS
/// </summary> /// </summary>
public class IpV4OptionBasicSecurity : IpV4OptionComplex, IEquatable<IpV4OptionBasicSecurity> [IpV4OptionTypeRegistration(IpV4OptionType.BasicSecurity)]
public class IpV4OptionBasicSecurity : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionBasicSecurity>
{ {
/// <summary> /// <summary>
/// The minimum number of bytes this option take. /// The minimum number of bytes this option take.
...@@ -74,6 +75,26 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -74,6 +75,26 @@ namespace PcapDotNet.Packets.IpV4
_length = length; _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> /// <summary>
/// This field specifies the (U.S.) classification level at which the datagram must be protected. /// 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. /// The information in the datagram must be protected at this level.
...@@ -141,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -141,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4
((((byte)ClassificationLevel) << 16) | (((byte)ProtectionAuthority) << 8) | Length).GetHashCode(); ((((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) if (valueLength < OptionValueMinimumLength)
return null; return null;
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace PcapDotNet.Packets.IpV4 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> /// <summary>
/// Represents a complex IPv4 option. /// Represents a complex IPv4 option.
/// Complex option means that it contains data and not just the type. /// Complex option means that it contains data and not just the type.
/// </summary> /// </summary>
public abstract class IpV4OptionComplex : IpV4Option 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> /// <summary>
/// The header length in bytes for the option (type and size). /// The header length in bytes for the option (type and size).
/// </summary> /// </summary>
...@@ -18,36 +64,13 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -18,36 +64,13 @@ namespace PcapDotNet.Packets.IpV4
byte optionLength = buffer[offset++]; byte optionLength = buffer[offset++];
if (length + 1 < optionLength) if (length + 1 < optionLength)
return null; return null;
byte optionValueLength = (byte)(optionLength - OptionHeaderLength); byte optionValueLength = (byte)(optionLength - OptionHeaderLength);
switch (optionType) IIpv4OptionComplexFactory prototype;
{ if (!_complexOptions.TryGetValue(optionType, out prototype))
case IpV4OptionType.BasicSecurity: return null;
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;
} return prototype.CreateInstance(buffer, ref offset, optionValueLength);
} }
internal override void Write(byte[] buffer, ref int offset) internal override void Write(byte[] buffer, ref int offset)
......
...@@ -42,7 +42,8 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -42,7 +42,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation. /// Must be copied on fragmentation.
/// Appears at most once in a datagram. /// Appears at most once in a datagram.
/// </summary> /// </summary>
public class IpV4OptionLooseSourceRouting : IpV4OptionRoute [IpV4OptionTypeRegistration(IpV4OptionType.LooseSourceRouting)]
public class IpV4OptionLooseSourceRouting : IpV4OptionRoute, IIpv4OptionComplexFactory
{ {
/// <summary> /// <summary>
/// Constructs the option from the given values. /// Constructs the option from the given values.
...@@ -54,7 +55,15 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -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; IpV4Address[] addresses;
byte pointedAddressIndex; byte pointedAddressIndex;
......
...@@ -39,7 +39,8 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -39,7 +39,8 @@ namespace PcapDotNet.Packets.IpV4
/// Not copied on fragmentation, goes in first fragment only. /// Not copied on fragmentation, goes in first fragment only.
/// Appears at most once in a datagram. /// Appears at most once in a datagram.
/// </summary> /// </summary>
public class IpV4OptionRecordRoute : IpV4OptionRoute [IpV4OptionTypeRegistration(IpV4OptionType.RecordRoute)]
public class IpV4OptionRecordRoute : IpV4OptionRoute, IIpv4OptionComplexFactory
{ {
/// <summary> /// <summary>
/// Constructs the option from the given values. /// Constructs the option from the given values.
...@@ -61,7 +62,15 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -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; IpV4Address[] addresses;
byte pointedAddressIndex; byte pointedAddressIndex;
......
...@@ -14,7 +14,8 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -14,7 +14,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation. /// Must be copied on fragmentation.
/// Appears at most once in a datagram. /// Appears at most once in a datagram.
/// </summary> /// </summary>
public class IpV4OptionStreamIdentifier : IpV4OptionComplex, IEquatable<IpV4OptionStreamIdentifier> [IpV4OptionTypeRegistration(IpV4OptionType.StreamIdentifier)]
public class IpV4OptionStreamIdentifier : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionStreamIdentifier>
{ {
/// <summary> /// <summary>
/// The number of bytes this option take. /// The number of bytes this option take.
...@@ -87,7 +88,15 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -87,7 +88,15 @@ namespace PcapDotNet.Packets.IpV4
Identifier.GetHashCode(); 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) if (valueLength != OptionHeaderLength)
return null; return null;
......
...@@ -43,7 +43,8 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -43,7 +43,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation. /// Must be copied on fragmentation.
/// Appears at most once in a datagram. /// Appears at most once in a datagram.
/// </summary> /// </summary>
public class IpV4OptionStrictSourceRouting : IpV4OptionRoute [IpV4OptionTypeRegistration(IpV4OptionType.StrictSourceRouting)]
public class IpV4OptionStrictSourceRouting : IpV4OptionRoute, IIpv4OptionComplexFactory
{ {
/// <summary> /// <summary>
/// Create the option according to the given values. /// Create the option according to the given values.
...@@ -53,7 +54,15 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -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; IpV4Address[] addresses;
byte pointedAddressIndex; byte pointedAddressIndex;
......
...@@ -52,6 +52,41 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -52,6 +52,41 @@ namespace PcapDotNet.Packets.IpV4
/// </summary> /// </summary>
public abstract class IpV4OptionTimestamp : IpV4OptionComplex, IEquatable<IpV4OptionTimestamp> 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> /// <summary>
/// The minimum length in bytes for the option (type, length, pointer, overflow and flags). /// The minimum length in bytes for the option (type, length, pointer, overflow and flags).
/// </summary> /// </summary>
...@@ -154,37 +189,6 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -154,37 +189,6 @@ namespace PcapDotNet.Packets.IpV4
PointedIndex.GetHashCode(); 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) internal override void Write(byte[] buffer, ref int offset)
{ {
base.Write(buffer, ref offset); base.Write(buffer, ref offset);
......
...@@ -24,7 +24,8 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -24,7 +24,8 @@ namespace PcapDotNet.Packets.IpV4
/// C (class): 2 (Debugging & Measurement) /// C (class): 2 (Debugging & Measurement)
/// Number: 18 (F+C+Number = 82) /// Number: 18 (F+C+Number = 82)
/// </summary> /// </summary>
public class IpV4OptionTraceRoute : IpV4OptionComplex, IEquatable<IpV4OptionTraceRoute> [IpV4OptionTypeRegistration(IpV4OptionType.TraceRoute)]
public class IpV4OptionTraceRoute : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionTraceRoute>
{ {
/// <summary> /// <summary>
/// The number of bytes this option take. /// The number of bytes this option take.
...@@ -66,6 +67,14 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -66,6 +67,14 @@ namespace PcapDotNet.Packets.IpV4
_originatorIpAddress = originatorIpAddress; _originatorIpAddress = originatorIpAddress;
} }
/// <summary>
/// Creates empty trace route option.
/// </summary>
public IpV4OptionTraceRoute()
: this(0, 0, 0, IpV4Address.Zero)
{
}
/// <summary> /// <summary>
/// An arbitrary number used by the originator of the Outbound Packet to identify the ICMP Traceroute messages. /// 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. /// It is NOT related to the ID number in the IP header.
...@@ -157,7 +166,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -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) if (valueLength != OptionValueLength)
return null; 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