Commit 32469b4d authored by Brickner_cp's avatar Brickner_cp

IGMP

parent acbfb27f
......@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets
{
......@@ -198,6 +199,35 @@ namespace PcapDotNet.Packets
return Buffer.ReadMacAddress(StartOffset + offset, endianity);
}
protected IpV4Address ReadIpV4Address(int offset, Endianity endianity)
{
return Buffer.ReadIpV4Address(StartOffset + offset, endianity);
}
protected static ushort Sum16BitsToChecksum(uint sum)
{
// Take only 16 bits out of the 32 bit sum and add up the carrier.
// if the results overflows - do it again.
while (sum > 0xFFFF)
sum = (sum & 0xFFFF) + (sum >> 16);
// one's complement the result
sum = ~sum;
return (ushort)sum;
}
protected static uint Sum16Bits(byte[] buffer, int offset, int length)
{
int endOffset = offset + length;
uint sum = 0;
while (offset < endOffset - 1)
sum += buffer.ReadUShort(ref offset, Endianity.Big);
if (offset < endOffset)
sum += (ushort)(buffer[offset] << 8);
return sum;
}
private static readonly Datagram _empty = new Datagram(new byte[0], 0, 0);
private readonly byte[] _buffer;
private readonly int _startOffset;
......
using System;
using System.Collections.ObjectModel;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.Igmp
{
/// <summary>
/// Version 1 (query or report):
/// <pre>
/// +-----+---------+------+--------+----------+
/// | Bit | 0-3 | 4-7 | 8-15 | 16-31 |
/// +-----+---------+------+--------+----------+
/// | 0 | Version | Type | Unused | Checksum |
/// +-----+---------+------+--------+----------+
/// | 32 | Group Address |
/// +-----+------------------------------------+
/// </pre>
///
/// Version 2 (query, report or leave group):
/// <pre>
/// +-----+------+---------------+----------+
/// | Bit | 0-7 | 8-15 | 16-31 |
/// +-----+------+---------------+----------+
/// | 0 | Type | Max Resp Time | Checksum |
/// +-----+------+---------------+----------+
/// | 32 | Group Address |
/// +-----+---------------------------------+
/// </pre>
///
/// Version 3 query:
/// <pre>
/// +-----+------+---+-----+---------------+-----------------------+
/// | Bit | 0-3 | 4 | 5-7 | 8-15 | 16-31 |
/// +-----+------+---+-----+---------------+-----------------------+
/// | 0 | Type = 0x11 | Max Resp Code | Checksum |
/// +-----+----------------+---------------+-----------------------+
/// | 32 | Group Address |
/// +-----+------+---+-----+---------------+-----------------------+
/// | 64 | Resv | S | QRV | QQIC | Number of Sources (N) |
/// +-----+------+---+-----+---------------+-----------------------+
/// | 96 | Source Address [1] |
/// +-----+--------------------------------------------------------+
/// | 128 | Source Address [2] |
/// +-----+--------------------------------------------------------+
/// . . . .
/// . . . .
/// +-----+--------------------------------------------------------+
/// | 64 | Source Address [N] |
/// | + | |
/// | 32N | |
/// +-----+--------------------------------------------------------+
/// </pre>
///
/// Version 3 report:
/// <pre>
/// +-----+-------------+----------+-----------------------------+
/// | Bit | 0-7 | 8-15 | 16-31 |
/// +-----+-------------+----------+-----------------------------+
/// | 0 | Type = 0x22 | Reserved | Checksum |
/// +-----+-------------+----------+-----------------------------+
/// | 32 | Reserved | Number of Group Records (M) |
/// +-----+------------------------+-----------------------------+
/// | 64 | Group Record [1] |
/// . . .
/// . . .
/// . . .
/// | | |
/// +-----+------------------------------------------------------+
/// | | Group Record [2] |
/// . . .
/// . . .
/// . . .
/// | | |
/// +-----+------------------------------------------------------+
/// | | . |
/// . . . .
/// | | . |
/// +-----+------------------------------------------------------+
/// | | Group Record [M] |
/// . . .
/// . . .
/// . . .
/// | | |
/// +-----+------------------------------------------------------+
/// </pre>
/// </summary>
public class IgmpDatagram : Datagram
{
public const int HeaderLength = 8;
private static class Offset
{
public const int Type = 0;
public const int MaxResponseCode = 1;
public const int Checksum = 2;
public const int GroupAddress = 4;
// Version 3 query
public const int IsSuppressRouterSideProcessing = 8;
public const int QueriersRobustnessVariable = 8;
public const int QueriersQueryIntervalCode = 9;
public const int NumberOfSources = 10;
public const int SourceAddresses = 12;
// Version 3 report
public const int NumberOfGroupRecords = 6;
public const int GroupRecords = 8;
}
/// <summary>
/// The type of the IGMP message of concern to the host-router interaction.
/// </summary>
public IgmpType Type
{
get { return (IgmpType)this[Offset.Type]; }
}
/// <summary>
/// The IGMP version of a Membership Query message is determined as follows:
/// <list type="bullet">
/// <item>IGMPv1 Query: length = 8 octets AND Max Resp Code field is zero.</item>
/// <item>IGMPv2 Query: length = 8 octets AND Max Resp Code field is non-zero.</item>
/// <item>IGMPv3 Query: length >= 12 octets.</item>
/// </list>
/// If the type is not a query, None will be returned.
/// If the query message do not match any of the above conditions (e.g., a Query of length 10 octets) Unknown will be returned.
/// </summary>
public IgmpQueryVersion QueryVersion
{
get
{
if (Type != IgmpType.MembershipQuery)
return IgmpQueryVersion.None;
if (Length >= 12)
return IgmpQueryVersion.Version3;
if (Length != 8)
return IgmpQueryVersion.Unknown;
if (MaxResponseCode == 0)
return IgmpQueryVersion.Version1;
return IgmpQueryVersion.Version2;
}
}
/// <summary>
/// The Max Resp Code field specifies the maximum time allowed before sending a responding report.
/// The actual time allowed, called the Max Resp Time, is represented in units of 1/10 second and is derived from the Max Resp Code as follows:
/// <list type="bullet">
/// <item>If Max Resp Code &lt; 128, Max Resp Time = Max Resp Code.</item>
/// <item>
/// If Max Resp Code >= 128, Max Resp Code represents a floating-point value as follows:
/// <pre>
/// 0 1 2 3 4 5 6 7
/// +-+-+-+-+-+-+-+-+
/// |1| exp | mant |
/// +-+-+-+-+-+-+-+-+
/// </pre>
/// Max Resp Time = (mant | 0x10) &lt;&lt; (exp + 3).
/// </item>
/// </list>
///
/// <para>
/// Small values of Max Resp Time allow IGMPv3 routers to tune the "leave latency"
/// (the time between the moment the last host leaves a group and the moment the routing protocol is notified that there are no more members).
/// Larger values, especially in the exponential range, allow tuning of the burstiness of IGMP traffic on a network.
/// </para>
/// </summary>
public byte MaxResponseCode
{
get { return this[Offset.MaxResponseCode]; }
}
/// <summary>
/// The actual time allowed, called the Max Resp Time, is represented in units of 1/10 second and is derived from the Max Resp Code as follows:
/// <list type="bullet">
/// <item>If the query version is 1 or 2 or if Max Resp Code &lt; 128, Max Resp Time = Max Resp Code.</item>
/// <item>
/// If Max Resp Code >= 128, Max Resp Code represents a floating-point value as follows:
/// <pre>
/// 0 1 2 3 4 5 6 7
/// +-+-+-+-+-+-+-+-+
/// |1| exp | mant |
/// +-+-+-+-+-+-+-+-+
/// </pre>
/// Max Resp Time = (mant | 0x10) &lt;&lt; (exp + 3).
/// </item>
/// </list>
/// </summary>
public TimeSpan MaxResponseTime
{
get
{
byte maxResponseCode = MaxResponseCode;
int numTenthOfASecond =
((maxResponseCode < 128 || Type != IgmpType.MembershipQuery || QueryVersion != IgmpQueryVersion.Version3)
? maxResponseCode
: CodeToValue(maxResponseCode));
return TimeSpan.FromMilliseconds(100 * numTenthOfASecond);
}
}
/// <summary>
/// The Checksum is the 16-bit one's complement of the one's complement sum of the whole IGMP message (the entire IP payload).
/// For computing the checksum, the Checksum field is set to zero.
/// When receiving packets, the checksum MUST be verified before processing a packet.
/// </summary>
public ushort Checksum
{
get { return ReadUShort(Offset.Checksum, Endianity.Big); }
}
/// <summary>
/// True iff the checksum value is correct according to the datagram data.
/// </summary>
public bool IsChecksumCorrect
{
get
{
if (_isChecksumCorrect == null)
_isChecksumCorrect = (CalculateChecksum() == Checksum);
return _isChecksumCorrect.Value;
}
}
/// <summary>
/// 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.
/// </summary>
public IpV4Address GroupAddress
{
get { return ReadIpV4Address(Offset.GroupAddress, Endianity.Big); }
}
/// <summary>
/// When set to one, the S Flag indicates to any receiving multicast routers that they are to suppress the normal timer updates they perform upon hearing a Query.
/// It does not, however, suppress the querier election or the normal "host-side" processing of a Query
/// that a router may be required to perform as a consequence of itself being a group member.
/// </summary>
/// <remarks>
/// Valid only on query of version 3.
/// </remarks>
public bool IsSuppressRouterSideProcessing
{
get { return ((this[Offset.IsSuppressRouterSideProcessing] >> 4) & 0x01) == 0x01; }
}
/// <summary>
/// If non-zero, the QRV field contains the [Robustness Variable] value used by the querier, i.e., the sender of the Query.
/// If the querier's [Robustness Variable] exceeds 7, the maximum value of the QRV field, the QRV is set to zero.
/// Routers adopt the QRV value from the most recently received Query as their own [Robustness Variable] value,
/// unless that most recently received QRV was zero, in which case the receivers use the default [Robustness Variable] value or a statically configured value.
/// </summary>
/// <remarks>
/// Valid only on query of version 3.
/// </remarks>
public byte QueriersRobustnessVariable
{
get { return (byte)(this[Offset.QueriersRobustnessVariable] & 0x07); }
}
/// <summary>
/// The Querier's Query Interval Code field specifies the [Query Interval] used by the querier.
/// The actual interval, called the Querier's Query Interval (QQI), is represented in units of seconds and is derived from the Querier's Query Interval Code as follows:
/// <list type="bullet">
/// <item>If QQIC &lt; 128, QQI = QQIC</item>
/// <item>
/// If QQIC >= 128, QQIC represents a floating-point value as follows:
/// <pre>
/// 0 1 2 3 4 5 6 7
/// +-+-+-+-+-+-+-+-+
/// |1| exp | mant |
/// +-+-+-+-+-+-+-+-+
/// </pre>
/// QQI = (mant | 0x10) &lt;&lt; (exp + 3)
/// </item>
/// </list>
/// Multicast routers that are not the current querier adopt the QQI value from the most recently received Query as their own [Query Interval] value,
/// unless that most recently received QQI was zero, in which case the receiving routers use the default [Query Interval] value.
/// </summary>
/// <remarks>
/// Valid only on query of version 3.
/// </remarks>
public byte QueriersQueryIntervalCode
{
get { return this[Offset.QueriersQueryIntervalCode]; }
}
/// <summary>
/// The actual interval, called the Querier's Query Interval (QQI), is represented in units of seconds and is derived from the Querier's Query Interval Code as follows:
/// <list type="bullet">
/// <item>If QQIC &lt; 128, QQI = QQIC</item>
/// <item>
/// If QQIC >= 128, QQIC represents a floating-point value as follows:
/// <pre>
/// 0 1 2 3 4 5 6 7
/// +-+-+-+-+-+-+-+-+
/// |1| exp | mant |
/// +-+-+-+-+-+-+-+-+
/// </pre>
/// QQI = (mant | 0x10) &lt;&lt; (exp + 3)
/// </item>
/// </list>
/// </summary>
/// <remarks>
/// Valid only on query of version 3.
/// </remarks>
public TimeSpan QueriersQueryInterval
{
get
{
int numSeconds = QueriersQueryIntervalCode < 128
? QueriersQueryIntervalCode
: CodeToValue(QueriersQueryIntervalCode);
return TimeSpan.FromSeconds(numSeconds);
}
}
/// <summary>
/// The Number of Sources (N) field specifies how many source addresses are present in the Query.
/// This number is zero in a General Query or a Group-Specific Query, and non-zero in a Group-and-Source-Specific Query.
/// This number is limited by the MTU of the network over which the Query is transmitted.
/// For example, on an Ethernet with an MTU of 1500 octets, the IP header including the Router Alert option consumes 24 octets,
/// and the IGMP fields up to including the Number of Sources (N) field consume 12 octets, leaving 1464 octets for source addresses,
/// which limits the number of source addresses to 366 (1464/4).
/// </summary>
/// <remarks>
/// Valid only on query of version 3.
/// </remarks>
public ushort NumberOfSources
{
get { return ReadUShort(Offset.NumberOfSources, Endianity.Big); }
}
/// <summary>
/// The Source Address [i] fields are a vector of n IP unicast addresses,
/// where n is the value in the Number of Sources (N) field.
/// </summary>
/// <remarks>
/// Valid only on query of version 3.
/// </remarks>
public ReadOnlyCollection<IpV4Address> SourceAddresses
{
get
{
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);
}
}
/// <summary>
/// The Number of Group Records (M) field specifies how many Group Records are present in this Report.
/// </summary>
/// <remarks>
/// Valid only on report of version 3.
/// </remarks>
public ushort NumberOfGroupRecords
{
get { return ReadUShort(Offset.NumberOfGroupRecords, Endianity.Big); }
}
public ReadOnlyCollection<IgmpGroupRecordDatagram> GroupRecords
{
get
{
IgmpGroupRecordDatagram[] groupRecords = new IgmpGroupRecordDatagram[NumberOfGroupRecords];
int offset = StartOffset + Offset.GroupRecords;
for (int i = 0; i != groupRecords.Length; ++i)
{
groupRecords[i] = new IgmpGroupRecordDatagram(Buffer, offset);
offset += groupRecords[i].Length;
}
return new ReadOnlyCollection<IgmpGroupRecordDatagram>(groupRecords);
}
}
internal IgmpDatagram(byte[] buffer, int offset, int length)
: base(buffer, offset, length)
{
}
protected override bool CalculateIsValid()
{
if (Length < HeaderLength || !IsChecksumCorrect)
return false;
// switch (Type)
// {
// case IgmpType.MembershipQuery:
// case IgmpType.LeaveGroupVersion2:
// case IgmpType.MembershipReportVersion1:
// case IgmpType.MembershipReportVersion2:
// case IgmpType.MembershipReportVersion3:
// }
return true;
}
private ushort CalculateChecksum()
{
uint sum = Sum16Bits(Buffer, StartOffset, Math.Min(Offset.Checksum, Length)) +
Sum16Bits(Buffer, StartOffset + Offset.Checksum + 2, Length - Offset.Checksum - 2);
return Sum16BitsToChecksum(sum);
}
/// <summary>
/// Calculates the value from the given code as follows:
/// <pre>
/// 0 1 2 3 4 5 6 7
/// +-+-+-+-+-+-+-+-+
/// |1| exp | mant |
/// +-+-+-+-+-+-+-+-+
/// </pre>
/// Value = (mant | 0x10) &lt;&lt; (exp + 3).
/// </summary>
private static int CodeToValue(byte code)
{
int mant = code & 0x0F;
int exp = (code & 0x70) >> 4;
return (mant | 0x10) << (exp + 3);
}
private bool? _isChecksumCorrect;
}
}
\ No newline at end of file
using System;
using System.Collections.ObjectModel;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.Igmp
{
/// <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.
/// A Group Record has the following internal format:
/// <pre>
/// +-----+-------------+--------------+--------+--------------+
/// | Bit | 0-7 | 8-15 | 16-31 | |
/// +-----+-------------+--------------+--------+--------------+
/// | 0 | Record Type | Aux Data Len | Number of Sources (N) |
/// +-----+-------------+--------------+--------+--------------+
/// | 32 | Multicast Address |
/// +-----+----------------------------------------------------+
/// | 64 | Source Address [1] |
/// +-----+----------------------------------------------------+
/// | 96 | Source Address [2] |
/// +-----+----------------------------------------------------+
/// . . . .
/// . . . .
/// +-----+----------------------------------------------------+
/// | 32 | Source Address [N] |
/// | + | |
/// | 32N | |
/// +-----+----------------------------------------------------+
/// | 64 | Auxiliary Data |
/// . + . .
/// . 32N . .
/// . . .
/// | | |
/// +-----+----------------------------------------------------+
/// </summary>
public class IgmpGroupRecordDatagram : Datagram
{
private static class Offset
{
public const int RecordType = 0;
public const int AuxiliaryDataLength = 1;
public const int NumberOfSources = 2;
public const int MulticastAddress = 4;
public const int SourceAddresses = 8;
}
public const int HeaderMinimumLength = 8;
public IgmpRecordType RecordType
{
get { return (IgmpRecordType)this[Offset.RecordType]; }
}
/// <summary>
/// The Aux Data Len field contains the length of the Auxiliary Data field in this Group Record, in bytes (after a translation from 32 bit words length).
/// It may contain zero, to indicate the absence of any auxiliary data.
/// </summary>
public int AuxiliaryDataLength
{
get { return 4 * this[Offset.AuxiliaryDataLength]; }
}
/// <summary>
/// The Number of Sources (N) field specifies how many source addresses are present in this Group Record.
/// </summary>
public int NumberOfSources
{
get { return ReadUShort(Offset.NumberOfSources, Endianity.Big); }
}
/// <summary>
/// The Multicast Address field contains the IP multicast address to which this Group Record pertains.
/// </summary>
public IpV4Address MulticastAddress
{
get { return ReadIpV4Address(Offset.MulticastAddress, Endianity.Big); }
}
/// <summary>
/// The Source Address [i] fields are a vector of n IP unicast addresses,
/// where n is the value in this record's Number of Sources (N) field.
/// </summary>
public ReadOnlyCollection<IpV4Address> SourceAddresses
{
get
{
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);
}
}
/// <summary>
/// The Auxiliary Data field, if present, contains additional information pertaining to this Group Record.
/// The protocol specified in this document, IGMPv3, does not define any auxiliary data.
/// Therefore, implementations of IGMPv3 MUST NOT include any auxiliary data (i.e., MUST set the Aux Data Len field to zero) in any transmitted Group Record,
/// and MUST ignore any auxiliary data present in any received Group Record.
/// The semantics and internal encoding of the Auxiliary Data field are to be defined by any future version or extension of IGMP that uses this field.
/// </summary>
public Datagram AuxiliaryData
{
get { return new Datagram(Buffer, StartOffset + Offset.AuxiliaryDataLength, AuxiliaryDataLength); }
}
internal IgmpGroupRecordDatagram(byte[] buffer, int offset)
: base(buffer, offset,
buffer.Length - offset < HeaderMinimumLength
? buffer.Length - offset
: Math.Min(buffer.Length - offset, HeaderMinimumLength +
4 * buffer.ReadUShort(offset + Offset.NumberOfSources, Endianity.Big) +
4 * buffer.ReadByte(offset + Offset.AuxiliaryDataLength)))
{
}
protected override bool CalculateIsValid()
{
return Length >= HeaderMinimumLength &&
Length == HeaderMinimumLength + 4 * NumberOfSources + AuxiliaryDataLength;
}
}
}
\ No newline at end of file
namespace PcapDotNet.Packets.Igmp
{
public enum IgmpQueryVersion
{
None,
Version1,
Version2,
Version3,
Unknown
}
}
\ No newline at end of file
namespace PcapDotNet.Packets.Igmp
{
/// <summary>
/// Group Record Type.
/// </summary>
public enum IgmpRecordType : byte
{
/// <summary>
/// A "Current-State Record" is sent by a system in response to a Query received on an interface.
/// It reports the current reception state of that interface, with respect to a single multicast address.
/// <para>
/// MODE_IS_INCLUDE - indicates that the interface has a filter mode of INCLUDE for the specified multicast address.
/// The Source Address [i] fields in this Group Record contain the interface's source list for the specified multicast address, if it is non-empty.
/// </para>
/// </summary>
CurrentStateRecordModeIsInclude = 1,
/// <summary>
/// A "Current-State Record" is sent by a system in response to a Query received on an interface.
/// It reports the current reception state of that interface, with respect to a single multicast address.
/// <para>
/// MODE_IS_EXCLUDE - indicates that the interface has a filter mode of EXCLUDE for the specified multicast address.
/// The Source Address [i] fields in this Group Record contain the interface's source list for the specified multicast address, if it is non-empty.
/// </para>
/// </summary>
CurrentStateRecordModeIsExclude = 2,
/// <summary>
/// A "Filter-Mode-Change Record" is sent by a system whenever a local invocation of IPMulticastListen causes a change of the filter mode
/// (i.e., a change from INCLUDE to EXCLUDE, or from EXCLUDE to INCLUDE),
/// of the interface-level state entry for a particular multicast address.
/// The Record is included in a Report sent from the interface on which the change occurred.
/// <para>
/// CHANGE_TO_INCLUDE_MODE - indicates that the interface has changed to INCLUDE filter mode for the specified multicast address.
/// The Source Address [i] fields in this Group Record contain the interface's new source list for the specified multicast address, if it is non-empty.
/// </para>
/// </summary>
FilterModeChangeToInclude = 3,
/// <summary>
/// A "Filter-Mode-Change Record" is sent by a system whenever a local invocation of IPMulticastListen causes a change of the filter mode
/// (i.e., a change from INCLUDE to EXCLUDE, or from EXCLUDE to INCLUDE),
/// of the interface-level state entry for a particular multicast address.
/// The Record is included in a Report sent from the interface on which the change occurred.
/// <para>
/// CHANGE_TO_EXCLUDE_MODE - indicates that the interface has changed to EXCLUDE filter mode for the specified multicast address.
/// The Source Address [i] fields in this Group Record contain the interface's new source list for the specified multicast address, if it is non-empty.
/// </para>
/// </summary>
FilterModeChangeToExclude= 4,
/// <summary>
/// A "Source-List-Change Record" is sent by a system whenever a local invocation of IPMulticastListen causes a change of source list
/// that is *not* coincident with a change of filter mode, of the interface-level state entry for a particular multicast address.
/// The Record is included in a Report sent from the interface on which the change occurred.
/// <para>
/// ALLOW_NEW_SOURCES - indicates that the Source Address [i] fields in this Group Record contain a list of the additional sources
/// that the system wishes to hear from, for packets sent to the specified multicast address.
/// If the change was to an INCLUDE source list, these are the addresses that were added to the list; if the change was to an EXCLUDE source list,
/// these are the addresses that were deleted from the list.
/// </para>
/// <para>
/// If a change of source list results in both allowing new sources and blocking old sources,
/// then two Group Records are sent for the same multicast address, one of type ALLOW_NEW_SOURCES and one of type BLOCK_OLD_SOURCES.
/// </para>
/// </summary>
SourceListChangeAllowNewSources = 5,
/// <summary>
/// A "Source-List-Change Record" is sent by a system whenever a local invocation of IPMulticastListen causes a change of source list
/// that is *not* coincident with a change of filter mode, of the interface-level state entry for a particular multicast address.
/// The Record is included in a Report sent from the interface on which the change occurred.
/// <para>
/// BLOCK_OLD_SOURCES - indicates that the Source Address [i] fields in this Group Record contain a list of the sources
/// that the system no longer wishes to hear from, for packets sent to the specified multicast address.
/// If the change was to an INCLUDE source list, these are the addresses that were deleted from the list; if the change was to an EXCLUDE source list,
/// these are the addresses that were added to the list.
/// </para>
/// If a change of source list results in both allowing new sources and blocking old sources,
/// then two Group Records are sent for the same multicast address, one of type ALLOW_NEW_SOURCES and one of type BLOCK_OLD_SOURCES.
/// </para>
/// </summary>
SourceListChangeBlockOldSources = 6,
}
}
\ No newline at end of file
namespace PcapDotNet.Packets.Igmp
{
public enum IgmpType : byte
{
/// <summary>
/// Membership Query (RFC3376).
/// </summary>
MembershipQuery = 0x11,
/// <summary>
/// Version 3 Membership Report (RFC3376).
/// </summary>
MembershipReportVersion3 = 0x22,
/// <summary>
/// Version 1 Membership Report (RFC1112).
/// </summary>
MembershipReportVersion1 = 0x12,
/// <summary>
/// Version 2 Membership Report (RFC2236).
/// </summary>
MembershipReportVersion2 = 0x16,
/// <summary>
/// Version 2 Leave Group (RFC2236).
/// </summary>
LeaveGroupVersion2 = 0x17
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@
using System.Collections;
using System.Linq;
using System.Text;
using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Packets.IpV4
......@@ -161,7 +162,7 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
public IpV4Address Source
{
get { return new IpV4Address(ReadUInt(Offset.Source, Endianity.Big)); }
get { return ReadIpV4Address(Offset.Source, Endianity.Big); }
}
/// <summary>
......@@ -169,7 +170,7 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
public IpV4Address Destination
{
get { return new IpV4Address(ReadUInt(Offset.Destination, Endianity.Big)); }
get { return ReadIpV4Address(Offset.Destination, Endianity.Big); }
}
/// <summary>
......@@ -212,6 +213,20 @@ namespace PcapDotNet.Packets.IpV4
get { return Tcp; }
}
/// <summary>
/// The payload of the datagram as an IGMP datagram.
/// </summary>
public IgmpDatagram Igmp
{
get
{
if (_igmp == null && Length >= HeaderLength)
_igmp = new IgmpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _igmp;
}
}
/// <summary>
/// The payload of the datagram as a TCP datagram.
/// </summary>
......@@ -333,6 +348,10 @@ namespace PcapDotNet.Packets.IpV4
case IpV4Protocol.Udp:
return Transport.IsValid && (Transport.IsChecksumOptional && Transport.Checksum == 0 ||
IsTransportChecksumCorrect);
case IpV4Protocol.InternetGroupManagementProtocol:
return Igmp.IsValid;
default:
// Todo check more protocols
return true;
......@@ -347,33 +366,10 @@ namespace PcapDotNet.Packets.IpV4
return Sum16BitsToChecksum(sum);
}
private static ushort Sum16BitsToChecksum(uint sum)
{
// Take only 16 bits out of the 32 bit sum and add up the carrier.
// if the results overflows - do it again.
while (sum > 0xFFFF)
sum = (sum & 0xFFFF) + (sum >> 16);
// one's complement the result
sum = ~sum;
return (ushort)sum;
}
private static uint Sum16Bits(byte[] buffer, int offset, int length)
{
int endOffset = offset + length;
uint sum = 0;
while (offset < endOffset - 1)
sum += buffer.ReadUShort(ref offset, Endianity.Big);
if (offset < endOffset)
sum += (ushort)(buffer[offset] << 8);
return sum;
}
private bool? _isHeaderChecksumCorrect;
private bool? _isTransportChecksumCorrect;
private IpV4Options _options;
private IgmpDatagram _igmp;
private TcpDatagram _tcp;
private UdpDatagram _udp;
}
......
......@@ -71,6 +71,11 @@
<Compile Include="Ethernet\EthernetType.cs" />
<Compile Include="Ethernet\MacAddress.cs" />
<Compile Include="IDataLink.cs" />
<Compile Include="Igmp\IgmpDatagram.cs" />
<Compile Include="Igmp\IgmpGroupRecordDatagram.cs" />
<Compile Include="Igmp\IgmpQueryVersion.cs" />
<Compile Include="Igmp\IgmpRecordType.cs" />
<Compile Include="Igmp\IgmpType.cs" />
<Compile Include="IOptionUnknownFactory.cs" />
<Compile Include="IpV4\IpV4OptionUnknown.cs" />
<Compile Include="Option.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