Commit 6703c3cd authored by Brickner_cp's avatar Brickner_cp

DNS

parent 82914442
......@@ -554,6 +554,11 @@ namespace PcapDotNet.Base
return ((long)this).ToString(CultureInfo.InvariantCulture);
}
public string ToString(string format)
{
return ((long)this).ToString(format);
}
private UInt48(long value)
{
_mostSignificant = (ushort)(value >> 32);
......
......@@ -77,6 +77,7 @@
<Compile Include="MoreTcpOption.cs" />
<Compile Include="WiresharkDatagramComparer.cs" />
<Compile Include="WiresharkDatagramComparerArp.cs" />
<Compile Include="WiresharkDatagramComparerDns.cs" />
<Compile Include="WiresharkDatagramComparerEthernet.cs" />
<Compile Include="WiresharkDatagramComparerGre.cs" />
<Compile Include="WiresharkDatagramComparerHttp.cs" />
......
......@@ -7,6 +7,7 @@ using System.Linq;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Dns;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Http;
......@@ -30,7 +31,7 @@ namespace PcapDotNet.Core.Test
private const bool IsRetry
// = true;
= false;
private const byte RetryNumber = 190;
private const byte RetryNumber = 27;
/// <summary>
/// Gets or sets the test context which provides
......@@ -135,21 +136,33 @@ namespace PcapDotNet.Core.Test
Gre,
Udp,
Tcp,
Dns,
Http,
}
private static Packet CreateRandomPacket(Random random)
{
PacketType packetType = random.NextEnum<PacketType>();
// BUG: Limited timestamp due to Windows bug: https://connect.microsoft.com/VisualStudio/feedback/details/559198/net-4-datetime-tolocaltime-is-sometimes-wrong
Packet packet;
do
{
packet = CreateRandomPacket(random, packetType);
} while (packet.Length > 65536);
return packet;
}
private static Packet CreateRandomPacket(Random random, PacketType packetType)
{
DateTime packetTimestamp =
random.NextDateTime(new DateTime(2010,1,1), new DateTime(2010,12,31)).ToUniversalTime().ToLocalTime();
//random.NextDateTime(PacketTimestamp.MinimumPacketTimestamp, PacketTimestamp.MaximumPacketTimestamp).ToUniversalTime().ToLocalTime();
//random.NextDateTime(PacketTimestamp.MinimumPacketTimestamp, PacketTimestamp.MaximumPacketTimestamp).ToUniversalTime().ToLocalTime();
EthernetLayer ethernetLayer = random.NextEthernetLayer();
IpV4Layer ipV4Layer = random.NextIpV4Layer();
PayloadLayer payloadLayer = random.NextPayloadLayer(random.Next(100));
switch (random.NextEnum<PacketType>())
switch (packetType)
// switch (PacketType.Icmp)
{
case PacketType.Ethernet:
......@@ -201,6 +214,21 @@ namespace PcapDotNet.Core.Test
ipV4Layer.Fragmentation = IpV4Fragmentation.None;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, random.NextTcpLayer(), payloadLayer);
case PacketType.Dns:
ethernetLayer.EtherType = EthernetType.None;
ipV4Layer.Protocol = null;
if (random.NextBool())
ipV4Layer.Fragmentation = IpV4Fragmentation.None;
UdpLayer udpLayer = random.NextUdpLayer();
DnsLayer dnsLayer = random.NextDnsLayer();
if (dnsLayer.IsQuery)
udpLayer.DestinationPort = 53;
else
udpLayer.SourcePort = 53;
return PacketBuilder.Build(packetTimestamp, ethernetLayer, ipV4Layer, udpLayer, dnsLayer);
case PacketType.Http:
ethernetLayer.EtherType = EthernetType.None;
ipV4Layer.Protocol = null;
......@@ -223,7 +251,10 @@ namespace PcapDotNet.Core.Test
private static IEnumerable<Packet> CreateRandomPackets(Random random, int numPackets)
{
for (int i = 0; i != numPackets; ++i)
yield return CreateRandomPacket(random);
{
Packet packet = CreateRandomPacket(random);
yield return packet;
}
}
private static void ComparePacketsToWireshark(params Packet[] packets)
......
......@@ -67,6 +67,9 @@ namespace PcapDotNet.Core.Test
case "tcp":
return new WiresharkDatagramComparerTcp();
case "dns":
return new WiresharkDatagramComparerDns();
case "http":
return new WiresharkDatagramComparerHttp();
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Dns;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Core.Test
{
internal class WiresharkDatagramComparerDns : WiresharkDatagramComparerSimple
{
protected override string PropertyName
{
get { return "Dns"; }
}
protected override bool CompareField(XElement field, Datagram datagram)
{
DnsDatagram dnsDatagram = (DnsDatagram)datagram;
switch (field.Name())
{
case "dns.id":
field.AssertShowHex(dnsDatagram.Id);
break;
case "dns.flags":
field.AssertShowHex(dnsDatagram.SubSegment(2, 2).ToArray().ReadUShort(0, Endianity.Big));
foreach (var flagField in field.Fields())
{
switch (flagField.Name())
{
case "dns.flags.response":
flagField.AssertShowDecimal(dnsDatagram.IsResponse);
break;
case "dns.flags.opcode":
flagField.AssertShowDecimal((byte)dnsDatagram.Opcode);
break;
case "dns.flags.authoritative":
flagField.AssertShowDecimal(dnsDatagram.IsAuthoritiveAnswer);
break;
case "dns.flags.truncated":
flagField.AssertShowDecimal(dnsDatagram.IsTruncated);
break;
case "dns.flags.recdesired":
flagField.AssertShowDecimal(dnsDatagram.IsRecusionDesired);
break;
case "dns.flags.recavail":
flagField.AssertShowDecimal(dnsDatagram.IsRecusionAvailable);
break;
case "dns.flags.z":
flagField.AssertShowDecimal(dnsDatagram.FutureUse);
break;
case "dns.flags.authenticated":
flagField.AssertShowDecimal(dnsDatagram.IsAuthenticData);
break;
case "dns.flags.checkdisable":
flagField.AssertShowDecimal(dnsDatagram.IsCheckingDisabled);
break;
case "dns.flags.rcode":
flagField.AssertShowDecimal((ushort)dnsDatagram.ResponseCode);
break;
default:
throw new InvalidOperationException("Invalid DNS flag field " + flagField.Name());
}
}
break;
case "dns.count.queries":
case "dns.count.zones":
field.AssertShowDecimal(dnsDatagram.QueryCount);
break;
case "dns.count.answers":
case "dns.count.prerequisites":
field.AssertShowDecimal(dnsDatagram.AnswerCount);
break;
case "dns.count.auth_rr":
case "dns.count.updates":
field.AssertShowDecimal(dnsDatagram.AuthorityCount);
break;
case "dns.count.add_rr":
field.AssertShowDecimal(dnsDatagram.AdditionalCount);
break;
case "":
var resourceRecordsFields = field.Fields();
switch (field.Show())
{
case "Queries":
case "Zone":
CompareResourceRecords(resourceRecordsFields, dnsDatagram.Queries);
break;
case "Answers":
case "Prerequisites":
CompareResourceRecords(resourceRecordsFields, dnsDatagram.Answers);
break;
case "Authoritative nameservers":
case "Updates":
CompareResourceRecords(resourceRecordsFields, dnsDatagram.Authorities);
break;
case "Additional records":
CompareResourceRecords(resourceRecordsFields, dnsDatagram.Additionals);
break;
default:
throw new InvalidOperationException("Invalid DNS resource records field " + field.Show());
}
break;
default:
throw new InvalidOperationException("Invalid DNS field " + field.Name());
}
return true;
}
private void CompareResourceRecords(IEnumerable<XElement> resourceRecordFields, IEnumerable<DnsResourceRecord> resourceRecords)
{
XElement[] resourceRecordFieldsArray= resourceRecordFields.ToArray();
DnsResourceRecord[] resourceRecordsArray = resourceRecords.ToArray();
Assert.AreEqual(resourceRecordFieldsArray.Length, resourceRecordsArray.Length);
for (int i = 0; i != resourceRecordFieldsArray.Length; ++i)
{
ResetRecordFields();
var resourceRecordField = resourceRecordFieldsArray[i];
var resourceRecord = resourceRecordsArray[i];
foreach (var resourceRecordAttributeField in resourceRecordField.Fields())
{
switch (resourceRecordAttributeField.Name())
{
case "dns.qry.name":
case "dns.resp.name":
resourceRecordAttributeField.AssertShow(GetWiresharkDomainName(resourceRecord.DomainName));
break;
case "dns.qry.type":
case "dns.resp.type":
resourceRecordAttributeField.AssertShowHex((ushort)resourceRecord.Type);
break;
case "dns.qry.class":
case "dns.resp.class":
resourceRecordAttributeField.AssertShowHex((ushort)resourceRecord.DnsClass);
break;
case "dns.resp.ttl":
resourceRecordAttributeField.AssertShowDecimal(resourceRecord.Ttl);
break;
case "dns.resp.len":
break;
default:
CompareResourceRecordData(resourceRecordAttributeField, resourceRecord);
break;
}
}
}
}
private void ResetRecordFields()
{
_hipRendezvousServersIndex = 0;
_wksBitMapIndex = 0;
_nxtTypeIndex = 0;
_nSecTypeIndex = 0;
_nSec3TypeIndex = 0;
_txtIndex = 0;
_aplItemIndex = 0;
}
private void CompareResourceRecordData(XElement dataField, DnsResourceRecord resourceRecord)
{
var data = resourceRecord.Data;
string dataFieldName = dataField.Name();
string dataFieldShow = dataField.Show();
string dataFieldShowUntilColon = dataFieldShow.Split(':')[0];
switch (resourceRecord.Type)
{
case DnsType.A:
switch (dataFieldName)
{
case "dns.resp.addr":
dataField.AssertShow(((DnsResourceDataIpV4)data).Data.ToString());
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.Ns:
dataField.AssertName("");
dataField.AssertShow("Name server: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
break;
case DnsType.Md: // 3.
case DnsType.Mf: // 4.
case DnsType.Mb: // 7.
case DnsType.Mg: // 8.
case DnsType.Mr: // 9.
dataField.AssertName("");
dataField.AssertShow("Host: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
break;
case DnsType.CName:
dataField.AssertName("");
dataField.AssertShow("Primary name: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
break;
case DnsType.Soa:
dataField.AssertName("");
var soaData = (DnsResourceDataStartOfAuthority)data;
switch (dataFieldShowUntilColon)
{
case "Primary name server":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(soaData.MainNameServer));
break;
case "Responsible authority's mailbox":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(soaData.ResponsibleMailBox));
break;
case "Serial number":
dataField.AssertShow(dataFieldShowUntilColon + ": " + soaData.Serial);
break;
case "Refresh interval":
dataField.AssertValue(soaData.Refresh);
break;
case "Retry interval":
dataField.AssertValue(soaData.Retry);
break;
case "Expiration limit":
dataField.AssertValue(soaData.Expire);
break;
case "Minimum TTL":
dataField.AssertValue(soaData.MinimumTtl);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Wks:
dataField.AssertName("");
var wksData = (DnsResourceDataWellKnownService)data;
switch (dataFieldShowUntilColon)
{
case "Addr":
dataField.AssertShow(dataFieldShowUntilColon + ": " + wksData.Address);
break;
case "Protocol":
dataField.AssertValue((byte)wksData.Protocol);
break;
case "Bits":
dataField.AssertValue(wksData.BitMap[_wksBitMapIndex++]);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Ptr:
dataField.AssertName("");
dataField.AssertShow("Domain name: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
break;
case DnsType.HInfo:
dataField.AssertName("");
var hInfoData = (DnsResourceDataHostInformation)data;
switch (dataFieldShowUntilColon)
{
case "CPU":
dataField.AssertValue(new[] {(byte)hInfoData.Cpu.Length}.Concat(hInfoData.Cpu));
break;
case "OS":
dataField.AssertValue(new[] {(byte)hInfoData.Os.Length}.Concat(hInfoData.Os));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.MInfo:
dataField.AssertName("");
var mInfoData = (DnsResourceDataMailingListInfo)data;
switch (dataFieldShowUntilColon)
{
case "Responsible Mailbox":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(mInfoData.MailingList));
break;
case "Error Mailbox":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(mInfoData.ErrorMailBox));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Mx:
var mxData = (DnsResourceDataMailExchange)data;
switch (dataFieldShowUntilColon)
{
case "Preference":
dataField.AssertShow(dataFieldShowUntilColon + ": " + mxData.Preference);
break;
case "Mail exchange":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(mxData.MailExchangeHost));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Txt: // 16.
case DnsType.Spf: // 99.
var txtData = (DnsResourceDataText)data;
dataField.AssertShow("Text: " + txtData.Text[_txtIndex++].ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
break;
case DnsType.Rp:
dataField.AssertName("");
var rpData = (DnsResourceDataResponsiblePerson)data;
switch (dataFieldShowUntilColon)
{
case "Mailbox":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(rpData.MailBox));
break;
case "TXT RR":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(rpData.TextDomain));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.AfsDb:
dataField.AssertName("");
var afsDbData = (DnsResourceDataAfsDb)data;
switch (dataFieldShowUntilColon)
{
case "Subtype":
dataField.AssertShow(dataFieldShowUntilColon + ": " + afsDbData.SubType);
break;
case "Hostname":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(afsDbData.Hostname));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.X25:
dataField.AssertName("");
dataField.AssertShow("PSDN-Address: " + ((DnsResourceDataString)data).String.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
break;
case DnsType.Isdn:
dataField.AssertName("");
var isdnData = (DnsResourceDataIsdn)data;
switch (dataFieldShowUntilColon)
{
case "ISDN Address":
dataField.AssertShow(dataFieldShowUntilColon + ": " +
isdnData.IsdnAddress.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
break;
case "Subaddress":
dataField.AssertShow(dataFieldShowUntilColon + ": " +
isdnData.SubAddress.ToString(EncodingExtensions.Iso88591).ToWiresharkLiteral(false));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Rt:
dataField.AssertName("");
var rtData = (DnsResourceDataRouteThrough)data;
switch (dataFieldShowUntilColon)
{
case "Preference":
dataField.AssertShow(dataFieldShowUntilColon + ": " + rtData.Preference);
break;
case "Intermediate-Host":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(rtData.IntermediateHost));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Nsap:
var nsapData = (DnsResourceDataNetworkServiceAccessPoint)data;
switch (dataFieldName)
{
case "dns.nsap.rdata":
byte[] nsapId = new byte[6];
nsapId.Write(0, nsapData.SystemIdentifier, Endianity.Big);
dataField.AssertValue(nsapData.AreaAddress.Concat(nsapId).Concat(nsapData.Selector));
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.NsapPtr:
dataField.AssertName("");
dataField.AssertShow("Owner: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
break;
case DnsType.Key:
dataField.AssertName("");
var keyData = (DnsResourceDataKey)data;
switch (dataFieldShowUntilColon)
{
case "Flags":
foreach (var flagField in dataField.Fields())
{
int flagCount = GetFlagCount(flagField);
switch (flagCount)
{
case 0:
flagField.AssertShow(keyData.AuthenticationProhibited
? "1... .... .... .... = Key prohibited for authentication"
: "0... .... .... .... = Key allowed for authentication");
break;
case 1:
flagField.AssertShow(keyData.ConfidentialityProhibited
? ".1.. .... .... .... = Key prohibited for confidentiality"
: ".0.. .... .... .... = Key allowed for confidentiality");
break;
case 2:
flagField.AssertShow(keyData.Experimental
? "..1. .... .... .... = Key is experimental or optional"
: "..0. .... .... .... = Key is required");
break;
case 5:
flagField.AssertShow(keyData.UserAssociated
? ".... .1.. .... .... = Key is associated with a user"
: ".... .0.. .... .... = Key is not associated with a user");
break;
case 6:
flagField.AssertShow(keyData.NameType == DnsKeyNameType.NonZoneEntity
? ".... ..1. .... .... = Key is associated with the named entity"
: ".... ..0. .... .... = Key is not associated with the named entity");
break;
case 8:
flagField.AssertShow(keyData.IpSec
? ".... .... 1... .... = Key is valid for use with IPSEC"
: ".... .... 0... .... = Key is not valid for use with IPSEC");
break;
case 9:
flagField.AssertShow(keyData.Email
? ".... .... .1.. .... = Key is valid for use with MIME security multiparts"
: ".... .... .0.. .... = Key is not valid for use with MIME security multiparts");
break;
case 12:
Assert.AreEqual(flagField.Show().Substring(19), " = Signatory = " + (byte)keyData.Signatory);
break;
default:
throw new InvalidOperationException("Invalid flag count " + flagCount);
}
}
break;
case "Protocol":
dataField.AssertShow(dataFieldShowUntilColon + ": " + (byte)keyData.Protocol);
break;
case "Algorithm":
dataField.AssertValue((byte)keyData.Algorithm);
break;
case "Key id":
// TODO: Remove this once wireshark bug is fixed.
// https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6704
break;
case "Public key":
byte[] flagsExtension;
if (keyData.FlagsExtension == null)
{
flagsExtension = new byte[0];
}
else
{
flagsExtension = new byte[2];
flagsExtension.Write(0, keyData.FlagsExtension.Value, Endianity.Big);
}
dataField.AssertValue(flagsExtension.Concat(keyData.PublicKey));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Sig: // 24.
case DnsType.RrSig: // 46.
dataField.AssertName("");
var sigData = (DnsResourceDataSig)data;
switch (dataFieldShowUntilColon)
{
case "Type covered":
dataField.AssertValue((ushort)sigData.TypeCovered);
break;
case "Algorithm":
dataField.AssertValue((byte)sigData.Algorithm);
break;
case "Labels":
dataField.AssertShow(dataFieldShowUntilColon + ": " + sigData.Labels);
break;
case "Original TTL":
dataField.AssertValue(sigData.OriginalTtl);
break;
case "Signature expiration":
dataField.AssertValue(sigData.SignatureExpiration);
break;
case "Time signed":
dataField.AssertValue(sigData.SignatureInception);
break;
case "Id of signing key(footprint)":
dataField.AssertShow(dataFieldShowUntilColon + ": " + sigData.KeyTag);
break;
case "Signer's name":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(sigData.SignersName));
break;
case "Signature":
dataField.AssertValue(sigData.Signature);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Px:
dataField.AssertName("");
var pxData = (DnsResourceDataX400Pointer)data;
switch (dataFieldShowUntilColon)
{
case "Preference":
dataField.AssertShow(dataFieldShowUntilColon + ": " + pxData.Preference);
break;
case "MAP822":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(pxData.Map822));
break;
case "MAPX400":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(pxData.MapX400));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.GPos:
dataField.AssertName("");
var gposData = (DnsResourceDataGeographicalPosition)data;
switch (dataFieldShowUntilColon)
{
case "Longitude":
dataField.AssertShow(dataFieldShowUntilColon + ": " + gposData.Longitude);
break;
case "Latitude":
dataField.AssertShow(dataFieldShowUntilColon + ": " + gposData.Latitude);
break;
case "Altitude":
dataField.AssertShow(dataFieldShowUntilColon + ": " + gposData.Altitude);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Aaaa:
dataField.AssertName("");
dataField.AssertShow("Addr: " + GetWiresharkIpV6(((DnsResourceDataIpV6)data).Data));
break;
case DnsType.Loc:
dataField.AssertName("");
var locData = (DnsResourceDataLocationInformation)data;
switch (dataFieldShowUntilColon)
{
case "Version":
dataField.AssertShow(dataFieldShowUntilColon + ": " + locData.Version);
break;
case "Data":
dataField.AssertShow("Data");
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Nxt:
dataField.AssertName("");
var nxtData = (DnsResourceDataNextDomain)data;
switch (dataFieldShowUntilColon)
{
case "Next domain name":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(nxtData.NextDomainName));
break;
case "RR type in bit map":
DnsType actualType = nxtData.TypesExist.Skip(_nxtTypeIndex++).First();
DnsType expectedType;
if (!TryGetDnsType(dataFieldShow, out expectedType))
{
if (dataFieldShow == "RR type in bit map: Unused (unused)")
{
switch (actualType)
{
case 0:
break;
default:
throw new InvalidOperationException(actualType + " can't be unused");
}
}
else
throw new InvalidOperationException("Can't parse DNS field " + dataFieldShow);
}
else
{
Assert.AreEqual(expectedType, actualType);
}
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Srv:
dataField.AssertName("");
var srvData = (DnsResourceDataServerSelection)data;
switch (dataFieldShowUntilColon)
{
case "Priority":
dataField.AssertShow(dataFieldShowUntilColon + ": " + srvData.Priority);
break;
case "Weight":
dataField.AssertShow(dataFieldShowUntilColon + ": " + srvData.Weight);
break;
case "Port":
dataField.AssertShow(dataFieldShowUntilColon + ": " + srvData.Port);
break;
case "Target":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(srvData.Target));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.NaPtr:
dataField.AssertName("");
var naPtrData = (DnsResourceDataNamingAuthorityPointer)data;
switch (dataFieldShowUntilColon)
{
case "Order":
dataField.AssertShow(dataFieldShowUntilColon + ": " + naPtrData.Order);
break;
case "Preference":
dataField.AssertShow(dataFieldShowUntilColon + ": " + naPtrData.Preference);
break;
case "Flags length":
dataField.AssertShow(dataFieldShowUntilColon + ": " + naPtrData.Flags.Length);
break;
case "Flags":
dataField.AssertValue(naPtrData.Flags);
break;
case "Service length":
dataField.AssertShow(dataFieldShowUntilColon + ": " + naPtrData.Services.Length);
break;
case "Service":
dataField.AssertValue(naPtrData.Services);
break;
case "Regex length":
dataField.AssertShow(dataFieldShowUntilColon + ": " + naPtrData.Regexp.Length);
break;
case "Regex":
dataField.AssertValue(naPtrData.Regexp);
break;
case "Replacement length":
dataField.AssertShow(dataFieldShowUntilColon + ": " + naPtrData.Replacement.NonCompressedLength);
break;
case "Replacement":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(naPtrData.Replacement));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Kx:
dataField.AssertName("");
var kxData = (DnsResourceDataKeyExchanger)data;
switch (dataFieldShowUntilColon)
{
case "Preference":
dataField.AssertShow(dataFieldShowUntilColon + ": 0");
dataField.AssertValue(kxData.Preference);
break;
case "Key exchange":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(kxData.KeyExchangeHost));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Cert:
dataField.AssertName("");
var certData = (DnsResourceDataCertificate)data;
switch (dataFieldShowUntilColon)
{
case "Type":
dataField.AssertValue((ushort)certData.CertificateType);
break;
case "Key footprint":
dataField.AssertValue(certData.KeyTag);
break;
case "Algorithm":
dataField.AssertValue((byte)certData.Algorithm);
break;
case "Public key":
dataField.AssertValue(certData.Certificate);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.A6:
var a6Data = (DnsResourceDataA6)data;
switch (dataFieldShowUntilColon)
{
case "Prefix len":
dataField.AssertShow(dataFieldShowUntilColon + ": " + a6Data.PrefixLength);
break;
case "Address suffix":
Assert.AreEqual(new IpV6Address(dataFieldShow.Substring(dataFieldShowUntilColon.Length + 2)), a6Data.AddressSuffix);
break;
case "Prefix name":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(a6Data.PrefixName));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.DName:
dataField.AssertName("");
dataField.AssertShow("Target name: " + GetWiresharkDomainName(((DnsResourceDataDomainName)data).Data));
break;
case DnsType.Opt:
var optResourceRecord = (DnsOptResourceRecord)resourceRecord;
var optData = (DnsResourceDataOptions)data;
switch (dataFieldName)
{
case "":
switch (dataFieldShowUntilColon)
{
case "UDP payload size":
dataField.AssertShow(dataFieldShowUntilColon + ": " + optResourceRecord.SendersUdpPayloadSize);
break;
case "Higher bits in extended RCODE":
dataField.AssertValue(optResourceRecord.ExtendedRcode);
break;
case "EDNS0 version":
dataField.AssertShow(dataFieldShowUntilColon + ": " + (byte)optResourceRecord.Version);
break;
case "Z":
dataField.AssertValue((ushort)optResourceRecord.Flags);
break;
case "Data":
Assert.AreEqual(dataField.Value().Length, 2 * optData.Options.Options.Sum(option => option.Length));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case "dns.resp.len":
dataField.AssertShow("Data length: " + optData.Options.Options.Sum(option => option.DataLength));
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.Apl:
var aplData = (DnsResourceDataAddressPrefixList)data;
switch (dataFieldName)
{
case "":
dataField.AssertValue((ushort)aplData.Items[_aplItemIndex++].AddressFamily);
break;
case "hf.dns.apl.coded.prefix":
dataField.AssertShowDecimal(aplData.Items[_aplItemIndex - 1].PrefixLength);
break;
case "dns.apl.negation":
dataField.AssertShowDecimal(aplData.Items[_aplItemIndex - 1].Negation);
break;
case "dns.apl.afdlength":
dataField.AssertShowDecimal(aplData.Items[_aplItemIndex - 1].AddressFamilyDependentPart.Length);
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.Ds: // 43.
case DnsType.Dlv: // 32769.
dataField.AssertName("");
var dsData = (DnsResourceDataDelegationSigner)data;
switch (dataFieldShowUntilColon)
{
case "Key id":
dataField.AssertShow(dataFieldShowUntilColon + ": " + dsData.KeyTag.ToString("0000"));
break;
case "Algorithm":
dataField.AssertValue((byte)dsData.Algorithm);
break;
case "Digest type":
dataField.AssertValue((byte)dsData.DigestType);
break;
case "Public key":
dataField.AssertValue(dsData.Digest);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.SshFp:
var sshFpData = (DnsResourceDataSshFingerprint)data;
switch (dataFieldName)
{
case "":
switch (dataFieldShowUntilColon)
{
case "Algorithm":
dataField.AssertValue((byte)sshFpData.Algorithm);
break;
case "Fingerprint type":
dataField.AssertValue((byte)sshFpData.FingerprintType);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case "dns.sshfp.fingerprint":
dataField.AssertValue(sshFpData.Fingerprint);
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.IpSecKey:
dataField.AssertName("");
var ipSecKeyData = (DnsResourceDataIpSecKey)data;
switch (dataFieldShowUntilColon)
{
case "Gateway precedence":
dataField.AssertValue(ipSecKeyData.Precedence);
break;
case "Algorithm":
dataField.AssertValue((byte)ipSecKeyData.Algorithm);
break;
case "Gateway":
switch (ipSecKeyData.GatewayType)
{
case DnsGatewayType.None:
dataField.AssertShow(dataFieldShowUntilColon + ": no gateway");
break;
case DnsGatewayType.IpV4:
dataField.AssertShow(dataFieldShowUntilColon + ": " + ((DnsGatewayIpV4)ipSecKeyData.Gateway).Value);
break;
case DnsGatewayType.IpV6:
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkIpV6(((DnsGatewayIpV6)ipSecKeyData.Gateway).Value));
break;
case DnsGatewayType.DomainName:
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(((DnsGatewayDomainName)ipSecKeyData.Gateway).Value));
break;
default:
throw new InvalidOperationException("Invalid Gateway Type " + ipSecKeyData.GatewayType);
}
break;
case "Public key":
dataField.AssertValue(ipSecKeyData.PublicKey);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.NSec:
dataField.AssertName("");
var nSecData = (DnsResourceDataNextDomainSecure)data;
switch (dataFieldShowUntilColon)
{
case "Next domain name":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(nSecData.NextDomainName));
break;
case "RR type in bit map":
DnsType actualType = nSecData.TypesExist[_nSecTypeIndex++];
DnsType expectedType;
if (!TryGetDnsType(dataFieldShow, out expectedType))
throw new InvalidOperationException("Failed parsing type from " + dataFieldShow);
Assert.AreEqual(expectedType, actualType);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.DnsKey:
dataField.AssertName("");
var dnsKeyData = (DnsResourceDataDnsKey)data;
switch (dataFieldShowUntilColon)
{
case "Flags":
foreach (var flagField in dataField.Fields())
{
int flagCount = GetFlagCount(flagField);
switch (flagCount)
{
case 7:
flagField.AssertShow(dnsKeyData.ZoneKey
? ".... ...1 .... .... = This is the zone key for the specified zone"
: ".... ...0 .... .... = This is not a zone key");
break;
case 8:
flagField.AssertShow(dnsKeyData.Revoke
? ".... .... 1... .... = Key is revoked"
: ".... .... 0... .... = Key is not revoked");
break;
case 15:
flagField.AssertShow(dnsKeyData.SecureEntryPoint
? ".... .... .... ...1 = Key is a Key Signing Key"
: ".... .... .... ...0 = Key is a Zone Signing Key");
break;
default:
throw new InvalidOperationException("Invalid DNS data flag field " + flagField.Show());
}
}
break;
case "Protocol":
dataField.AssertShow(dataFieldShowUntilColon + ": " + dnsKeyData.Protocol);
break;
case "Algorithm":
dataField.AssertValue((byte)dnsKeyData.Algorithm);
break;
case "Key id":
// TODO: Remove this once wireshark bug is fixed.
// https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6704
break;
case "Public key":
dataField.AssertValue(dnsKeyData.PublicKey);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.Dhcid:
switch (dataFieldName)
{
case "dns.dhcid.rdata":
dataField.AssertValue(((DnsResourceDataAnything)data).Data);
break;
default:
throw new InvalidOperationException("Invalid DNS resource data field name " + dataFieldName);
}
break;
case DnsType.NSec3:
var nSec3Data = (DnsResourceDataNextDomainSecure3)data;
switch (dataFieldName)
{
case "dns.nsec3.algo":
dataField.AssertShowDecimal((byte)nSec3Data.HashAlgorithm);
break;
case "dns.nsec3.flags":
dataField.AssertShowDecimal((byte)nSec3Data.Flags);
foreach (var flagField in dataField.Fields())
{
string flagFieldName = flagField.Name();
switch (flagFieldName)
{
case "dns.nsec3.flags.opt_out":
dataField.AssertShowDecimal((nSec3Data.Flags & DnsSecNSec3Flags.OptOut) == DnsSecNSec3Flags.OptOut);
break;
default:
throw new InvalidOperationException("Invalid DNS resource data flag field name " + flagFieldName);
}
}
break;
case "dns.nsec3.iterations":
dataField.AssertShowDecimal(nSec3Data.Iterations);
break;
case "dns.nsec3.salt_length":
dataField.AssertShowDecimal(nSec3Data.Salt.Length);
break;
case "dns.nsec3.salt_value":
dataField.AssertValue(nSec3Data.Salt);
break;
case "dns.nsec3.hash_length":
dataField.AssertShowDecimal(nSec3Data.NextHashedOwnerName.Length);
break;
case "dns.nsec3.hash_value":
dataField.AssertValue(nSec3Data.NextHashedOwnerName);
break;
case "":
DnsType expectedType = nSec3Data.TypesExist[_nSec3TypeIndex++];
Assert.IsTrue(dataField.Show().StartsWith("RR type in bit map: "));
if (dataField.Show().EndsWith(string.Format("({0})", (ushort)expectedType)))
dataField.AssertShow(string.Format("RR type in bit map: Unknown ({0})", (ushort)expectedType));
else
Assert.IsTrue(dataField.Show().Replace("-","").StartsWith("RR type in bit map: " + expectedType.ToString().ToUpperInvariant()));
break;
default:
throw new InvalidOperationException("Invalid DNS resource data field name " + dataFieldName);
}
break;
case DnsType.NSec3Param:
var nSec3ParamData = (DnsResourceDataNextDomainSecure3Parameters)data;
switch (dataFieldName)
{
case "dns.nsec3.algo":
dataField.AssertShowDecimal((byte)nSec3ParamData.HashAlgorithm);
break;
case "dns.nsec3.flags":
dataField.AssertShowDecimal((byte)nSec3ParamData.Flags);
break;
case "dns.nsec3.iterations":
dataField.AssertShowDecimal(nSec3ParamData.Iterations);
break;
case "dns.nsec3.salt_length":
dataField.AssertShowDecimal(nSec3ParamData.Salt.Length);
break;
case "dns.nsec3.salt_value":
dataField.AssertShow(nSec3ParamData.Salt);
break;
default:
throw new InvalidOperationException("Invalid DNS resource data field name " + dataFieldName);
}
break;
case DnsType.Hip:
var hipData = (DnsResourceDataHostIdentityProtocol)data;
switch (dataFieldName)
{
case "":
switch (dataFieldShowUntilColon)
{
case "HIT length":
dataField.AssertShow(dataFieldShowUntilColon + ": " + hipData.HostIdentityTag.Length);
break;
case "PK algorithm":
dataField.AssertValue((byte)hipData.PublicKeyAlgorithm);
break;
case "PK length":
dataField.AssertShow(dataFieldShowUntilColon + ": " + hipData.PublicKey.Length);
break;
case "Rendezvous Server":
dataField.AssertShow(dataFieldShowUntilColon + ": " +
GetWiresharkDomainName(hipData.RendezvousServers[_hipRendezvousServersIndex++]));
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case "dns.hip.hit":
dataField.AssertShow(hipData.HostIdentityTag);
break;
case "dns.hip.pk":
dataField.AssertShow(hipData.PublicKey);
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.TKey:
dataField.AssertName("");
var tKeyData = (DnsResourceDataTransactionKey)data;
switch (dataFieldShowUntilColon)
{
case "Algorithm name":
dataField.AssertShow(dataFieldShowUntilColon + ": " + GetWiresharkDomainName(tKeyData.Algorithm));
break;
case "Signature inception":
dataField.AssertValue(tKeyData.Inception);
break;
case "Signature expiration":
dataField.AssertValue(tKeyData.Expiration);
break;
case "Mode":
dataField.AssertValue((ushort)tKeyData.Mode);
break;
case "Error":
dataField.AssertValue((ushort)tKeyData.Error);
break;
case "Key Size":
dataField.AssertShow(dataFieldShowUntilColon + ": " + tKeyData.Key.Length);
break;
case "Key Data":
dataField.AssertValue(tKeyData.Key);
break;
case "Other Size":
dataField.AssertShow(dataFieldShowUntilColon + ": " + tKeyData.Other.Length);
break;
case "Other Data":
dataField.AssertValue(tKeyData.Other);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case DnsType.TSig:
var tSigData = (DnsResourceDataTransactionSignature)data;
switch (dataFieldName)
{
case "dns.tsig.algorithm_name":
dataField.AssertShow(GetWiresharkDomainName(tSigData.Algorithm));
break;
case "":
switch (dataFieldShowUntilColon)
{
case "Time signed":
dataField.AssertValue(tSigData.TimeSigned);
break;
default:
throw new InvalidOperationException("Invalid DNS data field " + dataFieldShow);
}
break;
case "dns.tsig.fudge":
dataField.AssertShowDecimal(tSigData.Fudge);
break;
case "dns.tsig.mac_size":
dataField.AssertShowDecimal(tSigData.MessageAuthenticationCode.Length);
break;
case "dns.tsig.mac":
dataField.AssertShow("");
Assert.AreEqual(1, dataField.Fields().Count());
var tsigSubfield = dataField.Fields().First();
tsigSubfield.AssertShow("No dissector for algorithm:" + GetWiresharkDomainName(tSigData.Algorithm));
tsigSubfield.AssertValue(tSigData.MessageAuthenticationCode);
break;
case "dns.tsig.original_id":
dataField.AssertShowDecimal(tSigData.OriginalId);
break;
case "dns.tsig.error":
dataField.AssertShowDecimal((ushort)tSigData.Error);
break;
case "dns.tsig.other_len":
dataField.AssertShowDecimal(tSigData.Other.Length);
break;
case "dns.tsig.other_data":
dataField.AssertValue(tSigData.Other);
break;
default:
throw new InvalidOperationException("Invalid DNS data field name " + dataFieldName);
}
break;
case DnsType.Null: // 10.
case DnsType.EId: // 31.
case DnsType.NimLoc: // 32.
case DnsType.AtmA: // 34.
case DnsType.Sink: // 40.
case DnsType.NInfo: // 56.
case DnsType.RKey: // 57.
case DnsType.TaLink: // 58.
case DnsType.Cds: // 59.
case DnsType.UInfo: // 100.
case DnsType.Uid: // 101.
case DnsType.Gid: // 102.
case DnsType.UnSpec: // 103.
case DnsType.Ixfr: // 251.
case DnsType.Axfr: // 252.
case DnsType.MailB: // 253.
case DnsType.MailA: // 254.
case DnsType.Any: // 255.
case DnsType.Uri: // 256.
case DnsType.Caa: // 257.
case DnsType.Ta: // 32768.
default:
dataField.AssertName("");
dataField.AssertShow("Data");
break;
}
}
private static string GetWiresharkDomainName(DnsDomainName domainName)
{
if (domainName.IsRoot)
return "<Root>";
return domainName.ToString().TrimEnd('.');
}
private static string GetWiresharkIpV6(IpV6Address data)
{
return data.ToString().ToLowerInvariant().TrimStart('0').Replace(":0", ":").Replace(":0", ":").Replace(":0", ":");
}
private static bool TryGetDnsType(string dataFieldShow, out DnsType type)
{
if (Enum.TryParse(dataFieldShow.Split(':')[1].Split(' ')[1].Replace("-", ""), true, out type))
return true;
ushort typeValue;
if (ushort.TryParse(dataFieldShow.Split('(', ')')[1], out typeValue))
{
type = (DnsType)typeValue;
return true;
}
return false;
}
private static int GetFlagCount(XElement flagField)
{
return flagField.Show().Replace(" ", "").TakeWhile(c => c == '.').Count();
}
private int _hipRendezvousServersIndex;
private int _wksBitMapIndex;
private int _nxtTypeIndex;
private int _nSecTypeIndex;
private int _nSec3TypeIndex;
private int _txtIndex;
private int _aplItemIndex;
}
}
......@@ -5,39 +5,41 @@ namespace PcapDotNet.Core.Test
{
public static class WiresharkStringExtensions
{
public static string ToWiresharkLiteral(this string value)
public static string ToWiresharkLiteral(this string value, bool putLeadingZerosInHexAndBackslashesBeforeSpecialCharacters = true)
{
StringBuilder result = new StringBuilder();
for (int i = 0; i != value.Length; ++i)
{
char currentChar = value[i];
switch (currentChar)
if (currentChar == '\0')
return result.ToString();
if (putLeadingZerosInHexAndBackslashesBeforeSpecialCharacters)
{
case '\\':
case '"':
result.Append('\\');
result.Append(currentChar);
break;
case '\r':
result.Append(@"\r");
break;
case '\n':
result.Append(@"\n");
break;
default:
if (currentChar >= 0x7F || currentChar < 0x20)
{
result.Append(@"\x");
result.Append(((int)currentChar).ToString("x2"));
break;
}
result.Append(currentChar);
break;
switch (currentChar)
{
case '\\':
case '"':
result.Append('\\');
result.Append(currentChar);
continue;
case '\r':
result.Append(@"\r");
continue;
case '\n':
result.Append(@"\n");
continue;
}
}
if (currentChar >= 0x7F || currentChar < 0x20)
{
result.Append(@"\x");
result.Append(((int)currentChar).ToString("x" + (putLeadingZerosInHexAndBackslashesBeforeSpecialCharacters ? "2" : "")));
}
else
result.Append(currentChar);
}
return result.ToString();
......
......@@ -24,7 +24,7 @@ namespace PcapDotNet.Core.Test
{
XAttribute attribute = element.Attribute(attributeName);
if (attribute == null)
throw new ArgumentException("element " + element.Name + " doesn't contain attribute " + attributeName, "attributeName");
return string.Empty;
return attribute.Value;
}
......@@ -168,5 +168,15 @@ namespace PcapDotNet.Core.Test
{
element.AssertValue(expectedValue.ToString("x8"));
}
public static void AssertValue(this XElement element, UInt48 expectedValue)
{
element.AssertValue(expectedValue.ToString("x12"));
}
public static void AssertValue(this XElement element, SerialNumber32 expectedValue)
{
element.AssertValue(expectedValue.Value);
}
}
}
\ No newline at end of file
......@@ -95,31 +95,31 @@ namespace PcapDotNet.Packets.Test
dnsLayer.Additionals = new List<DnsDataResourceRecord>();
TestDomainNameCompression(0, dnsLayer);
dnsLayer.Queries.Add(new DnsQueryResourceRecord(new DnsDomainName(""), DnsType.All, DnsClass.In));
dnsLayer.Queries.Add(new DnsQueryResourceRecord(new DnsDomainName(""), DnsType.Any, DnsClass.In));
TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName(""), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName(""), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(3, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("def.abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("def.abc"), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(6, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(6, dnsLayer);
dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(13, dnsLayer);
dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abd.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abd.def"), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(16, dnsLayer);
dnsLayer.Additionals.Add(new DnsDataResourceRecord(new DnsDomainName("hello.abd.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
dnsLayer.Additionals.Add(new DnsDataResourceRecord(new DnsDomainName("hello.abd.def"), DnsType.Any, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(23, dnsLayer);
}
......
......@@ -14,6 +14,8 @@ namespace PcapDotNet.Packets.TestUtils
{
public static DnsLayer NextDnsLayer(this Random random)
{
const int MaxRecordsPerSection = 5;
DnsLayer dnsLayer = new DnsLayer();
dnsLayer.Id = random.NextUShort();
dnsLayer.IsQuery = random.NextBool();
......@@ -22,25 +24,26 @@ namespace PcapDotNet.Packets.TestUtils
dnsLayer.IsTruncated = random.NextBool();
dnsLayer.IsRecusionDesired = random.NextBool();
dnsLayer.IsRecusionAvailable = random.NextBool();
dnsLayer.FutureUse = random.NextByte(DnsDatagram.MaxFutureUse + 1);
dnsLayer.ResponseCode = random.NextEnum<DnsResponseCode>();
dnsLayer.FutureUse = random.NextBool();
dnsLayer.ResponseCode = random.NextEnum(DnsResponseCode.BadVersOrBadSig, DnsResponseCode.BadKey, DnsResponseCode.BadTime, DnsResponseCode.BadMode,
DnsResponseCode.BadName, DnsResponseCode.BadAlg, DnsResponseCode.BadTrunc);
dnsLayer.DomainNameCompressionMode = random.NextEnum<DnsDomainNameCompressionMode>();
int numQueries = random.Next(10);
int numQueries = random.Next(MaxRecordsPerSection + 1);
List<DnsQueryResourceRecord> queries = new List<DnsQueryResourceRecord>();
for (int i = 0; i != numQueries; ++i)
queries.Add(random.NextDnsQueryResourceRecord());
dnsLayer.Queries = queries;
int numAnswers = random.Next(10);
int numAnswers = random.Next(MaxRecordsPerSection + 1);
List<DnsDataResourceRecord> answers = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAnswers; ++i)
answers.Add(random.NextDnsDataResourceRecord());
dnsLayer.Answers = answers;
int numAuthorities = random.Next(10);
int numAuthorities = random.Next(MaxRecordsPerSection + 1);
List<DnsDataResourceRecord> authorities = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAuthorities; ++i)
authorities.Add(random.NextDnsDataResourceRecord());
dnsLayer.Authorities = authorities;
int numAdditionals = random.Next(10);
int numAdditionals = random.Next(MaxRecordsPerSection + 1);
List<DnsDataResourceRecord> additionals = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAdditionals; ++i)
additionals.Add(random.NextDnsDataResourceRecord());
......@@ -179,7 +182,8 @@ namespace PcapDotNet.Packets.TestUtils
random.NextDataSegment(random.Next(100)));
case DnsType.Key:
return new DnsResourceDataKey(random.NextBool(), random.NextBool(), random.NextEnum<DnsKeyNameType>(), random.NextFlags<DnsKeySignatory>(),
return new DnsResourceDataKey(random.NextBool(), random.NextBool(), random.NextBool(), random.NextBool(), random.NextBool(),
random.NextBool(), random.NextEnum<DnsKeyNameType>(), random.NextFlags<DnsKeySignatory>(),
random.NextEnum<DnsKeyProtocol>(), random.NextEnum<DnsAlgorithm>(),
random.NextBool() ? (ushort?)random.NextUShort() : null, random.NextDataSegment(random.Next(100)));
......@@ -275,7 +279,8 @@ namespace PcapDotNet.Packets.TestUtils
return new DnsResourceDataNextDomainSecure(random.NextDnsDomainName(), random.NextDnsTypeArray(random.Next(100)));
case DnsType.DnsKey:
return new DnsResourceDataDnsKey(random.NextBool(), random.NextBool(), random.NextByte(), random.NextEnum<DnsAlgorithm>(), random.NextDataSegment(random.Next(100)));
return new DnsResourceDataDnsKey(random.NextBool(), random.NextBool(), random.NextBool(), random.NextByte(), random.NextEnum<DnsAlgorithm>(),
random.NextDataSegment(random.Next(100)));
case DnsType.NSec3:
return new DnsResourceDataNextDomainSecure3(random.NextEnum<DnsSecNSec3HashAlgorithm>(), random.NextFlags<DnsSecNSec3Flags>(),
......
......@@ -57,6 +57,11 @@ namespace PcapDotNet.Packets
public byte Last { get { return this[Length - 1]; } }
public DataSegment SubSegment(int offset, int length)
{
return SubSegment(ref offset, length);
}
/// <summary>
/// Returns the Segment's bytes as a read only MemoryStream with a non-public buffer.
/// </summary>
......@@ -177,11 +182,6 @@ namespace PcapDotNet.Packets
return subSegemnt;
}
internal DataSegment SubSegment(int offset, int length)
{
return SubSegment(ref offset, length);
}
internal bool ReadBool(int offset, byte mask)
{
return (this[offset] & mask) == mask;
......
......@@ -6,33 +6,33 @@ using System.Linq;
namespace PcapDotNet.Packets.Dns
{
/// <summary>
/// RFC 1035.
/// RFC 1035, 4035.
/// All communications inside of the domain protocol are carried in a single format called a message.
/// The top level format of message is divided into 5 sections (some of which are empty in certain cases) shown below:
/// <pre>
/// +-----+----+--------+----+----+----+----+------+--------+
/// | bit | 0 | 1-4 | 5 | 6 | 7 | 8 | 9-10 | 11-15 |
/// +-----+----+--------+----+----+----+----+------+--------+
/// | 0 | ID |
/// +-----+----+--------+----+----+----+----+------+--------+
/// | 16 | QR | Opcode | AA | TC | RD | RA | Z | RCODE |
/// +-----+----+--------+----+----+----+----+------+--------+
/// | 32 | QDCOUNT |
/// +-----+-------------------------------------------------+
/// | 48 | ANCOUNT |
/// +-----+-------------------------------------------------+
/// | 64 | NSCOUNT |
/// +-----+-------------------------------------------------+
/// | 80 | ARCOUNT |
/// +-----+-------------------------------------------------+
/// | 96 | Question - the question for the name server |
/// +-----+-------------------------------------------------+
/// | | Answer - RRs answering the question |
/// +-----+-------------------------------------------------+
/// | | Authority - RRs pointing toward an authority |
/// +-----+-------------------------------------------------+
/// | | Additional - RRs holding additional information |
/// +-----+-------------------------------------------------+
/// +-----+----+--------+----+----+----+----+---+----+----+-------+
/// | bit | 0 | 1-4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12-15 |
/// +-----+----+--------+----+----+----+----+---+----+----+-------+
/// | 0 | ID |
/// +-----+----+--------+----+----+----+----+---+----+----+-------+
/// | 16 | QR | Opcode | AA | TC | RD | RA | Z | AD | CD | RCODE |
/// +-----+----+--------+----+----+----+----+---+----+----+-------+
/// | 32 | QDCOUNT |
/// +-----+-------------------------------------------------------+
/// | 48 | ANCOUNT |
/// +-----+-------------------------------------------------------+
/// | 64 | NSCOUNT |
/// +-----+-------------------------------------------------------+
/// | 80 | ARCOUNT |
/// +-----+-------------------------------------------------------+
/// | 96 | Question - the question for the name server |
/// +-----+-------------------------------------------------------+
/// | | Answer - RRs answering the question |
/// +-----+-------------------------------------------------------+
/// | | Authority - RRs pointing toward an authority |
/// +-----+-------------------------------------------------------+
/// | | Additional - RRs holding additional information |
/// +-----+-------------------------------------------------------+
/// </pre>
/// The header section is always present.
/// The header includes fields that specify which of the remaining sections are present,
......@@ -56,6 +56,8 @@ namespace PcapDotNet.Packets.Dns
public const int IsRecusionDesired = 2;
public const int IsRecusionAvailable = 3;
public const int FutureUse = 3;
public const int IsAuthenticData = 3;
public const int IsCheckingDisabled = 3;
public const int ResponseCode = 3;
public const int QueryCount = 4;
public const int AnswerCount = 6;
......@@ -72,14 +74,15 @@ namespace PcapDotNet.Packets.Dns
public const byte IsTruncated = 0x02;
public const byte IsRecusionDesired = 0x01;
public const byte IsRecusionAvailable = 0x80;
public const byte FutureUse = 0x60;
public const ushort ResponseCode = 0x1F;
public const byte FutureUse = 0x40;
public const byte IsAuthenticData = 0x20;
public const byte IsCheckingDisabled = 0x10;
public const ushort ResponseCode = 0x000F;
}
private static class Shift
{
public const int Opcode = 3;
public const int FutureUse = 5;
}
/// <summary>
......@@ -87,8 +90,6 @@ namespace PcapDotNet.Packets.Dns
/// </summary>
public const int HeaderLength = 12;
public const byte MaxFutureUse = 3;
/// <summary>
/// A 16 bit identifier assigned by the program that generates any kind of query.
/// This identifier is copied the corresponding reply and can be used by the requester to match up replies to outstanding queries.
......@@ -161,11 +162,60 @@ namespace PcapDotNet.Packets.Dns
/// <summary>
/// Reserved for future use.
/// Must be zero in all queries and responses.
/// Must be false in all queries and responses.
/// </summary>
public bool FutureUse
{
get { return ReadBool(Offset.FutureUse, Mask.FutureUse); }
}
/// <summary>
/// The name server side of a security-aware recursive name server must not set the AD bit in a response
/// unless the name server considers all RRsets in the Answer and Authority sections of the response to be authentic.
/// The name server side should set the AD bit if and only if the resolver side considers all RRsets in the Answer section
/// and any relevant negative response RRs in the Authority section to be authentic.
/// The resolver side must follow the Authenticating DNS Responses procedure to determine whether the RRs in question are authentic.
/// However, for backward compatibility, a recursive name server may set the AD bit when a response includes unsigned CNAME RRs
/// if those CNAME RRs demonstrably could have been synthesized from an authentic DNAME RR that is also included in the response
/// according to the synthesis rules described in RFC 2672.
/// </summary>
public byte FutureUse
public bool IsAuthenticData
{
get { return (byte)((this[Offset.FutureUse] & Mask.FutureUse) >> Shift.FutureUse); }
get { return ReadBool(Offset.IsAuthenticData, Mask.IsAuthenticData); }
}
/// <summary>
/// Exists in order to allow a security-aware resolver to disable signature validation
/// in a security-aware name server's processing of a particular query.
///
/// The name server side must copy the setting of the CD bit from a query to the corresponding response.
///
/// The name server side of a security-aware recursive name server must pass the state of the CD bit to the resolver side
/// along with the rest of an initiating query,
/// so that the resolver side will know whether it is required to verify the response data it returns to the name server side.
/// If the CD bit is set, it indicates that the originating resolver is willing to perform whatever authentication its local policy requires.
/// Thus, the resolver side of the recursive name server need not perform authentication on the RRsets in the response.
/// When the CD bit is set, the recursive name server should, if possible, return the requested data to the originating resolver,
/// even if the recursive name server's local authentication policy would reject the records in question.
/// That is, by setting the CD bit, the originating resolver has indicated that it takes responsibility for performing its own authentication,
/// and the recursive name server should not interfere.
///
/// If the resolver side implements a BAD cache and the name server side receives a query that matches an entry in the resolver side's BAD cache,
/// the name server side's response depends on the state of the CD bit in the original query.
/// If the CD bit is set, the name server side should return the data from the BAD cache;
/// if the CD bit is not set, the name server side must return RCODE 2 (server failure).
///
/// The intent of the above rule is to provide the raw data to clients that are capable of performing their own signature verification checks
/// while protecting clients that depend on the resolver side of a security-aware recursive name server to perform such checks.
/// Several of the possible reasons why signature validation might fail involve conditions
/// that may not apply equally to the recursive name server and the client that invoked it.
/// For example, the recursive name server's clock may be set incorrectly, or the client may have knowledge of a relevant island of security
/// that the recursive name server does not share.
/// In such cases, "protecting" a client that is capable of performing its own signature validation from ever seeing the "bad" data does not help the client.
/// </summary>
public bool IsCheckingDisabled
{
get { return ReadBool(Offset.IsCheckingDisabled, Mask.IsCheckingDisabled); }
}
public DnsResponseCode ResponseCode
......@@ -256,21 +306,23 @@ namespace PcapDotNet.Packets.Dns
public override ILayer ExtractLayer()
{
return new DnsLayer
{
Id = Id,
IsQuery = IsQuery,
Opcode = Opcode,
IsAuthoritiveAnswer = IsAuthoritiveAnswer,
IsTruncated = IsTruncated,
IsRecusionDesired = IsRecusionDesired,
IsRecusionAvailable = IsRecusionAvailable,
FutureUse = FutureUse,
ResponseCode = ResponseCode,
Queries = Queries.ToList(),
Answers = Answers.ToList(),
Authorities = Authorities.ToList(),
Additionals = Additionals.ToList(),
};
{
Id = Id,
IsQuery = IsQuery,
Opcode = Opcode,
IsAuthoritiveAnswer = IsAuthoritiveAnswer,
IsTruncated = IsTruncated,
IsRecusionDesired = IsRecusionDesired,
IsRecusionAvailable = IsRecusionAvailable,
FutureUse = FutureUse,
IsAuthenticData = IsAuthenticData,
IsCheckingDisabled = IsCheckingDisabled,
ResponseCode = ResponseCode,
Queries = Queries.ToList(),
Answers = Answers.ToList(),
Authorities = Authorities.ToList(),
Additionals = Additionals.ToList(),
};
}
protected override bool CalculateIsValid()
......@@ -306,8 +358,8 @@ namespace PcapDotNet.Packets.Dns
internal static void Write(byte[] buffer, int offset,
ushort id, bool isResponse, DnsOpcode opcode, bool isAuthoritiveAnswer, bool isTruncated,
bool isRecursionDesired, bool isRecursionAvailable, byte futureUse, DnsResponseCode responseCode,
List<DnsQueryResourceRecord> queries, List<DnsDataResourceRecord> answers,
bool isRecursionDesired, bool isRecursionAvailable, bool futureUse, bool isAuthenticData, bool isCheckingDisabled,
DnsResponseCode responseCode, List<DnsQueryResourceRecord> queries, List<DnsDataResourceRecord> answers,
List<DnsDataResourceRecord> authorities, List<DnsDataResourceRecord> additionals,
DnsDomainNameCompressionMode domainNameCompressionMode)
{
......@@ -326,7 +378,12 @@ namespace PcapDotNet.Packets.Dns
byte flags1 = 0;
if (isRecursionAvailable)
flags1 |= Mask.IsRecusionAvailable;
flags1 |= (byte)((futureUse << Shift.FutureUse) & Mask.FutureUse);
if (futureUse)
flags1 |= Mask.FutureUse;
if (isAuthenticData)
flags1 |= Mask.IsAuthenticData;
if (isCheckingDisabled)
flags1 |= Mask.IsCheckingDisabled;
flags1 |= (byte)((ushort)responseCode & Mask.ResponseCode);
buffer.Write(offset + Offset.IsRecusionAvailable, flags1);
DnsDomainNameCompressionData compressionData = new DnsDomainNameCompressionData(domainNameCompressionMode);
......
......@@ -33,6 +33,11 @@ namespace PcapDotNet.Packets.Dns
}
}
public bool IsRoot
{
get { return NumLabels == 0; }
}
public int NonCompressedLength
{
get
......@@ -43,9 +48,9 @@ namespace PcapDotNet.Packets.Dns
public override string ToString()
{
if (_ascii == null)
_ascii = _labels.Select(label => label.ToString(Encoding.UTF8)).SequenceToString('.') + ".";
return _ascii;
if (_utf8 == null)
_utf8 = _labels.Select(label => label.ToString(Encoding.UTF8)).SequenceToString('.') + ".";
return _utf8;
}
public bool Equals(DnsDomainName other)
......@@ -160,6 +165,6 @@ namespace PcapDotNet.Packets.Dns
private static readonly DnsDomainName _root = new DnsDomainName("");
private readonly List<DataSegment> _labels;
private string _ascii;
private string _utf8;
}
}
\ No newline at end of file
......@@ -30,8 +30,12 @@ namespace PcapDotNet.Packets.Dns
public bool IsRecusionAvailable { get; set;}
public byte FutureUse { get; set; }
public bool FutureUse { get; set; }
public bool IsAuthenticData { get; set; }
public bool IsCheckingDisabled { get; set; }
public DnsResponseCode ResponseCode { get; set; }
public List<DnsQueryResourceRecord> Queries { get; set; }
......@@ -77,8 +81,8 @@ namespace PcapDotNet.Packets.Dns
protected override void Write(byte[] buffer, int offset)
{
DnsDatagram.Write(buffer, offset,
Id, IsResponse, Opcode, IsAuthoritiveAnswer, IsTruncated, IsRecusionDesired, IsRecusionAvailable, FutureUse, ResponseCode,
Queries, Answers, Authorities, Additionals, DomainNameCompressionMode);
Id, IsResponse, Opcode, IsAuthoritiveAnswer, IsTruncated, IsRecusionDesired, IsRecusionAvailable, FutureUse, IsAuthenticData,
IsCheckingDisabled, ResponseCode, Queries, Answers, Authorities, Additionals, DomainNameCompressionMode);
}
/// <summary>
......@@ -99,15 +103,17 @@ namespace PcapDotNet.Packets.Dns
public bool Equals(DnsLayer other)
{
return other != null &&
Id == other.Id &&
IsQuery == other.IsQuery &&
Opcode == other.Opcode &&
IsAuthoritiveAnswer == other.IsAuthoritiveAnswer &&
IsTruncated == other.IsTruncated &&
IsRecusionDesired == other.IsRecusionDesired &&
IsRecusionAvailable == other.IsRecusionAvailable &&
FutureUse == other.FutureUse &&
ResponseCode == other.ResponseCode &&
Id.Equals(other.Id) &&
IsQuery.Equals(other.IsQuery) &&
Opcode.Equals(other.Opcode) &&
IsAuthoritiveAnswer.Equals(other.IsAuthoritiveAnswer) &&
IsTruncated.Equals(other.IsTruncated) &&
IsRecusionDesired.Equals(other.IsRecusionDesired) &&
IsRecusionAvailable.Equals(other.IsRecusionAvailable) &&
FutureUse.Equals(other.FutureUse) &&
IsAuthenticData.Equals(other.IsAuthenticData) &&
IsCheckingDisabled.Equals(other.IsCheckingDisabled) &&
ResponseCode.Equals(other.ResponseCode) &&
(Queries.IsNullOrEmpty() && other.Queries.IsNullOrEmpty() || Queries.SequenceEqual(other.Queries)) &&
(Answers.IsNullOrEmpty() && other.Answers.IsNullOrEmpty() || Answers.SequenceEqual(other.Answers)) &&
(Authorities.IsNullOrEmpty() && other.Authorities.IsNullOrEmpty() || Authorities.SequenceEqual(other.Authorities)) &&
......
......@@ -1256,7 +1256,7 @@ namespace PcapDotNet.Packets.Dns
/// RFCs 2535, 2536, 2537, 2539, 3110, 3755, 4034, 5155, 5702, 5933.
/// The key algorithm.
/// </summary>
public enum DnsAlgorithm
public enum DnsAlgorithm : byte
{
/// <summary>
/// RFC 4034.
......@@ -1667,21 +1667,22 @@ namespace PcapDotNet.Packets.Dns
}
/// <summary>
/// RFC 2065, 2535.
/// <pre>
/// +-----+---+---+----------+----+----------+--------+----------+-------+
/// | bit | 0 | 1 | 2 | 3 | 4-5 | 6-7 | 8-11 | 12-15 |
/// +-----+---+---+----------+----+----------+--------+----------+-------+
/// | 0 | A | C | Reserved | XT | Reserved | NAMTYP | Reserved | SIG |
/// +-----+---+---+----------+----+----------+--------+----------+-------+
/// | 16 | protocol | algorithm |
/// +-----+-------------------------------------------+------------------+
/// | 32 | Flags extension (optional) |
/// +-----+--------------------------------------------------------------+
/// | 32 | public key |
/// | or | |
/// | 48 | |
/// | ... | |
/// +-----+--------------------------------------------------------------+
/// +-----+---+---+--------------+----+----------+------+--------+-------+-------+----------+-------+
/// | bit | 0 | 1 | 2 | 3 | 4 | 5 | 6-7 | 8 | 9 | 10-11 | 12-15 |
/// +-----+---+---+--------------+----+----------+------+--------+-------+-------+----------+-------+
/// | 0 | A | C | experimental | XT | Reserved | user | NAMTYP | IPSEC | email | Reserved | SIG |
/// +-----+---+---+--------------+----+----------+------+--------+-------+-------+----------+-------+
/// | 16 | protocol | algorithm |
/// +-----+------------------------------------------------------+----------------------------------+
/// | 32 | Flags extension (optional) |
/// +-----+-----------------------------------------------------------------------------------------+
/// | 32 | public key |
/// | or | |
/// | 48 | |
/// | ... | |
/// +-----+-----------------------------------------------------------------------------------------+
/// </pre>
/// </summary>
[DnsTypeRegistration(Type = DnsType.Key)]
......@@ -1691,8 +1692,12 @@ namespace PcapDotNet.Packets.Dns
{
public const int AuthenticationProhibited = 0;
public const int ConfidentialityProhibited = 0;
public const int Experimental = 0;
public const int IsFlagsExtension = 0;
public const int UserAssociated = 0;
public const int NameType = 0;
public const int IpSec = 1;
public const int Email = 1;
public const int Signatory = 1;
public const int Protocol = sizeof(ushort);
public const int Algorithm = Protocol + sizeof(byte);
......@@ -1703,18 +1708,27 @@ namespace PcapDotNet.Packets.Dns
{
public const byte AuthenticationProhibited = 0x80;
public const byte ConfidentialityProhibited = 0x40;
public const byte Experimental = 0x20;
public const byte IsFlagsExtension = 0x10;
public const byte UserAssociated = 0x04;
public const byte IpSec = 0x80;
public const byte Email = 0x40;
public const byte NameType = 0x03;
public const byte Signatory = 0x0F;
}
private const int ConstantPartLength = Offset.FlagsExtension;
public DnsResourceDataKey(bool authenticationProhibited, bool confidentialityProhibited, DnsKeyNameType nameType, DnsKeySignatory signatory,
DnsKeyProtocol protocol, DnsAlgorithm algorithm, ushort? flagsExtension, DataSegment publicKey)
public DnsResourceDataKey(bool authenticationProhibited, bool confidentialityProhibited, bool experimental, bool userAssociated, bool ipSec, bool email,
DnsKeyNameType nameType, DnsKeySignatory signatory, DnsKeyProtocol protocol, DnsAlgorithm algorithm, ushort? flagsExtension,
DataSegment publicKey)
{
AuthenticationProhibited = authenticationProhibited;
ConfidentialityProhibited = confidentialityProhibited;
Experimental = experimental;
UserAssociated = userAssociated;
IpSec = ipSec;
Email = email;
FlagsExtension = flagsExtension;
NameType = nameType;
Signatory = signatory;
......@@ -1733,6 +1747,43 @@ namespace PcapDotNet.Packets.Dns
/// </summary>
public bool ConfidentialityProhibited { get; private set; }
/// <summary>
/// Ignored if the type field indicates "no key" and the following description assumes that type field to be non-zero.
/// Keys may be associated with zones, entities, or users for experimental, trial, or optional use, in which case this bit will be one.
/// If this bit is a zero, it means that the use or availability of security based on the key is "mandatory".
/// Thus, if this bit is off for a zone key, the zone should be assumed secured by SIG RRs and any responses indicating the zone is not secured should be considered bogus.
/// If this bit is a one for a host or end entity, it might sometimes operate in a secure mode and at other times operate without security.
/// The experimental bit, like all other aspects of the KEY RR, is only effective if the KEY RR is appropriately signed by a SIG RR.
/// The experimental bit must be zero for safe secure operation and should only be a one for a minimal transition period.
/// </summary>
public bool Experimental { get; private set; }
/// <summary>
/// Indicates that this is a key associated with a "user" or "account" at an end entity, usually a host.
/// The coding of the owner name is that used for the responsible individual mailbox in the SOA and RP RRs:
/// The owner name is the user name as the name of a node under the entity name.
/// For example, "j.random_user" on host.subdomain.domain could have a public key associated through a KEY RR
/// with name j\.random_user.host.subdomain.domain and the user bit a one.
/// It could be used in an security protocol where authentication of a user was desired.
/// This key might be useful in IP or other security for a user level service such a telnet, ftp, rlogin, etc.
/// </summary>
public bool UserAssociated { get; private set; }
/// <summary>
/// Indicates that this key is valid for use in conjunction with that security standard.
/// This key could be used in connection with secured communication on behalf of an end entity or user whose name is the owner name of the KEY RR
/// if the entity or user bits are on.
/// The presence of a KEY resource with the IPSEC and entity bits on and experimental and no-key bits off is an assertion that the host speaks IPSEC.
/// </summary>
public bool IpSec { get; private set; }
/// <summary>
/// Indicates that this key is valid for use in conjunction with MIME security multiparts.
/// This key could be used in connection with secured communication on behalf of an end entity or user
/// whose name is the owner name of the KEY RR if the entity or user bits are on.
/// </summary>
public bool Email { get; private set; }
/// <summary>
/// The name type.
/// </summary>
......@@ -1771,6 +1822,10 @@ namespace PcapDotNet.Packets.Dns
return other != null &&
AuthenticationProhibited.Equals(other.AuthenticationProhibited) &&
ConfidentialityProhibited.Equals(other.ConfidentialityProhibited) &&
Experimental.Equals(other.Experimental) &&
UserAssociated.Equals(other.UserAssociated) &&
IpSec.Equals(other.IpSec) &&
Email.Equals(other.Email) &&
NameType.Equals(other.NameType) &&
Signatory.Equals(other.Signatory) &&
Protocol.Equals(other.Protocol) &&
......@@ -1787,7 +1842,8 @@ namespace PcapDotNet.Packets.Dns
}
internal DnsResourceDataKey()
: this(false, false, DnsKeyNameType.ZoneKey, DnsKeySignatory.Zone, DnsKeyProtocol.All, DnsAlgorithm.None, null, DataSegment.Empty)
: this(false, false, false, false, false, false, DnsKeyNameType.ZoneKey, DnsKeySignatory.Zone, DnsKeyProtocol.All, DnsAlgorithm.None, null,
DataSegment.Empty)
{
}
......@@ -1803,12 +1859,20 @@ namespace PcapDotNet.Packets.Dns
flagsByte0 |= Mask.AuthenticationProhibited;
if (ConfidentialityProhibited)
flagsByte0 |= Mask.ConfidentialityProhibited;
if (Experimental)
flagsByte0 |= Mask.Experimental;
if (UserAssociated)
flagsByte0 |= Mask.UserAssociated;
if (FlagsExtension.HasValue)
flagsByte0 |= Mask.IsFlagsExtension;
flagsByte0 |= (byte)((byte)NameType & Mask.NameType);
buffer.Write(offset + Offset.AuthenticationProhibited, flagsByte0);
byte flagsByte1 = 0;
if (IpSec)
flagsByte1 |= Mask.IpSec;
if (Email)
flagsByte1 |= Mask.Email;
flagsByte1 |= (byte)((byte)Signatory & Mask.Signatory);
buffer.Write(offset + Offset.Signatory, flagsByte1);
......@@ -1828,7 +1892,11 @@ namespace PcapDotNet.Packets.Dns
bool authenticationProhibited = data.ReadBool(Offset.AuthenticationProhibited, Mask.AuthenticationProhibited);
bool confidentialityProhibited = data.ReadBool(Offset.ConfidentialityProhibited, Mask.ConfidentialityProhibited);
bool experimental = data.ReadBool(Offset.Experimental, Mask.Experimental);
bool isFlagsExtension = data.ReadBool(Offset.IsFlagsExtension, Mask.IsFlagsExtension);
bool userAssociated = data.ReadBool(Offset.UserAssociated, Mask.UserAssociated);
bool ipSec = data.ReadBool(Offset.IpSec, Mask.IpSec);
bool email = data.ReadBool(Offset.Email, Mask.Email);
DnsKeyNameType nameType = (DnsKeyNameType)(data[Offset.NameType] & Mask.NameType);
DnsKeySignatory signatory = (DnsKeySignatory)(data[Offset.Signatory] & Mask.Signatory);
DnsKeyProtocol protocol = (DnsKeyProtocol)data[Offset.Protocol];
......@@ -1837,8 +1905,8 @@ namespace PcapDotNet.Packets.Dns
int publicKeyOffset = Offset.FlagsExtension + (isFlagsExtension ? sizeof(ushort) : 0);
DataSegment publicKey = data.SubSegment(publicKeyOffset, data.Length - publicKeyOffset);
return new DnsResourceDataKey(authenticationProhibited, confidentialityProhibited, nameType, signatory, protocol, algorithm, flagsExtension,
publicKey);
return new DnsResourceDataKey(authenticationProhibited, confidentialityProhibited, experimental, userAssociated, ipSec, email, nameType, signatory,
protocol, algorithm, flagsExtension, publicKey);
}
}
......@@ -1863,7 +1931,7 @@ namespace PcapDotNet.Packets.Dns
private static class Offset
{
public const int Preference = 0;
public const int Map822 = Preference + IpV4Address.SizeOf;
public const int Map822 = Preference + sizeof(ushort);
}
private const int ConstantPartLength = Offset.Map822;
......@@ -2029,32 +2097,35 @@ namespace PcapDotNet.Packets.Dns
byte[] latitudeBytes = Encoding.ASCII.GetBytes(Latitude);
byte[] altitudeBytes = Encoding.ASCII.GetBytes(Altitude);
buffer.Write(ref offset, (byte)longtitudeBytes.Length);
buffer.Write(ref offset, longtitudeBytes);
++offset;
buffer.Write(ref offset, (byte)latitudeBytes.Length);
buffer.Write(ref offset, latitudeBytes);
++offset;
buffer.Write(ref offset, (byte)altitudeBytes.Length);
buffer.Write(ref offset, altitudeBytes);
++offset;
}
internal override DnsResourceData CreateInstance(DataSegment data)
{
int longtitudeNumBytes = data.TakeWhile(value => value != 0).Count();
if (longtitudeNumBytes == data.Length)
if (data.Length < 3)
return null;
string longtitude = data.SubSegment(0, longtitudeNumBytes).ToString(Encoding.ASCII);
int longtitudeNumBytes = data[0];
if (data.Length < longtitudeNumBytes + 3)
return null;
string longtitude = data.SubSegment(1, longtitudeNumBytes).ToString(Encoding.ASCII);
data = data.SubSegment(longtitudeNumBytes + 1, data.Length - longtitudeNumBytes - 1);
int latitudeNumBytes = data.TakeWhile(value => value != 0).Count();
if (latitudeNumBytes == data.Length)
int latitudeNumBytes = data[0];
if (data.Length < latitudeNumBytes + 2)
return null;
string latitude = data.SubSegment(0, latitudeNumBytes).ToString(Encoding.ASCII);
string latitude = data.SubSegment(1, latitudeNumBytes).ToString(Encoding.ASCII);
data = data.SubSegment(latitudeNumBytes + 1, data.Length - latitudeNumBytes - 1);
int altitudeNumBytes = data.TakeWhile(value => value != 0).Count();
if (altitudeNumBytes == data.Length)
int altitudeNumBytes = data[0];
if (data.Length != altitudeNumBytes + 1)
return null;
string altitude = data.SubSegment(0, altitudeNumBytes).ToString(Encoding.ASCII);
string altitude = data.SubSegment(1, altitudeNumBytes).ToString(Encoding.ASCII);
return new DnsResourceDataGeographicalPosition(longtitude, latitude, altitude);
}
......@@ -2369,6 +2440,25 @@ namespace PcapDotNet.Packets.Dns
/// </summary>
public DataSegment TypeBitMap { get; private set; }
public IEnumerable<DnsType> TypesExist
{
get
{
ushort typeValue = 0;
for (int byteOffset = 0; byteOffset != TypeBitMap.Length; ++byteOffset)
{
byte mask = 0x80;
for (int i = 0; i != 8; ++i)
{
if (TypeBitMap.ReadBool(byteOffset, mask))
yield return (DnsType)typeValue;
++typeValue;
mask >>= 1;
}
}
}
}
public bool IsTypePresentForOwner(DnsType dnsType)
{
if (dnsType >= MaxTypeBitMapDnsType)
......@@ -2886,6 +2976,7 @@ namespace PcapDotNet.Packets.Dns
}
/// <summary>
/// RFC 2230.
/// <pre>
/// +-----+-------------------+
/// | bit | 0-15 |
......@@ -4529,7 +4620,23 @@ namespace PcapDotNet.Packets.Dns
KeyTag = keyTag;
Algorithm = algorithm;
DigestType = digestType;
Digest = digest;
int maxDigestLength;
switch (DigestType)
{
case DnsDigestType.Sha1:
maxDigestLength = 20;
break;
case DnsDigestType.Sha256:
maxDigestLength = 32;
break;
default:
maxDigestLength = int.MaxValue;
break;
}
Digest = digest.SubSegment(0, Math.Min(digest.Length, maxDigestLength));
ExtraDigest = digest.SubSegment(Digest.Length, digest.Length - Digest.Length);
}
/// <summary>
......@@ -4553,9 +4660,14 @@ namespace PcapDotNet.Packets.Dns
/// Calculated over the canonical name of the delegated domain name followed by the whole RDATA of the KEY record (all four fields).
/// digest = hash(canonical FQDN on KEY RR | KEY_RR_rdata)
/// KEY_RR_rdata = Flags | Protocol | Algorithm | Public Key
/// The size of the digest may vary depending on the digest type.
/// </summary>
public DataSegment Digest { get; private set; }
/// <summary>
/// The extra digest bytes after number of bytes according to the digest type.
/// </summary>
public DataSegment ExtraDigest { get; private set; }
public bool Equals(DnsResourceDataDelegationSigner other)
{
......@@ -4615,7 +4727,7 @@ namespace PcapDotNet.Packets.Dns
/// RFC 4255.
/// Describes the algorithm of the public key.
/// </summary>
public enum DnsFingerprintPublicKeyAlgorithm
public enum DnsFingerprintPublicKeyAlgorithm : byte
{
Rsa = 1,
Dss = 2,
......@@ -5298,18 +5410,18 @@ namespace PcapDotNet.Packets.Dns
}
/// <summary>
/// RFC 4034.
/// RFC 4034, 5011.
/// <pre>
/// +-----+----------+----------+----------+--------------------+
/// | bit | 0-6 | 7 | 8-14 | 15 |
/// +-----+----------+----------+----------+--------------------+
/// | 0 | Reserved | Zone Key | Reserved | Secure Entry Point |
/// +-----+----------+----------+----------+--------------------+
/// | 16 | Protocol | Algorithm |
/// +-----+---------------------+-------------------------------+
/// | 32 | Public Key |
/// | ... | |
/// +-----+---------------------+-------------------------------+
/// +-----+----------+----------+--------+----------+--------------------+
/// | bit | 0-6 | 7 | 8 | 9-14 | 15 |
/// +-----+----------+----------+--------+----------+--------------------+
/// | 0 | Reserved | Zone Key | Revoke | Reserved | Secure Entry Point |
/// +-----+----------+----------+--------+----------+--------------------+
/// | 16 | Protocol | Algorithm |
/// +-----+---------------------+----------------------------------------+
/// | 32 | Public Key |
/// | ... | |
/// +-----+--------------------------------------------------------------+
/// </pre>
/// </summary>
[DnsTypeRegistration(Type = DnsType.DnsKey)]
......@@ -5320,6 +5432,7 @@ namespace PcapDotNet.Packets.Dns
private static class Offset
{
public const int ZoneKey = 0;
public const int Revoke = 1;
public const int SecureEntryPoint = 1;
public const int Protocol = sizeof(ushort);
public const int Algorithm = Protocol + sizeof(byte);
......@@ -5329,14 +5442,16 @@ namespace PcapDotNet.Packets.Dns
private static class Mask
{
public const byte ZoneKey = 0x01;
public const byte Revoke = 0x80;
public const byte SecureEntryPoint = 0x01;
}
private const int ConstantPartLength = Offset.PublicKey;
public DnsResourceDataDnsKey(bool zoneKey, bool secureEntryPoint, byte protocol, DnsAlgorithm algorithm, DataSegment publicKey)
public DnsResourceDataDnsKey(bool zoneKey, bool revoke, bool secureEntryPoint, byte protocol, DnsAlgorithm algorithm, DataSegment publicKey)
{
ZoneKey = zoneKey;
Revoke = revoke;
SecureEntryPoint = secureEntryPoint;
Protocol = protocol;
Algorithm = algorithm;
......@@ -5349,6 +5464,12 @@ namespace PcapDotNet.Packets.Dns
/// </summary>
public bool ZoneKey { get; private set; }
/// <summary>
/// If true, and the resolver sees an RRSIG(DNSKEY) signed by the associated key,
/// then the resolver must consider this key permanently invalid for all purposes except for validating the revocation.
/// </summary>
public bool Revoke { get; private set; }
/// <summary>
/// RFC 3757.
/// If true, then the DNSKEY record holds a key intended for use as a secure entry point.
......@@ -5379,6 +5500,7 @@ namespace PcapDotNet.Packets.Dns
{
return other != null &&
ZoneKey.Equals(other.ZoneKey) &&
Revoke.Equals(other.Revoke) &&
SecureEntryPoint.Equals(other.SecureEntryPoint) &&
Protocol.Equals(other.Protocol) &&
Algorithm.Equals(other.Algorithm) &&
......@@ -5391,7 +5513,7 @@ namespace PcapDotNet.Packets.Dns
}
internal DnsResourceDataDnsKey()
: this(false, false, ProtocolValue, DnsAlgorithm.None, DataSegment.Empty)
: this(false, false, false, ProtocolValue, DnsAlgorithm.None, DataSegment.Empty)
{
}
......@@ -5408,6 +5530,8 @@ namespace PcapDotNet.Packets.Dns
buffer.Write(offset + Offset.ZoneKey, flagsByte0);
byte flagsByte1 = 0;
if (Revoke)
flagsByte1 |= Mask.Revoke;
if (SecureEntryPoint)
flagsByte1 |= Mask.SecureEntryPoint;
buffer.Write(offset + Offset.SecureEntryPoint, flagsByte1);
......@@ -5423,12 +5547,13 @@ namespace PcapDotNet.Packets.Dns
return null;
bool zoneKey = data.ReadBool(Offset.ZoneKey, Mask.ZoneKey);
bool revoke = data.ReadBool(Offset.Revoke, Mask.Revoke);
bool secureEntryPoint = data.ReadBool(Offset.SecureEntryPoint, Mask.SecureEntryPoint);
byte protocol = data[Offset.Protocol];
DnsAlgorithm algorithm = (DnsAlgorithm)data[Offset.Algorithm];
DataSegment publicKey = data.SubSegment(Offset.PublicKey, data.Length - ConstantPartLength);
return new DnsResourceDataDnsKey(zoneKey, secureEntryPoint, protocol, algorithm, publicKey);
return new DnsResourceDataDnsKey(zoneKey, revoke, secureEntryPoint, protocol, algorithm, publicKey);
}
}
......
......@@ -89,7 +89,7 @@ namespace PcapDotNet.Packets.Dns
internal static bool TryParseBase(DnsDatagram dns, int offsetInDns,
out DnsDomainName domainName, out DnsType type, out DnsClass dnsClass, out int numBytesRead)
{
type = DnsType.All;
type = DnsType.Any;
dnsClass = DnsClass.Any;
if (!DnsDomainName.TryParse(dns, offsetInDns, dns.Length - offsetInDns, out domainName, out numBytesRead))
return false;
......
......@@ -178,7 +178,7 @@
Sig = 24,
/// <summary>
/// RFCs 2535, 3755, 4034.
/// RFCs 2065, 2535, 3755, 4034.
/// For security key.
/// Payload type: DnsResourceDataKey.
/// </summary>
......@@ -340,7 +340,7 @@
NSec = 47,
/// <summary>
/// RFCs 3755, 4034.
/// RFCs 3755, 4034, 5011.
/// DNSKEY.
/// Represents the public key.
/// Payload type: DnsResourceDataDnsKey.
......@@ -483,7 +483,7 @@
/// A request for all records
/// Query Type.
/// </summary>
All = 255,
Any = 255,
/// <summary>
/// Faltstrom.
......
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