/// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <param name="timeout">Timeout for lookup in seconds.</param>
        /// <returns></returns>
        private DNSResponse TcpRequest(DNSRequest request, List<IPEndPoint> dnsServers, int timeout)
        {
            //System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            //sw.Start();

            byte[] responseMessage = new byte[512];

            for (int intAttempts = 0; intAttempts < m_Retries; intAttempts++)
            {
                for (int intDnsServer = 0; intDnsServer < dnsServers.Count; intDnsServer++)
                {
                    TcpClient tcpClient = new TcpClient();
                    tcpClient.ReceiveTimeout = timeout * 1000;

                    try
                    {
                        IAsyncResult result = tcpClient.BeginConnect(dnsServers[intDnsServer].Address, dnsServers[intDnsServer].Port, null, null);

                        bool success = result.AsyncWaitHandle.WaitOne(timeout * 1000, true);

                        if (!success || !tcpClient.Connected)
                        {
                            tcpClient.Close();
                            Verbose(string.Format(";; Connection to nameserver {0} failed", (intDnsServer + 1)));
                            continue;
                        }

                        BufferedStream bs = new BufferedStream(tcpClient.GetStream());

                        byte[] data = request.Data;
                        bs.WriteByte((byte)((data.Length >> 8) & 0xff));
                        bs.WriteByte((byte)(data.Length & 0xff));
                        bs.Write(data, 0, data.Length);
                        bs.Flush();

                        DNSResponse TransferResponse = new DNSResponse();
                        int intSoa = 0;
                        int intMessageSize = 0;

                        //Debug.WriteLine("Sending "+ (request.Length+2) + " bytes in "+ sw.ElapsedMilliseconds+" mS");

                        while (true)
                        {
                            int intLength = bs.ReadByte() << 8 | bs.ReadByte();
                            if (intLength <= 0)
                            {
                                tcpClient.Close();
                                Verbose(string.Format(";; Connection to nameserver {0} failed", (intDnsServer + 1)));
                                throw new SocketException(); // next try
                            }

                            intMessageSize += intLength;

                            data = new byte[intLength];
                            bs.Read(data, 0, intLength);
                            DNSResponse response = new DNSResponse(dnsServers[intDnsServer], data);

                            //Debug.WriteLine("Received "+ (intLength+2)+" bytes in "+sw.ElapsedMilliseconds +" mS");

                            if (response.header.RCODE != RCode.NOERROR)
                                return response;

                            if (response.Questions[0].QType != DNSQType.AXFR)
                            {
                                //AddToCache(response);
                                return response;
                            }

                            // Zone transfer!!

                            if (TransferResponse.Questions.Count == 0)
                                TransferResponse.Questions.AddRange(response.Questions);
                            TransferResponse.Answers.AddRange(response.Answers);
                            TransferResponse.Authorities.AddRange(response.Authorities);
                            TransferResponse.Additionals.AddRange(response.Additionals);

                            if (response.Answers[0].Type == DNSType.SOA)
                                intSoa++;

                            if (intSoa == 2)
                            {
                                TransferResponse.header.QDCOUNT = (ushort)TransferResponse.Questions.Count;
                                TransferResponse.header.ANCOUNT = (ushort)TransferResponse.Answers.Count;
                                TransferResponse.header.NSCOUNT = (ushort)TransferResponse.Authorities.Count;
                                TransferResponse.header.ARCOUNT = (ushort)TransferResponse.Additionals.Count;
                                TransferResponse.MessageSize = intMessageSize;
                                return TransferResponse;
                            }
                        }
                    } // try
                    catch (SocketException)
                    {
                        continue; // next try
                    }
                    finally
                    {
                        m_Unique++;

                        // close the socket
                        tcpClient.Close();
                    }
                }
            }
            DNSResponse responseTimeout = new DNSResponse();
            responseTimeout.Timedout = true;
            return responseTimeout;
        }
        private DNSResponse GetResponse(DNSRequest request, List<IPEndPoint> dnsServers, int timeout)
        {
            request.header.ID = m_Unique;
            request.header.RD = m_Recursion;
            DNSResponse response = null;

            if (m_TransportType == TransportType.Udp)
            {
                response = UdpRequest(request, dnsServers, timeout);
            }

            if (m_TransportType == TransportType.Tcp)
            {
                response = TcpRequest(request, dnsServers, timeout);
            }

            if (response == null)
            {
                response = new DNSResponse();
                response.Error = "Unknown TransportType";
            }

            Question question = request.Questions[0];
            string questionKey = question.QClass + "-" + question.QType + "-" + question.QName;
            AddToCache(response, questionKey);

            return response;
        }
        private void AddToCache(DNSResponse response, string questionKey)
        {
            if (!m_UseCache)
            {
                return;
            }
            else if (questionKey.IsNullOrBlank())
            {
                throw new ApplicationException("Cannot add a DNS response to the cache with an empty question key.");
            }

            // Question question = response.Questions[0];

            //string questionKey = question.QClass + "-" + question.QType + "-" + question.QName;
            if (response.Answers.Count == 0)
            {
                response.Error = "DNS response had no answers.";
            }

            //if (response.header.RCODE != RCode.NOERROR || response.Error != null)
            if (response.Error != null)
            {
                // Cache error responses for a short period of time to avoid overloading the server with failing DNS lookups.
                logger.Debug("Caching DNS lookup failure for " + questionKey + " error was " + response.Error + ".");
                lock (m_lookupFailures)
                {
                    if (m_lookupFailures.ContainsKey(questionKey))
                    {
                        m_lookupFailures.Remove(questionKey);
                    }

                    m_lookupFailures.Add(questionKey, response);
                }
            }
            else if(!response.Timedout && response.Answers.Count > 0)
            {
                // Cache non-error responses.
                logger.Debug("Caching DNS lookup success for " + questionKey + ".");
                lock (m_ResponseCache)
                {
                    if (m_ResponseCache.ContainsKey(questionKey))
                    {
                        m_ResponseCache.Remove(questionKey);
                    }
                    m_ResponseCache.Add(questionKey, response);
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <param name="timeout">Timeout for lookup in seconds.</param>
        /// <returns></returns>
        private DNSResponse UdpRequest(DNSRequest request, List<IPEndPoint> dnsServers, int timeout)
        {
            // RFC1035 max. size of a UDP datagram is 512 bytes
            byte[] responseMessage = new byte[512];

            IPEndPoint activeDNSServer = GetActiveDNSServer();

            //for (int intAttempts = 0; intAttempts < m_Retries; intAttempts++)
            //{
            //    for (int intDnsServer = 0; intDnsServer < dnsServers.Count; intDnsServer++)
            //	{
            string requestStr = request.Questions[0].QType + " " + request.Questions[0].QName;
            logger.Debug("Resolver sending UDP DNS request to " + activeDNSServer + " for " + requestStr + ".");

            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout * 1000);

            try
            {
                socket.SendTo(request.Data, activeDNSServer);
                int intReceived = socket.Receive(responseMessage);
                ResetTimeoutCount(activeDNSServer);
                byte[] data = new byte[intReceived];
                Array.Copy(responseMessage, data, intReceived);
                DNSResponse response = new DNSResponse(activeDNSServer, data);
                //AddToCache(response);
                //logger.Debug("Success in UdpRequest for " + requestStr + ".");
                return response;
            }
            catch (SocketException sockExcp)
            {
                //logger.Debug("SocketException UdpRequest for " + requestStr + ". " + sockExcp.Message);
                IncrementTimeoutCount(activeDNSServer);
                logger.Warn("Resolver connection to nameserver " + activeDNSServer + " failed. " + sockExcp.Message);
                //continue; // next try
            }
            catch (Exception excp)
            {
                logger.Error("Exception Resolver UdpRequest for " + requestStr + ". " + excp.Message);
            }
            finally
            {
                m_Unique++;

                // close the socket
                socket.Close();
            }
            //	}
            //}

            logger.Warn("Resolver UDP request timed out for " + requestStr + ".");
            DNSResponse responseTimeout = new DNSResponse();
            responseTimeout.Timedout = true;
            return responseTimeout;
        }
        public static DNSResponse Lookup(string hostname, DNSQType queryType, int timeout, List<IPEndPoint> dnsServers, bool useCache, bool async)
        {
            if (hostname == null || hostname.Trim().Length == 0)
            {
                return null;
            }

            DNSResponse ipAddressResult = MatchIPAddress(hostname);

            if (ipAddressResult != null)
            {
                return ipAddressResult;
            }
            else if (useCache)
            {
                DNSResponse cacheResult = m_resolver.QueryCache(hostname.Trim().ToLower(), queryType);
                if (cacheResult != null)
                {
                    return cacheResult;
                }
            }

            if (async)
            {
                //logger.Debug("DNS lookup cache miss for async lookup to " + queryType.ToString() + " " + hostname + ".");
                QueueLookup(new LookupRequest(hostname.Trim().ToLower(), queryType, timeout, dnsServers, null));
                return null;
            }
            else
            {
                ManualResetEvent completeEvent = new ManualResetEvent(false);
                QueueLookup(new LookupRequest(hostname.Trim().ToLower(), queryType, timeout, dnsServers, completeEvent));

                if (completeEvent.WaitOne(timeout * 1000 * 2, false))
                {
                    //logger.Debug("Complete event fired for DNS lookup on " + queryType.ToString() + " " + hostname + ".");
                    // Completed event was fired, the DNS entry will now be in cache.
                    DNSResponse result = m_resolver.QueryCache(hostname, queryType);
                    if (result != null)
                    {
                        return result;
                    }
                    else
                    {
                        //logger.Debug("DNS lookup cache miss for " + queryType.ToString() + " " + hostname + ".");
                        // Timeout.
                        DNSResponse timeoutResponse = new DNSResponse();
                        timeoutResponse.Timedout = true;
                        return timeoutResponse;
                    }
                }
                else
                {
                    // If this block gets called it's because the DNS resolver class did not return within twice the timeout period it
                    // was asked to do so in. If this happens a lot further investigation into the DNS resolver class is warranted.
                    logger.Error("DNSManager timed out waiting for the DNS resolver to complete the lookup for " + queryType.ToString() + " " + hostname + ".");

                    // Timeout.
                    DNSResponse timeoutResponse = new DNSResponse();
                    timeoutResponse.Timedout = true;
                    return timeoutResponse;
                }
            }
        }
        private static DNSResponse MatchIPAddress(string hostname)
        {
            try
            {
                if (hostname != null && hostname.Trim().Length > 0)
                {
                    hostname = hostname.Trim();

                    if (Regex.Match(hostname, @"(\d+\.){3}\d+(:\d+$|$)").Success)
                    {
                        string ipAddress = Regex.Match(hostname, @"(?<ipaddress>(\d+\.){3}\d+)(:\d+$|$)").Result("${ipaddress}");
                        DNSResponse result = new DNSResponse(IPAddress.Parse(ipAddress));
                        return result;
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception DNSManager MatchIPAddress. " + excp);
                return null;
            }
        }
Exemple #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="request"></param>
        /// <param name="timeout">Timeout for lookup in seconds.</param>
        /// <returns></returns>
        private DNSResponse TcpRequest(DNSRequest request, List <IPEndPoint> dnsServers, int timeout)
        {
            byte[] responseMessage = new byte[512];

            IPEndPoint activeDNSServer = GetActiveDNSServer();

            if (dnsServers == null)
            {
                dnsServers = new List <IPEndPoint>();
            }

            if (dnsServers.Count == 0)
            {
                dnsServers.Add(activeDNSServer);
            }

            ResetAllTimeoutCountIfNecessary();

            string requestStr = request.Questions[0].QType + " " + request.Questions[0].QName;

            for (int nAttempts = 0; nAttempts < m_Retries && !m_stop; nAttempts++)
            {
                for (int nDnsServer = 0; nDnsServer < dnsServers.Count && !m_stop; nDnsServer++)
                {
                    if (dnsServers[nDnsServer].Address.IsIPv6LinkLocal)
                    {
                        continue;
                    }
                    if (GetTimeoutCount(dnsServers[nDnsServer]) >= SWITCH_ACTIVE_TIMEOUT_COUNT)
                    {
                        logger.LogDebug("Resolver not sending TCP DNS request to " + dnsServers[nDnsServer] + " because of maximum count of request timeouts reached");
                        continue;
                    }
                    string requestStrWithDns = "for '" + requestStr + "' on dns-server '" + dnsServers[nDnsServer] + "'";
                    logger.LogDebug("Resolver sending TCP DNS request " + requestStrWithDns);

                    TcpClient tcpClient = new TcpClient();
                    tcpClient.ReceiveTimeout = timeout * 1000;

                    try
                    {
                        IAsyncResult result = tcpClient.BeginConnect(dnsServers[nDnsServer].Address, dnsServers[nDnsServer].Port, null, null);

                        bool success = result.AsyncWaitHandle.WaitOne(timeout * 1000, true);

                        if (!success || !tcpClient.Connected)
                        {
                            tcpClient.Close();
                            Verbose(string.Format(";; Connection to nameserver {0} failed", (nDnsServer + 1)));
                            continue;
                        }

                        BufferedStream bs = new BufferedStream(tcpClient.GetStream());

                        byte[] data = request.Data;
                        bs.WriteByte((byte)((data.Length >> 8) & 0xff));
                        bs.WriteByte((byte)(data.Length & 0xff));
                        bs.Write(data, 0, data.Length);
                        bs.Flush();

                        DNSResponse TransferResponse = new DNSResponse();
                        int         intSoa           = 0;
                        int         intMessageSize   = 0;

                        //Debug.WriteLine("Sending "+ (request.Length+2) + " bytes in "+ sw.ElapsedMilliseconds+" mS");

                        while (true)
                        {
                            int intLength = bs.ReadByte() << 8 | bs.ReadByte();
                            if (intLength <= 0)
                            {
                                tcpClient.Close();
                                Verbose(string.Format(";; Connection to nameserver {0} failed", (nDnsServer + 1)));
                                throw new SocketException(); // next try
                            }

                            intMessageSize += intLength;

                            data = new byte[intLength];
                            bs.Read(data, 0, intLength);
                            DNSResponse response = new DNSResponse(m_DnsServers[nDnsServer], data);

                            if (response.header.RCODE != RCode.NOERROR)
                            {
                                logger.LogDebug("Error " + response.header.RCODE + " in Resolver TcpRequest " + requestStrWithDns);
                                return(response);
                            }
                            else
                            {
                                logger.LogInformation("Success in TcpRequest " + requestStrWithDns);
                            }

                            if (response.Questions[0].QType != QType.AXFR)
                            {
                                return(response);
                            }

                            // Zone transfer!!

                            if (TransferResponse.Questions.Count == 0)
                            {
                                TransferResponse.Questions.AddRange(response.Questions);
                            }

                            TransferResponse.Answers.AddRange(response.Answers);
                            TransferResponse.Authorities.AddRange(response.Authorities);
                            TransferResponse.Additionals.AddRange(response.Additionals);

                            if (response.Answers[0].Type == DnsType.SOA)
                            {
                                intSoa++;
                            }

                            if (intSoa == 2)
                            {
                                TransferResponse.header.QDCOUNT = (ushort)TransferResponse.Questions.Count;
                                TransferResponse.header.ANCOUNT = (ushort)TransferResponse.Answers.Count;
                                TransferResponse.header.NSCOUNT = (ushort)TransferResponse.Authorities.Count;
                                TransferResponse.header.ARCOUNT = (ushort)TransferResponse.Additionals.Count;
                                TransferResponse.MessageSize    = intMessageSize;
                                return(TransferResponse);
                            }
                        }
                    } // try
                    catch (SocketException sockExcp)
                    {
                        IncrementTimeoutCount(dnsServers[nDnsServer]);
                        logger.LogWarning("SocketExcpetion(" + sockExcp.ErrorCode + ") Resolver TcpRequest connection to nameserver " + dnsServers[nDnsServer] + " failed. ", sockExcp);
                        continue; // next try
                    }
                    catch (Exception excp)
                    {
                        logger.LogError("Exception Resolver UdpRequest " + requestStrWithDns + ". ", excp);
                    }
                    finally
                    {
                        m_Unique++;

                        // close the socket
                        tcpClient.Close();
                    }
                }
            }

            logger.LogWarning("Resolver TCP request timed out for " + requestStr + ".");
            DNSResponse responseTimeout = new DNSResponse();

            responseTimeout.Timedout = true;
            responseTimeout.Error    = "Timeout Error";
            return(responseTimeout);
        }
Exemple #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="request"></param>
        /// <param name="timeout">Timeout for lookup in seconds.</param>
        /// <returns></returns>
        private DNSResponse UdpRequest(DNSRequest request, List <IPEndPoint> dnsServers, int timeout)
        {
            // RFC1035 max. size of a UDP datagram is 512 bytes
            byte[] responseMessage = new byte[512];

            IPEndPoint activeDNSServer = GetActiveDNSServer();

            if (dnsServers == null)
            {
                dnsServers = new List <IPEndPoint>();
            }

            if (dnsServers.Count == 0)
            {
                dnsServers.Add(activeDNSServer);
            }

            ResetAllTimeoutCountIfNecessary();

            string requestStr = request.Questions[0].QType + " " + request.Questions[0].QName;

            for (int nAttempts = 0; nAttempts < m_Retries && !m_stop; nAttempts++)
            {
                for (int nDnsServer = 0; nDnsServer < dnsServers.Count && !m_stop; nDnsServer++)
                {
                    if (dnsServers[nDnsServer].Address.IsIPv6LinkLocal)
                    {
                        continue;
                    }
                    if (GetTimeoutCount(dnsServers[nDnsServer]) >= SWITCH_ACTIVE_TIMEOUT_COUNT)
                    {
                        logger.LogDebug("Resolver not sending UDP DNS request to " + dnsServers[nDnsServer] + " because of maximum count of request timeouts reached");
                        continue;
                    }
                    string requestStrWithDns = "for '" + requestStr + "' on dns-server '" + dnsServers[nDnsServer] + "'";
                    logger.LogDebug("Resolver sending UDP DNS request " + requestStrWithDns);

                    Socket socket = new Socket(dnsServers[nDnsServer].AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout * 1000);

                    try
                    {
                        socket.SendTo(request.Data, dnsServers[nDnsServer]);
                        int nReceived = socket.Receive(responseMessage);
                        ResetTimeoutCount(dnsServers[nDnsServer]);
                        byte[] data = new byte[nReceived];
                        Array.Copy(responseMessage, data, nReceived);
                        DNSResponse response = new DNSResponse(dnsServers[nDnsServer], data);
                        if (response.header.RCODE == RCode.NOERROR)
                        {
                            logger.LogInformation("Success in UdpRequest " + requestStrWithDns);
                            return(response);
                        }
                        else
                        {
                            logger.LogDebug("Error " + response.header.RCODE + " in Resolver UdpRequest " + requestStrWithDns);
                        }
                    }
                    catch (SocketException sockExcp)
                    {
                        IncrementTimeoutCount(dnsServers[nDnsServer]);
                        logger.LogWarning("SocketExcpetion(" + sockExcp.ErrorCode + ") Resolver UdpRequest connection to nameserver " + dnsServers[nDnsServer] + " failed. ", sockExcp);
                        continue; // next try
                    }
                    catch (Exception excp)
                    {
                        logger.LogError("Exception Resolver UdpRequest " + requestStrWithDns + ". ", excp);
                    }
                    finally
                    {
                        m_Unique++;

                        // close the socket
                        socket.Close();
                    }
                }
            }

            logger.LogWarning("Resolver UDP request timed out for " + requestStr + ".");
            DNSResponse responseTimeout = new DNSResponse();

            responseTimeout.Timedout = true;
            responseTimeout.Error    = "Timeout Error";
            return(responseTimeout);
        }
Exemple #9
0
        private DNSResponse SearchInCache(Question question)
        {
            if (!m_UseCache)
            {
                return(null);
            }

            string strKey = question.QClass + "-" + question.QType + "-" + question.QName;

            //logger.LogDebug($"Searching DNS results cache for {strKey}.");

            lock (m_lookupFailures)
            {
                if (m_lookupFailures.ContainsKey(strKey))
                {
                    if (DateTime.Now.Subtract(m_lookupFailures[strKey].TimeStamp).TotalSeconds < FAILURE_RETRY)
                    {
                        return(m_lookupFailures[strKey]);
                    }
                    else
                    {
                        m_lookupFailures.Remove(strKey);
                        return(null);
                    }
                }
            }

            DNSResponse response = null;

            lock (m_ResponseCache)
            {
                if (!m_ResponseCache.ContainsKey(strKey))
                {
                    return(null);
                }

                response = m_ResponseCache[strKey];

                if (response.Answers.Count == 0)
                {
                    // A response should not have been cached with no answer records.
                    m_ResponseCache.Remove(strKey);
                    return(null);
                }
            }

            int TimeLived    = (int)((DateTime.Now.Ticks - response.TimeStamp.Ticks) / TimeSpan.TicksPerSecond);
            int secondsLived = (int)(DateTime.Now.Subtract(response.TimeStamp).TotalSeconds % Int32.MaxValue);

            //logger.LogDebug("Seconds lived=" + secondsLived + ".");
            foreach (RR rr in response.RecordsRR)
            {
                if (rr.Type == DnsType.OPT)
                {
                    continue;
                }

                rr.TimeLived = TimeLived;
                // The TTL property calculates its actual time to live
                if (secondsLived > MIN_CACHE_SECONDS && secondsLived >= rr.TTL)
                {
                    logger.LogDebug($"DNS cache out of date result found for {strKey}. SecondsLived({secondsLived}) is >= remaining TimeToLive({rr.TTL})");
                    return(null); // out of date
                }
                if (rr.TTL == 0)
                {
                    logger.LogDebug("DNS cache out of date (TTL==0) result found for " + strKey + ".");
                    return(null); // out of date
                }
            }

            logger.LogDebug("DNS cache curent result found for " + strKey + ".");
            return(response);
        }
Exemple #10
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="request"></param>
        /// <param name="timeout">Timeout for lookup in seconds.</param>
        /// <returns></returns>
        private DNSResponse TcpRequest(DNSRequest request, List <IPEndPoint> dnsServers, int timeout)
        {
            //System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            //sw.Start();

            byte[] responseMessage = new byte[512];

            for (int intAttempts = 0; intAttempts < m_Retries; intAttempts++)
            {
                for (int intDnsServer = 0; intDnsServer < dnsServers.Count; intDnsServer++)
                {
                    TcpClient tcpClient = new TcpClient();
                    tcpClient.ReceiveTimeout = timeout * 1000;

                    try
                    {
                        IAsyncResult result = tcpClient.BeginConnect(dnsServers[intDnsServer].Address, dnsServers[intDnsServer].Port, null, null);

                        bool success = result.AsyncWaitHandle.WaitOne(timeout * 1000, true);

                        if (!success || !tcpClient.Connected)
                        {
                            tcpClient.Close();
                            Verbose(string.Format(";; Connection to nameserver {0} failed", (intDnsServer + 1)));
                            continue;
                        }

                        BufferedStream bs = new BufferedStream(tcpClient.GetStream());

                        byte[] data = request.Data;
                        bs.WriteByte((byte)((data.Length >> 8) & 0xff));
                        bs.WriteByte((byte)(data.Length & 0xff));
                        bs.Write(data, 0, data.Length);
                        bs.Flush();

                        DNSResponse TransferResponse = new DNSResponse();
                        int         intSoa           = 0;
                        int         intMessageSize   = 0;

                        //Debug.WriteLine("Sending "+ (request.Length+2) + " bytes in "+ sw.ElapsedMilliseconds+" mS");

                        while (true)
                        {
                            int intLength = bs.ReadByte() << 8 | bs.ReadByte();
                            if (intLength <= 0)
                            {
                                tcpClient.Close();
                                Verbose(string.Format(";; Connection to nameserver {0} failed", (intDnsServer + 1)));
                                throw new SocketException(); // next try
                            }

                            intMessageSize += intLength;

                            data = new byte[intLength];
                            bs.Read(data, 0, intLength);
                            DNSResponse response = new DNSResponse(m_DnsServers[intDnsServer], data);

                            //Debug.WriteLine("Received "+ (intLength+2)+" bytes in "+sw.ElapsedMilliseconds +" mS");

                            if (response.header.RCODE != RCode.NOERROR)
                            {
                                return(response);
                            }

                            if (response.Questions[0].QType != QType.AXFR)
                            {
                                //AddToCache(response);
                                return(response);
                            }

                            // Zone transfer!!

                            if (TransferResponse.Questions.Count == 0)
                            {
                                TransferResponse.Questions.AddRange(response.Questions);
                            }

                            TransferResponse.Answers.AddRange(response.Answers);
                            TransferResponse.Authorities.AddRange(response.Authorities);
                            TransferResponse.Additionals.AddRange(response.Additionals);

                            if (response.Answers[0].Type == DnsType.SOA)
                            {
                                intSoa++;
                            }

                            if (intSoa == 2)
                            {
                                TransferResponse.header.QDCOUNT = (ushort)TransferResponse.Questions.Count;
                                TransferResponse.header.ANCOUNT = (ushort)TransferResponse.Answers.Count;
                                TransferResponse.header.NSCOUNT = (ushort)TransferResponse.Authorities.Count;
                                TransferResponse.header.ARCOUNT = (ushort)TransferResponse.Additionals.Count;
                                TransferResponse.MessageSize    = intMessageSize;
                                return(TransferResponse);
                            }
                        }
                    } // try
                    catch (SocketException)
                    {
                        continue; // next try
                    }
                    finally
                    {
                        m_Unique++;

                        // close the socket
                        tcpClient.Close();
                    }
                }
            }
            DNSResponse responseTimeout = new DNSResponse();

            responseTimeout.Error = "Timeout Error";
            return(responseTimeout);
        }
        private DNSResponse SearchInCache(Question question)
        {
            if (!m_UseCache)
            {
                return(null);
            }

            string strKey = question.QClass + "-" + question.QType + "-" + question.QName;

            //logger.Debug("Checking cache for " + strKey + ".");

            lock (m_lookupFailures)
            {
                if (m_lookupFailures.ContainsKey(strKey))
                {
                    //logger.Debug("DNS cache failed result found for " + strKey + ".");

                    if (DateTime.Now.Subtract(m_lookupFailures[strKey].TimeStamp).TotalSeconds < FAILURE_RETRY)
                    {
                        return(m_lookupFailures[strKey]);
                    }
                    else
                    {
                        m_lookupFailures.Remove(strKey);
                        return(null);
                    }
                }
            }

            DNSResponse response = null;

            lock (m_ResponseCache)
            {
                if (!m_ResponseCache.ContainsKey(strKey))
                {
                    //logger.Debug("DNS cache no result found for " + strKey + ".");
                    return(null);
                }

                response = m_ResponseCache[strKey];

                if (response.Answers.Count == 0)
                {
                    // A response should not have been cached with no answer records.
                    m_ResponseCache.Remove(strKey);
                    return(null);
                }
            }

            //int TimeLived = (int)((DateTime.Now.Ticks - response.TimeStamp.Ticks) / TimeSpan.TicksPerSecond);
            int secondsLived = (int)(DateTime.Now.Subtract(response.TimeStamp).TotalSeconds % Int32.MaxValue);

            //logger.Debug("Seconds lived=" + secondsLived + ".");
            foreach (RR rr in response.RecordsRR)
            {
                //rr.TimeLived = TimeLived;
                // The TTL property calculates its actual time to live
                if (secondsLived >= rr.TTL)
                {
                    //logger.Debug("DNS cache out of date result found for " + strKey + ".");
                    return(null); // out of date
                }
            }

            //logger.Debug("DNS cache curent result found for " + strKey + ".");
            return(response);
        }