Commit e295e0c9 authored by Brickner_cp's avatar Brickner_cp

TCP

parent ac8243a6
...@@ -18,9 +18,6 @@ namespace PcapDotNet.Core.Test ...@@ -18,9 +18,6 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.NoOperation: case TcpOptionType.NoOperation:
return "NOP"; return "NOP";
case TcpOptionType.MaximumSegmentSize:
return "Security";
default: default:
throw new InvalidOperationException("Illegal option type " + option.OptionType); throw new InvalidOperationException("Illegal option type " + option.OptionType);
} }
......
...@@ -616,6 +616,15 @@ namespace PcapDotNet.Core.Test ...@@ -616,6 +616,15 @@ namespace PcapDotNet.Core.Test
++currentOptionIndex; ++currentOptionIndex;
break; break;
case "tcp.options.wscale":
field.AssertShowDecimal(option is TcpOptionWindowScale);
break;
case "tcp.options.wscale_val":
field.AssertShowDecimal(((TcpOptionWindowScale)option).ScaleFactorLog);
++currentOptionIndex;
break;
default: default:
throw new InvalidOperationException(field.Name()); throw new InvalidOperationException(field.Name());
} }
......
...@@ -239,6 +239,8 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -239,6 +239,8 @@ namespace PcapDotNet.Packets.TestUtils
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);
if (maximumOptionLength < TcpOptionWindowScale.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.WindowScale);
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumData); impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumData);
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumRequest); impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumRequest);
...@@ -255,7 +257,6 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -255,7 +257,6 @@ namespace PcapDotNet.Packets.TestUtils
impossibleOptionTypes.Add(TcpOptionType.SackPermitted); impossibleOptionTypes.Add(TcpOptionType.SackPermitted);
impossibleOptionTypes.Add(TcpOptionType.TimeStamp); impossibleOptionTypes.Add(TcpOptionType.TimeStamp);
impossibleOptionTypes.Add(TcpOptionType.UserTimeout); impossibleOptionTypes.Add(TcpOptionType.UserTimeout);
impossibleOptionTypes.Add(TcpOptionType.WindowScale);
TcpOptionType optionType = random.NextEnum<TcpOptionType>(impossibleOptionTypes); TcpOptionType optionType = random.NextEnum<TcpOptionType>(impossibleOptionTypes);
switch (optionType) switch (optionType)
...@@ -269,6 +270,9 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -269,6 +270,9 @@ namespace PcapDotNet.Packets.TestUtils
case TcpOptionType.MaximumSegmentSize: case TcpOptionType.MaximumSegmentSize:
return new TcpOptionMaximumSegmentSize(random.NextUShort()); return new TcpOptionMaximumSegmentSize(random.NextUShort());
case TcpOptionType.WindowScale:
return new TcpOptionWindowScale(random.NextByte());
default: default:
throw new InvalidOperationException("optionType = " + optionType); throw new InvalidOperationException("optionType = " + optionType);
} }
......
...@@ -25,6 +25,18 @@ namespace PcapDotNet.Packets ...@@ -25,6 +25,18 @@ namespace PcapDotNet.Packets
Buffer.BlockCopy(source, sourceOffset, destination, destinationOffset, count); Buffer.BlockCopy(source, sourceOffset, destination, destinationOffset, count);
} }
public static byte ReadByte(this byte[] buffer, int offset)
{
return buffer[offset];
}
public static byte ReadByte(this byte[] buffer, ref int offset)
{
byte result = ReadByte(buffer, offset);
offset += sizeof(byte);
return result;
}
/// <summary> /// <summary>
/// Reads 2 bytes from a specific offset as a short with a given endianity. /// Reads 2 bytes from a specific offset as a short with a given endianity.
/// </summary> /// </summary>
...@@ -231,6 +243,17 @@ namespace PcapDotNet.Packets ...@@ -231,6 +243,17 @@ namespace PcapDotNet.Packets
return new IpV4OptionTimeOfDay(buffer.ReadUInt(ref offset, endianity)); return new IpV4OptionTimeOfDay(buffer.ReadUInt(ref offset, endianity));
} }
public static void Write(this byte[] buffer, int offset, byte value)
{
buffer[offset] = value;
}
public static void Write(this byte[] buffer, ref int offset, byte value)
{
Write(buffer, offset, value);
offset += sizeof(byte);
}
/// <summary> /// <summary>
/// Writes the given value to the buffer using the given endianity. /// Writes the given value to the buffer using the given endianity.
/// </summary> /// </summary>
......
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
<Compile Include="Transport\TcpOptions.cs" /> <Compile Include="Transport\TcpOptions.cs" />
<Compile Include="Transport\TcpOptionSimple.cs" /> <Compile Include="Transport\TcpOptionSimple.cs" />
<Compile Include="Transport\TcpOptionType.cs" /> <Compile Include="Transport\TcpOptionType.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" />
</ItemGroup> </ItemGroup>
......
...@@ -21,6 +21,8 @@ namespace PcapDotNet.Packets.Transport ...@@ -21,6 +21,8 @@ namespace PcapDotNet.Packets.Transport
/// </summary> /// </summary>
public const int OptionLength = 4; public const int OptionLength = 4;
public const int OptionValueLength = OptionLength - OptionHeaderLength;
public TcpOptionMaximumSegmentSize(ushort maximumSegmentSize) public TcpOptionMaximumSegmentSize(ushort maximumSegmentSize)
: base(TcpOptionType.MaximumSegmentSize) : base(TcpOptionType.MaximumSegmentSize)
{ {
...@@ -77,7 +79,7 @@ namespace PcapDotNet.Packets.Transport ...@@ -77,7 +79,7 @@ namespace PcapDotNet.Packets.Transport
/// <returns>On success - the complex option read. On failure - null.</returns> /// <returns>On success - the complex option read. On failure - null.</returns>
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength) public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{ {
if (valueLength != OptionHeaderLength) if (valueLength != OptionValueLength)
return null; return null;
ushort maximumSegmentSize = buffer.ReadUShort(ref offset, Endianity.Big); ushort maximumSegmentSize = buffer.ReadUShort(ref offset, Endianity.Big);
......
using System;
namespace PcapDotNet.Packets.Transport
{
/// <summary>
/// Window Scale Option (RFC 1323)
/// The three-byte Window Scale option may be sent in a SYN segment by a TCP.
/// It has two purposes: (1) indicate that the TCP is prepared to do both send and receive window scaling,
/// and (2) communicate a scale factor to be applied to its receive window.
/// Thus, a TCP that is prepared to scale windows should send the option, even if its own scale factor is 1.
/// The scale factor is limited to a power of two and encoded logarithmically, so it may be implemented by binary shift operations.
///
/// +---------+---------+---------+
/// | Kind=3 |Length=3 |shift.cnt|
/// +---------+---------+---------+
///
/// This option is an offer, not a promise; both sides must send Window Scale options in their SYN segments to enable window scaling in either direction.
/// If window scaling is enabled, then the TCP that sent this option will right-shift its true receive-window values by 'shift.cnt' bits
/// for transmission in SEG.WND.
/// The value 'shift.cnt' may be zero (offering to scale, while applying a scale factor of 1 to the receive window).
///
/// This option may be sent in an initial SYN segment (i.e., a segment with the SYN bit on and the ACK bit off).
/// It may also be sent in a SYN,ACK segment, but only if a Window Scale option was received in the initial SYN segment.
/// A Window Scale option in a segment without a SYN bit should be ignored.
///
/// The Window field in a SYN (i.e., a SYN or SYN,ACK) segment itself is never scaled.
/// </summary>
[OptionTypeRegistration(typeof(TcpOptionType), TcpOptionType.WindowScale)]
public class TcpOptionWindowScale: TcpOptionComplex, IOptionComplexFactory, IEquatable<TcpOptionWindowScale>
{
/// <summary>
/// The number of bytes this option take.
/// </summary>
public const int OptionLength = 3;
public const int OptionValueLength = OptionLength - OptionHeaderLength;
public TcpOptionWindowScale(byte scaleFactorLog)
: base(TcpOptionType.WindowScale)
{
ScaleFactorLog = scaleFactorLog;
}
public TcpOptionWindowScale()
: this(0)
{
}
public byte ScaleFactorLog { 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(TcpOptionWindowScale other)
{
if (other == null)
return false;
return ScaleFactorLog == other.ScaleFactorLog;
}
public override bool Equals(TcpOption other)
{
return Equals(other as TcpOptionWindowScale);
}
public override int GetHashCode()
{
return base.GetHashCode() ^
ScaleFactorLog.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 != OptionValueLength)
return null;
byte scaleFactorLog = buffer.ReadByte(ref offset);
return new TcpOptionWindowScale(scaleFactorLog);
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
buffer.Write(ref offset, ScaleFactorLog);
}
}
}
\ 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