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 ...@@ -42,7 +42,7 @@ namespace PcapDotNet.Core.Test
break; break;
case "data": case "data":
var casted1 = icmpDatagram as IcmpIpV4HeaderPlus64BitsPayloadDatagram; var casted1 = icmpDatagram as IcmpIpV4PayloadDatagram;
if (casted1 != null) if (casted1 != null)
{ {
if (casted1.IpV4.Protocol != IpV4Protocol.IpComp) // TODO: Support IpComp. if (casted1.IpV4.Protocol != IpV4Protocol.IpComp) // TODO: Support IpComp.
......
...@@ -78,7 +78,12 @@ namespace PcapDotNet.Packets.Test ...@@ -78,7 +78,12 @@ namespace PcapDotNet.Packets.Test
switch (icmpLayer.MessageType) switch (icmpLayer.MessageType)
{ {
case IcmpMessageType.ParameterProblem: 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; break;
case IcmpMessageType.SecurityFailures: case IcmpMessageType.SecurityFailures:
......
...@@ -36,7 +36,8 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -36,7 +36,8 @@ namespace PcapDotNet.Packets.TestUtils
return new IcmpParameterProblemLayer return new IcmpParameterProblemLayer
{ {
Checksum = checksum, Checksum = checksum,
Pointer = random.NextByte() Pointer = random.NextByte(),
OriginalDatagramLength = random.NextByte() * sizeof(uint),
}; };
case IcmpMessageType.SourceQuench: case IcmpMessageType.SourceQuench:
...@@ -192,12 +193,19 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -192,12 +193,19 @@ namespace PcapDotNet.Packets.TestUtils
{ {
case IcmpMessageType.DestinationUnreachable: case IcmpMessageType.DestinationUnreachable:
case IcmpMessageType.TimeExceeded: case IcmpMessageType.TimeExceeded:
case IcmpMessageType.ParameterProblem:
case IcmpMessageType.SourceQuench: case IcmpMessageType.SourceQuench:
case IcmpMessageType.Redirect: case IcmpMessageType.Redirect:
case IcmpMessageType.SecurityFailures: case IcmpMessageType.SecurityFailures:
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextIpV4Layer(), random.NextPayloadLayer(IcmpIpV4HeaderPlus64BitsPayloadDatagram.OriginalDatagramPayloadLength)); icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextIpV4Layer(), random.NextPayloadLayer(IcmpIpV4HeaderPlus64BitsPayloadDatagram.OriginalDatagramPayloadLength));
break; 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: case IcmpMessageType.ConversionFailed:
IpV4Layer icmpIpV4Layer = random.NextIpV4Layer(); IpV4Layer icmpIpV4Layer = random.NextIpV4Layer();
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, icmpIpV4Layer); icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, icmpIpV4Layer);
......
...@@ -30,7 +30,7 @@ namespace PcapDotNet.Packets.Icmp ...@@ -30,7 +30,7 @@ namespace PcapDotNet.Packets.Icmp
get get
{ {
if (_ipV4 == null && Length >= HeaderLength) if (_ipV4 == null && Length >= HeaderLength)
_ipV4 = new IpV4Datagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); _ipV4 = new IpV4Datagram(Buffer, StartOffset + HeaderLength, IpV4Length);
return _ipV4; return _ipV4;
} }
} }
...@@ -48,6 +48,8 @@ namespace PcapDotNet.Packets.Icmp ...@@ -48,6 +48,8 @@ namespace PcapDotNet.Packets.Icmp
return (ip.Length >= IpV4Datagram.HeaderMinimumLength && ip.Length >= ip.HeaderLength); return (ip.Length >= IpV4Datagram.HeaderMinimumLength && ip.Length >= ip.HeaderLength);
} }
internal virtual int IpV4Length { get { return Length - HeaderLength; } }
private IpV4Datagram _ipV4; private IpV4Datagram _ipV4;
} }
} }
\ No newline at end of file
...@@ -149,7 +149,7 @@ namespace PcapDotNet.Packets.Icmp ...@@ -149,7 +149,7 @@ namespace PcapDotNet.Packets.Icmp
TimeExceeded = 0x0B, TimeExceeded = 0x0B,
/// <summary> /// <summary>
/// RFC 792. /// RFCs 792, 4884.
/// ///
/// <para> /// <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. /// 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 namespace PcapDotNet.Packets.Icmp
{ {
/// <summary> /// <summary>
/// RFC 792. /// RFCs 792, 4884.
/// <pre> /// <pre>
/// +-----+---------+------+-----------+ /// +-----+---------+--------+----------+
/// | Bit | 0-7 | 8-15 | 16-31 | /// | Bit | 0-7 | 8-15 | 16-31 |
/// +-----+---------+------+-----------+ /// +-----+---------+--------+----------+
/// | 0 | Type | Code | Checksum | /// | 0 | Type | Code | Checksum |
/// +-----+---------+------+-----------+ /// +-----+---------+--------+----------+
/// | 32 | Pointer | unused | /// | 32 | Pointer | Length | unused |
/// +-----+---------+------------------+ /// +-----+---------+-------------------+
/// | 64 | Internet Header | /// | 64 | Internet Header |
/// | | + 64 bits of | /// | | + leading octets of |
/// | | Original Data Datagram | /// | | original datagram |
/// +-----+----------------------------+ /// +-----+-----------------------------+
/// </pre> /// </pre>
/// </summary> /// </summary>
[IcmpDatagramRegistration(IcmpMessageType.ParameterProblem)] [IcmpDatagramRegistration(IcmpMessageType.ParameterProblem)]
public sealed class IcmpParameterProblemDatagram : IcmpIpV4HeaderPlus64BitsPayloadDatagram public sealed class IcmpParameterProblemDatagram : IcmpIpV4PayloadDatagram
{ {
private static class Offset private static class Offset
{ {
public const int Pointer = 4; public const int Pointer = 4;
public const int OriginalDatagramLength = Pointer + sizeof(byte);
} }
/// <summary> /// <summary>
...@@ -33,6 +36,15 @@ namespace PcapDotNet.Packets.Icmp ...@@ -33,6 +36,15 @@ namespace PcapDotNet.Packets.Icmp
get { return this[Offset.Pointer]; } 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> /// <summary>
/// Creates a Layer that represents the datagram to be used with PacketBuilder. /// Creates a Layer that represents the datagram to be used with PacketBuilder.
/// </summary> /// </summary>
...@@ -41,7 +53,8 @@ namespace PcapDotNet.Packets.Icmp ...@@ -41,7 +53,8 @@ namespace PcapDotNet.Packets.Icmp
return new IcmpParameterProblemLayer return new IcmpParameterProblemLayer
{ {
Checksum = Checksum, Checksum = Checksum,
Pointer = Pointer Pointer = Pointer,
OriginalDatagramLength = OriginalDatagramLength,
}; };
} }
...@@ -52,7 +65,7 @@ namespace PcapDotNet.Packets.Icmp ...@@ -52,7 +65,7 @@ namespace PcapDotNet.Packets.Icmp
/// </summary> /// </summary>
protected override bool CalculateIsValid() 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) internal override IcmpDatagram CreateInstance(byte[] buffer, int offset, int length)
...@@ -60,6 +73,11 @@ namespace PcapDotNet.Packets.Icmp ...@@ -60,6 +73,11 @@ namespace PcapDotNet.Packets.Icmp
return new IcmpParameterProblemDatagram(buffer, offset, length); 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) private IcmpParameterProblemDatagram(byte[] buffer, int offset, int length)
: base(buffer, offset, length) : base(buffer, offset, length)
{ {
......
using System;
namespace PcapDotNet.Packets.Icmp namespace PcapDotNet.Packets.Icmp
{ {
/// <summary> /// <summary>
...@@ -5,12 +7,34 @@ namespace PcapDotNet.Packets.Icmp ...@@ -5,12 +7,34 @@ namespace PcapDotNet.Packets.Icmp
/// </summary> /// </summary>
public sealed class IcmpParameterProblemLayer : IcmpLayer public sealed class IcmpParameterProblemLayer : IcmpLayer
{ {
/// <summary>
/// The maximum value that OriginalDatagramLength can take.
/// </summary>
public const int OriginalDatagramLengthMaxValue = Byte.MaxValue * sizeof(uint);
/// <summary> /// <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). /// 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. /// 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> /// </summary>
public byte Pointer { get; set; } 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> /// <summary>
/// The value of this field determines the format of the remaining data. /// The value of this field determines the format of the remaining data.
/// </summary> /// </summary>
...@@ -24,7 +48,9 @@ namespace PcapDotNet.Packets.Icmp ...@@ -24,7 +48,9 @@ namespace PcapDotNet.Packets.Icmp
/// </summary> /// </summary>
protected override uint Variable 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