From 8b929a84d8bfe5c95da53337ad1d0312204ff0f1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 12:55:08 +0530 Subject: [PATCH 01/24] AdvancedBlocking: updated parser to read inline comments correctly. --- Apps/AdvancedBlockingApp/App.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Apps/AdvancedBlockingApp/App.cs b/Apps/AdvancedBlockingApp/App.cs index a15781cb..28a9228a 100644 --- a/Apps/AdvancedBlockingApp/App.cs +++ b/Apps/AdvancedBlockingApp/App.cs @@ -1110,7 +1110,7 @@ namespace AdvancedBlocking if (line.Length == 0) continue; //skip empty line - if (line.StartsWith("#")) + if (line.StartsWith('#')) continue; //skip comment line firstWord = PopWord(ref line); @@ -1123,7 +1123,7 @@ namespace AdvancedBlocking { secondWord = PopWord(ref line); - if (secondWord.Length == 0) + if ((secondWord.Length == 0) || secondWord.StartsWith('#')) hostname = firstWord; else hostname = secondWord; @@ -1239,7 +1239,7 @@ namespace AdvancedBlocking if (line.Length == 0) continue; //skip empty line - if (line.StartsWith("#")) + if (line.StartsWith('#')) continue; //skip comment line regices.Enqueue(line); @@ -1338,7 +1338,7 @@ namespace AdvancedBlocking if (line.Length == 0) continue; //skip empty line - if (line.StartsWith("!")) + if (line.StartsWith('!')) continue; //skip comment line if (line.StartsWith("||")) @@ -1349,7 +1349,7 @@ namespace AdvancedBlocking string domain = line.Substring(2, i - 2); string options = line.Substring(i + 1); - if (((options.Length == 0) || (options.StartsWith("$") && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) + if (((options.Length == 0) || (options.StartsWith('$') && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) blockedDomains.Enqueue(domain); } else @@ -1368,7 +1368,7 @@ namespace AdvancedBlocking string domain = line.Substring(4, i - 4); string options = line.Substring(i + 1); - if (((options.Length == 0) || (options.StartsWith("$") && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) + if (((options.Length == 0) || (options.StartsWith('$') && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) allowedDomains.Enqueue(domain); } else From 2aba1bb46c0dd12a9e7f3ebbe1dd2a79faafd2fb Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 12:56:16 +0530 Subject: [PATCH 02/24] AdvancedForwarding: updated app to detect if domain is the same as that of the forwarder. --- Apps/AdvancedForwardingApp/App.cs | 54 +++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/Apps/AdvancedForwardingApp/App.cs b/Apps/AdvancedForwardingApp/App.cs index 267fc0e4..bbed2e56 100644 --- a/Apps/AdvancedForwardingApp/App.cs +++ b/Apps/AdvancedForwardingApp/App.cs @@ -444,6 +444,28 @@ namespace AdvancedForwarding return false; } + public static bool IsForwarderDomain(string domain, IReadOnlyList forwardings) + { + foreach (Forwarding forwarding in forwardings) + { + if (IsForwarderDomain(domain, forwarding._forwarderRecords)) + return true; + } + + return false; + } + + public static bool IsForwarderDomain(string domain, IReadOnlyList forwarderRecords) + { + foreach (DnsForwarderRecordData forwarderRecord in forwarderRecords) + { + if (domain.Equals(forwarderRecord.NameServer.Host, StringComparison.OrdinalIgnoreCase)) + return true; + } + + return false; + } + #endregion #region private @@ -554,7 +576,12 @@ namespace AdvancedForwarding { DateTime configFileLastModified = File.GetLastWriteTimeUtc(_configFile); if (configFileLastModified > _configFileLastModified) + { ReloadUpstreamsFile(); + + //force GC collection to remove old cache data from memory quickly + GC.Collect(); + } } catch (Exception ex) { @@ -611,10 +638,10 @@ namespace AdvancedForwarding if (line.Length == 0) continue; //skip empty line - if (line.StartsWith("#")) + if (line.StartsWith('#')) continue; //skip comment line - if (line.StartsWith("[")) + if (line.StartsWith('[')) { int i = line.LastIndexOf(']'); if (i < 0) @@ -689,11 +716,26 @@ namespace AdvancedForwarding public bool TryGetForwarderRecords(string domain, out IReadOnlyList forwarderRecords) { - if ((_forwardings.Count > 0) && Forwarding.TryGetForwarderRecords(domain, _forwardings, out forwarderRecords)) - return true; - - if (_defaultForwarderRecords.Count > 0) + if ((_forwardings is not null) && (_forwardings.Count > 0)) { + if (Forwarding.IsForwarderDomain(domain, _forwardings)) + { + forwarderRecords = null; + return false; + } + + if (Forwarding.TryGetForwarderRecords(domain, _forwardings, out forwarderRecords)) + return true; + } + + if ((_defaultForwarderRecords is not null) && (_defaultForwarderRecords.Count > 0)) + { + if (Forwarding.IsForwarderDomain(domain, _defaultForwarderRecords)) + { + forwarderRecords = null; + return false; + } + forwarderRecords = _defaultForwarderRecords; return true; } From 2737d136bbd5822277e7bde5457956ba970bfce3 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 12:57:21 +0530 Subject: [PATCH 03/24] updated systemd.service to use new install path. --- DnsServerApp/systemd.service | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerApp/systemd.service b/DnsServerApp/systemd.service index b445223c..ee68d091 100644 --- a/DnsServerApp/systemd.service +++ b/DnsServerApp/systemd.service @@ -2,8 +2,8 @@ Description=Technitium DNS Server [Service] -WorkingDirectory=/etc/dns -ExecStart=/usr/bin/dotnet /etc/dns/DnsServerApp.dll +WorkingDirectory=/opt/technitium/dns +ExecStart=/usr/bin/dotnet /opt/technitium/dns/DnsServerApp.dll /etc/dns Restart=always # Restart service after 10 seconds if the dotnet service crashes: RestartSec=10 From 19025f8e1260cadcb19424daf1fdfa7e9eaa4a1c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 12:57:48 +0530 Subject: [PATCH 04/24] install.sh: updated to use new install path. --- DnsServerApp/install.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/DnsServerApp/install.sh b/DnsServerApp/install.sh index 5b7a1885..131120c7 100644 --- a/DnsServerApp/install.sh +++ b/DnsServerApp/install.sh @@ -1,8 +1,15 @@ #!/bin/sh dotnetDir="/opt/dotnet" -dnsDir="/etc/dns" -dnsTar="/etc/dns/DnsServerPortable.tar.gz" + +if [ -d "/etc/dns/config" ] +then + dnsDir="/etc/dns" +else + dnsDir="/opt/technitium/dns" +fi + +dnsTar="$dnsDir/DnsServerPortable.tar.gz" dnsUrl="https://download.technitium.com/dns/DnsServerPortable.tar.gz" mkdir -p $dnsDir From 2d89c62cb6ffac77aa5b02935d5e20b57d75be17 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 12:58:07 +0530 Subject: [PATCH 05/24] uinstall.sh: updated to use new install path. --- DnsServerApp/uninstall.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DnsServerApp/uninstall.sh b/DnsServerApp/uninstall.sh index 02414c42..bbeebcac 100644 --- a/DnsServerApp/uninstall.sh +++ b/DnsServerApp/uninstall.sh @@ -1,7 +1,13 @@ #!/bin/sh dotnetDir="/opt/dotnet" -dnsDir="/etc/dns" + +if [ -d "/etc/dns/config" ] +then + dnsDir="/etc/dns" +else + dnsDir="/opt/technitium/dns" +fi echo "" echo "=================================" From cc597d8694d613ca14d6377bf91b3330b910b227 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:03:40 +0530 Subject: [PATCH 06/24] AllowedZoneManager: refactored Query() to IsAllowed(). --- DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs index 34eff79d..7b94a70d 100644 --- a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs @@ -176,9 +176,12 @@ namespace DnsServerCore.Dns.ZoneManagers log.Write("DNS Server allowed zone file was saved: " + allowedZoneFile); } - public DnsDatagram Query(DnsDatagram request) + public bool IsAllowed(DnsDatagram request) { - return _zoneManager.Query(request); + if (_zoneManager.TotalZones < 1) + return false; + + return _zoneManager.Query(request) is not null; } #endregion From d62483bd517e4049f097f1b072b613547ad4ad7f Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:04:25 +0530 Subject: [PATCH 07/24] BlockedZoneManager: updated Query() to check count before query. --- DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs index 3f6f4695..cfe11d88 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs @@ -196,6 +196,9 @@ namespace DnsServerCore.Dns.ZoneManagers public DnsDatagram Query(DnsDatagram request) { + if (_zoneManager.TotalZones < 1) + return null; + return _zoneManager.Query(request); } From a53d5df19cc2124d1830af3b3f39b6838eea6584 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:06:04 +0530 Subject: [PATCH 08/24] BlockListZoneManager: updated implementation of allowed list by having a separate allowed zone. Updated parser to detect inline comment. Added IsAllowed() method. Updated Query() to check count before query. --- .../Dns/ZoneManagers/BlockListZoneManager.cs | 135 +++++++++++------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs index 0dc0bcfb..9862cca2 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs @@ -43,6 +43,8 @@ namespace DnsServerCore.Dns.ZoneManagers readonly List _allowListUrls = new List(); readonly List _blockListUrls = new List(); + + IReadOnlyDictionary _allowListZone = new Dictionary(); IReadOnlyDictionary> _blockListZone = new Dictionary>(); DnsSOARecordData _soaRecord; @@ -109,9 +111,10 @@ namespace DnsServerCore.Dns.ZoneManagers return word; } - private Queue ReadListFile(Uri listUrl, bool isAllowList, Dictionary allowedDomains) + private Queue ReadListFile(Uri listUrl, bool isAllowList, out Queue exceptionDomains) { Queue domains = new Queue(); + exceptionDomains = new Queue(); try { @@ -141,7 +144,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (line.Length == 0) continue; //skip empty line - if (line.StartsWith("#") || line.StartsWith("!")) + if (line.StartsWith('#') || line.StartsWith("!")) continue; //skip comment line if (line.StartsWith("||")) @@ -153,38 +156,35 @@ namespace DnsServerCore.Dns.ZoneManagers domain = line.Substring(2, i - 2); options = line.Substring(i + 1); - if (((options.Length == 0) || (options.StartsWith("$") && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) - domains.Enqueue(domain); + if (((options.Length == 0) || (options.StartsWith('$') && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) + domains.Enqueue(domain.ToLower()); } else { domain = line.Substring(2); if (DnsClient.IsDomainNameValid(domain)) - domains.Enqueue(domain); + domains.Enqueue(domain.ToLower()); } } else if (line.StartsWith("@@||")) { - //adblock format - if (!isAllowList) + //adblock format - exception syntax + i = line.IndexOf('^'); + if (i > -1) { - i = line.IndexOf('^'); - if (i > -1) - { - domain = line.Substring(4, i - 4); - options = line.Substring(i + 1); + domain = line.Substring(4, i - 4); + options = line.Substring(i + 1); - if (((options.Length == 0) || (options.StartsWith("$") && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) - allowedDomains.TryAdd(domain, null); - } - else - { - domain = line.Substring(4); + if (((options.Length == 0) || (options.StartsWith('$') && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) + exceptionDomains.Enqueue(domain.ToLower()); + } + else + { + domain = line.Substring(4); - if (DnsClient.IsDomainNameValid(domain)) - allowedDomains.TryAdd(domain, null); - } + if (DnsClient.IsDomainNameValid(domain)) + exceptionDomains.Enqueue(domain.ToLower()); } } else @@ -200,7 +200,7 @@ namespace DnsServerCore.Dns.ZoneManagers { secondWord = PopWord(ref line); - if (secondWord.Length == 0) + if ((secondWord.Length == 0) || secondWord.StartsWith('#')) hostname = firstWord; else hostname = secondWord; @@ -267,11 +267,13 @@ namespace DnsServerCore.Dns.ZoneManagers return null; } - private static bool IsZoneAllowed(Dictionary allowedDomains, string domain) + private bool IsZoneAllowed(string domain) { + domain = domain.ToLower(); + do { - if (allowedDomains.TryGetValue(domain, out _)) + if (_allowListZone.TryGetValue(domain, out _)) return true; domain = AuthZoneManager.GetParentZone(domain); @@ -287,37 +289,57 @@ namespace DnsServerCore.Dns.ZoneManagers public void LoadBlockLists() { - //read all allowed domains in dictionary - Dictionary allowedDomains = new Dictionary(); + Dictionary> allowListQueues = new Dictionary>(_allowListUrls.Count); + Dictionary> blockListQueues = new Dictionary>(_blockListUrls.Count); + int totalAllowedDomains = 0; + int totalBlockedDomains = 0; + //read all allow lists in a queue foreach (Uri allowListUrl in _allowListUrls) { - Queue queue = ReadListFile(allowListUrl, true, null); + if (!allowListQueues.ContainsKey(allowListUrl)) + { + Queue allowListQueue = ReadListFile(allowListUrl, true, out Queue blockListQueue); + + totalAllowedDomains += allowListQueue.Count; + allowListQueues.Add(allowListUrl, allowListQueue); + + totalBlockedDomains += blockListQueue.Count; + blockListQueues.Add(allowListUrl, blockListQueue); + } + } + + //read all block lists in a queue + foreach (Uri blockListUrl in _blockListUrls) + { + if (!blockListQueues.ContainsKey(blockListUrl)) + { + Queue blockListQueue = ReadListFile(blockListUrl, false, out Queue allowListQueue); + + totalBlockedDomains += blockListQueue.Count; + blockListQueues.Add(blockListUrl, blockListQueue); + + totalAllowedDomains += allowListQueue.Count; + allowListQueues.Add(blockListUrl, allowListQueue); + } + } + + //load block list zone + Dictionary allowListZone = new Dictionary(totalAllowedDomains); + + foreach (KeyValuePair> allowListQueue in allowListQueues) + { + Queue queue = allowListQueue.Value; while (queue.Count > 0) { string domain = queue.Dequeue(); - allowedDomains.TryAdd(domain, null); + allowListZone.TryAdd(domain, null); } } - //read all block lists in a queue - Dictionary> blockListQueues = new Dictionary>(_blockListUrls.Count); - int totalDomains = 0; - - foreach (Uri blockListUrl in _blockListUrls) - { - if (!blockListQueues.ContainsKey(blockListUrl)) - { - Queue blockListQueue = ReadListFile(blockListUrl, false, allowedDomains); - totalDomains += blockListQueue.Count; - blockListQueues.Add(blockListUrl, blockListQueue); - } - } - - //load block list zone - Dictionary> blockListZone = new Dictionary>(totalDomains); + Dictionary> blockListZone = new Dictionary>(totalBlockedDomains); foreach (KeyValuePair> blockListQueue in blockListQueues) { @@ -327,9 +349,6 @@ namespace DnsServerCore.Dns.ZoneManagers { string domain = queue.Dequeue(); - if (IsZoneAllowed(allowedDomains, domain)) - continue; //domain is in allowed list so skip adding it to block list zone - if (!blockListZone.TryGetValue(domain, out List blockLists)) { blockLists = new List(2); @@ -340,16 +359,16 @@ namespace DnsServerCore.Dns.ZoneManagers } } - //set new blocked zone + //set new allowed and blocked zones + _allowListZone = allowListZone; _blockListZone = blockListZone; - LogManager log = _dnsServer.LogManager; - if (log != null) - log.Write("DNS Server block list zone was loaded successfully."); + _dnsServer.LogManager?.Write("DNS Server block list zone was loaded successfully."); } public void Flush() { + _allowListZone = new Dictionary(); _blockListZone = new Dictionary>(); } @@ -451,8 +470,19 @@ namespace DnsServerCore.Dns.ZoneManagers return downloaded || notModified; } + public bool IsAllowed(DnsDatagram request) + { + if (_allowListZone.Count < 1) + return false; + + return IsZoneAllowed(request.Question[0].Name); + } + public DnsDatagram Query(DnsDatagram request) { + if (_blockListZone.Count < 1) + return null; + DnsQuestionRecord question = request.Question[0]; List blockLists = IsZoneBlocked(question.Name, out string blockedDomain); @@ -572,6 +602,9 @@ namespace DnsServerCore.Dns.ZoneManagers public List BlockListUrls { get { return _blockListUrls; } } + public int TotalZonesAllowed + { get { return _allowListZone.Count; } } + public int TotalZonesBlocked { get { return _blockListZone.Count; } } From fa82a737e912189b11848e717881f1d932225497 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:10:42 +0530 Subject: [PATCH 09/24] DnsServer: Updated ProcessAuthoritativeQueryAsync() by moving query code into separate AuthoritativeQueryAsync() method. Updated ProcessCNAME(), ProcessANAME(), and CachePrefetchSamplingTimerCallback() to use AuthoritativeQueryAsync(). Updated "this-server" implementation to move checking code into RecursiveResolveAsync(). Code refactoring changes done. --- DnsServerCore/Dns/DnsServer.cs | 173 ++++++++++++++------------------- 1 file changed, 73 insertions(+), 100 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index d71f67f9..a0423ea5 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -619,6 +619,10 @@ namespace DnsServerCore.Dns _queryLog?.Write(remoteEP, protocol, request, response); _stats.QueueUpdate(request, remoteEP, protocol, response); } + catch (ObjectDisposedException) + { + //ignore + } catch (IOException) { //ignore IO exceptions @@ -1839,38 +1843,9 @@ namespace DnsServerCore.Dns private async Task ProcessAuthoritativeQueryAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, bool skipDnsAppAuthoritativeRequestHandlers) { - DnsDatagram response = null; - - if (!skipDnsAppAuthoritativeRequestHandlers) - { - foreach (IDnsAuthoritativeRequestHandler requestHandler in _dnsApplicationManager.DnsAuthoritativeRequestHandlers) - { - try - { - response = await requestHandler.ProcessRequestAsync(request, remoteEP, protocol, isRecursionAllowed); - if (response is not null) - { - if (response.Tag is null) - response.Tag = DnsServerResponseType.Authoritative; - - break; - } - } - catch (Exception ex) - { - _log?.Write(remoteEP, protocol, ex); - } - } - } - + DnsDatagram response = await AuthoritativeQueryAsync(request, remoteEP, protocol, isRecursionAllowed, skipDnsAppAuthoritativeRequestHandlers); if (response is null) - { - response = _authZoneManager.Query(request); - if (response is null) - return null; - - response.Tag = DnsServerResponseType.Authoritative; - } + return null; bool reprocessResponse; do @@ -1911,16 +1886,8 @@ namespace DnsServerCore.Dns break; case DnsResourceRecordType.FWD: - if ((response.Authority.Count == 1) && (firstAuthority.RDATA is DnsForwarderRecordData fwd) && fwd.Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) - { - //do conditional forwarding via "this-server" - return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, null, fwd.DnssecValidation, false, skipDnsAppAuthoritativeRequestHandlers); - } - else - { - //do conditional forwarding - return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, response.Authority, _dnssecValidation, false, skipDnsAppAuthoritativeRequestHandlers); - } + //do conditional forwarding + return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, response.Authority, _dnssecValidation, false, skipDnsAppAuthoritativeRequestHandlers); case DnsResourceRecordType.APP: response = await ProcessAPPAsync(request, remoteEP, response, isRecursionAllowed, protocol); @@ -1935,6 +1902,41 @@ namespace DnsServerCore.Dns return response; } + private async Task AuthoritativeQueryAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, bool skipDnsAppAuthoritativeRequestHandlers) + { + if (!skipDnsAppAuthoritativeRequestHandlers) + { + foreach (IDnsAuthoritativeRequestHandler requestHandler in _dnsApplicationManager.DnsAuthoritativeRequestHandlers) + { + try + { + DnsDatagram appResponse = await requestHandler.ProcessRequestAsync(request, remoteEP, protocol, isRecursionAllowed); + if (appResponse is not null) + { + if (appResponse.Tag is null) + appResponse.Tag = DnsServerResponseType.Authoritative; + + return appResponse; + } + } + catch (Exception ex) + { + _log?.Write(remoteEP, protocol, ex); + } + } + } + + DnsDatagram response = _authZoneManager.Query(request); + if (response is not null) + { + response.Tag = DnsServerResponseType.Authoritative; + + return response; + } + + return null; + } + private async Task ProcessAPPAsync(DnsDatagram request, IPEndPoint remoteEP, DnsDatagram response, bool isRecursionAllowed, DnsTransportProtocol protocol) { DnsResourceRecord appResourceRecord = response.Authority[0]; @@ -2059,7 +2061,7 @@ namespace DnsServerCore.Dns DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(cnameDomain, request.Question[0].Type, request.Question[0].Class) }, null, null, null, _udpPayloadSize, request.DnssecOk ? EDnsHeaderFlags.DNSSEC_OK : EDnsHeaderFlags.None, eDnsClientSubnetOption); //query authoritative zone first - newResponse = _authZoneManager.Query(newRequest); + newResponse = await AuthoritativeQueryAsync(newRequest, remoteEP, protocol, isRecursionAllowed, skipDnsAppAuthoritativeRequestHandlers); if (newResponse is null) { //not found in auth zone @@ -2096,19 +2098,9 @@ namespace DnsServerCore.Dns break; case DnsResourceRecordType.FWD: - if ((newResponse.Authority.Count == 1) && (firstAuthority.RDATA is DnsForwarderRecordData fwd) && fwd.Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) - { - //do conditional forwarding via "this-server" - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, null, fwd.DnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); - isAuthoritativeAnswer = false; - } - else - { - //do conditional forwarding - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, newResponse.Authority, _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); - isAuthoritativeAnswer = false; - } - + //do conditional forwarding + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, newResponse.Authority, _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); + isAuthoritativeAnswer = false; break; case DnsResourceRecordType.APP: @@ -2216,7 +2208,7 @@ namespace DnsServerCore.Dns 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) }, null, null, null, _udpPayloadSize, request.DnssecOk ? EDnsHeaderFlags.DNSSEC_OK : EDnsHeaderFlags.None, eDnsClientSubnetOption); //query authoritative zone first - DnsDatagram newResponse = _authZoneManager.Query(newRequest); + DnsDatagram newResponse = await AuthoritativeQueryAsync(newRequest, remoteEP, protocol, isRecursionAllowed, skipDnsAppAuthoritativeRequestHandlers); if (newResponse is null) { //not found in auth zone; do recursion @@ -2234,17 +2226,8 @@ namespace DnsServerCore.Dns break; case DnsResourceRecordType.FWD: - if ((newResponse.Authority.Count == 1) && (firstAuthority.RDATA is DnsForwarderRecordData fwd) && fwd.Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) - { - //do conditional forwarding via "this-server" - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, null, fwd.DnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); - } - else - { - //do conditional forwarding - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, newResponse.Authority, _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); - } - + //do conditional forwarding + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, newResponse.Authority, _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); break; case DnsResourceRecordType.APP: @@ -2366,27 +2349,17 @@ namespace DnsServerCore.Dns private DnsDatagram ProcessBlockedQuery(DnsDatagram request) { - DnsDatagram response = null; - - if (_blockedZoneManager.TotalZonesBlocked > 0) - response = _blockedZoneManager.Query(request); - + DnsDatagram response = _blockedZoneManager.Query(request); if (response is null) { //domain not blocked in blocked zone - if (_blockListZoneManager.TotalZonesBlocked > 0) - { - response = _blockListZoneManager.Query(request); //check in block list zone - if (response is not null) - { - //domain is blocked in block list zone - response.Tag = DnsServerResponseType.Blocked; - return response; - } - } + response = _blockListZoneManager.Query(request); //check in block list zone + if (response is null) + return null; //domain not blocked in block list zone - //domain not blocked in block list zone - return null; + //domain is blocked in block list zone + response.Tag = DnsServerResponseType.Blocked; + return response; } else { @@ -2505,7 +2478,7 @@ namespace DnsServerCore.Dns } else { - inAllowedZone = (_allowedZoneManager.TotalZonesAllowed > 0) && (_allowedZoneManager.Query(request) is not null); + inAllowedZone = _allowedZoneManager.IsAllowed(request) || _blockListZoneManager.IsAllowed(request); if (!inAllowedZone) { //check in blocked zone and block list zone @@ -2538,7 +2511,7 @@ namespace DnsServerCore.Dns DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord((record.RDATA as DnsCNAMERecordData).Domain, request.Question[0].Type, request.Question[0].Class) }); //check allowed zone - inAllowedZone = (_allowedZoneManager.TotalZonesAllowed > 0) && (_allowedZoneManager.Query(newRequest) is not null); + inAllowedZone = _allowedZoneManager.IsAllowed(newRequest) || _blockListZoneManager.IsAllowed(newRequest); if (inAllowedZone) break; //CNAME is in allowed zone @@ -2743,6 +2716,14 @@ namespace DnsServerCore.Dns else dnsCache = _dnsCache; + //check for this-server + if ((conditionalForwarders is not null) && (conditionalForwarders.Count == 1) && (conditionalForwarders[0].RDATA is DnsForwarderRecordData fwd) && fwd.Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) + { + //resolve directly with DNSSEC validation preference + conditionalForwarders = null; + dnssecValidation = fwd.DnssecValidation; + } + DnsDatagram response; if ((conditionalForwarders is not null) && (conditionalForwarders.Count > 0)) @@ -3414,7 +3395,7 @@ namespace DnsServerCore.Dns return false; //no need to refresh for this query } - private void CachePrefetchSamplingTimerCallback(object state) + private async void CachePrefetchSamplingTimerCallback(object state) { try { @@ -3439,7 +3420,8 @@ namespace DnsServerCore.Dns { reQueryAuthZone = false; - DnsDatagram response = _authZoneManager.Query(new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, false, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { eligibleQuerySample })); + DnsDatagram request = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, false, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { eligibleQuerySample }); + DnsDatagram response = await AuthoritativeQueryAsync(request, IPENDPOINT_ANY_0, DnsTransportProtocol.Tcp, true, false); if (response is null) { //zone not hosted; do refresh @@ -3469,16 +3451,7 @@ namespace DnsServerCore.Dns case DnsResourceRecordType.FWD: //zone is conditional forwarder refreshQuery = GetCacheRefreshNeededQuery(eligibleQuerySample, cacheRefreshTrigger); - - if ((response.Authority.Count == 1) && (firstAuthority.RDATA as DnsForwarderRecordData).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase)) - { - //do conditional forwarding via "this-server" - } - else - { - //do conditional forwarding - conditionalForwarders = response.Authority; - } + conditionalForwarders = response.Authority; //do conditional forwarding break; } } @@ -3951,8 +3924,8 @@ namespace DnsServerCore.Dns #endregion - udpListener.ReceiveBufferSize = 64 * 1024; - udpListener.SendBufferSize = 64 * 1024; + udpListener.ReceiveBufferSize = 512 * 1024; + udpListener.SendBufferSize = 512 * 1024; udpListener.Bind(localEP); From 7fb8e2730dd287c6d95ee38bf3b7351c4c96f881 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:12:06 +0530 Subject: [PATCH 10/24] DnsWebService: updated StartWebServiceAsync() to have safe mode to allow only http listening when required. Code refactoring changes done. --- DnsServerCore/DnsWebService.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index 98079fef..f1389005 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -203,7 +203,7 @@ namespace DnsServerCore try { _webServiceLocalAddresses = DnsServer.GetValidKestralLocalAddresses(_webServiceLocalAddresses); - await StartWebServiceAsync(); + await StartWebServiceAsync(false); } catch (Exception ex) { @@ -213,7 +213,7 @@ namespace DnsServerCore try { _webServiceLocalAddresses = new IPAddress[] { IPAddress.Any }; - await StartWebServiceAsync(); + await StartWebServiceAsync(false); } catch (Exception ex2) { @@ -221,12 +221,12 @@ namespace DnsServerCore _log.Write("Attempting to start Web Service on loopback (127.0.0.1) fallback address..."); _webServiceLocalAddresses = new IPAddress[] { IPAddress.Loopback }; - await StartWebServiceAsync(); + await StartWebServiceAsync(true); } } } - private async Task StartWebServiceAsync() + private async Task StartWebServiceAsync(bool safeMode) { WebApplicationBuilder builder = WebApplication.CreateBuilder(); @@ -249,7 +249,7 @@ namespace DnsServerCore serverOptions.Listen(webServiceLocalAddress, _webServiceHttpPort); //https - if (_webServiceEnableTls && (_webServiceTlsCertificate is not null)) + if (!safeMode && _webServiceEnableTls && (_webServiceTlsCertificate is not null)) { serverOptions.ConfigureHttpsDefaults(delegate (HttpsConnectionAdapterOptions configureOptions) { @@ -277,7 +277,7 @@ namespace DnsServerCore _webService = builder.Build(); - if (_webServiceHttpToTlsRedirect) + if (_webServiceHttpToTlsRedirect && !safeMode && _webServiceEnableTls && (_webServiceTlsCertificate is not null)) _webService.UseHttpsRedirection(); _webService.UseDefaultFiles(); @@ -300,7 +300,7 @@ namespace DnsServerCore { _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Http", "Web Service was bound successfully."); - if (_webServiceEnableTls && (_webServiceTlsCertificate is not null)) + if (!safeMode && _webServiceEnableTls && (_webServiceTlsCertificate is not null)) _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Https", "Web Service was bound successfully."); } } @@ -312,7 +312,7 @@ namespace DnsServerCore { _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Http", "Web Service failed to bind."); - if (_webServiceEnableTls && (_webServiceTlsCertificate is not null)) + if (!safeMode && _webServiceEnableTls && (_webServiceTlsCertificate is not null)) _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Https", "Web Service failed to bind."); } @@ -832,7 +832,7 @@ namespace DnsServerCore foreach (string strBlockListUrl in strBlockListUrlList) { - if (strBlockListUrl.StartsWith("!")) + if (strBlockListUrl.StartsWith('!')) { Uri allowListUrl = new Uri(strBlockListUrl.Substring(1)); @@ -1288,7 +1288,7 @@ namespace DnsServerCore { string listUrl = bR.ReadShortString(); - if (listUrl.StartsWith("!")) + if (listUrl.StartsWith('!')) _dnsServer.BlockListZoneManager.AllowListUrls.Add(new Uri(listUrl.Substring(1))); else _dnsServer.BlockListZoneManager.BlockListUrls.Add(new Uri(listUrl)); @@ -1710,7 +1710,7 @@ namespace DnsServerCore { string listUrl = bR.ReadShortString(); - if (listUrl.StartsWith("!")) + if (listUrl.StartsWith('!')) _dnsServer.BlockListZoneManager.AllowListUrls.Add(new Uri(listUrl.Substring(1))); else _dnsServer.BlockListZoneManager.BlockListUrls.Add(new Uri(listUrl)); From 2c14da3c2e9bbab5ab8421a3bcfb3fbaa4726027 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:14:50 +0530 Subject: [PATCH 11/24] WebServiceDashboardApi: updated dashboard api to add allow list zones count. --- DnsServerCore/WebServiceDashboardApi.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DnsServerCore/WebServiceDashboardApi.cs b/DnsServerCore/WebServiceDashboardApi.cs index f15ab21d..4c9c22ee 100644 --- a/DnsServerCore/WebServiceDashboardApi.cs +++ b/DnsServerCore/WebServiceDashboardApi.cs @@ -237,6 +237,7 @@ namespace DnsServerCore jsonWriter.WriteNumber("cachedEntries", _dnsWebService.DnsServer.CacheZoneManager.TotalEntries); jsonWriter.WriteNumber("allowedZones", _dnsWebService.DnsServer.AllowedZoneManager.TotalZonesAllowed); jsonWriter.WriteNumber("blockedZones", _dnsWebService.DnsServer.BlockedZoneManager.TotalZonesBlocked); + jsonWriter.WriteNumber("allowListZones", _dnsWebService.DnsServer.BlockListZoneManager.TotalZonesAllowed); jsonWriter.WriteNumber("blockListZones", _dnsWebService.DnsServer.BlockListZoneManager.TotalZonesBlocked); jsonWriter.WriteEndObject(); From 22d480b4ddec90321b796098a79ea098fbd04104 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:15:03 +0530 Subject: [PATCH 12/24] code refactoring changes --- DnsServerCore/WebServiceSettingsApi.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/WebServiceSettingsApi.cs b/DnsServerCore/WebServiceSettingsApi.cs index 22ff70fb..cebbc06c 100644 --- a/DnsServerCore/WebServiceSettingsApi.cs +++ b/DnsServerCore/WebServiceSettingsApi.cs @@ -1033,7 +1033,7 @@ namespace DnsServerCore { foreach (string strBlockListUrl in blockListUrlList) { - if (strBlockListUrl.StartsWith("!")) + if (strBlockListUrl.StartsWith('!')) { string strAllowListUrl = strBlockListUrl.Substring(1); @@ -1062,7 +1062,7 @@ namespace DnsServerCore foreach (string strBlockListUrl in blockListUrlList) { - if (strBlockListUrl.StartsWith("!")) + if (strBlockListUrl.StartsWith('!')) { Uri allowListUrl = new Uri(strBlockListUrl.Substring(1)); From 1fa8fdf95def7ec345bc755b7c0df3936f61e4ab Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:16:26 +0530 Subject: [PATCH 13/24] webapp: updated index to add blog post links. Updated dashboard to add allow list stats. Other minor changes done. --- DnsServerCore/www/index.html | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 596c5c0d..e7ad3453 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -223,27 +223,32 @@
10
-
Hosted Zones
+
Zones
10
-
Cached Entries
+
Cache
10
-
Allowed Zones
+
Allowed
10
-
Blocked Zones
+
Blocked
+
+ +
+
10
+
Allow List
10
-
Block List Zones
+
Block List
@@ -935,7 +940,7 @@
DNS Server will validate all responses from name servers or forwarders when this option is enabled.
@@ -1167,6 +1172,8 @@

