Пример #1
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner DNS client.</param>
        /// <param name="dnsServers">DNS servers.</param>
        /// <param name="id">Transaction ID.</param>
        /// <param name="qtype">QTYPE value.</param>
        /// <param name="qname">QNAME value.</param>
        /// <param name="timeout">Timeout in milliseconds.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>qname</b> is null reference.</exception>
        internal DNS_ClientTransaction(Dns_Client owner, IPAddress[] dnsServers, int id, DNS_QType qtype, string qname, int timeout)
        {
            if (owner == null)
            {
                throw new ArgumentNullException("owner");
            }
            if (dnsServers == null)
            {
                throw new ArgumentNullException("dnsServers");
            }
            if (qname == null)
            {
                throw new ArgumentNullException("qname");
            }

            m_pOwner      = owner;
            m_pDnsServers = dnsServers;
            m_ID          = id;
            m_QName       = qname;
            m_QType       = qtype;

            m_CreateTime             = DateTime.Now;
            m_pTimeoutTimer          = new TimerEx(timeout);
            m_pTimeoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimeoutTimer_Elapsed);
        }
Пример #2
0
        /// <summary>
        /// Queries server with specified query.
        /// </summary>
        /// <param name="queryText">Query text. It depends on queryType.</param>
        /// <param name="queryType">Query type.</param>
        /// <param name="timeout">Query timeout in milli seconds.</param>
        /// <returns>Returns DSN server response.</returns>
        public DnsServerResponse Query(string queryText, DNS_QType queryType, int timeout)
        {
            DnsServerResponse retVal = null;
            ManualResetEvent  wait   = new ManualResetEvent(false);

            DNS_ClientTransaction transaction = CreateTransaction(queryType, queryText, timeout);

            transaction.Timeout += delegate(object s, EventArgs e)
            {
                wait.Set();
            };
            transaction.StateChanged += delegate(object s1, EventArgs <DNS_ClientTransaction> e1)
            {
                if (transaction.State == DNS_ClientTransactionState.Completed || transaction.State == DNS_ClientTransactionState.Disposed)
                {
                    retVal = transaction.Response;

                    wait.Set();
                }
            };
            transaction.Start();

            // Wait transaction to complete.
            wait.WaitOne();

            return(retVal);
        }
Пример #3
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="qclass">Query class.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qname">Query text. It depends on query type.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>qname</b> is null reference.</exception>
        public DNS_Query(DNS_QClass qclass,DNS_QType qtype,string qname)
        {
            if(qname == null){
                throw new ArgumentNullException("qname");
            }

            m_QClass = qclass;
            m_QType  = qtype;
            m_QName  = qname;
        }
Пример #4
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="qclass">Query class.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qname">Query text. It depends on query type.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>qname</b> is null reference.</exception>
        public DNS_Query(DNS_QClass qclass, DNS_QType qtype, string qname)
        {
            if (qname == null)
            {
                throw new ArgumentNullException("qname");
            }

            m_QClass = qclass;
            m_QType  = qtype;
            m_QName  = qname;
        }
Пример #5
0
        /// <summary>
        /// Filters out specified type of records from answer.
        /// </summary>
        /// <param name="answers"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private List <DNS_rr> FilterRecordsX(List <DNS_rr> answers, DNS_QType type)
        {
            List <DNS_rr> retVal = new List <DNS_rr>();

            foreach (DNS_rr record in answers)
            {
                if (record.RecordType == type)
                {
                    retVal.Add(record);
                }
            }

            return(retVal);
        }
Пример #6
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner DNS client.</param>
        /// <param name="id">Transaction ID.</param>
        /// <param name="qtype">QTYPE value.</param>
        /// <param name="qname">QNAME value.</param>
        /// <param name="timeout">Timeout in milliseconds.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>qname</b> is null reference.</exception>
        internal DNS_ClientTransaction(Dns_Client owner,int id,DNS_QType qtype,string qname,int timeout)
        {
            if(owner == null){
                throw new ArgumentNullException("owner");
            }
            if(qname == null){
                throw new ArgumentNullException("qname");
            }

            m_pOwner = owner;
            m_ID     = id;
            m_QName  = qname;
            m_QType  = qtype;
                        
            m_CreateTime    = DateTime.Now;
            m_pTimeoutTimer = new TimerEx(timeout);
            m_pTimeoutTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimeoutTimer_Elapsed);
        }
