Folder structure reconstruction
This commit is contained in:
287
MailServer/DNSClient/Query/DnsQueryBase.cs
Normal file
287
MailServer/DNSClient/Query/DnsQueryBase.cs
Normal 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
|
||||
}
|
||||
}
|
385
MailServer/DNSClient/Query/DnsQueryRequest.cs
Normal file
385
MailServer/DNSClient/Query/DnsQueryRequest.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
168
MailServer/DNSClient/Query/DnsQueryResponse.cs
Normal file
168
MailServer/DNSClient/Query/DnsQueryResponse.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user