Use the following openssl command to convert your TLS certificate that is in PEM format to PKCS #12 certificate (.pfx) format:

openssl pkcs12 -export -out "example.com.pfx" -inkey "privkey.pem" -in "cert.pem" -certfile "chain.pem"
+ + @@ -1260,7 +1267,7 @@

Note! These optional DNS server protocol changes will be automatically applied and so you do not need to manually restart the main service. The DNS-over-TLS, DNS-over-QUIC, and DNS-over-HTTPS protocols will be enabled only when a TLS certificate is configured.

These optional DNS server protocols are used to host these as a service. You do not need to enable these optional protocols to use them with Forwarders or Conditional Forwarder Zones.

-

For DNS-over-HTTP, use http://localhost:8053/dns-query with a TLS terminating reverse proxy like nginx. For DNS-over-TLS, use tls-certificate-domain:853, for DNS-over-QUIC, use tls-certificate-domain:853, and for DNS-over-HTTPS use https://tls-certificate-domain/dns-query to configure supported DNS clients.

+

For DNS-over-HTTP, use http://localhost:8053/dns-query with a TLS terminating reverse proxy like nginx. For DNS-over-TLS, use tls-certificate-domain:853, for DNS-over-QUIC, use tls-certificate-domain:853, and for DNS-over-HTTPS use https://tls-certificate-domain/dns-query to configure supported DNS clients.

