Commit 430c24ac authored by Brickner_cp's avatar Brickner_cp

Add support for quick start IPv4 option.

Fixed IPv4 Header checksum bug.
parent b4143c20
using System;
using System.Collections.Generic;
using System.Text;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Core.Test
......@@ -40,6 +41,32 @@ namespace PcapDotNet.Core.Test
case IpV4OptionType.RouterAlert:
return "Router Alert: Unknown (" + ((IpV4OptionRouterAlert)option).Value + ")";
case IpV4OptionType.QuickStart:
IpV4OptionQuickStart quickStart = (IpV4OptionQuickStart)option;
StringBuilder quickStartWireshark = new StringBuilder("Quick-Start: ");
if (quickStart.Function == IpV4OptionQuickStartFunction.RateRequest)
quickStartWireshark.Append("Rate request");
else
quickStartWireshark.Append("Rate report");
quickStartWireshark.Append(", ");
if (quickStart.RateKbps == 0)
quickStartWireshark.Append("0 bit/s");
else if (quickStart.RateKbps < 1024)
quickStartWireshark.Append(quickStart.RateKbps + " kbit/s");
else if (quickStart.RateKbps < 1024 * 1024)
quickStartWireshark.Append(((double)quickStart.RateKbps / 1000) + " Mbit/s");
else
quickStartWireshark.Append(((double)quickStart.RateKbps / 1000000) + " Gbit/s");
if (quickStart.Function == IpV4OptionQuickStartFunction.RateRequest)
quickStartWireshark.Append(", QS TTL " + quickStart.Ttl);
return quickStartWireshark.ToString();
default:
throw new InvalidOperationException("Illegal option type " + option.OptionType);
}
......@@ -53,6 +80,7 @@ namespace PcapDotNet.Core.Test
case IpV4OptionType.NoOperation:
case IpV4OptionType.StreamIdentifier:
case IpV4OptionType.RouterAlert:
case IpV4OptionType.QuickStart:
break;
case IpV4OptionType.LooseSourceRouting:
......
......@@ -349,7 +349,7 @@ namespace PcapDotNet.Core.Test
DateTime fieldTimestamp = fieldShow[4] == ' '
? DateTime.ParseExact(fieldShow, "MMM d, yyyy HH:mm:ss.fffffff", CultureInfo.InvariantCulture)
: DateTime.ParseExact(fieldShow, "MMM dd, yyyy HH:mm:ss.fffffff", CultureInfo.InvariantCulture);
MoreAssert.IsInRange(fieldTimestamp.AddSeconds(-1), fieldTimestamp.AddSeconds(1), packet.Timestamp);
MoreAssert.IsInRange(fieldTimestamp.AddSeconds(-2), fieldTimestamp.AddSeconds(2), packet.Timestamp);
break;
case "frame.len":
......
......@@ -106,6 +106,8 @@ namespace PcapDotNet.Packets.TestUtils
impossibleOptionTypes.Add(IpV4OptionType.InternetTimestamp);
if (maximumOptionLength < IpV4OptionTraceRoute.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.TraceRoute);
if (maximumOptionLength < IpV4OptionQuickStart.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.QuickStart);
IpV4OptionType optionType = random.NextEnum<IpV4OptionType>(impossibleOptionTypes);
switch (optionType)
......@@ -193,6 +195,12 @@ namespace PcapDotNet.Packets.TestUtils
case IpV4OptionType.RouterAlert:
return new IpV4OptionRouterAlert(random.NextUShort());
case IpV4OptionType.QuickStart:
return new IpV4OptionQuickStart(random.NextEnum<IpV4OptionQuickStartFunction>(),
random.NextByte(IpV4OptionQuickStart.RateMaximumValue + 1),
random.NextByte(),
random.NextUInt() & 0xFFFFFFFC);
default:
throw new InvalidOperationException("optionType = " + optionType);
}
......
......@@ -254,7 +254,7 @@ namespace PcapDotNet.Packets.IpV4
private ushort CalculateHeaderChecksum()
{
uint sum = Sum16Bits(Buffer, StartOffset, Math.Min(Offset.HeaderChecksum, Length)) +
Sum16Bits(Buffer, StartOffset + Offset.HeaderChecksum + 2, Math.Min(HeaderLength, Length) - Offset.HeaderChecksum - 2);
Sum16Bits(Buffer, StartOffset + Offset.HeaderChecksum + 2, RealHeaderLength - Offset.HeaderChecksum - 2);
return Sum16BitsToChecksum(sum);
}
......@@ -275,6 +275,8 @@ namespace PcapDotNet.Packets.IpV4
uint sum = 0;
while (offset < endOffset - 1)
sum += buffer.ReadUShort(ref offset, Endianity.Big);
if (offset < endOffset)
sum += buffer[offset];
return sum;
}
......
using System;
namespace PcapDotNet.Packets.IpV4
{
public enum IpV4OptionQuickStartFunction : byte
{
RateRequest = 0x00,
RateReport = 0x80
}
/// <summary>
/// The Quick-Start Option for IPv4
///
/// The Quick-Start Request for IPv4 is defined as follows:
/// 0 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Option | Length=8 | Func. | Rate | QS TTL |
/// | | | 0000 |Request| |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | QS Nonce | R |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// </summary>
[IpV4OptionTypeRegistration(IpV4OptionType.QuickStart)]
public class IpV4OptionQuickStart : IpV4OptionComplex, IIpv4OptionComplexFactory, IEquatable<IpV4OptionQuickStart>
{
/// <summary>
/// The number of bytes this option take.
/// </summary>
public const int OptionLength = 8;
/// <summary>
/// The number of bytes this option's value take.
/// </summary>
public const int OptionValueLength = OptionLength - OptionHeaderLength;
public const byte RateMaximumValue = 0x0F;
/// <summary>
/// Create a quick start option according to the given field values.
/// </summary>
/// <param name="function">The function of this quick start option.</param>
/// <param name="rate">Either the rate requested or reported.</param>
/// <param name="ttl">
/// The Quick-Start TTL (QS TTL) field.
/// The sender MUST set the QS TTL field to a random value.
/// Routers that approve the Quick-Start Request decrement the QS TTL (mod 256) by the same amount that they decrement the IP TTL.
/// The QS TTL is used by the sender to detect if all the routers along the path understood and approved the Quick-Start option.
/// </param>
/// <param name="nonce">
/// The QS Nonce gives the Quick-Start sender some protection against receivers lying about the value of the received Rate Request.
/// </param>
public IpV4OptionQuickStart(IpV4OptionQuickStartFunction function, byte rate, byte ttl, uint nonce)
: base(IpV4OptionType.QuickStart)
{
if (function != IpV4OptionQuickStartFunction.RateRequest &&
function != IpV4OptionQuickStartFunction.RateReport)
{
throw new ArgumentException("Illegal function " + function, "function");
}
if (rate > RateMaximumValue)
throw new ArgumentOutOfRangeException("rate", rate, "Rate maximum value is " + RateMaximumValue);
if ((nonce & 0x00000003) != 0)
throw new ArgumentException("nonce last two bits are reserved and must be zero", "nonce");
_function = function;
_rate = rate;
_ttl = ttl;
_nonce = nonce;
}
/// <summary>
/// Creates a request with 0 fields.
/// </summary>
public IpV4OptionQuickStart()
: this(IpV4OptionQuickStartFunction.RateRequest, 0, 0, 0)
{
}
/// <summary>
/// The function of this quick start option.
/// </summary>
public IpV4OptionQuickStartFunction Function
{
get { return _function; }
}
/// <summary>
/// If function is request then this field is the rate request.
/// If function is report then this field is the rate report.
/// </summary>
public byte Rate
{
get { return _rate; }
}
/// <summary>
/// The rate translated to KBPS.
/// </summary>
public int RateKbps
{
get
{
if (Rate == 0)
return 0;
return 40 * (1 << Rate);
}
}
/// <summary>
/// The Quick-Start TTL (QS TTL) field.
/// The sender MUST set the QS TTL field to a random value.
/// Routers that approve the Quick-Start Request decrement the QS TTL (mod 256) by the same amount that they decrement the IP TTL.
/// The QS TTL is used by the sender to detect if all the routers along the path understood and approved the Quick-Start option.
///
/// For a Rate Request, the transport sender MUST calculate and store the TTL Diff,
/// the difference between the IP TTL value, and the QS TTL value in the Quick-Start Request packet, as follows:
/// TTL Diff = ( IP TTL - QS TTL ) mod 256
/// </summary>
public byte Ttl
{
get { return _ttl; }
}
/// <summary>
/// The QS Nonce gives the Quick-Start sender some protection against receivers lying about the value of the received Rate Request.
/// This is particularly important if the receiver knows the original value of the Rate Request
/// (e.g., when the sender always requests the same value, and the receiver has a long history of communication with that sender).
/// Without the QS Nonce, there is nothing to prevent the receiver from reporting back to the sender a Rate Request of K,
/// when the received Rate Request was, in fact, less than K.
///
/// The format for the 30-bit QS Nonce.
/// Bits Purpose
/// --------- ------------------
/// Bits 0-1: Rate 15 -> Rate 14
/// Bits 2-3: Rate 14 -> Rate 13
/// Bits 4-5: Rate 13 -> Rate 12
/// Bits 6-7: Rate 12 -> Rate 11
/// Bits 8-9: Rate 11 -> Rate 10
/// Bits 10-11: Rate 10 -> Rate 9
/// Bits 12-13: Rate 9 -> Rate 8
/// Bits 14-15: Rate 8 -> Rate 7
/// Bits 16-17: Rate 7 -> Rate 6
/// Bits 18-19: Rate 6 -> Rate 5
/// Bits 20-21: Rate 5 -> Rate 4
/// Bits 22-23: Rate 4 -> Rate 3
/// Bits 24-25: Rate 3 -> Rate 2
/// Bits 26-27: Rate 2 -> Rate 1
/// Bits 28-29: Rate 1 -> Rate 0
///
/// The transport sender MUST initialize the QS Nonce to a random value.
/// If the router reduces the Rate Request from rate K to rate K-1,
/// then the router MUST set the field in the QS Nonce for "Rate K -> Rate K-1" to a new random value.
/// Similarly, if the router reduces the Rate Request by N steps,
/// the router MUST set the 2N bits in the relevant fields in the QS Nonce to a new random value.
/// The receiver MUST report the QS Nonce back to the sender.
///
/// If the Rate Request was not decremented in the network, then the QS Nonce should have its original value.
/// Similarly, if the Rate Request was decremented by N steps in the network,
/// and the receiver reports back a Rate Request of K, then the last 2K bits of the QS Nonce should have their original value.
/// </summary>
public uint Nonce
{
get { return _nonce; }
}
/// <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; }
}
/// <summary>
/// Two quick start options are equal iff they have the exact same field values.
/// </summary>
public bool Equals(IpV4OptionQuickStart other)
{
if (other == null)
return false;
return Function == other.Function &&
Rate == other.Rate &&
Ttl == other.Ttl &&
Nonce == other.Nonce;
}
/// <summary>
/// Two trace route options are equal iff they have the exact same field values.
/// </summary>
public override bool Equals(IpV4Option other)
{
return Equals(other as IpV4OptionQuickStart);
}
/// <summary>
/// The hash code is the xor of the base class hash code with the following values hash code:
/// The combination of function, rate and ttl and the nonce.
/// </summary>
public override int GetHashCode()
{
return base.GetHashCode() ^
((((byte)Function | Rate) << 8) | Ttl).GetHashCode() ^
Nonce.GetHashCode();
}
public IpV4OptionComplex CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionValueLength)
return null;
byte functionAndRate = buffer[offset++];
IpV4OptionQuickStartFunction function = (IpV4OptionQuickStartFunction)(functionAndRate & 0xF0);
byte rate = (byte)(functionAndRate & 0x0F);
byte ttl = buffer[offset++];
uint nonce = buffer.ReadUInt(ref offset, Endianity.Big);
return new IpV4OptionQuickStart(function, rate, ttl, nonce);
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
buffer[offset++] = (byte)((byte)Function | Rate);
buffer[offset++] = Ttl;
buffer.Write(ref offset, Nonce, Endianity.Big);
}
private readonly IpV4OptionQuickStartFunction _function;
private readonly byte _rate;
private readonly byte _ttl;
private readonly uint _nonce;
}
}
\ No newline at end of file
......@@ -33,6 +33,11 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
NoOperation = 1,
/// <summary>
/// Quick Start (QS). RFC 4782.
/// </summary>
QuickStart = 25,
/// <summary>
/// Traceroute Using an IP Option.
/// RFC 1393.
......
......@@ -75,6 +75,7 @@
<Compile Include="IpV4\IpV4Option.cs" />
<Compile Include="IpV4\IpV4OptionComplex.cs" />
<Compile Include="IpV4\IpV4OptionLooseSourceRouting.cs" />
<Compile Include="IpV4\IpV4OptionQuickStart.cs" />
<Compile Include="IpV4\IpV4OptionRouterAlert.cs" />
<Compile Include="IpV4\IpV4OptionSecurityProtectionAuthority.cs" />
<Compile Include="IpV4\IpV4OptionSimple.cs" />
......
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