Commit acf3f428 authored by Brickner_cp's avatar Brickner_cp

Generalize IcmpParameterProblem according to RFC 4884.

parent 339bb612
......@@ -42,7 +42,7 @@ namespace PcapDotNet.Core.Test
break;
case "data":
var casted1 = icmpDatagram as IcmpIpV4HeaderPlus64BitsPayloadDatagram;
var casted1 = icmpDatagram as IcmpIpV4PayloadDatagram;
if (casted1 != null)
{
if (casted1.IpV4.Protocol != IpV4Protocol.IpComp) // TODO: Support IpComp.
......
......@@ -78,7 +78,12 @@ namespace PcapDotNet.Packets.Test
switch (icmpLayer.MessageType)
{
case IcmpMessageType.ParameterProblem:
((IcmpParameterProblemLayer)icmpLayer).Pointer %= (byte)icmpPayloadLength;
if (icmpPayloadLength % 4 != 0)
icmpPayloadLayers = icmpPayloadLayers.Concat(new[] {new PayloadLayer {Data = random.NextDatagram(4 - icmpPayloadLength % 4)}});
icmpPayloadLength = icmpPayloadLayers.Select(layer => layer.Length).Sum();
IcmpParameterProblemLayer icmpParameterProblemLayer = (IcmpParameterProblemLayer)icmpLayer;
icmpParameterProblemLayer.Pointer = (byte)(icmpParameterProblemLayer.Pointer % icmpPayloadLength);
icmpParameterProblemLayer.OriginalDatagramLength = icmpPayloadLength;
break;
case IcmpMessageType.SecurityFailures:
......
......@@ -36,7 +36,8 @@ namespace PcapDotNet.Packets.TestUtils
return new IcmpParameterProblemLayer
{
Checksum = checksum,
Pointer = random.NextByte()
Pointer = random.NextByte(),
OriginalDatagramLength = random.NextByte() * sizeof(uint),
};
case IcmpMessageType.SourceQuench:
......@@ -192,12 +193,19 @@ namespace PcapDotNet.Packets.TestUtils
{
case IcmpMessageType.DestinationUnreachable:
case IcmpMessageType.TimeExceeded:
case IcmpMessageType.ParameterProblem:
case IcmpMessageType.SourceQuench:
case IcmpMessageType.Redirect:
case IcmpMessageType.SecurityFailures:
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextIpV4Layer(), random.NextPayloadLayer(IcmpIpV4HeaderPlus64BitsPayloadDatagram.OriginalDatagramPayloadLength));
break;
case IcmpMessageType.ParameterProblem:
IpV4Layer ipV4Layer = random.NextIpV4Layer();
icmpPayloadLayers =
IEnumerableExtensions.Concat(icmpPayloadLayers, ipV4Layer,
random.NextPayloadLayer(random.NextInt(0,
IcmpParameterProblemLayer.OriginalDatagramLengthMaxValue + 1 -
ipV4Layer.Length)));
break;
case IcmpMessageType.ConversionFailed:
IpV4Layer icmpIpV4Layer = random.NextIpV4Layer();
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, icmpIpV4Layer);
......
......@@ -30,7 +30,7 @@ namespace PcapDotNet.Packets.Icmp
get
{
if (_ipV4 == null && Length >= HeaderLength)
_ipV4 = new IpV4Datagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
_ipV4 = new IpV4Datagram(Buffer, StartOffset + HeaderLength, IpV4Length);
return _ipV4;
}
}
......@@ -48,6 +48,8 @@ namespace PcapDotNet.Packets.Icmp
return (ip.Length >= IpV4Datagram.HeaderMinimumLength && ip.Length >= ip.HeaderLength);
}
internal virtual int IpV4Length { get { return Length - HeaderLength; } }
private IpV4Datagram _ipV4;
}
}
\ No newline at end of file
......@@ -149,7 +149,7 @@ namespace PcapDotNet.Packets.Icmp
TimeExceeded = 0x0B,
/// <summary>
/// RFC 792.
/// RFCs 792, 4884.
///
/// <para>
/// If the gateway or host processing a datagram finds a problem with the header parameters such that it cannot complete processing the datagram it must discard the datagram.
......
using System;
namespace PcapDotNet.Packets.Icmp
{
/// <summary>
/// RFC 792.
/// RFCs 792, 4884.
/// <pre>
/// +-----+---------+------+-----------+
/// | Bit | 0-7 | 8-15 | 16-31 |
/// +-----+---------+------+-----------+
/// | 0 | Type | Code | Checksum |
/// +-----+---------+------+-----------+
/// | 32 | Pointer | unused |
/// +-----+---------+------------------+
/// | 64 | Internet Header |
/// | | + 64 bits of |
/// | | Original Data Datagram |
/// +-----+----------------------------+
/// +-----+---------+--------+----------+
/// | Bit | 0-7 | 8-15 | 16-31 |
/// +-----+---------+--------+----------+
/// | 0 | Type | Code | Checksum |
/// +-----+---------+--------+----------+
/// | 32 | Pointer | Length | unused |
/// +-----+---------+-------------------+
/// | 64 | Internet Header |
/// | | + leading octets of |
/// | | original datagram |
/// +-----+-----------------------------+
/// </pre>
/// </summary>
[IcmpDatagramRegistration(IcmpMessageType.ParameterProblem)]
public sealed class IcmpParameterProblemDatagram : IcmpIpV4HeaderPlus64BitsPayloadDatagram
public sealed class IcmpParameterProblemDatagram : IcmpIpV4PayloadDatagram
{
private static class Offset
{
public const int Pointer = 4;
public const int OriginalDatagramLength = Pointer + sizeof(byte);
}
/// <summary>
......@@ -33,6 +36,15 @@ namespace PcapDotNet.Packets.Icmp
get { return this[Offset.Pointer]; }
}
/// <summary>
/// Length of the padded "original datagram".
/// Must divide by 4 and cannot exceed OriginalDatagramLengthMaxValue.
/// </summary>
public int OriginalDatagramLength
{
get { return this[Offset.OriginalDatagramLength] * sizeof(uint); }
}
/// <summary>
/// Creates a Layer that represents the datagram to be used with PacketBuilder.
/// </summary>
......@@ -41,7 +53,8 @@ namespace PcapDotNet.Packets.Icmp
return new IcmpParameterProblemLayer
{
Checksum = Checksum,
Pointer = Pointer
Pointer = Pointer,
OriginalDatagramLength = OriginalDatagramLength,
};
}
......@@ -52,7 +65,7 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
protected override bool CalculateIsValid()
{
return base.CalculateIsValid() && Pointer < IpV4.Length;
return base.CalculateIsValid() && Pointer < IpV4.Length && OriginalDatagramLength == IpV4.Length;
}
internal override IcmpDatagram CreateInstance(byte[] buffer, int offset, int length)
......@@ -60,6 +73,11 @@ namespace PcapDotNet.Packets.Icmp
return new IcmpParameterProblemDatagram(buffer, offset, length);
}
internal override int IpV4Length
{
get { return Math.Min(Length - HeaderLength, OriginalDatagramLength); }
}
private IcmpParameterProblemDatagram(byte[] buffer, int offset, int length)
: base(buffer, offset, length)
{
......
using System;
namespace PcapDotNet.Packets.Icmp
{
/// <summary>
......@@ -5,12 +7,34 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
public sealed class IcmpParameterProblemLayer : IcmpLayer
{
/// <summary>
/// The maximum value that OriginalDatagramLength can take.
/// </summary>
public const int OriginalDatagramLengthMaxValue = Byte.MaxValue * sizeof(uint);
/// <summary>
/// The pointer identifies the octet of the original datagram's header where the error was detected (it may be in the middle of an option).
/// For example, 1 indicates something is wrong with the Type of Service, and (if there are options present) 20 indicates something is wrong with the type code of the first option.
/// </summary>
public byte Pointer { get; set; }
/// <summary>
/// Length of the padded "original datagram".
/// Must divide by 4 and cannot exceed OriginalDatagramLengthMaxValue.
/// </summary>
public int OriginalDatagramLength
{
get { return _originalDatagramLength; }
set
{
if (value % sizeof(uint) != 0)
throw new ArgumentOutOfRangeException("value", value, string.Format("Must divide by {0}.", sizeof(uint)));
if (value > OriginalDatagramLengthMaxValue)
throw new ArgumentOutOfRangeException("value", value, string.Format("Must not exceed {0}.", OriginalDatagramLengthMaxValue));
_originalDatagramLength = value;
}
}
/// <summary>
/// The value of this field determines the format of the remaining data.
/// </summary>
......@@ -24,7 +48,9 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
protected override uint Variable
{
get { return (uint)(Pointer << 24); }
get { return (uint)((Pointer << 24) | ((OriginalDatagramLength / sizeof(uint)) << 16)); }
}
private int _originalDatagramLength = 0;
}
}
\ 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