When using a reverse proxy with the DNS-over-HTTP service, you need to add X-Real-IP header to the proxy request with the IP address of the client to allow the DNS server to know the real IP address of the client originating the request. For example, if you are using nginx as the reverse proxy, you can add proxy_set_header X-Real-IP $remote_addr; to make it work.

DNS-over-QUIC protocol support is not available on all platforms. On Windows, it is available only on Windows 11 (build 22000 or later) and Windows Server 2022. On Linux, it requires libmsquic and openssl v1.1.1 to be installed.

Use the following openssl command to convert your TLS certificate that is in PEM format to PKCS #12 certificate (.pfx) format:

@@ -1268,6 +1275,7 @@
+ @@ -1446,7 +1454,7 @@ (default 10000; set 0 to disable) -
The maximum number of entries that the cache can store. A relevant value should be configured by monitoring the Cached Entries value on Dashboard and the server's memory usage to limit the amount of RAM used by the DNS server. A cache entry is a complete Resource Record Set (RR Set) which is a group of records with the same type for a given domain name. When a value is configured, the DNS server will trigger a clean up operation every few minutes and remove least recently used entries to maintain the maximum allowed entries in cache.
+
The maximum number of entries that the cache can store. A relevant value should be configured by monitoring the Cache entries value on Dashboard and the server's memory usage to limit the amount of RAM used by the DNS server. A cache entry is a complete Resource Record Set (RR Set) which is a group of records with the same type for a given domain name. When a value is configured, the DNS server will trigger a clean up operation every few minutes and remove least recently used entries to maintain the maximum allowed entries in cache.
@@ -1630,7 +1638,7 @@

