Commit c17d49be authored by Brickner_cp's avatar Brickner_cp

IGMP

parent 45344f31
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace PcapDotNet.Base
{
public static class MoreTimeSpan
{
public static TimeSpan Divide(this TimeSpan timeSpan, double value)
{
return TimeSpan.FromTicks((long)(timeSpan.Ticks / value));
}
}
}
\ No newline at end of file
......@@ -62,6 +62,7 @@
<Compile Include="MoreIEnumerable.cs" />
<Compile Include="MoreIList.cs" />
<Compile Include="MorePropertyInfo.cs" />
<Compile Include="MoreTimeSpan.cs" />
<Compile Include="MoreType.cs" />
<Compile Include="Tuple.cs" />
<Compile Include="UInt24.cs" />
......
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.TestUtils;
using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.Test
{
/// <summary>
/// Summary description for UdpTests
/// </summary>
[TestClass]
public class IgmpTests
{
public IgmpTests()
{
//
// TODO: Add constructor logic here
//
}
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void RandomIgmpTest()
{
MacAddress ethernetSource = new MacAddress("00:01:02:03:04:05");
MacAddress ethernetDestination = new MacAddress("A0:A1:A2:A3:A4:A5");
Random random = new Random();
byte ipV4TypeOfService = random.NextByte();
ushort ipV4Identification = random.NextUShort();
byte ipV4Ttl = random.NextByte();
IpV4FragmentationOptions ipV4FragmentationOptions = random.NextEnum<IpV4FragmentationOptions>();
ushort ipV4FragmentationOffset = (ushort)(random.NextUShort(ushort.MaxValue / 8) * 8);
IpV4Fragmentation ipV4Fragmentation = new IpV4Fragmentation(ipV4FragmentationOptions, ipV4FragmentationOffset);
IpV4Address ipV4Source = new IpV4Address(random.NextUInt());
IpV4Address ipV4Destination = new IpV4Address(random.NextUInt());
IpV4Options ipV4Options = random.NextIpV4Options();
for (int i = 0; i != 1000; ++i)
{
IgmpMessageType igmpMessageType = random.NextEnum(IgmpMessageType.None);
IgmpQueryVersion igmpQueryVersion = IgmpQueryVersion.None;
TimeSpan igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(256 * 0.1) - TimeSpan.FromTicks(1));
IpV4Address igmpGroupAddress = random.NextIpV4Address();
bool? igmpIsSuppressRouterSideProcessing = null;
byte? igmpQueryRobustnessVariable = null;
TimeSpan? igmpQueryInterval = null;
IpV4Address[] igmpSourceAddresses = null;
Packet packet;
switch (igmpMessageType)
{
case IgmpMessageType.MembershipQuery:
igmpQueryVersion = random.NextEnum(IgmpQueryVersion.None, IgmpQueryVersion.Unknown);
switch (igmpQueryVersion)
{
case IgmpQueryVersion.Version1:
igmpMaxResponseTime = TimeSpan.Zero;
packet = PacketBuilder.EthernetIpV4IgmpQueryVersion1(DateTime.Now,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
ipV4Source, ipV4Destination, ipV4Options,
igmpGroupAddress);
break;
case IgmpQueryVersion.Version2:
packet = PacketBuilder.EthernetIpV4IgmpQueryVersion2(DateTime.Now,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
ipV4Source, ipV4Destination, ipV4Options,
igmpMaxResponseTime, igmpGroupAddress);
break;
case IgmpQueryVersion.Version3:
igmpIsSuppressRouterSideProcessing = random.NextBool();
igmpQueryRobustnessVariable = random.NextByte(8);
igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1),
IgmpDatagram.MaxVersion3MaxResponseTime - TimeSpan.FromTicks(1));
igmpQueryInterval = random.NextTimeSpan(TimeSpan.Zero, IgmpDatagram.MaxVersion3QueryInterval - TimeSpan.FromTicks(1));
igmpSourceAddresses = new IpV4Address[random.Next(1000)];
for (int sourceAddressIndex = 0; sourceAddressIndex != igmpSourceAddresses.Length; ++sourceAddressIndex)
igmpSourceAddresses[sourceAddressIndex] = random.NextIpV4Address();
packet = PacketBuilder.EthernetIpV4IgmpQueryVersion3(DateTime.Now,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
ipV4Source, ipV4Destination, ipV4Options,
igmpMaxResponseTime, igmpGroupAddress,
igmpIsSuppressRouterSideProcessing.Value,
igmpQueryRobustnessVariable.Value, igmpQueryInterval.Value,
igmpSourceAddresses);
break;
default:
continue;
}
break;
case IgmpMessageType.MembershipReportVersion1:
igmpMaxResponseTime = TimeSpan.Zero;
packet = PacketBuilder.EthernetIpV4IgmpReportVersion1(DateTime.Now,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
ipV4Source, ipV4Destination, ipV4Options,
igmpGroupAddress);
break;
case IgmpMessageType.MembershipReportVersion2:
packet = PacketBuilder.EthernetIpV4IgmpReportVersion2(DateTime.Now,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
ipV4Source, ipV4Destination, ipV4Options,
igmpMaxResponseTime, igmpGroupAddress);
break;
case IgmpMessageType.LeaveGroupVersion2:
packet = PacketBuilder.EthernetIpV4IgmpLeaveGroupVersion2(DateTime.Now,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation, ipV4Ttl,
ipV4Source, ipV4Destination, ipV4Options,
igmpMaxResponseTime, igmpGroupAddress);
break;
default:
continue;
}
Assert.IsTrue(packet.IsValid, "IsValid");
// IGMP
Assert.IsTrue(packet.Ethernet.IpV4.Igmp.IsChecksumCorrect);
Assert.AreEqual(igmpMessageType, packet.Ethernet.IpV4.Igmp.MessageType);
Assert.AreEqual(igmpQueryVersion, packet.Ethernet.IpV4.Igmp.QueryVersion);
MoreAssert.IsInRange(igmpMaxResponseTime.Divide(2), igmpMaxResponseTime,
packet.Ethernet.IpV4.Igmp.MaxResponseTime, "MaxResponseTime");
Assert.AreEqual(igmpGroupAddress, packet.Ethernet.IpV4.Igmp.GroupAddress);
// Query Version 3
if (packet.Ethernet.IpV4.Igmp.QueryVersion == IgmpQueryVersion.Version3)
{
Assert.AreEqual(igmpIsSuppressRouterSideProcessing.Value, packet.Ethernet.IpV4.Igmp.IsSuppressRouterSideProcessing,
"IsSuppressRouterSideProcessing");
MoreAssert.IsInRange(igmpQueryInterval.Value.Divide(2), igmpQueryInterval.Value, packet.Ethernet.IpV4.Igmp.QueryInterval);
Assert.AreEqual(igmpQueryRobustnessVariable, packet.Ethernet.IpV4.Igmp.QueryRobustnessVariable);
Assert.AreEqual(igmpSourceAddresses.Length, packet.Ethernet.IpV4.Igmp.NumberOfSources);
MoreAssert.AreSequenceEqual(igmpSourceAddresses, packet.Ethernet.IpV4.Igmp.SourceAddresses);
}
}
}
}
}
\ No newline at end of file
......@@ -49,6 +49,7 @@
<Compile Include="DataLinkTests.cs" />
<Compile Include="EndianitiyTests.cs" />
<Compile Include="EthernetTests.cs" />
<Compile Include="IgmpTests.cs" />
<Compile Include="IpV4Tests.cs" />
<Compile Include="MacAddressTests.cs" />
<Compile Include="PacketTests.cs" />
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using PcapDotNet.Packets.IpV4;
......@@ -109,12 +110,22 @@ namespace PcapDotNet.Packets.Igmp
public const int GroupRecords = 8;
}
public static TimeSpan MaxVersion3MaxResponseTime
{
get { return _maxVersion3MaxResponseTime; }
}
public static TimeSpan MaxVersion3QueryInterval
{
get { return _maxVersion3QueryInterval; }
}
/// <summary>
/// The type of the IGMP message of concern to the host-router interaction.
/// </summary>
public IgmpType MessageType
public IgmpMessageType MessageType
{
get { return (IgmpType)this[Offset.MessageType]; }
get { return (IgmpMessageType)this[Offset.MessageType]; }
}
/// <summary>
......@@ -131,7 +142,7 @@ namespace PcapDotNet.Packets.Igmp
{
get
{
if (MessageType != IgmpType.MembershipQuery)
if (MessageType != IgmpMessageType.MembershipQuery)
return IgmpQueryVersion.None;
if (Length >= QueryVersion3HeaderLength)
......@@ -197,7 +208,7 @@ namespace PcapDotNet.Packets.Igmp
{
byte maxResponseCode = MaxResponseCode;
int numTenthOfASecond =
((maxResponseCode < 128 || MessageType != IgmpType.MembershipQuery || QueryVersion != IgmpQueryVersion.Version3)
((maxResponseCode < 128 || MessageType != IgmpMessageType.MembershipQuery || QueryVersion != IgmpQueryVersion.Version3)
? maxResponseCode
: CodeToValue(maxResponseCode));
......@@ -350,11 +361,16 @@ namespace PcapDotNet.Packets.Igmp
public ReadOnlyCollection<IpV4Address> SourceAddresses
{
get
{
if (_sourceAddresses == null)
{
IpV4Address[] sourceAddresses = new IpV4Address[NumberOfSources];
for (int i = 0; i != sourceAddresses.Length; ++i)
sourceAddresses[i] = ReadIpV4Address(Offset.SourceAddresses + 4 * i, Endianity.Big);
return new ReadOnlyCollection<IpV4Address>(sourceAddresses);
sourceAddresses[i] = ReadIpV4Address(Offset.SourceAddresses + IpV4Address.SizeOf * i, Endianity.Big);
_sourceAddresses = new ReadOnlyCollection<IpV4Address>(sourceAddresses);
}
return _sourceAddresses;
}
}
......@@ -369,9 +385,14 @@ namespace PcapDotNet.Packets.Igmp
get { return ReadUShort(Offset.NumberOfGroupRecords, Endianity.Big); }
}
/// <summary>
/// Each Group Record is a block of fields containing information pertaining to the sender's membership in a single multicast group on the interface from which the Report is sent.
/// </summary>
public ReadOnlyCollection<IgmpGroupRecordDatagram> GroupRecords
{
get
{
if (_groupRecords == null)
{
IgmpGroupRecordDatagram[] groupRecords = new IgmpGroupRecordDatagram[NumberOfGroupRecords];
int offset = StartOffset + Offset.GroupRecords;
......@@ -381,7 +402,10 @@ namespace PcapDotNet.Packets.Igmp
offset += groupRecords[i].Length;
}
return new ReadOnlyCollection<IgmpGroupRecordDatagram>(groupRecords);
_groupRecords = new ReadOnlyCollection<IgmpGroupRecordDatagram>(groupRecords);
}
return _groupRecords;
}
}
......@@ -390,6 +414,71 @@ namespace PcapDotNet.Packets.Igmp
{
}
internal static int GetQueryVersion3Length(int numSourceAddresses)
{
return QueryVersion3HeaderLength + IpV4Address.SizeOf * numSourceAddresses;
}
internal static void WriteHeader(byte[] buffer, int offset,
IgmpMessageType igmpMessageType, TimeSpan maxResponseTime, IpV4Address groupAddress)
{
buffer.Write(offset + Offset.MessageType, (byte)igmpMessageType);
double numTenthOfASecond = (maxResponseTime.TotalSeconds * 10);
if (numTenthOfASecond >= 256 || numTenthOfASecond < 0)
throw new ArgumentOutOfRangeException("maxResponseTime", maxResponseTime, "must be in the range [" + TimeSpan.Zero + ", " + TimeSpan.FromSeconds(255 * 0.1) + "]");
buffer.Write(offset + Offset.MaxResponseCode, (byte)numTenthOfASecond);
buffer.Write(offset + Offset.GroupAddress, groupAddress, Endianity.Big);
buffer.Write(offset + Offset.Checksum, Sum16BitsToChecksum(Sum16Bits(buffer, offset, HeaderLength)), Endianity.Big);
}
internal static void WriteQueryVersion3(byte[] buffer, int offset,
TimeSpan maxResponseTime, IpV4Address groupAddress,
bool isSuppressRouterSideProcessing, byte queryRobustnessVariable, TimeSpan queryInterval,
IEnumerable<IpV4Address> sourceAddresses)
{
// MessageType
buffer.Write(offset + Offset.MessageType, (byte)IgmpMessageType.MembershipQuery);
// MaxResponseCode
if (maxResponseTime < TimeSpan.Zero || maxResponseTime > MaxVersion3MaxResponseTime)
throw new ArgumentOutOfRangeException("maxResponseTime", maxResponseTime, "must be in the range [" + TimeSpan.Zero + ", " + MaxVersion3MaxResponseTime + "]");
double maxResponseTimeTenthOfASecond = maxResponseTime.TotalSeconds * 10;
byte maxResponseCode = (byte)(maxResponseTimeTenthOfASecond < 128 ? maxResponseTimeTenthOfASecond : ValueToCode((int)maxResponseTimeTenthOfASecond));
buffer.Write(offset + Offset.MaxResponseCode, maxResponseCode);
// GroupAddress
buffer.Write(offset + Offset.GroupAddress, groupAddress, Endianity.Big);
// IsSuppressRouterSideProcessing and QueryRobustnessVariable
if (queryRobustnessVariable > 0x07)
throw new ArgumentOutOfRangeException("queryRobustnessVariable", queryRobustnessVariable, "must be in range [0, 7]");
buffer.Write(offset + Offset.QueryRobustnessVariable, (byte)(queryRobustnessVariable | (isSuppressRouterSideProcessing ? 0x10 : 0x00)));
// QueryIntervalCode
if (queryInterval < TimeSpan.Zero || queryInterval > MaxVersion3QueryInterval)
throw new ArgumentOutOfRangeException("queryInterval", maxResponseTime, "must be in the range [" + TimeSpan.Zero + ", " + MaxVersion3QueryInterval + "]");
double queryIntervalTenthOfASecond = queryInterval.TotalSeconds;
byte queryIntervalCode = (byte)(queryIntervalTenthOfASecond < 128 ? queryIntervalTenthOfASecond : ValueToCode((int)queryIntervalTenthOfASecond));
buffer.Write(offset + Offset.QueryIntervalCode, queryIntervalCode);
// SourceAddresses
int numSourceAddresses = 0;
foreach (IpV4Address sourceAddress in sourceAddresses)
{
buffer.Write(offset + Offset.SourceAddresses + IpV4Address.SizeOf * numSourceAddresses, sourceAddress, Endianity.Big);
++numSourceAddresses;
}
// NumberOfSources
buffer.Write(offset + Offset.NumberOfSources, (ushort)numSourceAddresses, Endianity.Big);
// Checksum
buffer.Write(offset + Offset.Checksum, Sum16BitsToChecksum(Sum16Bits(buffer, offset, QueryVersion3HeaderLength + IpV4Address.SizeOf * numSourceAddresses)), Endianity.Big);
}
protected override bool CalculateIsValid()
{
if (Length < HeaderLength || !IsChecksumCorrect)
......@@ -397,7 +486,7 @@ namespace PcapDotNet.Packets.Igmp
switch (MessageType)
{
case IgmpType.MembershipQuery:
case IgmpMessageType.MembershipQuery:
switch (QueryVersion)
{
case IgmpQueryVersion.Version1:
......@@ -408,21 +497,21 @@ namespace PcapDotNet.Packets.Igmp
case IgmpQueryVersion.Version3:
return Length >= QueryVersion3HeaderLength &&
Length == QueryVersion3HeaderLength + 4 * NumberOfSources &&
Length == GetQueryVersion3Length(NumberOfSources) &&
NumberOfSources == SourceAddresses.Count;
default:
return false;
}
case IgmpType.MembershipReportVersion1:
case IgmpMessageType.MembershipReportVersion1:
return Length == HeaderLength && MaxResponseCode == 0;
case IgmpType.LeaveGroupVersion2:
case IgmpType.MembershipReportVersion2:
case IgmpMessageType.LeaveGroupVersion2:
case IgmpMessageType.MembershipReportVersion2:
return Length == HeaderLength;
case IgmpType.MembershipReportVersion3:
case IgmpMessageType.MembershipReportVersion3:
return MaxResponseCode == 0 && NumberOfGroupRecords == GroupRecords.Count &&
Length == HeaderLength + GroupRecords.Sum(record => record.Length) &&
GroupRecords.All(record => record.IsValid);
......@@ -457,6 +546,24 @@ namespace PcapDotNet.Packets.Igmp
return (mant | 0x10) << (exp + 3);
}
private static byte ValueToCode(int value)
{
int exp = (int)(Math.Log(value, 2) - 7);
if (exp > 7 || exp < 0)
throw new ArgumentOutOfRangeException("exp", exp, "value " + value + " is out of range");
int mant = (int)(value * Math.Pow(2, -exp - 3) - 16);
if (mant > 15 || mant < 0)
throw new ArgumentOutOfRangeException("mant", mant, "value " + value + " is out of range");
return (byte)(0x80 | (exp << 4) | mant);
}
private static readonly TimeSpan _maxVersion3MaxResponseTime = TimeSpan.FromSeconds(0.1 * CodeToValue(byte.MaxValue)) + TimeSpan.FromSeconds(0.1) - TimeSpan.FromTicks(1);
private static readonly TimeSpan _maxVersion3QueryInterval = TimeSpan.FromSeconds(CodeToValue(byte.MaxValue)) + TimeSpan.FromSeconds(1) - TimeSpan.FromTicks(1);
private bool? _isChecksumCorrect;
private ReadOnlyCollection<IpV4Address> _sourceAddresses;
private ReadOnlyCollection<IgmpGroupRecordDatagram> _groupRecords;
}
}
\ No newline at end of file
......@@ -48,6 +48,9 @@ namespace PcapDotNet.Packets.Igmp
public const int HeaderMinimumLength = 8;
/// <summary>
/// The type of group record included in the report message.
/// </summary>
public IgmpRecordType RecordType
{
get { return (IgmpRecordType)this[Offset.RecordType]; }
......
namespace PcapDotNet.Packets.Igmp
{
public enum IgmpType : byte
public enum IgmpMessageType : byte
{
/// <summary>
/// Illegal type.
......
......@@ -13,6 +13,19 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
public const int SizeOf = sizeof(uint);
/// <summary>
/// The zero address (0.0.0.0).
/// </summary>
public static IpV4Address Zero
{
get { return _zero; }
}
public static IpV4Address AllHostsHroupAddress
{
get { return _allHostsHroupAddress; }
}
/// <summary>
/// Create an address from a 32 bit integer.
/// 0 -> 0.0.0.0
......@@ -36,14 +49,6 @@ namespace PcapDotNet.Packets.IpV4
(byte.Parse(values[3], CultureInfo.InvariantCulture)));
}
/// <summary>
/// The zero address (0.0.0.0).
/// </summary>
public static IpV4Address Zero
{
get { return _zero; }
}
/// <summary>
/// Gets the address valud as a 32 bit integer.
/// </summary>
......@@ -113,5 +118,6 @@ namespace PcapDotNet.Packets.IpV4
private readonly uint _value;
private static readonly IpV4Address _zero = new IpV4Address(0);
private static readonly IpV4Address _allHostsHroupAddress = new IpV4Address("224.0.0.1");
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using PcapDotNet.Packets.Arp;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
......@@ -103,7 +106,261 @@ namespace PcapDotNet.Packets
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options, ipV4Payload.Length);
ipV4Payload.Write(buffer, EthernetDatagram.HeaderLength + ipHeaderLength);
return new Packet(buffer, timestamp, new DataLink(DataLinkKind.Ethernet));
return new Packet(buffer, timestamp, DataLinkKind.Ethernet);
}
/// <summary>
/// Builds an IGMP query version 1 over IPv4 over Ethernet packet.
/// </summary>
/// <param name="timestamp">The packet timestamp.</param>
/// <param name="ethernetSource">The ethernet source mac address.</param>
/// <param name="ethernetDestination">The ethernet destination mac address.</param>
/// <param name="ipV4TypeOfService">The IPv4 Type of Service.</param>
/// <param name="ipV4Identification">The IPv4 Identification.</param>
/// <param name="ipV4Fragmentation">The IPv4 Fragmentation.</param>
/// <param name="ipV4Ttl">The IPv4 TTL.</param>
/// <param name="ipV4SourceAddress">The IPv4 source address.</param>
/// <param name="ipV4DestinationAddress">The IPv4 destination address.</param>
/// <param name="ipV4Options">The IPv4 options.</param>
/// <param name="igmpGroupAddress">
/// The Group Address field is set to zero when sending a General Query,
/// and set to the IP multicast address being queried when sending a Group-Specific Query or Group-and-Source-Specific Query.
/// In a Membership Report of version 1 or 2 or Leave Group message, the group address field holds the IP multicast group address of the group being reported or left.
/// In a Membership Report of version 3 this field is meaningless.
/// </param>
/// <returns>A packet with an IGMP query version 1 over IPv4 over Ethernet datagram.</returns>
public static Packet EthernetIpV4IgmpQueryVersion1(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
byte ipV4Ttl,
IpV4Address ipV4SourceAddress, IpV4Address ipV4DestinationAddress,
IpV4Options ipV4Options,
IpV4Address igmpGroupAddress)
{
return EthernetIpV4Igmp(timestamp,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation,
ipV4Ttl,
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options,
IgmpMessageType.MembershipQuery, TimeSpan.Zero, igmpGroupAddress);
}
/// <summary>
/// Builds an IGMP report version 1 over IPv4 over Ethernet packet.
/// </summary>
/// <param name="timestamp">The packet timestamp.</param>
/// <param name="ethernetSource">The ethernet source mac address.</param>
/// <param name="ethernetDestination">The ethernet destination mac address.</param>
/// <param name="ipV4TypeOfService">The IPv4 Type of Service.</param>
/// <param name="ipV4Identification">The IPv4 Identification.</param>
/// <param name="ipV4Fragmentation">The IPv4 Fragmentation.</param>
/// <param name="ipV4Ttl">The IPv4 TTL.</param>
/// <param name="ipV4SourceAddress">The IPv4 source address.</param>
/// <param name="ipV4DestinationAddress">The IPv4 destination address.</param>
/// <param name="ipV4Options">The IPv4 options.</param>
/// <param name="igmpGroupAddress">
/// The Group Address field is set to zero when sending a General Query,
/// and set to the IP multicast address being queried when sending a Group-Specific Query or Group-and-Source-Specific Query.
/// In a Membership Report of version 1 or 2 or Leave Group message, the group address field holds the IP multicast group address of the group being reported or left.
/// In a Membership Report of version 3 this field is meaningless.
/// </param>
/// <returns>A packet with an IGMP report version 1 over IPv4 over Ethernet datagram.</returns>
public static Packet EthernetIpV4IgmpReportVersion1(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
byte ipV4Ttl,
IpV4Address ipV4SourceAddress, IpV4Address ipV4DestinationAddress,
IpV4Options ipV4Options,
IpV4Address igmpGroupAddress)
{
return EthernetIpV4Igmp(timestamp,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation,
ipV4Ttl,
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options,
IgmpMessageType.MembershipReportVersion1, TimeSpan.Zero, igmpGroupAddress);
}
/// <summary>
/// Builds an IGMP query version 2 over IPv4 over Ethernet packet.
/// </summary>
/// <param name="timestamp">The packet timestamp.</param>
/// <param name="ethernetSource">The ethernet source mac address.</param>
/// <param name="ethernetDestination">The ethernet destination mac address.</param>
/// <param name="ipV4TypeOfService">The IPv4 Type of Service.</param>
/// <param name="ipV4Identification">The IPv4 Identification.</param>
/// <param name="ipV4Fragmentation">The IPv4 Fragmentation.</param>
/// <param name="ipV4Ttl">The IPv4 TTL.</param>
/// <param name="ipV4SourceAddress">The IPv4 source address.</param>
/// <param name="ipV4DestinationAddress">The IPv4 destination address.</param>
/// <param name="ipV4Options">The IPv4 options.</param>
/// <param name="igmpMaxResponseTime">The actual time allowed.</param>
/// <param name="igmpGroupAddress">
/// The Group Address field is set to zero when sending a General Query,
/// and set to the IP multicast address being queried when sending a Group-Specific Query or Group-and-Source-Specific Query.
/// In a Membership Report of version 1 or 2 or Leave Group message, the group address field holds the IP multicast group address of the group being reported or left.
/// In a Membership Report of version 3 this field is meaningless.
/// </param>
/// <returns>A packet with an IGMP query version 2 over IPv4 over Ethernet datagram.</returns>
public static Packet EthernetIpV4IgmpQueryVersion2(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
byte ipV4Ttl,
IpV4Address ipV4SourceAddress, IpV4Address ipV4DestinationAddress,
IpV4Options ipV4Options,
TimeSpan igmpMaxResponseTime, IpV4Address igmpGroupAddress)
{
return EthernetIpV4Igmp(timestamp,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation,
ipV4Ttl,
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options,
IgmpMessageType.MembershipQuery, igmpMaxResponseTime, igmpGroupAddress);
}
/// <summary>
/// Builds an IGMP report version 2 over IPv4 over Ethernet packet.
/// </summary>
/// <param name="timestamp">The packet timestamp.</param>
/// <param name="ethernetSource">The ethernet source mac address.</param>
/// <param name="ethernetDestination">The ethernet destination mac address.</param>
/// <param name="ipV4TypeOfService">The IPv4 Type of Service.</param>
/// <param name="ipV4Identification">The IPv4 Identification.</param>
/// <param name="ipV4Fragmentation">The IPv4 Fragmentation.</param>
/// <param name="ipV4Ttl">The IPv4 TTL.</param>
/// <param name="ipV4SourceAddress">The IPv4 source address.</param>
/// <param name="ipV4DestinationAddress">The IPv4 destination address.</param>
/// <param name="ipV4Options">The IPv4 options.</param>
/// <param name="igmpMaxResponseTime">The actual time allowed.</param>
/// <param name="igmpGroupAddress">
/// The Group Address field is set to zero when sending a General Query,
/// and set to the IP multicast address being queried when sending a Group-Specific Query or Group-and-Source-Specific Query.
/// In a Membership Report of version 1 or 2 or Leave Group message, the group address field holds the IP multicast group address of the group being reported or left.
/// In a Membership Report of version 3 this field is meaningless.
/// </param>
/// <returns>A packet with an IGMP report version 2 over IPv4 over Ethernet datagram.</returns>
public static Packet EthernetIpV4IgmpReportVersion2(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
byte ipV4Ttl,
IpV4Address ipV4SourceAddress, IpV4Address ipV4DestinationAddress,
IpV4Options ipV4Options,
TimeSpan igmpMaxResponseTime, IpV4Address igmpGroupAddress)
{
return EthernetIpV4Igmp(timestamp,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation,
ipV4Ttl,
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options,
IgmpMessageType.MembershipReportVersion2, igmpMaxResponseTime, igmpGroupAddress);
}
/// <summary>
/// Builds an IGMP leave group version 2 over IPv4 over Ethernet packet.
/// </summary>
/// <param name="timestamp">The packet timestamp.</param>
/// <param name="ethernetSource">The ethernet source mac address.</param>
/// <param name="ethernetDestination">The ethernet destination mac address.</param>
/// <param name="ipV4TypeOfService">The IPv4 Type of Service.</param>
/// <param name="ipV4Identification">The IPv4 Identification.</param>
/// <param name="ipV4Fragmentation">The IPv4 Fragmentation.</param>
/// <param name="ipV4Ttl">The IPv4 TTL.</param>
/// <param name="ipV4SourceAddress">The IPv4 source address.</param>
/// <param name="ipV4DestinationAddress">The IPv4 destination address.</param>
/// <param name="ipV4Options">The IPv4 options.</param>
/// <param name="igmpMaxResponseTime">The actual time allowed.</param>
/// <param name="igmpGroupAddress">
/// The Group Address field is set to zero when sending a General Query,
/// and set to the IP multicast address being queried when sending a Group-Specific Query or Group-and-Source-Specific Query.
/// In a Membership Report of version 1 or 2 or Leave Group message, the group address field holds the IP multicast group address of the group being reported or left.
/// In a Membership Report of version 3 this field is meaningless.
/// </param>
/// <returns>A packet with an IGMP leave group version 2 over IPv4 over Ethernet datagram.</returns>
public static Packet EthernetIpV4IgmpLeaveGroupVersion2(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
byte ipV4Ttl,
IpV4Address ipV4SourceAddress, IpV4Address ipV4DestinationAddress,
IpV4Options ipV4Options,
TimeSpan igmpMaxResponseTime, IpV4Address igmpGroupAddress)
{
return EthernetIpV4Igmp(timestamp,
ethernetSource, ethernetDestination,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation,
ipV4Ttl,
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options,
IgmpMessageType.LeaveGroupVersion2, igmpMaxResponseTime, igmpGroupAddress);
}
/// <summary>
/// Builds an IGMP query version 3 over IPv4 over Ethernet packet.
/// </summary>
/// <param name="timestamp">The packet timestamp.</param>
/// <param name="ethernetSource">The ethernet source mac address.</param>
/// <param name="ethernetDestination">The ethernet destination mac address.</param>
/// <param name="ipV4TypeOfService">The IPv4 Type of Service.</param>
/// <param name="ipV4Identification">The IPv4 Identification.</param>
/// <param name="ipV4Fragmentation">The IPv4 Fragmentation.</param>
/// <param name="ipV4Ttl">The IPv4 TTL.</param>
/// <param name="ipV4SourceAddress">The IPv4 source address.</param>
/// <param name="ipV4DestinationAddress">The IPv4 destination address.</param>
/// <param name="ipV4Options">The IPv4 options.</param>
/// <param name="igmpMaxResponseTime">The actual time allowed.</param>
/// <param name="igmpGroupAddress">
/// The Group Address field is set to zero when sending a General Query,
/// and set to the IP multicast address being queried when sending a Group-Specific Query or Group-and-Source-Specific Query.
/// In a Membership Report of version 1 or 2 or Leave Group message, the group address field holds the IP multicast group address of the group being reported or left.
/// In a Membership Report of version 3 this field is meaningless.
/// </param>
/// <returns>A packet with an IGMP query version 3 over IPv4 over Ethernet datagram.</returns>
public static Packet EthernetIpV4IgmpQueryVersion3(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
byte ipV4Ttl,
IpV4Address ipV4SourceAddress, IpV4Address ipV4DestinationAddress,
IpV4Options ipV4Options,
TimeSpan igmpMaxResponseTime, IpV4Address igmpGroupAddress,
bool igmpIsSuppressRouterSideProcessing, byte igmpQueryRobustnessVariable,
TimeSpan igmpQueryInterval, IEnumerable<IpV4Address> igmpSourceAddresses)
{
int ipHeaderLength = IpV4Datagram.HeaderMinimumLength + ipV4Options.BytesLength;
byte[] buffer = new byte[EthernetDatagram.HeaderLength + ipHeaderLength + IgmpDatagram.GetQueryVersion3Length(igmpSourceAddresses.Count())];
EthernetDatagram.WriteHeader(buffer, 0, ethernetSource, ethernetDestination, EthernetType.IpV4);
IpV4Datagram.WriteHeader(buffer, EthernetDatagram.HeaderLength,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation,
ipV4Ttl, IpV4Protocol.InternetGroupManagementProtocol,
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options, IgmpDatagram.HeaderLength);
IgmpDatagram.WriteQueryVersion3(buffer, EthernetDatagram.HeaderLength + ipHeaderLength,
igmpMaxResponseTime, igmpGroupAddress, igmpIsSuppressRouterSideProcessing, igmpQueryRobustnessVariable,
igmpQueryInterval, igmpSourceAddresses);
return new Packet(buffer, timestamp, DataLinkKind.Ethernet);
}
private static Packet EthernetIpV4Igmp(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
byte ipV4Ttl,
IpV4Address ipV4SourceAddress, IpV4Address ipV4DestinationAddress,
IpV4Options ipV4Options,
IgmpMessageType igmpMessageType, TimeSpan igmpMaxResponseTime, IpV4Address igmpGroupAddress)
{
int ipHeaderLength = IpV4Datagram.HeaderMinimumLength + ipV4Options.BytesLength;
byte[] buffer = new byte[EthernetDatagram.HeaderLength + ipHeaderLength + IgmpDatagram.HeaderLength];
EthernetDatagram.WriteHeader(buffer, 0, ethernetSource, ethernetDestination, EthernetType.IpV4);
IpV4Datagram.WriteHeader(buffer, EthernetDatagram.HeaderLength,
ipV4TypeOfService, ipV4Identification, ipV4Fragmentation,
ipV4Ttl, IpV4Protocol.InternetGroupManagementProtocol,
ipV4SourceAddress, ipV4DestinationAddress,
ipV4Options, IgmpDatagram.HeaderLength);
IgmpDatagram.WriteHeader(buffer, EthernetDatagram.HeaderLength + ipHeaderLength,
igmpMessageType, igmpMaxResponseTime, igmpGroupAddress);
return new Packet(buffer, timestamp, DataLinkKind.Ethernet);
}
/// <summary>
......@@ -153,7 +410,7 @@ namespace PcapDotNet.Packets
if (udpCalculateChecksum)
IpV4Datagram.WriteTransportChecksum(buffer, EthernetDatagram.HeaderLength, ipV4HeaderLength, (ushort)transportLength, UdpDatagram.Offset.Checksum, true);
return new Packet(buffer, timestamp, new DataLink(DataLinkKind.Ethernet));
return new Packet(buffer, timestamp, DataLinkKind.Ethernet);
}
/// <summary>
......@@ -191,7 +448,6 @@ namespace PcapDotNet.Packets
TcpControlBits tcpControlBits, ushort tcpWindow, ushort tcpUrgentPointer,
TcpOptions tcpOptions,
Datagram tcpPayload)
{
int ipV4HeaderLength = IpV4Datagram.HeaderMinimumLength + ipV4Options.BytesLength;
int tcpHeaderLength = TcpDatagram.HeaderMinimumLength + tcpOptions.BytesLength;
......@@ -217,7 +473,7 @@ namespace PcapDotNet.Packets
IpV4Datagram.WriteTransportChecksum(buffer, EthernetDatagram.HeaderLength, ipV4HeaderLength, (ushort)transportLength, TcpDatagram.Offset.Checksum, false);
return new Packet(buffer, timestamp, new DataLink(DataLinkKind.Ethernet));
return new Packet(buffer, timestamp, DataLinkKind.Ethernet);
}
}
}
\ No newline at end of file
......@@ -75,7 +75,7 @@
<Compile Include="Igmp\IgmpGroupRecordDatagram.cs" />
<Compile Include="Igmp\IgmpQueryVersion.cs" />
<Compile Include="Igmp\IgmpRecordType.cs" />
<Compile Include="Igmp\IgmpType.cs" />
<Compile Include="Igmp\IgmpMessageType.cs" />
<Compile Include="IOptionUnknownFactory.cs" />
<Compile Include="IpV4\IpV4OptionUnknown.cs" />
<Compile Include="Option.cs" />
......
......@@ -101,6 +101,11 @@ namespace PcapDotNet.TestUtils
return random.NextDateTime(DateTime.MinValue, DateTime.MaxValue);
}
public static TimeSpan NextTimeSpan(this Random random, TimeSpan minimumValue, TimeSpan maximumValue)
{
return TimeSpan.FromTicks(random.NextLong(minimumValue.Ticks, maximumValue.Ticks + 1));
}
public static T NextEnum<T>(this Random random, IEnumerable<T> valuesToIgnore)
{
Type type = typeof(T);
......
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