From 3abb76fe8dd2068d55c0d12c5fbd66ed62904e6d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 27 Jun 2020 12:03:54 +0530 Subject: [PATCH] DnsServer: implemented ResolverDnsCache for recursive resolution. Updated ProcessQuery() to change the sequence of checking for blocked zones to allow blocking correctly in case of stub zone or forwarder zone being used. Fixed implementation changes in ProcessAuthoritativeQuery(), ProcessCNAME(), ProcessANAME() and ProcessRecursiveQuery(). RecursiveResolveAsync() stopped caching failure record in case of exception due to undesirable side effects for clients. CachePrefetchSamplingAsync() added zone type checks. Code refactoring done. --- DnsServerCore/Dns/DnsServer.cs | 495 +++++++++++++++++---------------- 1 file changed, 258 insertions(+), 237 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 534a74bf..67c977e1 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -82,6 +82,8 @@ namespace DnsServerCore.Dns readonly BlockListZoneManager _blockListZoneManager; readonly CacheZoneManager _cacheZoneManager = new CacheZoneManager(); + readonly ResolverDnsCache _dnsCache; + readonly DnsARecord _aRecord = new DnsARecord(IPAddress.Any); readonly DnsAAAARecord _aaaaRecord = new DnsAAAARecord(IPAddress.IPv6Any); readonly DnsTXTRecord _txtRecord = new DnsTXTRecord("blockList=custom"); @@ -163,6 +165,8 @@ namespace DnsServerCore.Dns _blockedZoneManager = new BlockedZoneManager(this); _blockListZoneManager = new BlockListZoneManager(this); + _dnsCache = new ResolverDnsCache(_authZoneManager, _cacheZoneManager); + //init stats string statsFolder = Path.Combine(_configFolder, "stats"); @@ -847,7 +851,7 @@ namespace DnsServerCore.Dns { try { - string statusString = statusCode + " " + GetStatusString((HttpStatusCode)statusCode); + string statusString = statusCode + " " + GetHttpStatusString((HttpStatusCode)statusCode); byte[] bufferContent = Encoding.UTF8.GetBytes("" + statusString + "

" + statusString + "

" + (message == null ? "" : "

" + message + "