Пример #7
0
		/// <summary>
		/// Creates binary query.
		/// </summary>
        /// <param name="buffer">Buffer where to store query.</param>
		/// <param name="ID">Query ID.</param>
		/// <param name="qname">Query text.</param>
		/// <param name="qtype">Query type.</param>
		/// <param name="qclass">Query class.</param>
		/// <returns>Returns number of bytes stored to <b>buffer</b>.</returns>
		private int CreateQuery(byte[] buffer,int ID,string qname,DNS_QType qtype,int qclass)
		{
			//---- Create header --------------------------------------------//
			// Header is first 12 bytes of query

			/* 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                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			
			QR  A one bit field that specifies whether this message is a
                query (0), or a response (1).
				
			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.  The values are:

                0               a standard query (QUERY)

                1               an inverse query (IQUERY)

                2               a server status request (STATUS)
				
			*/

			//--------- Header part -----------------------------------//
			buffer[0]  = (byte) (ID >> 8); buffer[1]  = (byte) (ID & 0xFF);
			buffer[2]  = (byte) 1;         buffer[3]  = (byte) 0;
			buffer[4]  = (byte) 0;         buffer[5]  = (byte) 1;
			buffer[6]  = (byte) 0;         buffer[7]  = (byte) 0;
			buffer[8]  = (byte) 0;         buffer[9]  = (byte) 0;
			buffer[10] = (byte) 0;         buffer[11] = (byte) 0;
			//---------------------------------------------------------//

			//---- End of header --------------------------------------------//


			//----Create query ------------------------------------//

			/* 	Rfc 1035 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                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			
			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.
			*/

            // Convert unicode domain name. For more info see RFC 5890.
            System.Globalization.IdnMapping ldn = new System.Globalization.IdnMapping();
            qname = ldn.GetAscii(qname);

			string[] labels = qname.Split(new char[] {'.'});
			int position = 12;
					
			// Copy all domain parts(labels) to query
			// eg. lumisoft.ee = 2 labels, lumisoft and ee.
			// format = label.length + label(bytes)
			foreach(string label in labels){
                // convert label string to byte array
                byte[] b = Encoding.ASCII.GetBytes(label);

				// add label lenght to query
				buffer[position++] = (byte)(b.Length);
                b.CopyTo(buffer,position);

				// Move position by label length
				position += b.Length;
			}

			// Terminate domain (see note above)
			buffer[position++] = (byte) 0; 
			
			// Set QTYPE 
			buffer[position++] = (byte) 0;
			buffer[position++] = (byte)qtype;
				
			// Set QCLASS
			buffer[position++] = (byte) 0;
			buffer[position++] = (byte)qclass;
			//-------------------------------------------------------//
			
			return position;
		}
