Commit 1830bbda authored by Brickner_cp's avatar Brickner_cp

TCP

parent 4c59dc64
......@@ -4,15 +4,15 @@ namespace PcapDotNet.Packets.IpV4
/// This interface is used to create all complex options.
/// Every complex option should implement such a factory to create itself from a buffer.
/// </summary>
internal interface IIpv4OptionComplexFactory
{
/// <summary>
/// Tries to read the option from a buffer starting from the option value (after the type and length).
/// </summary>
/// <param name="buffer">The buffer to read the option from.</param>
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength);
}
// internal interface IIpv4OptionComplexFactory
// {
// /// <summary>
// /// Tries to read the option from a buffer starting from the option value (after the type and length).
// /// </summary>
// /// <param name="buffer">The buffer to read the option from.</param>
// /// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
// /// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
// /// <returns>On success - the complex option read. On failure - null.</returns>
// IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength);
// }
}
\ No newline at end of file
......@@ -94,7 +94,7 @@ namespace PcapDotNet.Packets.IpV4
return Nop;
default:
return IpV4OptionComplex.ReadOptionComplex(optionType, buffer, ref offset, offsetEnd - offset);
return OptionComplexFactory<IpV4OptionType>.Read(optionType, buffer, ref offset, offsetEnd - offset);
}
}
......
......@@ -31,8 +31,8 @@ namespace PcapDotNet.Packets.IpV4
/// LEVEL AUTHORITY
/// FLAGS
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.BasicSecurity)]
public class IpV4OptionBasicSecurity : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionBasicSecurity>
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.BasicSecurity)]
public class IpV4OptionBasicSecurity : IpV4OptionComplex, IOptionComplexFactory, IEquatable<IpV4OptionBasicSecurity>
{
/// <summary>
/// The minimum number of bytes this option take.
......@@ -169,7 +169,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength)
return null;
......
......@@ -16,32 +16,6 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
public const int OptionHeaderLength = 2;
internal sealed class IpV4OptionTypeRegistrationAttribute : Attribute
{
public IpV4OptionTypeRegistrationAttribute(IpV4OptionType optionType)
{
OptionType = optionType;
}
public IpV4OptionType OptionType { get; set; }
}
internal static IpV4OptionComplex ReadOptionComplex(IpV4OptionType optionType, byte[] buffer, ref int offset, int length)
{
if (length < 1)
return null;
byte optionLength = buffer[offset++];
if (length + 1 < optionLength)
return null;
byte optionValueLength = (byte)(optionLength - OptionHeaderLength);
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)
{
base.Write(buffer, ref offset);
......@@ -55,31 +29,5 @@ namespace PcapDotNet.Packets.IpV4
: base(type)
{
}
private static Dictionary<IpV4OptionType, IIpv4OptionComplexFactory> InitializeComplexOptions()
{
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)
};
return 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]);
}
private static readonly Dictionary<IpV4OptionType, IIpv4OptionComplexFactory> _complexOptions = InitializeComplexOptions();
}
}
\ No newline at end of file
......@@ -42,8 +42,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.LooseSourceRouting)]
public class IpV4OptionLooseSourceRouting : IpV4OptionRoute, IIpv4OptionComplexFactory
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.LooseSourceRouting)]
public class IpV4OptionLooseSourceRouting : IpV4OptionRoute, IOptionComplexFactory
{
/// <summary>
/// Constructs the option from the given values.
......@@ -70,7 +70,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
IpV4Address[] addresses;
byte pointedAddressIndex;
......
......@@ -15,8 +15,8 @@ namespace PcapDotNet.Packets.IpV4
/// | QS Nonce | R |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.QuickStart)]
public class IpV4OptionQuickStart : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionQuickStart>
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.QuickStart)]
public class IpV4OptionQuickStart : IpV4OptionComplex, IOptionComplexFactory, IEquatable<IpV4OptionQuickStart>
{
/// <summary>
/// The number of bytes this option take.
......@@ -220,7 +220,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionValueLength)
return null;
......
......@@ -39,8 +39,8 @@ namespace PcapDotNet.Packets.IpV4
/// Not copied on fragmentation, goes in first fragment only.
/// Appears at most once in a datagram.
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.RecordRoute)]
public class IpV4OptionRecordRoute : IpV4OptionRoute, IIpv4OptionComplexFactory
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.RecordRoute)]
public class IpV4OptionRecordRoute : IpV4OptionRoute, IOptionComplexFactory
{
/// <summary>
/// Constructs the option from the given values.
......@@ -77,7 +77,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
IpV4Address[] addresses;
byte pointedAddressIndex;
......
......@@ -23,8 +23,8 @@ namespace PcapDotNet.Packets.IpV4
/// |10010100|00000100| 2 octet value |
/// +--------+--------+--------+--------+
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.RouterAlert)]
public class IpV4OptionRouterAlert : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionRouterAlert>
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.RouterAlert)]
public class IpV4OptionRouterAlert : IpV4OptionComplex, IOptionComplexFactory, IEquatable<IpV4OptionRouterAlert>
{
/// <summary>
/// The number of bytes this option take.
......@@ -111,7 +111,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionHeaderLength)
return null;
......
......@@ -14,19 +14,14 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.StreamIdentifier)]
public class IpV4OptionStreamIdentifier : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionStreamIdentifier>
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.StreamIdentifier)]
public class IpV4OptionStreamIdentifier : IpV4OptionComplex, IOptionComplexFactory, IEquatable<IpV4OptionStreamIdentifier>
{
/// <summary>
/// The number of bytes this option take.
/// </summary>
public const int OptionLength = 4;
/// <summary>
/// The number of bytes this option's value take.
/// </summary>
public const int OptionValueLength = OptionLength - OptionHeaderLength;
/// <summary>
/// Create the option according to the given identifier.
/// </summary>
......@@ -102,7 +97,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionHeaderLength)
return null;
......
......@@ -43,8 +43,8 @@ namespace PcapDotNet.Packets.IpV4
/// Must be copied on fragmentation.
/// Appears at most once in a datagram.
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.StrictSourceRouting)]
public class IpV4OptionStrictSourceRouting : IpV4OptionRoute, IIpv4OptionComplexFactory
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.StrictSourceRouting)]
public class IpV4OptionStrictSourceRouting : IpV4OptionRoute, IOptionComplexFactory
{
/// <summary>
/// Create the option according to the given values.
......@@ -69,7 +69,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
IpV4Address[] addresses;
byte pointedAddressIndex;
......
......@@ -52,10 +52,10 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
public abstract class IpV4OptionTimestamp : IpV4OptionComplex, IEquatable<IpV4OptionTimestamp>
{
[IpV4OptionTypeRegistration(IpV4OptionType.InternetTimestamp)]
internal class IpV4OptionTimestampFactory : IIpv4OptionComplexFactory
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.InternetTimestamp)]
internal class IpV4OptionTimestampFactory : IOptionComplexFactory
{
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength || valueLength % 4 != 2)
return null;
......
......@@ -24,8 +24,8 @@ namespace PcapDotNet.Packets.IpV4
/// C (class): 2 (Debugging and Measurement)
/// Number: 18 (F+C+Number = 82)
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.TraceRoute)]
public class IpV4OptionTraceRoute : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionTraceRoute>
[OptionTypeRegistration(typeof(IpV4OptionType), IpV4OptionType.TraceRoute)]
public class IpV4OptionTraceRoute : IpV4OptionComplex, IOptionComplexFactory, IEquatable<IpV4OptionTraceRoute>
{
/// <summary>
/// The number of bytes this option take.
......@@ -173,7 +173,7 @@ namespace PcapDotNet.Packets.IpV4
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionValueLength)
return null;
......
using System;
namespace PcapDotNet.Packets
{
internal sealed class OptionTypeRegistrationAttribute : Attribute
{
public OptionTypeRegistrationAttribute(Type optionTypeType, object optionType)
{
OptionTypeType = optionTypeType;
OptionType = optionType;
}
public object OptionType { get; private set; }
public Type OptionTypeType { get; private set; }
}
}
\ No newline at end of file
......@@ -109,8 +109,11 @@
<Compile Include="Transport\TcpDatagram.cs" />
<Compile Include="Transport\TcpFlags.cs" />
<Compile Include="Transport\TcpOption.cs" />
<Compile Include="Transport\TcpOptionComplex.cs" />
<Compile Include="Transport\TcpOptionMaximumSegmentSize.cs" />
<Compile Include="Transport\TcpOptions.cs" />
<Compile Include="Transport\TcpOptionSimple.cs" />
<Compile Include="Transport\TcpOptionType.cs" />
<Compile Include="Transport\TransportDatagram.cs" />
<Compile Include="Transport\UdpDatagram.cs" />
</ItemGroup>
......
......@@ -2,13 +2,7 @@ using System;
namespace PcapDotNet.Packets.Transport
{
public enum TcpOptionType : byte
{
EndOfOptionList = 0,
NoOperation = 1
}
public abstract class TcpOption : Option
public abstract class TcpOption : Option, IEquatable<TcpOption>
{
public static TcpOption End
{
......@@ -25,12 +19,30 @@ namespace PcapDotNet.Packets.Transport
OptionType = optionType;
}
public TcpOptionType OptionType { get; private set; }
public override bool Equivalent(Option other)
{
return OptionType == ((TcpOption)other).OptionType;
}
public TcpOptionType OptionType { get; private set; }
/// <summary>
/// Checks if the two options are exactly the same - including type and value.
/// </summary>
public virtual bool Equals(TcpOption other)
{
if (other == null)
return false;
return Equivalent(other);
}
/// <summary>
/// Checks if the two options are exactly the same - including type and value.
/// </summary>
public override bool Equals(object obj)
{
return Equals(obj as TcpOption);
}
internal override Option Read(byte[] buffer, ref int offset, int length)
{
......
namespace PcapDotNet.Packets.Transport
{
public abstract class TcpOptionComplex : TcpOption
{
public const int OptionHeaderLength = 2;
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
buffer[offset++] = (byte)Length;
}
protected TcpOptionComplex(TcpOptionType type)
: base(type)
{
}
}
}
\ No newline at end of file
using System;
namespace PcapDotNet.Packets.Transport
{
/// <summary>
/// Maximum Segment Size (RFC 793)
/// +--------+--------+---------+--------+
/// |00000010|00000100| max seg size |
/// +--------+--------+---------+--------+
/// Kind=2 Length=4
///
/// If this option is present, then it communicates the maximum receive segment size at the TCP which sends this segment.
/// This field must only be sent in the initial connection request (i.e., in segments with the SYN control bit set).
/// If this option is not used, any segment size is allowed.
/// </summary>
[OptionTypeRegistration(typeof(TcpOptionType), TcpOptionType.MaximumSegmentSize)]
public class TcpOptionMaximumSegmentSize : TcpOptionComplex, IOptionComplexFactory, IEquatable<TcpOptionMaximumSegmentSize>
{
/// <summary>
/// The number of bytes this option take.
/// </summary>
public const int OptionLength = 4;
public TcpOptionMaximumSegmentSize(ushort maximumSegmentSize)
: base(TcpOptionType.MaximumSegmentSize)
{
MaximumSegmentSize = maximumSegmentSize;
}
public TcpOptionMaximumSegmentSize()
: this(0)
{
}
public ushort MaximumSegmentSize { get; private set; }
/// <summary>
/// The number of bytes this option will take.
/// </summary>
public override int Length
{
get { return OptionLength; }
}
/// <summary>
/// True iff this option may appear at most once in a datagram.
/// </summary>
public override bool IsAppearsAtMostOnce
{
get { return true; }
}
public bool Equals(TcpOptionMaximumSegmentSize other)
{
if (other == null)
return false;
return MaximumSegmentSize == other.MaximumSegmentSize;
}
public override bool Equals(TcpOption other)
{
return Equals(other as TcpOptionMaximumSegmentSize);
}
public override int GetHashCode()
{
return base.GetHashCode() ^
MaximumSegmentSize.GetHashCode();
}
/// <summary>
/// Tries to read the option from a buffer starting from the option value (after the type and length).
/// </summary>
/// <param name="buffer">The buffer to read the option from.</param>
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionHeaderLength)
return null;
ushort maximumSegmentSize = buffer.ReadUShort(ref offset, Endianity.Big);
return new TcpOptionMaximumSegmentSize(maximumSegmentSize);
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
buffer.Write(ref offset, MaximumSegmentSize, Endianity.Big);
}
}
}
\ No newline at end of file
namespace PcapDotNet.Packets.Transport
{
public enum TcpOptionType : byte
{
EndOfOptionList = 0,
NoOperation = 1,
MaximumSegmentSize = 2,
WindowScale = 3,
SackPermitted = 4,
Sack = 5,
Echo = 6,
EchoReply = 7,
TimeStamp = 8,
PartialOrderConnectionPermitted = 9,
PartialOrderServiceProfile = 10,
Cc = 11,
CcNew = 12,
CcEcho = 13,
AlternateChecksumRequest = 14,
AlternateChecksumData = 15,
Md5Signature = 19,
QuickStartResponse = 27,
UserTimeout = 28,
}
}
\ No newline at end of file
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