") + ""); byte[] bufferHeader = Encoding.UTF8.GetBytes("HTTP/1.1 " + statusString + "\r\nDate: " + DateTime.UtcNow.ToString("r") + "\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: " + bufferContent.Length + "\r\nX-Robots-Tag: noindex, nofollow\r\n\r\n"); @@ -859,7 +863,7 @@ namespace DnsServerCore.Dns { } } - internal static string GetStatusString(HttpStatusCode statusCode) + internal static string GetHttpStatusString(HttpStatusCode statusCode) { StringBuilder sb = new StringBuilder(); @@ -924,15 +928,10 @@ namespace DnsServerCore.Dns return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NotImplemented, request.Question); default: - //query authoritative zone - DnsDatagram response = ProcessAuthoritativeQuery(request, isRecursionAllowed); - - if ((response.RCODE != DnsResponseCode.Refused) || !request.RecursionDesired || !isRecursionAllowed) - return response; + DnsDatagram response; //check in allowed zone bool inAllowedZone = _allowedZoneManager.Query(request).RCODE != DnsResponseCode.Refused; - if (!inAllowedZone) { //check in blocked zone and block list zone @@ -941,8 +940,14 @@ namespace DnsServerCore.Dns return response; } + //query authoritative zone + response = ProcessAuthoritativeQuery(request, isRecursionAllowed); + + if ((response.RCODE != DnsResponseCode.Refused) || !request.RecursionDesired || !isRecursionAllowed) + return response; + //do recursive query - return ProcessRecursiveQuery(request, !inAllowedZone, null, null, false); + return ProcessRecursiveQuery(request, null, null, !inAllowedZone, false); } } catch (Exception ex) @@ -1190,81 +1195,7 @@ namespace DnsServerCore.Dns switch (lastRR.Type) { case DnsResourceRecordType.CNAME: - List responseAnswer = new List(); - responseAnswer.AddRange(response.Answer); - - DnsDatagram lastResponse; - - int queryCount = 0; - do - { - DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord((lastRR.RDATA as DnsCNAMERecord).Domain, questionType, request.Question[0].Class) }); - - //query authoritative zone first - lastResponse = _authZoneManager.Query(newRequest); - - if (lastResponse.RCODE == DnsResponseCode.Refused) - { - //not found in auth zone - if (newRequest.RecursionDesired && isRecursionAllowed) - { - //do recursion - lastResponse = ProcessRecursiveQuery(newRequest, false, null, null, false); - } - else - { - lastResponse = response; //response is logically last valid response - break; //break since no recursion allowed/desired - } - } - else if ((lastResponse.Answer.Count > 0) && (lastResponse.Answer[0].Type == DnsResourceRecordType.ANAME)) - { - lastResponse = ProcessANAME(request, lastResponse, isRecursionAllowed); - } - else if ((lastResponse.Answer.Count == 0) && (lastResponse.Authority.Count > 0)) - { - //found delegated/forwarded zone - lastResponse = ProcessAuthoritySection(newRequest, lastResponse, isRecursionAllowed); - } - - //check last response - if (lastResponse.Answer.Count == 0) - break; //cannot proceed to resolve cname further - - responseAnswer.AddRange(lastResponse.Answer); - - lastRR = lastResponse.Answer[lastResponse.Answer.Count - 1]; - - if (lastRR.Type != DnsResourceRecordType.CNAME) - break; //cname was resolved - } - while (++queryCount < MAX_CNAME_HOPS); - - DnsResponseCode rcode; - IReadOnlyList authority = null; - IReadOnlyList additional = null; - - if ((lastResponse.RCODE == DnsResponseCode.Refused) && !(request.RecursionDesired && isRecursionAllowed)) - { - rcode = DnsResponseCode.NoError; - } - else - { - rcode = lastResponse.RCODE; - - if (lastResponse.AuthoritativeAnswer) - { - authority = lastResponse.Authority; - additional = lastResponse.Additional; - } - else - { - if ((lastResponse.Authority.Count > 0) && (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA)) - authority = lastResponse.Authority; - } - } - - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, lastResponse.AuthoritativeAnswer, false, request.RecursionDesired, isRecursionAllowed, false, false, rcode, request.Question, responseAnswer, authority, additional) { Tag = response.Tag }; + return ProcessCNAME(request, response, isRecursionAllowed, false); case DnsResourceRecordType.ANAME: return ProcessANAME(request, response, isRecursionAllowed); @@ -1273,13 +1204,166 @@ namespace DnsServerCore.Dns } else if (response.Authority.Count > 0) { - return ProcessAuthoritySection(request, response, isRecursionAllowed); + switch (response.Authority[0].Type) + { + case DnsResourceRecordType.NS: + if (request.RecursionDesired && isRecursionAllowed) + { + //do recursive resolution using response authority name servers + List nameServers = NameServerAddress.GetNameServersFromResponse(response, _preferIPv6, false); + + return ProcessRecursiveQuery(request, nameServers, null, false, false); + } + + break; + + case DnsResourceRecordType.FWD: + if ((response.Authority.Count == 1) && (response.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) + { + //do conditional forwarding via "this-server" + return ProcessRecursiveQuery(request, null, null, false, false); + } + else + { + //do conditional forwarding + List forwarders = new List(response.Authority.Count); + + foreach (DnsResourceRecord rr in response.Authority) + { + if (rr.Type == DnsResourceRecordType.FWD) + forwarders.Add((rr.RDATA as DnsForwarderRecord).NameServer); + } + + return ProcessRecursiveQuery(request, null, forwarders, false, false); + } + } } } return response; } + private DnsDatagram ProcessCNAME(DnsDatagram request, DnsDatagram response, bool isRecursionAllowed, bool cacheRefreshOperation) + { + List responseAnswer = new List(); + responseAnswer.AddRange(response.Answer); + + DnsDatagram lastResponse; + bool isAuthoritativeAnswer = response.AuthoritativeAnswer; + string lastDomain = (response.Answer[response.Answer.Count - 1].RDATA as DnsCNAMERecord).Domain; + + int queryCount = 0; + do + { + DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(lastDomain, request.Question[0].Type, request.Question[0].Class) }); + + //query authoritative zone first + lastResponse = _authZoneManager.Query(newRequest); + + if (lastResponse.RCODE == DnsResponseCode.Refused) + { + //not found in auth zone + if (newRequest.RecursionDesired && isRecursionAllowed) + { + //do recursion + lastResponse = RecursiveResolve(newRequest, null, null, false, cacheRefreshOperation); + isAuthoritativeAnswer = false; + } + else + { + //break since no recursion allowed/desired + break; + } + } + else if ((lastResponse.Answer.Count > 0) && (lastResponse.Answer[0].Type == DnsResourceRecordType.ANAME)) + { + lastResponse = ProcessANAME(request, lastResponse, isRecursionAllowed); + } + else if ((lastResponse.Answer.Count == 0) && (lastResponse.Authority.Count > 0)) + { + //found delegated/forwarded zone + switch (lastResponse.Authority[0].Type) + { + case DnsResourceRecordType.NS: + if (newRequest.RecursionDesired && isRecursionAllowed) + { + //do recursive resolution using last response authority name servers + List nameServers = NameServerAddress.GetNameServersFromResponse(lastResponse, _preferIPv6, false); + + lastResponse = RecursiveResolve(newRequest, nameServers, null, false, false); + isAuthoritativeAnswer = false; + } + + break; + + case DnsResourceRecordType.FWD: + if ((lastResponse.Authority.Count == 1) && (lastResponse.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) + { + //do conditional forwarding via "this-server" + lastResponse = RecursiveResolve(newRequest, null, null, false, false); + isAuthoritativeAnswer = false; + } + else + { + //do conditional forwarding + List forwarders = new List(lastResponse.Authority.Count); + + foreach (DnsResourceRecord rr in lastResponse.Authority) + { + if (rr.Type == DnsResourceRecordType.FWD) + forwarders.Add((rr.RDATA as DnsForwarderRecord).NameServer); + } + + lastResponse = RecursiveResolve(newRequest, null, forwarders, false, false); + isAuthoritativeAnswer = false; + } + + break; + } + } + + //check last response + if (lastResponse.Answer.Count == 0) + break; //cannot proceed to resolve further + + responseAnswer.AddRange(lastResponse.Answer); + + DnsResourceRecord lastRR = lastResponse.Answer[lastResponse.Answer.Count - 1]; + + if (lastRR.Type != DnsResourceRecordType.CNAME) + break; //cname was resolved + + lastDomain = (lastRR.RDATA as DnsCNAMERecord).Domain; + } + while (++queryCount < MAX_CNAME_HOPS); + + DnsResponseCode rcode; + IReadOnlyList authority = null; + IReadOnlyList additional = null; + + if ((lastResponse.RCODE == DnsResponseCode.Refused) && !(request.RecursionDesired && isRecursionAllowed)) + { + rcode = DnsResponseCode.NoError; + } + else + { + rcode = lastResponse.RCODE; + + if (isAuthoritativeAnswer) + { + authority = response.Authority; + additional = response.Additional; + } + else + { + if ((lastResponse.Authority.Count > 0) && (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA)) + authority = lastResponse.Authority; + } + } + + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, isAuthoritativeAnswer, false, request.RecursionDesired, isRecursionAllowed, false, false, rcode, request.Question, responseAnswer, authority, additional) { Tag = response.Tag }; + } + private DnsDatagram ProcessANAME(DnsDatagram request, DnsDatagram response, bool isRecursionAllowed) { List responseAnswer = new List(); @@ -1302,12 +1386,42 @@ namespace DnsServerCore.Dns if (lastResponse.RCODE == DnsResponseCode.Refused) { //not found in auth zone; do recursion - lastResponse = ProcessRecursiveQuery(newRequest, false, null, null, false); + lastResponse = RecursiveResolve(newRequest, null, null, false, false); } else if ((lastResponse.Answer.Count == 0) && (lastResponse.Authority.Count > 0)) { //found delegated/forwarded zone - lastResponse = ProcessAuthoritySection(newRequest, lastResponse, true); + switch (lastResponse.Authority[0].Type) + { + case DnsResourceRecordType.NS: + //do recursive resolution using last response authority name servers + List nameServers = NameServerAddress.GetNameServersFromResponse(lastResponse, _preferIPv6, false); + + lastResponse = RecursiveResolve(newRequest, nameServers, null, false, false); + break; + + case DnsResourceRecordType.FWD: + if ((lastResponse.Authority.Count == 1) && (lastResponse.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) + { + //do conditional forwarding via "this-server" + lastResponse = RecursiveResolve(newRequest, null, null, false, false); + } + else + { + //do conditional forwarding + List forwarders = new List(lastResponse.Authority.Count); + + foreach (DnsResourceRecord rr in lastResponse.Authority) + { + if (rr.Type == DnsResourceRecordType.FWD) + forwarders.Add((rr.RDATA as DnsForwarderRecord).NameServer); + } + + lastResponse = RecursiveResolve(newRequest, null, forwarders, false, false); + } + + break; + } } //check last response @@ -1346,45 +1460,6 @@ namespace DnsServerCore.Dns return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, rcode, request.Question, responseAnswer, response.Authority, response.Additional) { Tag = response.Tag }; } - private DnsDatagram ProcessAuthoritySection(DnsDatagram request, DnsDatagram response, bool isRecursionAllowed) - { - switch (response.Authority[0].Type) - { - case DnsResourceRecordType.NS: - if (request.RecursionDesired && isRecursionAllowed) - { - //do recursive resolution using response authority name servers - List nameServers = NameServerAddress.GetNameServersFromResponse(response, _preferIPv6, false); - - return ProcessRecursiveQuery(request, false, nameServers, null, false); - } - - break; - - case DnsResourceRecordType.FWD: - if ((response.Authority.Count == 1) && (response.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) - { - //do conditional forwarding via "this-server" - return ProcessRecursiveQuery(request, false, null, null, false); - } - else - { - //do conditional forwarding - List forwarders = new List(response.Authority.Count); - - foreach (DnsResourceRecord rr in response.Authority) - { - if (rr.Type == DnsResourceRecordType.FWD) - forwarders.Add((rr.RDATA as DnsForwarderRecord).NameServer); - } - - return ProcessRecursiveQuery(request, false, null, forwarders, false); - } - } - - return response; - } - private DnsDatagram ProcessBlockedQuery(DnsDatagram request) { DnsDatagram response = _blockedZoneManager.Query(request); @@ -1431,113 +1506,61 @@ namespace DnsServerCore.Dns return response; } - private DnsDatagram ProcessRecursiveQuery(DnsDatagram request, bool checkForCnameCloaking, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders, bool cacheRefreshOperation) + private DnsDatagram ProcessRecursiveQuery(DnsDatagram request, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders, bool checkForCnameCloaking, bool cacheRefreshOperation) { DnsDatagram response = RecursiveResolve(request, viaNameServers, viaForwarders, false, cacheRefreshOperation); - DnsResponseCode rcode = response.RCODE; - IReadOnlyList answer = response.Answer; - IReadOnlyList authority = null; - IReadOnlyList additional = null; - if (response.Answer.Count > 0) { - bool cnameCheckPassed = true; + DnsResourceRecordType questionType = request.Question[0].Type; + DnsResourceRecord lastRR = response.Answer[response.Answer.Count - 1]; + + if ((lastRR.Type != questionType) && (lastRR.Type == DnsResourceRecordType.CNAME) && (questionType != DnsResourceRecordType.ANY)) + response = ProcessCNAME(request, response, true, cacheRefreshOperation); if (checkForCnameCloaking && (response.Answer.Count > 1)) { - List responseAnswer = new List(); - - foreach (DnsResourceRecord record in response.Answer) + for (int i = 0; i < response.Answer.Count; i++) { - responseAnswer.Add(record); + DnsResourceRecord record = response.Answer[i]; - if (record.Type == DnsResourceRecordType.CNAME) + if (record.Type != DnsResourceRecordType.CNAME) + break; //no further CNAME records exists + + DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord((record.RDATA as DnsCNAMERecord).Domain, request.Question[0].Type, request.Question[0].Class) }); + DnsDatagram lastResponse = ProcessBlockedQuery(newRequest); + if (lastResponse != null) { - DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord((record.RDATA as DnsCNAMERecord).Domain, request.Question[0].Type, request.Question[0].Class) }); - DnsDatagram lastResponse = ProcessBlockedQuery(newRequest); - if (lastResponse != null) - { - //found cname cloaking - cnameCheckPassed = false; - responseAnswer.AddRange(lastResponse.Answer); + //found cname cloaking + List answer = new List(); - rcode = lastResponse.RCODE; - answer = responseAnswer; + //copy previous CNAME records + for (int j = 0; j < i; j++) + answer.Add(record); - if ((lastResponse.Authority.Count > 0) && (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA)) - authority = lastResponse.Authority; + //copy last response answers + answer.AddRange(lastResponse.Answer); - response.Tag = lastResponse.Tag; - break; - } + IReadOnlyList authority = null; + + if ((lastResponse.Authority.Count > 0) && (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA)) + authority = lastResponse.Authority; + + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, true, true, false, false, DnsResponseCode.NoError, request.Question, answer, authority) { Tag = lastResponse.Tag }; } } } - - if (cnameCheckPassed) - { - DnsResourceRecordType questionType = request.Question[0].Type; - DnsResourceRecord lastRR = response.Answer[response.Answer.Count - 1]; - - if ((lastRR.Type != questionType) && (lastRR.Type == DnsResourceRecordType.CNAME) && (questionType != DnsResourceRecordType.ANY)) - { - List responseAnswer = new List(); - responseAnswer.AddRange(response.Answer); - - DnsDatagram lastResponse; - int queryCount = 0; - - do - { - DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord((lastRR.RDATA as DnsCNAMERecord).Domain, request.Question[0].Type, request.Question[0].Class) }); - - if (checkForCnameCloaking) - { - //check if cname domain is blocked to prevent cname cloaking - lastResponse = ProcessBlockedQuery(newRequest); - if (lastResponse == null) - lastResponse = RecursiveResolve(newRequest, null, null, false, cacheRefreshOperation); //cname is not blocked; so do recursive query - } - else - { - //do recursive query for cname - lastResponse = RecursiveResolve(newRequest, null, null, false, cacheRefreshOperation); - } - - if (lastResponse.Answer.Count == 0) - break; - - responseAnswer.AddRange(lastResponse.Answer); - - lastRR = lastResponse.Answer[lastResponse.Answer.Count - 1]; - - if (lastRR.Type == questionType) - break; - - if (lastRR.Type != DnsResourceRecordType.CNAME) - throw new DnsServerException("Invalid response received from DNS server."); - } - while (++queryCount < MAX_CNAME_HOPS); - - rcode = lastResponse.RCODE; - answer = responseAnswer; - - if ((lastResponse.Authority.Count > 0) && (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA)) - authority = lastResponse.Authority; - - response.Tag = lastResponse.Tag; - } - } } - if ((authority == null) && (response.Authority.Count > 0) && (response.Authority[0].Type == DnsResourceRecordType.SOA)) - authority = response.Authority; + //return response + { + IReadOnlyList authority = null; - if ((response.Additional.Count > 0) && (request.Question[0].Type == DnsResourceRecordType.MX)) - additional = response.Additional; + if ((authority == null) && (response.Authority.Count > 0) && (response.Authority[0].Type == DnsResourceRecordType.SOA)) + authority = response.Authority; - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, true, true, false, false, rcode, request.Question, answer, authority, additional) { Tag = response.Tag }; + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, true, true, false, false, response.RCODE, request.Question, response.Answer, authority) { Tag = response.Tag }; + } } private DnsDatagram RecursiveResolve(DnsDatagram request, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders, bool cachePrefetchOperation, bool cacheRefreshOperation) @@ -1595,8 +1618,7 @@ namespace DnsServerCore.Dns return null; //return null as prefetch worker thread does not need valid response and thus does not need to wait //wait till short timeout for response - bool signalled = queryHandle.WaitForResponse(1800, out DnsDatagram response); //1.8 sec wait as per draft-ietf-dnsop-serve-stale-04 - if (signalled) + if (queryHandle.WaitForResponse(1800, out DnsDatagram response)) //1.8 sec wait as per draft-ietf-dnsop-serve-stale-04 { //resolver signaled if (response != null) @@ -1620,11 +1642,11 @@ namespace DnsServerCore.Dns if (response != null) return response; - //no response available from resolver + //no response available from resolver or resolver had exception and no stale record was found } } - //no response available respond with ServerFailure + //no response available; respond with ServerFailure return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.ServerFailure, request.Question); } @@ -1655,7 +1677,7 @@ namespace DnsServerCore.Dns foreach (NameServerAddress nameServerAddress in forwarders) { if (nameServerAddress.IsIPEndPointStale) //refresh forwarder IPEndPoint if stale - nameServerAddress.RecursiveResolveIPAddress(_cacheZoneManager, null, _preferIPv6, _retries, _timeout); + nameServerAddress.RecursiveResolveIPAddress(_dnsCache, null, _preferIPv6, _retries, _timeout); } } @@ -1679,9 +1701,9 @@ namespace DnsServerCore.Dns IDnsCache dnsCache; if (cachePrefetchOperation || cacheRefreshOperation) - dnsCache = new ResolverPrefetchDnsCache(_cacheZoneManager, request.Question[0]); + dnsCache = new ResolverPrefetchDnsCache(_authZoneManager, _cacheZoneManager, request.Question[0]); else - dnsCache = _cacheZoneManager; + dnsCache = _dnsCache; DnsDatagram response = DnsClient.RecursiveResolve(request.Question[0], viaNameServers, dnsCache, _proxy, _preferIPv6, _retries, _timeout, _maxStackCount); queryHandle.Set(response); @@ -1720,21 +1742,10 @@ namespace DnsServerCore.Dns //fetch stale record DnsDatagram cacheResponse = QueryCache(request, true); - if ((cacheResponse == null) || ((cacheResponse.Answer.Count == 0) && (cacheResponse.Authority.Count == 0))) + if (cacheResponse == null) { - //no stale record or empty record found; cache new empty record to avoid frequent retries by the resolver - DnsResponseCode rcode; - - if (cacheResponse == null) - rcode = DnsResponseCode.ServerFailure; - else - rcode = cacheResponse.RCODE; - - DnsDatagram failureResponse = new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, rcode, request.Question); - - _cacheZoneManager.CacheResponse(failureResponse); - - queryHandle.Set(failureResponse); + //no stale record was found; signal null response to release waiting threads + queryHandle.Set(null); } else { @@ -1844,9 +1855,16 @@ namespace DnsServerCore.Dns AuthZoneInfo zoneInfo = _authZoneManager.GetAuthZoneInfo(query.Key.Name); if (zoneInfo != null) { - //zone is hosted - if (!zoneInfo.Disabled) - continue; //no cache refresh for zone that is hosted and enabled + switch (zoneInfo.Type) + { + case AuthZoneType.Primary: + case AuthZoneType.Secondary: + //zone is hosted + if (!zoneInfo.Disabled) + continue; //no cache refresh for zone that is hosted and enabled + + break; + } } if (query.Key.Type == DnsResourceRecordType.ANY) @@ -1903,7 +1921,7 @@ namespace DnsServerCore.Dns { //refresh cache DnsDatagram request = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { sampleQuestion }); - DnsDatagram response = ProcessRecursiveQuery(request, false, null, null, true); + DnsDatagram response = ProcessRecursiveQuery(request, null, null, false, true); bool removeFromSampleList = true; @@ -2449,6 +2467,9 @@ namespace DnsServerCore.Dns public CacheZoneManager CacheZoneManager { get { return _cacheZoneManager; } } + public IDnsCache DnsCache + { get { return _dnsCache; } } + public bool AllowRecursion { get { return _allowRecursion; }