Folder structure reconstruction

This commit is contained in:
Fabian Stamm
2016-12-09 15:41:35 +01:00
parent df48102215
commit c4c32efb04
98 changed files with 5 additions and 2 deletions

View File

@ -0,0 +1,287 @@
/**********************************************************************
* Copyright (c) 2010, j. montgomery *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* + Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* + Redistributions in binary form must reproduce the above copyright*
* notice, this list of conditions and the following disclaimer *
* in the documentation and/or other materials provided with the *
* distribution. *
* *
* + Neither the name of j. montgomery's employer nor the names of *
* its contributors may be used to endorse or promote products *
* derived from this software without specific prior written *
* permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
* OF THE POSSIBILITY OF SUCH DAMAGE. *
**********************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using DnDns.Enums;
using DnDns.Records;
namespace DnDns.Query
{
/// <summary>
/// DnsQueryBase maintains the common state of DNS Queries (both responses and requests)
/// </summary>
public abstract class DnsQueryBase
{
#region Fields
// RFC 1034
//
// 4.1.1. Header section format
//
// 1 1 1 1 1 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ID |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QDCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ANCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | NSCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ARCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// <summary>
/// ID - A 16 bit identifier. This identifier is copied
/// the corresponding reply and can be used by the requester
/// to match up replies to outstanding queries.
/// </summary>
protected ushort _transactionId;
/// <summary>
/// _flags will store a combination of the enums that make up the 16 bits after the
/// TransactionID in the DNS protocol header
/// </summary>
protected ushort _flags;
/// <summary>
/// A one bit field that specifies whether this message is a
/// query (0), or a response (1).
/// </summary>
protected QueryResponse _queryResponse;
/// <summary>
/// OPCODE - A four bit field that specifies kind of query in this
/// message. This value is set by the originator of a query
/// and copied into the response.
/// </summary>
protected OpCode _opCode;
/// <summary>
/// - A combination of flag fields in the DNS header (|AA|TC|RD|RA|)
/// </summary>
protected NsFlags _nsFlags;
/// <summary>
/// Response code - this 4 bit field is set as part of
/// responses only.
/// </summary>
protected RCode _rCode;
/// <summary>
/// QDCOUNT - an unsigned 16 bit integer specifying the number of
/// entries in the question section.
/// </summary>
protected ushort _questions;
/// <summary>
/// ANCOUNT - an unsigned 16 bit integer specifying the number of
/// resource records in the answer section.
/// </summary>
protected ushort _answerRRs;
/// <summary>
/// NSCOUNT - an unsigned 16 bit integer specifying the number of name
/// server resource records in the authority records
/// section.
/// </summary>
protected ushort _authorityRRs;
// RFC 1034
// 4.1.2. Question section format
// 1 1 1 1 1 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | |
// / QNAME /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QTYPE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QCLASS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// <summary>
/// QNAME - a domain name represented as a sequence of labels, where
/// each label consists of a length octet followed by that
/// number of octets. The domain name terminates with the
/// zero length octet for the null label of the root. Note
/// that this field may be an odd number of octets; no
/// padding is used
/// </summary>
protected string _name;
/// <summary>
/// QTYPE - a two octet code which specifies the type of the query.
/// The values for this field include all codes valid for a
/// TYPE field, together with some more general codes which
/// can match more than one type of RR.
/// </summary>
protected NsType _nsType;
/// <summary>
/// QCLASS - a two octet code that specifies the class of the query.
/// For example, the QCLASS field is IN for the Internet.
/// </summary>
protected NsClass _nsClass;
/// <summary>
/// The additional records for the DNS Query
/// </summary>
protected List<IDnsRecord> _additionalRecords = new List<IDnsRecord>();
#endregion Fields
#region Properties
/// ID - A 16 bit identifier. This identifier is copied
/// the corresponding reply and can be used by the requester
/// to match up replies to outstanding queries.
/// </summary>
public ushort TransactionID
{
get { return _transactionId; }
}
/// <summary>
/// A one bit field that specifies whether this message is a
/// query (0), or a response (1).
/// </summary>
public QueryResponse QueryResponse
{
get { return _queryResponse; }
}
/// <summary>
/// OPCODE - A four bit field that specifies kind of query in this
/// message. This value is set by the originator of a query
/// and copied into the response.
/// </summary>
public OpCode OpCode
{
get { return _opCode; }
}
/// <summary>
/// NsFlags - A combination of flag fields in the DNS header (|AA|TC|RD|RA|)
/// </summary>
public NsFlags NsFlags
{
get { return _nsFlags; }
}
/// <summary>
/// Response code - this 4 bit field is set as part of
/// responses only.
/// </summary>
public RCode RCode
{
get { return _rCode; }
}
/// <summary>
/// QDCOUNT - an unsigned 16 bit integer specifying the number of
/// entries in the question section.
/// </summary>
public ushort Questions
{
get { return _questions; }
}
/// <summary>
/// ANCOUNT - an unsigned 16 bit integer specifying the number of
/// resource records in the answer section.
/// </summary>
public ushort AnswerRRs
{
get { return _answerRRs; }
}
/// <summary>
/// NSCOUNT - an unsigned 16 bit integer specifying the number of name
/// server resource records in the authority records
/// section.
/// </summary>
public ushort AuthorityRRs
{
get { return _authorityRRs; }
}
/// <summary>
/// ARCOUNT - an unsigned 16 bit integer specifying the number of
/// resource records in the additional records section.
/// </summary>
public ushort AdditionalRRs
{
get { return (ushort) _additionalRecords.Count; }
}
/// <summary>
/// QNAME - a domain name represented as a sequence of labels, where
/// each label consists of a length octet followed by that
/// number of octets. The domain name terminates with the
/// zero length octet for the null label of the root. Note
/// that this field may be an odd number of octets; no
/// padding is used
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// QTYPE - a two octet code which specifies the type of the query.
/// The values for this field include all codes valid for a
/// TYPE field, together with some more general codes which
/// can match more than one type of RR.
/// </summary>
public NsType NsType
{
get { return _nsType; }
set { _nsType = value; }
}
/// <summary>
/// QCLASS - a two octet code that specifies the class of the query.
/// For example, the QCLASS field is IN for the Internet.
/// </summary>
public NsClass NsClass
{
get { return _nsClass; }
set { _nsClass = value; }
}
public List<IDnsRecord> AdditionalRRecords
{
get { return _additionalRecords; }
}
#endregion
}
}

View File

@ -0,0 +1,385 @@
/**********************************************************************
* Copyright (c) 2010, j. montgomery *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* + Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* + Redistributions in binary form must reproduce the above copyright*
* notice, this list of conditions and the following disclaimer *
* in the documentation and/or other materials provided with the *
* distribution. *
* *
* + Neither the name of j. montgomery's employer nor the names of *
* its contributors may be used to endorse or promote products *
* derived from this software without specific prior written *
* permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
* OF THE POSSIBILITY OF SUCH DAMAGE. *
**********************************************************************/
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Text;
using DnDns.Enums;
using DnDns.Records;
using DnDns.Security;
using System.Threading.Tasks;
namespace DnDns.Query
{
/// <summary>
/// Summary description for DnsQueryRequest.
/// </summary>
public class DnsQueryRequest : DnsQueryBase
{
private static Random r = new Random();
private int _bytesSent = 0;
private int _socketTimeout = 5000;
/// <summary>
/// The number of bytes sent to query the DNS Server.
/// </summary>
public int BytesSent
{
get { return _bytesSent; }
}
/// <summary>
/// Gets or sets the amount of time in milliseconds that a DnsQueryRequest will wait to receive data once a read operation is initiated.
/// Defauts to 5 seconds (5000 ms)
/// </summary>
public int Timeout
{
get { return _socketTimeout; }
set { _socketTimeout = value; }
}
#region Constructors
public DnsQueryRequest()
{
// Construct the class with some defaults
_transactionId = (ushort) r.Next();
_flags = 0;
_queryResponse = QueryResponse.Query;
this._opCode = OpCode.QUERY;
// Recursion Desired
this._nsFlags = NsFlags.RD;
this._questions = 1;
}
#endregion Constructors
private byte[] BuildQuery(string host)
{
string newHost;
int newLocation = 0;
int oldLocation = 0;
MemoryStream ms = new MemoryStream();
host = host.Trim();
// decide how to build this query based on type
switch (_nsType)
{
case NsType.PTR:
IPAddress queryIP = IPAddress.Parse(host);
// pointer should be translated as follows
// 209.115.22.3 -> 3.22.115.209.in-addr.arpa
char[] ipDelim = new char[] {'.'};
string[] s = host.Split(ipDelim,4);
newHost = String.Format("{0}.{1}.{2}.{3}.in-addr.arpa", s[3], s[2], s[1], s[0]);
break;
default:
newHost = host;
break;
}
// Package up the host
while(oldLocation < newHost.Length)
{
newLocation = newHost.IndexOf(".", oldLocation);
if (newLocation == -1) newLocation = newHost.Length;
byte subDomainLength = (byte)(newLocation - oldLocation);
char[] sub = newHost.Substring(oldLocation, subDomainLength).ToCharArray();
ms.WriteByte(subDomainLength);
ms.Write(Encoding.ASCII.GetBytes(sub, 0, sub.Length), 0, sub.Length);
oldLocation = newLocation + 1;
}
// Terminate the domain name w/ a 0x00.
ms.WriteByte(0x00);
return ms.ToArray();
}
/// <summary>
///
/// </summary>
/// <param name="host"></param>
/// <param name="queryType"></param>
/// <param name="queryClass"></param>
/// <param name="protocol"></param>
/// <returns></returns>
public async Task<DnsQueryResponse> ResolveAsync(string host, NsType queryType, NsClass queryClass, ProtocolType protocol)
{
return await ResolveAsync(host, queryType, queryClass, protocol, null);
}
public async Task<DnsQueryResponse> ResolveAsync(string host, NsType queryType, NsClass queryClass, ProtocolType protocol, TsigMessageSecurityProvider provider)
{
string dnsServer = string.Empty;
dnsServer = "8.8.8.8";
/*// Test for Unix/Linux OS
if (Tools.IsPlatformLinuxUnix())
{
dnsServer = Tools.DiscoverUnixDnsServerAddress();
}
else
{
IPAddressCollection dnsServerCollection = Tools.DiscoverDnsServerAddresses();
if (dnsServerCollection.Count == 0)
throw new Exception("Couldn't detect local DNS Server.");
dnsServer = dnsServerCollection[0].ToString();
}
if (String.IsNullOrEmpty(dnsServer))
throw new Exception("Couldn't detect local DNS Server.");
*/
return await ResolveAsync(dnsServer, host, queryType, queryClass, protocol, provider);
}
/// <summary>
///
/// </summary>
/// <param name="dnsServer"></param>
/// <param name="host"></param>
/// <param name="queryType"></param>
/// <param name="queryClass"></param>
/// <param name="protocol"></param>
/// <param name="messageSecurityProvider">The instance of the message security provider to use to secure the DNS request.</param>
/// <returns>A <see cref="T:DnDns.Net.Dns.DnsQueryResponse"></see> instance that contains the Dns Answer for the request query.</returns>
/// <PermissionSet>
/// <IPermission class="System.Net.DnsPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
/// </PermissionSet>
public async Task<DnsQueryResponse> ResolveAsync(string dnsServer, string host, NsType queryType, NsClass queryClass, ProtocolType protocol, IMessageSecurityProvider messageSecurityProvider)
{
byte[] bDnsQuery = this.BuildDnsRequest(host, queryType, queryClass, protocol, messageSecurityProvider);
// Connect to DNS server and get the record for the current server.
IPHostEntry ipe = await Dns.GetHostEntryAsync(dnsServer);
IPAddress ipa = ipe.AddressList[0];
IPEndPoint ipep = new IPEndPoint(ipa, (int)UdpServices.Domain);
byte[] recvBytes = null;
switch (protocol)
{
case ProtocolType.Tcp:
{
recvBytes = ResolveTcp(bDnsQuery, ipep);
break;
}
case ProtocolType.Udp:
{
recvBytes = ResolveUdp(bDnsQuery, ipep);
break;
}
default:
{
throw new InvalidOperationException("Invalid Protocol: " + protocol);
}
}
//Console.Assert(recvBytes != null, "Failed to retrieve data from the remote DNS server.");
if(recvBytes == null)
{
Logging.AddLogMessage(Logging.LoggingType.ERROR, "Failed to retrieve data from the remote DNS server.");
}
DnsQueryResponse dnsQR = new DnsQueryResponse();
dnsQR.ParseResponse(recvBytes, protocol);
return dnsQR;
}
private byte[] ResolveUdp(byte[] bDnsQuery, IPEndPoint ipep)
{
// UDP messages, data size = 512 octets or less
//UdpClient udpClient = new UdpClient();
Socket udp = new Socket(SocketType.Dgram, ProtocolType.Udp);
byte[] recvBytes = null;
try
{
udp.ReceiveTimeout = _socketTimeout;
//udpClient.Client.ReceiveTimeout = _socketTimeout;
//udpClient.ConnectAsync(ipep);
udp.Connect(ipep);
//udpClient.Send(bDnsQuery, bDnsQuery.Length);
udp.Send(bDnsQuery);
//recvBytes = udpClient.Receive(ref ipep);
recvBytes = new byte[udp.ReceiveBufferSize];
udp.Receive(recvBytes);
}
finally
{
//udpClient.Close();
}
return recvBytes;
}
private static byte[] ResolveTcp(byte[] bDnsQuery, IPEndPoint ipep)
{
Socket tcp = new Socket(SocketType.Stream, ProtocolType.Tcp);
//TcpClient tcpClient = new TcpClient();
byte[] recvBytes = null;
try
{
tcp.Connect(ipep);
//tcpClient.ConnectAsync(ipep);
//NetworkStream ns = tcp.Receive
//NetworkStream netStream = tcpClient.GetStream();
//BinaryReader netReader = new System.IO.BinaryReader(netStream);
//netStream.Write(bDnsQuery, 0, bDnsQuery.Length);
tcp.Send(bDnsQuery);
// wait until data is avail
//while (!netStream.DataAvailable) ;
while (tcp.Available < 1) ;
//if (tcpClient.Connected && netStream.DataAvailable)
if (tcp.Connected && tcp.Available > 1)
{
// Read first two bytes to find out the length of the response
byte[] bLen = new byte[2];
// NOTE: The order of the next two lines matter. Do not reorder
// Array indexes are also intentionally reversed
tcp.Receive(bLen, bLen.Length, SocketFlags.None);
//bLen[1] = (byte)netStream.ReadByte();
//bLen[0] = (byte)netStream.ReadByte();
UInt16 length = BitConverter.ToUInt16(bLen, 0);
recvBytes = new byte[length];
tcp.Receive(recvBytes, length, SocketFlags.None);
//netStream.Read(recvBytes, 0, length);
}
} catch (Exception e) {
Logging.AddException(e);
}
return recvBytes;
}
private byte[] BuildDnsRequest(string host, NsType queryType, NsClass queryClass, ProtocolType protocol, IMessageSecurityProvider messageSecurityProvider)
{
// Combind the NsFlags with our constant flags
ushort flags = (ushort)((ushort)_queryResponse | (ushort)_opCode | (ushort)_nsFlags);
this._flags = flags;
//NOTE: This limits the librarys ablity to issue multiple queries per request.
this._nsType = queryType;
this._nsClass = queryClass;
this._name = host;
if(messageSecurityProvider != null)
{
messageSecurityProvider.SecureMessage(this);
}
byte[] bDnsQuery = GetMessageBytes();
// Add two byte prefix that contains the packet length per RFC 1035 section 4.2.2
if (protocol == ProtocolType.Tcp)
{
// 4.2.2. TCP usageMessages sent over TCP connections use server port 53 (decimal).
// The message is prefixed with a two byte length field which gives the message
// length, excluding the two byte length field. This length field allows the
// low-level processing to assemble a complete message before beginning to parse
// it.
int len = bDnsQuery.Length;
Array.Resize<byte>(ref bDnsQuery, len + 2);
Array.Copy(bDnsQuery, 0, bDnsQuery, 2, len);
bDnsQuery[0] = (byte)((len >> 8) & 0xFF);
bDnsQuery[1] = (byte)((len & 0xFF));
}
return bDnsQuery;
}
internal byte[] GetMessageBytes()
{
MemoryStream memoryStream = new MemoryStream();
byte[] data = new byte[2];
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_transactionId) >> 16));
memoryStream.Write(data, 0, data.Length);
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_flags) >> 16));
memoryStream.Write(data, 0, data.Length);
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_questions) >> 16));
memoryStream.Write(data, 0, data.Length);
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_answerRRs) >> 16));
memoryStream.Write(data, 0, data.Length);
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_authorityRRs) >> 16));
memoryStream.Write(data, 0, data.Length);
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_additionalRecords.Count) >> 16));
memoryStream.Write(data, 0, data.Length);
data = DnsHelpers.CanonicaliseDnsName(_name, false);
memoryStream.Write(data, 0, data.Length);
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_nsType) >> 16));
memoryStream.Write(data, 0, data.Length);
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_nsClass) >> 16));
memoryStream.Write(data, 0, data.Length);
foreach (IDnsRecord dnsRecord in AdditionalRRecords)
{
data = dnsRecord.GetMessageBytes();
memoryStream.Write(data, 0, data.Length);
}
Logging.AddLogMessage(Logging.LoggingType.INFO, String.Format("The message bytes: {0}", DnsHelpers.DumpArrayToString(memoryStream.ToArray())));
return memoryStream.ToArray();
}
}
}