Пример #8
0
        /// <summary>
        /// Creates binary query.
        /// </summary>
        /// <param name="buffer">Buffer where to store query.</param>
        /// <param name="ID">Query ID.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns>Returns number of bytes stored to <b>buffer</b>.</returns>
        private int CreateQuery(byte[] buffer, int ID, string qname, DNS_QType qtype, int qclass)
        {
            //---- Create header --------------------------------------------//
            // Header is first 12 bytes of query

            /* 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                    |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |
             |          QR  A one bit field that specifies whether this message is a
             |  query (0), or a response (1).
             |
             |          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.  The values are:
             |
             |  0               a standard query (QUERY)
             |
             |  1               an inverse query (IQUERY)
             |
             |  2               a server status request (STATUS)
             |
             */

            //--------- Header part -----------------------------------//
            buffer[0]  = (byte)(ID >> 8); buffer[1] = (byte)(ID & 0xFF);
            buffer[2]  = (byte)1; buffer[3] = (byte)0;
            buffer[4]  = (byte)0; buffer[5] = (byte)1;
            buffer[6]  = (byte)0; buffer[7] = (byte)0;
            buffer[8]  = (byte)0; buffer[9] = (byte)0;
            buffer[10] = (byte)0; buffer[11] = (byte)0;
            //---------------------------------------------------------//

            //---- End of header --------------------------------------------//


            //----Create query ------------------------------------//

            /*  Rfc 1035 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                    |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |
             |          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.
             */

            // Convert unicode domain name. For more info see RFC 5890.
            System.Globalization.IdnMapping ldn = new System.Globalization.IdnMapping();
            qname = ldn.GetAscii(qname);

            string[] labels   = qname.Split(new char[] { '.' });
            int      position = 12;

            // Copy all domain parts(labels) to query
            // eg. lumisoft.ee = 2 labels, lumisoft and ee.
            // format = label.length + label(bytes)
            foreach (string label in labels)
            {
                // convert label string to byte array
                byte[] b = Encoding.ASCII.GetBytes(label);

                // add label lenght to query
                buffer[position++] = (byte)(b.Length);
                b.CopyTo(buffer, position);

                // Move position by label length
                position += b.Length;
            }

            // Terminate domain (see note above)
            buffer[position++] = (byte)0;

            // Set QTYPE
            buffer[position++] = (byte)0;
            buffer[position++] = (byte)qtype;

            // Set QCLASS
            buffer[position++] = (byte)0;
            buffer[position++] = (byte)qclass;
            //-------------------------------------------------------//

            return(position);
        }
Пример #9
0
        /// <summary>
        /// Queries server with specified query.
        /// </summary>
        /// <param name="queryText">Query text. It depends on queryType.</param>
        /// <param name="queryType">Query type.</param>
        /// <param name="timeout">Query timeout in milli seconds.</param>
        /// <returns>Returns DSN server response.</returns>
        public DnsServerResponse Query(string queryText,DNS_QType queryType,int timeout)
        {
            DnsServerResponse retVal = null;
            ManualResetEvent  wait   = new ManualResetEvent(false);

            DNS_ClientTransaction transaction = CreateTransaction(queryType,queryText,timeout);
            transaction.Timeout += delegate(object s,EventArgs e){
                wait.Set();
            };
            transaction.StateChanged += delegate(object s1,EventArgs<DNS_ClientTransaction> e1){
                if(transaction.State == DNS_ClientTransactionState.Completed || transaction.State == DNS_ClientTransactionState.Disposed){
                    retVal = transaction.Response;

                    wait.Set();
                }
            };
            transaction.Start();

            // Wait transaction to complete.
            wait.WaitOne();

            return retVal;
        }
Пример #10
0
 /// <summary>
 /// Queries server with specified query.
 /// </summary>
 /// <param name="queryText">Query text. It depends on queryType.</param>
 /// <param name="queryType">Query type.</param>
 /// <returns>Returns DSN server response.</returns>
 public DnsServerResponse Query(string queryText,DNS_QType queryType)
 {
     return Query(queryText,queryType,2000);
 }
Пример #11
0
 /// <summary>
 /// Queries server with specified query.
 /// </summary>
 /// <param name="queryText">Query text. It depends on queryType.</param>
 /// <param name="queryType">Query type.</param>
 /// <returns>Returns DSN server response.</returns>
 public DnsServerResponse Query(string queryText, DNS_QType queryType)
 {
     return(Query(queryText, queryType, 2000));
 }
