/// <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; } }
/// <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); }
/// <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); }
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); }
/// <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); }