Commit 093d3d08 authored by Brickner_cp's avatar Brickner_cp

TCP

parent e295e0c9
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4; using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport; using PcapDotNet.Packets.Transport;
...@@ -18,6 +20,15 @@ namespace PcapDotNet.Core.Test ...@@ -18,6 +20,15 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.NoOperation: case TcpOptionType.NoOperation:
return "NOP"; return "NOP";
case TcpOptionType.SelectiveAcknowledgmentPermitted:
return "SACK permitted";
case TcpOptionType.SelectiveAcknowledgment:
IEnumerable<TcpOptionSelectiveAcknowledgmentBlock> blocks = ((TcpOptionSelectiveAcknowledgment)option).Blocks;
return "SACK:" + (blocks.Count() == 0
? string.Empty
: ((TcpOptionSelectiveAcknowledgment)option).Blocks.SequenceToString(" ", " "));
default: default:
throw new InvalidOperationException("Illegal option type " + option.OptionType); throw new InvalidOperationException("Illegal option type " + option.OptionType);
} }
...@@ -30,10 +41,20 @@ namespace PcapDotNet.Core.Test ...@@ -30,10 +41,20 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.EndOfOptionList: case TcpOptionType.EndOfOptionList:
case TcpOptionType.NoOperation: case TcpOptionType.NoOperation:
case TcpOptionType.MaximumSegmentSize: case TcpOptionType.MaximumSegmentSize:
case TcpOptionType.WindowScale:
case TcpOptionType.SelectiveAcknowledgmentPermitted:
break; break;
case TcpOptionType.WindowScale: case TcpOptionType.SelectiveAcknowledgment:
yield return ""; var blocks = ((TcpOptionSelectiveAcknowledgment)option).Blocks;
if (blocks.Count() == 0)
break;
yield return "1";
foreach (TcpOptionSelectiveAcknowledgmentBlock block in blocks)
{
yield return block.LeftEdge.ToString();
yield return block.RightEdge.ToString();
}
break; break;
default: default:
......
...@@ -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 != 10; ++i) for (int i = 0; i != 100; ++i)
{ {
// Create packets // Create packets
List<Packet> packets = new List<Packet>(CreateRandomPackets(100)); List<Packet> packets = new List<Packet>(CreateRandomPackets(100));
...@@ -629,9 +629,8 @@ namespace PcapDotNet.Core.Test ...@@ -629,9 +629,8 @@ namespace PcapDotNet.Core.Test
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()));
// Assert.IsTrue(optionShows.SequenceEqual(option.GetWiresharkSubfieldStrings()));
} }
} }
} }
......
...@@ -241,6 +241,10 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -241,6 +241,10 @@ namespace PcapDotNet.Packets.TestUtils
impossibleOptionTypes.Add(TcpOptionType.MaximumSegmentSize); impossibleOptionTypes.Add(TcpOptionType.MaximumSegmentSize);
if (maximumOptionLength < TcpOptionWindowScale.OptionLength) if (maximumOptionLength < TcpOptionWindowScale.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.WindowScale); impossibleOptionTypes.Add(TcpOptionType.WindowScale);
if (maximumOptionLength < TcpOptionSelectiveAcknowledgment.OptionMinimumLength)
impossibleOptionTypes.Add(TcpOptionType.SelectiveAcknowledgment);
if (maximumOptionLength < TcpOptionSelectiveAcknowledgmentPermitted.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.SelectiveAcknowledgmentPermitted);
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumData); impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumData);
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumRequest); impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumRequest);
...@@ -253,8 +257,6 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -253,8 +257,6 @@ namespace PcapDotNet.Packets.TestUtils
impossibleOptionTypes.Add(TcpOptionType.PartialOrderConnectionPermitted); impossibleOptionTypes.Add(TcpOptionType.PartialOrderConnectionPermitted);
impossibleOptionTypes.Add(TcpOptionType.PartialOrderServiceProfile); impossibleOptionTypes.Add(TcpOptionType.PartialOrderServiceProfile);
impossibleOptionTypes.Add(TcpOptionType.QuickStartResponse); impossibleOptionTypes.Add(TcpOptionType.QuickStartResponse);
impossibleOptionTypes.Add(TcpOptionType.Sack);
impossibleOptionTypes.Add(TcpOptionType.SackPermitted);
impossibleOptionTypes.Add(TcpOptionType.TimeStamp); impossibleOptionTypes.Add(TcpOptionType.TimeStamp);
impossibleOptionTypes.Add(TcpOptionType.UserTimeout); impossibleOptionTypes.Add(TcpOptionType.UserTimeout);
...@@ -273,6 +275,16 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -273,6 +275,16 @@ namespace PcapDotNet.Packets.TestUtils
case TcpOptionType.WindowScale: case TcpOptionType.WindowScale:
return new TcpOptionWindowScale(random.NextByte()); return new TcpOptionWindowScale(random.NextByte());
case TcpOptionType.SelectiveAcknowledgment:
int numBlocks = random.Next((maximumOptionLength - TcpOptionSelectiveAcknowledgment.OptionMinimumLength) / 8 + 1);
TcpOptionSelectiveAcknowledgmentBlock[] blocks = new TcpOptionSelectiveAcknowledgmentBlock[numBlocks];
for (int i = 0; i != numBlocks; ++i)
blocks[i] = new TcpOptionSelectiveAcknowledgmentBlock(random.NextUInt(), random.NextUInt());
return new TcpOptionSelectiveAcknowledgment(blocks);
case TcpOptionType.SelectiveAcknowledgmentPermitted:
return new TcpOptionSelectiveAcknowledgmentPermitted();
default: default:
throw new InvalidOperationException("optionType = " + optionType); throw new InvalidOperationException("optionType = " + optionType);
} }
......
...@@ -112,6 +112,9 @@ ...@@ -112,6 +112,9 @@
<Compile Include="Transport\TcpOptionComplex.cs" /> <Compile Include="Transport\TcpOptionComplex.cs" />
<Compile Include="Transport\TcpOptionMaximumSegmentSize.cs" /> <Compile Include="Transport\TcpOptionMaximumSegmentSize.cs" />
<Compile Include="Transport\TcpOptions.cs" /> <Compile Include="Transport\TcpOptions.cs" />
<Compile Include="Transport\TcpOptionSelectiveAcknowledgment.cs" />
<Compile Include="Transport\TcpOptionSelectiveAcknowledgmentBlock.cs" />
<Compile Include="Transport\TcpOptionSelectiveAcknowledgmentPermitted.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\TcpOptionWindowScale.cs" />
......
...@@ -44,6 +44,16 @@ namespace PcapDotNet.Packets.Transport ...@@ -44,6 +44,16 @@ namespace PcapDotNet.Packets.Transport
return Equals(obj as TcpOption); return Equals(obj as TcpOption);
} }
public override int GetHashCode()
{
return OptionType.GetHashCode();
}
public override string ToString()
{
return OptionType.ToString();
}
internal override Option Read(byte[] buffer, ref int offset, int length) internal override Option Read(byte[] buffer, ref int offset, int length)
{ {
int offsetEnd = offset + length; int offsetEnd = offset + length;
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace PcapDotNet.Packets.Transport
{
/// <summary>
/// The SACK option is to be used to convey extended acknowledgment information from the receiver to the sender over an established TCP connection.
///
/// +--------+--------+
/// | Kind=5 | Length |
/// +--------+--------+--------+--------+
/// | Left Edge of 1st Block |
/// +--------+--------+--------+--------+
/// | Right Edge of 1st Block |
/// +--------+--------+--------+--------+
/// | |
/// / . . . /
/// | |
/// +--------+--------+--------+--------+
/// | Left Edge of nth Block |
/// +--------+--------+--------+--------+
/// | Right Edge of nth Block |
/// +--------+--------+--------+--------+
///
/// The SACK option is to be sent by a data receiver to inform the data sender of non-contiguous blocks of data that have been received and queued.
/// The data receiver awaits the receipt of data (perhaps by means of retransmissions) to fill the gaps in sequence space between received blocks.
/// When missing segments are received, the data receiver acknowledges the data normally by advancing
/// the left window edge in the Acknowledgement Number Field of the TCP header.
/// The SACK option does not change the meaning of the Acknowledgement Number field.
///
/// This option contains a list of some of the blocks of contiguous sequence space occupied by data that has been received and queued within the window.
/// Each contiguous block of data queued at the data receiver is defined in the SACK option by two 32-bit unsigned integers in network byte order:
/// * Left Edge of Block - This is the first sequence number of this block.
/// * Right Edge of Block - This is the sequence number immediately following the last sequence number of this block.
///
/// Each block represents received bytes of data that are contiguous and isolated;
/// that is, the bytes just below the block, (Left Edge of Block - 1), and just above the block, (Right Edge of Block), have not been received.
///
/// A SACK option that specifies n blocks will have a length of 8*n+2 bytes, so the 40 bytes available for TCP options can specify a maximum of 4 blocks.
/// It is expected that SACK will often be used in conjunction with the Timestamp option used for RTTM [Jacobson92],
/// which takes an additional 10 bytes (plus two bytes of padding); thus a maximum of 3 SACK blocks will be allowed in this case.
///
/// The SACK option is advisory, in that, while it notifies the data sender that the data receiver has received the indicated segments,
/// the data receiver is permitted to later discard data which have been reported in a SACK option.
/// </summary>
[OptionTypeRegistration(typeof(TcpOptionType), TcpOptionType.SelectiveAcknowledgment)]
public class TcpOptionSelectiveAcknowledgment : TcpOptionComplex, IOptionComplexFactory, IEquatable<TcpOptionSelectiveAcknowledgment>
{
/// <summary>
/// The minimum number of bytes this option take.
/// </summary>
public const int OptionMinimumLength = 2;
public const int OptionValueMinimumLength = OptionMinimumLength - OptionHeaderLength;
public TcpOptionSelectiveAcknowledgment(IList<TcpOptionSelectiveAcknowledgmentBlock> blocks)
: base(TcpOptionType.SelectiveAcknowledgment)
{
_blocks = new ReadOnlyCollection<TcpOptionSelectiveAcknowledgmentBlock>(blocks);
}
public TcpOptionSelectiveAcknowledgment()
: this(new TcpOptionSelectiveAcknowledgmentBlock[]{})
{
}
public ReadOnlyCollection<TcpOptionSelectiveAcknowledgmentBlock> Blocks
{
get { return _blocks; }
}
/// <summary>
/// The number of bytes this option will take.
/// </summary>
public override int Length
{
get { return OptionMinimumLength + TcpOptionSelectiveAcknowledgmentBlock.SizeOf * Blocks.Count; }
}
/// <summary>
/// True iff this option may appear at most once in a datagram.
/// </summary>
public override bool IsAppearsAtMostOnce
{
get { return true; }
}
public bool Equals(TcpOptionSelectiveAcknowledgment other)
{
if (other == null)
return false;
return Blocks.SequenceEqual(other.Blocks);
}
public override bool Equals(TcpOption other)
{
return Equals(other as TcpOptionSelectiveAcknowledgment);
}
/// <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 < OptionValueMinimumLength || valueLength % TcpOptionSelectiveAcknowledgmentBlock.SizeOf != 0)
return null;
int numBlocks = valueLength / TcpOptionSelectiveAcknowledgmentBlock.SizeOf;
TcpOptionSelectiveAcknowledgmentBlock[] blocks = new TcpOptionSelectiveAcknowledgmentBlock[numBlocks];
for (int i = 0; i != numBlocks; ++i)
{
blocks[i] = new TcpOptionSelectiveAcknowledgmentBlock(buffer.ReadUInt(ref offset, Endianity.Big),
buffer.ReadUInt(ref offset, Endianity.Big));
}
return new TcpOptionSelectiveAcknowledgment(blocks);
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
foreach (TcpOptionSelectiveAcknowledgmentBlock block in Blocks)
{
buffer.Write(ref offset, block.LeftEdge, Endianity.Big);
buffer.Write(ref offset, block.RightEdge, Endianity.Big);
}
}
private readonly ReadOnlyCollection<TcpOptionSelectiveAcknowledgmentBlock> _blocks;
}
}
\ No newline at end of file
namespace PcapDotNet.Packets.Transport
{
public struct TcpOptionSelectiveAcknowledgmentBlock
{
public const int SizeOf = 8;
public TcpOptionSelectiveAcknowledgmentBlock(uint leftEdge, uint rightEdge)
{
_leftEdge = leftEdge;
_rightEdge = rightEdge;
}
public uint LeftEdge
{
get { return _leftEdge; }
}
public uint RightEdge
{
get { return _rightEdge; }
}
public override string ToString()
{
return LeftEdge + "-" + RightEdge;
}
private readonly uint _leftEdge;
private readonly uint _rightEdge;
}
}
\ No newline at end of file
using System;
namespace PcapDotNet.Packets.Transport
{
/// <summary>
/// Sack-Permitted Option (RFC 2018)
/// This two-byte option may be sent in a SYN by a TCP that has been extended to receive (and presumably process)
/// the SACK option once the connection has opened.
/// It MUST NOT be sent on non-SYN segments.
///
/// +---------+---------+
/// | Kind=4 | Length=2|
/// +---------+---------+
/// </summary>
[OptionTypeRegistration(typeof(TcpOptionType), TcpOptionType.SelectiveAcknowledgmentPermitted)]
public class TcpOptionSelectiveAcknowledgmentPermitted : TcpOptionComplex, IOptionComplexFactory, IEquatable<TcpOptionSelectiveAcknowledgmentPermitted>
{
/// <summary>
/// The number of bytes this option take.
/// </summary>
public const int OptionLength = 2;
public const int OptionValueLength = OptionLength - OptionHeaderLength;
public TcpOptionSelectiveAcknowledgmentPermitted()
: base(TcpOptionType.SelectiveAcknowledgmentPermitted)
{
}
/// <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(TcpOptionSelectiveAcknowledgmentPermitted other)
{
return other != null;
}
public override bool Equals(TcpOption other)
{
return Equals(other as TcpOptionSelectiveAcknowledgmentPermitted);
}
/// <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;
return _instance;
}
private static readonly TcpOptionSelectiveAcknowledgmentPermitted _instance = new TcpOptionSelectiveAcknowledgmentPermitted();
}
}
\ No newline at end of file
...@@ -6,8 +6,8 @@ namespace PcapDotNet.Packets.Transport ...@@ -6,8 +6,8 @@ namespace PcapDotNet.Packets.Transport
NoOperation = 1, NoOperation = 1,
MaximumSegmentSize = 2, MaximumSegmentSize = 2,
WindowScale = 3, WindowScale = 3,
SackPermitted = 4, SelectiveAcknowledgmentPermitted = 4,
Sack = 5, SelectiveAcknowledgment = 5,
Echo = 6, Echo = 6,
EchoReply = 7, EchoReply = 7,
TimeStamp = 8, TimeStamp = 8,
......
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