diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 7faf5d7c..f60cb4d3 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -17,6 +17,7 @@ along with this program. If not, see . */ +using DnsServerCore.Dns.Applications; using DnsServerCore.Dns.ZoneManagers; using DnsServerCore.Dns.Zones; using Newtonsoft.Json; @@ -83,6 +84,7 @@ namespace DnsServerCore.Dns readonly BlockedZoneManager _blockedZoneManager; readonly BlockListZoneManager _blockListZoneManager; readonly CacheZoneManager _cacheZoneManager = new CacheZoneManager(); + readonly DnsApplicationManager _dnsApplicationManager; readonly ResolverDnsCache _dnsCache; @@ -95,6 +97,7 @@ namespace DnsServerCore.Dns IReadOnlyList _forwarders; bool _preferIPv6; bool _randomizeName; + bool _qnameMinimization; int _forwarderRetries = 3; int _resolverRetries = 5; int _forwarderTimeout = 4000; @@ -177,6 +180,7 @@ namespace DnsServerCore.Dns _allowedZoneManager = new AllowedZoneManager(this); _blockedZoneManager = new BlockedZoneManager(this); _blockListZoneManager = new BlockListZoneManager(this); + _dnsApplicationManager = new DnsApplicationManager(_configFolder); _dnsCache = new ResolverDnsCache(_authZoneManager, _cacheZoneManager); @@ -202,6 +206,9 @@ namespace DnsServerCore.Dns if (_authZoneManager != null) _authZoneManager.Dispose(); + if (_dnsApplicationManager != null) + _dnsApplicationManager.Dispose(); + if (_stats != null) _stats.Dispose(); } @@ -914,13 +921,13 @@ namespace DnsServerCore.Dns } //query authoritative zone - response = await ProcessAuthoritativeQueryAsync(request, inAllowedZone, isRecursionAllowed); + response = await ProcessAuthoritativeQueryAsync(request, remoteEP, inAllowedZone, isRecursionAllowed, protocol); if ((response.RCODE != DnsResponseCode.Refused) || !request.RecursionDesired || !isRecursionAllowed) return response; //do recursive query - return await ProcessRecursiveQueryAsync(request, null, null, !inAllowedZone, false); + return await ProcessRecursiveQueryAsync(request, null, !inAllowedZone, false); } } catch (InvalidDomainNameException) @@ -1022,7 +1029,7 @@ namespace DnsServerCore.Dns return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, axfrRecords) { Tag = StatsResponseType.Authoritative }; } - private Task ProcessAuthoritativeQueryAsync(DnsDatagram request, bool inAllowedZone, bool isRecursionAllowed) + private async Task ProcessAuthoritativeQueryAsync(DnsDatagram request, IPEndPoint remoteEP, bool inAllowedZone, bool isRecursionAllowed, DnsTransportProtocol protocol) { DnsDatagram response = _authZoneManager.Query(request); response.Tag = StatsResponseType.Authoritative; @@ -1039,10 +1046,10 @@ namespace DnsServerCore.Dns switch (lastRR.Type) { case DnsResourceRecordType.CNAME: - return ProcessCNAMEAsync(request, response, isRecursionAllowed, false); + return await ProcessCNAMEAsync(request, response, isRecursionAllowed, false); case DnsResourceRecordType.ANAME: - return ProcessANAMEAsync(request, response, isRecursionAllowed); + return await ProcessANAMEAsync(request, response, isRecursionAllowed); } } } @@ -1053,10 +1060,8 @@ namespace DnsServerCore.Dns case DnsResourceRecordType.NS: if (request.RecursionDesired && isRecursionAllowed) { - //do recursive resolution using response authority name servers - List nameServers = NameServerAddress.GetNameServersFromResponse(response, _preferIPv6, false); - - return ProcessRecursiveQueryAsync(request, nameServers, null, !inAllowedZone, false); + //do recursive resolution; name servers will be provided via ResolverDnsCache + return await ProcessRecursiveQueryAsync(request, null, !inAllowedZone, false); } break; @@ -1065,7 +1070,7 @@ namespace DnsServerCore.Dns if ((response.Authority.Count == 1) && (response.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) { //do conditional forwarding via "this-server" - return ProcessRecursiveQueryAsync(request, null, null, !inAllowedZone, false); + return await ProcessRecursiveQueryAsync(request, null, !inAllowedZone, false); } else { @@ -1083,8 +1088,49 @@ namespace DnsServerCore.Dns } } - return ProcessRecursiveQueryAsync(request, null, forwarders, !inAllowedZone, false); + return await ProcessRecursiveQueryAsync(request, forwarders, !inAllowedZone, false); } + + case DnsResourceRecordType.APP: + if (response.Authority.Count > 0) + { + //do application query + DnsResourceRecord appResourceRecord = response.Authority[0]; + DnsApplicationRecord appRecord = appResourceRecord.RDATA as DnsApplicationRecord; + + if (_dnsApplicationManager.Packages.TryGetValue(appRecord.Package, out DnsApplicationPackage package)) + { + if (package.DnsApplications.TryGetValue(appRecord.ClassPath, out IDnsApplication dnsApplication)) + { + AuthZoneInfo zoneInfo = _authZoneManager.GetAuthZoneInfo(appResourceRecord.Name); + IDnsServer dnsServer = new DnsServerInternal(this, package.PackagePath); + + DnsDatagram appResponse = await dnsApplication.ProcessQueryAsync(request, remoteEP, zoneInfo.Name, appRecord.Data, isRecursionAllowed, dnsServer); + if (appResponse != null) + { + if (appResponse.AuthoritativeAnswer) + appResponse.Tag = StatsResponseType.Authoritative; + + return appResponse; //return app response + } + } + else + { + LogManager log = _log; + if (log != null) + log.Write(remoteEP, protocol, "DNS application '" + appRecord.ClassPath + "' was not found in the package: " + appRecord.Package); + } + } + else + { + LogManager log = _log; + if (log != null) + log.Write(remoteEP, protocol, "DNS application package was not found: " + appRecord.Package); + } + } + + //return refused response + return new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.Refused, request.Question); } } } @@ -1092,7 +1138,7 @@ namespace DnsServerCore.Dns if (response.RecursionAvailable != isRecursionAllowed) response = new DnsDatagram(response.Identifier, response.IsResponse, response.OPCODE, response.AuthoritativeAnswer, response.Truncation, response.RecursionDesired, isRecursionAllowed, response.AuthenticData, response.CheckingDisabled, response.RCODE, response.Question, response.Answer, response.Authority, response.Additional); - return Task.FromResult(response); + return response; } private async Task ProcessCNAMEAsync(DnsDatagram request, DnsDatagram response, bool isRecursionAllowed, bool cacheRefreshOperation) @@ -1118,7 +1164,7 @@ namespace DnsServerCore.Dns if (newRequest.RecursionDesired && isRecursionAllowed) { //do recursion - lastResponse = await RecursiveResolveAsync(newRequest, null, null, false, cacheRefreshOperation); + lastResponse = await RecursiveResolveAsync(newRequest, null, false, cacheRefreshOperation); isAuthoritativeAnswer = false; } else @@ -1139,10 +1185,8 @@ namespace DnsServerCore.Dns case DnsResourceRecordType.NS: if (newRequest.RecursionDesired && isRecursionAllowed) { - //do recursive resolution using last response authority name servers - List nameServers = NameServerAddress.GetNameServersFromResponse(lastResponse, _preferIPv6, false); - - lastResponse = await RecursiveResolveAsync(newRequest, nameServers, null, false, false); + //do recursive resolution; name servers will be provided via ResolveDnsCache + lastResponse = await RecursiveResolveAsync(newRequest, null, false, false); isAuthoritativeAnswer = false; } @@ -1152,7 +1196,7 @@ namespace DnsServerCore.Dns if ((lastResponse.Authority.Count == 1) && (lastResponse.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) { //do conditional forwarding via "this-server" - lastResponse = await RecursiveResolveAsync(newRequest, null, null, false, false); + lastResponse = await RecursiveResolveAsync(newRequest, null, false, false); isAuthoritativeAnswer = false; } else @@ -1171,7 +1215,7 @@ namespace DnsServerCore.Dns } } - lastResponse = await RecursiveResolveAsync(newRequest, null, forwarders, false, false); + lastResponse = await RecursiveResolveAsync(newRequest, forwarders, false, false); isAuthoritativeAnswer = false; } @@ -1256,7 +1300,7 @@ namespace DnsServerCore.Dns if (lastResponse.RCODE == DnsResponseCode.Refused) { //not found in auth zone; do recursion - lastResponse = await RecursiveResolveAsync(newRequest, null, null, false, false); + lastResponse = await RecursiveResolveAsync(newRequest, null, false, false); } else if ((lastResponse.Answer.Count == 0) && (lastResponse.Authority.Count > 0)) { @@ -1264,17 +1308,15 @@ namespace DnsServerCore.Dns 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 = await RecursiveResolveAsync(newRequest, nameServers, null, false, false); + //do recursive resolution; name servers will be provided via ResolverDnsCache + lastResponse = await RecursiveResolveAsync(newRequest, 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 = await RecursiveResolveAsync(newRequest, null, null, false, false); + lastResponse = await RecursiveResolveAsync(newRequest, null, false, false); } else { @@ -1292,7 +1334,7 @@ namespace DnsServerCore.Dns } } - lastResponse = await RecursiveResolveAsync(newRequest, null, forwarders, false, false); + lastResponse = await RecursiveResolveAsync(newRequest, forwarders, false, false); } break; @@ -1381,9 +1423,9 @@ namespace DnsServerCore.Dns return response; } - private async Task ProcessRecursiveQueryAsync(DnsDatagram request, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders, bool checkForCnameCloaking, bool cacheRefreshOperation) + private async Task ProcessRecursiveQueryAsync(DnsDatagram request, IReadOnlyList viaForwarders, bool checkForCnameCloaking, bool cacheRefreshOperation) { - DnsDatagram response = await RecursiveResolveAsync(request, viaNameServers, viaForwarders, false, cacheRefreshOperation); + DnsDatagram response = await RecursiveResolveAsync(request, viaForwarders, false, cacheRefreshOperation); if (response.Answer.Count > 0) { @@ -1473,7 +1515,7 @@ namespace DnsServerCore.Dns } } - private async Task RecursiveResolveAsync(DnsDatagram request, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders, bool cachePrefetchOperation, bool cacheRefreshOperation) + private async Task RecursiveResolveAsync(DnsDatagram request, IReadOnlyList viaForwarders, bool cachePrefetchOperation, bool cacheRefreshOperation) { if (!cachePrefetchOperation && !cacheRefreshOperation) { @@ -1489,7 +1531,7 @@ namespace DnsServerCore.Dns if ((answer.OriginalTtlValue > _cachePrefetchEligibility) && (answer.TtlValue < _cachePrefetchTrigger)) { //trigger prefetch async - _ = PrefetchCacheAsync(request, viaNameServers, viaForwarders); + _ = PrefetchCacheAsync(request, viaForwarders); break; } } @@ -1508,7 +1550,7 @@ namespace DnsServerCore.Dns //got new resolver task added so question is not being resolved; do recursive resolution in another task on resolver thread pool _ = Task.Factory.StartNew(delegate () { - return RecursiveResolveAsync(request, viaNameServers, viaForwarders, cachePrefetchOperation, cacheRefreshOperation, resolverTaskCompletionSource); + return RecursiveResolveAsync(request, viaForwarders, cachePrefetchOperation, cacheRefreshOperation, resolverTaskCompletionSource); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _resolverTaskScheduler); } @@ -1563,7 +1605,7 @@ namespace DnsServerCore.Dns return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.ServerFailure, request.Question); } - private async Task RecursiveResolveAsync(DnsDatagram request, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders, bool cachePrefetchOperation, bool cacheRefreshOperation, TaskCompletionSource taskCompletionSource) + private async Task RecursiveResolveAsync(DnsDatagram request, IReadOnlyList viaForwarders, bool cachePrefetchOperation, bool cacheRefreshOperation, TaskCompletionSource taskCompletionSource) { IReadOnlyList forwarders = _forwarders; if (viaForwarders != null) @@ -1571,7 +1613,7 @@ namespace DnsServerCore.Dns try { - if ((viaNameServers == null) && (forwarders != null)) + if (forwarders != null) { //use forwarders if (_proxy == null) @@ -1580,7 +1622,7 @@ namespace DnsServerCore.Dns foreach (NameServerAddress nameServerAddress in forwarders) { if (nameServerAddress.IsIPEndPointStale) //refresh forwarder IPEndPoint if stale - await nameServerAddress.RecursiveResolveIPAddressAsync(_dnsCache, null, _preferIPv6, _randomizeName, _resolverRetries, _resolverTimeout); + await nameServerAddress.RecursiveResolveIPAddressAsync(_dnsCache, null, _preferIPv6, _randomizeName, _qnameMinimization, _resolverRetries, _resolverTimeout); } } @@ -1610,7 +1652,7 @@ namespace DnsServerCore.Dns else dnsCache = _dnsCache; - DnsDatagram response = await DnsClient.RecursiveResolveAsync(request.Question[0], viaNameServers, dnsCache, _proxy, _preferIPv6, _randomizeName, _resolverRetries, _resolverTimeout, _resolverMaxStackCount); + DnsDatagram response = await DnsClient.RecursiveResolveAsync(request.Question[0], dnsCache, _proxy, _preferIPv6, _randomizeName, _qnameMinimization, _resolverRetries, _resolverTimeout, _resolverMaxStackCount); taskCompletionSource.SetResult(response); } } @@ -1619,30 +1661,20 @@ namespace DnsServerCore.Dns LogManager log = _log; if (log != null) { - string nameServers = null; + string strForwarders = null; - if (viaNameServers != null) - { - foreach (NameServerAddress nameServer in viaNameServers) - { - if (nameServers == null) - nameServers = nameServer.ToString(); - else - nameServers += ", " + nameServer.ToString(); - } - } - else if (forwarders != null) + if (forwarders != null) { foreach (NameServerAddress nameServer in forwarders) { - if (nameServers == null) - nameServers = nameServer.ToString(); + if (strForwarders == null) + strForwarders = nameServer.ToString(); else - nameServers += ", " + nameServer.ToString(); + strForwarders += ", " + nameServer.ToString(); } } - log.Write("DNS Server recursive resolution failed for QNAME: " + request.Question[0].Name + "; QTYPE: " + request.Question[0].Type.ToString() + "; QCLASS: " + request.Question[0].Class.ToString() + (nameServers == null ? "" : "; Name Servers: " + nameServers) + ";\r\n" + ex.ToString()); + log.Write("DNS Server recursive resolution failed for QNAME: " + request.Question[0].Name + "; QTYPE: " + request.Question[0].Type.ToString() + "; QCLASS: " + request.Question[0].Class.ToString() + (strForwarders == null ? "" : "; Forwarders: " + strForwarders) + ";\r\n" + ex.ToString()); } if (_serveStale) @@ -1704,11 +1736,11 @@ namespace DnsServerCore.Dns return null; } - private async Task PrefetchCacheAsync(DnsDatagram request, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders) + private async Task PrefetchCacheAsync(DnsDatagram request, IReadOnlyList viaForwarders) { try { - await RecursiveResolveAsync(request, viaNameServers, viaForwarders, true, false); + await RecursiveResolveAsync(request, viaForwarders, true, false); } catch (Exception ex) { @@ -1724,7 +1756,7 @@ namespace DnsServerCore.Dns { //refresh cache DnsDatagram request = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { sample.SampleQuestion }); - DnsDatagram response = await ProcessRecursiveQueryAsync(request, sample.ViaNameServers, sample.ViaForwarders, false, true); + DnsDatagram response = await ProcessRecursiveQueryAsync(request, sample.ViaForwarders, false, true); bool removeFromSampleList = true; DateTime utcNow = DateTime.UtcNow; @@ -1824,7 +1856,6 @@ namespace DnsServerCore.Dns DnsQuestionRecord refreshQuery; - IReadOnlyList viaNameServers = null; IReadOnlyList viaForwarders = null; //query auth zone for refresh query @@ -1853,10 +1884,6 @@ namespace DnsServerCore.Dns { case DnsResourceRecordType.NS: refreshQuery = GetCacheRefreshNeededQuery(eligibleQuery.Key, cacheRefreshTrigger); - - if ((refreshQuery != null) && refreshQuery.Equals(eligibleQuery.Key)) - viaNameServers = NameServerAddress.GetNameServersFromResponse(response, _preferIPv6, false); - break; case DnsResourceRecordType.FWD: @@ -1904,7 +1931,7 @@ namespace DnsServerCore.Dns } if (refreshQuery != null) - cacheRefreshSampleList.Add(new CacheRefreshSample(refreshQuery, viaNameServers, viaForwarders)); + cacheRefreshSampleList.Add(new CacheRefreshSample(refreshQuery, viaForwarders)); } _cacheRefreshSampleList = cacheRefreshSampleList; @@ -2472,6 +2499,9 @@ namespace DnsServerCore.Dns public CacheZoneManager CacheZoneManager { get { return _cacheZoneManager; } } + public DnsApplicationManager DnsApplicationManager + { get { return _dnsApplicationManager; } } + public IDnsCache DnsCache { get { return _dnsCache; } } @@ -2515,6 +2545,12 @@ namespace DnsServerCore.Dns set { _randomizeName = value; } } + public bool QnameMinimization + { + get { return _qnameMinimization; } + set { _qnameMinimization = value; } + } + public int ForwarderRetries { get { return _forwarderRetries; } @@ -2670,15 +2706,13 @@ namespace DnsServerCore.Dns class CacheRefreshSample { - public CacheRefreshSample(DnsQuestionRecord sampleQuestion, IReadOnlyList viaNameServers, IReadOnlyList viaForwarders) + public CacheRefreshSample(DnsQuestionRecord sampleQuestion, IReadOnlyList viaForwarders) { SampleQuestion = sampleQuestion; - ViaNameServers = viaNameServers; ViaForwarders = viaForwarders; } public DnsQuestionRecord SampleQuestion { get; } - public IReadOnlyList ViaNameServers { get; } public IReadOnlyList ViaForwarders { get; } } }