View File

@ -0,0 +1,168 @@
/**********************************************************************
* Copyright (c) 2010, j. montgomery *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* + Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* + Redistributions in binary form must reproduce the above copyright*
* notice, this list of conditions and the following disclaimer *
* in the documentation and/or other materials provided with the *
* distribution. *
* *
* + Neither the name of j. montgomery's employer nor the names of *
* its contributors may be used to endorse or promote products *
* derived from this software without specific prior written *
* permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
* OF THE POSSIBILITY OF SUCH DAMAGE. *
**********************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using DnDns.Records;
using DnDns.Enums;
namespace DnDns.Query
{
/// <summary>
/// Summary description for DnsQueryResponse.
/// </summary>
public class DnsQueryResponse : DnsQueryBase
{
#region Fields
private DnsQueryRequest _queryRequest = new DnsQueryRequest();
private IDnsRecord[] _answers;
private IDnsRecord[] _authoritiveNameServers;
private int _bytesReceived = 0;
#endregion Fields
#region properties
public DnsQueryRequest QueryRequest
{
get { return _queryRequest; }
}
public IDnsRecord[] Answers
{
get { return _answers; }
}
public IDnsRecord[] AuthoritiveNameServers
{
get { return _authoritiveNameServers; }
}
public int BytesReceived
{
get { return _bytesReceived; }
}
#endregion
/// <summary>
///
/// </summary>
public DnsQueryResponse()
{
}
private DnsQueryRequest ParseQuery(ref MemoryStream ms)
{
DnsQueryRequest queryRequest = new DnsQueryRequest();
// Read name
queryRequest.Name = DnsRecordBase.ParseName(ref ms);
return queryRequest;
}
internal void ParseResponse(byte[] recvBytes, ProtocolType protocol)
{
MemoryStream memoryStream = new MemoryStream(recvBytes);
byte[] flagBytes = new byte[2];
byte[] transactionId = new byte[2];
byte[] questions = new byte[2];
byte[] answerRRs = new byte[2];
byte[] authorityRRs = new byte[2];
byte[] additionalRRCountBytes = new byte[2];
byte[] nsType = new byte[2];
byte[] nsClass = new byte[2];
this._bytesReceived = recvBytes.Length;
// Parse DNS Response
memoryStream.Read(transactionId, 0, 2);
memoryStream.Read(flagBytes, 0, 2);
memoryStream.Read(questions, 0, 2);
memoryStream.Read(answerRRs, 0, 2);
memoryStream.Read(authorityRRs, 0, 2);
memoryStream.Read(additionalRRCountBytes, 0, 2);
// Parse Header
_transactionId = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(transactionId, 0));
_flags = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(flagBytes, 0));
_queryResponse = (QueryResponse)(_flags & (ushort)FlagMasks.QueryResponseMask);
_opCode = (OpCode)(_flags & (ushort)FlagMasks.OpCodeMask);
_nsFlags = (NsFlags)(_flags & (ushort)FlagMasks.NsFlagMask);
_rCode = (RCode)(_flags & (ushort)FlagMasks.RCodeMask);
// Parse Questions Section
_questions = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(questions, 0));
_answerRRs = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(answerRRs, 0));
_authorityRRs = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(authorityRRs, 0));
ushort additionalRRCount = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(additionalRRCountBytes, 0));
_additionalRecords = new List<IDnsRecord>();
_answers = new DnsRecordBase[_answerRRs];
_authoritiveNameServers = new DnsRecordBase[_authorityRRs];
// Parse Queries
_queryRequest = this.ParseQuery(ref memoryStream);
// Read dnsType
memoryStream.Read(nsType, 0, 2);
// Read dnsClass
memoryStream.Read(nsClass, 0, 2);
_nsType = (NsType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsType, 0));
_nsClass = (NsClass)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsClass, 0));
// Read in Answer Blocks
for (int i=0; i < _answerRRs; i++)
{
_answers[i] = RecordFactory.Create(ref memoryStream);
}
// Parse Authority Records
for (int i=0; i < _authorityRRs; i++)
{
_authoritiveNameServers[i] = RecordFactory.Create(ref memoryStream);
}
// Parse Additional Records
for (int i=0; i < additionalRRCount; i++)
{
_additionalRecords.Add(RecordFactory.Create(ref memoryStream));
}
}
}
}