Пример #12
0
		/// <summary>
		/// Queries server with specified query.
		/// </summary>
		/// <param name="queryText">Query text. It depends on queryType.</param>
		/// <param name="queryType">Query type.</param>
        /// <param name="timeout">Query timeout in milli seconds.</param>
		/// <returns>Returns DSN server response.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>queryText</b> is null.</exception>
		public DnsServerResponse Query(string queryText,DNS_QType queryType,int timeout)
		{
            if(m_IsDisposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if(queryText == null){
                throw new ArgumentNullException("queryText");
            }

            DnsServerResponse retVal = null;
            ManualResetEvent  wait   = new ManualResetEvent(false);

            DNS_ClientTransaction transaction = CreateTransaction(queryType,queryText,timeout);            
            transaction.Timeout += delegate(object s,EventArgs e){
                wait.Set();
            };
            transaction.StateChanged += delegate(object s1,EventArgs<DNS_ClientTransaction> e1){
                if(transaction.State == DNS_ClientTransactionState.Completed || transaction.State == DNS_ClientTransactionState.Disposed){ 
                    retVal = transaction.Response;

                    wait.Set();
                }
            };
            transaction.Start();

            // Wait transaction to complete.
            wait.WaitOne();
            wait.Close();

            return retVal;
		}
Пример #13
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="qtype">Query type.</param>
 /// <param name="qname">Query text. It depends on query type.</param>
 /// <exception cref="ArgumentNullException">Is raised when <b>qname</b> is null reference.</exception>
 public DNS_Query(DNS_QType qtype,string qname) : this(DNS_QClass.IN,qtype,qname)
 {
 }
Пример #14
0
		/// <summary>
		/// Filters out specified type of records from answer.
		/// </summary>
		/// <param name="answers"></param>
		/// <param name="type"></param>
		/// <returns></returns>
		private List<DNS_rr> FilterRecordsX(List<DNS_rr> answers,DNS_QType type)
		{
            List<DNS_rr> retVal = new List<DNS_rr>();
            foreach(DNS_rr record in answers){
                if(record.RecordType == type){
                    retVal.Add(record);
                }
            }

            return retVal;
		}
Пример #15
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="name">DNS domain name that owns a resource record.</param>
 /// <param name="recordType">Record type (A,MX, ...).</param>
 /// <param name="ttl">TTL (time to live) value in seconds.</param>
 public DNS_rr(string name, DNS_QType recordType, int ttl)
 {
     m_Name = name;
     m_Type = recordType;
     m_TTL  = ttl;
 }
Пример #16
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="qtype">Query type.</param>
 /// <param name="qname">Query text. It depends on query type.</param>
 /// <exception cref="ArgumentNullException">Is raised when <b>qname</b> is null reference.</exception>
 public DNS_Query(DNS_QType qtype, string qname) : this(DNS_QClass.IN, qtype, qname)
 {
 }
Пример #17
0
        /// <summary>
        /// Creates new DNS client transaction.
        /// </summary>
        /// <param name="queryType">Query type.</param>
        /// <param name="queryText">Query text. It depends on queryType.</param>
        /// <param name="timeout">Transaction timeout in milliseconds. DNS default value is 2000, value 0 means no timeout - this is not suggested.</param>
        /// <returns>Returns DNS client transaction.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>queryText</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <remarks>Creates asynchronous(non-blocking) DNS transaction. Call <see cref="DNS_ClientTransaction.Start"/> to start transaction.
        /// It is allowd to create multiple conccurent transactions.</remarks>
        public DNS_ClientTransaction CreateTransaction(DNS_QType queryType,string queryText,int timeout)
        {
            if(queryType == DNS_QType.PTR){
                IPAddress ip = null;
                if(!IPAddress.TryParse(queryText,out ip)){
                    throw new ArgumentException("Argument 'queryText' value must be IP address if queryType == DNS_QType.PTR.","queryText");
                }
            }
            if(queryText == null){
                throw new ArgumentNullException("queryText");
            }
            if(queryText == string.Empty){
                throw new ArgumentException("Argument 'queryText' value may not be \"\".","queryText");
            }

            if(queryType == DNS_QType.PTR){
                string ip = queryText;

                // See if IP is ok.
                IPAddress ipA = IPAddress.Parse(ip);
                queryText = "";

                // IPv6
                if(ipA.AddressFamily == AddressFamily.InterNetworkV6){
                    // 4321:0:1:2:3:4:567:89ab
                    // would be
                    // b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.ARPA

                    char[] ipChars = ip.Replace(":","").ToCharArray();
                    for(int i=ipChars.Length - 1;i>-1;i--){
                        queryText += ipChars[i] + ".";
                    }
                    queryText += "IP6.ARPA";
                }
                // IPv4
                else{
                    // 213.35.221.186
                    // would be
                    // 186.221.35.213.in-addr.arpa

                    string[] ipParts = ip.Split('.');
                    //--- Reverse IP ----------
                    for(int i=3;i>-1;i--){
                        queryText += ipParts[i] + ".";
                    }
                    queryText += "in-addr.arpa";
                }
            }

            DNS_ClientTransaction retVal = new DNS_ClientTransaction(this,new Random().Next(0xFFFF),queryType,queryText,timeout);
            retVal.StateChanged += delegate(object s1,EventArgs<DNS_ClientTransaction> e1){
                if(retVal.State == DNS_ClientTransactionState.Completed){
                    m_pTransactions.Remove(e1.Value.ID);
                }
            };
            m_pTransactions.Add(retVal.ID,retVal);

            return retVal;
        }
Пример #18
0
		/// <summary>
		/// Default constructor.
		/// </summary>
        /// <param name="name">DNS domain name that owns a resource record.</param>
		/// <param name="recordType">Record type (A,MX, ...).</param>
		/// <param name="ttl">TTL (time to live) value in seconds.</param>
		public DNS_rr(string name,DNS_QType recordType,int ttl)
		{
            m_Name = name;
			m_Type = recordType;
			m_TTL  = ttl;
        }
Пример #19
0
        /// <summary>
        /// Creates new DNS client transaction.
        /// </summary>
        /// <param name="queryType">Query type.</param>
        /// <param name="queryText">Query text. It depends on queryType.</param>
        /// <param name="timeout">Transaction timeout in milliseconds. DNS default value is 2000, value 0 means no timeout - this is not suggested.</param>
        /// <returns>Returns DNS client transaction.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>queryText</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <remarks>Creates asynchronous(non-blocking) DNS transaction. Call <see cref="DNS_ClientTransaction.Start"/> to start transaction.
        /// It is allowd to create multiple conccurent transactions.</remarks>
        public DNS_ClientTransaction CreateTransaction(DNS_QType queryType, string queryText, int timeout)
        {
            if (queryType == DNS_QType.PTR)
            {
                IPAddress ip = null;
                if (!IPAddress.TryParse(queryText, out ip))
                {
                    throw new ArgumentException("Argument 'queryText' value must be IP address if queryType == DNS_QType.PTR.", "queryText");
                }
            }
            if (queryText == null)
            {
                throw new ArgumentNullException("queryText");
            }
            if (queryText == string.Empty)
            {
                throw new ArgumentException("Argument 'queryText' value may not be \"\".", "queryText");
            }

            if (queryType == DNS_QType.PTR)
            {
                string ip = queryText;

                // See if IP is ok.
                IPAddress ipA = IPAddress.Parse(ip);
                queryText = "";

                // IPv6
                if (ipA.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    // 4321:0:1:2:3:4:567:89ab
                    // would be
                    // b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.ARPA

                    char[] ipChars = ip.Replace(":", "").ToCharArray();
                    for (int i = ipChars.Length - 1; i > -1; i--)
                    {
                        queryText += ipChars[i] + ".";
                    }
                    queryText += "IP6.ARPA";
                }
                // IPv4
                else
                {
                    // 213.35.221.186
                    // would be
                    // 186.221.35.213.in-addr.arpa

                    string[] ipParts = ip.Split('.');
                    //--- Reverse IP ----------
                    for (int i = 3; i > -1; i--)
                    {
                        queryText += ipParts[i] + ".";
                    }
                    queryText += "in-addr.arpa";
                }
            }

            DNS_ClientTransaction retVal = new DNS_ClientTransaction(this, new Random().Next(0xFFFF), queryType, queryText, timeout);

            retVal.StateChanged += delegate(object s1, EventArgs <DNS_ClientTransaction> e1)
            {
                if (retVal.State == DNS_ClientTransactionState.Completed)
                {
                    m_pTransactions.Remove(e1.Value.ID);
                }
            };
            m_pTransactions.Add(retVal.ID, retVal);

            return(retVal);
        }