Commit cdb913a5 authored by Brickner_cp's avatar Brickner_cp

GRE

parent b9e2fbb1
......@@ -142,6 +142,14 @@ namespace PcapDotNet.Core.Test
ethernetLayer.EtherType = EthernetType.None;
ipV4Layer.Protocol = null;
GreLayer greLayer = random.NextGreLayer();
// GreLayer greLayer = new GreLayer
// {
// AcknowledgmentSequenceNumber = 10,
// ProtocolType = EthernetType.AppleTalk,
// //EthernetType.PointToPointProtocol,
// Key = 0,
// Version = GreVersion.EnhancedGre,
// };
// IEnumerable<ILayer> grePayloadLayers = random.NextIcmpPayloadLayers(icmpLayer);
return PacketBuilder.Build(packetTimestamp, new ILayer[] {ethernetLayer, ipV4Layer, greLayer});
......@@ -173,7 +181,7 @@ namespace PcapDotNet.Core.Test
private static void ComparePacketsToWireshark(IEnumerable<Packet> packets)
{
string pcapFilename = Path.GetTempPath() + "temp.pcap";
string pcapFilename = Path.GetTempPath() + "temp." + new Random().NextUShort() + ".pcap";
PacketDumpFile.Dump(pcapFilename, new PcapDataLink(DataLinkKind.Ethernet), PacketDevice.DefaultSnapshotLength, packets);
// List<Packet> packetsList = new List<Packet>();
// new OfflinePacketDevice(pcapFilename).Open().ReceivePackets(1000, packetsList.Add);
......@@ -851,31 +859,52 @@ namespace PcapDotNet.Core.Test
if (field.Show().StartsWith("Flags and version: "))
{
XElement[] innerFields = field.Fields().ToArray();
Assert.AreEqual(8, innerFields.Length);
bool isEnhanced = greDatagram.ProtocolType == EthernetType.PointToPointProtocol;
Assert.AreEqual(isEnhanced ? 9 : 8, innerFields.Length, "innerFields.Length");
foreach (var innerField in innerFields)
{
innerField.AssertName("");
}
innerFields[0].AssertShow(string.Format("{0}... .... .... .... = {1}", greDatagram.ChecksumPresent.ToInt(),
int currentInnerFieldIndex = 0;
innerFields[currentInnerFieldIndex++].AssertShow(string.Format("{0}... .... .... .... = {1}", greDatagram.ChecksumPresent.ToInt(),
(greDatagram.ChecksumPresent ? "Checksum" : "No checksum")));
innerFields[1].AssertShow(string.Format(".{0}.. .... .... .... = {1}", greDatagram.RoutingPresent.ToInt(),
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".{0}.. .... .... .... = {1}", greDatagram.RoutingPresent.ToInt(),
(greDatagram.RoutingPresent ? "Routing" : "No routing")));
innerFields[2].AssertShow(string.Format("..{0}. .... .... .... = {1}", greDatagram.KeyPresent.ToInt(),
innerFields[currentInnerFieldIndex++].AssertShow(string.Format("..{0}. .... .... .... = {1}", greDatagram.KeyPresent.ToInt(),
(greDatagram.KeyPresent ? "Key" : "No key")));
innerFields[3].AssertShow(string.Format("...{0} .... .... .... = {1}", greDatagram.SequenceNumberPresent.ToInt(),
innerFields[currentInnerFieldIndex++].AssertShow(string.Format("...{0} .... .... .... = {1}", greDatagram.SequenceNumberPresent.ToInt(),
(greDatagram.SequenceNumberPresent ? "Sequence number" : "No sequence number")));
innerFields[4].AssertShow(string.Format(".... {0}... .... .... = {1}", greDatagram.StrictSourceRoute.ToInt(),
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... {0}... .... .... = {1}", greDatagram.StrictSourceRoute.ToInt(),
(greDatagram.StrictSourceRoute ? "Strict source route" : "No strict source route")));
innerFields[5].AssertShow(string.Format(".... .{0} .... .... = Recursion control: {1}",
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .{0} .... .... = Recursion control: {1}",
greDatagram.RecursionControl.ToBits().Skip(5).Select(b => b.ToInt()).
SequenceToString(),
greDatagram.RecursionControl));
innerFields[6].AssertShow(string.Format(".... .... {0}... = Flags: {1}",
greDatagram.Flags.ToBits().Skip(3).Select(b => b.ToInt()).SequenceToString().
Insert(4, " "),
if (isEnhanced)
{
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... {0}... .... = {1}",
greDatagram.AcknowledgmentSequenceNumberPresent.ToInt(),
(greDatagram.AcknowledgmentSequenceNumberPresent
? "Acknowledgment number"
: "No acknowledgment number")));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... .{0}... = Flags: {1}",
greDatagram.Flags.ToBits().Skip(3).Take(4).Select(b => b.ToInt()).
SequenceToString().
Insert(3, " "),
greDatagram.Flags));
innerFields[7].AssertShow(string.Format(".... .... .... .{0} = Version: {1}",
}
else
{
byte fullFlags = (byte)(greDatagram.Flags | (greDatagram.AcknowledgmentSequenceNumberPresent ? 0x10 : 0x00));
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... {0}... = Flags: {1}",
fullFlags.ToBits().Skip(3).Select(b => b.ToInt()).
SequenceToString().
Insert(4, " "),
fullFlags));
}
innerFields[currentInnerFieldIndex++].AssertShow(string.Format(".... .... .... .{0} = Version: {1}",
((byte)greDatagram.Version).ToBits().Skip(5).Select(b => b.ToInt()).
SequenceToString(),
(byte)greDatagram.Version));
......@@ -888,10 +917,22 @@ namespace PcapDotNet.Core.Test
{
field.AssertValue(greDatagram.RoutingOffset);
}
else if (field.Show().StartsWith("Payload length: "))
{
field.AssertValue(greDatagram.KeyPayloadLength);
}
else if (field.Show().StartsWith("Call ID: "))
{
field.AssertValue(greDatagram.KeyCallId);
}
else if (field.Show().StartsWith("Sequence number: "))
{
field.AssertValue(greDatagram.SequenceNumber);
}
else if (field.Show().StartsWith("Acknowledgement number: "))
{
field.AssertValue(greDatagram.AcknowledgmentSequenceNumber);
}
else if (field.Show().StartsWith("Address family: "))
{
++currentEntry;
......
......@@ -583,12 +583,17 @@ namespace PcapDotNet.Packets.TestUtils
// GRE
public static GreLayer NextGreLayer(this Random random)
{
GreVersion version = random.NextEnum<GreVersion>();
bool isChecksum = random.NextBool();
bool isRouting = random.NextBool();
GreSourceRouteEntry[] routing = null;
ushort? routingOffset = null;
bool strictSourceRoute = false;
if (isRouting)
EthernetType protocolType = random.NextEnum(EthernetType.None);
uint? key = random.NextBool() ? (uint?)random.NextUInt() : null;
if (version == GreVersion.Gre)
{
if (random.NextBool())
{
strictSourceRoute = random.NextBool();
routing = new GreSourceRouteEntry[random.Next(5)];
......@@ -638,17 +643,25 @@ namespace PcapDotNet.Packets.TestUtils
routingOffset += (ushort)routing[i].Length;
}
}
}
else
{
protocolType = EthernetType.PointToPointProtocol;
isChecksum = false;
key = random.NextUInt();
}
return new GreLayer
{
Version = random.NextEnum<GreVersion>(),
ProtocolType = random.NextEnum(EthernetType.None),
Version = version,
ProtocolType = protocolType,
ChecksumPresent = isChecksum,
Checksum = isChecksum && random.NextBool() ? (ushort?)random.NextUShort() : null,
Key = random.NextBool() ? (uint?)random.NextUInt() : null,
Key = key,
SequenceNumber = random.NextBool() ? (uint?)random.NextUInt() : null,
AcknowledgmentSequenceNumber = version == GreVersion.EnhancedGre && random.NextBool() ? (uint?)random.NextUInt() : null,
RecursionControl = random.NextByte(8),
Flags = random.NextByte(32),
// Flags = random.NextByte(32),
Routing = routing == null ? null : routing.AsReadOnly(),
RoutingOffset = routingOffset,
StrictSourceRoute = strictSourceRoute,
......
......@@ -51,6 +51,10 @@ namespace PcapDotNet.Packets.Ethernet
/// </summary>
MacControl = 0x8808,
/// <summary>
/// PPP, Point-to-Point Protocol
/// </summary>
PointToPointProtocol = 0x880B,
/// <summary>
/// CobraNet
/// </summary>
CobraNet = 0x8819,
......
......@@ -11,19 +11,21 @@ namespace PcapDotNet.Packets.Gre
/// <summary>
/// RFC 1701, RFC 1702, RFC 2637, RFC 2784.
/// <pre>
/// +-----+---+---+---+---+---+-------+-------+---------+-------------------+
/// | Bit | 0 | 1 | 2 | 3 | 4 | 5-7 | 8-12 | 13-15 | 16-31 |
/// +-----+---+-----------+---+-------+-------+---------+-------------------+
/// | 0 | C | R | K | S | s | Recur | Flags | Version | Protocol Type |
/// +-----+---+-----------+---+-------+-------+---------+-------------------+
/// +-----+---+---+---+---+---+-------+---+-------+---------+-------------------+
/// | Bit | 0 | 1 | 2 | 3 | 4 | 5-7 | 8 | 9-12 | 13-15 | 16-31 |
/// +-----+---+-----------+---+-------+---+-------+---------+-------------------+
/// | 0 | C | R | K | S | s | Recur | A | Flags | Version | Protocol Type |
/// +-----+---+-----------+---+-------+---+-------+---------+-------------------+
/// | 32 | Checksum (optional) | Offset (optional) |
/// +-----+---------------------------------------------+-------------------+
/// +-----+-------------------------------------------------+-------------------+
/// | 32 | Key (optional) |
/// +-----+-----------------------------------------------------------------+
/// +-----+---------------------------------------------------------------------+
/// | 32 | Sequence Number (optional) |
/// +-----+-----------------------------------------------------------------+
/// +-----+---------------------------------------------------------------------+
/// | 32 | Acknowledgment Number (optional) |
/// +-----+---------------------------------------------------------------------+
/// | 32 | Routing (optional) |
/// +-----+-----------------------------------------------------------------+
/// +-----+---------------------------------------------------------------------+
/// </pre>
/// </summary>
public class GreDatagram : Datagram
......@@ -36,6 +38,7 @@ namespace PcapDotNet.Packets.Gre
public const int SequenceNumberPresent = 0;
public const int StrictSourceRoute = 0;
public const int RecursionControl = 0;
public const int AcknowledgmentSequenceNumberPresent = 1;
public const int Flags = 1;
public const int Version = 1;
public const int ProtocolType = 2;
......@@ -51,7 +54,8 @@ namespace PcapDotNet.Packets.Gre
public const byte SequenceNumberPresent = 0x10;
public const byte StrictSourceRoute = 0x08;
public const byte RecursionControl = 0x07;
public const byte Flags = 0xF8;
public const byte AcknowledgmentSequenceNumberPresent = 0x80;
public const byte Flags = 0x78;
public const byte Version = 0x07;
}
......@@ -66,7 +70,7 @@ namespace PcapDotNet.Packets.Gre
{
get
{
return GetHeaderLength(ChecksumPresent, KeyPresent, SequenceNumberPresent, Routing);
return GetHeaderLength(ChecksumPresent, KeyPresent, SequenceNumberPresent, AcknowledgmentSequenceNumberPresent, Routing);
}
}
......@@ -124,6 +128,17 @@ namespace PcapDotNet.Packets.Gre
get { return (byte)(this[Offset.RecursionControl] & Mask.RecursionControl); }
}
/// <summary>
/// Set to one (1) if packet contains Acknowledgment Number to be used for acknowledging previously transmitted data.
/// </summary>
public bool AcknowledgmentSequenceNumberPresent
{
get { return (this[Offset.AcknowledgmentSequenceNumberPresent] & Mask.AcknowledgmentSequenceNumberPresent) == Mask.AcknowledgmentSequenceNumberPresent; }
}
/// <summary>
/// Must be set to zero (0).
/// </summary>
public byte Flags
{
get { return (byte)((this[Offset.Flags] & Mask.Flags) >> Shift.Flags); }
......@@ -208,6 +223,16 @@ namespace PcapDotNet.Packets.Gre
get { return ReadUInt(OffsetKey, Endianity.Big); }
}
public ushort KeyPayloadLength
{
get { return ReadUShort(OffsetKeyPayloadLength, Endianity.Big); }
}
public ushort KeyCallId
{
get { return ReadUShort(OffsetKeyCallId, Endianity.Big); }
}
/// <summary>
/// The Sequence Number field contains an unsigned 32 bit integer which is inserted by the encapsulator.
/// It may be used by the receiver to establish the order in which packets have been transmitted from the encapsulator to the receiver.
......@@ -217,6 +242,15 @@ namespace PcapDotNet.Packets.Gre
get { return ReadUInt(OffsetSequenceNumber, Endianity.Big); }
}
/// <summary>
/// Contains the sequence number of the highest numbered GRE packet received by the sending peer for this user session.
/// Present if A bit (Bit 8) is one (1).
/// </summary>
public uint AcknowledgmentSequenceNumber
{
get { return ReadUInt(OffsetAcknowledgmentSequenceNumber, Endianity.Big); }
}
/// <summary>
/// The Routing field is optional and is present only if the Routing Present bit is set to 1.
/// The Routing field is a list of Source Route Entries (SREs).
......@@ -263,6 +297,7 @@ namespace PcapDotNet.Packets.Gre
Checksum = ChecksumPresent ? (ushort?)Checksum : null,
Key = KeyPresent ? (uint?)Key : null,
SequenceNumber = SequenceNumberPresent ? (uint?)SequenceNumber : null,
AcknowledgmentSequenceNumber = AcknowledgmentSequenceNumberPresent ? (uint?)AcknowledgmentSequenceNumber : null,
Routing = RoutingPresent ? Routing : null,
RoutingOffset = RoutingPresent ? (ushort?)RoutingOffset : null,
StrictSourceRoute = StrictSourceRoute,
......@@ -271,7 +306,10 @@ namespace PcapDotNet.Packets.Gre
protected override bool CalculateIsValid()
{
return (Length >= HeaderMinimumLength && Length >= HeaderLength && IsValidRouting && (!ChecksumPresent || IsChecksumCorrect));
return (Length >= HeaderMinimumLength && Length >= HeaderLength &&
IsValidRouting && Flags == 0 &&
(Version == GreVersion.EnhancedGre || Version == GreVersion.Gre && !AcknowledgmentSequenceNumberPresent) &&
(!ChecksumPresent || IsChecksumCorrect));
}
internal GreDatagram(byte[] buffer, int offset, int length)
......@@ -279,18 +317,19 @@ namespace PcapDotNet.Packets.Gre
{
}
internal static int GetHeaderLength(bool isChecksumPresent, bool isKeyPresent, bool isSequenceNumberPresent, IEnumerable<GreSourceRouteEntry> routing)
internal static int GetHeaderLength(bool isChecksumPresent, bool isKeyPresent, bool isSequenceNumberPresent, bool isAcknowledgmentSequenceNumberPresent, IEnumerable<GreSourceRouteEntry> routing)
{
return HeaderMinimumLength +
(isChecksumPresent || routing != null ? sizeof(ushort) + sizeof(ushort) : 0) +
(isKeyPresent ? sizeof(uint) : 0) +
(isSequenceNumberPresent ? sizeof(uint) : 0) +
(isAcknowledgmentSequenceNumberPresent ? sizeof(uint) : 0) +
(routing != null ? routing.Sum(entry => entry.Length) + GreSourceRouteEntry.HeaderLength : 0);
}
internal static void WriteHeader(byte[] buffer, int offset,
byte recursionControl, byte flags, GreVersion version, EthernetType protocolType,
bool checksumPresent, uint? key, uint? sequenceNumber,
bool checksumPresent, uint? key, uint? sequenceNumber, uint? acknowledgmentSequenceNumber,
ReadOnlyCollection<GreSourceRouteEntry> routing, ushort? routingOffset, bool strictSourceRoute)
{
buffer.Write(offset + Offset.ChecksumPresent,
......@@ -301,7 +340,9 @@ namespace PcapDotNet.Packets.Gre
(strictSourceRoute ? Mask.StrictSourceRoute : (byte)0) |
(recursionControl & Mask.RecursionControl)));
buffer.Write(offset + Offset.Flags, (byte)(((flags << Shift.Flags) & Mask.Flags) | ((byte)version & Mask.Version)));
buffer.Write(offset + Offset.Flags, (byte)((acknowledgmentSequenceNumber != null ? Mask.AcknowledgmentSequenceNumberPresent : (byte)0) |
((flags << Shift.Flags) & Mask.Flags) |
((byte)version & Mask.Version)));
buffer.Write(offset + Offset.ProtocolType, (ushort)protocolType, Endianity.Big);
......@@ -320,6 +361,9 @@ namespace PcapDotNet.Packets.Gre
if (sequenceNumber != null)
buffer.Write(ref offset, sequenceNumber.Value, Endianity.Big);
if (acknowledgmentSequenceNumber != null)
buffer.Write(ref offset, acknowledgmentSequenceNumber.Value, Endianity.Big);
if (routing != null)
{
foreach (GreSourceRouteEntry entry in routing)
......@@ -342,16 +386,31 @@ namespace PcapDotNet.Packets.Gre
get { return HeaderMinimumLength + ((ChecksumPresent || RoutingPresent) ? sizeof(ushort) + sizeof(ushort) : 0); }
}
private int OffsetKeyPayloadLength
{
get { return OffsetKey; }
}
private int OffsetKeyCallId
{
get { return OffsetKey + sizeof(ushort); }
}
private int OffsetSequenceNumber
{
get { return OffsetKey + (KeyPresent ? sizeof(uint) : 0); }
}
private int OffsetRouting
private int OffsetAcknowledgmentSequenceNumber
{
get { return OffsetSequenceNumber + (SequenceNumberPresent ? sizeof(uint) : 0); }
}
private int OffsetRouting
{
get { return OffsetAcknowledgmentSequenceNumber + (AcknowledgmentSequenceNumberPresent ? sizeof(uint) : 0); }
}
private void TryParseRouting()
{
if (_routing != null || !RoutingPresent)
......
......@@ -16,6 +16,7 @@ namespace PcapDotNet.Packets.Gre
public ushort? Checksum { get; set; }
public uint? Key { get; set; }
public uint? SequenceNumber { get; set; }
public uint? AcknowledgmentSequenceNumber { get; set; }
public ushort? RoutingOffset { get; set; }
public ReadOnlyCollection<GreSourceRouteEntry> Routing { get; set; }
public bool StrictSourceRoute { get; set; }
......@@ -24,13 +25,13 @@ namespace PcapDotNet.Packets.Gre
{
get
{
return GreDatagram.GetHeaderLength(ChecksumPresent, Key != null, SequenceNumber != null, Routing);
return GreDatagram.GetHeaderLength(ChecksumPresent, Key != null, SequenceNumber != null, AcknowledgmentSequenceNumber != null, Routing);
}
}
public override void Write(byte[] buffer, int offset, int payloadLength, ILayer previousLayer, ILayer nextLayer)
{
GreDatagram.WriteHeader(buffer, offset, RecursionControl, Flags, Version, ProtocolType, ChecksumPresent, Key, SequenceNumber, Routing, RoutingOffset, StrictSourceRoute);
GreDatagram.WriteHeader(buffer, offset, RecursionControl, Flags, Version, ProtocolType, ChecksumPresent, Key, SequenceNumber, AcknowledgmentSequenceNumber, Routing, RoutingOffset, StrictSourceRoute);
}
public override void Finalize(byte[] buffer, int offset, int payloadLength, ILayer nextLayer)
......@@ -50,6 +51,7 @@ namespace PcapDotNet.Packets.Gre
(Checksum == null ? other.Checksum == null : Checksum.Equals(other.Checksum)) &&
(Key == null ? other.Key == null : Key.Equals(other.Key)) &&
(SequenceNumber == null ? other.SequenceNumber == null : SequenceNumber.Equals(other.SequenceNumber)) &&
(AcknowledgmentSequenceNumber == null ? other.AcknowledgmentSequenceNumber == null : AcknowledgmentSequenceNumber.Equals(other.AcknowledgmentSequenceNumber)) &&
(RoutingOffset == null ? other.RoutingOffset == null : RoutingOffset.Equals(other.RoutingOffset)) &&
(Routing == null ? other.Routing == null : Routing.SequenceEqual(other.Routing)) &&
StrictSourceRoute.Equals(other.StrictSourceRoute);
......
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