Commit 762de5ab authored by Brickner_cp's avatar Brickner_cp

Add support for DNS Option Client Subnet.

Fix ICMP Parameter Problem.
Add CommercialSecurity to the list of IPv4 option types (without supporting it).
Wireshark 1.12.3
parent 3695a2fb
......@@ -195,6 +195,15 @@ namespace PcapDotNet.Core.Test
DateTime.Now, new DataLink(DataLinkKind.LinuxSll)));
}
[TestMethod]
public void CompareMdnsQueryToWiresharkTest()
{
ComparePacketsToWireshark(
Packet.FromHexadecimalString(
"9221e942a2a35fe13e477f6d080047ef03095fa200003f117cef97257914f7ef2dc08804d67189037c0014e914eb02edce8b92b103b0000300050002000208797773697971696701660176046c78736d01780867716973656a6f6e07726b6b6563747703766e67026e7600003900ff086a776d7871626f690561656f6374046c7573720372616b066f717072756f0000fa0003076577656c74636e0469687178016c000003000306656a6c766a7904766e786406666a6f706869096f7467716479706d64066b71736d726e086b6963747171786b01790774766b636f656b0977726976736c68666300000900013406fb7a00070575746578670001690279790872676669626e62740663626c6a686a047563737502796302646900000b0004612e5287000d4c0cbd4134281019613edfe69d06646c76766d72046466657200003900fe15ed69250038fe22370c90f301b65c0ea97d6a0b441061ea7586f14b7deb653febba13d87cf9e9f3f09777b40c8599edb6ab467e60914419632ebaa03325036e7978036e766a00002800043c425d7600283f8aaddeefed0494d1a5e6de5975fa744e3e48c0cb6dfbe6ba7d5249311a95e9e976977fb550cab307646c736567687300001e00043be655710031087364646379746462096a70717865636e676f096a636a6d66696c6873016405627369617902706500b64f3e9ec623719b066277726b6a62096a6a68736a7178746e046b777576057770646367066a6c666b736b00000c00015006760d000100026471047071696a08716173747666697408667975676177636806666f656d6e740000fe00fe4b61a27e00467ec11db77e8d0ef41eda501b46a903087e497a411870b17e6e1a0e07661b65d9f67bbc48ebfa9f2001a96ece1e347dd0b0a1d4e72c3c4d0e109f49647f078e02747625caedbb036e76680772676364697770096a7178696864686f7602716c0000ff0000713ccfa7000cb2e3f484503cd3fcde0b2d3f097572696e6a797365650270770468667570086474616d6273696305676d61656400000c000072b2e660001a09646f6d646f78706e680674746c797164077869707066676b00",
DateTime.Now, new DataLink(DataLinkKind.Ethernet)));
}
[TestMethod]
public void CompareTcpZeroChecksumToWiresharkTest()
{
......
......@@ -37,7 +37,9 @@ namespace PcapDotNet.Core.Test
break;
case "eth.fcs":
field.AssertValue(ethernetDatagram.FrameCheckSequence);
// TODO: Support RARP.
if (ethernetDatagram.EtherType != EthernetType.ReverseArp)
field.AssertValue(ethernetDatagram.FrameCheckSequence);
break;
case "eth.padding":
......
using System;
using System.Text;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.IpV4;
using System.Linq;
namespace PcapDotNet.Core.Test
{
......@@ -42,11 +42,28 @@ namespace PcapDotNet.Core.Test
break;
case "data":
var casted1 = icmpDatagram as IcmpIpV4PayloadDatagram;
if (casted1 != null)
var icmpIpV4PayloadDatagram = icmpDatagram as IcmpIpV4PayloadDatagram;
if (icmpIpV4PayloadDatagram != null)
{
if (casted1.IpV4.Protocol != IpV4Protocol.IpComp) // TODO: Support IpComp.
field.AssertDataField(casted1.IpV4.Payload);
if (!new[]
{
IpV4Protocol.IpComp, // TODO: Support IpComp.
IpV4Protocol.Ax25, // TODO: Support Ax25.
IpV4Protocol.FibreChannel, // TODO: Support FibreChannel.
}.Contains(icmpIpV4PayloadDatagram.IpV4.Protocol))
{
if (icmpIpV4PayloadDatagram.IpV4.Protocol == IpV4Protocol.Udp)
{
// Uncomment this when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10990 is fixed.
// field.AssertDataField(casted1.IpV4.Udp.Payload);
}
else
{
// TODO: Remove this condition when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10991 and https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10992 are fixed.
if (!(icmpIpV4PayloadDatagram is IcmpParameterProblemDatagram || icmpIpV4PayloadDatagram is IcmpRedirectDatagram))
field.AssertDataField(icmpIpV4PayloadDatagram.IpV4.Payload);
}
}
}
else
{
......
......@@ -58,11 +58,13 @@ namespace PcapDotNet.Core.Test
break;
case "ip.flags.df":
subfield.AssertShowDecimal((ipV4Datagram.Fragmentation.Options & IpV4FragmentationOptions.DoNotFragment) == IpV4FragmentationOptions.DoNotFragment);
subfield.AssertShowDecimal((ipV4Datagram.Fragmentation.Options & IpV4FragmentationOptions.DoNotFragment) ==
IpV4FragmentationOptions.DoNotFragment);
break;
case "ip.flags.mf":
subfield.AssertShowDecimal((ipV4Datagram.Fragmentation.Options & IpV4FragmentationOptions.MoreFragments) == IpV4FragmentationOptions.MoreFragments);
subfield.AssertShowDecimal((ipV4Datagram.Fragmentation.Options & IpV4FragmentationOptions.MoreFragments) ==
IpV4FragmentationOptions.MoreFragments);
break;
default:
......@@ -137,16 +139,20 @@ namespace PcapDotNet.Core.Test
case "ip.dst":
case "ip.dst_host":
// TODO: Remove this condition when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10959 is fixed or (worst case) when MTU Reply option is supported.
if (ipV4Datagram.Options == null || !ipV4Datagram.Options.Any(option => option.OptionType == IpV4OptionType.MaximumTransmissionUnitReply))
// TODO: Remove this condition when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10959 is fixed or (worst case) when MTU Reply and CommercialSecurity options are supported.
if (ipV4Datagram.Options == null || !ipV4Datagram.Options.Any(option => option.OptionType == IpV4OptionType.MaximumTransmissionUnitReply ||
option.OptionType == IpV4OptionType.CommercialSecurity))
{
field.AssertShow(ipV4Datagram.Destination.ToString());
}
field.AssertNoFields();
break;
case "ip.addr":
case "ip.host":
// TODO: Remove this condition when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10959 is fixed or (worst case) when MTU Reply option is supported.
if (ipV4Datagram.Options == null || !ipV4Datagram.Options.Any(option => option.OptionType == IpV4OptionType.MaximumTransmissionUnitReply))
// TODO: Remove this condition when https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10959 is fixed or (worst case) when MTU Reply and CommercialSecurity options are supported.
if (ipV4Datagram.Options == null || !ipV4Datagram.Options.Any(option => option.OptionType == IpV4OptionType.MaximumTransmissionUnitReply ||
option.OptionType == IpV4OptionType.CommercialSecurity))
{
Assert.IsTrue(field.Show() == ipV4Datagram.Source.ToString() ||
field.Show() == ipV4Datagram.Destination.ToString());
......@@ -184,7 +190,7 @@ namespace PcapDotNet.Core.Test
field.Show().StartsWith("Unknown") ||
field.Show().StartsWith("Security") ||
field.Show().StartsWith("Router Alert (with option length = ") ||
field.Show().StartsWith("Stream identifier (with option length = ") ||
field.Show().StartsWith("Stream ID (with option length = ") ||
field.Show().Contains("with too") ||
field.Show().Contains(" bytes says option goes past end of options") ||
field.Show().Contains("(length byte past end of options)") ||
......
......@@ -103,14 +103,12 @@ namespace PcapDotNet.Core.Test
{
Assert.IsFalse(ipV6Datagram.ExtensionHeaders.IsValid);
int maxLength = ipV6Datagram.Length - IpV6Datagram.HeaderLength - ipV6Datagram.ExtensionHeaders.BytesLength;
if (field.Fields().Any(subfield => subfield.Name() == ""))
if (field.Fields().Any(subfield => subfield.Name() == "ipv6.opt.length"))
{
int length = int.Parse(
field.Fields().Where(subfield => subfield.Name() == "" && subfield.Show().StartsWith("Length:")).Select(
subfield => subfield.Show().Split(new[] {':', '(', ' '}, StringSplitOptions.RemoveEmptyEntries)[2]).First());
int length = int.Parse(field.Fields().First(subfield => subfield.Name() == "ipv6.opt.length").Show());
MoreAssert.IsBigger(maxLength, length);
} else
}
else
{
Assert.AreEqual(6, maxLength);
}
......
......@@ -265,6 +265,7 @@ namespace PcapDotNet.Core.Test
field.Show().StartsWith("Unknown (0x09) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net.
field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net.
field.Show().StartsWith("Unknown (0x19) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net.
field.Show().StartsWith("Unknown (0x2d) ") || // Unknown in Wireshark and unknown and invalid in Pcap.Net.
field.Show().StartsWith("Echo reply (with option length = ") ||
field.Show().Contains("bytes says option goes past end of options") ||
field.Show().Contains(") (with too-short option length = ") ||
......
......@@ -48,15 +48,32 @@ namespace PcapDotNet.Core.Test
field.AssertNoFields();
if (!new[]
{
(EthernetType)1, (EthernetType)5, (EthernetType)17, (EthernetType)29, (EthernetType)30, (EthernetType)43, (EthernetType)50, EthernetType.ReverseArp,
(EthernetType)1,
(EthernetType)5,
(EthernetType)17,
(EthernetType)29,
(EthernetType)30,
(EthernetType)43,
(EthernetType)50,
EthernetType.ReverseArp, // TODO: Support RARP
EthernetType.ExtensibleAuthenticationProtocolOverLan, // TODO: Support this protocol.
}.Contains(
vLanTaggedFrameDatagram.EtherType))
{
field.AssertValue(vLanTaggedFrameDatagram.ExtraData);
}
break;
case "eth.padding":
field.AssertNoFields();
field.AssertValue(vLanTaggedFrameDatagram.Trailer);
if (!new[]
{
EthernetType.ExtensibleAuthenticationProtocolOverLan, // TODO: Support this protocol.
}.Contains(
vLanTaggedFrameDatagram.EtherType))
{
field.AssertValue(vLanTaggedFrameDatagram.Trailer);
}
break;
default:
......
......@@ -94,6 +94,9 @@ namespace PcapDotNet.Packets.TestUtils
case DnsOptionCode.NameServerIdentifier:
return new DnsOptionAnything(DnsOptionCode.NameServerIdentifier, random.NextDataSegment(random.NextInt(0, 100)));
case DnsOptionCode.ClientSubnet:
return new DnsOptionClientSubnet(random.NextEnum<AddressFamily>(), random.NextByte(), random.NextByte(), random.NextDataSegment(random.NextInt(0, 50)));
default:
throw new InvalidOperationException("Invalid value");
}
......
......@@ -75,11 +75,12 @@ namespace PcapDotNet.Packets.TestUtils
if (maximumOptionLength >= IpV4OptionUnknown.OptionMinimumLength && random.Next(100) > 90)
return random.NextIpV4OptionUnknown(maximumOptionLength);
// TODO: Support MTU Probe and MTU Reply.
// TODO: Support MTU Probe, MTU Reply and CommercialSecurity.
List<IpV4OptionType> impossibleOptionTypes = new List<IpV4OptionType>
{
IpV4OptionType.MaximumTransmissionUnitProbe,
IpV4OptionType.MaximumTransmissionUnitReply
IpV4OptionType.MaximumTransmissionUnitReply,
IpV4OptionType.CommercialSecurity,
};
if (maximumOptionLength < IpV4OptionBasicSecurity.OptionMinimumLength)
impossibleOptionTypes.Add(IpV4OptionType.BasicSecurity);
......
......@@ -83,6 +83,9 @@ namespace PcapDotNet.Packets.Dns
case DnsOptionCode.UpdateLease:
return DnsOptionUpdateLease.Read(data);
case DnsOptionCode.ClientSubnet:
return DnsOptionClientSubnet.Read(data);
case DnsOptionCode.NameServerIdentifier:
default:
return new DnsOptionAnything(code, data);
......
using PcapDotNet.Base;
namespace PcapDotNet.Packets.Dns
{
/// <summary>
/// https://tools.ietf.org/html/draft-ietf-dnsop-edns-client-subnet
/// <pre>
/// +-----+----------------+---------------+
/// | bit | 0-7 | 8-15 |
/// +-----+----------------+---------------+
/// | 0 | FAMILY |
/// +-----+----------------+---------------+
/// | 16 | SOURCE NETMASK | SCOPE NETMASK |
/// +-----+----------------+---------------+
/// | 32 | ADDRESS |
/// | ... | |
/// +-----+--------------------------------+
/// </pre>
/// </summary>
public sealed class DnsOptionClientSubnet : DnsOption
{
private static class Offset
{
public const int Family = 0;
public const int SourceNetmask = Family + sizeof(ushort);
public const int ScopeNetmask = SourceNetmask + sizeof(byte);
public const int Address = ScopeNetmask + sizeof(byte);
}
/// <summary>
/// The minimum number of bytes this option data can take.
/// </summary>
public const int MininmumDataLength = Offset.Address;
public DnsOptionClientSubnet(AddressFamily family, byte sourceMask, byte scopeNetmask, DataSegment address)
: base(DnsOptionCode.ClientSubnet)
{
Family = family;
SourceNetmask = sourceMask;
ScopeNetmask = scopeNetmask;
Address = address;
}
/// <summary>
/// Indicates the family of the address contained in the option.
/// </summary>
public AddressFamily Family { get; private set; }
/// <summary>
/// Representing the length of the netmask pertaining to the query.
/// In replies, it mirrors the same value as in the requests.
/// It can be set to 0 to disable client-based lookups, in which case the Address field must be absent.
/// </summary>
public byte SourceNetmask { get; private set; }
/// <summary>
/// Representing the length of the netmask pertaining to the reply.
/// In requests, it should be set to the longest cacheable length supported by the Intermediate Nameserver.
/// In requests it may be set to 0 to have the Authoritative Nameserver treat the longest cacheable length as the SourceNetmask length.
/// In responses, this field is set by the Authoritative Nameserver to indicate the coverage of the response.
/// It might or might not match SourceNetmask; it could be shorter or longer.
/// </summary>
public byte ScopeNetmask { get; private set; }
/// <summary>
/// Contains either an IPv4 or IPv6 address, depending on Family, truncated in the request to the number of bits indicated by the Source Netmask field,
/// with bits set to 0 to pad up to the end of the last octet used. (This need not be as many octets as a complete address would take.)
/// In the reply, if the ScopeNetmask of the request was 0 then Address must contain the same octets as in the request.
/// Otherwise, the bits for Address will be significant through the maximum of the SouceNetmask or ScopeNetmask, and 0 filled to the end of an octet.
/// </summary>
public DataSegment Address { get; private set; }
/// <summary>
/// The number of bytes the option data takes.
/// </summary>
public override int DataLength
{
get { return MininmumDataLength + Address.Length; }
}
internal override bool EqualsData(DnsOption other)
{
return EqualsData(other as DnsOptionClientSubnet);
}
internal override int DataGetHashCode()
{
return Sequence.GetHashCode(BitSequence.Merge((ushort)Family, SourceNetmask, ScopeNetmask), Address);
}
internal override void WriteData(byte[] buffer, ref int offset)
{
buffer.Write(ref offset, (ushort)Family, Endianity.Big);
buffer.Write(ref offset, SourceNetmask);
buffer.Write(ref offset, ScopeNetmask);
buffer.Write(ref offset, Address);
}
internal static DnsOptionClientSubnet Read(DataSegment data)
{
if (data.Length < MininmumDataLength)
return null;
AddressFamily family = (AddressFamily)data.ReadUShort(Offset.Family, Endianity.Big);
byte sourceNetmask = data[Offset.SourceNetmask];
byte scopeNetmask = data[Offset.ScopeNetmask];
DataSegment address = data.Subsegment(Offset.Address, data.Length - Offset.Address);
return new DnsOptionClientSubnet(family, sourceNetmask, scopeNetmask, address);
}
private bool EqualsData(DnsOptionClientSubnet other)
{
return other != null &&
Family.Equals(other.Family) &&
SourceNetmask.Equals(other.SourceNetmask) &&
ScopeNetmask.Equals(other.ScopeNetmask) &&
Address.Equals(other.Address);
}
}
}
\ No newline at end of file
......@@ -28,5 +28,10 @@
/// NSID.
/// </summary>
NameServerIdentifier = 3,
/// <summary>
/// https://tools.ietf.org/html/draft-ietf-dnsop-edns-client-subnet
/// </summary>
ClientSubnet = 8,
}
}
\ No newline at end of file
......@@ -18,9 +18,18 @@
public const int ConstDataLength = sizeof(int);
/// <summary>
/// Builds
/// Builds an instance from a least value.
/// </summary>
/// <param name="lease"></param>
/// <param name="lease">
/// Indicating the lease life, in seconds, desired by the client.
/// In Update Responses, this field contains the actual lease granted by the server.
/// Note that the lease granted by the server may be less than, greater than, or equal to the value requested by the client.
/// To reduce network and server load, a minimum lease of 30 minutes (1800 seconds) is recommended.
/// Note that leases are expected to be sufficiently long as to make timer discrepancies (due to transmission latency, etc.)
/// between a client and server negligible.
/// Clients that expect the updated records to be relatively static may request appropriately longer leases.
/// Servers may grant relatively longer or shorter leases to reduce network traffic due to refreshes, or reduce stale data, respectively.
/// </param>
public DnsOptionUpdateLease(int lease)
: base(DnsOptionCode.UpdateLease)
{
......
......@@ -30,7 +30,11 @@ namespace PcapDotNet.Packets.Icmp
get
{
if (_ipV4 == null && Length >= HeaderLength)
_ipV4 = new IpV4Datagram(Buffer, StartOffset + HeaderLength, IpV4Length);
{
_ipV4 = new IpV4Datagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
// TODO: Do this processing without recreating the datagram again.
ProcessIpV4Payload(ref _ipV4);
}
return _ipV4;
}
}
......@@ -48,7 +52,9 @@ namespace PcapDotNet.Packets.Icmp
return (ip.Length >= IpV4Datagram.HeaderMinimumLength && ip.Length >= ip.HeaderLength);
}
internal virtual int IpV4Length { get { return Length - HeaderLength; } }
internal virtual void ProcessIpV4Payload(ref IpV4Datagram ipV4)
{
}
private IpV4Datagram _ipV4;
}
......
using System;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.Icmp
{
......@@ -65,7 +66,7 @@ namespace PcapDotNet.Packets.Icmp
/// </summary>
protected override bool CalculateIsValid()
{
return base.CalculateIsValid() && Pointer < IpV4.Length && OriginalDatagramLength == IpV4.Length;
return base.CalculateIsValid() && Pointer < IpV4.Length && OriginalDatagramLength == IpV4.Payload.Length;
}
internal override IcmpDatagram CreateInstance(byte[] buffer, int offset, int length)
......@@ -73,9 +74,10 @@ namespace PcapDotNet.Packets.Icmp
return new IcmpParameterProblemDatagram(buffer, offset, length);
}
internal override int IpV4Length
internal override void ProcessIpV4Payload(ref IpV4Datagram ipV4)
{
get { return Math.Min(Length - HeaderLength, OriginalDatagramLength); }
if (ipV4.Payload.Length > OriginalDatagramLength)
ipV4 = new IpV4Datagram(ipV4.Buffer, ipV4.StartOffset, ipV4.HeaderLength + OriginalDatagramLength);
}
private IcmpParameterProblemDatagram(byte[] buffer, int offset, int length)
......
......@@ -104,6 +104,12 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
LooseSourceRouting = 131,
/// <summary>
/// http://tools.ietf.org/html/draft-ietf-cipso-ipsecurity
/// CIPSO - Commercial Security.
/// </summary>
CommercialSecurity = 134,
/// <summary>
/// Strict Source Routing.
/// Used to route the internet datagram based on information supplied by the source.
......
......@@ -128,6 +128,7 @@
<Compile Include="Dns\ResourceData\DnsLongLivedQueryErrorCode.cs" />
<Compile Include="Dns\ResourceData\DnsLongLivedQueryOpcode.cs" />
<Compile Include="Dns\ResourceData\DnsOption.cs" />
<Compile Include="Dns\ResourceData\DnsOptionClientSubnet.cs" />
<Compile Include="Dns\ResourceData\DnsOptionCode.cs" />
<Compile Include="Dns\ResourceData\DnsOptionLongLivedQuery.cs" />
<Compile Include="Dns\ResourceData\DnsOptions.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