Enter block list URL one below another in the above text field or use the Quick Add list to add known block list URLs.

-

Add ! character at the start of an URL to make it an allow list URL. Domain names in such an allow list URL are prevented from being added to the block list zone.

+

Add ! character at the start of an URL to make it an allow list URL. This option must not be used with allow lists that use Adblock plus format.

@@ -1847,6 +1855,7 @@
Forwarders are DNS servers which this DNS Server should use to resolve recursive queries. If no forwarders are configured then this DNS server will use preconfigured ROOT SERVERS to perform recursive resolution.
+
From 50be5d0b095e2c909ead4aadce341b1f0dae186f Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:16:51 +0530 Subject: [PATCH 14/24] updated main.css for dashboard zone stats changes. --- DnsServerCore/www/css/main.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DnsServerCore/www/css/main.css b/DnsServerCore/www/css/main.css index ddcfc970..14451dcd 100644 --- a/DnsServerCore/www/css/main.css +++ b/DnsServerCore/www/css/main.css @@ -289,16 +289,16 @@ th a { } .zone-stats-panel .stats-item { - width: 19.25%; + width: 16%; float: left; padding: 6px 4px; - margin-right: 0.75%; + margin-right: 0.65%; background-color: rgba(51, 122, 183, 0.7); color: #ffffff; } .zone-stats-panel .stats-item .number { - font-size: 15px; + font-size: 14px; font-weight: bold; padding: 6px 0; } From b73d2e2ffc2bc0702a2bc1bc3d028c1e7f19c865 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:17:41 +0530 Subject: [PATCH 15/24] dhcp.js: updated saveDhcpScope() to use POST method to prevent long url error. --- DnsServerCore/www/js/dhcp.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/www/js/dhcp.js b/DnsServerCore/www/js/dhcp.js index a7313b45..45046a7c 100644 --- a/DnsServerCore/www/js/dhcp.js +++ b/DnsServerCore/www/js/dhcp.js @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2022 Shreyas Zare (shreyas@technitium.com) +Copyright (C) 2023 Shreyas Zare (shreyas@technitium.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -516,11 +516,14 @@ function saveDhcpScope() { var btn = $("#btnSaveDhcpScope").button('loading'); HTTPRequest({ - url: "/api/dhcp/scopes/set?token=" + sessionData.token + "&name=" + encodeURIComponent(name) + (newName == null ? "" : "&newName=" + encodeURIComponent(newName)) + "&startingAddress=" + encodeURIComponent(startingAddress) + "&endingAddress=" + encodeURIComponent(endingAddress) + "&subnetMask=" + encodeURIComponent(subnetMask) + + url: "/api/dhcp/scopes/set", + method: "POST", + data: "token=" + sessionData.token + "&name=" + encodeURIComponent(name) + (newName == null ? "" : "&newName=" + encodeURIComponent(newName)) + "&startingAddress=" + encodeURIComponent(startingAddress) + "&endingAddress=" + encodeURIComponent(endingAddress) + "&subnetMask=" + encodeURIComponent(subnetMask) + "&leaseTimeDays=" + leaseTimeDays + "&leaseTimeHours=" + leaseTimeHours + "&leaseTimeMinutes=" + leaseTimeMinutes + "&offerDelayTime=" + offerDelayTime + "&pingCheckEnabled=" + pingCheckEnabled + "&pingCheckTimeout=" + pingCheckTimeout + "&pingCheckRetries=" + pingCheckRetries + "&domainName=" + encodeURIComponent(domainName) + "&domainSearchList=" + encodeURIComponent(domainSearchList) + "&dnsUpdates=" + dnsUpdates + "&dnsTtl=" + dnsTtl + "&serverAddress=" + encodeURIComponent(serverAddress) + "&serverHostName=" + encodeURIComponent(serverHostName) + "&bootFileName=" + encodeURIComponent(bootFileName) + "&routerAddress=" + encodeURIComponent(routerAddress) + "&useThisDnsServer=" + useThisDnsServer + (useThisDnsServer ? "" : "&dnsServers=" + encodeURIComponent(dnsServers)) + "&winsServers=" + encodeURIComponent(winsServers) + "&ntpServers=" + encodeURIComponent(ntpServers) + "&ntpServerDomainNames=" + encodeURIComponent(ntpServerDomainNames) + "&staticRoutes=" + encodeURIComponent(staticRoutes) + "&vendorInfo=" + encodeURIComponent(vendorInfo) + "&capwapAcIpAddresses=" + encodeURIComponent(capwapAcIpAddresses) + "&tftpServerAddresses=" + encodeURIComponent(tftpServerAddresses) + "&genericOptions=" + encodeURIComponent(genericOptions) + "&exclusions=" + encodeURIComponent(exclusions) + "&reservedLeases=" + encodeURIComponent(reservedLeases) + "&allowOnlyReservedLeases=" + allowOnlyReservedLeases + "&blockLocallyAdministeredMacAddresses=" + blockLocallyAdministeredMacAddresses, + processData: false, success: function (responseJSON) { refreshDhcpScopes(); btn.button('reset'); From b8813fe4324d15c1984f5db95749010be391c02b Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:19:33 +0530 Subject: [PATCH 16/24] main.js: updated dashboard api changes. Updated settings code to show DoH url too in info. --- DnsServerCore/www/js/main.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index 6523349f..57f31b3f 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.js @@ -942,9 +942,10 @@ function loadDnsSettings() { else $("#txtDnsTlsCertificatePassword").val(responseJSON.response.dnsTlsCertificatePassword); - $("#lblDoHHost").text(window.location.hostname + ":" + responseJSON.response.dnsOverHttpPort); + $("#lblDoHHost").text(window.location.hostname + (responseJSON.response.dnsOverHttpPort == 80 ? "" : ":" + responseJSON.response.dnsOverHttpPort)); $("#lblDoTHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverTlsPort); $("#lblDoQHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverQuicPort); + $("#lblDoHsHost").text("tls-certificate-domain" + (responseJSON.response.dnsOverHttpsPort == 443 ? "" : ":" + responseJSON.response.dnsOverHttpsPort)); //tsig $("#tableTsigKeys").html(""); @@ -1651,9 +1652,10 @@ function saveDnsSettings() { $("#txtWebServiceTlsCertificatePassword").prop("disabled", !responseJSON.response.webServiceEnableTls); //optional protocols - $("#lblDoHHost").text(window.location.hostname + ":" + responseJSON.response.dnsOverHttpPort); + $("#lblDoHHost").text(window.location.hostname + (responseJSON.response.dnsOverHttpPort == 80 ? "" : ":" + responseJSON.response.dnsOverHttpPort)); $("#lblDoTHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverTlsPort); $("#lblDoQHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverQuicPort); + $("#lblDoHsHost").text("tls-certificate-domain" + (responseJSON.response.dnsOverHttpsPort == 443 ? "" : ":" + responseJSON.response.dnsOverHttpsPort)); //reload tsig keys $("#tableTsigKeys").html(""); @@ -1992,6 +1994,7 @@ function refreshDashboard(hideLoader) { $("#divDashboardStatsCachedEntries").text(responseJSON.response.stats.cachedEntries.toLocaleString()); $("#divDashboardStatsAllowedZones").text(responseJSON.response.stats.allowedZones.toLocaleString()); $("#divDashboardStatsBlockedZones").text(responseJSON.response.stats.blockedZones.toLocaleString()); + $("#divDashboardStatsAllowListZones").text(responseJSON.response.stats.allowListZones.toLocaleString()); $("#divDashboardStatsBlockListZones").text(responseJSON.response.stats.blockListZones.toLocaleString()); if (responseJSON.response.stats.totalQueries > 0) { From e81d1162e88752af7d5a82f208bf0b2133a11240 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 13:19:59 +0530 Subject: [PATCH 17/24] updated apidocs --- APIDOCS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/APIDOCS.md b/APIDOCS.md index 575542f2..e5958e5f 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -494,8 +494,12 @@ RESPONSE: "totalCached": 228, "totalBlocked": 111, "totalClients": 831, + "zones": 5, + "cachedEntries": 28, "allowedZones": 6, - "blockedZones": 1136182 + "blockedZones": 10, + "allowListZones": 0, + "blockListZones": 1136182 }, "mainChartData": { "labelFormat": "HH:mm", From c975caa76df007f788f1fc274693d4bc91376762 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 17:07:12 +0530 Subject: [PATCH 18/24] updated app config default values. --- Apps/NxDomainApp/dnsApp.config | 4 +++- Apps/QueryLogsSqliteApp/dnsApp.config | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Apps/NxDomainApp/dnsApp.config b/Apps/NxDomainApp/dnsApp.config index 1cbf6609..aaaacc26 100644 --- a/Apps/NxDomainApp/dnsApp.config +++ b/Apps/NxDomainApp/dnsApp.config @@ -2,6 +2,8 @@ "enableBlocking": true, "allowTxtBlockingReport": true, "blocked": [ - "use-application-dns.net" + "use-application-dns.net", + "mask.icloud.com", + "mask-h2.icloud.com" ] } diff --git a/Apps/QueryLogsSqliteApp/dnsApp.config b/Apps/QueryLogsSqliteApp/dnsApp.config index 73323d35..743c53f7 100644 --- a/Apps/QueryLogsSqliteApp/dnsApp.config +++ b/Apps/QueryLogsSqliteApp/dnsApp.config @@ -1,6 +1,6 @@ { "enableLogging": true, - "maxLogDays": 0, + "maxLogDays": 7, "sqliteDbPath": "querylogs.db", "connectionString": "Data Source='{sqliteDbPath}'; Cache=Shared;" } From 4a81bc765616f44526511856ae0072ead3da6627 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 17:07:36 +0530 Subject: [PATCH 19/24] app assembly version updated for release. --- Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj | 2 +- Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj b/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj index 6cd8b4ab..8b246742 100644 --- a/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj +++ b/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 5.0 + 5.0.1 Technitium Technitium DNS Server Shreyas Zare diff --git a/Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj b/Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj index c923bc47..ffae889c 100644 --- a/Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj +++ b/Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 1.0 + 1.0.1 Technitium Technitium DNS Server Shreyas Zare From e182571e416cb88503f90020a090383e1af0f3bb Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 17:08:01 +0530 Subject: [PATCH 20/24] inno: app version updated to v11.0.1. --- DnsServerWindowsSetup/DnsServerSetup.iss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DnsServerWindowsSetup/DnsServerSetup.iss b/DnsServerWindowsSetup/DnsServerSetup.iss index b4115872..aa151a11 100644 --- a/DnsServerWindowsSetup/DnsServerSetup.iss +++ b/DnsServerWindowsSetup/DnsServerSetup.iss @@ -2,7 +2,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "Technitium DNS Server" -#define MyAppVersion "11.0" +#define MyAppVersion "11.0.1" #define MyAppPublisher "Technitium" #define MyAppURL "https://technitium.com/dns/" #define MyAppExeName "DnsServerSystemTrayApp.exe" From 7422262640222daa32860f952706a72c74ad8d12 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 17:08:39 +0530 Subject: [PATCH 21/24] updated Dockerfile to support DNS-over-QUIC and graceful shutdown. --- Dockerfile | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 59d7695c..6f6ba4dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,14 @@ LABEL email="support@technitium.com" LABEL project_url="https://technitium.com/dns/" LABEL github_url="https://github.com/TechnitiumSoftware/DnsServer" -WORKDIR /etc/dns/ +WORKDIR /opt/technitium/dns/ + +RUN apt update; apt install curl -y; \ +curl https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb --output packages-microsoft-prod.deb; \ +dpkg -i packages-microsoft-prod.deb; \ +rm packages-microsoft-prod.deb + +RUN apt update; apt install libmsquic -y; apt clean -y; COPY ./DnsServerApp/bin/Release/publish/ . @@ -21,6 +28,9 @@ EXPOSE 80/tcp EXPOSE 8053/tcp EXPOSE 67/udp -VOLUME ["/etc/dns/config"] +VOLUME ["/etc/dns"] -CMD ["/usr/bin/dotnet", "/etc/dns/DnsServerApp.dll"] +STOPSIGNAL SIGINT + +ENTRYPOINT ["/usr/bin/dotnet", "/opt/technitium/dns/DnsServerApp.dll"] +CMD ["/etc/dns"] From 0c31a0a03dfebb923970cd13ef0386e3d6efdbc6 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 17:09:19 +0530 Subject: [PATCH 22/24] docker-compose.yml: updated file to use new config folder location. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 036cf532..378a488d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,7 +34,7 @@ services: # - DNS_SERVER_FORWARDER_PROTOCOL=Tcp #Forwarder protocol options: Udp, Tcp, Tls, Https, HttpsJson. # - DNS_SERVER_LOG_USING_LOCAL_TIME=true #Enable this option to use local time instead of UTC for logging. volumes: - - config:/etc/dns/config + - config:/etc/dns restart: unless-stopped sysctls: - net.ipv4.ip_local_port_range=1024 65000 From cabd87a7d287b98cc54e24698a1750edc7029dd0 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 17:09:54 +0530 Subject: [PATCH 23/24] assembly version updated to 11.0.1 for release. --- DnsServerApp/DnsServerApp.csproj | 2 +- DnsServerCore/DnsServerCore.csproj | 2 +- DnsServerWindowsService/DnsServerWindowsService.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DnsServerApp/DnsServerApp.csproj b/DnsServerApp/DnsServerApp.csproj index 827cb031..13079d49 100644 --- a/DnsServerApp/DnsServerApp.csproj +++ b/DnsServerApp/DnsServerApp.csproj @@ -6,7 +6,7 @@ Exe net7.0 logo2.ico - 11.0 + 11.0.1 Technitium Technitium DNS Server Shreyas Zare diff --git a/DnsServerCore/DnsServerCore.csproj b/DnsServerCore/DnsServerCore.csproj index 6e8ebc08..b0c7fe05 100644 --- a/DnsServerCore/DnsServerCore.csproj +++ b/DnsServerCore/DnsServerCore.csproj @@ -12,7 +12,7 @@ DnsServer - 11.0 + 11.0.1 diff --git a/DnsServerWindowsService/DnsServerWindowsService.csproj b/DnsServerWindowsService/DnsServerWindowsService.csproj index c62ea5c5..c894b3f6 100644 --- a/DnsServerWindowsService/DnsServerWindowsService.csproj +++ b/DnsServerWindowsService/DnsServerWindowsService.csproj @@ -8,7 +8,7 @@ DnsServerWindowsService DnsService logo2.ico - 11.0 + 11.0.1 Shreyas Zare Technitium Technitium DNS Server From 43575f1a3b7126dfcdd90b45792e4b32dbf59eab Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 25 Feb 2023 17:12:05 +0530 Subject: [PATCH 24/24] updated changelog for v11.0.1 release. --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cff8c749..10826b25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Technitium DNS Server Change Log +## Version 11.0.1 +Release Date: 25 February 2023 + +- Changed allow list implementation to handle them separately and show allow list count on Dashboard. +- Fixed bug in conditional forwarder zone for root zone that caused the DNS server to return RCODE=ServerFailure. +- Fixed issues with DNS server's App request query handling sequence to fix issues with Advanced Forwarding app. +- Fixed issues with block list parser to detect in-line comments. +- Fixed issue of "URI too long" in save DHCP scope action. +- Updated Linux install script to use new install path in `/opt` and new config path `/etc/dns` for new installations. +- Updated Docker container to use new volume path `/etc/dns` for config. +- Updated Docker container to correctly handle container stop event to gracefully shutdown the DNS server. +- Updated Docker container to include `libmsquic` to allow QUIC support. +- Multiple other minor bug fixes and improvements. + ## Version 11.0 Release Date: 18 February 2023