DnsServer: Implemented DnsCache abstract class and refactored existing code as per its implementation requirements. Negative record caching set to 5 mins. ProcessRecursiveQuery() implementation updated to ignore RCODE value and only check answer responses. RecursiveResolve() implementation updated to use DnsClient object for querying forwarders and only use DnsClient.RecursiveResolve() when recursive resolution is required.

This commit is contained in:
Shreyas Zare
2019-05-11 11:30:09 +05:30
parent 4b89f54b29
commit 52b375d8eb

View File

@@ -71,11 +71,14 @@ namespace DnsServerCore
X509Certificate2 _certificate;
readonly Zone _authoritativeZoneRoot = new Zone(true);
readonly Zone _cacheZoneRoot = new Zone(false) { ServeStaleTtl = 7 * 24 * 60 * 60 }; //7 days serve stale ttl as per draft-ietf-dnsop-serve-stale-04
readonly Zone _cacheZoneRoot = new Zone(false);
readonly Zone _allowedZoneRoot = new Zone(true);
Zone _blockedZoneRoot = new Zone(true);
readonly IDnsCache _dnsCache;
const uint NEGATIVE_RECORD_TTL = 300u;
const uint MINIMUM_RECORD_TTL = 0u;
const uint SERVE_STALE_TTL = 7 * 24 * 60 * 60; //7 days serve stale ttl as per draft-ietf-dnsop-serve-stale-04
readonly DnsCache _dnsCache;
bool _allowRecursion = false;
bool _allowRecursionOnlyForPrivateNetworks = false;
@@ -145,7 +148,7 @@ namespace DnsServerCore
public DnsServer(IPAddress[] localIPs)
{
_localIPs = localIPs;
_dnsCache = new DnsCache(_cacheZoneRoot);
_dnsCache = new ResolverDnsCache(_cacheZoneRoot);
}
#endregion
@@ -1074,7 +1077,7 @@ namespace DnsServerCore
DnsResourceRecord[] authority;
DnsResourceRecord[] additional;
if ((response.Header.RCODE == DnsResponseCode.NoError) && (response.Answer.Length > 0))
if (response.Answer.Length > 0)
{
DnsResourceRecordType questionType = request.Question[0].Type;
DnsResourceRecord lastRR = response.Answer[response.Answer.Length - 1];
@@ -1095,7 +1098,7 @@ namespace DnsServerCore
lastResponse = RecursiveResolve(new DnsDatagram(new DnsHeader(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, 1, 0, 0, 0), new DnsQuestionRecord[] { question }, null, null, null), null, false, cacheRefreshOperation);
cacheHit &= ("cacheHit".Equals(lastResponse.Tag));
if ((lastResponse.Header.RCODE != DnsResponseCode.NoError) || (lastResponse.Answer.Length == 0))
if (lastResponse.Answer.Length == 0)
break;
responseAnswer.AddRange(lastResponse.Answer);
@@ -1188,25 +1191,39 @@ namespace DnsServerCore
//got lock so question not being resolved; do recursive resolution in worker thread
ThreadPool.QueueUserWorkItem(delegate (object state)
{
//select protocol
DnsTransportProtocol protocol;
if ((viaNameServers == null) && (_forwarders != null))
{
viaNameServers = _forwarders;
protocol = _forwarderProtocol;
}
else
{
protocol = _recursiveResolveProtocol;
}
DnsDatagram response = null;
try
{
//recursive resolve and update cache
response = DnsClient.RecursiveResolve(request.Question[0], viaNameServers, (cachePrefetchOperation || cacheRefreshOperation ? new PrefetchDnsCache(_cacheZoneRoot, request.Question[0]) : _dnsCache), _proxy, _preferIPv6, protocol, _retries, _timeout, _recursiveResolveProtocol, _maxStackCount);
if ((viaNameServers == null) && (_forwarders != null))
{
//use forwarders
//refresh forwarder IPEndPoint if stale
foreach (NameServerAddress nameServerAddress in _forwarders)
{
if (nameServerAddress.IsIPEndPointStale && (_proxy == null)) //recursive resolve name server when proxy is null else let proxy resolve it
nameServerAddress.RecursiveResolveIPAddress(_dnsCache, _proxy, _preferIPv6, _recursiveResolveProtocol, _retries, _timeout, _recursiveResolveProtocol);
}
//query forwarders and update cache
DnsClient dnsClient = new DnsClient(_forwarders);
dnsClient.Proxy = _proxy;
dnsClient.PreferIPv6 = _preferIPv6;
dnsClient.Protocol = _forwarderProtocol;
dnsClient.Retries = _retries;
dnsClient.Timeout = _timeout;
dnsClient.RecursiveResolveProtocol = _recursiveResolveProtocol;
response = dnsClient.Resolve(request.Question[0]);
_dnsCache.CacheResponse(response);
}
else
{
//recursive resolve and update cache
response = DnsClient.RecursiveResolve(request.Question[0], viaNameServers, (cachePrefetchOperation || cacheRefreshOperation ? new ResolverPrefetchDnsCache(_cacheZoneRoot, request.Question[0]) : _dnsCache), _proxy, _preferIPv6, _recursiveResolveProtocol, _retries, _timeout, _recursiveResolveProtocol, _maxStackCount);
}
}
catch (Exception ex)
{
@@ -1927,7 +1944,7 @@ namespace DnsServerCore
}
}
internal IDnsCache Cache
internal DnsCache Cache
{ get { return _dnsCache; } }
public bool AllowRecursion
@@ -2080,17 +2097,18 @@ namespace DnsServerCore
#endregion
class DnsCache : IDnsCache
class ResolverDnsCache : DnsCache
{
#region variables
readonly Zone _cacheZoneRoot;
readonly protected Zone _cacheZoneRoot;
#endregion
#region constructor
public DnsCache(Zone cacheZoneRoot)
public ResolverDnsCache(Zone cacheZoneRoot)
: base(NEGATIVE_RECORD_TTL, MINIMUM_RECORD_TTL, SERVE_STALE_TTL)
{
_cacheZoneRoot = cacheZoneRoot;
}
@@ -2099,33 +2117,32 @@ namespace DnsServerCore
#region public
public DnsDatagram Query(DnsDatagram request)
public override DnsDatagram Query(DnsDatagram request)
{
return _cacheZoneRoot.Query(request);
}
public void CacheResponse(DnsDatagram response)
protected override void CacheRecords(ICollection<DnsResourceRecord> resourceRecords)
{
_cacheZoneRoot.CacheResponse(response);
_cacheZoneRoot.SetRecords(resourceRecords);
}
#endregion
}
class PrefetchDnsCache : IDnsCache
class ResolverPrefetchDnsCache : ResolverDnsCache
{
#region variables
readonly Zone _cacheZoneRoot;
readonly DnsQuestionRecord _prefetchQuery;
#endregion
#region constructor
public PrefetchDnsCache(Zone cacheZoneRoot, DnsQuestionRecord prefetchQuery)
public ResolverPrefetchDnsCache(Zone cacheZoneRoot, DnsQuestionRecord prefetchQuery)
: base(cacheZoneRoot)
{
_cacheZoneRoot = cacheZoneRoot;
_prefetchQuery = prefetchQuery;
}
@@ -2133,7 +2150,7 @@ namespace DnsServerCore
#region public
public DnsDatagram Query(DnsDatagram request)
public override DnsDatagram Query(DnsDatagram request)
{
if (_prefetchQuery.Equals(request.Question[0]))
return _cacheZoneRoot.QueryCacheGetClosestNameServers(request); //return closest name servers so that the recursive resolver queries them to refreshes cache instead of returning response from cache
@@ -2141,11 +2158,6 @@ namespace DnsServerCore
return _cacheZoneRoot.Query(request);
}
public void CacheResponse(DnsDatagram response)
{
_cacheZoneRoot.CacheResponse(response);
}
#endregion
}