From ca579cf09698ffac29bacc8df3293c117fd9b8f8 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 17 Dec 2022 13:22:53 +0530 Subject: [PATCH 001/191] webapp: removed twitter link from about us. --- DnsServerCore/www/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 6031ba5f..79485261 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -2497,7 +2497,6 @@

For support, send an email to support@technitium.com.

Follow @technitium@mastodon.social on Mastodon.
- Follow @technitium on Twitter.
Checkout Technitium Blog.

From 2a8ea3eea52534dc5bddb5b359a7af19ad5f3928 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 17 Dec 2022 13:53:29 +0530 Subject: [PATCH 002/191] AdvancedBlocking: removed newtonsoft --- Apps/AdvancedBlockingApp/App.cs | 111 ++++++++++++-------------------- 1 file changed, 40 insertions(+), 71 deletions(-) diff --git a/Apps/AdvancedBlockingApp/App.cs b/Apps/AdvancedBlockingApp/App.cs index 1cd2e73d..7d38b34e 100644 --- a/Apps/AdvancedBlockingApp/App.cs +++ b/Apps/AdvancedBlockingApp/App.cs @@ -18,7 +18,6 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -27,9 +26,11 @@ using System.Net.Http; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; +using System.Text.Json; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -252,29 +253,21 @@ namespace AdvancedBlocking _soaRecord = new DnsSOARecordData(_dnsServer.ServerDomain, "hostadmin@" + _dnsServer.ServerDomain, 1, 14400, 3600, 604800, 60); _nsRecord = new DnsNSRecordData(_dnsServer.ServerDomain); - dynamic jsonConfig = JsonConvert.DeserializeObject(config); + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; - _enableBlocking = jsonConfig.enableBlocking.Value; - _blockListUrlUpdateIntervalHours = Convert.ToInt32(jsonConfig.blockListUrlUpdateIntervalHours.Value); + _enableBlocking = jsonConfig.GetProperty("enableBlocking").GetBoolean(); + _blockListUrlUpdateIntervalHours = jsonConfig.GetProperty("blockListUrlUpdateIntervalHours").GetInt32(); + + _networkGroupMap = jsonConfig.ReadObjectAsMap("networkGroupMap", delegate (string network, JsonElement jsonGroup) + { + if (!NetworkAddress.TryParse(network, out NetworkAddress networkAddress)) + throw new InvalidOperationException("Network group map contains an invalid network address: " + network); + + return new Tuple(networkAddress, jsonGroup.GetString()); + }); { - Dictionary networkGroupMap = new Dictionary(); - - foreach (dynamic jsonProperty in jsonConfig.networkGroupMap) - { - string network = jsonProperty.Name; - string group = jsonProperty.Value; - - if (NetworkAddress.TryParse(network, out NetworkAddress networkAddress)) - networkGroupMap.Add(networkAddress, group); - } - - _networkGroupMap = networkGroupMap; - } - - { - Dictionary groups = new Dictionary(); - Dictionary allAllowListZones = new Dictionary(0); Dictionary allBlockListZones = new Dictionary(0); @@ -283,11 +276,9 @@ namespace AdvancedBlocking Dictionary allAdBlockListZones = new Dictionary(0); - foreach (dynamic jsonGroup in jsonConfig.groups) + _groups = jsonConfig.ReadArrayAsMap("groups", delegate (JsonElement jsonGroup) { Group group = new Group(this, jsonGroup); - if (!groups.TryAdd(group.Name, group)) - continue; foreach (Uri allowListUrl in group.AllowListUrls) { @@ -343,9 +334,9 @@ namespace AdvancedBlocking allAdBlockListZones.Add(adblockListUrl, new AdBlockList(_dnsServer, adblockListUrl)); } } - } - _groups = groups; + return new Tuple(group.Name, group); + }); _allAllowListZones = allAllowListZones; _allBlockListZones = allBlockListZones; @@ -600,22 +591,23 @@ namespace AdvancedBlocking #region constructor - public Group(App app, dynamic jsonGroup) + public Group(App app, JsonElement jsonGroup) { _app = app; - _name = jsonGroup.name.Value; - _enableBlocking = jsonGroup.enableBlocking.Value; - _allowTxtBlockingReport = jsonGroup.allowTxtBlockingReport.Value; - _blockAsNxDomain = jsonGroup.blockAsNxDomain.Value; + _name = jsonGroup.GetProperty("name").GetString(); + _enableBlocking = jsonGroup.GetProperty("enableBlocking").GetBoolean(); + _allowTxtBlockingReport = jsonGroup.GetProperty("allowTxtBlockingReport").GetBoolean(); + _blockAsNxDomain = jsonGroup.GetProperty("blockAsNxDomain").GetBoolean(); { + JsonElement jsonBlockingAddresses = jsonGroup.GetProperty("blockingAddresses"); List aRecords = new List(); List aaaaRecords = new List(); - foreach (dynamic jsonBlockingAddress in jsonGroup.blockingAddresses) + foreach (JsonElement jsonBlockingAddress in jsonBlockingAddresses.EnumerateArray()) { - string strAddress = jsonBlockingAddress.Value; + string strAddress = jsonBlockingAddress.GetString(); if (IPAddress.TryParse(strAddress, out IPAddress address)) { @@ -636,59 +628,36 @@ namespace AdvancedBlocking _aaaaRecords = aaaaRecords; } - _allowed = ReadJsonDomainArray(jsonGroup.allowed); - _blocked = ReadJsonDomainArray(jsonGroup.blocked); - _allowListUrls = ReadJsonUrlArray(jsonGroup.allowListUrls); - _blockListUrls = ReadJsonUrlArray(jsonGroup.blockListUrls); + _allowed = jsonGroup.ReadArrayAsMap("allowed", GetMapEntry); + _blocked = jsonGroup.ReadArrayAsMap("blocked", GetMapEntry); + _allowListUrls = jsonGroup.ReadArray("allowListUrls", GetUriEntry); + _blockListUrls = jsonGroup.ReadArray("blockListUrls", GetUriEntry); - _allowedRegex = ReadJsonRegexArray(jsonGroup.allowedRegex); - _blockedRegex = ReadJsonRegexArray(jsonGroup.blockedRegex); - _regexAllowListUrls = ReadJsonUrlArray(jsonGroup.regexAllowListUrls); - _regexBlockListUrls = ReadJsonUrlArray(jsonGroup.regexBlockListUrls); + _allowedRegex = jsonGroup.ReadArray("allowedRegex", GetRegexEntry); + _blockedRegex = jsonGroup.ReadArray("blockedRegex", GetRegexEntry); + _regexAllowListUrls = jsonGroup.ReadArray("regexAllowListUrls", GetUriEntry); + _regexBlockListUrls = jsonGroup.ReadArray("regexBlockListUrls", GetUriEntry); - _adblockListUrls = ReadJsonUrlArray(jsonGroup.adblockListUrls); + _adblockListUrls = jsonGroup.ReadArray("adblockListUrls", GetUriEntry); } #endregion #region private - private static IReadOnlyDictionary ReadJsonDomainArray(dynamic jsonDomainArray) + private static Tuple GetMapEntry(JsonElement jsonElement) { - Dictionary domains = new Dictionary(jsonDomainArray.Count); - - foreach (dynamic jsonDomain in jsonDomainArray) - domains.TryAdd(jsonDomain.Value, null); - - return domains; + return new Tuple(jsonElement.GetString(), null); } - private static IReadOnlyList ReadJsonRegexArray(dynamic jsonRegexArray) + private static Uri GetUriEntry(string uriString) { - List regices = new List(jsonRegexArray.Count); - - foreach (dynamic jsonRegex in jsonRegexArray) - { - string regexPattern = jsonRegex.Value; - - regices.Add(new Regex(regexPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled)); - } - - return regices; + return new Uri(uriString); } - private static IReadOnlyList ReadJsonUrlArray(dynamic jsonUrlArray) + private static Regex GetRegexEntry(string pattern) { - List urls = new List(jsonUrlArray.Count); - - foreach (dynamic jsonUrl in jsonUrlArray) - { - string strUrl = jsonUrl.Value; - - urls.Add(new Uri(strUrl)); - } - - return urls; + return new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled); } #endregion From 4412f031329abd4260644283a1e1422662728648 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 17 Dec 2022 13:58:47 +0530 Subject: [PATCH 003/191] BlockPage: removed newtonsoft. --- Apps/BlockPageApp/App.cs | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/Apps/BlockPageApp/App.cs b/Apps/BlockPageApp/App.cs index cf4c8581..5d2099d4 100644 --- a/Apps/BlockPageApp/App.cs +++ b/Apps/BlockPageApp/App.cs @@ -18,7 +18,6 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -28,6 +27,7 @@ using System.Net.Sockets; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using TechnitiumLibrary; @@ -479,35 +479,29 @@ namespace BlockPage { _dnsServer = dnsServer; - dynamic jsonConfig = JsonConvert.DeserializeObject(config); + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; - { - List webServerLocalAddresses = new List(); + _webServerLocalAddresses = jsonConfig.ReadArray("webServerLocalAddresses", IPAddress.Parse); - foreach (dynamic jsonAddress in jsonConfig.webServerLocalAddresses) - webServerLocalAddresses.Add(IPAddress.Parse(jsonAddress.Value)); - - _webServerLocalAddresses = webServerLocalAddresses; - } - - if (jsonConfig.webServerUseSelfSignedTlsCertificate is null) - _webServerUseSelfSignedTlsCertificate = true; + if (jsonConfig.TryGetProperty("webServerUseSelfSignedTlsCertificate", out JsonElement jsonWebServerUseSelfSignedTlsCertificate)) + _webServerUseSelfSignedTlsCertificate = jsonWebServerUseSelfSignedTlsCertificate.GetBoolean(); else - _webServerUseSelfSignedTlsCertificate = jsonConfig.webServerUseSelfSignedTlsCertificate.Value; + _webServerUseSelfSignedTlsCertificate = true; - _webServerTlsCertificateFilePath = jsonConfig.webServerTlsCertificateFilePath.Value; - _webServerTlsCertificatePassword = jsonConfig.webServerTlsCertificatePassword.Value; + _webServerTlsCertificateFilePath = jsonConfig.GetProperty("webServerTlsCertificateFilePath").GetString(); + _webServerTlsCertificatePassword = jsonConfig.GetProperty("webServerTlsCertificatePassword").GetString(); - _webServerRootPath = jsonConfig.webServerRootPath.Value; + _webServerRootPath = jsonConfig.GetProperty("webServerRootPath").GetString(); if (!Path.IsPathRooted(_webServerRootPath)) _webServerRootPath = Path.Combine(_dnsServer.ApplicationFolder, _webServerRootPath); - _serveBlockPageFromWebServerRoot = jsonConfig.serveBlockPageFromWebServerRoot.Value; + _serveBlockPageFromWebServerRoot = jsonConfig.GetProperty("serveBlockPageFromWebServerRoot").GetBoolean(); - string blockPageTitle = jsonConfig.blockPageTitle.Value; - string blockPageHeading = jsonConfig.blockPageHeading.Value; - string blockPageMessage = jsonConfig.blockPageMessage.Value; + string blockPageTitle = jsonConfig.GetProperty("blockPageTitle").GetString(); + string blockPageHeading = jsonConfig.GetProperty("blockPageHeading").GetString(); + string blockPageMessage = jsonConfig.GetProperty("blockPageMessage").GetString(); string blockPageContent = @" @@ -570,7 +564,7 @@ namespace BlockPage _dnsServer.WriteLog(ex); } - if (jsonConfig.webServerUseSelfSignedTlsCertificate is null) + if (!jsonConfig.TryGetProperty("webServerUseSelfSignedTlsCertificate", out _)) { config = config.Replace("\"webServerTlsCertificateFilePath\"", "\"webServerUseSelfSignedTlsCertificate\": true,\r\n \"webServerTlsCertificateFilePath\""); From b0f2290bc0ec4112971999b79bdcd501f2218444 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 17 Dec 2022 16:33:57 +0530 Subject: [PATCH 004/191] DropRequests: removed newtonsoft --- Apps/DropRequestsApp/App.cs | 77 +++++++++++-------------------------- 1 file changed, 22 insertions(+), 55 deletions(-) diff --git a/Apps/DropRequestsApp/App.cs b/Apps/DropRequestsApp/App.cs index 724bbbf6..a542f27e 100644 --- a/Apps/DropRequestsApp/App.cs +++ b/Apps/DropRequestsApp/App.cs @@ -18,12 +18,13 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -55,64 +56,32 @@ namespace DropRequests public async Task InitializeAsync(IDnsServer dnsServer, string config) { - dynamic jsonConfig = JsonConvert.DeserializeObject(config); + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; - _enableBlocking = jsonConfig.enableBlocking.Value; + _enableBlocking = jsonConfig.GetProperty("enableBlocking").GetBoolean(); - if (jsonConfig.dropMalformedRequests is null) + if (jsonConfig.TryGetProperty("dropMalformedRequests", out JsonElement jsonDropMalformedRequests)) + _dropMalformedRequests = jsonDropMalformedRequests.GetBoolean(); + else _dropMalformedRequests = false; - else - _dropMalformedRequests = jsonConfig.dropMalformedRequests.Value; - - if (jsonConfig.allowedNetworks is null) - { - _allowedNetworks = Array.Empty(); - } - else - { - List allowedNetworks = new List(); - - foreach (dynamic allowedNetwork in jsonConfig.allowedNetworks) - { - allowedNetworks.Add(NetworkAddress.Parse(allowedNetwork.Value)); - } + if (jsonConfig.TryReadArray("allowedNetworks", NetworkAddress.Parse, out NetworkAddress[] allowedNetworks)) _allowedNetworks = allowedNetworks; - } - - if (jsonConfig.blockedNetworks is null) - { - _blockedNetworks = Array.Empty(); - } else - { - List blockedNetworks = new List(); - - foreach (dynamic blockedNetwork in jsonConfig.blockedNetworks) - { - blockedNetworks.Add(NetworkAddress.Parse(blockedNetwork.Value)); - } + _allowedNetworks = Array.Empty(); + if (jsonConfig.TryReadArray("blockedNetworks", NetworkAddress.Parse, out NetworkAddress[] blockedNetworks)) _blockedNetworks = blockedNetworks; - } - - if (jsonConfig.blockedQuestions is null) - { - _blockedQuestions = Array.Empty(); - } else - { - List blockedQuestions = new List(); - - foreach (dynamic blockedQuestion in jsonConfig.blockedQuestions) - { - blockedQuestions.Add(new BlockedQuestion(blockedQuestion)); - } + _blockedNetworks = Array.Empty(); + if (jsonConfig.TryReadArray("blockedQuestions", delegate (JsonElement blockedQuestion) { return new BlockedQuestion(blockedQuestion); }, out BlockedQuestion[] blockedQuestions)) _blockedQuestions = blockedQuestions; - } + else + _blockedQuestions = Array.Empty(); - if (jsonConfig.dropMalformedRequests is null) + if (!jsonConfig.TryGetProperty("dropMalformedRequests", out _)) { config = config.Replace("\"allowedNetworks\"", "\"dropMalformedRequests\": false,\r\n \"allowedNetworks\""); @@ -177,17 +146,15 @@ namespace DropRequests #region constructor - public BlockedQuestion(dynamic jsonQuestion) + public BlockedQuestion(JsonElement jsonQuestion) { - _name = jsonQuestion.name?.Value; - if (_name is not null) - _name = _name.TrimEnd('.'); + if (jsonQuestion.TryGetProperty("name", out JsonElement jsonName)) + _name = jsonName.GetString().TrimEnd('.'); - if (jsonQuestion.blockZone is not null) - _blockZone = jsonQuestion.blockZone.Value; + if (jsonQuestion.TryGetProperty("blockZone", out JsonElement jsonBlockZone)) + _blockZone = jsonBlockZone.GetBoolean(); - string strType = jsonQuestion.type?.Value; - if (!string.IsNullOrEmpty(strType) && Enum.TryParse(strType, true, out DnsResourceRecordType type)) + if (jsonQuestion.TryGetProperty("type", out JsonElement jsonType) && Enum.TryParse(jsonType.GetString(), true, out DnsResourceRecordType type)) _type = type; else _type = DnsResourceRecordType.Unknown; From c1ff7d6cf4245f2d7e73534d173799fec9cb9593 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 17 Dec 2022 16:36:43 +0530 Subject: [PATCH 005/191] DNS64: removed newtonsoft --- Apps/Dns64App/App.cs | 114 +++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 70 deletions(-) diff --git a/Apps/Dns64App/App.cs b/Apps/Dns64App/App.cs index 39c9f682..f76d3ce3 100644 --- a/Apps/Dns64App/App.cs +++ b/Apps/Dns64App/App.cs @@ -18,12 +18,13 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -60,41 +61,27 @@ namespace Dns64 { _dnsServer = dnsServer; - dynamic jsonConfig = JsonConvert.DeserializeObject(config); + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; - _enableDns64 = jsonConfig.enableDns64.Value; + _enableDns64 = jsonConfig.GetProperty("enableDns64").GetBoolean(); + _networkGroupMap = jsonConfig.ReadObjectAsMap("networkGroupMap", delegate (string network, JsonElement group) { - Dictionary networkGroupMap = new Dictionary(); + if (!NetworkAddress.TryParse(network, out NetworkAddress networkAddress)) + throw new InvalidOperationException("Network group map contains an invalid network address: " + network); - foreach (dynamic jsonProperty in jsonConfig.networkGroupMap) - { - string network = jsonProperty.Name; - string group = jsonProperty.Value; + if (networkAddress.Address.AddressFamily == AddressFamily.InterNetwork) + throw new InvalidOperationException("Network group map can only have IPv6 network addresses: " + network); - if (!NetworkAddress.TryParse(network, out NetworkAddress networkAddress)) - throw new InvalidOperationException("Network group map contains an invalid network address: " + network); - - if (networkAddress.Address.AddressFamily == AddressFamily.InterNetwork) - throw new InvalidOperationException("Network group map can only have IPv6 network addresses: " + network); - - networkGroupMap.Add(networkAddress, group); - } - - _networkGroupMap = networkGroupMap; - } + return new Tuple(networkAddress, group.GetString()); + }); + _groups = jsonConfig.ReadArrayAsMap("groups", delegate (JsonElement jsonGroup) { - Dictionary groups = new Dictionary(); - - foreach (dynamic jsonGroup in jsonConfig.groups) - { - Group group = new Group(jsonGroup); - groups.Add(group.Name, group); - } - - _groups = groups; - } + Group group = new Group(jsonGroup); + return new Tuple(group.Name, group); + }); return Task.CompletedTask; } @@ -275,61 +262,48 @@ namespace Dns64 #region constructor - public Group(dynamic jsonGroup) + public Group(JsonElement jsonGroup) { - _name = jsonGroup.name.Value; - _enableDns64 = jsonGroup.enableDns64.Value; + _name = jsonGroup.GetProperty("name").GetString(); + _enableDns64 = jsonGroup.GetProperty("enableDns64").GetBoolean(); + _dns64PrefixMap = jsonGroup.ReadObjectAsMap("dns64PrefixMap", delegate (string strNetwork, JsonElement jsonDns64Prefix) { - Dictionary dns64PrefixMap = new Dictionary(); + string strDns64Prefix = jsonDns64Prefix.GetString(); - foreach (dynamic jsonProperty in jsonGroup.dns64PrefixMap) + NetworkAddress network = NetworkAddress.Parse(strNetwork); + NetworkAddress dns64Prefix = null; + + if (strDns64Prefix is not null) { - string strNetwork = jsonProperty.Name; - string strDns64Prefix = jsonProperty.Value; + dns64Prefix = NetworkAddress.Parse(strDns64Prefix); - NetworkAddress network = NetworkAddress.Parse(strNetwork); - NetworkAddress dns64Prefix = null; - - if (strDns64Prefix is not null) + switch (dns64Prefix.PrefixLength) { - dns64Prefix = NetworkAddress.Parse(strDns64Prefix); + case 32: + case 40: + case 48: + case 56: + case 64: + case 96: + break; - switch (dns64Prefix.PrefixLength) - { - case 32: - case 40: - case 48: - case 56: - case 64: - case 96: - break; - - default: - throw new NotSupportedException("DNS64 prefix can have only the following prefixes: 32, 40, 48, 56, 64, or 96."); - } + default: + throw new NotSupportedException("DNS64 prefix can have only the following prefixes: 32, 40, 48, 56, 64, or 96."); } - - dns64PrefixMap.Add(network, dns64Prefix); } - _dns64PrefixMap = dns64PrefixMap; - } + return new Tuple(network, dns64Prefix); + }); + _excludedIpv6 = jsonGroup.ReadArray("excludedIpv6", delegate (string strNetworkAddress) { - List excludedIpv6 = new List(); + NetworkAddress networkAddress = NetworkAddress.Parse(strNetworkAddress); + if (networkAddress.Address.AddressFamily != AddressFamily.InterNetworkV6) + throw new InvalidOperationException("An IPv6 network address is expected for 'excludedIpv6' array."); - foreach (dynamic jsonItem in jsonGroup.excludedIpv6) - { - NetworkAddress networkAddress = NetworkAddress.Parse(jsonItem.Value); - if (networkAddress.Address.AddressFamily != AddressFamily.InterNetworkV6) - throw new InvalidOperationException("An IPv6 network address is expected for 'excludedIpv6' array."); - - excludedIpv6.Add(networkAddress); - } - - _excludedIpv6 = excludedIpv6; - } + return networkAddress; + }); } #endregion From 3544a273b15288602650501bbab9907990d119d4 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:27:45 +0530 Subject: [PATCH 006/191] AdvancedBlocking: updated ReadListFile() to support wildcard block lists. --- Apps/AdvancedBlockingApp/App.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/AdvancedBlockingApp/App.cs b/Apps/AdvancedBlockingApp/App.cs index 7d38b34e..ae00fe35 100644 --- a/Apps/AdvancedBlockingApp/App.cs +++ b/Apps/AdvancedBlockingApp/App.cs @@ -1065,7 +1065,7 @@ namespace AdvancedBlocking if (line == null) break; //eof - line = line.TrimStart(' ', '\t'); + line = line.TrimStart(' ', '\t', '*', '.'); if (line.Length == 0) continue; //skip empty line From d83bfc783a350e64bedf8b6b75c53d6e1551432d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:31:52 +0530 Subject: [PATCH 007/191] Dns64: minor changes. --- Apps/Dns64App/App.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/Dns64App/App.cs b/Apps/Dns64App/App.cs index f76d3ce3..043ed0cb 100644 --- a/Apps/Dns64App/App.cs +++ b/Apps/Dns64App/App.cs @@ -154,7 +154,7 @@ namespace Dns64 { DnsResourceRecord soa = response.FindFirstAuthorityRecord(); if ((soa is not null) && (soa.Type == DnsResourceRecordType.SOA)) - soaTtl = soa.TtlValue; + soaTtl = soa.TTL; else soaTtl = 600; } @@ -182,7 +182,7 @@ namespace Dns64 IPAddress ipv6Address = ipv4Address.MapToIPv6(dns64Prefix); - newAnswer.Add(new DnsResourceRecord(answer.Name, DnsResourceRecordType.AAAA, answer.Class, Math.Min(answer.TtlValue, soaTtl), new DnsAAAARecordData(ipv6Address))); + newAnswer.Add(new DnsResourceRecord(answer.Name, DnsResourceRecordType.AAAA, answer.Class, Math.Min(answer.TTL, soaTtl), new DnsAAAARecordData(ipv6Address))); } return new DnsDatagram(response.Identifier, true, response.OPCODE, response.AuthoritativeAnswer, response.Truncation, response.RecursionDesired, response.RecursionAvailable, response.AuthenticData, response.CheckingDisabled, newResponse.RCODE, response.Question, newAnswer, newResponse.Authority, newResponse.Additional) { Tag = response.Tag }; From 5d04668faa68bb5ed2129bfce4991f699306066c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:41:49 +0530 Subject: [PATCH 008/191] Failover: Removed newtonsoft. Added retries for send alert email. --- Apps/FailoverApp/Address.cs | 77 +++++++++---------- Apps/FailoverApp/CNAME.cs | 51 ++++++------ Apps/FailoverApp/EmailAlert.cs | 99 ++++++++++-------------- Apps/FailoverApp/HealthCheck.cs | 65 ++++------------ Apps/FailoverApp/HealthService.cs | 89 ++++++++------------- Apps/FailoverApp/WebHook.cs | 124 +++++++++--------------------- 6 files changed, 189 insertions(+), 316 deletions(-) diff --git a/Apps/FailoverApp/Address.cs b/Apps/FailoverApp/Address.cs index cda6b414..cf60fd9e 100644 --- a/Apps/FailoverApp/Address.cs +++ b/Apps/FailoverApp/Address.cs @@ -18,11 +18,11 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; @@ -64,17 +64,14 @@ namespace Failover #region private - private void GetAnswers(dynamic jsonAddresses, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List answers) + private void GetAnswers(JsonElement jsonAddresses, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List answers) { - if (jsonAddresses == null) - return; - switch (question.Type) { case DnsResourceRecordType.A: - foreach (dynamic jsonAddress in jsonAddresses) + foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray()) { - IPAddress address = IPAddress.Parse(jsonAddress.Value); + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); if (address.AddressFamily == AddressFamily.InterNetwork) { @@ -94,9 +91,9 @@ namespace Failover break; case DnsResourceRecordType.AAAA: - foreach (dynamic jsonAddress in jsonAddresses) + foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray()) { - IPAddress address = IPAddress.Parse(jsonAddress.Value); + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); if (address.AddressFamily == AddressFamily.InterNetworkV6) { @@ -117,14 +114,11 @@ namespace Failover } } - private void GetStatusAnswers(dynamic jsonAddresses, FailoverType type, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List answers) + private void GetStatusAnswers(JsonElement jsonAddresses, FailoverType type, DnsQuestionRecord question, uint appRecordTtl, string healthCheck, Uri healthCheckUrl, List answers) { - if (jsonAddresses == null) - return; - - foreach (dynamic jsonAddress in jsonAddresses) + foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray()) { - IPAddress address = IPAddress.Parse(jsonAddress.Value); + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); HealthCheckResponse response = _healthService.QueryStatus(address, healthCheck, healthCheckUrl, false); string text = "app=failover; addressType=" + type.ToString() + "; address=" + address.ToString() + "; healthCheck=" + healthCheck + (healthCheckUrl is null ? "" : "; healthCheckUrl=" + healthCheckUrl.AbsoluteUri) + "; healthStatus=" + response.Status.ToString() + ";"; @@ -145,7 +139,7 @@ namespace Failover if (_healthService is null) _healthService = HealthService.Create(dnsServer); - _healthService.Initialize(JsonConvert.DeserializeObject(config)); + _healthService.Initialize(config); return Task.CompletedTask; } @@ -158,17 +152,18 @@ namespace Failover case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: { - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; - string healthCheck = jsonAppRecordData.healthCheck?.Value; + string healthCheck = jsonAppRecordData.GetPropertyValue("healthCheck", null); Uri healthCheckUrl = null; if (_healthService.HealthChecks.TryGetValue(healthCheck, out HealthCheck hc) && ((hc.Type == HealthCheckType.Https) || (hc.Type == HealthCheckType.Http)) && (hc.Url is null)) { //read health check url only for http/https type checks and only when app config does not have an url configured - if ((jsonAppRecordData.healthCheckUrl is not null) && (jsonAppRecordData.healthCheckUrl.Value is not null)) + if (jsonAppRecordData.TryGetProperty("healthCheckUrl", out JsonElement jsonHealthCheckUrl) && (jsonHealthCheckUrl.ValueKind != JsonValueKind.Null)) { - healthCheckUrl = new Uri(jsonAppRecordData.healthCheckUrl.Value); + healthCheckUrl = new Uri(jsonHealthCheckUrl.GetString()); } else { @@ -181,19 +176,23 @@ namespace Failover List answers = new List(); - GetAnswers(jsonAppRecordData.primary, question, appRecordTtl, healthCheck, healthCheckUrl, answers); + if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary)) + GetAnswers(jsonPrimary, question, appRecordTtl, healthCheck, healthCheckUrl, answers); + if (answers.Count == 0) { - GetAnswers(jsonAppRecordData.secondary, question, appRecordTtl, healthCheck, healthCheckUrl, answers); + if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary)) + GetAnswers(jsonSecondary, question, appRecordTtl, healthCheck, healthCheckUrl, answers); + if (answers.Count == 0) { - if (jsonAppRecordData.serverDown is not null) + if (jsonAppRecordData.TryGetProperty("serverDown", out JsonElement jsonServerDown)) { if (question.Type == DnsResourceRecordType.A) { - foreach (dynamic jsonAddress in jsonAppRecordData.serverDown) + foreach (JsonElement jsonAddress in jsonServerDown.EnumerateArray()) { - IPAddress address = IPAddress.Parse(jsonAddress.Value); + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); if (address.AddressFamily == AddressFamily.InterNetwork) answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, question.Class, 30, new DnsARecordData(address))); @@ -201,9 +200,9 @@ namespace Failover } else { - foreach (dynamic jsonAddress in jsonAppRecordData.serverDown) + foreach (JsonElement jsonAddress in jsonServerDown.EnumerateArray()) { - IPAddress address = IPAddress.Parse(jsonAddress.Value); + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); if (address.AddressFamily == AddressFamily.InterNetworkV6) answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, question.Class, 30, new DnsAAAARecordData(address))); @@ -224,27 +223,22 @@ namespace Failover case DnsResourceRecordType.TXT: { - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - - bool allowTxtStatus; - - if (jsonAppRecordData.allowTxtStatus == null) - allowTxtStatus = false; - else - allowTxtStatus = jsonAppRecordData.allowTxtStatus.Value; + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; + bool allowTxtStatus = jsonAppRecordData.GetPropertyValue("allowTxtStatus", false); if (!allowTxtStatus) return Task.FromResult(null); - string healthCheck = jsonAppRecordData.healthCheck?.Value; + string healthCheck = jsonAppRecordData.GetPropertyValue("healthCheck", null); Uri healthCheckUrl = null; if (_healthService.HealthChecks.TryGetValue(healthCheck, out HealthCheck hc) && ((hc.Type == HealthCheckType.Https) || (hc.Type == HealthCheckType.Http)) && (hc.Url is null)) { //read health check url only for http/https type checks and only when app config does not have an url configured - if ((jsonAppRecordData.healthCheckUrl is not null) && (jsonAppRecordData.healthCheckUrl.Value is not null)) + if (jsonAppRecordData.TryGetProperty("healthCheckUrl", out JsonElement jsonHealthCheckUrl) && (jsonHealthCheckUrl.ValueKind != JsonValueKind.Null)) { - healthCheckUrl = new Uri(jsonAppRecordData.healthCheckUrl.Value); + healthCheckUrl = new Uri(jsonHealthCheckUrl.GetString()); } else { @@ -257,8 +251,11 @@ namespace Failover List answers = new List(); - GetStatusAnswers(jsonAppRecordData.primary, FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, answers); - GetStatusAnswers(jsonAppRecordData.secondary, FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, answers); + if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary)) + GetStatusAnswers(jsonPrimary, FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, answers); + + if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary)) + GetStatusAnswers(jsonSecondary, FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, answers); return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); } diff --git a/Apps/FailoverApp/CNAME.cs b/Apps/FailoverApp/CNAME.cs index e6dcd076..785b7e43 100644 --- a/Apps/FailoverApp/CNAME.cs +++ b/Apps/FailoverApp/CNAME.cs @@ -18,11 +18,12 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -119,17 +120,18 @@ namespace Failover { DnsQuestionRecord question = request.Question[0]; - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; - string healthCheck = jsonAppRecordData.healthCheck?.Value; + string healthCheck = jsonAppRecordData.GetPropertyValue("healthCheck", null); Uri healthCheckUrl = null; if (_healthService.HealthChecks.TryGetValue(healthCheck, out HealthCheck hc) && ((hc.Type == HealthCheckType.Https) || (hc.Type == HealthCheckType.Http)) && (hc.Url is null)) { //read health check url only for http/https type checks and only when app config does not have an url configured - if ((jsonAppRecordData.healthCheckUrl is not null) && (jsonAppRecordData.healthCheckUrl.Value is not null)) + if (jsonAppRecordData.TryGetProperty("healthCheckUrl", out JsonElement jsonHealthCheckUrl) && (jsonHealthCheckUrl.ValueKind != JsonValueKind.Null)) { - healthCheckUrl = new Uri(jsonAppRecordData.healthCheckUrl.Value); + healthCheckUrl = new Uri(jsonHealthCheckUrl.GetString()); } else { @@ -140,47 +142,50 @@ namespace Failover } } - IReadOnlyList answers; + IReadOnlyList answers = null; if (question.Type == DnsResourceRecordType.TXT) { - bool allowTxtStatus; - - if (jsonAppRecordData.allowTxtStatus == null) - allowTxtStatus = false; - else - allowTxtStatus = jsonAppRecordData.allowTxtStatus.Value; - + bool allowTxtStatus = jsonAppRecordData.GetPropertyValue("allowTxtStatus", false); if (!allowTxtStatus) return Task.FromResult(null); List txtAnswers = new List(); - GetStatusAnswers(jsonAppRecordData.primary.Value, FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, txtAnswers); + if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary)) + GetStatusAnswers(jsonPrimary.GetString(), FailoverType.Primary, question, 30, healthCheck, healthCheckUrl, txtAnswers); - foreach (dynamic jsonDomain in jsonAppRecordData.secondary) - GetStatusAnswers(jsonDomain.Value, FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, txtAnswers); + if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary)) + { + foreach (JsonElement jsonDomain in jsonSecondary.EnumerateArray()) + GetStatusAnswers(jsonDomain.GetString(), FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, txtAnswers); + } answers = txtAnswers; } else { - answers = GetAnswers(jsonAppRecordData.primary.Value, question, zoneName, appRecordTtl, healthCheck, healthCheckUrl); + if (jsonAppRecordData.TryGetProperty("primary", out JsonElement jsonPrimary)) + answers = GetAnswers(jsonPrimary.GetString(), question, zoneName, appRecordTtl, healthCheck, healthCheckUrl); + if (answers is null) { - foreach (dynamic jsonDomain in jsonAppRecordData.secondary) + if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary)) { - answers = GetAnswers(jsonDomain.Value, question, zoneName, appRecordTtl, healthCheck, healthCheckUrl); - if (answers is not null) - break; + foreach (JsonElement jsonDomain in jsonSecondary.EnumerateArray()) + { + answers = GetAnswers(jsonDomain.GetString(), question, zoneName, appRecordTtl, healthCheck, healthCheckUrl); + if (answers is not null) + break; + } } if (answers is null) { - if ((jsonAppRecordData.serverDown is null) || (jsonAppRecordData.serverDown.Value is null)) + if (!jsonAppRecordData.TryGetProperty("serverDown", out JsonElement jsonServerDown) || (jsonServerDown.ValueKind == JsonValueKind.Null)) return Task.FromResult(null); - string serverDown = jsonAppRecordData.serverDown.Value; + string serverDown = jsonServerDown.GetString(); if (question.Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase)) //check for zone apex answers = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.ANAME, DnsClass.IN, 30, new DnsANAMERecordData(serverDown)) }; //use ANAME diff --git a/Apps/FailoverApp/EmailAlert.cs b/Apps/FailoverApp/EmailAlert.cs index dea45264..d45c8d56 100644 --- a/Apps/FailoverApp/EmailAlert.cs +++ b/Apps/FailoverApp/EmailAlert.cs @@ -23,8 +23,10 @@ using System.Collections.Generic; using System.Net; using System.Net.Mail; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; using TechnitiumLibrary.Net.Mail; @@ -37,7 +39,7 @@ namespace Failover readonly HealthService _service; - string _name; + readonly string _name; bool _enabled; MailAddress[] _alertTo; string _smtpServer; @@ -54,13 +56,15 @@ namespace Failover #region constructor - public EmailAlert(HealthService service, dynamic jsonEmailAlert) + public EmailAlert(HealthService service, JsonElement jsonEmailAlert) { _service = service; _smtpClient = new SmtpClientEx(); _smtpClient.DnsClient = new DnsClientInternal(_service.DnsServer); + _name = jsonEmailAlert.GetPropertyValue("name", "default"); + Reload(jsonEmailAlert); } @@ -98,7 +102,24 @@ namespace Failover { try { - await _smtpClient.SendMailAsync(message); + const int MAX_RETRIES = 3; + const int WAIT_INTERVAL = 30000; + + for (int retries = 0; retries < MAX_RETRIES; retries++) + { + try + { + await _smtpClient.SendMailAsync(message); + break; + } + catch + { + if (retries == MAX_RETRIES - 1) + throw; + + await Task.Delay(WAIT_INTERVAL); + } + } } catch (Exception ex) { @@ -110,71 +131,33 @@ namespace Failover #region public - public void Reload(dynamic jsonEmailAlert) + public void Reload(JsonElement jsonEmailAlert) { - if (jsonEmailAlert.name is null) - _name = "default"; - else - _name = jsonEmailAlert.name.Value; + _enabled = jsonEmailAlert.GetPropertyValue("enabled", false); - if (jsonEmailAlert.enabled is null) - _enabled = false; + if (jsonEmailAlert.TryReadArray("alertTo", delegate (string emailAddress) { return new MailAddress(emailAddress); }, out MailAddress[] alertTo)) + _alertTo = alertTo; else - _enabled = jsonEmailAlert.enabled.Value; - - if (jsonEmailAlert.alertTo is null) - { _alertTo = null; - } - else + + _smtpServer = jsonEmailAlert.GetPropertyValue("smtpServer", null); + _smtpPort = jsonEmailAlert.GetPropertyValue("smtpPort", 25); + _startTls = jsonEmailAlert.GetPropertyValue("startTls", false); + _smtpOverTls = jsonEmailAlert.GetPropertyValue("smtpOverTls", false); + _username = jsonEmailAlert.GetPropertyValue("username", null); + _password = jsonEmailAlert.GetPropertyValue("password", null); + + if (jsonEmailAlert.TryGetProperty("mailFrom", out JsonElement jsonMailFrom)) { - _alertTo = new MailAddress[jsonEmailAlert.alertTo.Count]; - - for (int i = 0; i < _alertTo.Length; i++) - _alertTo[i] = new MailAddress(jsonEmailAlert.alertTo[i].Value); + if (jsonEmailAlert.TryGetProperty("mailFromName", out JsonElement jsonMailFromName)) + _mailFrom = new MailAddress(jsonMailFrom.GetString(), jsonMailFromName.GetString(), Encoding.UTF8); + else + _mailFrom = new MailAddress(jsonMailFrom.GetString()); } - - if (jsonEmailAlert.smtpServer is null) - _smtpServer = null; else - _smtpServer = jsonEmailAlert.smtpServer.Value; - - if (jsonEmailAlert.smtpPort is null) - _smtpPort = 25; - else - _smtpPort = Convert.ToInt32(jsonEmailAlert.smtpPort.Value); - - if (jsonEmailAlert.startTls is null) - _startTls = false; - else - _startTls = jsonEmailAlert.startTls.Value; - - if (jsonEmailAlert.smtpOverTls is null) - _smtpOverTls = false; - else - _smtpOverTls = jsonEmailAlert.smtpOverTls.Value; - - if (jsonEmailAlert.username is null) - _username = null; - else - _username = jsonEmailAlert.username.Value; - - if (jsonEmailAlert.password is null) - _password = null; - else - _password = jsonEmailAlert.password.Value; - - if (jsonEmailAlert.mailFrom is null) { _mailFrom = null; } - else - { - if (jsonEmailAlert.mailFromName is null) - _mailFrom = new MailAddress(jsonEmailAlert.mailFrom.Value); - else - _mailFrom = new MailAddress(jsonEmailAlert.mailFrom.Value, jsonEmailAlert.mailFromName.Value, Encoding.UTF8); - } //update smtp client settings _smtpClient.Host = _smtpServer; diff --git a/Apps/FailoverApp/HealthCheck.cs b/Apps/FailoverApp/HealthCheck.cs index ce202abd..85c02a2d 100644 --- a/Apps/FailoverApp/HealthCheck.cs +++ b/Apps/FailoverApp/HealthCheck.cs @@ -23,6 +23,7 @@ using System.Net; using System.Net.Http; using System.Net.NetworkInformation; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net; @@ -49,7 +50,7 @@ namespace Failover readonly HealthService _service; - string _name; + readonly string _name; HealthCheckType _type; int _interval; int _retries; @@ -66,10 +67,12 @@ namespace Failover #region constructor - public HealthCheck(HealthService service, dynamic jsonHealthCheck) + public HealthCheck(HealthService service, JsonElement jsonHealthCheck) { _service = service; + _name = jsonHealthCheck.GetPropertyValue("name", "default"); + Reload(jsonHealthCheck); } @@ -200,63 +203,25 @@ namespace Failover #region public - public void Reload(dynamic jsonHealthCheck) + public void Reload(JsonElement jsonHealthCheck) { - if (jsonHealthCheck.name is null) - _name = "default"; - else - _name = jsonHealthCheck.name.Value; + _type = Enum.Parse(jsonHealthCheck.GetPropertyValue("type", "Tcp"), true); + _interval = jsonHealthCheck.GetPropertyValue("interval", 60) * 1000; + _retries = jsonHealthCheck.GetPropertyValue("retries", 3); + _timeout = jsonHealthCheck.GetPropertyValue("timeout", 10) * 1000; + _port = jsonHealthCheck.GetPropertyValue("port", 80); - if (jsonHealthCheck.type == null) - _type = HealthCheckType.Tcp; + if (jsonHealthCheck.TryGetProperty("url", out JsonElement jsonUrl) && (jsonUrl.ValueKind != JsonValueKind.Null)) + _url = new Uri(jsonUrl.GetString()); else - _type = Enum.Parse(jsonHealthCheck.type.Value, true); - - if (jsonHealthCheck.interval is null) - _interval = 60000; - else - _interval = Convert.ToInt32(jsonHealthCheck.interval.Value) * 1000; - - if (jsonHealthCheck.retries is null) - _retries = 3; - else - _retries = Convert.ToInt32(jsonHealthCheck.retries.Value); - - if (jsonHealthCheck.timeout is null) - _timeout = 10000; - else - _timeout = Convert.ToInt32(jsonHealthCheck.timeout.Value) * 1000; - - if (jsonHealthCheck.port is null) - _port = 80; - else - _port = Convert.ToInt32(jsonHealthCheck.port.Value); - - if ((jsonHealthCheck.url is null) || (jsonHealthCheck.url.Value is null)) _url = null; - else - _url = new Uri(jsonHealthCheck.url.Value); - string emailAlertName; - - if (jsonHealthCheck.emailAlert is null) - emailAlertName = null; - else - emailAlertName = jsonHealthCheck.emailAlert.Value; - - if ((emailAlertName is not null) && _service.EmailAlerts.TryGetValue(emailAlertName, out EmailAlert emailAlert)) + if (jsonHealthCheck.TryGetProperty("emailAlert", out JsonElement jsonEmailAlert) && _service.EmailAlerts.TryGetValue(jsonEmailAlert.GetString(), out EmailAlert emailAlert)) _emailAlert = emailAlert; else _emailAlert = null; - string webHookName; - - if (jsonHealthCheck.webHook is null) - webHookName = null; - else - webHookName = jsonHealthCheck.webHook.Value; - - if ((webHookName is not null) && _service.WebHooks.TryGetValue(webHookName, out WebHook webHook)) + if (jsonHealthCheck.TryGetProperty("webHook", out JsonElement jsonWebHook) && _service.WebHooks.TryGetValue(jsonWebHook.GetString(), out WebHook webHook)) _webHook = webHook; else _webHook = null; diff --git a/Apps/FailoverApp/HealthService.cs b/Apps/FailoverApp/HealthService.cs index adf55513..67b26511 100644 --- a/Apps/FailoverApp/HealthService.cs +++ b/Apps/FailoverApp/HealthService.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2021 Shreyas Zare (shreyas@technitium.com) +Copyright (C) 2022 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 @@ -22,7 +22,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading; +using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -178,19 +180,19 @@ namespace Failover #region public - public void Initialize(dynamic jsonConfig) + public void Initialize(string config) { + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; + //email alerts { - //add or update email alerts - foreach (dynamic jsonEmailAlert in jsonConfig.emailAlerts) - { - string name; + JsonElement jsonEmailAlerts = jsonConfig.GetProperty("emailAlerts"); - if (jsonEmailAlert.name is null) - name = "default"; - else - name = jsonEmailAlert.name.Value; + //add or update email alerts + foreach (JsonElement jsonEmailAlert in jsonEmailAlerts.EnumerateArray()) + { + string name = jsonEmailAlert.GetPropertyValue("name", "default"); if (_emailAlerts.TryGetValue(name, out EmailAlert existingEmailAlert)) { @@ -201,7 +203,6 @@ namespace Failover { //add EmailAlert emailAlert = new EmailAlert(this, jsonEmailAlert); - _emailAlerts.TryAdd(emailAlert.Name, emailAlert); } } @@ -211,15 +212,9 @@ namespace Failover { bool emailAlertExists = false; - foreach (dynamic jsonEmailAlert in jsonConfig.emailAlerts) + foreach (JsonElement jsonEmailAlert in jsonEmailAlerts.EnumerateArray()) { - string name; - - if (jsonEmailAlert.name is null) - name = "default"; - else - name = jsonEmailAlert.name.Value; - + string name = jsonEmailAlert.GetPropertyValue("name", "default"); if (name == emailAlert.Key) { emailAlertExists = true; @@ -237,15 +232,12 @@ namespace Failover //web hooks { - //add or update email alerts - foreach (dynamic jsonWebHook in jsonConfig.webHooks) - { - string name; + JsonElement jsonWebHooks = jsonConfig.GetProperty("webHooks"); - if (jsonWebHook.name is null) - name = "default"; - else - name = jsonWebHook.name.Value; + //add or update email alerts + foreach (JsonElement jsonWebHook in jsonWebHooks.EnumerateArray()) + { + string name = jsonWebHook.GetPropertyValue("name", "default"); if (_webHooks.TryGetValue(name, out WebHook existingWebHook)) { @@ -256,7 +248,6 @@ namespace Failover { //add WebHook webHook = new WebHook(this, jsonWebHook); - _webHooks.TryAdd(webHook.Name, webHook); } } @@ -266,15 +257,9 @@ namespace Failover { bool webHookExists = false; - foreach (dynamic jsonWebHook in jsonConfig.webHooks) + foreach (JsonElement jsonWebHook in jsonWebHooks.EnumerateArray()) { - string name; - - if (jsonWebHook.name is null) - name = "default"; - else - name = jsonWebHook.name.Value; - + string name = jsonWebHook.GetPropertyValue("name", "default"); if (name == webHook.Key) { webHookExists = true; @@ -292,15 +277,12 @@ namespace Failover //health checks { - //add or update health checks - foreach (dynamic jsonHealthCheck in jsonConfig.healthChecks) - { - string name; + JsonElement jsonHealthChecks = jsonConfig.GetProperty("healthChecks"); - if (jsonHealthCheck.name is null) - name = "default"; - else - name = jsonHealthCheck.name.Value; + //add or update health checks + foreach (JsonElement jsonHealthCheck in jsonHealthChecks.EnumerateArray()) + { + string name = jsonHealthCheck.GetPropertyValue("name", "default"); if (_healthChecks.TryGetValue(name, out HealthCheck existingHealthCheck)) { @@ -311,7 +293,6 @@ namespace Failover { //add HealthCheck healthCheck = new HealthCheck(this, jsonHealthCheck); - _healthChecks.TryAdd(healthCheck.Name, healthCheck); } } @@ -321,15 +302,9 @@ namespace Failover { bool healthCheckExists = false; - foreach (dynamic jsonHealthCheck in jsonConfig.healthChecks) + foreach (JsonElement jsonHealthCheck in jsonHealthChecks.EnumerateArray()) { - string name; - - if (jsonHealthCheck.name is null) - name = "default"; - else - name = jsonHealthCheck.name.Value; - + string name = jsonHealthCheck.GetPropertyValue("name", "default"); if (name == healthCheck.Key) { healthCheckExists = true; @@ -353,12 +328,12 @@ namespace Failover //under maintenance networks _underMaintenance.Clear(); - if (jsonConfig.underMaintenance is not null) + if (jsonConfig.TryGetProperty("underMaintenance", out JsonElement jsonUnderMaintenance)) { - foreach (dynamic jsonNetwork in jsonConfig.underMaintenance) + foreach (JsonElement jsonNetwork in jsonUnderMaintenance.EnumerateArray()) { - string network = jsonNetwork.network.Value; - bool enable = jsonNetwork.enable.Value; + string network = jsonNetwork.GetProperty("network").GetString(); + bool enable = jsonNetwork.GetProperty("enable").GetBoolean(); _underMaintenance.TryAdd(NetworkAddress.Parse(network), enable); } diff --git a/Apps/FailoverApp/WebHook.cs b/Apps/FailoverApp/WebHook.cs index 7aecc7f0..5356c972 100644 --- a/Apps/FailoverApp/WebHook.cs +++ b/Apps/FailoverApp/WebHook.cs @@ -17,14 +17,15 @@ along with this program. If not, see . */ -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns.ResourceRecords; using TechnitiumLibrary.Net.Proxy; @@ -36,7 +37,7 @@ namespace Failover readonly HealthService _service; - string _name; + readonly string _name; bool _enabled; Uri[] _urls; @@ -47,10 +48,12 @@ namespace Failover #region constructor - public WebHook(HealthService service, dynamic jsonWebHook) + public WebHook(HealthService service, JsonElement jsonWebHook) { _service = service; + _name = jsonWebHook.GetPropertyValue("name", "default"); + Reload(jsonWebHook); } @@ -176,29 +179,14 @@ namespace Failover #region public - public void Reload(dynamic jsonWebHook) + public void Reload(JsonElement jsonWebHook) { - if (jsonWebHook.name is null) - _name = "default"; - else - _name = jsonWebHook.name.Value; + _enabled = jsonWebHook.GetPropertyValue("enabled", false); - if (jsonWebHook.enabled is null) - _enabled = false; + if (jsonWebHook.TryReadArray("urls", delegate (string uri) { return new Uri(uri); }, out Uri[] urls)) + _urls = urls; else - _enabled = jsonWebHook.enabled.Value; - - if (jsonWebHook.urls is null) - { _urls = null; - } - else - { - _urls = new Uri[jsonWebHook.urls.Count]; - - for (int i = 0; i < _urls.Length; i++) - _urls[i] = new Uri(jsonWebHook.urls[i].Value); - } ConditionalHttpReload(); } @@ -212,26 +200,17 @@ namespace Failover { using (MemoryStream mS = new MemoryStream()) { - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("address"); - jsonWriter.WriteValue(address.ToString()); - - jsonWriter.WritePropertyName("healthCheck"); - jsonWriter.WriteValue(healthCheck); - - jsonWriter.WritePropertyName("status"); - jsonWriter.WriteValue(healthCheckResponse.Status.ToString()); + jsonWriter.WriteString("address", address.ToString()); + jsonWriter.WriteString("healthCheck", healthCheck); + jsonWriter.WriteString("status", healthCheckResponse.Status.ToString()); if (healthCheckResponse.Status == HealthStatus.Failed) - { - jsonWriter.WritePropertyName("failureReason"); - jsonWriter.WriteValue(healthCheckResponse.FailureReason); - } + jsonWriter.WriteString("failureReason", healthCheckResponse.FailureReason); - jsonWriter.WritePropertyName("dateTime"); - jsonWriter.WriteValue(healthCheckResponse.DateTime); + jsonWriter.WriteString("dateTime", healthCheckResponse.DateTime); jsonWriter.WriteEndObject(); jsonWriter.Flush(); @@ -253,23 +232,14 @@ namespace Failover { using (MemoryStream mS = new MemoryStream()) { - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("address"); - jsonWriter.WriteValue(address.ToString()); - - jsonWriter.WritePropertyName("healthCheck"); - jsonWriter.WriteValue(healthCheck); - - jsonWriter.WritePropertyName("status"); - jsonWriter.WriteValue("Error"); - - jsonWriter.WritePropertyName("failureReason"); - jsonWriter.WriteValue(ex.ToString()); - - jsonWriter.WritePropertyName("dateTime"); - jsonWriter.WriteValue(DateTime.UtcNow); + jsonWriter.WriteString("address", address.ToString()); + jsonWriter.WriteString("healthCheck", healthCheck); + jsonWriter.WriteString("status", "Error"); + jsonWriter.WriteString("failureReason", ex.ToString()); + jsonWriter.WriteString("dateTime", DateTime.UtcNow); jsonWriter.WriteEndObject(); jsonWriter.Flush(); @@ -291,29 +261,18 @@ namespace Failover { using (MemoryStream mS = new MemoryStream()) { - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(domain); - - jsonWriter.WritePropertyName("recordType"); - jsonWriter.WriteValue(type.ToString()); - - jsonWriter.WritePropertyName("healthCheck"); - jsonWriter.WriteValue(healthCheck); - - jsonWriter.WritePropertyName("status"); - jsonWriter.WriteValue(healthCheckResponse.Status.ToString()); + jsonWriter.WriteString("domain", domain); + jsonWriter.WriteString("recordType", type.ToString()); + jsonWriter.WriteString("healthCheck", healthCheck); + jsonWriter.WriteString("status", healthCheckResponse.Status.ToString()); if (healthCheckResponse.Status == HealthStatus.Failed) - { - jsonWriter.WritePropertyName("failureReason"); - jsonWriter.WriteValue(healthCheckResponse.FailureReason); - } + jsonWriter.WriteString("failureReason", healthCheckResponse.FailureReason); - jsonWriter.WritePropertyName("dateTime"); - jsonWriter.WriteValue(healthCheckResponse.DateTime); + jsonWriter.WriteString("dateTime", healthCheckResponse.DateTime); jsonWriter.WriteEndObject(); jsonWriter.Flush(); @@ -335,26 +294,15 @@ namespace Failover { using (MemoryStream mS = new MemoryStream()) { - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(domain); - - jsonWriter.WritePropertyName("recordType"); - jsonWriter.WriteValue(type.ToString()); - - jsonWriter.WritePropertyName("healthCheck"); - jsonWriter.WriteValue(healthCheck); - - jsonWriter.WritePropertyName("status"); - jsonWriter.WriteValue("Error"); - - jsonWriter.WritePropertyName("failureReason"); - jsonWriter.WriteValue(ex.ToString()); - - jsonWriter.WritePropertyName("dateTime"); - jsonWriter.WriteValue(DateTime.UtcNow); + jsonWriter.WriteString("domain", domain); + jsonWriter.WriteString("recordType", type.ToString()); + jsonWriter.WriteString("healthCheck", healthCheck); + jsonWriter.WriteString("status", "Error"); + jsonWriter.WriteString("failureReason", ex.ToString()); + jsonWriter.WriteString("dateTime", DateTime.UtcNow); jsonWriter.WriteEndObject(); jsonWriter.Flush(); From 89d35cca70afba546e2754e655de9fd444e67786 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:43:14 +0530 Subject: [PATCH 009/191] GeoContinent: removed newtonsoft. --- Apps/GeoContinentApp/Address.cs | 141 ++++++++++++++++---------------- Apps/GeoContinentApp/CNAME.cs | 33 ++++---- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/Apps/GeoContinentApp/Address.cs b/Apps/GeoContinentApp/Address.cs index 65cd833c..8cf4f2bd 100644 --- a/Apps/GeoContinentApp/Address.cs +++ b/Apps/GeoContinentApp/Address.cs @@ -19,10 +19,10 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using MaxMind.GeoIP2.Responses; -using Newtonsoft.Json; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; @@ -82,86 +82,87 @@ namespace GeoContinent { case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonContinent = null; - - bool ecsUsed = false; - EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(); - if (requestECS is not null) + using (JsonDocument jsonDocument = JsonDocument.Parse(appRecordData)) { - if (_maxMind.DatabaseReader.TryCountry(requestECS.Address, out CountryResponse csResponse)) + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonContinent = default; + + bool ecsUsed = false; + EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(); + if (requestECS is not null) { - ecsUsed = true; - jsonContinent = jsonAppRecordData[csResponse.Continent.Code]; - if (jsonContinent is null) - jsonContinent = jsonAppRecordData["default"]; + if (_maxMind.DatabaseReader.TryCountry(requestECS.Address, out CountryResponse csResponse)) + { + ecsUsed = true; + if (!jsonAppRecordData.TryGetProperty(csResponse.Continent.Code, out jsonContinent)) + jsonAppRecordData.TryGetProperty("default", out jsonContinent); + } } - } - if (jsonContinent is null) - { - if (_maxMind.DatabaseReader.TryCountry(remoteEP.Address, out CountryResponse response)) + if (jsonContinent.ValueKind == JsonValueKind.Undefined) { - jsonContinent = jsonAppRecordData[response.Continent.Code]; - if (jsonContinent is null) - jsonContinent = jsonAppRecordData["default"]; + if (_maxMind.DatabaseReader.TryCountry(remoteEP.Address, out CountryResponse response)) + { + if (!jsonAppRecordData.TryGetProperty(response.Continent.Code, out jsonContinent)) + jsonAppRecordData.TryGetProperty("default", out jsonContinent); + } + else + { + jsonAppRecordData.TryGetProperty("default", out jsonContinent); + } + + if (jsonContinent.ValueKind == JsonValueKind.Undefined) + return Task.FromResult(null); + } + + List answers = new List(); + + switch (question.Type) + { + case DnsResourceRecordType.A: + foreach (JsonElement jsonAddress in jsonContinent.EnumerateArray()) + { + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); + + if (address.AddressFamily == AddressFamily.InterNetwork) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); + } + break; + + case DnsResourceRecordType.AAAA: + foreach (JsonElement jsonAddress in jsonContinent.EnumerateArray()) + { + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); + + if (address.AddressFamily == AddressFamily.InterNetworkV6) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); + } + break; + } + + if (answers.Count == 0) + return Task.FromResult(null); + + if (answers.Count > 1) + answers.Shuffle(); + + EDnsOption[] options; + + if (requestECS is null) + { + options = null; } else { - jsonContinent = jsonAppRecordData["default"]; + if (ecsUsed) + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.Address); + else + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } + + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } - if (jsonContinent is null) - return Task.FromResult(null); - - List answers = new List(); - - switch (question.Type) - { - case DnsResourceRecordType.A: - foreach (dynamic jsonAddress in jsonContinent) - { - IPAddress address = IPAddress.Parse(jsonAddress.Value); - - if (address.AddressFamily == AddressFamily.InterNetwork) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); - } - break; - - case DnsResourceRecordType.AAAA: - foreach (dynamic jsonAddress in jsonContinent) - { - IPAddress address = IPAddress.Parse(jsonAddress.Value); - - if (address.AddressFamily == AddressFamily.InterNetworkV6) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); - } - break; - } - - if (answers.Count == 0) - return Task.FromResult(null); - - if (answers.Count > 1) - answers.Shuffle(); - - EDnsOption[] options; - - if (requestECS is null) - { - options = null; - } - else - { - if (ecsUsed) - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.AddressValue); - else - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.AddressValue); - } - - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); - default: return Task.FromResult(null); } diff --git a/Apps/GeoContinentApp/CNAME.cs b/Apps/GeoContinentApp/CNAME.cs index 1893360b..da471dcb 100644 --- a/Apps/GeoContinentApp/CNAME.cs +++ b/Apps/GeoContinentApp/CNAME.cs @@ -19,10 +19,10 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using MaxMind.GeoIP2.Responses; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.EDnsOptions; @@ -76,8 +76,9 @@ namespace GeoContinent public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) { - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonContinent = null; + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonContinent = default; bool ecsUsed = false; EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(); @@ -86,30 +87,28 @@ namespace GeoContinent if (_maxMind.DatabaseReader.TryCountry(requestECS.Address, out CountryResponse csResponse)) { ecsUsed = true; - jsonContinent = jsonAppRecordData[csResponse.Continent.Code]; - if (jsonContinent is null) - jsonContinent = jsonAppRecordData["default"]; + if (!jsonAppRecordData.TryGetProperty(csResponse.Continent.Code, out jsonContinent)) + jsonAppRecordData.TryGetProperty("default", out jsonContinent); } } - if (jsonContinent is null) + if (jsonContinent.ValueKind == JsonValueKind.Undefined) { if (_maxMind.DatabaseReader.TryCountry(remoteEP.Address, out CountryResponse response)) { - jsonContinent = jsonAppRecordData[response.Continent.Code]; - if (jsonContinent is null) - jsonContinent = jsonAppRecordData["default"]; + if (!jsonAppRecordData.TryGetProperty(response.Continent.Code, out jsonContinent)) + jsonAppRecordData.TryGetProperty("default", out jsonContinent); } else { - jsonContinent = jsonAppRecordData["default"]; + jsonAppRecordData.TryGetProperty("default", out jsonContinent); } + + if (jsonContinent.ValueKind == JsonValueKind.Undefined) + return Task.FromResult(null); } - if (jsonContinent is null) - return Task.FromResult(null); - - string cname = jsonContinent.Value; + string cname = jsonContinent.GetString(); if (string.IsNullOrEmpty(cname)) return Task.FromResult(null); @@ -129,9 +128,9 @@ namespace GeoContinent else { if (ecsUsed) - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.AddressValue); + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.Address); else - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.AddressValue); + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); From 7ef157fe2300fc5c12718df30fd4b36c6140eb51 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:44:14 +0530 Subject: [PATCH 010/191] GeoCountry: removed netwonsoft. --- Apps/GeoCountryApp/Address.cs | 141 +++++++++++++++++----------------- Apps/GeoCountryApp/CNAME.cs | 33 ++++---- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/Apps/GeoCountryApp/Address.cs b/Apps/GeoCountryApp/Address.cs index ade2a668..6c5d9c3a 100644 --- a/Apps/GeoCountryApp/Address.cs +++ b/Apps/GeoCountryApp/Address.cs @@ -19,10 +19,10 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using MaxMind.GeoIP2.Responses; -using Newtonsoft.Json; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; @@ -82,86 +82,87 @@ namespace GeoCountry { case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonCountry = null; - - bool ecsUsed = false; - EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(); - if (requestECS is not null) + using (JsonDocument jsonDocument = JsonDocument.Parse(appRecordData)) { - if (_maxMind.DatabaseReader.TryCountry(requestECS.Address, out CountryResponse csResponse)) + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonCountry = default; + + bool ecsUsed = false; + EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(); + if (requestECS is not null) { - ecsUsed = true; - jsonCountry = jsonAppRecordData[csResponse.Country.IsoCode]; - if (jsonCountry is null) - jsonCountry = jsonAppRecordData["default"]; + if (_maxMind.DatabaseReader.TryCountry(requestECS.Address, out CountryResponse csResponse)) + { + ecsUsed = true; + if (!jsonAppRecordData.TryGetProperty(csResponse.Country.IsoCode, out jsonCountry)) + jsonAppRecordData.TryGetProperty("default", out jsonCountry); + } } - } - if (jsonCountry is null) - { - if (_maxMind.DatabaseReader.TryCountry(remoteEP.Address, out CountryResponse response)) + if (jsonCountry.ValueKind == JsonValueKind.Undefined) { - jsonCountry = jsonAppRecordData[response.Country.IsoCode]; - if (jsonCountry is null) - jsonCountry = jsonAppRecordData["default"]; + if (_maxMind.DatabaseReader.TryCountry(remoteEP.Address, out CountryResponse response)) + { + if (!jsonAppRecordData.TryGetProperty(response.Country.IsoCode, out jsonCountry)) + jsonAppRecordData.TryGetProperty("default", out jsonCountry); + } + else + { + jsonAppRecordData.TryGetProperty("default", out jsonCountry); + } + + if (jsonCountry.ValueKind == JsonValueKind.Undefined) + return Task.FromResult(null); + } + + List answers = new List(); + + switch (question.Type) + { + case DnsResourceRecordType.A: + foreach (JsonElement jsonAddress in jsonCountry.EnumerateArray()) + { + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); + + if (address.AddressFamily == AddressFamily.InterNetwork) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); + } + break; + + case DnsResourceRecordType.AAAA: + foreach (JsonElement jsonAddress in jsonCountry.EnumerateArray()) + { + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); + + if (address.AddressFamily == AddressFamily.InterNetworkV6) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); + } + break; + } + + if (answers.Count == 0) + return Task.FromResult(null); + + if (answers.Count > 1) + answers.Shuffle(); + + EDnsOption[] options; + + if (requestECS is null) + { + options = null; } else { - jsonCountry = jsonAppRecordData["default"]; + if (ecsUsed) + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.Address); + else + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } + + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } - if (jsonCountry is null) - return Task.FromResult(null); - - List answers = new List(); - - switch (question.Type) - { - case DnsResourceRecordType.A: - foreach (dynamic jsonAddress in jsonCountry) - { - IPAddress address = IPAddress.Parse(jsonAddress.Value); - - if (address.AddressFamily == AddressFamily.InterNetwork) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); - } - break; - - case DnsResourceRecordType.AAAA: - foreach (dynamic jsonAddress in jsonCountry) - { - IPAddress address = IPAddress.Parse(jsonAddress.Value); - - if (address.AddressFamily == AddressFamily.InterNetworkV6) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); - } - break; - } - - if (answers.Count == 0) - return Task.FromResult(null); - - if (answers.Count > 1) - answers.Shuffle(); - - EDnsOption[] options; - - if (requestECS is null) - { - options = null; - } - else - { - if (ecsUsed) - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.AddressValue); - else - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.AddressValue); - } - - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); - default: return Task.FromResult(null); } diff --git a/Apps/GeoCountryApp/CNAME.cs b/Apps/GeoCountryApp/CNAME.cs index 237b06e3..46440915 100644 --- a/Apps/GeoCountryApp/CNAME.cs +++ b/Apps/GeoCountryApp/CNAME.cs @@ -19,10 +19,10 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using MaxMind.GeoIP2.Responses; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.EDnsOptions; @@ -76,8 +76,9 @@ namespace GeoCountry public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) { - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonCountry = null; + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonCountry = default; bool ecsUsed = false; EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(); @@ -86,30 +87,28 @@ namespace GeoCountry if (_maxMind.DatabaseReader.TryCountry(requestECS.Address, out CountryResponse csResponse)) { ecsUsed = true; - jsonCountry = jsonAppRecordData[csResponse.Country.IsoCode]; - if (jsonCountry is null) - jsonCountry = jsonAppRecordData["default"]; + if (!jsonAppRecordData.TryGetProperty(csResponse.Country.IsoCode, out jsonCountry)) + jsonAppRecordData.TryGetProperty("default", out jsonCountry); } } - if (jsonCountry is null) + if (jsonCountry.ValueKind == JsonValueKind.Undefined) { if (_maxMind.DatabaseReader.TryCountry(remoteEP.Address, out CountryResponse response)) { - jsonCountry = jsonAppRecordData[response.Country.IsoCode]; - if (jsonCountry is null) - jsonCountry = jsonAppRecordData["default"]; + if (!jsonAppRecordData.TryGetProperty(response.Country.IsoCode, out jsonCountry)) + jsonAppRecordData.TryGetProperty("default", out jsonCountry); } else { - jsonCountry = jsonAppRecordData["default"]; + jsonAppRecordData.TryGetProperty("default", out jsonCountry); } + + if (jsonCountry.ValueKind == JsonValueKind.Undefined) + return Task.FromResult(null); } - if (jsonCountry is null) - return Task.FromResult(null); - - string cname = jsonCountry.Value; + string cname = jsonCountry.GetString(); if (string.IsNullOrEmpty(cname)) return Task.FromResult(null); @@ -129,9 +128,9 @@ namespace GeoCountry else { if (ecsUsed) - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.AddressValue); + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.Address); else - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.AddressValue); + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); From 36691a4ca1fc5d282a9376873e33600a6859b439 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:51:47 +0530 Subject: [PATCH 011/191] GeoDistance: removed netwonsoft. --- Apps/GeoDistanceApp/Address.cs | 118 +++++++++++++++++---------------- Apps/GeoDistanceApp/CNAME.cs | 29 ++++---- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/Apps/GeoDistanceApp/Address.cs b/Apps/GeoDistanceApp/Address.cs index 3e4c5dd3..93793773 100644 --- a/Apps/GeoDistanceApp/Address.cs +++ b/Apps/GeoDistanceApp/Address.cs @@ -20,11 +20,11 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using MaxMind.GeoIP2.Model; using MaxMind.GeoIP2.Responses; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; @@ -115,81 +115,85 @@ namespace GeoDistance if ((location is null) && _maxMind.DatabaseReader.TryCity(remoteEP.Address, out CityResponse response) && response.Location.HasCoordinates) location = response.Location; - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonClosestServer = null; - - if (location is null) + using (JsonDocument jsonDocument = JsonDocument.Parse(appRecordData)) { - jsonClosestServer = jsonAppRecordData[0]; - } - else - { - double lastDistance = double.MaxValue; + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonClosestServer = default; - foreach (dynamic jsonServer in jsonAppRecordData) + if (location is null) { - double lat = Convert.ToDouble(jsonServer.lat.Value); - double @long = Convert.ToDouble(jsonServer.@long.Value); + if (jsonAppRecordData.GetArrayLength() > 0) + jsonClosestServer = jsonAppRecordData[0]; + } + else + { + double lastDistance = double.MaxValue; - double distance = GetDistance(lat, @long, location.Latitude.Value, location.Longitude.Value); - - if (distance < lastDistance) + foreach (JsonElement jsonServer in jsonAppRecordData.EnumerateArray()) { - lastDistance = distance; - jsonClosestServer = jsonServer; + double lat = Convert.ToDouble(jsonServer.GetProperty("lat").GetString()); + double @long = Convert.ToDouble(jsonServer.GetProperty("long").GetString()); + + double distance = GetDistance(lat, @long, location.Latitude.Value, location.Longitude.Value); + + if (distance < lastDistance) + { + lastDistance = distance; + jsonClosestServer = jsonServer; + } } } - } - if (jsonClosestServer is null) - return Task.FromResult(null); + if (jsonClosestServer.ValueKind == JsonValueKind.Undefined) + return Task.FromResult(null); - List answers = new List(); + List answers = new List(); - switch (question.Type) - { - case DnsResourceRecordType.A: - foreach (dynamic jsonAddress in jsonClosestServer.addresses) - { - IPAddress address = IPAddress.Parse(jsonAddress.Value); + switch (question.Type) + { + case DnsResourceRecordType.A: + foreach (JsonElement jsonAddress in jsonClosestServer.GetProperty("addresses").EnumerateArray()) + { + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); - if (address.AddressFamily == AddressFamily.InterNetwork) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); - } - break; + if (address.AddressFamily == AddressFamily.InterNetwork) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); + } + break; - case DnsResourceRecordType.AAAA: - foreach (dynamic jsonAddress in jsonClosestServer.addresses) - { - IPAddress address = IPAddress.Parse(jsonAddress.Value); + case DnsResourceRecordType.AAAA: + foreach (JsonElement jsonAddress in jsonClosestServer.GetProperty("addresses").EnumerateArray()) + { + IPAddress address = IPAddress.Parse(jsonAddress.GetString()); - if (address.AddressFamily == AddressFamily.InterNetworkV6) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); - } - break; - } + if (address.AddressFamily == AddressFamily.InterNetworkV6) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); + } + break; + } - if (answers.Count == 0) - return Task.FromResult(null); + if (answers.Count == 0) + return Task.FromResult(null); - if (answers.Count > 1) - answers.Shuffle(); + if (answers.Count > 1) + answers.Shuffle(); - EDnsOption[] options; + EDnsOption[] options; - if (requestECS is null) - { - options = null; - } - else - { - if (ecsUsed) - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.AddressValue); + if (requestECS is null) + { + options = null; + } else - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.AddressValue); - } + { + if (ecsUsed) + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.Address); + else + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); + } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + } default: return Task.FromResult(null); diff --git a/Apps/GeoDistanceApp/CNAME.cs b/Apps/GeoDistanceApp/CNAME.cs index ca3c7783..ceaeb612 100644 --- a/Apps/GeoDistanceApp/CNAME.cs +++ b/Apps/GeoDistanceApp/CNAME.cs @@ -20,11 +20,12 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using MaxMind.GeoIP2.Model; using MaxMind.GeoIP2.Responses; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.EDnsOptions; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -108,21 +109,23 @@ namespace GeoDistance if ((location is null) && _maxMind.DatabaseReader.TryCity(remoteEP.Address, out CityResponse response) && response.Location.HasCoordinates) location = response.Location; - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonClosestServer = null; + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonClosestServer = default; if (location is null) { - jsonClosestServer = jsonAppRecordData[0]; + if (jsonAppRecordData.GetArrayLength() > 0) + jsonClosestServer = jsonAppRecordData[0]; } else { double lastDistance = double.MaxValue; - foreach (dynamic jsonServer in jsonAppRecordData) + foreach (JsonElement jsonServer in jsonAppRecordData.EnumerateArray()) { - double lat = Convert.ToDouble(jsonServer.lat.Value); - double @long = Convert.ToDouble(jsonServer.@long.Value); + double lat = Convert.ToDouble(jsonServer.GetProperty("lat").GetString()); + double @long = Convert.ToDouble(jsonServer.GetProperty("long").GetString()); double distance = GetDistance(lat, @long, location.Latitude.Value, location.Longitude.Value); @@ -134,14 +137,10 @@ namespace GeoDistance } } - if (jsonClosestServer is null) + if (jsonClosestServer.ValueKind == JsonValueKind.Undefined) return Task.FromResult(null); - dynamic jsonCname = jsonClosestServer.cname; - if (jsonCname is null) - return Task.FromResult(null); - - string cname = jsonCname.Value; + string cname = jsonClosestServer.GetPropertyValue("cname", null); if (string.IsNullOrEmpty(cname)) return Task.FromResult(null); @@ -161,9 +160,9 @@ namespace GeoDistance else { if (ecsUsed) - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.AddressValue); + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, requestECS.SourcePrefixLength, requestECS.Address); else - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.AddressValue); + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); From 724a13484eb6e2410b6bb32308d610861f601da8 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:52:54 +0530 Subject: [PATCH 012/191] NoData: removed newtonsoft. --- Apps/NoDataApp/App.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Apps/NoDataApp/App.cs b/Apps/NoDataApp/App.cs index 09f4584c..0f9e294d 100644 --- a/Apps/NoDataApp/App.cs +++ b/Apps/NoDataApp/App.cs @@ -18,9 +18,9 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -52,11 +52,12 @@ namespace NoData if (question.Name.Equals(appRecordName, StringComparison.OrdinalIgnoreCase)) { - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; - foreach (dynamic jsonBlockedType in jsonAppRecordData.blockedTypes) + foreach (JsonElement jsonBlockedType in jsonAppRecordData.GetProperty("blockedTypes").EnumerateArray()) { - DnsResourceRecordType blockedType = Enum.Parse(jsonBlockedType.Value, true); + DnsResourceRecordType blockedType = Enum.Parse(jsonBlockedType.GetString(), true); if ((blockedType == question.Type) || (blockedType == DnsResourceRecordType.ANY)) return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question)); } From 7759893bbc2c9eae65af46309931da123a2cd809 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:53:47 +0530 Subject: [PATCH 013/191] NxDomain: removed newtonsoft. --- Apps/NxDomainApp/App.cs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/Apps/NxDomainApp/App.cs b/Apps/NxDomainApp/App.cs index 51c52cb7..2b6af49f 100644 --- a/Apps/NxDomainApp/App.cs +++ b/Apps/NxDomainApp/App.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2021 Shreyas Zare (shreyas@technitium.com) +Copyright (C) 2022 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 @@ -18,10 +18,12 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -51,16 +53,6 @@ namespace NxDomain #region private - private static IReadOnlyDictionary ReadJsonDomainArray(dynamic jsonDomainArray) - { - Dictionary domains = new Dictionary(jsonDomainArray.Count); - - foreach (dynamic jsonDomain in jsonDomainArray) - domains.TryAdd(jsonDomain.Value, null); - - return domains; - } - private static string GetParentZone(string domain) { int i = domain.IndexOf('.'); @@ -100,18 +92,21 @@ namespace NxDomain { _soaRecord = new DnsSOARecordData(dnsServer.ServerDomain, "hostadmin@" + dnsServer.ServerDomain, 1, 14400, 3600, 604800, 60); - dynamic jsonConfig = JsonConvert.DeserializeObject(config); + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; - _enableBlocking = jsonConfig.enableBlocking.Value; - _allowTxtBlockingReport = jsonConfig.allowTxtBlockingReport.Value; - - _blockListZone = ReadJsonDomainArray(jsonConfig.blocked); + _enableBlocking = jsonConfig.GetProperty("enableBlocking").GetBoolean(); + _allowTxtBlockingReport = jsonConfig.GetProperty("allowTxtBlockingReport").GetBoolean(); + _blockListZone = jsonConfig.ReadArrayAsMap("blocked", delegate (JsonElement jsonDomainName) { return new Tuple(jsonDomainName.GetString(), null); }); return Task.CompletedTask; } public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed) { + if (!_enableBlocking) + return Task.FromResult(null); + DnsQuestionRecord question = request.Question[0]; if (!IsZoneBlocked(question.Name, out string blockedDomain)) From fa50efc8ee1c5041c6a7bc59bc6d768d2efe2378 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 11:54:35 +0530 Subject: [PATCH 014/191] QueryLogsSqlite: removed newtonsoft. --- Apps/QueryLogsSqliteApp/App.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Apps/QueryLogsSqliteApp/App.cs b/Apps/QueryLogsSqliteApp/App.cs index f59e7186..bb55fdc0 100644 --- a/Apps/QueryLogsSqliteApp/App.cs +++ b/Apps/QueryLogsSqliteApp/App.cs @@ -19,12 +19,12 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using Microsoft.Data.Sqlite; -using Newtonsoft.Json; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Net; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using TechnitiumLibrary.Net.Dns; @@ -192,13 +192,14 @@ namespace QueryLogsSqlite { _dnsServer = dnsServer; - dynamic jsonConfig = JsonConvert.DeserializeObject(config); + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; - _enableLogging = jsonConfig.enableLogging.Value; - _maxLogDays = Convert.ToInt32(jsonConfig.maxLogDays.Value); + _enableLogging = jsonConfig.GetProperty("enableLogging").GetBoolean(); + _maxLogDays = jsonConfig.GetProperty("maxLogDays").GetInt32(); - string sqliteDbPath = jsonConfig.sqliteDbPath.Value; - string connectionString = jsonConfig.connectionString.Value; + string sqliteDbPath = jsonConfig.GetProperty("sqliteDbPath").GetString(); + string connectionString = jsonConfig.GetProperty("connectionString").GetString(); if (!Path.IsPathRooted(sqliteDbPath)) sqliteDbPath = Path.Combine(_dnsServer.ApplicationFolder, sqliteDbPath); From 34e758315869b5b9357ca4198bf1137f277d4e70 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:02:18 +0530 Subject: [PATCH 015/191] SplitHorizon: removed newtonsoft. --- Apps/SplitHorizonApp/AddressTranslation.cs | 88 ++++++------ Apps/SplitHorizonApp/SimpleAddress.cs | 160 +++++++++++---------- Apps/SplitHorizonApp/SimpleCNAME.cs | 28 ++-- 3 files changed, 140 insertions(+), 136 deletions(-) diff --git a/Apps/SplitHorizonApp/AddressTranslation.cs b/Apps/SplitHorizonApp/AddressTranslation.cs index 3491e1fb..ca7d81a1 100644 --- a/Apps/SplitHorizonApp/AddressTranslation.cs +++ b/Apps/SplitHorizonApp/AddressTranslation.cs @@ -18,12 +18,13 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -106,15 +107,18 @@ namespace SplitHorizon await File.WriteAllTextAsync(Path.Combine(dnsServer.ApplicationFolder, "dnsApp.config"), config); } - dynamic jsonConfig = JsonConvert.DeserializeObject(config); - - if (jsonConfig.enableAddressTranslation is null) + do { - //update old config with default config - config = config.TrimEnd(' ', '\t', '\r', '\n'); - config = config.Substring(0, config.Length - 1); - config = config.TrimEnd(' ', '\t', '\r', '\n'); - config += """ + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; + + if (!jsonConfig.TryGetProperty("enableAddressTranslation", out _)) + { + //update old config with default config + config = config.TrimEnd(' ', '\t', '\r', '\n'); + config = config.Substring(0, config.Length - 1); + config = config.TrimEnd(' ', '\t', '\r', '\n'); + config += """ , "enableAddressTranslation": false, "networkGroupMap": { @@ -153,43 +157,31 @@ namespace SplitHorizon ] } """; - await File.WriteAllTextAsync(Path.Combine(dnsServer.ApplicationFolder, "dnsApp.config"), config); + await File.WriteAllTextAsync(Path.Combine(dnsServer.ApplicationFolder, "dnsApp.config"), config); - jsonConfig = JsonConvert.DeserializeObject(config); - } - - _enableAddressTranslation = jsonConfig.enableAddressTranslation.Value; - - { - Dictionary networkGroupMap = new Dictionary(); - - foreach (dynamic jsonProperty in jsonConfig.networkGroupMap) - { - string network = jsonProperty.Name; - string group = jsonProperty.Value; - - if (!NetworkAddress.TryParse(network, out NetworkAddress networkAddress)) - throw new InvalidOperationException("Network group map contains an invalid network address: " + network); - - networkGroupMap.Add(networkAddress, group); + //reparse config + continue; } - _networkGroupMap = networkGroupMap; - } + _enableAddressTranslation = jsonConfig.GetProperty("enableAddressTranslation").GetBoolean(); - { - Dictionary groups = new Dictionary(); + _networkGroupMap = jsonConfig.ReadObjectAsMap("networkGroupMap", delegate (string strNetworkAddress, JsonElement jsonGroupName) + { + if (!NetworkAddress.TryParse(strNetworkAddress, out NetworkAddress networkAddress)) + throw new InvalidOperationException("Network group map contains an invalid network address: " + strNetworkAddress); - foreach (dynamic jsonGroup in jsonConfig.groups) + return new Tuple(networkAddress, jsonGroupName.GetString()); + }); + + _groups = jsonConfig.ReadArrayAsMap("groups", delegate (JsonElement jsonGroup) { Group group = new Group(jsonGroup); - groups.Add(group.Name, group); - } + return new Tuple(group.Name, group); + }); - _groups = groups; + break; } - - return; + while (true); } public Task PostProcessAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, DnsDatagram response) @@ -245,7 +237,7 @@ namespace SplitHorizon IPAddress externalIp = (answer.RDATA as DnsARecordData).Address; if (group.ExternalToInternalTranslation.TryGetValue(externalIp, out IPAddress internalIp)) - newAnswer.Add(new DnsResourceRecord(answer.Name, answer.Type, answer.Class, answer.TtlValue, new DnsARecordData(internalIp))); + newAnswer.Add(new DnsResourceRecord(answer.Name, answer.Type, answer.Class, answer.TTL, new DnsARecordData(internalIp))); else newAnswer.Add(answer); } @@ -256,7 +248,7 @@ namespace SplitHorizon IPAddress externalIp = (answer.RDATA as DnsAAAARecordData).Address; if (group.ExternalToInternalTranslation.TryGetValue(externalIp, out IPAddress internalIp)) - newAnswer.Add(new DnsResourceRecord(answer.Name, answer.Type, answer.Class, answer.TtlValue, new DnsAAAARecordData(internalIp))); + newAnswer.Add(new DnsResourceRecord(answer.Name, answer.Type, answer.Class, answer.TTL, new DnsAAAARecordData(internalIp))); else newAnswer.Add(answer); } @@ -332,21 +324,23 @@ namespace SplitHorizon #region constructor - public Group(dynamic jsonGroup) + public Group(JsonElement jsonGroup) { - _name = jsonGroup.name.Value; - _enabled = jsonGroup.enabled.Value; - _translateReverseLookups = jsonGroup.translateReverseLookups.Value; + _name = jsonGroup.GetProperty("name").GetString(); + _enabled = jsonGroup.GetProperty("enabled").GetBoolean(); + _translateReverseLookups = jsonGroup.GetProperty("translateReverseLookups").GetBoolean(); + + JsonElement jsonExternalToInternalTranslation = jsonGroup.GetProperty("externalToInternalTranslation"); if (_translateReverseLookups) { Dictionary externalToInternalTranslation = new Dictionary(); Dictionary internalToExternalTranslation = new Dictionary(); - foreach (dynamic jsonProperty in jsonGroup.externalToInternalTranslation) + foreach (JsonProperty jsonProperty in jsonExternalToInternalTranslation.EnumerateObject()) { string strExternalIp = jsonProperty.Name; - string strInternalIp = jsonProperty.Value; + string strInternalIp = jsonProperty.Value.GetString(); IPAddress externalIp = IPAddress.Parse(strExternalIp); IPAddress internalIp = IPAddress.Parse(strInternalIp); @@ -362,10 +356,10 @@ namespace SplitHorizon { Dictionary externalToInternalTranslation = new Dictionary(); - foreach (dynamic jsonProperty in jsonGroup.externalToInternalTranslation) + foreach (JsonProperty jsonProperty in jsonExternalToInternalTranslation.EnumerateObject()) { string strExternalIp = jsonProperty.Name; - string strInternalIp = jsonProperty.Value; + string strInternalIp = jsonProperty.Value.GetString(); IPAddress externalIp = IPAddress.Parse(strExternalIp); IPAddress internalIp = IPAddress.Parse(strInternalIp); diff --git a/Apps/SplitHorizonApp/SimpleAddress.cs b/Apps/SplitHorizonApp/SimpleAddress.cs index be1e5c62..c0257459 100644 --- a/Apps/SplitHorizonApp/SimpleAddress.cs +++ b/Apps/SplitHorizonApp/SimpleAddress.cs @@ -18,11 +18,11 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net; @@ -105,28 +105,24 @@ namespace SplitHorizon await File.WriteAllTextAsync(Path.Combine(dnsServer.ApplicationFolder, "dnsApp.config"), config); } - dynamic jsonConfig = JsonConvert.DeserializeObject(config); + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; - dynamic jsonNetworks = jsonConfig.networks; - if (jsonNetworks is null) - { - _networks = new Dictionary>(1); - } - else + if (jsonConfig.TryGetProperty("networks", out JsonElement jsonNetworks)) { Dictionary> networks = new Dictionary>(); - foreach (dynamic jsonProperty in jsonNetworks) + foreach (JsonProperty jsonProperty in jsonNetworks.EnumerateObject()) { string networkName = jsonProperty.Name; - dynamic jsonNetworkAddresses = jsonProperty.Value; - if (jsonNetworkAddresses is not null) + JsonElement jsonNetworkAddresses = jsonProperty.Value; + if (jsonNetworkAddresses.ValueKind == JsonValueKind.Array) { - List networkAddresses = new List(); + List networkAddresses = new List(jsonNetworkAddresses.GetArrayLength()); - foreach (dynamic jsonNetworkAddress in jsonNetworkAddresses) - networkAddresses.Add(NetworkAddress.Parse(jsonNetworkAddress.Value)); + foreach (JsonElement jsonNetworkAddress in jsonNetworkAddresses.EnumerateArray()) + networkAddresses.Add(NetworkAddress.Parse(jsonNetworkAddress.GetString())); networks.TryAdd(networkName, networkAddresses); } @@ -134,6 +130,10 @@ namespace SplitHorizon _networks = networks; } + else + { + _networks = new Dictionary>(1); + } } public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) @@ -143,82 +143,88 @@ namespace SplitHorizon { case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonAddresses = null; - - NetworkAddress selectedNetwork = null; - - foreach (dynamic jsonProperty in jsonAppRecordData) + using (JsonDocument jsonDocument = JsonDocument.Parse(appRecordData)) { - string name = jsonProperty.Name; + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonAddresses = default; - if ((name == "public") || (name == "private")) - continue; + NetworkAddress selectedNetwork = null; - if (_networks.TryGetValue(name, out List networkAddresses)) + foreach (JsonProperty jsonProperty in jsonAppRecordData.EnumerateObject()) { - foreach (NetworkAddress networkAddress in networkAddresses) + string name = jsonProperty.Name; + + if ((name == "public") || (name == "private")) + continue; + + if (_networks.TryGetValue(name, out List networkAddresses)) { - if (networkAddress.Contains(remoteEP.Address)) + foreach (NetworkAddress networkAddress in networkAddresses) { - jsonAddresses = jsonProperty.Value; + if (networkAddress.Contains(remoteEP.Address)) + { + jsonAddresses = jsonProperty.Value; + break; + } + } + + if (jsonAddresses.ValueKind != JsonValueKind.Undefined) break; + } + else if (NetworkAddress.TryParse(name, out NetworkAddress networkAddress)) + { + if (networkAddress.Contains(remoteEP.Address) && ((selectedNetwork is null) || (networkAddress.PrefixLength > selectedNetwork.PrefixLength))) + { + selectedNetwork = networkAddress; + jsonAddresses = jsonProperty.Value; } } + } - if (jsonAddresses is not null) + if (jsonAddresses.ValueKind == JsonValueKind.Undefined) + { + if (NetUtilities.IsPrivateIP(remoteEP.Address)) + { + if (!jsonAppRecordData.TryGetProperty("private", out jsonAddresses)) + return Task.FromResult(null); + } + else + { + if (!jsonAppRecordData.TryGetProperty("public", out jsonAddresses)) + return Task.FromResult(null); + } + } + + List answers = new List(); + + switch (question.Type) + { + case DnsResourceRecordType.A: + foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray()) + { + if (IPAddress.TryParse(jsonAddress.GetString(), out IPAddress address) && (address.AddressFamily == AddressFamily.InterNetwork)) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); + } + break; + + case DnsResourceRecordType.AAAA: + foreach (JsonElement jsonAddress in jsonAddresses.EnumerateArray()) + { + if (IPAddress.TryParse(jsonAddress.GetString(), out IPAddress address) && (address.AddressFamily == AddressFamily.InterNetworkV6)) + answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); + } break; } - else if (NetworkAddress.TryParse(name, out NetworkAddress networkAddress)) - { - if (networkAddress.Contains(remoteEP.Address) && ((selectedNetwork is null) || (networkAddress.PrefixLength > selectedNetwork.PrefixLength))) - { - selectedNetwork = networkAddress; - jsonAddresses = jsonProperty.Value; - } - } - } - if (jsonAddresses is null) - { - if (NetUtilities.IsPrivateIP(remoteEP.Address)) - jsonAddresses = jsonAppRecordData.@private; - else - jsonAddresses = jsonAppRecordData.@public; - - if (jsonAddresses is null) + if (answers.Count == 0) return Task.FromResult(null); + + if (answers.Count > 1) + answers.Shuffle(); + + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); } - List answers = new List(); - - switch (question.Type) - { - case DnsResourceRecordType.A: - foreach (dynamic jsonAddress in jsonAddresses) - { - if (IPAddress.TryParse(jsonAddress.Value, out IPAddress address) && (address.AddressFamily == AddressFamily.InterNetwork)) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address))); - } - break; - - case DnsResourceRecordType.AAAA: - foreach (dynamic jsonAddress in jsonAddresses) - { - if (IPAddress.TryParse(jsonAddress.Value, out IPAddress address) && (address.AddressFamily == AddressFamily.InterNetworkV6)) - answers.Add(new DnsResourceRecord(question.Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address))); - } - break; - } - - if (answers.Count == 0) - return Task.FromResult(null); - - if (answers.Count > 1) - answers.Shuffle(); - - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); - default: return Task.FromResult(null); } @@ -240,15 +246,15 @@ namespace SplitHorizon { return @"{ ""public"": [ - ""1.1.1.1"", + ""1.1.1.1"", ""2.2.2.2"" ], ""private"": [ - ""192.168.1.1"", + ""192.168.1.1"", ""::1"" ], ""custom-networks"": [ - ""172.16.1.1"", + ""172.16.1.1"" ], ""10.0.0.0/8"": [ ""10.1.1.1"" diff --git a/Apps/SplitHorizonApp/SimpleCNAME.cs b/Apps/SplitHorizonApp/SimpleCNAME.cs index f7e62db0..0ce8cb6e 100644 --- a/Apps/SplitHorizonApp/SimpleCNAME.cs +++ b/Apps/SplitHorizonApp/SimpleCNAME.cs @@ -18,10 +18,10 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; @@ -50,12 +50,13 @@ namespace SplitHorizon public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) { - dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); - dynamic jsonCname = null; + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; + JsonElement jsonCname = default; NetworkAddress selectedNetwork = null; - foreach (dynamic jsonProperty in jsonAppRecordData) + foreach (JsonProperty jsonProperty in jsonAppRecordData.EnumerateObject()) { string name = jsonProperty.Name; @@ -73,7 +74,7 @@ namespace SplitHorizon } } - if (jsonCname is not null) + if (jsonCname.ValueKind != JsonValueKind.Undefined) break; } else if (NetworkAddress.TryParse(name, out NetworkAddress networkAddress)) @@ -86,18 +87,21 @@ namespace SplitHorizon } } - if (jsonCname is null) + if (jsonCname.ValueKind == JsonValueKind.Undefined) { if (NetUtilities.IsPrivateIP(remoteEP.Address)) - jsonCname = jsonAppRecordData.@private; + { + if (!jsonAppRecordData.TryGetProperty("private", out jsonCname)) + return Task.FromResult(null); + } else - jsonCname = jsonAppRecordData.@public; - - if (jsonCname is null) - return Task.FromResult(null); + { + if (!jsonAppRecordData.TryGetProperty("public", out jsonCname)) + return Task.FromResult(null); + } } - string cname = jsonCname.Value; + string cname = jsonCname.GetString(); if (string.IsNullOrEmpty(cname)) return Task.FromResult(null); From c9c57f2167fffbc20925b897990d792c6e9a5fda Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:04:26 +0530 Subject: [PATCH 016/191] VendorSpecificInformationOption: updated code to accept hex string in both colon separator and normal format . --- .../VendorSpecificInformationOption.cs | 51 ++----------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/DnsServerCore/Dhcp/Options/VendorSpecificInformationOption.cs b/DnsServerCore/Dhcp/Options/VendorSpecificInformationOption.cs index a9de2681..cb7c83da 100644 --- a/DnsServerCore/Dhcp/Options/VendorSpecificInformationOption.cs +++ b/DnsServerCore/Dhcp/Options/VendorSpecificInformationOption.cs @@ -18,7 +18,6 @@ along with this program. If not, see . */ using System; -using System.Globalization; using System.IO; using TechnitiumLibrary.IO; @@ -37,7 +36,10 @@ namespace DnsServerCore.Dhcp.Options public VendorSpecificInformationOption(string hexInfo) : base(DhcpOptionCode.VendorSpecificInformation) { - _information = ParseHexString(hexInfo); + if (hexInfo.Contains(':')) + _information = ParseColonHexString(hexInfo); + else + _information = Convert.FromHexString(hexInfo); } public VendorSpecificInformationOption(byte[] information) @@ -52,42 +54,6 @@ namespace DnsServerCore.Dhcp.Options #endregion - #region private - - private static byte[] ParseHexString(string value) - { - int i; - int j = -1; - string strHex; - int b; - - using (MemoryStream mS = new MemoryStream()) - { - while (true) - { - i = value.IndexOf(':', j + 1); - if (i < 0) - i = value.Length; - - strHex = value.Substring(j + 1, i - j - 1); - - if (!int.TryParse(strHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b) || (b < byte.MinValue) || (b > byte.MaxValue)) - throw new InvalidDataException("VendorSpecificInformation option data must be a colon (:) separated hex string."); - - mS.WriteByte((byte)b); - - if (i == value.Length) - break; - - j = i; - } - - return mS.ToArray(); - } - } - - #endregion - #region protected protected override void ParseOptionValue(Stream s) @@ -102,15 +68,6 @@ namespace DnsServerCore.Dhcp.Options #endregion - #region public - - public override string ToString() - { - return BitConverter.ToString(_information).Replace("-", ":"); - } - - #endregion - #region properties public byte[] Information From 9562964b824d13f63b75223318baece074f3f185 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:04:53 +0530 Subject: [PATCH 017/191] implemented TftpServerAddressOption option. --- .../Dhcp/Options/TftpServerAddressOption.cs | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 DnsServerCore/Dhcp/Options/TftpServerAddressOption.cs diff --git a/DnsServerCore/Dhcp/Options/TftpServerAddressOption.cs b/DnsServerCore/Dhcp/Options/TftpServerAddressOption.cs new file mode 100644 index 00000000..67588f1f --- /dev/null +++ b/DnsServerCore/Dhcp/Options/TftpServerAddressOption.cs @@ -0,0 +1,79 @@ +/* +Technitium DNS Server +Copyright (C) 2022 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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using System.Collections.Generic; +using System.IO; +using System.Net; +using TechnitiumLibrary.IO; + +namespace DnsServerCore.Dhcp.Options +{ + class TftpServerAddressOption : DhcpOption + { + #region variables + + IReadOnlyCollection _addresses; + + #endregion + + #region constructor + + public TftpServerAddressOption(IReadOnlyCollection addresses) + : base(DhcpOptionCode.TftpServerAddress) + { + _addresses = addresses; + } + + public TftpServerAddressOption(Stream s) + : base(DhcpOptionCode.TftpServerAddress, s) + { } + + #endregion + + #region protected + + protected override void ParseOptionValue(Stream s) + { + if ((s.Length % 4 != 0) || (s.Length < 4)) + throw new InvalidDataException(); + + IPAddress[] addresses = new IPAddress[s.Length / 4]; + + for (int i = 0; i < addresses.Length; i++) + addresses[i] = new IPAddress(s.ReadBytes(4)); + + _addresses = addresses; + } + + protected override void WriteOptionValue(Stream s) + { + foreach (IPAddress address in _addresses) + s.Write(address.GetAddressBytes()); + } + + #endregion + + #region properties + + public IReadOnlyCollection Addresses + { get { return _addresses; } } + + #endregion + } +} From 3f9f7db65bdf98d8b60d49f67352c68c9dbda7bc Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:05:50 +0530 Subject: [PATCH 018/191] DhcpOption: Implemented support for generic option and TftpServerAddress option. --- DnsServerCore/Dhcp/DhcpOption.cs | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/DnsServerCore/Dhcp/DhcpOption.cs b/DnsServerCore/Dhcp/DhcpOption.cs index ea77a287..8792de38 100644 --- a/DnsServerCore/Dhcp/DhcpOption.cs +++ b/DnsServerCore/Dhcp/DhcpOption.cs @@ -19,6 +19,7 @@ along with this program. If not, see . using DnsServerCore.Dhcp.Options; using System; +using System.Globalization; using System.IO; using TechnitiumLibrary.IO; @@ -105,6 +106,7 @@ namespace DnsServerCore.Dhcp DomainSearch = 119, ClasslessStaticRoute = 121, CAPWAPAccessControllerAddresses = 138, + TftpServerAddress = 150, End = 255 } @@ -119,6 +121,28 @@ namespace DnsServerCore.Dhcp #region constructor + public DhcpOption(DhcpOptionCode code, string hexValue) + { + if (hexValue is null) + throw new ArgumentNullException(nameof(hexValue)); + + _code = code; + + if (hexValue.Contains(':')) + _value = ParseColonHexString(hexValue); + else + _value = Convert.FromHexString(hexValue); + } + + public DhcpOption(DhcpOptionCode code, byte[] value) + { + if (value is null) + throw new ArgumentNullException(nameof(value)); + + _code = code; + _value = value; + } + protected DhcpOption(DhcpOptionCode code, Stream s) { _code = code; @@ -223,6 +247,9 @@ namespace DnsServerCore.Dhcp case DhcpOptionCode.CAPWAPAccessControllerAddresses: return new CAPWAPAccessControllerOption(s); + case DhcpOptionCode.TftpServerAddress: + return new TftpServerAddressOption(s); + case DhcpOptionCode.Pad: case DhcpOptionCode.End: return new DhcpOption(optionCode); @@ -233,6 +260,38 @@ namespace DnsServerCore.Dhcp } } + protected static byte[] ParseColonHexString(string value) + { + int i; + int j = -1; + string strHex; + int b; + + using (MemoryStream mS = new MemoryStream()) + { + while (true) + { + i = value.IndexOf(':', j + 1); + if (i < 0) + i = value.Length; + + strHex = value.Substring(j + 1, i - j - 1); + + if (!int.TryParse(strHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b) || (b < byte.MinValue) || (b > byte.MaxValue)) + throw new InvalidDataException("VendorSpecificInformation option data must be a colon (:) separated hex string."); + + mS.WriteByte((byte)b); + + if (i == value.Length) + break; + + j = i; + } + + return mS.ToArray(); + } + } + #endregion #region internal @@ -321,6 +380,9 @@ namespace DnsServerCore.Dhcp public DhcpOptionCode Code { get { return _code; } } + public byte[] RawValue + { get { return _value; } } + #endregion } } From f08b489476dd8334be7b6512e7fe10a1aa853865 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:07:34 +0530 Subject: [PATCH 019/191] Scope: implemented support for TFTP server address and generic options. --- DnsServerCore/Dhcp/Scope.cs | 104 +++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/DnsServerCore/Dhcp/Scope.cs b/DnsServerCore/Dhcp/Scope.cs index a2cd9afb..9ff638a7 100644 --- a/DnsServerCore/Dhcp/Scope.cs +++ b/DnsServerCore/Dhcp/Scope.cs @@ -76,8 +76,10 @@ namespace DnsServerCore.Dhcp IReadOnlyCollection _staticRoutes; IReadOnlyDictionary _vendorInfo; IReadOnlyCollection _capwapAcIpAddresses; + IReadOnlyCollection _tftpServerAddreses; //advanced options + IReadOnlyCollection _genericOptions; IReadOnlyCollection _exclusions; readonly ConcurrentDictionary _reservedLeases = new ConcurrentDictionary(); bool _allowOnlyReservedLeases; @@ -130,6 +132,7 @@ namespace DnsServerCore.Dhcp case 5: case 6: case 7: + case 8: _name = bR.ReadShortString(); _enabled = bR.ReadBoolean(); @@ -299,6 +302,40 @@ namespace DnsServerCore.Dhcp } } + if (version >= 8) + { + int count = bR.ReadByte(); + if (count > 0) + { + IPAddress[] tftpServerAddreses = new IPAddress[count]; + + for (int i = 0; i < count; i++) + tftpServerAddreses[i] = IPAddressExtension.ReadFrom(bR); + + _tftpServerAddreses = tftpServerAddreses; + } + } + + if (version >= 8) + { + int count = bR.ReadByte(); + if (count > 0) + { + DhcpOption[] genericOptions = new DhcpOption[count]; + + for (int i = 0; i < count; i++) + { + DhcpOptionCode code = (DhcpOptionCode)bR.ReadByte(); + short length = bR.ReadInt16(); + byte[] value = bR.ReadBytes(length); + + genericOptions[i] = new DhcpOption(code, value); + } + + _genericOptions = genericOptions; + } + } + { int count = bR.ReadByte(); if (count > 0) @@ -1121,6 +1158,27 @@ namespace DnsServerCore.Dhcp options.Add(new CAPWAPAccessControllerOption(_capwapAcIpAddresses)); break; + + case DhcpOptionCode.TftpServerAddress: + if (_tftpServerAddreses is not null) + options.Add(new TftpServerAddressOption(_tftpServerAddreses)); + + break; + + default: + if (_genericOptions is not null) + { + foreach (DhcpOption genericOption in _genericOptions) + { + if (optionCode == genericOption.Code) + { + options.Add(genericOption); + break; + } + } + } + + break; } } } @@ -1429,7 +1487,7 @@ namespace DnsServerCore.Dhcp public void WriteTo(BinaryWriter bW) { bW.Write(Encoding.ASCII.GetBytes("SC")); - bW.Write((byte)7); //version + bW.Write((byte)8); //version bW.WriteShortString(_name); bW.Write(_enabled); @@ -1576,6 +1634,34 @@ namespace DnsServerCore.Dhcp capwapAcIpAddress.WriteTo(bW); } + if (_tftpServerAddreses is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(_tftpServerAddreses.Count)); + + foreach (IPAddress tftpServerAddress in _tftpServerAddreses) + tftpServerAddress.WriteTo(bW); + } + + if (_genericOptions is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(_genericOptions.Count)); + + foreach (DhcpOption genericOption in _genericOptions) + { + bW.Write((byte)genericOption.Code); + bW.Write(Convert.ToInt16(genericOption.RawValue.Length)); + bW.Write(genericOption.RawValue); + } + } + if (_exclusions is null) { bW.Write((byte)0); @@ -1898,6 +1984,22 @@ namespace DnsServerCore.Dhcp } } + public IReadOnlyCollection TftpServerAddresses + { + get { return _tftpServerAddreses; } + set + { + ValidateIpv4(value, nameof(TftpServerAddresses)); + _tftpServerAddreses = value; + } + } + + public IReadOnlyCollection GenericOptions + { + get { return _genericOptions; } + set { _genericOptions = value; } + } + public IReadOnlyCollection Exclusions { get { return _exclusions; } From bad83253f5e3221f445c882e7124ffc9c3f857fc Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:12:41 +0530 Subject: [PATCH 020/191] minor refactoring changes --- DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs | 2 +- .../DnsResourceRecordExtension.cs | 4 ++-- .../Dns/ZoneManagers/AuthZoneManager.cs | 8 ++++---- .../Dns/ZoneManagers/CacheZoneManager.cs | 8 ++++---- DnsServerCore/Dns/Zones/AuthZone.cs | 8 ++++---- DnsServerCore/Dns/Zones/PrimaryZone.cs | 12 ++++++------ DnsServerCore/Dns/Zones/SecondaryZone.cs | 16 ++++++++-------- DnsServerCore/Dns/Zones/StubZone.cs | 12 ++++++------ 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs b/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs index cd54ffcc..eb750bf8 100644 --- a/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs +++ b/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs @@ -270,7 +270,7 @@ namespace DnsServerCore.Dns.Dnssec byte[] signature = SignHash(hash); - DnsRRSIGRecordData signedRRSigRecord = new DnsRRSIGRecordData(unsignedRRSigRecord.TypeCovered, unsignedRRSigRecord.Algorithm, unsignedRRSigRecord.Labels, unsignedRRSigRecord.OriginalTtl, unsignedRRSigRecord.SignatureExpirationValue, unsignedRRSigRecord.SignatureInceptionValue, unsignedRRSigRecord.KeyTag, unsignedRRSigRecord.SignersName, signature); + DnsRRSIGRecordData signedRRSigRecord = new DnsRRSIGRecordData(unsignedRRSigRecord.TypeCovered, unsignedRRSigRecord.Algorithm, unsignedRRSigRecord.Labels, unsignedRRSigRecord.OriginalTtl, unsignedRRSigRecord.SignatureExpiration, unsignedRRSigRecord.SignatureInception, unsignedRRSigRecord.KeyTag, unsignedRRSigRecord.SignersName, signature); return new DnsResourceRecord(firstRecord.Name, DnsResourceRecordType.RRSIG, firstRecord.Class, firstRecord.OriginalTtlValue, signedRRSigRecord); } diff --git a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs index aa8c87e8..54a71deb 100644 --- a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs +++ b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs @@ -65,11 +65,11 @@ namespace DnsServerCore.Dns.ResourceRecords switch (glueAddresses[i].AddressFamily) { case AddressFamily.InterNetwork: - glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.A, DnsClass.IN, record.TtlValue, new DnsARecordData(glueAddresses[i])); + glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.A, DnsClass.IN, record.TTL, new DnsARecordData(glueAddresses[i])); break; case AddressFamily.InterNetworkV6: - glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN, record.TtlValue, new DnsAAAARecordData(glueAddresses[i])); + glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN, record.TTL, new DnsAAAARecordData(glueAddresses[i])); break; } } diff --git a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs index 77d92609..327cd7f0 100644 --- a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs @@ -110,7 +110,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (responsiblePerson.EndsWith(_serverDomain)) responsiblePerson = responsiblePerson.Replace(_serverDomain, serverDomain); - SetRecords(zone.Name, record.Name, record.Type, record.TtlValue, new DnsResourceRecordData[] { new DnsSOARecordData(serverDomain, responsiblePerson, soa.Serial, soa.Refresh, soa.Retry, soa.Expire, soa.Minimum) }); + SetRecords(zone.Name, record.Name, record.Type, record.TTL, new DnsResourceRecordData[] { new DnsSOARecordData(serverDomain, responsiblePerson, soa.Serial, soa.Refresh, soa.Retry, soa.Expire, soa.Minimum) }); //update NS records IReadOnlyList nsResourceRecords = zone.GetApexRecords(DnsResourceRecordType.NS); @@ -119,7 +119,7 @@ namespace DnsServerCore.Dns.ZoneManagers { if ((nsResourceRecord.RDATA as DnsNSRecordData).NameServer.Equals(_serverDomain, StringComparison.OrdinalIgnoreCase)) { - UpdateRecord(zone.Name, nsResourceRecord, new DnsResourceRecord(nsResourceRecord.Name, nsResourceRecord.Type, nsResourceRecord.Class, nsResourceRecord.TtlValue, new DnsNSRecordData(serverDomain)) { Tag = nsResourceRecord.Tag }); + UpdateRecord(zone.Name, nsResourceRecord, new DnsResourceRecord(nsResourceRecord.Name, nsResourceRecord.Type, nsResourceRecord.Class, nsResourceRecord.TTL, new DnsNSRecordData(serverDomain)) { Tag = nsResourceRecord.Tag }); break; } } @@ -301,7 +301,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (DnsClient.IsDomainNameValid(result)) { - DnsResourceRecord cnameRR = new DnsResourceRecord(question.Name, DnsResourceRecordType.CNAME, question.Class, dnameRR.TtlValue, new DnsCNAMERecordData(result)); + DnsResourceRecord cnameRR = new DnsResourceRecord(question.Name, DnsResourceRecordType.CNAME, question.Class, dnameRR.TTL, new DnsCNAMERecordData(result)); List list = new List(5); @@ -1922,7 +1922,7 @@ namespace DnsServerCore.Dns.ZoneManagers DnsResourceRecord[] wildcardAnswers = new DnsResourceRecord[answers.Count]; for (int i = 0; i < answers.Count; i++) - wildcardAnswers[i] = new DnsResourceRecord(question.Name, answers[i].Type, answers[i].Class, answers[i].TtlValue, answers[i].RDATA) { Tag = answers[i].Tag }; + wildcardAnswers[i] = new DnsResourceRecord(question.Name, answers[i].Type, answers[i].Class, answers[i].TTL, answers[i].RDATA) { Tag = answers[i].Tag }; answers = wildcardAnswers; diff --git a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs index 1d28c6e6..fe06fe96 100644 --- a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs @@ -299,7 +299,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (DnsClient.IsDomainNameValid(result)) { - DnsResourceRecord cnameRR = new DnsResourceRecord(question.Name, DnsResourceRecordType.CNAME, question.Class, dnameRR.TtlValue, new DnsCNAMERecordData(result)); + DnsResourceRecord cnameRR = new DnsResourceRecord(question.Name, DnsResourceRecordType.CNAME, question.Class, dnameRR.TTL, new DnsCNAMERecordData(result)); List list = new List(5) { @@ -591,7 +591,7 @@ namespace DnsServerCore.Dns.ZoneManagers { EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(); if (requestECS is not null) - eDnsClientSubnet = new NetworkAddress(requestECS.AddressValue, requestECS.SourcePrefixLength); + eDnsClientSubnet = new NetworkAddress(requestECS.Address, requestECS.SourcePrefixLength); } CacheZone zone; @@ -671,7 +671,7 @@ namespace DnsServerCore.Dns.ZoneManagers NetworkAddress recordECS = firstRR.GetRecordInfo().EDnsClientSubnet; if (recordECS is not null) { - EDnsOption[] ecsOption = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, recordECS.PrefixLength, requestECS.AddressValue); + EDnsOption[] ecsOption = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, recordECS.PrefixLength, requestECS.Address); if ((specialOptions is null) || (specialOptions.Count == 0)) { @@ -808,7 +808,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (suitableECS is not null) { - EDnsOption[] ecsOption = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, suitableECS.PrefixLength, requestECS.AddressValue); + EDnsOption[] ecsOption = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, suitableECS.PrefixLength, requestECS.Address); if (options is null) { diff --git a/DnsServerCore/Dns/Zones/AuthZone.cs b/DnsServerCore/Dns/Zones/AuthZone.cs index 22bc39bf..acd73d3e 100644 --- a/DnsServerCore/Dns/Zones/AuthZone.cs +++ b/DnsServerCore/Dns/Zones/AuthZone.cs @@ -491,10 +491,10 @@ namespace DnsServerCore.Dns.Zones { DnsRRSIGRecordData rrsig = rrsigRecord.RDATA as DnsRRSIGRecordData; - uint signatureValidityPeriod = rrsig.SignatureExpirationValue - rrsig.SignatureInceptionValue; + uint signatureValidityPeriod = rrsig.SignatureExpiration - rrsig.SignatureInception; uint refreshPeriod = signatureValidityPeriod / 3; - if (utcNow > DateTime.UnixEpoch.AddSeconds(rrsig.SignatureExpirationValue - refreshPeriod)) + if (utcNow > DateTime.UnixEpoch.AddSeconds(rrsig.SignatureExpiration - refreshPeriod)) typesToRefresh.Add(rrsig.TypeCovered); } @@ -531,7 +531,7 @@ namespace DnsServerCore.Dns.Zones DnsNSECRecordData newNSecRecord = new DnsNSECRecordData(nextDomainName, types); - if (!_entries.TryGetValue(DnsResourceRecordType.NSEC, out IReadOnlyList existingRecords) || (existingRecords[0].TtlValue != ttl) || !existingRecords[0].RDATA.Equals(newNSecRecord)) + if (!_entries.TryGetValue(DnsResourceRecordType.NSEC, out IReadOnlyList existingRecords) || (existingRecords[0].TTL != ttl) || !existingRecords[0].RDATA.Equals(newNSecRecord)) return new DnsResourceRecord[] { new DnsResourceRecord(_name, DnsResourceRecordType.NSEC, DnsClass.IN, ttl, newNSecRecord) }; return Array.Empty(); @@ -539,7 +539,7 @@ namespace DnsServerCore.Dns.Zones internal IReadOnlyList GetUpdatedNSec3RRSet(IReadOnlyList newNSec3Records) { - if (!_entries.TryGetValue(DnsResourceRecordType.NSEC3, out IReadOnlyList existingRecords) || (existingRecords[0].TtlValue != newNSec3Records[0].TtlValue) || !existingRecords[0].RDATA.Equals(newNSec3Records[0].RDATA)) + if (!_entries.TryGetValue(DnsResourceRecordType.NSEC3, out IReadOnlyList existingRecords) || (existingRecords[0].TTL != newNSec3Records[0].TTL) || !existingRecords[0].RDATA.Equals(newNSec3Records[0].RDATA)) return newNSec3Records; return Array.Empty(); diff --git a/DnsServerCore/Dns/Zones/PrimaryZone.cs b/DnsServerCore/Dns/Zones/PrimaryZone.cs index 4cb3b0be..05408116 100644 --- a/DnsServerCore/Dns/Zones/PrimaryZone.cs +++ b/DnsServerCore/Dns/Zones/PrimaryZone.cs @@ -826,7 +826,7 @@ namespace DnsServerCore.Dns.Zones IReadOnlyList nsec3ParamRecords = GetRecords(DnsResourceRecordType.NSEC3PARAM); DnsNSEC3PARAMRecordData nsec3Param = nsec3ParamRecords[0].RDATA as DnsNSEC3PARAMRecordData; - EnableNSec3(nonNSec3Zones, nsec3Param.Iterations, nsec3Param.SaltValue); + EnableNSec3(nonNSec3Zones, nsec3Param.Iterations, nsec3Param.Salt); } } @@ -2195,7 +2195,7 @@ namespace DnsServerCore.Dns.Zones if (nextHashedOwnerName is null) nextHashedOwnerName = DnsNSEC3RecordData.GetHashedOwnerNameFrom(hashedOwnerName); //only 1 NSEC3 record in zone - IReadOnlyList newNSec3Records = zone.CreateNSec3RRSet(hashedOwnerName, nextHashedOwnerName, ttl, nsec3Param.Iterations, nsec3Param.SaltValue); + IReadOnlyList newNSec3Records = zone.CreateNSec3RRSet(hashedOwnerName, nextHashedOwnerName, ttl, nsec3Param.Iterations, nsec3Param.Salt); if (forceGetNewRRSet) return newNSec3Records; @@ -2310,9 +2310,9 @@ namespace DnsServerCore.Dns.Zones DnsNSEC3RecordData newPreviousNSec3; if (wasRemoved) - newPreviousNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, previousNSec3.Iterations, previousNSec3.SaltValue, currentNSec3.NextHashedOwnerNameValue, previousNSec3.Types); + newPreviousNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, previousNSec3.Iterations, previousNSec3.Salt, currentNSec3.NextHashedOwnerNameValue, previousNSec3.Types); else - newPreviousNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, previousNSec3.Iterations, previousNSec3.SaltValue, DnsNSEC3RecordData.GetHashedOwnerNameFrom(currentNSec3Record.Name), previousNSec3.Types); + newPreviousNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, previousNSec3.Iterations, previousNSec3.Salt, DnsNSEC3RecordData.GetHashedOwnerNameFrom(currentNSec3Record.Name), previousNSec3.Types); DnsResourceRecord[] newPreviousNSec3Records = new DnsResourceRecord[] { new DnsResourceRecord(previousNSec3Record.Name, DnsResourceRecordType.NSEC3, DnsClass.IN, ttl, newPreviousNSec3) }; @@ -2611,7 +2611,7 @@ namespace DnsServerCore.Dns.Zones else serial = 1; - newSoaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, addSoaRecord.TtlValue, new DnsSOARecordData(addSoa.PrimaryNameServer, addSoa.ResponsiblePerson, serial, addSoa.Refresh, addSoa.Retry, addSoa.Expire, addSoa.Minimum)) { Tag = addSoaRecord.Tag }; + newSoaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, addSoaRecord.TTL, new DnsSOARecordData(addSoa.PrimaryNameServer, addSoa.ResponsiblePerson, serial, addSoa.Refresh, addSoa.Retry, addSoa.Expire, addSoa.Minimum)) { Tag = addSoaRecord.Tag }; addedRecords = null; } else @@ -2623,7 +2623,7 @@ namespace DnsServerCore.Dns.Zones else serial = 1; - newSoaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, oldSoaRecord.TtlValue, new DnsSOARecordData(oldSoa.PrimaryNameServer, oldSoa.ResponsiblePerson, serial, oldSoa.Refresh, oldSoa.Retry, oldSoa.Expire, oldSoa.Minimum)) { Tag = oldSoaRecord.Tag }; + newSoaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, oldSoaRecord.TTL, new DnsSOARecordData(oldSoa.PrimaryNameServer, oldSoa.ResponsiblePerson, serial, oldSoa.Refresh, oldSoa.Retry, oldSoa.Expire, oldSoa.Minimum)) { Tag = oldSoaRecord.Tag }; } } diff --git a/DnsServerCore/Dns/Zones/SecondaryZone.cs b/DnsServerCore/Dns/Zones/SecondaryZone.cs index e8b73644..973ed368 100644 --- a/DnsServerCore/Dns/Zones/SecondaryZone.cs +++ b/DnsServerCore/Dns/Zones/SecondaryZone.cs @@ -309,7 +309,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received RCODE=" + soaResponse.RCODE.ToString() + " for '" + (_name == "" ? "" : _name) + "' secondary zone refresh from: " + soaResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received RCODE=" + soaResponse.RCODE.ToString() + " for '" + (_name == "" ? "" : _name) + "' secondary zone refresh from: " + soaResponse.Metadata.NameServer.ToString()); return false; } @@ -318,7 +318,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received an empty response for SOA query for '" + (_name == "" ? "" : _name) + "' secondary zone refresh from: " + soaResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received an empty response for SOA query for '" + (_name == "" ? "" : _name) + "' secondary zone refresh from: " + soaResponse.Metadata.NameServer.ToString()); return false; } @@ -331,7 +331,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server successfully checked for '" + (_name == "" ? "" : _name) + "' secondary zone update from: " + soaResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server successfully checked for '" + (_name == "" ? "" : _name) + "' secondary zone update from: " + soaResponse.Metadata.NameServer.ToString()); return true; } @@ -414,7 +414,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received a zone transfer response (RCODE=" + xfrResponse.RCODE.ToString() + ") for '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received a zone transfer response (RCODE=" + xfrResponse.RCODE.ToString() + ") for '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServer.ToString()); return false; } @@ -423,7 +423,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received an empty response for zone transfer query for '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received an empty response for zone transfer query for '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServer.ToString()); return false; } @@ -432,7 +432,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received invalid response for zone transfer query for '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received invalid response for zone transfer query for '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServer.ToString()); return false; } @@ -460,13 +460,13 @@ namespace DnsServerCore.Dns.Zones LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server successfully refreshed '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server successfully refreshed '" + (_name == "" ? "" : _name) + "' secondary zone from: " + xfrResponse.Metadata.NameServer.ToString()); } else { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server successfully checked for '" + (_name == "" ? "" : _name) + "' secondary zone update from: " + xfrResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server successfully checked for '" + (_name == "" ? "" : _name) + "' secondary zone update from: " + xfrResponse.Metadata.NameServer.ToString()); } return true; diff --git a/DnsServerCore/Dns/Zones/StubZone.cs b/DnsServerCore/Dns/Zones/StubZone.cs index 25168511..a7a05abf 100644 --- a/DnsServerCore/Dns/Zones/StubZone.cs +++ b/DnsServerCore/Dns/Zones/StubZone.cs @@ -255,7 +255,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received RCODE=" + soaResponse.RCODE.ToString() + " for '" + (_name == "" ? "" : _name) + "' stub zone refresh from: " + soaResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received RCODE=" + soaResponse.RCODE.ToString() + " for '" + (_name == "" ? "" : _name) + "' stub zone refresh from: " + soaResponse.Metadata.NameServer.ToString()); return false; } @@ -264,7 +264,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received an empty response for SOA query for '" + (_name == "" ? "" : _name) + "' stub zone refresh from: " + soaResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received an empty response for SOA query for '" + (_name == "" ? "" : _name) + "' stub zone refresh from: " + soaResponse.Metadata.NameServer.ToString()); return false; } @@ -280,7 +280,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server successfully checked for '" + (_name == "" ? "" : _name) + "' stub zone update from: " + soaResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server successfully checked for '" + (_name == "" ? "" : _name) + "' stub zone update from: " + soaResponse.Metadata.NameServer.ToString()); return true; } @@ -307,7 +307,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received RCODE=" + nsResponse.RCODE.ToString() + " for '" + (_name == "" ? "" : _name) + "' stub zone refresh from: " + nsResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received RCODE=" + nsResponse.RCODE.ToString() + " for '" + (_name == "" ? "" : _name) + "' stub zone refresh from: " + nsResponse.Metadata.NameServer.ToString()); return false; } @@ -316,7 +316,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server received an empty response for NS query for '" + (_name == "" ? "" : _name) + "' stub zone from: " + nsResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server received an empty response for NS query for '" + (_name == "" ? "" : _name) + "' stub zone from: " + nsResponse.Metadata.NameServer.ToString()); return false; } @@ -342,7 +342,7 @@ namespace DnsServerCore.Dns.Zones { LogManager log = _dnsServer.LogManager; if (log != null) - log.Write("DNS Server successfully refreshed '" + (_name == "" ? "" : _name) + "' stub zone from: " + nsResponse.Metadata.NameServerAddress.ToString()); + log.Write("DNS Server successfully refreshed '" + (_name == "" ? "" : _name) + "' stub zone from: " + nsResponse.Metadata.NameServer.ToString()); } return true; From a247b1562a99559ab4ecd9cfa2ddcfed727defb7 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:13:25 +0530 Subject: [PATCH 021/191] BlockListZoneManager: Updated ReadListFile() to support wildcard block lists. --- DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs index a33a1421..656e220f 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs @@ -131,7 +131,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (line == null) break; //eof - line = line.TrimStart(' ', '\t'); + line = line.TrimStart(' ', '\t', '*', '.'); if (line.Length == 0) continue; //skip empty line From 1fa22609e94fee59d0d0566effc014c2af4d17dc Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:17:22 +0530 Subject: [PATCH 022/191] DnsServer: Removed newtonsoft. Removed doh-json support. Updated ProcessNotifyQueryAsync() and ProcessUpdateQueryAsync() to add log messages. --- DnsServerCore/Dns/DnsServer.cs | 107 +++++++++++---------------------- 1 file changed, 34 insertions(+), 73 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index ef59a9af..71c22fe5 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -23,7 +23,6 @@ using DnsServerCore.Dns.ResourceRecords; using DnsServerCore.Dns.Trees; using DnsServerCore.Dns.ZoneManagers; using DnsServerCore.Dns.Zones; -using Newtonsoft.Json; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -721,12 +720,6 @@ namespace DnsServerCore.Dns protocol = DnsTransportProtocol.Https; break; } - else if (acceptType == "application/dns-json") - { - protocol = DnsTransportProtocol.HttpsJson; - dnsProtocol = DnsTransportProtocol.HttpsJson; - break; - } } } @@ -801,51 +794,8 @@ namespace DnsServerCore.Dns #endregion break; - case DnsTransportProtocol.HttpsJson: - #region https json format - { - string strName = httpRequest.QueryString["name"]; - if (string.IsNullOrEmpty(strName)) - throw new DnsServerException("Missing query string parameter: name"); - - string strType = httpRequest.QueryString["type"]; - if (string.IsNullOrEmpty(strType)) - strType = "1"; - - bool dnssecOk; - string strDO = httpRequest.QueryString["do"]; - if (string.IsNullOrEmpty(strDO)) - dnssecOk = false; - else - dnssecOk = bool.Parse(strDO); - - dnsRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(strName.TrimEnd('.'), (DnsResourceRecordType)int.Parse(strType), DnsClass.IN) }, null, null, null, _udpPayloadSize, dnssecOk ? EDnsHeaderFlags.DNSSEC_OK : EDnsHeaderFlags.None); - - DnsDatagram dnsResponse = await PreProcessQueryAsync(dnsRequest, remoteEP, protocol, IsRecursionAllowed(remoteEP)); - if (dnsResponse is null) - return; //drop request - - using (MemoryStream mS = new MemoryStream(512)) - { - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); - dnsResponse.WriteToJson(jsonWriter); - jsonWriter.Flush(); - - mS.Position = 0; - await SendContentAsync(stream, requestConnection, "application/dns-json; charset=utf-8", mS); - } - - LogManager queryLog = _queryLog; - if (queryLog is not null) - queryLog.Write(remoteEP, protocol, dnsRequest, dnsResponse); - - _stats.QueueUpdate(dnsRequest, remoteEP, protocol, dnsResponse); - } - #endregion - break; - default: - await RedirectAsync(stream, httpRequest.Protocol, requestConnection, "https://" + httpRequest.Headers[HttpRequestHeader.Host]); + await RedirectAsync(stream, httpRequest.Protocol, requestConnection, (usingHttps ? "https://" : "http://") + httpRequest.Headers[HttpRequestHeader.Host]); break; } @@ -1117,7 +1067,7 @@ namespace DnsServerCore.Dns EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(true); if ((requestECS is not null) && (request.Question.Count == 1) && CacheZone.IsTypeSupportedForEDnsClientSubnet(request.Question[0].Type)) - options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.AddressValue); + options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); if (response.Additional.Count == 0) return response.Clone(null, null, new DnsResourceRecord[] { DnsDatagramEdns.GetOPTFor(_udpPayloadSize, response.RCODE, 0, request.DnssecOk ? EDnsHeaderFlags.DNSSEC_OK : EDnsHeaderFlags.None, options) }); @@ -1233,12 +1183,18 @@ namespace DnsServerCore.Dns } } - if (!remoteVerified) - return new DnsDatagram(request.Identifier, true, DnsOpcode.Notify, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; - LogManager log = _log; + + if (!remoteVerified) + { + if (log is not null) + log.Write(remoteEP, protocol, "DNS Server refused a NOTIFY request since the request IP address was not recognized by the secondary zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + + return new DnsDatagram(request.Identifier, true, DnsOpcode.Notify, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; + } + if (log is not null) - log.Write(remoteEP, protocol, "DNS Server received NOTIFY for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + log.Write(remoteEP, protocol, "DNS Server received a NOTIFY request for secondary zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); if ((request.Answer.Count > 0) && (request.Answer[0].Type == DnsResourceRecordType.SOA)) { @@ -1269,7 +1225,7 @@ namespace DnsServerCore.Dns LogManager log = _log; if (log is not null) - log.Write(remoteEP, protocol, "DNS Server received UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + log.Write(remoteEP, protocol, "DNS Server received a zone UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); async Task IsZoneNameServerAllowedAsync() { @@ -1332,7 +1288,7 @@ namespace DnsServerCore.Dns if (!isUpdateAllowed) { if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused an UPDATE request since the request IP address is not allowed by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + log.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request since the request IP address is not allowed by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return false; } @@ -1393,7 +1349,7 @@ namespace DnsServerCore.Dns foreach (DnsResourceRecord prRecord in request.Answer) { - if (prRecord.TtlValue != 0) + if (prRecord.TTL != 0) return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.FormatError, request.Question) { Tag = DnsServerResponseType.Authoritative }; AuthZoneInfo prAuthZoneInfo = _authZoneManager.FindAuthZoneInfo(prRecord.Name); @@ -1507,7 +1463,12 @@ namespace DnsServerCore.Dns //check for permissions if (!await IsUpdatePermittedAsync()) + { + if (log is not null) + log.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request due to Dynamic Updates Security Policy for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; + } //process update section { @@ -1532,7 +1493,7 @@ namespace DnsServerCore.Dns } else if (uRecord.Class == DnsClass.ANY) { - if ((uRecord.TtlValue != 0) || (uRecord.RDATA.RDLENGTH != 0)) + if ((uRecord.TTL != 0) || (uRecord.RDATA.RDLENGTH != 0)) return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.FormatError, request.Question) { Tag = DnsServerResponseType.Authoritative }; switch (uRecord.Type) @@ -1546,7 +1507,7 @@ namespace DnsServerCore.Dns } else if (uRecord.Class == DnsClass.NONE) { - if (uRecord.TtlValue != 0) + if (uRecord.TTL != 0) return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.FormatError, request.Question) { Tag = DnsServerResponseType.Authoritative }; switch (uRecord.Type) @@ -1747,7 +1708,7 @@ namespace DnsServerCore.Dns _authZoneManager.SaveZoneFile(authZoneInfo.Name); if (log is not null) - log.Write(remoteEP, protocol, "DNS Server processes UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + log.Write(remoteEP, protocol, "DNS Server successfully processed a zone UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); //NOERROR return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question) { Tag = DnsServerResponseType.Authoritative }; @@ -2058,7 +2019,7 @@ namespace DnsServerCore.Dns { AuthZoneInfo zoneInfo = _authZoneManager.FindAuthZoneInfo(appResourceRecord.Name); - DnsDatagram appResponse = await appRecordRequestHandler.ProcessRequestAsync(request, remoteEP, protocol, isRecursionAllowed, zoneInfo.Name, appResourceRecord.Name, appResourceRecord.TtlValue, appRecord.Data); + DnsDatagram appResponse = await appRecordRequestHandler.ProcessRequestAsync(request, remoteEP, protocol, isRecursionAllowed, zoneInfo.Name, appResourceRecord.Name, appResourceRecord.TTL, appRecord.Data); if (appResponse is null) { IReadOnlyList authority = null; @@ -2380,10 +2341,10 @@ namespace DnsServerCore.Dns if (answer.Type != questionType) continue; - if (anameRR.TtlValue < answer.TtlValue) - answers.Add(new DnsResourceRecord(anameRR.Name, answer.Type, answer.Class, anameRR.TtlValue, answer.RDATA)); + if (anameRR.TTL < answer.TTL) + answers.Add(new DnsResourceRecord(anameRR.Name, answer.Type, answer.Class, anameRR.TTL, answer.RDATA)); else - answers.Add(new DnsResourceRecord(anameRR.Name, answer.Type, answer.Class, answer.TtlValue, answer.RDATA)); + answers.Add(new DnsResourceRecord(anameRR.Name, answer.Type, answer.Class, answer.TTL, answer.RDATA)); } return answers; @@ -2702,7 +2663,7 @@ namespace DnsServerCore.Dns { return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.FormatError, request.Question) { Tag = DnsServerResponseType.Authoritative }; } - else if ((requestECS.SourcePrefixLength == 0) || NetUtilities.IsPrivateIP(requestECS.AddressValue)) + else if ((requestECS.SourcePrefixLength == 0) || NetUtilities.IsPrivateIP(requestECS.Address)) { //disable ECS option request.ShadowHideEDnsClientSubnetOption(); @@ -2713,12 +2674,12 @@ namespace DnsServerCore.Dns switch (requestECS.Family) { case EDnsClientSubnetAddressFamily.IPv4: - eDnsClientSubnet = new NetworkAddress(requestECS.AddressValue, Math.Min(requestECS.SourcePrefixLength, _eDnsClientSubnetIPv4PrefixLength)); + eDnsClientSubnet = new NetworkAddress(requestECS.Address, Math.Min(requestECS.SourcePrefixLength, _eDnsClientSubnetIPv4PrefixLength)); request.SetShadowEDnsClientSubnetOption(eDnsClientSubnet); break; case EDnsClientSubnetAddressFamily.IPv6: - eDnsClientSubnet = new NetworkAddress(requestECS.AddressValue, Math.Min(requestECS.SourcePrefixLength, _eDnsClientSubnetIPv6PrefixLength)); + eDnsClientSubnet = new NetworkAddress(requestECS.Address, Math.Min(requestECS.SourcePrefixLength, _eDnsClientSubnetIPv6PrefixLength)); request.SetShadowEDnsClientSubnetOption(eDnsClientSubnet); break; } @@ -2741,7 +2702,7 @@ namespace DnsServerCore.Dns //inspect response TTL values to decide if prefetch trigger is needed foreach (DnsResourceRecord answer in cacheResponse.Answer) { - if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (answer.TtlValue <= _cachePrefetchTrigger)) + if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (answer.TTL <= _cachePrefetchTrigger)) { //trigger prefetch async _ = PrefetchCacheAsync(request, remoteEP, conditionalForwarders); @@ -3417,7 +3378,7 @@ namespace DnsServerCore.Dns foreach (DnsResourceRecord answer in response.Answer) { - if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (utcNow.AddSeconds(answer.TtlValue) < _cachePrefetchSamplingTimerTriggersOn)) + if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (utcNow.AddSeconds(answer.TTL) < _cachePrefetchSamplingTimerTriggersOn)) { //answer expires before next sampling so add back to the list to allow refreshing it addBackToSampleList = true; @@ -3454,7 +3415,7 @@ namespace DnsServerCore.Dns //inspect response TTL values to decide if refresh is needed foreach (DnsResourceRecord answer in cacheResponse.Answer) { - if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (answer.TtlValue <= trigger)) + if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (answer.TTL <= trigger)) return question; //TTL eligible and less than trigger so refresh question } @@ -3487,7 +3448,7 @@ namespace DnsServerCore.Dns //inspect response TTL values to decide if refresh is needed foreach (DnsResourceRecord answer in cacheResponse.Answer) { - if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (answer.TtlValue <= trigger)) + if ((answer.OriginalTtlValue >= _cachePrefetchEligibility) && (answer.TTL <= trigger)) return true; //TTL eligible less than trigger so refresh } From 9136130bf3ccd25f6675c15a551683f6936af0be Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:18:01 +0530 Subject: [PATCH 023/191] LogManager: fixed ECS log entry to use scope prefix length. --- DnsServerCore/LogManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DnsServerCore/LogManager.cs b/DnsServerCore/LogManager.cs index 4a7f224d..a6132626 100644 --- a/DnsServerCore/LogManager.cs +++ b/DnsServerCore/LogManager.cs @@ -592,7 +592,7 @@ namespace DnsServerCore EDnsClientSubnetOptionData responseECS = response.GetEDnsClientSubnetOption(); if (responseECS is not null) - answer += "; ECS: " + responseECS.Address.ToString() + "/" + responseECS.SourcePrefixLength; + answer += "; ECS: " + responseECS.Address.ToString() + "/" + responseECS.ScopePrefixLength; responseInfo = " RCODE: " + response.RCODE.ToString() + "; ANSWER: " + answer; } From 27788acfa5b3ae0f0e72af0cb69e767ee14376a1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 12:57:53 +0530 Subject: [PATCH 024/191] DnsWebService: Removed newtonsoft. Fixed issues in RestoreSettingsAsync() related to reloading block lists. Removed doh-json support. --- DnsServerCore/DnsWebService.cs | 918 +++++++++++++++------------------ 1 file changed, 411 insertions(+), 507 deletions(-) diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index 46dd560f..24cf1cbd 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -23,8 +23,6 @@ using DnsServerCore.Dns; using DnsServerCore.Dns.ResourceRecords; using DnsServerCore.Dns.ZoneManagers; using DnsServerCore.Dns.Zones; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; using System; using System.Collections.Generic; using System.IO; @@ -37,6 +35,7 @@ using System.Reflection; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using TechnitiumLibrary; @@ -371,7 +370,7 @@ namespace DnsServerCore { try { - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); jsonWriter.WriteStartObject(); switch (path) @@ -1184,8 +1183,7 @@ namespace DnsServerCore break; } - jsonWriter.WritePropertyName("status"); - jsonWriter.WriteValue("ok"); + jsonWriter.WriteString("status", "ok"); jsonWriter.WriteEndObject(); jsonWriter.Flush(); @@ -1193,14 +1191,11 @@ namespace DnsServerCore catch (InvalidTokenWebServiceException ex) { mS.SetLength(0); - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("status"); - jsonWriter.WriteValue("invalid-token"); - - jsonWriter.WritePropertyName("errorMessage"); - jsonWriter.WriteValue(ex.Message); + jsonWriter.WriteString("status", "invalid-token"); + jsonWriter.WriteString("errorMessage", ex.Message); jsonWriter.WriteEndObject(); jsonWriter.Flush(); @@ -1219,23 +1214,15 @@ namespace DnsServerCore _log.Write(GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + ex.ToString()); mS.SetLength(0); - JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS)); + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("status"); - jsonWriter.WriteValue("error"); + jsonWriter.WriteString("status", "error"); + jsonWriter.WriteString("errorMessage", ex.Message); + jsonWriter.WriteString("stackTrace", ex.StackTrace); - jsonWriter.WritePropertyName("errorMessage"); - jsonWriter.WriteValue(ex.Message); - - jsonWriter.WritePropertyName("stackTrace"); - jsonWriter.WriteValue(ex.StackTrace); - - if (ex.InnerException != null) - { - jsonWriter.WritePropertyName("innerErrorMessage"); - jsonWriter.WriteValue(ex.InnerException.Message); - } + if (ex.InnerException is not null) + jsonWriter.WriteString("innerErrorMessage", ex.InnerException.Message); jsonWriter.WriteEndObject(); jsonWriter.Flush(); @@ -1446,12 +1433,11 @@ namespace DnsServerCore #region update api - private async Task CheckForUpdateAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + private async Task CheckForUpdateAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { if (_updateCheckUri is null) { - jsonWriter.WritePropertyName("updateAvailable"); - jsonWriter.WriteValue(false); + jsonWriter.WriteBoolean("updateAvailable", false); return; } @@ -1463,43 +1449,30 @@ namespace DnsServerCore using (HttpClient http = new HttpClient(handler)) { - string response = await http.GetStringAsync(_updateCheckUri); - dynamic jsonResponse = JsonConvert.DeserializeObject(response); + Stream response = await http.GetStreamAsync(_updateCheckUri); + using JsonDocument jsonDocument = await JsonDocument.ParseAsync(response); + JsonElement jsonResponse = jsonDocument.RootElement; - string updateVersion = jsonResponse.updateVersion.Value; - string updateTitle = jsonResponse.updateTitle?.Value; - string updateMessage = jsonResponse.updateMessage?.Value; - string downloadLink = jsonResponse.downloadLink?.Value; - string instructionsLink = jsonResponse.instructionsLink?.Value; - string changeLogLink = jsonResponse.changeLogLink?.Value; + string updateVersion = jsonResponse.GetProperty("updateVersion").GetString(); + string updateTitle = jsonResponse.GetPropertyValue("updateTitle", null); + string updateMessage = jsonResponse.GetPropertyValue("updateMessage", null); + string downloadLink = jsonResponse.GetPropertyValue("downloadLink", null); + string instructionsLink = jsonResponse.GetPropertyValue("instructionsLink", null); + string changeLogLink = jsonResponse.GetPropertyValue("changeLogLink", null); bool updateAvailable = new Version(updateVersion) > _currentVersion; - jsonWriter.WritePropertyName("updateAvailable"); - jsonWriter.WriteValue(updateAvailable); - - jsonWriter.WritePropertyName("updateVersion"); - jsonWriter.WriteValue(updateVersion); - - jsonWriter.WritePropertyName("currentVersion"); - jsonWriter.WriteValue(GetCleanVersion(_currentVersion)); + jsonWriter.WriteBoolean("updateAvailable", updateAvailable); + jsonWriter.WriteString("updateVersion", updateVersion); + jsonWriter.WriteString("currentVersion", GetCleanVersion(_currentVersion)); if (updateAvailable) { - jsonWriter.WritePropertyName("updateTitle"); - jsonWriter.WriteValue(updateTitle); - - jsonWriter.WritePropertyName("updateMessage"); - jsonWriter.WriteValue(updateMessage); - - jsonWriter.WritePropertyName("downloadLink"); - jsonWriter.WriteValue(downloadLink); - - jsonWriter.WritePropertyName("instructionsLink"); - jsonWriter.WriteValue(instructionsLink); - - jsonWriter.WritePropertyName("changeLogLink"); - jsonWriter.WriteValue(changeLogLink); + jsonWriter.WriteString("updateTitle", updateTitle); + jsonWriter.WriteString("updateMessage", updateMessage); + jsonWriter.WriteString("downloadLink", downloadLink); + jsonWriter.WriteString("instructionsLink", instructionsLink); + jsonWriter.WriteString("changeLogLink", changeLogLink); } string strLog = "Check for update was done {updateAvailable: " + updateAvailable + "; updateVersion: " + updateVersion + ";"; @@ -1528,8 +1501,7 @@ namespace DnsServerCore { _log.Write(GetRequestRemoteEndPoint(request), "Check for update was done {updateAvailable: False;}\r\n" + ex.ToString()); - jsonWriter.WritePropertyName("updateAvailable"); - jsonWriter.WriteValue(false); + jsonWriter.WriteBoolean("updateAvailable", false); } } @@ -1555,71 +1527,73 @@ namespace DnsServerCore #region settings api - private void GetDnsSettings(JsonTextWriter jsonWriter) + private void GetDnsSettings(Utf8JsonWriter jsonWriter) { - jsonWriter.WritePropertyName("version"); - jsonWriter.WriteValue(GetServerVersion()); - - jsonWriter.WritePropertyName("dnsServerDomain"); - jsonWriter.WriteValue(_dnsServer.ServerDomain); + //general + jsonWriter.WriteString("version", GetServerVersion()); + jsonWriter.WriteString("dnsServerDomain", _dnsServer.ServerDomain); jsonWriter.WritePropertyName("dnsServerLocalEndPoints"); jsonWriter.WriteStartArray(); foreach (IPEndPoint localEP in _dnsServer.LocalEndPoints) - jsonWriter.WriteValue(localEP.ToString()); + jsonWriter.WriteStringValue(localEP.ToString()); jsonWriter.WriteEndArray(); + jsonWriter.WriteNumber("defaultRecordTtl", _zonesApi.DefaultRecordTtl); + jsonWriter.WriteBoolean("dnsAppsEnableAutomaticUpdate", _appsApi.EnableAutomaticUpdate); + + jsonWriter.WriteBoolean("preferIPv6", _dnsServer.PreferIPv6); + + jsonWriter.WriteNumber("udpPayloadSize", _dnsServer.UdpPayloadSize); + + jsonWriter.WriteBoolean("dnssecValidation", _dnsServer.DnssecValidation); + + jsonWriter.WriteBoolean("eDnsClientSubnet", _dnsServer.EDnsClientSubnet); + jsonWriter.WriteNumber("eDnsClientSubnetIPv4PrefixLength", _dnsServer.EDnsClientSubnetIPv4PrefixLength); + jsonWriter.WriteNumber("eDnsClientSubnetIPv6PrefixLength", _dnsServer.EDnsClientSubnetIPv6PrefixLength); + + jsonWriter.WriteNumber("qpmLimitRequests", _dnsServer.QpmLimitRequests); + jsonWriter.WriteNumber("qpmLimitErrors", _dnsServer.QpmLimitErrors); + jsonWriter.WriteNumber("qpmLimitSampleMinutes", _dnsServer.QpmLimitSampleMinutes); + jsonWriter.WriteNumber("qpmLimitIPv4PrefixLength", _dnsServer.QpmLimitIPv4PrefixLength); + jsonWriter.WriteNumber("qpmLimitIPv6PrefixLength", _dnsServer.QpmLimitIPv6PrefixLength); + + jsonWriter.WriteNumber("clientTimeout", _dnsServer.ClientTimeout); + jsonWriter.WriteNumber("tcpSendTimeout", _dnsServer.TcpSendTimeout); + jsonWriter.WriteNumber("tcpReceiveTimeout", _dnsServer.TcpReceiveTimeout); + + //web service jsonWriter.WritePropertyName("webServiceLocalAddresses"); jsonWriter.WriteStartArray(); foreach (IPAddress localAddress in _webServiceLocalAddresses) { if (localAddress.AddressFamily == AddressFamily.InterNetworkV6) - jsonWriter.WriteValue("[" + localAddress.ToString() + "]"); + jsonWriter.WriteStringValue("[" + localAddress.ToString() + "]"); else - jsonWriter.WriteValue(localAddress.ToString()); + jsonWriter.WriteStringValue(localAddress.ToString()); } jsonWriter.WriteEndArray(); - jsonWriter.WritePropertyName("webServiceHttpPort"); - jsonWriter.WriteValue(_webServiceHttpPort); + jsonWriter.WriteNumber("webServiceHttpPort", _webServiceHttpPort); + jsonWriter.WriteBoolean("webServiceEnableTls", _webServiceEnableTls); + jsonWriter.WriteBoolean("webServiceHttpToTlsRedirect", _webServiceHttpToTlsRedirect); + jsonWriter.WriteBoolean("webServiceUseSelfSignedTlsCertificate", _webServiceUseSelfSignedTlsCertificate); + jsonWriter.WriteNumber("webServiceTlsPort", _webServiceTlsPort); + jsonWriter.WriteString("webServiceTlsCertificatePath", _webServiceTlsCertificatePath); + jsonWriter.WriteString("webServiceTlsCertificatePassword", "************"); - jsonWriter.WritePropertyName("webServiceEnableTls"); - jsonWriter.WriteValue(_webServiceEnableTls); - - jsonWriter.WritePropertyName("webServiceHttpToTlsRedirect"); - jsonWriter.WriteValue(_webServiceHttpToTlsRedirect); - - jsonWriter.WritePropertyName("webServiceTlsPort"); - jsonWriter.WriteValue(_webServiceTlsPort); - - jsonWriter.WritePropertyName("webServiceUseSelfSignedTlsCertificate"); - jsonWriter.WriteValue(_webServiceUseSelfSignedTlsCertificate); - - jsonWriter.WritePropertyName("webServiceTlsCertificatePath"); - jsonWriter.WriteValue(_webServiceTlsCertificatePath); - - jsonWriter.WritePropertyName("webServiceTlsCertificatePassword"); - jsonWriter.WriteValue("************"); - - jsonWriter.WritePropertyName("enableDnsOverHttp"); - jsonWriter.WriteValue(_dnsServer.EnableDnsOverHttp); - - jsonWriter.WritePropertyName("enableDnsOverTls"); - jsonWriter.WriteValue(_dnsServer.EnableDnsOverTls); - - jsonWriter.WritePropertyName("enableDnsOverHttps"); - jsonWriter.WriteValue(_dnsServer.EnableDnsOverHttps); - - jsonWriter.WritePropertyName("dnsTlsCertificatePath"); - jsonWriter.WriteValue(_dnsTlsCertificatePath); - - jsonWriter.WritePropertyName("dnsTlsCertificatePassword"); - jsonWriter.WriteValue("************"); + //optional protocols + jsonWriter.WriteBoolean("enableDnsOverHttp", _dnsServer.EnableDnsOverHttp); + jsonWriter.WriteBoolean("enableDnsOverTls", _dnsServer.EnableDnsOverTls); + jsonWriter.WriteBoolean("enableDnsOverHttps", _dnsServer.EnableDnsOverHttps); + jsonWriter.WriteString("dnsTlsCertificatePath", _dnsTlsCertificatePath); + jsonWriter.WriteString("dnsTlsCertificatePassword", "************"); + //tsig jsonWriter.WritePropertyName("tsigKeys"); { jsonWriter.WriteStartArray(); @@ -1630,14 +1604,9 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("keyName"); - jsonWriter.WriteValue(tsigKey.Key); - - jsonWriter.WritePropertyName("sharedSecret"); - jsonWriter.WriteValue(tsigKey.Value.SharedSecret); - - jsonWriter.WritePropertyName("algorithmName"); - jsonWriter.WriteValue(tsigKey.Value.AlgorithmName); + jsonWriter.WriteString("keyName", tsigKey.Key); + jsonWriter.WriteString("sharedSecret", tsigKey.Value.SharedSecret); + jsonWriter.WriteString("algorithmName", tsigKey.Value.AlgorithmName); jsonWriter.WriteEndObject(); } @@ -1646,77 +1615,8 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - jsonWriter.WritePropertyName("defaultRecordTtl"); - jsonWriter.WriteValue(_zonesApi.DefaultRecordTtl); - - jsonWriter.WritePropertyName("dnsAppsEnableAutomaticUpdate"); - jsonWriter.WriteValue(_appsApi.EnableAutomaticUpdate); - - jsonWriter.WritePropertyName("preferIPv6"); - jsonWriter.WriteValue(_dnsServer.PreferIPv6); - - jsonWriter.WritePropertyName("udpPayloadSize"); - jsonWriter.WriteValue(_dnsServer.UdpPayloadSize); - - jsonWriter.WritePropertyName("dnssecValidation"); - jsonWriter.WriteValue(_dnsServer.DnssecValidation); - - jsonWriter.WritePropertyName("eDnsClientSubnet"); - jsonWriter.WriteValue(_dnsServer.EDnsClientSubnet); - - jsonWriter.WritePropertyName("eDnsClientSubnetIPv4PrefixLength"); - jsonWriter.WriteValue(_dnsServer.EDnsClientSubnetIPv4PrefixLength); - - jsonWriter.WritePropertyName("eDnsClientSubnetIPv6PrefixLength"); - jsonWriter.WriteValue(_dnsServer.EDnsClientSubnetIPv6PrefixLength); - - jsonWriter.WritePropertyName("resolverRetries"); - jsonWriter.WriteValue(_dnsServer.ResolverRetries); - - jsonWriter.WritePropertyName("resolverTimeout"); - jsonWriter.WriteValue(_dnsServer.ResolverTimeout); - - jsonWriter.WritePropertyName("resolverMaxStackCount"); - jsonWriter.WriteValue(_dnsServer.ResolverMaxStackCount); - - jsonWriter.WritePropertyName("forwarderRetries"); - jsonWriter.WriteValue(_dnsServer.ForwarderRetries); - - jsonWriter.WritePropertyName("forwarderTimeout"); - jsonWriter.WriteValue(_dnsServer.ForwarderTimeout); - - jsonWriter.WritePropertyName("forwarderConcurrency"); - jsonWriter.WriteValue(_dnsServer.ForwarderConcurrency); - - jsonWriter.WritePropertyName("clientTimeout"); - jsonWriter.WriteValue(_dnsServer.ClientTimeout); - - jsonWriter.WritePropertyName("tcpSendTimeout"); - jsonWriter.WriteValue(_dnsServer.TcpSendTimeout); - - jsonWriter.WritePropertyName("tcpReceiveTimeout"); - jsonWriter.WriteValue(_dnsServer.TcpReceiveTimeout); - - jsonWriter.WritePropertyName("enableLogging"); - jsonWriter.WriteValue(_log.EnableLogging); - - jsonWriter.WritePropertyName("logQueries"); - jsonWriter.WriteValue(_dnsServer.QueryLogManager != null); - - jsonWriter.WritePropertyName("useLocalTime"); - jsonWriter.WriteValue(_log.UseLocalTime); - - jsonWriter.WritePropertyName("logFolder"); - jsonWriter.WriteValue(_log.LogFolder); - - jsonWriter.WritePropertyName("maxLogFileDays"); - jsonWriter.WriteValue(_log.MaxLogFileDays); - - jsonWriter.WritePropertyName("maxStatFileDays"); - jsonWriter.WriteValue(_dnsServer.StatsManager.MaxStatFileDays); - - jsonWriter.WritePropertyName("recursion"); - jsonWriter.WriteValue(_dnsServer.Recursion.ToString()); + //recursion + jsonWriter.WriteString("recursion", _dnsServer.Recursion.ToString()); jsonWriter.WritePropertyName("recursionDeniedNetworks"); { @@ -1725,7 +1625,7 @@ namespace DnsServerCore if (_dnsServer.RecursionDeniedNetworks is not null) { foreach (NetworkAddress networkAddress in _dnsServer.RecursionDeniedNetworks) - jsonWriter.WriteValue(networkAddress.ToString()); + jsonWriter.WriteStringValue(networkAddress.ToString()); } jsonWriter.WriteEndArray(); @@ -1738,73 +1638,88 @@ namespace DnsServerCore if (_dnsServer.RecursionAllowedNetworks is not null) { foreach (NetworkAddress networkAddress in _dnsServer.RecursionAllowedNetworks) - jsonWriter.WriteValue(networkAddress.ToString()); + jsonWriter.WriteStringValue(networkAddress.ToString()); } jsonWriter.WriteEndArray(); } - jsonWriter.WritePropertyName("randomizeName"); - jsonWriter.WriteValue(_dnsServer.RandomizeName); + jsonWriter.WriteBoolean("randomizeName", _dnsServer.RandomizeName); + jsonWriter.WriteBoolean("qnameMinimization", _dnsServer.QnameMinimization); + jsonWriter.WriteBoolean("nsRevalidation", _dnsServer.NsRevalidation); - jsonWriter.WritePropertyName("qnameMinimization"); - jsonWriter.WriteValue(_dnsServer.QnameMinimization); + jsonWriter.WriteNumber("resolverRetries", _dnsServer.ResolverRetries); + jsonWriter.WriteNumber("resolverTimeout", _dnsServer.ResolverTimeout); + jsonWriter.WriteNumber("resolverMaxStackCount", _dnsServer.ResolverMaxStackCount); - jsonWriter.WritePropertyName("nsRevalidation"); - jsonWriter.WriteValue(_dnsServer.NsRevalidation); + //cache + jsonWriter.WriteBoolean("serveStale", _dnsServer.ServeStale); + jsonWriter.WriteNumber("serveStaleTtl", _dnsServer.CacheZoneManager.ServeStaleTtl); - jsonWriter.WritePropertyName("qpmLimitRequests"); - jsonWriter.WriteValue(_dnsServer.QpmLimitRequests); + jsonWriter.WriteNumber("cacheMaximumEntries", _dnsServer.CacheZoneManager.MaximumEntries); + jsonWriter.WriteNumber("cacheMinimumRecordTtl", _dnsServer.CacheZoneManager.MinimumRecordTtl); + jsonWriter.WriteNumber("cacheMaximumRecordTtl", _dnsServer.CacheZoneManager.MaximumRecordTtl); + jsonWriter.WriteNumber("cacheNegativeRecordTtl", _dnsServer.CacheZoneManager.NegativeRecordTtl); + jsonWriter.WriteNumber("cacheFailureRecordTtl", _dnsServer.CacheZoneManager.FailureRecordTtl); - jsonWriter.WritePropertyName("qpmLimitErrors"); - jsonWriter.WriteValue(_dnsServer.QpmLimitErrors); + jsonWriter.WriteNumber("cachePrefetchEligibility", _dnsServer.CachePrefetchEligibility); + jsonWriter.WriteNumber("cachePrefetchTrigger", _dnsServer.CachePrefetchTrigger); + jsonWriter.WriteNumber("cachePrefetchSampleIntervalInMinutes", _dnsServer.CachePrefetchSampleIntervalInMinutes); + jsonWriter.WriteNumber("cachePrefetchSampleEligibilityHitsPerHour", _dnsServer.CachePrefetchSampleEligibilityHitsPerHour); - jsonWriter.WritePropertyName("qpmLimitSampleMinutes"); - jsonWriter.WriteValue(_dnsServer.QpmLimitSampleMinutes); + //blocking + jsonWriter.WriteBoolean("enableBlocking", _dnsServer.EnableBlocking); + jsonWriter.WriteBoolean("allowTxtBlockingReport", _dnsServer.AllowTxtBlockingReport); - jsonWriter.WritePropertyName("qpmLimitIPv4PrefixLength"); - jsonWriter.WriteValue(_dnsServer.QpmLimitIPv4PrefixLength); + if (!_dnsServer.EnableBlocking && (DateTime.UtcNow < _temporaryDisableBlockingTill)) + jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); - jsonWriter.WritePropertyName("qpmLimitIPv6PrefixLength"); - jsonWriter.WriteValue(_dnsServer.QpmLimitIPv6PrefixLength); + jsonWriter.WriteString("blockingType", _dnsServer.BlockingType.ToString()); - jsonWriter.WritePropertyName("serveStale"); - jsonWriter.WriteValue(_dnsServer.ServeStale); + jsonWriter.WritePropertyName("customBlockingAddresses"); + jsonWriter.WriteStartArray(); - jsonWriter.WritePropertyName("serveStaleTtl"); - jsonWriter.WriteValue(_dnsServer.CacheZoneManager.ServeStaleTtl); + foreach (DnsARecordData record in _dnsServer.CustomBlockingARecords) + jsonWriter.WriteStringValue(record.Address.ToString()); - jsonWriter.WritePropertyName("cacheMaximumEntries"); - jsonWriter.WriteValue(_dnsServer.CacheZoneManager.MaximumEntries); + foreach (DnsAAAARecordData record in _dnsServer.CustomBlockingAAAARecords) + jsonWriter.WriteStringValue(record.Address.ToString()); - jsonWriter.WritePropertyName("cacheMinimumRecordTtl"); - jsonWriter.WriteValue(_dnsServer.CacheZoneManager.MinimumRecordTtl); + jsonWriter.WriteEndArray(); - jsonWriter.WritePropertyName("cacheMaximumRecordTtl"); - jsonWriter.WriteValue(_dnsServer.CacheZoneManager.MaximumRecordTtl); + jsonWriter.WritePropertyName("blockListUrls"); - jsonWriter.WritePropertyName("cacheNegativeRecordTtl"); - jsonWriter.WriteValue(_dnsServer.CacheZoneManager.NegativeRecordTtl); + if ((_dnsServer.BlockListZoneManager.AllowListUrls.Count == 0) && (_dnsServer.BlockListZoneManager.BlockListUrls.Count == 0)) + { + jsonWriter.WriteNullValue(); + } + else + { + jsonWriter.WriteStartArray(); - jsonWriter.WritePropertyName("cacheFailureRecordTtl"); - jsonWriter.WriteValue(_dnsServer.CacheZoneManager.FailureRecordTtl); + foreach (Uri allowListUrl in _dnsServer.BlockListZoneManager.AllowListUrls) + jsonWriter.WriteStringValue("!" + allowListUrl.AbsoluteUri); - jsonWriter.WritePropertyName("cachePrefetchEligibility"); - jsonWriter.WriteValue(_dnsServer.CachePrefetchEligibility); + foreach (Uri blockListUrl in _dnsServer.BlockListZoneManager.BlockListUrls) + jsonWriter.WriteStringValue(blockListUrl.AbsoluteUri); - jsonWriter.WritePropertyName("cachePrefetchTrigger"); - jsonWriter.WriteValue(_dnsServer.CachePrefetchTrigger); + jsonWriter.WriteEndArray(); + } - jsonWriter.WritePropertyName("cachePrefetchSampleIntervalInMinutes"); - jsonWriter.WriteValue(_dnsServer.CachePrefetchSampleIntervalInMinutes); + jsonWriter.WriteNumber("blockListUpdateIntervalHours", _blockListUpdateIntervalHours); - jsonWriter.WritePropertyName("cachePrefetchSampleEligibilityHitsPerHour"); - jsonWriter.WriteValue(_dnsServer.CachePrefetchSampleEligibilityHitsPerHour); + if (_blockListUpdateTimer is not null) + { + DateTime blockListNextUpdatedOn = _blockListLastUpdatedOn.AddHours(_blockListUpdateIntervalHours); + jsonWriter.WriteString("blockListNextUpdatedOn", blockListNextUpdatedOn); + } + + //proxy & forwarders jsonWriter.WritePropertyName("proxy"); if (_dnsServer.Proxy == null) { - jsonWriter.WriteNull(); + jsonWriter.WriteNullValue(); } else { @@ -1812,31 +1727,22 @@ namespace DnsServerCore NetProxy proxy = _dnsServer.Proxy; - jsonWriter.WritePropertyName("type"); - jsonWriter.WriteValue(proxy.Type.ToString()); - - jsonWriter.WritePropertyName("address"); - jsonWriter.WriteValue(proxy.Address); - - jsonWriter.WritePropertyName("port"); - jsonWriter.WriteValue(proxy.Port); + jsonWriter.WriteString("type", proxy.Type.ToString()); + jsonWriter.WriteString("address", proxy.Address); + jsonWriter.WriteNumber("port", proxy.Port); NetworkCredential credential = proxy.Credential; - if (credential != null) { - jsonWriter.WritePropertyName("username"); - jsonWriter.WriteValue(credential.UserName); - - jsonWriter.WritePropertyName("password"); - jsonWriter.WriteValue(credential.Password); + jsonWriter.WriteString("username", credential.UserName); + jsonWriter.WriteString("password", credential.Password); } jsonWriter.WritePropertyName("bypass"); jsonWriter.WriteStartArray(); foreach (NetProxyBypassItem item in proxy.BypassList) - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteStringValue(item.Value); jsonWriter.WriteEndArray(); @@ -1849,7 +1755,7 @@ namespace DnsServerCore if (_dnsServer.Forwarders == null) { - jsonWriter.WriteNull(); + jsonWriter.WriteNullValue(); } else { @@ -1858,77 +1764,34 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (NameServerAddress forwarder in _dnsServer.Forwarders) - jsonWriter.WriteValue(forwarder.OriginalAddress); + jsonWriter.WriteStringValue(forwarder.OriginalAddress); jsonWriter.WriteEndArray(); } - jsonWriter.WritePropertyName("forwarderProtocol"); - jsonWriter.WriteValue(forwarderProtocol.ToString()); + jsonWriter.WriteString("forwarderProtocol", forwarderProtocol.ToString()); - jsonWriter.WritePropertyName("enableBlocking"); - jsonWriter.WriteValue(_dnsServer.EnableBlocking); + jsonWriter.WriteNumber("forwarderRetries", _dnsServer.ForwarderRetries); + jsonWriter.WriteNumber("forwarderTimeout", _dnsServer.ForwarderTimeout); + jsonWriter.WriteNumber("forwarderConcurrency", _dnsServer.ForwarderConcurrency); - jsonWriter.WritePropertyName("allowTxtBlockingReport"); - jsonWriter.WriteValue(_dnsServer.AllowTxtBlockingReport); - - if (!_dnsServer.EnableBlocking && (DateTime.UtcNow < _temporaryDisableBlockingTill)) - { - jsonWriter.WritePropertyName("temporaryDisableBlockingTill"); - jsonWriter.WriteValue(_temporaryDisableBlockingTill); - } - - jsonWriter.WritePropertyName("blockingType"); - jsonWriter.WriteValue(_dnsServer.BlockingType.ToString()); - - jsonWriter.WritePropertyName("customBlockingAddresses"); - jsonWriter.WriteStartArray(); - - foreach (DnsARecordData record in _dnsServer.CustomBlockingARecords) - jsonWriter.WriteValue(record.Address.ToString()); - - foreach (DnsAAAARecordData record in _dnsServer.CustomBlockingAAAARecords) - jsonWriter.WriteValue(record.Address.ToString()); - - jsonWriter.WriteEndArray(); - - jsonWriter.WritePropertyName("blockListUrls"); - - if ((_dnsServer.BlockListZoneManager.AllowListUrls.Count == 0) && (_dnsServer.BlockListZoneManager.BlockListUrls.Count == 0)) - { - jsonWriter.WriteNull(); - } - else - { - jsonWriter.WriteStartArray(); - - foreach (Uri allowListUrl in _dnsServer.BlockListZoneManager.AllowListUrls) - jsonWriter.WriteValue("!" + allowListUrl.AbsoluteUri); - - foreach (Uri blockListUrl in _dnsServer.BlockListZoneManager.BlockListUrls) - jsonWriter.WriteValue(blockListUrl.AbsoluteUri); - - jsonWriter.WriteEndArray(); - } - - jsonWriter.WritePropertyName("blockListUpdateIntervalHours"); - jsonWriter.WriteValue(_blockListUpdateIntervalHours); - - if (_blockListUpdateTimer is not null) - { - DateTime blockListNextUpdatedOn = _blockListLastUpdatedOn.AddHours(_blockListUpdateIntervalHours); - - jsonWriter.WritePropertyName("blockListNextUpdatedOn"); - jsonWriter.WriteValue(blockListNextUpdatedOn); - } + //logging + jsonWriter.WriteBoolean("enableLogging", _log.EnableLogging); + jsonWriter.WriteBoolean("logQueries", _dnsServer.QueryLogManager != null); + jsonWriter.WriteBoolean("useLocalTime", _log.UseLocalTime); + jsonWriter.WriteString("logFolder", _log.LogFolder); + jsonWriter.WriteNumber("maxLogFileDays", _log.MaxLogFileDays); + jsonWriter.WriteNumber("maxStatFileDays", _dnsServer.StatsManager.MaxStatFileDays); } - private void SetDnsSettings(HttpListenerRequest request, JsonTextWriter jsonWriter) + private void SetDnsSettings(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { bool serverDomainChanged = false; bool restartDnsService = false; bool restartWebService = false; + int oldWebServiceHttpPort = _webServiceHttpPort; + //general string strDnsServerDomain = request.QueryString["dnsServerDomain"]; if (!string.IsNullOrEmpty(strDnsServerDomain)) { @@ -1974,6 +1837,71 @@ namespace DnsServerCore } } + string strDefaultRecordTtl = request.QueryString["defaultRecordTtl"]; + if (!string.IsNullOrEmpty(strDefaultRecordTtl)) + _zonesApi.DefaultRecordTtl = uint.Parse(strDefaultRecordTtl); + + string strDnsAppsEnableAutomaticUpdate = request.QueryString["dnsAppsEnableAutomaticUpdate"]; + if (!string.IsNullOrEmpty(strDnsAppsEnableAutomaticUpdate)) + _appsApi.EnableAutomaticUpdate = bool.Parse(strDnsAppsEnableAutomaticUpdate); + + string strPreferIPv6 = request.QueryString["preferIPv6"]; + if (!string.IsNullOrEmpty(strPreferIPv6)) + _dnsServer.PreferIPv6 = bool.Parse(strPreferIPv6); + + string strUdpPayloadSize = request.QueryString["udpPayloadSize"]; + if (!string.IsNullOrEmpty(strUdpPayloadSize)) + _dnsServer.UdpPayloadSize = ushort.Parse(strUdpPayloadSize); + + string strDnssecValidation = request.QueryString["dnssecValidation"]; + if (!string.IsNullOrEmpty(strDnssecValidation)) + _dnsServer.DnssecValidation = bool.Parse(strDnssecValidation); + + string strEDnsClientSubnet = request.QueryString["eDnsClientSubnet"]; + if (!string.IsNullOrEmpty(strEDnsClientSubnet)) + _dnsServer.EDnsClientSubnet = bool.Parse(strEDnsClientSubnet); + + string strEDnsClientSubnetIPv4PrefixLength = request.QueryString["eDnsClientSubnetIPv4PrefixLength"]; + if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv4PrefixLength)) + _dnsServer.EDnsClientSubnetIPv4PrefixLength = byte.Parse(strEDnsClientSubnetIPv4PrefixLength); + + string strEDnsClientSubnetIPv6PrefixLength = request.QueryString["eDnsClientSubnetIPv6PrefixLength"]; + if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv6PrefixLength)) + _dnsServer.EDnsClientSubnetIPv6PrefixLength = byte.Parse(strEDnsClientSubnetIPv6PrefixLength); + + string strQpmLimitRequests = request.QueryString["qpmLimitRequests"]; + if (!string.IsNullOrEmpty(strQpmLimitRequests)) + _dnsServer.QpmLimitRequests = int.Parse(strQpmLimitRequests); + + string strQpmLimitErrors = request.QueryString["qpmLimitErrors"]; + if (!string.IsNullOrEmpty(strQpmLimitErrors)) + _dnsServer.QpmLimitErrors = int.Parse(strQpmLimitErrors); + + string strQpmLimitSampleMinutes = request.QueryString["qpmLimitSampleMinutes"]; + if (!string.IsNullOrEmpty(strQpmLimitSampleMinutes)) + _dnsServer.QpmLimitSampleMinutes = int.Parse(strQpmLimitSampleMinutes); + + string strQpmLimitIPv4PrefixLength = request.QueryString["qpmLimitIPv4PrefixLength"]; + if (!string.IsNullOrEmpty(strQpmLimitIPv4PrefixLength)) + _dnsServer.QpmLimitIPv4PrefixLength = int.Parse(strQpmLimitIPv4PrefixLength); + + string strQpmLimitIPv6PrefixLength = request.QueryString["qpmLimitIPv6PrefixLength"]; + if (!string.IsNullOrEmpty(strQpmLimitIPv6PrefixLength)) + _dnsServer.QpmLimitIPv6PrefixLength = int.Parse(strQpmLimitIPv6PrefixLength); + + string strClientTimeout = request.QueryString["clientTimeout"]; + if (!string.IsNullOrEmpty(strClientTimeout)) + _dnsServer.ClientTimeout = int.Parse(strClientTimeout); + + string strTcpSendTimeout = request.QueryString["tcpSendTimeout"]; + if (!string.IsNullOrEmpty(strTcpSendTimeout)) + _dnsServer.TcpSendTimeout = int.Parse(strTcpSendTimeout); + + string strTcpReceiveTimeout = request.QueryString["tcpReceiveTimeout"]; + if (!string.IsNullOrEmpty(strTcpReceiveTimeout)) + _dnsServer.TcpReceiveTimeout = int.Parse(strTcpReceiveTimeout); + + //web service string strWebServiceLocalAddresses = request.QueryString["webServiceLocalAddresses"]; if (strWebServiceLocalAddresses != null) { @@ -2011,8 +1939,6 @@ namespace DnsServerCore } } - int oldWebServiceHttpPort = _webServiceHttpPort; - string strWebServiceHttpPort = request.QueryString["webServiceHttpPort"]; if (!string.IsNullOrEmpty(strWebServiceHttpPort)) { @@ -2037,6 +1963,10 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(strWebServiceHttpToTlsRedirect)) _webServiceHttpToTlsRedirect = bool.Parse(strWebServiceHttpToTlsRedirect); + string strWebServiceUseSelfSignedTlsCertificate = request.QueryString["webServiceUseSelfSignedTlsCertificate"]; + if (!string.IsNullOrEmpty(strWebServiceUseSelfSignedTlsCertificate)) + _webServiceUseSelfSignedTlsCertificate = bool.Parse(strWebServiceUseSelfSignedTlsCertificate); + string strWebServiceTlsPort = request.QueryString["webServiceTlsPort"]; if (!string.IsNullOrEmpty(strWebServiceTlsPort)) { @@ -2048,10 +1978,6 @@ namespace DnsServerCore restartWebService = true; } - string strWebServiceUseSelfSignedTlsCertificate = request.QueryString["webServiceUseSelfSignedTlsCertificate"]; - if (!string.IsNullOrEmpty(strWebServiceUseSelfSignedTlsCertificate)) - _webServiceUseSelfSignedTlsCertificate = bool.Parse(strWebServiceUseSelfSignedTlsCertificate); - string strWebServiceTlsCertificatePath = request.QueryString["webServiceTlsCertificatePath"]; string strWebServiceTlsCertificatePassword = request.QueryString["webServiceTlsCertificatePassword"]; if (string.IsNullOrEmpty(strWebServiceTlsCertificatePath)) @@ -2075,6 +2001,7 @@ namespace DnsServerCore } } + //optional protocols string enableDnsOverHttp = request.QueryString["enableDnsOverHttp"]; if (!string.IsNullOrEmpty(enableDnsOverHttp)) { @@ -2131,6 +2058,7 @@ namespace DnsServerCore } } + //tsig string strTsigKeys = request.QueryString["tsigKeys"]; if (!string.IsNullOrEmpty(strTsigKeys)) { @@ -2166,103 +2094,7 @@ namespace DnsServerCore } } - string strDefaultRecordTtl = request.QueryString["defaultRecordTtl"]; - if (!string.IsNullOrEmpty(strDefaultRecordTtl)) - _zonesApi.DefaultRecordTtl = uint.Parse(strDefaultRecordTtl); - - string strDnsAppsEnableAutomaticUpdate = request.QueryString["dnsAppsEnableAutomaticUpdate"]; - if (!string.IsNullOrEmpty(strDnsAppsEnableAutomaticUpdate)) - _appsApi.EnableAutomaticUpdate = bool.Parse(strDnsAppsEnableAutomaticUpdate); - - string strPreferIPv6 = request.QueryString["preferIPv6"]; - if (!string.IsNullOrEmpty(strPreferIPv6)) - _dnsServer.PreferIPv6 = bool.Parse(strPreferIPv6); - - string strUdpPayloadSize = request.QueryString["udpPayloadSize"]; - if (!string.IsNullOrEmpty(strUdpPayloadSize)) - _dnsServer.UdpPayloadSize = ushort.Parse(strUdpPayloadSize); - - string strDnssecValidation = request.QueryString["dnssecValidation"]; - if (!string.IsNullOrEmpty(strDnssecValidation)) - _dnsServer.DnssecValidation = bool.Parse(strDnssecValidation); - - string strEDnsClientSubnet = request.QueryString["eDnsClientSubnet"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnet)) - _dnsServer.EDnsClientSubnet = bool.Parse(strEDnsClientSubnet); - - string strEDnsClientSubnetIPv4PrefixLength = request.QueryString["eDnsClientSubnetIPv4PrefixLength"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv4PrefixLength)) - _dnsServer.EDnsClientSubnetIPv4PrefixLength = byte.Parse(strEDnsClientSubnetIPv4PrefixLength); - - string strEDnsClientSubnetIPv6PrefixLength = request.QueryString["eDnsClientSubnetIPv6PrefixLength"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv6PrefixLength)) - _dnsServer.EDnsClientSubnetIPv6PrefixLength = byte.Parse(strEDnsClientSubnetIPv6PrefixLength); - - string strResolverRetries = request.QueryString["resolverRetries"]; - if (!string.IsNullOrEmpty(strResolverRetries)) - _dnsServer.ResolverRetries = int.Parse(strResolverRetries); - - string strResolverTimeout = request.QueryString["resolverTimeout"]; - if (!string.IsNullOrEmpty(strResolverTimeout)) - _dnsServer.ResolverTimeout = int.Parse(strResolverTimeout); - - string strResolverMaxStackCount = request.QueryString["resolverMaxStackCount"]; - if (!string.IsNullOrEmpty(strResolverMaxStackCount)) - _dnsServer.ResolverMaxStackCount = int.Parse(strResolverMaxStackCount); - - string strForwarderRetries = request.QueryString["forwarderRetries"]; - if (!string.IsNullOrEmpty(strForwarderRetries)) - _dnsServer.ForwarderRetries = int.Parse(strForwarderRetries); - - string strForwarderTimeout = request.QueryString["forwarderTimeout"]; - if (!string.IsNullOrEmpty(strForwarderTimeout)) - _dnsServer.ForwarderTimeout = int.Parse(strForwarderTimeout); - - string strForwarderConcurrency = request.QueryString["forwarderConcurrency"]; - if (!string.IsNullOrEmpty(strForwarderConcurrency)) - _dnsServer.ForwarderConcurrency = int.Parse(strForwarderConcurrency); - - string strClientTimeout = request.QueryString["clientTimeout"]; - if (!string.IsNullOrEmpty(strClientTimeout)) - _dnsServer.ClientTimeout = int.Parse(strClientTimeout); - - string strTcpSendTimeout = request.QueryString["tcpSendTimeout"]; - if (!string.IsNullOrEmpty(strTcpSendTimeout)) - _dnsServer.TcpSendTimeout = int.Parse(strTcpSendTimeout); - - string strTcpReceiveTimeout = request.QueryString["tcpReceiveTimeout"]; - if (!string.IsNullOrEmpty(strTcpReceiveTimeout)) - _dnsServer.TcpReceiveTimeout = int.Parse(strTcpReceiveTimeout); - - string strEnableLogging = request.QueryString["enableLogging"]; - if (!string.IsNullOrEmpty(strEnableLogging)) - _log.EnableLogging = bool.Parse(strEnableLogging); - - string strLogQueries = request.QueryString["logQueries"]; - if (!string.IsNullOrEmpty(strLogQueries)) - { - if (bool.Parse(strLogQueries)) - _dnsServer.QueryLogManager = _log; - else - _dnsServer.QueryLogManager = null; - } - - string strUseLocalTime = request.QueryString["useLocalTime"]; - if (!string.IsNullOrEmpty(strUseLocalTime)) - _log.UseLocalTime = bool.Parse(strUseLocalTime); - - string strLogFolder = request.QueryString["logFolder"]; - if (!string.IsNullOrEmpty(strLogFolder)) - _log.LogFolder = strLogFolder; - - string strMaxLogFileDays = request.QueryString["maxLogFileDays"]; - if (!string.IsNullOrEmpty(strMaxLogFileDays)) - _log.MaxLogFileDays = int.Parse(strMaxLogFileDays); - - string strMaxStatFileDays = request.QueryString["maxStatFileDays"]; - if (!string.IsNullOrEmpty(strMaxStatFileDays)) - _dnsServer.StatsManager.MaxStatFileDays = int.Parse(strMaxStatFileDays); - + //recursion string strRecursion = request.QueryString["recursion"]; if (!string.IsNullOrEmpty(strRecursion)) _dnsServer.Recursion = Enum.Parse(strRecursion, true); @@ -2319,26 +2151,19 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(strNsRevalidation)) _dnsServer.NsRevalidation = bool.Parse(strNsRevalidation); - string strQpmLimitRequests = request.QueryString["qpmLimitRequests"]; - if (!string.IsNullOrEmpty(strQpmLimitRequests)) - _dnsServer.QpmLimitRequests = int.Parse(strQpmLimitRequests); + string strResolverRetries = request.QueryString["resolverRetries"]; + if (!string.IsNullOrEmpty(strResolverRetries)) + _dnsServer.ResolverRetries = int.Parse(strResolverRetries); - string strQpmLimitErrors = request.QueryString["qpmLimitErrors"]; - if (!string.IsNullOrEmpty(strQpmLimitErrors)) - _dnsServer.QpmLimitErrors = int.Parse(strQpmLimitErrors); + string strResolverTimeout = request.QueryString["resolverTimeout"]; + if (!string.IsNullOrEmpty(strResolverTimeout)) + _dnsServer.ResolverTimeout = int.Parse(strResolverTimeout); - string strQpmLimitSampleMinutes = request.QueryString["qpmLimitSampleMinutes"]; - if (!string.IsNullOrEmpty(strQpmLimitSampleMinutes)) - _dnsServer.QpmLimitSampleMinutes = int.Parse(strQpmLimitSampleMinutes); - - string strQpmLimitIPv4PrefixLength = request.QueryString["qpmLimitIPv4PrefixLength"]; - if (!string.IsNullOrEmpty(strQpmLimitIPv4PrefixLength)) - _dnsServer.QpmLimitIPv4PrefixLength = int.Parse(strQpmLimitIPv4PrefixLength); - - string strQpmLimitIPv6PrefixLength = request.QueryString["qpmLimitIPv6PrefixLength"]; - if (!string.IsNullOrEmpty(strQpmLimitIPv6PrefixLength)) - _dnsServer.QpmLimitIPv6PrefixLength = int.Parse(strQpmLimitIPv6PrefixLength); + string strResolverMaxStackCount = request.QueryString["resolverMaxStackCount"]; + if (!string.IsNullOrEmpty(strResolverMaxStackCount)) + _dnsServer.ResolverMaxStackCount = int.Parse(strResolverMaxStackCount); + //cache string strServeStale = request.QueryString["serveStale"]; if (!string.IsNullOrEmpty(strServeStale)) _dnsServer.ServeStale = bool.Parse(strServeStale); @@ -2383,69 +2208,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(strCachePrefetchSampleEligibilityHitsPerHour)) _dnsServer.CachePrefetchSampleEligibilityHitsPerHour = int.Parse(strCachePrefetchSampleEligibilityHitsPerHour); - string strProxyType = request.QueryString["proxyType"]; - if (!string.IsNullOrEmpty(strProxyType)) - { - NetProxyType proxyType = Enum.Parse(strProxyType, true); - if (proxyType == NetProxyType.None) - { - _dnsServer.Proxy = null; - } - else - { - NetworkCredential credential = null; - - string strUsername = request.QueryString["proxyUsername"]; - if (!string.IsNullOrEmpty(strUsername)) - credential = new NetworkCredential(strUsername, request.QueryString["proxyPassword"]); - - _dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.QueryString["proxyAddress"], int.Parse(request.QueryString["proxyPort"]), credential); - - string strProxyBypass = request.QueryString["proxyBypass"]; - if (!string.IsNullOrEmpty(strProxyBypass)) - { - string[] strBypassList = strProxyBypass.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List bypassList = new List(strBypassList.Length); - - for (int i = 0; i < strBypassList.Length; i++) - bypassList.Add(new NetProxyBypassItem(strBypassList[i])); - - _dnsServer.Proxy.BypassList = bypassList; - } - } - } - - DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; - string strForwarderProtocol = request.QueryString["forwarderProtocol"]; - if (!string.IsNullOrEmpty(strForwarderProtocol)) - forwarderProtocol = Enum.Parse(strForwarderProtocol, true); - - string strForwarders = request.QueryString["forwarders"]; - if (!string.IsNullOrEmpty(strForwarders)) - { - if (strForwarders == "false") - { - _dnsServer.Forwarders = null; - } - else - { - string[] strForwardersList = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - NameServerAddress[] forwarders = new NameServerAddress[strForwardersList.Length]; - - for (int i = 0; i < strForwardersList.Length; i++) - { - NameServerAddress forwarder = new NameServerAddress(strForwardersList[i]); - - if (forwarder.Protocol != forwarderProtocol) - forwarder = forwarder.ChangeProtocol(forwarderProtocol); - - forwarders[i] = forwarder; - } - - _dnsServer.Forwarders = forwarders; - } - } - + //blocking string strEnableBlocking = request.QueryString["enableBlocking"]; if (!string.IsNullOrEmpty(strEnableBlocking)) { @@ -2610,6 +2373,117 @@ namespace DnsServerCore StopBlockListUpdateTimer(); } + //proxy & forwarders + string strProxyType = request.QueryString["proxyType"]; + if (!string.IsNullOrEmpty(strProxyType)) + { + NetProxyType proxyType = Enum.Parse(strProxyType, true); + if (proxyType == NetProxyType.None) + { + _dnsServer.Proxy = null; + } + else + { + NetworkCredential credential = null; + + string strUsername = request.QueryString["proxyUsername"]; + if (!string.IsNullOrEmpty(strUsername)) + credential = new NetworkCredential(strUsername, request.QueryString["proxyPassword"]); + + _dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.QueryString["proxyAddress"], int.Parse(request.QueryString["proxyPort"]), credential); + + string strProxyBypass = request.QueryString["proxyBypass"]; + if (!string.IsNullOrEmpty(strProxyBypass)) + { + string[] strBypassList = strProxyBypass.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + List bypassList = new List(strBypassList.Length); + + for (int i = 0; i < strBypassList.Length; i++) + bypassList.Add(new NetProxyBypassItem(strBypassList[i])); + + _dnsServer.Proxy.BypassList = bypassList; + } + } + } + + DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; + string strForwarderProtocol = request.QueryString["forwarderProtocol"]; + if (!string.IsNullOrEmpty(strForwarderProtocol)) + { + forwarderProtocol = Enum.Parse(strForwarderProtocol, true); + if (forwarderProtocol == DnsTransportProtocol.HttpsJson) + forwarderProtocol = DnsTransportProtocol.Https; + } + + string strForwarders = request.QueryString["forwarders"]; + if (!string.IsNullOrEmpty(strForwarders)) + { + if (strForwarders == "false") + { + _dnsServer.Forwarders = null; + } + else + { + string[] strForwardersList = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + NameServerAddress[] forwarders = new NameServerAddress[strForwardersList.Length]; + + for (int i = 0; i < strForwardersList.Length; i++) + { + NameServerAddress forwarder = new NameServerAddress(strForwardersList[i]); + + if (forwarder.Protocol != forwarderProtocol) + forwarder = forwarder.ChangeProtocol(forwarderProtocol); + + forwarders[i] = forwarder; + } + + _dnsServer.Forwarders = forwarders; + } + } + + string strForwarderRetries = request.QueryString["forwarderRetries"]; + if (!string.IsNullOrEmpty(strForwarderRetries)) + _dnsServer.ForwarderRetries = int.Parse(strForwarderRetries); + + string strForwarderTimeout = request.QueryString["forwarderTimeout"]; + if (!string.IsNullOrEmpty(strForwarderTimeout)) + _dnsServer.ForwarderTimeout = int.Parse(strForwarderTimeout); + + string strForwarderConcurrency = request.QueryString["forwarderConcurrency"]; + if (!string.IsNullOrEmpty(strForwarderConcurrency)) + _dnsServer.ForwarderConcurrency = int.Parse(strForwarderConcurrency); + + //logging + string strEnableLogging = request.QueryString["enableLogging"]; + if (!string.IsNullOrEmpty(strEnableLogging)) + _log.EnableLogging = bool.Parse(strEnableLogging); + + string strLogQueries = request.QueryString["logQueries"]; + if (!string.IsNullOrEmpty(strLogQueries)) + { + if (bool.Parse(strLogQueries)) + _dnsServer.QueryLogManager = _log; + else + _dnsServer.QueryLogManager = null; + } + + string strUseLocalTime = request.QueryString["useLocalTime"]; + if (!string.IsNullOrEmpty(strUseLocalTime)) + _log.UseLocalTime = bool.Parse(strUseLocalTime); + + string strLogFolder = request.QueryString["logFolder"]; + if (!string.IsNullOrEmpty(strLogFolder)) + _log.LogFolder = strLogFolder; + + string strMaxLogFileDays = request.QueryString["maxLogFileDays"]; + if (!string.IsNullOrEmpty(strMaxLogFileDays)) + _log.MaxLogFileDays = int.Parse(strMaxLogFileDays); + + string strMaxStatFileDays = request.QueryString["maxStatFileDays"]; + if (!string.IsNullOrEmpty(strMaxStatFileDays)) + _dnsServer.StatsManager.MaxStatFileDays = int.Parse(strMaxStatFileDays); + + //TLS actions if ((_webServiceTlsCertificatePath == null) && (_dnsTlsCertificatePath == null)) StopTlsCertificateUpdateTimer(); @@ -2622,6 +2496,7 @@ namespace DnsServerCore restartWebService = true; } + //save config SaveConfigFile(); _log.Save(); @@ -2632,7 +2507,7 @@ namespace DnsServerCore RestartService(restartDnsService, restartWebService); } - private void GetTsigKeyNames(JsonTextWriter jsonWriter) + private void GetTsigKeyNames(Utf8JsonWriter jsonWriter) { jsonWriter.WritePropertyName("tsigKeyNames"); { @@ -2641,7 +2516,7 @@ namespace DnsServerCore if (_dnsServer.TsigKeys is not null) { foreach (KeyValuePair tsigKey in _dnsServer.TsigKeys) - jsonWriter.WriteValue(tsigKey.Key); + jsonWriter.WriteStringValue(tsigKey.Key); } jsonWriter.WriteEndArray(); @@ -2969,7 +2844,7 @@ namespace DnsServerCore } } - private async Task RestoreSettingsAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + private async Task RestoreSettingsAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { bool blockLists = false; bool logs = false; @@ -3127,17 +3002,6 @@ namespace DnsServerCore _authManager.LoadConfigFile(session); } - if (dnsSettings) - { - ZipArchiveEntry entry = backupZip.GetEntry("dns.config"); - if (entry != null) - entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true); - - //reload settings and block list zone - LoadConfigFile(); - _dnsServer.BlockListZoneManager.LoadBlockLists(); - } - if (blockLists) { if (deleteExistingFiles) @@ -3158,6 +3022,36 @@ namespace DnsServerCore } } + if (dnsSettings) + { + ZipArchiveEntry entry = backupZip.GetEntry("dns.config"); + if (entry != null) + entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true); + + //reload settings and block list zone + LoadConfigFile(); + + if ((_blockListUpdateIntervalHours > 0) && (_dnsServer.BlockListZoneManager.BlockListUrls.Count > 0)) + { + ThreadPool.QueueUserWorkItem(delegate (object state) + { + try + { + _dnsServer.BlockListZoneManager.LoadBlockLists(); + StartBlockListUpdateTimer(); + } + catch (Exception ex) + { + _log.Write(ex); + } + }); + } + else + { + StopBlockListUpdateTimer(); + } + } + if (apps) { //unload apps @@ -3344,7 +3238,7 @@ namespace DnsServerCore _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).User.Username + "] Block list update was triggered."); } - private void TemporaryDisableBlocking(HttpListenerRequest request, JsonTextWriter jsonWriter) + private void TemporaryDisableBlocking(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strMinutes = request.QueryString["minutes"]; if (string.IsNullOrEmpty(strMinutes)) @@ -3383,15 +3277,14 @@ namespace DnsServerCore newTemporaryDisableBlockingTimer.Dispose(); } - jsonWriter.WritePropertyName("temporaryDisableBlockingTill"); - jsonWriter.WriteValue(_temporaryDisableBlockingTill); + jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); } #endregion #region dns client api - private async Task ResolveQueryAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + private async Task ResolveQueryAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string server = request.QueryString["server"]; if (string.IsNullOrEmpty(server)) @@ -3487,11 +3380,8 @@ namespace DnsServerCore case DnsTransportProtocol.Https: throw new DnsServerException("Cannot use DNS-over-HTTPS protocol for 'this-server'. Please use the TLS certificate domain name with a url as the server."); - case DnsTransportProtocol.HttpsJson: - throw new DnsServerException("Cannot use DNS-over-HTTPS (JSON) protocol for 'this-server'. Please use the TLS certificate domain name with a url as the server."); - default: - throw new InvalidOperationException(); + throw new NotSupportedException("DNS transport protocol is not supported: " + protocol.ToString()); } proxy = null; //no proxy required for this server @@ -3632,13 +3522,10 @@ namespace DnsServerCore } if (dnssecErrorMessage is not null) - { - jsonWriter.WritePropertyName("warningMessage"); - jsonWriter.WriteValue(dnssecErrorMessage); - } + jsonWriter.WriteString("warningMessage", dnssecErrorMessage); jsonWriter.WritePropertyName("result"); - jsonWriter.WriteRawValue(JsonConvert.SerializeObject(dnsResponse, new StringEnumConverter())); + dnsResponse.SerializeTo(jsonWriter); } #endregion @@ -3910,9 +3797,15 @@ namespace DnsServerCore string strForwarderProtocol = Environment.GetEnvironmentVariable("DNS_SERVER_FORWARDER_PROTOCOL"); if (string.IsNullOrEmpty(strForwarderProtocol)) + { forwarderProtocol = DnsTransportProtocol.Udp; + } else + { forwarderProtocol = Enum.Parse(strForwarderProtocol, true); + if (forwarderProtocol == DnsTransportProtocol.HttpsJson) + forwarderProtocol = DnsTransportProtocol.Https; + } List forwarders = new List(); string[] strForwardersAddresses = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); @@ -4323,8 +4216,13 @@ namespace DnsServerCore NameServerAddress[] forwarders = new NameServerAddress[count]; for (int i = 0; i < count; i++) + { forwarders[i] = new NameServerAddress(bR); + if (forwarders[i].Protocol == DnsTransportProtocol.HttpsJson) + forwarders[i] = forwarders[i].ChangeProtocol(DnsTransportProtocol.Https); + } + _dnsServer.Forwarders = forwarders; } } @@ -4562,7 +4460,11 @@ namespace DnsServerCore NameServerAddress[] forwarders = new NameServerAddress[count]; for (int i = 0; i < count; i++) + { forwarders[i] = new NameServerAddress(bR); + if (forwarders[i].Protocol == DnsTransportProtocol.HttpsJson) + forwarders[i] = forwarders[i].ChangeProtocol(DnsTransportProtocol.Https); + } _dnsServer.Forwarders = forwarders; } @@ -4571,6 +4473,8 @@ namespace DnsServerCore if (version <= 10) { DnsTransportProtocol forwarderProtocol = (DnsTransportProtocol)bR.ReadByte(); + if (forwarderProtocol == DnsTransportProtocol.HttpsJson) + forwarderProtocol = DnsTransportProtocol.Https; if (_dnsServer.Forwarders != null) { From a13bd80399b7320d7580a647d6713a7c0837a95d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 13:03:35 +0530 Subject: [PATCH 025/191] WebServiceAppsApi: removed newtonsoft. --- DnsServerCore/WebServiceAppsApi.cs | 204 +++++++++++++---------------- 1 file changed, 89 insertions(+), 115 deletions(-) diff --git a/DnsServerCore/WebServiceAppsApi.cs b/DnsServerCore/WebServiceAppsApi.cs index d72b5801..04879045 100644 --- a/DnsServerCore/WebServiceAppsApi.cs +++ b/DnsServerCore/WebServiceAppsApi.cs @@ -19,12 +19,12 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using DnsServerCore.Dns.Applications; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using TechnitiumLibrary; @@ -92,22 +92,23 @@ namespace DnsServerCore _dnsWebService.Log.Write("DNS Server has started automatic update check for DNS Apps."); string storeAppsJsonData = await GetStoreAppsJsonData().WithTimeout(5000); - dynamic jsonStoreAppsArray = JsonConvert.DeserializeObject(storeAppsJsonData); + using JsonDocument jsonDocument = JsonDocument.Parse(storeAppsJsonData); + JsonElement jsonStoreAppsArray = jsonDocument.RootElement; foreach (DnsApplication application in _dnsWebService.DnsServer.DnsApplicationManager.Applications.Values) { - foreach (dynamic jsonStoreApp in jsonStoreAppsArray) + foreach (JsonElement jsonStoreApp in jsonStoreAppsArray.EnumerateArray()) { - string name = jsonStoreApp.name.Value; + string name = jsonStoreApp.GetProperty("name").GetString(); if (name.Equals(application.Name)) { string url = null; Version storeAppVersion = null; Version lastServerVersion = null; - foreach (dynamic jsonVersion in jsonStoreApp.versions) + foreach (JsonElement jsonVersion in jsonStoreApp.GetProperty("versions").EnumerateArray()) { - string strServerVersion = jsonVersion.serverVersion.Value; + string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); Version requiredServerVersion = new Version(strServerVersion); if (_dnsWebService.ServerVersion < requiredServerVersion) @@ -116,8 +117,8 @@ namespace DnsServerCore if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) continue; - string version = jsonVersion.version.Value; - url = jsonVersion.url.Value; + string version = jsonVersion.GetProperty("version").GetString(); + url = jsonVersion.GetProperty("url").GetString(); storeAppVersion = new Version(version); lastServerVersion = requiredServerVersion; @@ -219,24 +220,19 @@ namespace DnsServerCore } } - private void WriteAppAsJson(JsonTextWriter jsonWriter, DnsApplication application, dynamic jsonStoreAppsArray) + private void WriteAppAsJson(Utf8JsonWriter jsonWriter, DnsApplication application, JsonElement jsonStoreAppsArray = default) { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(application.Name); - - jsonWriter.WritePropertyName("description"); - jsonWriter.WriteValue(application.Description); + jsonWriter.WriteString("name", application.Name); + jsonWriter.WriteString("description", application.Description); + jsonWriter.WriteString("version", DnsWebService.GetCleanVersion(application.Version)); - jsonWriter.WritePropertyName("version"); - jsonWriter.WriteValue(DnsWebService.GetCleanVersion(application.Version)); - - if (jsonStoreAppsArray != null) + if (jsonStoreAppsArray.ValueKind != JsonValueKind.Undefined) { - foreach (dynamic jsonStoreApp in jsonStoreAppsArray) + foreach (JsonElement jsonStoreApp in jsonStoreAppsArray.EnumerateArray()) { - string name = jsonStoreApp.name.Value; + string name = jsonStoreApp.GetProperty("name").GetString(); if (name.Equals(application.Name)) { string version = null; @@ -244,9 +240,9 @@ namespace DnsServerCore Version storeAppVersion = null; Version lastServerVersion = null; - foreach (dynamic jsonVersion in jsonStoreApp.versions) + foreach (JsonElement jsonVersion in jsonStoreApp.GetProperty("versions").EnumerateArray()) { - string strServerVersion = jsonVersion.serverVersion.Value; + string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); Version requiredServerVersion = new Version(strServerVersion); if (_dnsWebService.ServerVersion < requiredServerVersion) @@ -255,8 +251,8 @@ namespace DnsServerCore if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) continue; - version = jsonVersion.version.Value; - url = jsonVersion.url.Value; + version = jsonVersion.GetProperty("version").GetString(); + url = jsonVersion.GetProperty("url").GetString(); storeAppVersion = new Version(version); lastServerVersion = requiredServerVersion; @@ -265,14 +261,9 @@ namespace DnsServerCore if (storeAppVersion is null) break; //no compatible update available - jsonWriter.WritePropertyName("updateVersion"); - jsonWriter.WriteValue(version); - - jsonWriter.WritePropertyName("updateUrl"); - jsonWriter.WriteValue(url); - - jsonWriter.WritePropertyName("updateAvailable"); - jsonWriter.WriteValue(storeAppVersion > application.Version); + jsonWriter.WriteString("updateVersion", version); + jsonWriter.WriteString("updateUrl", url); + jsonWriter.WriteBoolean("updateAvailable", storeAppVersion > application.Version); break; } } @@ -286,37 +277,23 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("classPath"); - jsonWriter.WriteValue(dnsApp.Key); - - jsonWriter.WritePropertyName("description"); - jsonWriter.WriteValue(dnsApp.Value.Description); + jsonWriter.WriteString("classPath", dnsApp.Key); + jsonWriter.WriteString("description", dnsApp.Value.Description); if (dnsApp.Value is IDnsAppRecordRequestHandler appRecordHandler) { - jsonWriter.WritePropertyName("isAppRecordRequestHandler"); - jsonWriter.WriteValue(true); - - jsonWriter.WritePropertyName("recordDataTemplate"); - jsonWriter.WriteValue(appRecordHandler.ApplicationRecordDataTemplate); + jsonWriter.WriteBoolean("isAppRecordRequestHandler", true); + jsonWriter.WriteString("recordDataTemplate", appRecordHandler.ApplicationRecordDataTemplate); } else { - jsonWriter.WritePropertyName("isAppRecordRequestHandler"); - jsonWriter.WriteValue(false); + jsonWriter.WriteBoolean("isAppRecordRequestHandler", false); } - jsonWriter.WritePropertyName("isRequestController"); - jsonWriter.WriteValue(dnsApp.Value is IDnsRequestController); - - jsonWriter.WritePropertyName("isAuthoritativeRequestHandler"); - jsonWriter.WriteValue(dnsApp.Value is IDnsAuthoritativeRequestHandler); - - jsonWriter.WritePropertyName("isQueryLogger"); - jsonWriter.WriteValue(dnsApp.Value is IDnsQueryLogger); - - jsonWriter.WritePropertyName("isPostProcessor"); - jsonWriter.WriteValue(dnsApp.Value is IDnsPostProcessor); + jsonWriter.WriteBoolean("isRequestController", dnsApp.Value is IDnsRequestController); + jsonWriter.WriteBoolean("isAuthoritativeRequestHandler", dnsApp.Value is IDnsAuthoritativeRequestHandler); + jsonWriter.WriteBoolean("isQueryLogger", dnsApp.Value is IDnsQueryLogger); + jsonWriter.WriteBoolean("isPostProcessor", dnsApp.Value is IDnsPostProcessor); jsonWriter.WriteEndObject(); } @@ -331,57 +308,68 @@ namespace DnsServerCore #region public - public async Task ListInstalledAppsAsync(JsonTextWriter jsonWriter) + public async Task ListInstalledAppsAsync(Utf8JsonWriter jsonWriter) { List apps = new List(_dnsWebService.DnsServer.DnsApplicationManager.Applications.Keys); apps.Sort(); - dynamic jsonStoreAppsArray = null; - - if (apps.Count > 0) + JsonDocument jsonDocument = null; + try { - try + JsonElement jsonStoreAppsArray = default; + + if (apps.Count > 0) { - string storeAppsJsonData = await GetStoreAppsJsonData().WithTimeout(5000); - jsonStoreAppsArray = JsonConvert.DeserializeObject(storeAppsJsonData); + try + { + string storeAppsJsonData = await GetStoreAppsJsonData().WithTimeout(5000); + jsonDocument = JsonDocument.Parse(storeAppsJsonData); + jsonStoreAppsArray = jsonDocument.RootElement; + } + catch + { } } - catch - { } + + jsonWriter.WritePropertyName("apps"); + jsonWriter.WriteStartArray(); + + foreach (string app in apps) + { + if (_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(app, out DnsApplication application)) + WriteAppAsJson(jsonWriter, application, jsonStoreAppsArray); + } + + jsonWriter.WriteEndArray(); } - - jsonWriter.WritePropertyName("apps"); - jsonWriter.WriteStartArray(); - - foreach (string app in apps) + finally { - if (_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(app, out DnsApplication application)) - WriteAppAsJson(jsonWriter, application, jsonStoreAppsArray); + if (jsonDocument is not null) + jsonDocument.Dispose(); } - - jsonWriter.WriteEndArray(); } - public async Task ListStoreApps(JsonTextWriter jsonWriter) + public async Task ListStoreApps(Utf8JsonWriter jsonWriter) { string storeAppsJsonData = await GetStoreAppsJsonData(); - dynamic jsonStoreAppsArray = JsonConvert.DeserializeObject(storeAppsJsonData); + using JsonDocument jsonDocument = JsonDocument.Parse(storeAppsJsonData); + JsonElement jsonStoreAppsArray = jsonDocument.RootElement; jsonWriter.WritePropertyName("storeApps"); jsonWriter.WriteStartArray(); - foreach (dynamic jsonStoreApp in jsonStoreAppsArray) + foreach (JsonElement jsonStoreApp in jsonStoreAppsArray.EnumerateArray()) { - string name = jsonStoreApp.name.Value; - string description = jsonStoreApp.description.Value; + string name = jsonStoreApp.GetProperty("name").GetString(); + string description = jsonStoreApp.GetProperty("description").GetString(); string version = null; string url = null; string size = null; Version storeAppVersion = null; Version lastServerVersion = null; - foreach (dynamic jsonVersion in jsonStoreApp.versions) + foreach (JsonElement jsonVersion in jsonStoreApp.GetProperty("versions").EnumerateArray()) { - string strServerVersion = jsonVersion.serverVersion.Value; + string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); Version requiredServerVersion = new Version(strServerVersion); if (_dnsWebService.ServerVersion < requiredServerVersion) @@ -390,9 +378,9 @@ namespace DnsServerCore if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) continue; - version = jsonVersion.version.Value; - url = jsonVersion.url.Value; - size = jsonVersion.size.Value; + version = jsonVersion.GetProperty("version").GetString(); + url = jsonVersion.GetProperty("url").GetString(); + size = jsonVersion.GetProperty("size").GetString(); storeAppVersion = new Version(version); lastServerVersion = requiredServerVersion; @@ -403,33 +391,20 @@ namespace DnsServerCore jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(name); - - jsonWriter.WritePropertyName("description"); - jsonWriter.WriteValue(description); - - jsonWriter.WritePropertyName("version"); - jsonWriter.WriteValue(version); - - jsonWriter.WritePropertyName("url"); - jsonWriter.WriteValue(url); - - jsonWriter.WritePropertyName("size"); - jsonWriter.WriteValue(size); + jsonWriter.WriteString("name", name); + jsonWriter.WriteString("description", description); + jsonWriter.WriteString("version", version); + jsonWriter.WriteString("url", url); + jsonWriter.WriteString("size", size); bool installed = _dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); - jsonWriter.WritePropertyName("installed"); - jsonWriter.WriteValue(installed); + jsonWriter.WriteBoolean("installed", installed); if (installed) { - jsonWriter.WritePropertyName("installedVersion"); - jsonWriter.WriteValue(DnsWebService.GetCleanVersion(installedApp.Version)); - - jsonWriter.WritePropertyName("updateAvailable"); - jsonWriter.WriteValue(storeAppVersion > installedApp.Version); + jsonWriter.WriteString("installedVersion", DnsWebService.GetCleanVersion(installedApp.Version)); + jsonWriter.WriteBoolean("updateAvailable", storeAppVersion > installedApp.Version); } jsonWriter.WriteEndObject(); @@ -438,7 +413,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public async Task DownloadAndInstallAppAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task DownloadAndInstallAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string name = request.QueryString["name"]; if (string.IsNullOrEmpty(name)) @@ -479,7 +454,7 @@ namespace DnsServerCore _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully from: " + url); jsonWriter.WritePropertyName("installedApp"); - WriteAppAsJson(jsonWriter, application, null); + WriteAppAsJson(jsonWriter, application); } } finally @@ -495,7 +470,7 @@ namespace DnsServerCore } } - public async Task DownloadAndUpdateAppAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task DownloadAndUpdateAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string name = request.QueryString["name"]; if (string.IsNullOrEmpty(name)) @@ -515,10 +490,10 @@ namespace DnsServerCore _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully from: " + url); jsonWriter.WritePropertyName("updatedApp"); - WriteAppAsJson(jsonWriter, application, null); + WriteAppAsJson(jsonWriter, application); } - public async Task InstallAppAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task InstallAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string name = request.QueryString["name"]; if (string.IsNullOrEmpty(name)) @@ -564,7 +539,7 @@ namespace DnsServerCore _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully."); jsonWriter.WritePropertyName("installedApp"); - WriteAppAsJson(jsonWriter, application, null); + WriteAppAsJson(jsonWriter, application); } } finally @@ -580,7 +555,7 @@ namespace DnsServerCore } } - public async Task UpdateAppAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task UpdateAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string name = request.QueryString["name"]; if (string.IsNullOrEmpty(name)) @@ -626,7 +601,7 @@ namespace DnsServerCore _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully."); jsonWriter.WritePropertyName("updatedApp"); - WriteAppAsJson(jsonWriter, application, null); + WriteAppAsJson(jsonWriter, application); } } finally @@ -654,7 +629,7 @@ namespace DnsServerCore _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was uninstalled successfully."); } - public async Task GetAppConfigAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task GetAppConfigAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string name = request.QueryString["name"]; if (string.IsNullOrEmpty(name)) @@ -667,8 +642,7 @@ namespace DnsServerCore string config = await application.GetConfigAsync(); - jsonWriter.WritePropertyName("config"); - jsonWriter.WriteValue(config); + jsonWriter.WriteString("config", config); } public async Task SetAppConfigAsync(HttpListenerRequest request) From 5dcbcdcca4a606777edc9bf67e9674d175340eb8 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 13:06:05 +0530 Subject: [PATCH 026/191] WebServiceAuthApi: removed newtonsoft. --- DnsServerCore/WebServiceAuthApi.cs | 219 ++++++++++------------------- 1 file changed, 72 insertions(+), 147 deletions(-) diff --git a/DnsServerCore/WebServiceAuthApi.cs b/DnsServerCore/WebServiceAuthApi.cs index 869e4548..139c6093 100644 --- a/DnsServerCore/WebServiceAuthApi.cs +++ b/DnsServerCore/WebServiceAuthApi.cs @@ -18,10 +18,10 @@ along with this program. If not, see . */ using DnsServerCore.Auth; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; namespace DnsServerCore @@ -45,29 +45,19 @@ namespace DnsServerCore #region private - private void WriteCurrentSessionDetails(JsonTextWriter jsonWriter, UserSession currentSession, bool includeInfo) + private void WriteCurrentSessionDetails(Utf8JsonWriter jsonWriter, UserSession currentSession, bool includeInfo) { if (currentSession.Type == UserSessionType.ApiToken) { - jsonWriter.WritePropertyName("username"); - jsonWriter.WriteValue(currentSession.User.Username); - - jsonWriter.WritePropertyName("tokenName"); - jsonWriter.WriteValue(currentSession.TokenName); - - jsonWriter.WritePropertyName("token"); - jsonWriter.WriteValue(currentSession.Token); + jsonWriter.WriteString("username", currentSession.User.Username); + jsonWriter.WriteString("tokenName", currentSession.TokenName); + jsonWriter.WriteString("token", currentSession.Token); } else { - jsonWriter.WritePropertyName("displayName"); - jsonWriter.WriteValue(currentSession.User.DisplayName); - - jsonWriter.WritePropertyName("username"); - jsonWriter.WriteValue(currentSession.User.Username); - - jsonWriter.WritePropertyName("token"); - jsonWriter.WriteValue(currentSession.Token); + jsonWriter.WriteString("displayName", currentSession.User.DisplayName); + jsonWriter.WriteString("username", currentSession.User.Username); + jsonWriter.WriteString("token", currentSession.Token); } if (includeInfo) @@ -75,14 +65,9 @@ namespace DnsServerCore jsonWriter.WritePropertyName("info"); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("version"); - jsonWriter.WriteValue(_dnsWebService.GetServerVersion()); - - jsonWriter.WritePropertyName("dnsServerDomain"); - jsonWriter.WriteValue(_dnsWebService.DnsServer.ServerDomain); - - jsonWriter.WritePropertyName("defaultRecordTtl"); - jsonWriter.WriteValue(_dnsWebService.ZonesApi.DefaultRecordTtl); + jsonWriter.WriteString("version", _dnsWebService.GetServerVersion()); + jsonWriter.WriteString("dnsServerDomain", _dnsWebService.DnsServer.ServerDomain); + jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService.ZonesApi.DefaultRecordTtl); jsonWriter.WritePropertyName("permissions"); jsonWriter.WriteStartObject(); @@ -94,14 +79,9 @@ namespace DnsServerCore jsonWriter.WritePropertyName(section.ToString()); jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("canView"); - jsonWriter.WriteValue(_dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.View)); - - jsonWriter.WritePropertyName("canModify"); - jsonWriter.WriteValue(_dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Modify)); - - jsonWriter.WritePropertyName("canDelete"); - jsonWriter.WriteValue(_dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Delete)); + jsonWriter.WriteBoolean("canView", _dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.View)); + jsonWriter.WriteBoolean("canModify", _dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Modify)); + jsonWriter.WriteBoolean("canDelete", _dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } @@ -112,33 +92,19 @@ namespace DnsServerCore } } - private void WriteUserDetails(JsonTextWriter jsonWriter, User user, UserSession currentSession, bool includeMoreDetails, bool includeGroups) + private void WriteUserDetails(Utf8JsonWriter jsonWriter, User user, UserSession currentSession, bool includeMoreDetails, bool includeGroups) { - jsonWriter.WritePropertyName("displayName"); - jsonWriter.WriteValue(user.DisplayName); - - jsonWriter.WritePropertyName("username"); - jsonWriter.WriteValue(user.Username); - - jsonWriter.WritePropertyName("disabled"); - jsonWriter.WriteValue(user.Disabled); - - jsonWriter.WritePropertyName("previousSessionLoggedOn"); - jsonWriter.WriteValue(user.PreviousSessionLoggedOn); - - jsonWriter.WritePropertyName("previousSessionRemoteAddress"); - jsonWriter.WriteValue(user.PreviousSessionRemoteAddress.ToString()); - - jsonWriter.WritePropertyName("recentSessionLoggedOn"); - jsonWriter.WriteValue(user.RecentSessionLoggedOn); - - jsonWriter.WritePropertyName("recentSessionRemoteAddress"); - jsonWriter.WriteValue(user.RecentSessionRemoteAddress.ToString()); + jsonWriter.WriteString("displayName", user.DisplayName); + jsonWriter.WriteString("username", user.Username); + jsonWriter.WriteBoolean("disabled", user.Disabled); + jsonWriter.WriteString("previousSessionLoggedOn", user.PreviousSessionLoggedOn); + jsonWriter.WriteString("previousSessionRemoteAddress", user.PreviousSessionRemoteAddress.ToString()); + jsonWriter.WriteString("recentSessionLoggedOn", user.RecentSessionLoggedOn); + jsonWriter.WriteString("recentSessionRemoteAddress", user.RecentSessionRemoteAddress.ToString()); if (includeMoreDetails) { - jsonWriter.WritePropertyName("sessionTimeoutSeconds"); - jsonWriter.WriteValue(user.SessionTimeoutSeconds); + jsonWriter.WriteNumber("sessionTimeoutSeconds", user.SessionTimeoutSeconds); jsonWriter.WritePropertyName("memberOfGroups"); jsonWriter.WriteStartArray(); @@ -151,7 +117,7 @@ namespace DnsServerCore if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase)) continue; - jsonWriter.WriteValue(group.Name); + jsonWriter.WriteStringValue(group.Name); } jsonWriter.WriteEndArray(); @@ -181,51 +147,33 @@ namespace DnsServerCore if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase)) continue; - jsonWriter.WriteValue(group.Name); + jsonWriter.WriteStringValue(group.Name); } jsonWriter.WriteEndArray(); } } - private static void WriteUserSessionDetails(JsonTextWriter jsonWriter, UserSession session, UserSession currentSession) + private static void WriteUserSessionDetails(Utf8JsonWriter jsonWriter, UserSession session, UserSession currentSession) { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("username"); - jsonWriter.WriteValue(session.User.Username); - - jsonWriter.WritePropertyName("isCurrentSession"); - jsonWriter.WriteValue(session.Equals(currentSession)); - - jsonWriter.WritePropertyName("partialToken"); - jsonWriter.WriteValue(session.Token.Substring(0, 16)); - - jsonWriter.WritePropertyName("type"); - jsonWriter.WriteValue(session.Type.ToString()); - - jsonWriter.WritePropertyName("tokenName"); - jsonWriter.WriteValue(session.TokenName); - - jsonWriter.WritePropertyName("lastSeen"); - jsonWriter.WriteValue(session.LastSeen); - - jsonWriter.WritePropertyName("lastSeenRemoteAddress"); - jsonWriter.WriteValue(session.LastSeenRemoteAddress.ToString()); - - jsonWriter.WritePropertyName("lastSeenUserAgent"); - jsonWriter.WriteValue(session.LastSeenUserAgent); + jsonWriter.WriteString("username", session.User.Username); + jsonWriter.WriteBoolean("isCurrentSession", session.Equals(currentSession)); + jsonWriter.WriteString("partialToken", session.Token.Substring(0, 16)); + jsonWriter.WriteString("type", session.Type.ToString()); + jsonWriter.WriteString("tokenName", session.TokenName); + jsonWriter.WriteString("lastSeen", session.LastSeen); + jsonWriter.WriteString("lastSeenRemoteAddress", session.LastSeenRemoteAddress.ToString()); + jsonWriter.WriteString("lastSeenUserAgent", session.LastSeenUserAgent); jsonWriter.WriteEndObject(); } - private void WriteGroupDetails(JsonTextWriter jsonWriter, Group group, bool includeMembers, bool includeUsers) + private void WriteGroupDetails(Utf8JsonWriter jsonWriter, Group group, bool includeMembers, bool includeUsers) { - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(group.Name); - - jsonWriter.WritePropertyName("description"); - jsonWriter.WriteValue(group.Description); + jsonWriter.WriteString("name", group.Name); + jsonWriter.WriteString("description", group.Description); if (includeMembers) { @@ -236,7 +184,7 @@ namespace DnsServerCore members.Sort(); foreach (User user in members) - jsonWriter.WriteValue(user.Username); + jsonWriter.WriteStringValue(user.Username); jsonWriter.WriteEndArray(); } @@ -250,22 +198,18 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (User user in users) - jsonWriter.WriteValue(user.Username); + jsonWriter.WriteStringValue(user.Username); jsonWriter.WriteEndArray(); } } - private void WritePermissionDetails(JsonTextWriter jsonWriter, Permission permission, string subItem, bool includeUsersAndGroups) + private void WritePermissionDetails(Utf8JsonWriter jsonWriter, Permission permission, string subItem, bool includeUsersAndGroups) { - jsonWriter.WritePropertyName("section"); - jsonWriter.WriteValue(permission.Section.ToString()); + jsonWriter.WriteString("section", permission.Section.ToString()); if (subItem is not null) - { - jsonWriter.WritePropertyName("subItem"); - jsonWriter.WriteValue(subItem.Length == 0 ? "." : subItem); - } + jsonWriter.WriteString("subItem", subItem.Length == 0 ? "." : subItem); jsonWriter.WritePropertyName("userPermissions"); jsonWriter.WriteStartArray(); @@ -281,17 +225,10 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("username"); - jsonWriter.WriteValue(userPermission.Key.Username); - - jsonWriter.WritePropertyName("canView"); - jsonWriter.WriteValue(userPermission.Value.HasFlag(PermissionFlag.View)); - - jsonWriter.WritePropertyName("canModify"); - jsonWriter.WriteValue(userPermission.Value.HasFlag(PermissionFlag.Modify)); - - jsonWriter.WritePropertyName("canDelete"); - jsonWriter.WriteValue(userPermission.Value.HasFlag(PermissionFlag.Delete)); + jsonWriter.WriteString("username", userPermission.Key.Username); + jsonWriter.WriteBoolean("canView", userPermission.Value.HasFlag(PermissionFlag.View)); + jsonWriter.WriteBoolean("canModify", userPermission.Value.HasFlag(PermissionFlag.Modify)); + jsonWriter.WriteBoolean("canDelete", userPermission.Value.HasFlag(PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } @@ -312,17 +249,10 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(groupPermission.Key.Name); - - jsonWriter.WritePropertyName("canView"); - jsonWriter.WriteValue(groupPermission.Value.HasFlag(PermissionFlag.View)); - - jsonWriter.WritePropertyName("canModify"); - jsonWriter.WriteValue(groupPermission.Value.HasFlag(PermissionFlag.Modify)); - - jsonWriter.WritePropertyName("canDelete"); - jsonWriter.WriteValue(groupPermission.Value.HasFlag(PermissionFlag.Delete)); + jsonWriter.WriteString("name", groupPermission.Key.Name); + jsonWriter.WriteBoolean("canView", groupPermission.Value.HasFlag(PermissionFlag.View)); + jsonWriter.WriteBoolean("canModify", groupPermission.Value.HasFlag(PermissionFlag.Modify)); + jsonWriter.WriteBoolean("canDelete", groupPermission.Value.HasFlag(PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } @@ -341,7 +271,7 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (User user in users) - jsonWriter.WriteValue(user.Username); + jsonWriter.WriteStringValue(user.Username); jsonWriter.WriteEndArray(); @@ -349,7 +279,7 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (Group group in groups) - jsonWriter.WriteValue(group.Name); + jsonWriter.WriteStringValue(group.Name); jsonWriter.WriteEndArray(); } @@ -359,7 +289,7 @@ namespace DnsServerCore #region public - public async Task LoginAsync(HttpListenerRequest request, JsonTextWriter jsonWriter, UserSessionType sessionType) + public async Task LoginAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter, UserSessionType sessionType) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) @@ -411,7 +341,7 @@ namespace DnsServerCore } } - public void GetCurrentSessionDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetCurrentSessionDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { if (!_dnsWebService.TryGetSession(request, out UserSession session)) throw new InvalidTokenWebServiceException("Invalid token or session expired."); @@ -437,14 +367,14 @@ namespace DnsServerCore _dnsWebService.AuthManager.SaveConfigFile(); } - public void GetProfile(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetProfile(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { UserSession session = _dnsWebService.GetSession(request); WriteUserDetails(jsonWriter, session.User, session, true, false); } - public void SetProfile(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void SetProfile(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { UserSession session = _dnsWebService.GetSession(request); @@ -466,7 +396,7 @@ namespace DnsServerCore WriteUserDetails(jsonWriter, session.User, session, true, false); } - public void ListSessions(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void ListSessions(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { UserSession session = _dnsWebService.GetSession(request); @@ -485,7 +415,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void CreateApiToken(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void CreateApiToken(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) @@ -503,14 +433,9 @@ namespace DnsServerCore _dnsWebService.AuthManager.SaveConfigFile(); - jsonWriter.WritePropertyName("username"); - jsonWriter.WriteValue(session.User.Username); - - jsonWriter.WritePropertyName("tokenName"); - jsonWriter.WriteValue(session.TokenName); - - jsonWriter.WritePropertyName("token"); - jsonWriter.WriteValue(session.Token); + jsonWriter.WriteString("username", session.User.Username); + jsonWriter.WriteString("tokenName", session.TokenName); + jsonWriter.WriteString("token", session.Token); } public void DeleteSession(HttpListenerRequest request, bool isAdminContext) @@ -552,7 +477,7 @@ namespace DnsServerCore _dnsWebService.AuthManager.SaveConfigFile(); } - public void ListUsers(JsonTextWriter jsonWriter) + public void ListUsers(Utf8JsonWriter jsonWriter) { List users = new List(_dnsWebService.AuthManager.Users); users.Sort(); @@ -572,7 +497,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void CreateUser(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void CreateUser(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strDisplayName = request.QueryString["displayName"]; @@ -595,7 +520,7 @@ namespace DnsServerCore WriteUserDetails(jsonWriter, user, null, false, false); } - public void GetUserDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetUserDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) @@ -615,7 +540,7 @@ namespace DnsServerCore WriteUserDetails(jsonWriter, user, null, true, includeGroups); } - public void SetUserDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void SetUserDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) @@ -728,7 +653,7 @@ namespace DnsServerCore _dnsWebService.AuthManager.SaveConfigFile(); } - public void ListGroups(JsonTextWriter jsonWriter) + public void ListGroups(Utf8JsonWriter jsonWriter) { List groups = new List(_dnsWebService.AuthManager.Groups); groups.Sort(); @@ -751,7 +676,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void CreateGroup(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void CreateGroup(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strGroup = request.QueryString["group"]; if (string.IsNullOrEmpty(strGroup)) @@ -772,7 +697,7 @@ namespace DnsServerCore WriteGroupDetails(jsonWriter, group, false, false); } - public void GetGroupDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetGroupDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strGroup = request.QueryString["group"]; if (string.IsNullOrEmpty(strGroup)) @@ -792,7 +717,7 @@ namespace DnsServerCore WriteGroupDetails(jsonWriter, group, true, includeUsers); } - public void SetGroupDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void SetGroupDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strGroup = request.QueryString["group"]; if (string.IsNullOrEmpty(strGroup)) @@ -859,7 +784,7 @@ namespace DnsServerCore _dnsWebService.AuthManager.SaveConfigFile(); } - public void ListPermissions(JsonTextWriter jsonWriter) + public void ListPermissions(Utf8JsonWriter jsonWriter) { List permissions = new List(_dnsWebService.AuthManager.Permissions); permissions.Sort(); @@ -879,7 +804,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void GetPermissionDetails(HttpListenerRequest request, JsonTextWriter jsonWriter, PermissionSection section) + public void GetPermissionDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter, PermissionSection section) { if (section == PermissionSection.Unknown) { @@ -936,7 +861,7 @@ namespace DnsServerCore WritePermissionDetails(jsonWriter, permission, strSubItem, includeUsersAndGroups); } - public void SetPermissionsDetails(HttpListenerRequest request, JsonTextWriter jsonWriter, PermissionSection section) + public void SetPermissionsDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter, PermissionSection section) { if (section == PermissionSection.Unknown) { From 0ccd342bbeece121b660c20c6b8a5d0decd8ed46 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 13:07:15 +0530 Subject: [PATCH 027/191] WebServiceDashboardApi: removed newtonsoft. --- DnsServerCore/WebServiceDashboardApi.cs | 154 +++++++++--------------- 1 file changed, 57 insertions(+), 97 deletions(-) diff --git a/DnsServerCore/WebServiceDashboardApi.cs b/DnsServerCore/WebServiceDashboardApi.cs index f30d6d0a..33d4a153 100644 --- a/DnsServerCore/WebServiceDashboardApi.cs +++ b/DnsServerCore/WebServiceDashboardApi.cs @@ -18,11 +18,11 @@ along with this program. If not, see . */ using DnsServerCore.Dns; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Globalization; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -48,29 +48,22 @@ namespace DnsServerCore #region private - private static void WriteChartDataSet(JsonTextWriter jsonWriter, string label, string backgroundColor, string borderColor, List> statsPerInterval) + private static void WriteChartDataSet(Utf8JsonWriter jsonWriter, string label, string backgroundColor, string borderColor, List> statsPerInterval) { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("label"); - jsonWriter.WriteValue(label); - - jsonWriter.WritePropertyName("backgroundColor"); - jsonWriter.WriteValue(backgroundColor); - - jsonWriter.WritePropertyName("borderColor"); - jsonWriter.WriteValue(borderColor); - - jsonWriter.WritePropertyName("borderWidth"); - jsonWriter.WriteValue(2); - - jsonWriter.WritePropertyName("fill"); - jsonWriter.WriteValue(true); + jsonWriter.WriteString("label", label); + jsonWriter.WriteString("backgroundColor", backgroundColor); + jsonWriter.WriteString("borderColor", borderColor); + jsonWriter.WriteNumber("borderWidth", 2); + jsonWriter.WriteBoolean("fill", true); jsonWriter.WritePropertyName("data"); jsonWriter.WriteStartArray(); + foreach (KeyValuePair item in statsPerInterval) - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteNumberValue(item.Value); + jsonWriter.WriteEndArray(); jsonWriter.WriteEndObject(); @@ -128,7 +121,7 @@ namespace DnsServerCore #region public - public async Task GetStats(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task GetStats(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strType = request.QueryString["type"]; if (string.IsNullOrEmpty(strType)) @@ -244,25 +237,13 @@ namespace DnsServerCore jsonWriter.WriteStartObject(); foreach (KeyValuePair item in stats) - { - jsonWriter.WritePropertyName(item.Key); - jsonWriter.WriteValue(item.Value); - } + jsonWriter.WriteNumber(item.Key, item.Value); - jsonWriter.WritePropertyName("zones"); - jsonWriter.WriteValue(_dnsWebService.DnsServer.AuthZoneManager.TotalZones); - - jsonWriter.WritePropertyName("cachedEntries"); - jsonWriter.WriteValue(_dnsWebService.DnsServer.CacheZoneManager.TotalEntries); - - jsonWriter.WritePropertyName("allowedZones"); - jsonWriter.WriteValue(_dnsWebService.DnsServer.AllowedZoneManager.TotalZonesAllowed); - - jsonWriter.WritePropertyName("blockedZones"); - jsonWriter.WriteValue(_dnsWebService.DnsServer.BlockedZoneManager.TotalZonesBlocked); - - jsonWriter.WritePropertyName("blockListZones"); - jsonWriter.WriteValue(_dnsWebService.DnsServer.BlockListZoneManager.TotalZonesBlocked); + jsonWriter.WriteNumber("zones", _dnsWebService.DnsServer.AuthZoneManager.TotalZones); + jsonWriter.WriteNumber("cachedEntries", _dnsWebService.DnsServer.CacheZoneManager.TotalEntries); + jsonWriter.WriteNumber("allowedZones", _dnsWebService.DnsServer.AllowedZoneManager.TotalZonesAllowed); + jsonWriter.WriteNumber("blockedZones", _dnsWebService.DnsServer.BlockedZoneManager.TotalZonesBlocked); + jsonWriter.WriteNumber("blockListZones", _dnsWebService.DnsServer.BlockListZoneManager.TotalZonesBlocked); jsonWriter.WriteEndObject(); } @@ -274,8 +255,7 @@ namespace DnsServerCore //label format { - jsonWriter.WritePropertyName("labelFormat"); - jsonWriter.WriteValue(labelFormat); + jsonWriter.WriteString("labelFormat", labelFormat); } //label @@ -286,7 +266,7 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (KeyValuePair item in statsPerInterval) - jsonWriter.WriteValue(item.Key); + jsonWriter.WriteStringValue(item.Key); jsonWriter.WriteEndArray(); } @@ -332,19 +312,19 @@ namespace DnsServerCore switch (item.Key) { case "totalAuthoritative": - jsonWriter.WriteValue("Authoritative"); + jsonWriter.WriteStringValue("Authoritative"); break; case "totalRecursive": - jsonWriter.WriteValue("Recursive"); + jsonWriter.WriteStringValue("Recursive"); break; case "totalCached": - jsonWriter.WriteValue("Cached"); + jsonWriter.WriteStringValue("Cached"); break; case "totalBlocked": - jsonWriter.WriteValue("Blocked"); + jsonWriter.WriteStringValue("Blocked"); break; } } @@ -370,7 +350,7 @@ namespace DnsServerCore case "totalRecursive": case "totalCached": case "totalBlocked": - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteNumberValue(item.Value); break; } } @@ -379,10 +359,10 @@ namespace DnsServerCore jsonWriter.WritePropertyName("backgroundColor"); jsonWriter.WriteStartArray(); - jsonWriter.WriteValue("rgba(150, 150, 0, 0.5)"); - jsonWriter.WriteValue("rgba(23, 162, 184, 0.5)"); - jsonWriter.WriteValue("rgba(111, 84, 153, 0.5)"); - jsonWriter.WriteValue("rgba(255, 165, 0, 0.5)"); + jsonWriter.WriteStringValue("rgba(150, 150, 0, 0.5)"); + jsonWriter.WriteStringValue("rgba(23, 162, 184, 0.5)"); + jsonWriter.WriteStringValue("rgba(111, 84, 153, 0.5)"); + jsonWriter.WriteStringValue("rgba(255, 165, 0, 0.5)"); jsonWriter.WriteEndArray(); jsonWriter.WriteEndObject(); @@ -406,7 +386,7 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (KeyValuePair item in queryTypes) - jsonWriter.WriteValue(item.Key); + jsonWriter.WriteStringValue(item.Key); jsonWriter.WriteEndArray(); } @@ -420,22 +400,24 @@ namespace DnsServerCore jsonWriter.WritePropertyName("data"); jsonWriter.WriteStartArray(); + foreach (KeyValuePair item in queryTypes) - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteNumberValue(item.Value); + jsonWriter.WriteEndArray(); jsonWriter.WritePropertyName("backgroundColor"); jsonWriter.WriteStartArray(); - jsonWriter.WriteValue("rgba(102, 153, 255, 0.5)"); - jsonWriter.WriteValue("rgba(92, 184, 92, 0.5)"); - jsonWriter.WriteValue("rgba(7, 7, 7, 0.5)"); - jsonWriter.WriteValue("rgba(91, 192, 222, 0.5)"); - jsonWriter.WriteValue("rgba(150, 150, 0, 0.5)"); - jsonWriter.WriteValue("rgba(23, 162, 184, 0.5)"); - jsonWriter.WriteValue("rgba(111, 84, 153, 0.5)"); - jsonWriter.WriteValue("rgba(255, 165, 0, 0.5)"); - jsonWriter.WriteValue("rgba(51, 122, 183, 0.5)"); - jsonWriter.WriteValue("rgba(150, 150, 150, 0.5)"); + jsonWriter.WriteStringValue("rgba(102, 153, 255, 0.5)"); + jsonWriter.WriteStringValue("rgba(92, 184, 92, 0.5)"); + jsonWriter.WriteStringValue("rgba(7, 7, 7, 0.5)"); + jsonWriter.WriteStringValue("rgba(91, 192, 222, 0.5)"); + jsonWriter.WriteStringValue("rgba(150, 150, 0, 0.5)"); + jsonWriter.WriteStringValue("rgba(23, 162, 184, 0.5)"); + jsonWriter.WriteStringValue("rgba(111, 84, 153, 0.5)"); + jsonWriter.WriteStringValue("rgba(255, 165, 0, 0.5)"); + jsonWriter.WriteStringValue("rgba(51, 122, 183, 0.5)"); + jsonWriter.WriteStringValue("rgba(150, 150, 150, 0.5)"); jsonWriter.WriteEndArray(); jsonWriter.WriteEndObject(); @@ -459,17 +441,12 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(item.Key); + jsonWriter.WriteString("name", item.Key); if (clientIpMap.TryGetValue(item.Key, out string clientDomain) && !string.IsNullOrEmpty(clientDomain)) - { - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(clientDomain); - } + jsonWriter.WriteString("domain", clientDomain); - jsonWriter.WritePropertyName("hits"); - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteNumber("hits", item.Value); jsonWriter.WriteEndObject(); } @@ -488,11 +465,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(item.Key); - - jsonWriter.WritePropertyName("hits"); - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteString("name", item.Key); + jsonWriter.WriteNumber("hits", item.Value); jsonWriter.WriteEndObject(); } @@ -511,11 +485,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(item.Key); - - jsonWriter.WritePropertyName("hits"); - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteString("name", item.Key); + jsonWriter.WriteNumber("hits", item.Value); jsonWriter.WriteEndObject(); } @@ -524,7 +495,7 @@ namespace DnsServerCore } } - public async Task GetTopStats(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task GetTopStats(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strType = request.QueryString["type"]; if (string.IsNullOrEmpty(strType)) @@ -607,17 +578,12 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(item.Key); + jsonWriter.WriteString("name", item.Key); if (clientIpMap.TryGetValue(item.Key, out string clientDomain) && !string.IsNullOrEmpty(clientDomain)) - { - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(clientDomain); - } + jsonWriter.WriteString("domain", clientDomain); - jsonWriter.WritePropertyName("hits"); - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteNumber("hits", item.Value); jsonWriter.WriteEndObject(); } @@ -635,11 +601,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(item.Key); - - jsonWriter.WritePropertyName("hits"); - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteString("name", item.Key); + jsonWriter.WriteNumber("hits", item.Value); jsonWriter.WriteEndObject(); } @@ -657,11 +620,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(item.Key); - - jsonWriter.WritePropertyName("hits"); - jsonWriter.WriteValue(item.Value); + jsonWriter.WriteString("name", item.Key); + jsonWriter.WriteNumber("hits", item.Value); jsonWriter.WriteEndObject(); } From 054a919ad0bf7902be24f7b6003af8821b0d1a3e Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 13:10:48 +0530 Subject: [PATCH 028/191] WebServiceDhcpApi: removed newtonsoft. Added support for TFTP server address option and generic option. --- DnsServerCore/WebServiceDhcpApi.cs | 298 +++++++++++++---------------- 1 file changed, 136 insertions(+), 162 deletions(-) diff --git a/DnsServerCore/WebServiceDhcpApi.cs b/DnsServerCore/WebServiceDhcpApi.cs index 5159775b..f42ead9e 100644 --- a/DnsServerCore/WebServiceDhcpApi.cs +++ b/DnsServerCore/WebServiceDhcpApi.cs @@ -19,10 +19,10 @@ along with this program. If not, see . using DnsServerCore.Dhcp; using DnsServerCore.Dhcp.Options; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; +using System.Text.Json; using System.Threading.Tasks; namespace DnsServerCore @@ -46,7 +46,7 @@ namespace DnsServerCore #region public - public void ListDhcpLeases(JsonTextWriter jsonWriter) + public void ListDhcpLeases(Utf8JsonWriter jsonWriter) { IReadOnlyDictionary scopes = _dnsWebService.DhcpServer.Scopes; @@ -77,29 +77,14 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("scope"); - jsonWriter.WriteValue(scope.Name); - - jsonWriter.WritePropertyName("type"); - jsonWriter.WriteValue(lease.Type.ToString()); - - jsonWriter.WritePropertyName("hardwareAddress"); - jsonWriter.WriteValue(BitConverter.ToString(lease.HardwareAddress)); - - jsonWriter.WritePropertyName("clientIdentifier"); - jsonWriter.WriteValue(lease.ClientIdentifier.ToString()); - - jsonWriter.WritePropertyName("address"); - jsonWriter.WriteValue(lease.Address.ToString()); - - jsonWriter.WritePropertyName("hostName"); - jsonWriter.WriteValue(lease.HostName); - - jsonWriter.WritePropertyName("leaseObtained"); - jsonWriter.WriteValue(lease.LeaseObtained); - - jsonWriter.WritePropertyName("leaseExpires"); - jsonWriter.WriteValue(lease.LeaseExpires); + jsonWriter.WriteString("scope", scope.Name); + jsonWriter.WriteString("type", lease.Type.ToString()); + jsonWriter.WriteString("hardwareAddress", BitConverter.ToString(lease.HardwareAddress)); + jsonWriter.WriteString("clientIdentifier", lease.ClientIdentifier.ToString()); + jsonWriter.WriteString("address", lease.Address.ToString()); + jsonWriter.WriteString("hostName", lease.HostName); + jsonWriter.WriteString("leaseObtained", lease.LeaseObtained); + jsonWriter.WriteString("leaseExpires", lease.LeaseExpires); jsonWriter.WriteEndObject(); } @@ -108,7 +93,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void ListDhcpScopes(JsonTextWriter jsonWriter) + public void ListDhcpScopes(Utf8JsonWriter jsonWriter) { IReadOnlyDictionary scopes = _dnsWebService.DhcpServer.Scopes; @@ -127,32 +112,16 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(scope.Name); + jsonWriter.WriteString("name", scope.Name); + jsonWriter.WriteBoolean("enabled", scope.Enabled); + jsonWriter.WriteString("startingAddress", scope.StartingAddress.ToString()); + jsonWriter.WriteString("endingAddress", scope.EndingAddress.ToString()); + jsonWriter.WriteString("subnetMask", scope.SubnetMask.ToString()); + jsonWriter.WriteString("networkAddress", scope.NetworkAddress.ToString()); + jsonWriter.WriteString("broadcastAddress", scope.BroadcastAddress.ToString()); - jsonWriter.WritePropertyName("enabled"); - jsonWriter.WriteValue(scope.Enabled); - - jsonWriter.WritePropertyName("startingAddress"); - jsonWriter.WriteValue(scope.StartingAddress.ToString()); - - jsonWriter.WritePropertyName("endingAddress"); - jsonWriter.WriteValue(scope.EndingAddress.ToString()); - - jsonWriter.WritePropertyName("subnetMask"); - jsonWriter.WriteValue(scope.SubnetMask.ToString()); - - jsonWriter.WritePropertyName("networkAddress"); - jsonWriter.WriteValue(scope.NetworkAddress.ToString()); - - jsonWriter.WritePropertyName("broadcastAddress"); - jsonWriter.WriteValue(scope.BroadcastAddress.ToString()); - - if (scope.InterfaceAddress != null) - { - jsonWriter.WritePropertyName("interfaceAddress"); - jsonWriter.WriteValue(scope.InterfaceAddress.ToString()); - } + if (scope.InterfaceAddress is not null) + jsonWriter.WriteString("interfaceAddress", scope.InterfaceAddress.ToString()); jsonWriter.WriteEndObject(); } @@ -160,7 +129,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void GetDhcpScope(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetDhcpScope(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string scopeName = request.QueryString["name"]; if (string.IsNullOrEmpty(scopeName)) @@ -170,44 +139,21 @@ namespace DnsServerCore if (scope == null) throw new DnsWebServiceException("DHCP scope was not found: " + scopeName); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(scope.Name); + jsonWriter.WriteString("name", scope.Name); + jsonWriter.WriteString("startingAddress", scope.StartingAddress.ToString()); + jsonWriter.WriteString("endingAddress", scope.EndingAddress.ToString()); + jsonWriter.WriteString("subnetMask", scope.SubnetMask.ToString()); + jsonWriter.WriteNumber("leaseTimeDays", scope.LeaseTimeDays); + jsonWriter.WriteNumber("leaseTimeHours", scope.LeaseTimeHours); + jsonWriter.WriteNumber("leaseTimeMinutes", scope.LeaseTimeMinutes); + jsonWriter.WriteNumber("offerDelayTime", scope.OfferDelayTime); - jsonWriter.WritePropertyName("startingAddress"); - jsonWriter.WriteValue(scope.StartingAddress.ToString()); - - jsonWriter.WritePropertyName("endingAddress"); - jsonWriter.WriteValue(scope.EndingAddress.ToString()); - - jsonWriter.WritePropertyName("subnetMask"); - jsonWriter.WriteValue(scope.SubnetMask.ToString()); - - jsonWriter.WritePropertyName("leaseTimeDays"); - jsonWriter.WriteValue(scope.LeaseTimeDays); - - jsonWriter.WritePropertyName("leaseTimeHours"); - jsonWriter.WriteValue(scope.LeaseTimeHours); - - jsonWriter.WritePropertyName("leaseTimeMinutes"); - jsonWriter.WriteValue(scope.LeaseTimeMinutes); - - jsonWriter.WritePropertyName("offerDelayTime"); - jsonWriter.WriteValue(scope.OfferDelayTime); - - jsonWriter.WritePropertyName("pingCheckEnabled"); - jsonWriter.WriteValue(scope.PingCheckEnabled); - - jsonWriter.WritePropertyName("pingCheckTimeout"); - jsonWriter.WriteValue(scope.PingCheckTimeout); - - jsonWriter.WritePropertyName("pingCheckRetries"); - jsonWriter.WriteValue(scope.PingCheckRetries); + jsonWriter.WriteBoolean("pingCheckEnabled", scope.PingCheckEnabled); + jsonWriter.WriteNumber("pingCheckTimeout", scope.PingCheckTimeout); + jsonWriter.WriteNumber("pingCheckRetries", scope.PingCheckRetries); if (!string.IsNullOrEmpty(scope.DomainName)) - { - jsonWriter.WritePropertyName("domainName"); - jsonWriter.WriteValue(scope.DomainName); - } + jsonWriter.WriteString("domainName", scope.DomainName); if (scope.DomainSearchList is not null) { @@ -215,73 +161,57 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (string domainSearchString in scope.DomainSearchList) - jsonWriter.WriteValue(domainSearchString); + jsonWriter.WriteStringValue(domainSearchString); jsonWriter.WriteEndArray(); } - jsonWriter.WritePropertyName("dnsUpdates"); - jsonWriter.WriteValue(scope.DnsUpdates); + jsonWriter.WriteBoolean("dnsUpdates", scope.DnsUpdates); + jsonWriter.WriteNumber("dnsTtl", scope.DnsTtl); - jsonWriter.WritePropertyName("dnsTtl"); - jsonWriter.WriteValue(scope.DnsTtl); + if (scope.ServerAddress is not null) + jsonWriter.WriteString("serverAddress", scope.ServerAddress.ToString()); - if (scope.ServerAddress != null) - { - jsonWriter.WritePropertyName("serverAddress"); - jsonWriter.WriteValue(scope.ServerAddress.ToString()); - } + if (scope.ServerHostName is not null) + jsonWriter.WriteString("serverHostName", scope.ServerHostName); - if (scope.ServerHostName != null) - { - jsonWriter.WritePropertyName("serverHostName"); - jsonWriter.WriteValue(scope.ServerHostName); - } + if (scope.BootFileName is not null) + jsonWriter.WriteString("bootFileName", scope.BootFileName); - if (scope.BootFileName != null) - { - jsonWriter.WritePropertyName("bootFileName"); - jsonWriter.WriteValue(scope.BootFileName); - } + if (scope.RouterAddress is not null) + jsonWriter.WriteString("routerAddress", scope.RouterAddress.ToString()); - if (scope.RouterAddress != null) - { - jsonWriter.WritePropertyName("routerAddress"); - jsonWriter.WriteValue(scope.RouterAddress.ToString()); - } + jsonWriter.WriteBoolean("useThisDnsServer", scope.UseThisDnsServer); - jsonWriter.WritePropertyName("useThisDnsServer"); - jsonWriter.WriteValue(scope.UseThisDnsServer); - - if (scope.DnsServers != null) + if (scope.DnsServers is not null) { jsonWriter.WritePropertyName("dnsServers"); jsonWriter.WriteStartArray(); foreach (IPAddress dnsServer in scope.DnsServers) - jsonWriter.WriteValue(dnsServer.ToString()); + jsonWriter.WriteStringValue(dnsServer.ToString()); jsonWriter.WriteEndArray(); } - if (scope.WinsServers != null) + if (scope.WinsServers is not null) { jsonWriter.WritePropertyName("winsServers"); jsonWriter.WriteStartArray(); foreach (IPAddress winsServer in scope.WinsServers) - jsonWriter.WriteValue(winsServer.ToString()); + jsonWriter.WriteStringValue(winsServer.ToString()); jsonWriter.WriteEndArray(); } - if (scope.NtpServers != null) + if (scope.NtpServers is not null) { jsonWriter.WritePropertyName("ntpServers"); jsonWriter.WriteStartArray(); foreach (IPAddress ntpServer in scope.NtpServers) - jsonWriter.WriteValue(ntpServer.ToString()); + jsonWriter.WriteStringValue(ntpServer.ToString()); jsonWriter.WriteEndArray(); } @@ -292,12 +222,12 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (string ntpServerDomainName in scope.NtpServerDomainNames) - jsonWriter.WriteValue(ntpServerDomainName); + jsonWriter.WriteStringValue(ntpServerDomainName); jsonWriter.WriteEndArray(); } - if (scope.StaticRoutes != null) + if (scope.StaticRoutes is not null) { jsonWriter.WritePropertyName("staticRoutes"); jsonWriter.WriteStartArray(); @@ -306,14 +236,9 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("destination"); - jsonWriter.WriteValue(route.Destination.ToString()); - - jsonWriter.WritePropertyName("subnetMask"); - jsonWriter.WriteValue(route.SubnetMask.ToString()); - - jsonWriter.WritePropertyName("router"); - jsonWriter.WriteValue(route.Router.ToString()); + jsonWriter.WriteString("destination", route.Destination.ToString()); + jsonWriter.WriteString("subnetMask", route.SubnetMask.ToString()); + jsonWriter.WriteString("router", route.Router.ToString()); jsonWriter.WriteEndObject(); } @@ -321,7 +246,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - if (scope.VendorInfo != null) + if (scope.VendorInfo is not null) { jsonWriter.WritePropertyName("vendorInfo"); jsonWriter.WriteStartArray(); @@ -330,11 +255,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("identifier"); - jsonWriter.WriteValue(entry.Key); - - jsonWriter.WritePropertyName("information"); - jsonWriter.WriteValue(entry.Value.ToString()); + jsonWriter.WriteString("identifier", entry.Key); + jsonWriter.WriteString("information", BitConverter.ToString(entry.Value.Information).Replace('-', ':')); jsonWriter.WriteEndObject(); } @@ -348,12 +270,41 @@ namespace DnsServerCore jsonWriter.WriteStartArray(); foreach (IPAddress acIpAddress in scope.CAPWAPAcIpAddresses) - jsonWriter.WriteValue(acIpAddress.ToString()); + jsonWriter.WriteStringValue(acIpAddress.ToString()); jsonWriter.WriteEndArray(); } - if (scope.Exclusions != null) + if (scope.TftpServerAddresses is not null) + { + jsonWriter.WritePropertyName("tftpServerAddresses"); + jsonWriter.WriteStartArray(); + + foreach (IPAddress address in scope.TftpServerAddresses) + jsonWriter.WriteStringValue(address.ToString()); + + jsonWriter.WriteEndArray(); + } + + if (scope.GenericOptions is not null) + { + jsonWriter.WritePropertyName("genericOptions"); + jsonWriter.WriteStartArray(); + + foreach (DhcpOption genericOption in scope.GenericOptions) + { + jsonWriter.WriteStartObject(); + + jsonWriter.WriteNumber("code", (byte)genericOption.Code); + jsonWriter.WriteString("value", BitConverter.ToString(genericOption.RawValue).Replace('-', ':')); + + jsonWriter.WriteEndObject(); + } + + jsonWriter.WriteEndArray(); + } + + if (scope.Exclusions is not null) { jsonWriter.WritePropertyName("exclusions"); jsonWriter.WriteStartArray(); @@ -362,11 +313,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("startingAddress"); - jsonWriter.WriteValue(exclusion.StartingAddress.ToString()); - - jsonWriter.WritePropertyName("endingAddress"); - jsonWriter.WriteValue(exclusion.EndingAddress.ToString()); + jsonWriter.WriteString("startingAddress", exclusion.StartingAddress.ToString()); + jsonWriter.WriteString("endingAddress", exclusion.EndingAddress.ToString()); jsonWriter.WriteEndObject(); } @@ -381,28 +329,18 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("hostName"); - jsonWriter.WriteValue(reservedLease.HostName); - - jsonWriter.WritePropertyName("hardwareAddress"); - jsonWriter.WriteValue(BitConverter.ToString(reservedLease.HardwareAddress)); - - jsonWriter.WritePropertyName("address"); - jsonWriter.WriteValue(reservedLease.Address.ToString()); - - jsonWriter.WritePropertyName("comments"); - jsonWriter.WriteValue(reservedLease.Comments); + jsonWriter.WriteString("hostName", reservedLease.HostName); + jsonWriter.WriteString("hardwareAddress", BitConverter.ToString(reservedLease.HardwareAddress)); + jsonWriter.WriteString("address", reservedLease.Address.ToString()); + jsonWriter.WriteString("comments", reservedLease.Comments); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); - jsonWriter.WritePropertyName("allowOnlyReservedLeases"); - jsonWriter.WriteValue(scope.AllowOnlyReservedLeases); - - jsonWriter.WritePropertyName("blockLocallyAdministeredMacAddresses"); - jsonWriter.WriteValue(scope.BlockLocallyAdministeredMacAddresses); + jsonWriter.WriteBoolean("allowOnlyReservedLeases", scope.AllowOnlyReservedLeases); + jsonWriter.WriteBoolean("blockLocallyAdministeredMacAddresses", scope.BlockLocallyAdministeredMacAddresses); } public async Task SetDhcpScopeAsync(HttpListenerRequest request) @@ -641,9 +579,7 @@ namespace DnsServerCore Dictionary vendorInfo = new Dictionary(); for (int i = 0; i < strVendorInfoParts.Length; i += 2) - { vendorInfo.Add(strVendorInfoParts[i + 0], new VendorSpecificInformationOption(strVendorInfoParts[i + 1])); - } scope.VendorInfo = vendorInfo; } @@ -668,6 +604,44 @@ namespace DnsServerCore } } + string strTftpServerAddresses = request.QueryString["tftpServerAddresses"]; + if (strTftpServerAddresses is not null) + { + if (strTftpServerAddresses.Length == 0) + { + scope.TftpServerAddresses = null; + } + else + { + string[] strTftpServerAddressesParts = strTftpServerAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + IPAddress[] tftpServerAddresses = new IPAddress[strTftpServerAddressesParts.Length]; + + for (int i = 0; i < strTftpServerAddressesParts.Length; i++) + tftpServerAddresses[i] = IPAddress.Parse(strTftpServerAddressesParts[i]); + + scope.TftpServerAddresses = tftpServerAddresses; + } + } + + string strGenericOptions = request.QueryString["genericOptions"]; + if (strGenericOptions is not null) + { + if (strGenericOptions.Length == 0) + { + scope.GenericOptions = null; + } + else + { + string[] strGenericOptionsParts = strGenericOptions.Split('|'); + List genericOptions = new List(); + + for (int i = 0; i < strGenericOptionsParts.Length; i += 2) + genericOptions.Add(new DhcpOption((DhcpOptionCode)byte.Parse(strGenericOptionsParts[i + 0]), strGenericOptionsParts[i + 1])); + + scope.GenericOptions = genericOptions; + } + } + string strExclusions = request.QueryString["exclusions"]; if (strExclusions != null) { From bd35098e4193ba126a83a59d3ab4b0c928e3d7a2 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 13:11:25 +0530 Subject: [PATCH 029/191] WebServiceLogsApi: removed newtonsoft. --- DnsServerCore/WebServiceLogsApi.cs | 63 +++++++++--------------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/DnsServerCore/WebServiceLogsApi.cs b/DnsServerCore/WebServiceLogsApi.cs index d1b7995c..a3e31683 100644 --- a/DnsServerCore/WebServiceLogsApi.cs +++ b/DnsServerCore/WebServiceLogsApi.cs @@ -19,11 +19,11 @@ along with this program. If not, see . using DnsServerCore.ApplicationCommon; using DnsServerCore.Dns.Applications; -using Newtonsoft.Json; using System; using System.Globalization; using System.IO; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; @@ -50,7 +50,7 @@ namespace DnsServerCore #region public - public void ListLogs(JsonTextWriter jsonWriter) + public void ListLogs(Utf8JsonWriter jsonWriter) { string[] logFiles = _dnsWebService.Log.ListLogFiles(); @@ -64,11 +64,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("fileName"); - jsonWriter.WriteValue(Path.GetFileNameWithoutExtension(logFile)); - - jsonWriter.WritePropertyName("size"); - jsonWriter.WriteValue(WebUtilities.GetFormattedSize(new FileInfo(logFile).Length)); + jsonWriter.WriteString("fileName", Path.GetFileNameWithoutExtension(logFile)); + jsonWriter.WriteString("size", WebUtilities.GetFormattedSize(new FileInfo(logFile).Length)); jsonWriter.WriteEndObject(); } @@ -117,7 +114,7 @@ namespace DnsServerCore _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] All stats files were deleted."); } - public async Task QueryLogsAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task QueryLogsAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string name = request.QueryString["name"]; if (string.IsNullOrEmpty(name)) @@ -216,14 +213,9 @@ namespace DnsServerCore DnsLogPage page = await logger.QueryLogsAsync(pageNumber, entriesPerPage, descendingOrder, start, end, clientIpAddress, protocol, responseType, rcode, qname, qtype, qclass); - jsonWriter.WritePropertyName("pageNumber"); - jsonWriter.WriteValue(page.PageNumber); - - jsonWriter.WritePropertyName("totalPages"); - jsonWriter.WriteValue(page.TotalPages); - - jsonWriter.WritePropertyName("totalEntries"); - jsonWriter.WriteValue(page.TotalEntries); + jsonWriter.WriteNumber("pageNumber", page.PageNumber); + jsonWriter.WriteNumber("totalPages", page.TotalPages); + jsonWriter.WriteNumber("totalEntries", page.TotalEntries); jsonWriter.WritePropertyName("entries"); jsonWriter.WriteStartArray(); @@ -232,35 +224,16 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("rowNumber"); - jsonWriter.WriteValue(entry.RowNumber); - - jsonWriter.WritePropertyName("timestamp"); - jsonWriter.WriteValue(entry.Timestamp); - - jsonWriter.WritePropertyName("clientIpAddress"); - jsonWriter.WriteValue(entry.ClientIpAddress.ToString()); - - jsonWriter.WritePropertyName("protocol"); - jsonWriter.WriteValue(entry.Protocol.ToString()); - - jsonWriter.WritePropertyName("responseType"); - jsonWriter.WriteValue(entry.ResponseType.ToString()); - - jsonWriter.WritePropertyName("rcode"); - jsonWriter.WriteValue(entry.RCODE.ToString()); - - jsonWriter.WritePropertyName("qname"); - jsonWriter.WriteValue(entry.Question?.Name); - - jsonWriter.WritePropertyName("qtype"); - jsonWriter.WriteValue(entry.Question?.Type.ToString()); - - jsonWriter.WritePropertyName("qclass"); - jsonWriter.WriteValue(entry.Question?.Class.ToString()); - - jsonWriter.WritePropertyName("answer"); - jsonWriter.WriteValue(entry.Answer); + jsonWriter.WriteNumber("rowNumber", entry.RowNumber); + jsonWriter.WriteString("timestamp", entry.Timestamp); + jsonWriter.WriteString("clientIpAddress", entry.ClientIpAddress.ToString()); + jsonWriter.WriteString("protocol", entry.Protocol.ToString()); + jsonWriter.WriteString("responseType", entry.ResponseType.ToString()); + jsonWriter.WriteString("rcode", entry.RCODE.ToString()); + jsonWriter.WriteString("qname", entry.Question?.Name); + jsonWriter.WriteString("qtype", entry.Question?.Type.ToString()); + jsonWriter.WriteString("qclass", entry.Question?.Class.ToString()); + jsonWriter.WriteString("answer", entry.Answer); jsonWriter.WriteEndObject(); } From 53c854aea3cc13b25b3cc749fa6cd2efd827738a Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 13:12:02 +0530 Subject: [PATCH 030/191] WebServiceOtherZonesApi: removed newtonsoft. --- DnsServerCore/WebServiceOtherZonesApi.cs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/DnsServerCore/WebServiceOtherZonesApi.cs b/DnsServerCore/WebServiceOtherZonesApi.cs index 85f2a58d..e5b02e19 100644 --- a/DnsServerCore/WebServiceOtherZonesApi.cs +++ b/DnsServerCore/WebServiceOtherZonesApi.cs @@ -18,11 +18,11 @@ along with this program. If not, see . */ using DnsServerCore.Dns.Zones; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -57,7 +57,7 @@ namespace DnsServerCore _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Cache was flushed."); } - public void ListCachedZones(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void ListCachedZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string domain = request.QueryString["domain"]; if (domain == null) @@ -107,8 +107,7 @@ namespace DnsServerCore subZones.Sort(); - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(domain); + jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); @@ -117,7 +116,7 @@ namespace DnsServerCore domain = "." + domain; foreach (string subZone in subZones) - jsonWriter.WriteValue(subZone + domain); + jsonWriter.WriteStringValue(subZone + domain); jsonWriter.WriteEndArray(); @@ -138,7 +137,7 @@ namespace DnsServerCore #region allowed zones api - public void ListAllowedZones(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void ListAllowedZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string domain = request.QueryString["domain"]; if (domain == null) @@ -188,8 +187,7 @@ namespace DnsServerCore subZones.Sort(); - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(domain); + jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); @@ -198,7 +196,7 @@ namespace DnsServerCore domain = "." + domain; foreach (string subZone in subZones) - jsonWriter.WriteValue(subZone + domain); + jsonWriter.WriteStringValue(subZone + domain); jsonWriter.WriteEndArray(); @@ -300,7 +298,7 @@ namespace DnsServerCore #region blocked zones api - public void ListBlockedZones(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void ListBlockedZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string domain = request.QueryString["domain"]; if (domain == null) @@ -350,8 +348,7 @@ namespace DnsServerCore subZones.Sort(); - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(domain); + jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); @@ -360,7 +357,7 @@ namespace DnsServerCore domain = "." + domain; foreach (string subZone in subZones) - jsonWriter.WriteValue(subZone + domain); + jsonWriter.WriteStringValue(subZone + domain); jsonWriter.WriteEndArray(); From 455a62c6d1b8d57a685d750d98a6b0843bd3fe9b Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 13:44:04 +0530 Subject: [PATCH 031/191] WebServiceZonesApi: removed newtonsoft. --- DnsServerCore/WebServiceZonesApi.cs | 674 +++++++++------------------- 1 file changed, 200 insertions(+), 474 deletions(-) diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index b5500db2..4c9a44d1 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -22,11 +22,11 @@ using DnsServerCore.Dns; using DnsServerCore.Dns.Dnssec; using DnsServerCore.Dns.ResourceRecords; using DnsServerCore.Dns.Zones; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; +using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; @@ -56,7 +56,7 @@ namespace DnsServerCore #region static - public static void WriteRecordsAsJson(List records, JsonTextWriter jsonWriter, bool authoritativeZoneRecords, AuthZoneInfo zoneInfo = null) + public static void WriteRecordsAsJson(List records, Utf8JsonWriter jsonWriter, bool authoritativeZoneRecords, AuthZoneInfo zoneInfo = null) { if (records is null) { @@ -90,36 +90,28 @@ namespace DnsServerCore #region private - private static void WriteRecordAsJson(DnsResourceRecord record, JsonTextWriter jsonWriter, bool authoritativeZoneRecords, AuthZoneInfo zoneInfo = null) + private static void WriteRecordAsJson(DnsResourceRecord record, Utf8JsonWriter jsonWriter, bool authoritativeZoneRecords, AuthZoneInfo zoneInfo = null) { jsonWriter.WriteStartObject(); if (authoritativeZoneRecords) - { - jsonWriter.WritePropertyName("disabled"); - jsonWriter.WriteValue(record.IsDisabled()); - } + jsonWriter.WriteBoolean("disabled", record.IsDisabled()); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(record.Name); + jsonWriter.WriteString("name", record.Name); - jsonWriter.WritePropertyName("type"); - jsonWriter.WriteValue(record.Type.ToString()); + jsonWriter.WriteString("type", record.Type.ToString()); jsonWriter.WritePropertyName("ttl"); if (authoritativeZoneRecords) - jsonWriter.WriteValue(record.TtlValue); + jsonWriter.WriteNumberValue(record.TTL); else - jsonWriter.WriteValue(record.TTL); + jsonWriter.WriteStringValue(record.TTL + " (" + WebUtilities.GetFormattedTime((int)record.TTL) + ")"); if (authoritativeZoneRecords) { string comments = record.GetComments(); if (!string.IsNullOrEmpty(comments)) - { - jsonWriter.WritePropertyName("comments"); - jsonWriter.WriteValue(comments); - } + jsonWriter.WriteString("comments", comments); } jsonWriter.WritePropertyName("rData"); @@ -133,16 +125,12 @@ namespace DnsServerCore { if (record.RDATA is DnsARecordData rdata) { - jsonWriter.WritePropertyName("ipAddress"); - jsonWriter.WriteValue(rdata.IPAddress); + jsonWriter.WriteString("ipAddress", rdata.Address.ToString()); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -151,27 +139,18 @@ namespace DnsServerCore { if (record.RDATA is DnsNSRecordData rdata) { - jsonWriter.WritePropertyName("nameServer"); - jsonWriter.WriteValue(rdata.NameServer.Length == 0 ? "." : rdata.NameServer); + jsonWriter.WriteString("nameServer", rdata.NameServer.Length == 0 ? "." : rdata.NameServer); if (!authoritativeZoneRecords) { if (rdata.IsParentSideTtlSet) - { - int parentSideTtl = (int)rdata.ParentSideTtl; - - jsonWriter.WritePropertyName("parentSideTtl"); - jsonWriter.WriteValue(parentSideTtl + " (" + WebUtilities.GetFormattedTime(parentSideTtl) + ")"); - } + jsonWriter.WriteString("parentSideTtl", rdata.ParentSideTtl + " (" + WebUtilities.GetFormattedTime((int)rdata.ParentSideTtl) + ")"); } } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -180,16 +159,12 @@ namespace DnsServerCore { if (record.RDATA is DnsCNAMERecordData rdata) { - jsonWriter.WritePropertyName("cname"); - jsonWriter.WriteValue(rdata.Domain.Length == 0 ? "." : rdata.Domain); + jsonWriter.WriteString("cname", rdata.Domain.Length == 0 ? "." : rdata.Domain); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -198,34 +173,18 @@ namespace DnsServerCore { if (record.RDATA is DnsSOARecordData rdata) { - jsonWriter.WritePropertyName("primaryNameServer"); - jsonWriter.WriteValue(rdata.PrimaryNameServer); - - jsonWriter.WritePropertyName("responsiblePerson"); - jsonWriter.WriteValue(rdata.ResponsiblePerson); - - jsonWriter.WritePropertyName("serial"); - jsonWriter.WriteValue(rdata.Serial); - - jsonWriter.WritePropertyName("refresh"); - jsonWriter.WriteValue(rdata.Refresh); - - jsonWriter.WritePropertyName("retry"); - jsonWriter.WriteValue(rdata.Retry); - - jsonWriter.WritePropertyName("expire"); - jsonWriter.WriteValue(rdata.Expire); - - jsonWriter.WritePropertyName("minimum"); - jsonWriter.WriteValue(rdata.Minimum); + jsonWriter.WriteString("primaryNameServer", rdata.PrimaryNameServer); + jsonWriter.WriteString("responsiblePerson", rdata.ResponsiblePerson); + jsonWriter.WriteNumber("serial", rdata.Serial); + jsonWriter.WriteNumber("refresh", rdata.Refresh); + jsonWriter.WriteNumber("retry", rdata.Retry); + jsonWriter.WriteNumber("expire", rdata.Expire); + jsonWriter.WriteNumber("minimum", rdata.Minimum); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } if (authoritativeZoneRecords) @@ -243,21 +202,14 @@ namespace DnsServerCore primaryAddresses = primaryAddresses + ", " + primaryNameServer.OriginalAddress; } - jsonWriter.WritePropertyName("primaryAddresses"); - jsonWriter.WriteValue(primaryAddresses); + jsonWriter.WriteString("primaryAddresses", primaryAddresses); } if (recordInfo.ZoneTransferProtocol != DnsTransportProtocol.Udp) - { - jsonWriter.WritePropertyName("zoneTransferProtocol"); - jsonWriter.WriteValue(recordInfo.ZoneTransferProtocol.ToString()); - } + jsonWriter.WriteString("zoneTransferProtocol", recordInfo.ZoneTransferProtocol.ToString()); if (!string.IsNullOrEmpty(recordInfo.TsigKeyName)) - { - jsonWriter.WritePropertyName("tsigKeyName"); - jsonWriter.WriteValue(recordInfo.TsigKeyName); - } + jsonWriter.WriteString("tsigKeyName", recordInfo.TsigKeyName); } } break; @@ -266,16 +218,12 @@ namespace DnsServerCore { if (record.RDATA is DnsPTRRecordData rdata) { - jsonWriter.WritePropertyName("ptrName"); - jsonWriter.WriteValue(rdata.Domain.Length == 0 ? "." : rdata.Domain); + jsonWriter.WriteString("ptrName", rdata.Domain.Length == 0 ? "." : rdata.Domain); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -284,20 +232,13 @@ namespace DnsServerCore { if (record.RDATA is DnsMXRecordData rdata) { - jsonWriter.WritePropertyName("preference"); - jsonWriter.WriteValue(rdata.Preference); - - jsonWriter.WritePropertyName("exchange"); - jsonWriter.WriteValue(rdata.Exchange.Length == 0 ? "." : rdata.Exchange); - + jsonWriter.WriteNumber("preference", rdata.Preference); + jsonWriter.WriteString("exchange", rdata.Exchange.Length == 0 ? "." : rdata.Exchange); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -306,16 +247,12 @@ namespace DnsServerCore { if (record.RDATA is DnsTXTRecordData rdata) { - jsonWriter.WritePropertyName("text"); - jsonWriter.WriteValue(rdata.Text); + jsonWriter.WriteString("text", rdata.Text); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -324,16 +261,12 @@ namespace DnsServerCore { if (record.RDATA is DnsAAAARecordData rdata) { - jsonWriter.WritePropertyName("ipAddress"); - jsonWriter.WriteValue(rdata.IPAddress); + jsonWriter.WriteString("ipAddress", rdata.Address.ToString()); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -342,25 +275,15 @@ namespace DnsServerCore { if (record.RDATA is DnsSRVRecordData rdata) { - jsonWriter.WritePropertyName("priority"); - jsonWriter.WriteValue(rdata.Priority); - - jsonWriter.WritePropertyName("weight"); - jsonWriter.WriteValue(rdata.Weight); - - jsonWriter.WritePropertyName("port"); - jsonWriter.WriteValue(rdata.Port); - - jsonWriter.WritePropertyName("target"); - jsonWriter.WriteValue(rdata.Target.Length == 0 ? "." : rdata.Target); + jsonWriter.WriteNumber("priority", rdata.Priority); + jsonWriter.WriteNumber("weight", rdata.Weight); + jsonWriter.WriteNumber("port", rdata.Port); + jsonWriter.WriteString("target", rdata.Target.Length == 0 ? "." : rdata.Target); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -369,16 +292,12 @@ namespace DnsServerCore { if (record.RDATA is DnsDNAMERecordData rdata) { - jsonWriter.WritePropertyName("dname"); - jsonWriter.WriteValue(rdata.Domain.Length == 0 ? "." : rdata.Domain); + jsonWriter.WriteString("dname", rdata.Domain.Length == 0 ? "." : rdata.Domain); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -387,25 +306,15 @@ namespace DnsServerCore { if (record.RDATA is DnsDSRecordData rdata) { - jsonWriter.WritePropertyName("keyTag"); - jsonWriter.WriteValue(rdata.KeyTag); - - jsonWriter.WritePropertyName("algorithm"); - jsonWriter.WriteValue(rdata.Algorithm.ToString()); - - jsonWriter.WritePropertyName("digestType"); - jsonWriter.WriteValue(rdata.DigestType.ToString()); - - jsonWriter.WritePropertyName("digest"); - jsonWriter.WriteValue(rdata.Digest); + jsonWriter.WriteNumber("keyTag", rdata.KeyTag); + jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString()); + jsonWriter.WriteString("digestType", rdata.DigestType.ToString()); + jsonWriter.WriteString("digest", Convert.ToHexString(rdata.Digest)); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -414,22 +323,14 @@ namespace DnsServerCore { if (record.RDATA is DnsSSHFPRecordData rdata) { - jsonWriter.WritePropertyName("algorithm"); - jsonWriter.WriteValue(rdata.Algorithm.ToString()); - - jsonWriter.WritePropertyName("fingerprintType"); - jsonWriter.WriteValue(rdata.FingerprintType.ToString()); - - jsonWriter.WritePropertyName("fingerprint"); - jsonWriter.WriteValue(rdata.Fingerprint); + jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString()); + jsonWriter.WriteString("fingerprintType", rdata.FingerprintType.ToString()); + jsonWriter.WriteString("fingerprint", Convert.ToHexString(rdata.Fingerprint)); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -438,40 +339,20 @@ namespace DnsServerCore { if (record.RDATA is DnsRRSIGRecordData rdata) { - jsonWriter.WritePropertyName("typeCovered"); - jsonWriter.WriteValue(rdata.TypeCovered.ToString()); - - jsonWriter.WritePropertyName("algorithm"); - jsonWriter.WriteValue(rdata.Algorithm.ToString()); - - jsonWriter.WritePropertyName("labels"); - jsonWriter.WriteValue(rdata.Labels); - - jsonWriter.WritePropertyName("originalTtl"); - jsonWriter.WriteValue(rdata.OriginalTtl); - - jsonWriter.WritePropertyName("signatureExpiration"); - jsonWriter.WriteValue(rdata.SignatureExpiration); - - jsonWriter.WritePropertyName("signatureInception"); - jsonWriter.WriteValue(rdata.SignatureInception); - - jsonWriter.WritePropertyName("keyTag"); - jsonWriter.WriteValue(rdata.KeyTag); - - jsonWriter.WritePropertyName("signersName"); - jsonWriter.WriteValue(rdata.SignersName.Length == 0 ? "." : rdata.SignersName); - - jsonWriter.WritePropertyName("signature"); - jsonWriter.WriteValue(Convert.ToBase64String(rdata.Signature)); + jsonWriter.WriteString("typeCovered", rdata.TypeCovered.ToString()); + jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString()); + jsonWriter.WriteNumber("labels", rdata.Labels); + jsonWriter.WriteNumber("originalTtl", rdata.OriginalTtl); + jsonWriter.WriteString("signatureExpiration", DateTime.UnixEpoch.AddSeconds(rdata.SignatureExpiration)); + jsonWriter.WriteString("signatureInception", DateTime.UnixEpoch.AddSeconds(rdata.SignatureInception)); + jsonWriter.WriteNumber("keyTag", rdata.KeyTag); + jsonWriter.WriteString("signersName", rdata.SignersName.Length == 0 ? "." : rdata.SignersName); + jsonWriter.WriteString("signature", Convert.ToBase64String(rdata.Signature)); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -480,24 +361,20 @@ namespace DnsServerCore { if (record.RDATA is DnsNSECRecordData rdata) { - jsonWriter.WritePropertyName("nextDomainName"); - jsonWriter.WriteValue(rdata.NextDomainName); + jsonWriter.WriteString("nextDomainName", rdata.NextDomainName); jsonWriter.WritePropertyName("types"); jsonWriter.WriteStartArray(); foreach (DnsResourceRecordType type in rdata.Types) - jsonWriter.WriteValue(type.ToString()); + jsonWriter.WriteStringValue(type.ToString()); jsonWriter.WriteEndArray(); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -506,20 +383,11 @@ namespace DnsServerCore { if (record.RDATA is DnsDNSKEYRecordData rdata) { - jsonWriter.WritePropertyName("flags"); - jsonWriter.WriteValue(rdata.Flags.ToString()); - - jsonWriter.WritePropertyName("protocol"); - jsonWriter.WriteValue(rdata.Protocol); - - jsonWriter.WritePropertyName("algorithm"); - jsonWriter.WriteValue(rdata.Algorithm.ToString()); - - jsonWriter.WritePropertyName("publicKey"); - jsonWriter.WriteValue(rdata.PublicKey.ToString()); - - jsonWriter.WritePropertyName("computedKeyTag"); - jsonWriter.WriteValue(rdata.ComputedKeyTag); + jsonWriter.WriteString("flags", rdata.Flags.ToString()); + jsonWriter.WriteNumber("protocol", rdata.Protocol); + jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString()); + jsonWriter.WriteString("publicKey", rdata.PublicKey.ToString()); + jsonWriter.WriteNumber("computedKeyTag", rdata.ComputedKeyTag); if (authoritativeZoneRecords) { @@ -529,14 +397,11 @@ namespace DnsServerCore { if (dnssecPrivateKey.KeyTag == rdata.ComputedKeyTag) { - jsonWriter.WritePropertyName("dnsKeyState"); - jsonWriter.WriteValue(dnssecPrivateKey.State.ToString()); + jsonWriter.WriteString("dnsKeyState", dnssecPrivateKey.State.ToString()); if ((dnssecPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (dnssecPrivateKey.State == DnssecPrivateKeyState.Published)) - { - jsonWriter.WritePropertyName("dnsKeyStateReadyBy"); - jsonWriter.WriteValue((zoneInfo.ApexZone as PrimaryZone).GetDnsKeyStateReadyBy(dnssecPrivateKey)); - } + jsonWriter.WriteString("dnsKeyStateReadyBy", (zoneInfo.ApexZone as PrimaryZone).GetDnsKeyStateReadyBy(dnssecPrivateKey)); + break; } } @@ -550,11 +415,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("digestType"); - jsonWriter.WriteValue("SHA256"); - - jsonWriter.WritePropertyName("digest"); - jsonWriter.WriteValue(rdata.CreateDS(record.Name, DnssecDigestType.SHA256).Digest); + jsonWriter.WriteString("digestType", "SHA256"); + jsonWriter.WriteString("digest", Convert.ToHexString(rdata.CreateDS(record.Name, DnssecDigestType.SHA256).Digest)); jsonWriter.WriteEndObject(); } @@ -562,11 +424,8 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("digestType"); - jsonWriter.WriteValue("SHA384"); - - jsonWriter.WritePropertyName("digest"); - jsonWriter.WriteValue(rdata.CreateDS(record.Name, DnssecDigestType.SHA384).Digest); + jsonWriter.WriteString("digestType", "SHA384"); + jsonWriter.WriteString("digest", Convert.ToHexString(rdata.CreateDS(record.Name, DnssecDigestType.SHA384).Digest)); jsonWriter.WriteEndObject(); } @@ -577,11 +436,8 @@ namespace DnsServerCore } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -590,36 +446,24 @@ namespace DnsServerCore { if (record.RDATA is DnsNSEC3RecordData rdata) { - jsonWriter.WritePropertyName("hashAlgorithm"); - jsonWriter.WriteValue(rdata.HashAlgorithm.ToString()); - - jsonWriter.WritePropertyName("flags"); - jsonWriter.WriteValue(rdata.Flags.ToString()); - - jsonWriter.WritePropertyName("iterations"); - jsonWriter.WriteValue(rdata.Iterations); - - jsonWriter.WritePropertyName("salt"); - jsonWriter.WriteValue(rdata.Salt); - - jsonWriter.WritePropertyName("nextHashedOwnerName"); - jsonWriter.WriteValue(rdata.NextHashedOwnerName); + jsonWriter.WriteString("hashAlgorithm", rdata.HashAlgorithm.ToString()); + jsonWriter.WriteString("flags", rdata.Flags.ToString()); + jsonWriter.WriteNumber("iterations", rdata.Iterations); + jsonWriter.WriteString("salt", Convert.ToHexString(rdata.Salt)); + jsonWriter.WriteString("nextHashedOwnerName", rdata.NextHashedOwnerName); jsonWriter.WritePropertyName("types"); jsonWriter.WriteStartArray(); foreach (DnsResourceRecordType type in rdata.Types) - jsonWriter.WriteValue(type.ToString()); + jsonWriter.WriteStringValue(type.ToString()); jsonWriter.WriteEndArray(); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -628,25 +472,15 @@ namespace DnsServerCore { if (record.RDATA is DnsNSEC3PARAMRecordData rdata) { - jsonWriter.WritePropertyName("hashAlgorithm"); - jsonWriter.WriteValue(rdata.HashAlgorithm.ToString()); - - jsonWriter.WritePropertyName("flags"); - jsonWriter.WriteValue(rdata.Flags.ToString()); - - jsonWriter.WritePropertyName("iterations"); - jsonWriter.WriteValue(rdata.Iterations); - - jsonWriter.WritePropertyName("salt"); - jsonWriter.WriteValue(rdata.Salt); + jsonWriter.WriteString("hashAlgorithm", rdata.HashAlgorithm.ToString()); + jsonWriter.WriteString("flags", rdata.Flags.ToString()); + jsonWriter.WriteNumber("iterations", rdata.Iterations); + jsonWriter.WriteString("salt", Convert.ToHexString(rdata.Salt)); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -655,25 +489,15 @@ namespace DnsServerCore { if (record.RDATA is DnsTLSARecordData rdata) { - jsonWriter.WritePropertyName("certificateUsage"); - jsonWriter.WriteValue(rdata.CertificateUsage.ToString().Replace('_', '-')); - - jsonWriter.WritePropertyName("selector"); - jsonWriter.WriteValue(rdata.Selector.ToString()); - - jsonWriter.WritePropertyName("matchingType"); - jsonWriter.WriteValue(rdata.MatchingType.ToString().Replace('_', '-')); - - jsonWriter.WritePropertyName("certificateAssociationData"); - jsonWriter.WriteValue(rdata.CertificateAssociationData); + jsonWriter.WriteString("certificateUsage", rdata.CertificateUsage.ToString().Replace('_', '-')); + jsonWriter.WriteString("selector", rdata.Selector.ToString()); + jsonWriter.WriteString("matchingType", rdata.MatchingType.ToString().Replace('_', '-')); + jsonWriter.WriteString("certificateAssociationData", Convert.ToHexString(rdata.CertificateAssociationData)); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -682,22 +506,14 @@ namespace DnsServerCore { if (record.RDATA is DnsCAARecordData rdata) { - jsonWriter.WritePropertyName("flags"); - jsonWriter.WriteValue(rdata.Flags); - - jsonWriter.WritePropertyName("tag"); - jsonWriter.WriteValue(rdata.Tag); - - jsonWriter.WritePropertyName("value"); - jsonWriter.WriteValue(rdata.Value); + jsonWriter.WriteNumber("flags", rdata.Flags); + jsonWriter.WriteString("tag", rdata.Tag); + jsonWriter.WriteString("value", rdata.Value); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -706,16 +522,12 @@ namespace DnsServerCore { if (record.RDATA is DnsANAMERecordData rdata) { - jsonWriter.WritePropertyName("aname"); - jsonWriter.WriteValue(rdata.Domain.Length == 0 ? "." : rdata.Domain); + jsonWriter.WriteString("aname", rdata.Domain.Length == 0 ? "." : rdata.Domain); } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -724,31 +536,17 @@ namespace DnsServerCore { if (record.RDATA is DnsForwarderRecordData rdata) { - jsonWriter.WritePropertyName("protocol"); - jsonWriter.WriteValue(rdata.Protocol.ToString()); - - jsonWriter.WritePropertyName("forwarder"); - jsonWriter.WriteValue(rdata.Forwarder); - - jsonWriter.WritePropertyName("dnssecValidation"); - jsonWriter.WriteValue(rdata.DnssecValidation); - - jsonWriter.WritePropertyName("proxyType"); - jsonWriter.WriteValue(rdata.ProxyType.ToString()); + jsonWriter.WriteString("protocol", rdata.Protocol.ToString()); + jsonWriter.WriteString("forwarder", rdata.Forwarder); + jsonWriter.WriteBoolean("dnssecValidation", rdata.DnssecValidation); + jsonWriter.WriteString("proxyType", rdata.ProxyType.ToString()); if (rdata.ProxyType != NetProxyType.None) { - jsonWriter.WritePropertyName("proxyAddress"); - jsonWriter.WriteValue(rdata.ProxyAddress); - - jsonWriter.WritePropertyName("proxyPort"); - jsonWriter.WriteValue(rdata.ProxyPort); - - jsonWriter.WritePropertyName("proxyUsername"); - jsonWriter.WriteValue(rdata.ProxyUsername); - - jsonWriter.WritePropertyName("proxyPassword"); - jsonWriter.WriteValue(rdata.ProxyPassword); + jsonWriter.WriteString("proxyAddress", rdata.ProxyAddress); + jsonWriter.WriteNumber("proxyPort", rdata.ProxyPort); + jsonWriter.WriteString("proxyUsername", rdata.ProxyUsername); + jsonWriter.WriteString("proxyPassword", rdata.ProxyPassword); } } } @@ -758,14 +556,9 @@ namespace DnsServerCore { if (record.RDATA is DnsApplicationRecordData rdata) { - jsonWriter.WritePropertyName("appName"); - jsonWriter.WriteValue(rdata.AppName); - - jsonWriter.WritePropertyName("classPath"); - jsonWriter.WriteValue(rdata.ClassPath); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(rdata.Data); + jsonWriter.WriteString("appName", rdata.AppName); + jsonWriter.WriteString("classPath", rdata.ClassPath); + jsonWriter.WriteString("data", rdata.Data); } } break; @@ -774,22 +567,17 @@ namespace DnsServerCore { if (record.RDATA is DnsUnknownRecordData) { - jsonWriter.WritePropertyName("value"); - using (MemoryStream mS = new MemoryStream()) { record.RDATA.WriteTo(mS); - jsonWriter.WriteValue(Convert.ToBase64String(mS.ToArray())); + jsonWriter.WriteString("value", Convert.ToBase64String(mS.ToArray())); } } else { - jsonWriter.WritePropertyName("dataType"); - jsonWriter.WriteValue(record.RDATA.GetType().Name); - - jsonWriter.WritePropertyName("data"); - jsonWriter.WriteValue(record.RDATA.ToString()); + jsonWriter.WriteString("dataType", record.RDATA.GetType().Name); + jsonWriter.WriteString("data", record.RDATA.ToString()); } } break; @@ -810,8 +598,7 @@ namespace DnsServerCore glue = glue + ", " + glueRecord.RDATA.ToString(); } - jsonWriter.WritePropertyName("glueRecords"); - jsonWriter.WriteValue(glue); + jsonWriter.WriteString("glueRecords", glue); } IReadOnlyList rrsigRecords = recordInfo.RRSIGRecords; @@ -825,91 +612,65 @@ namespace DnsServerCore if (rrsigRecords is not null) { foreach (DnsResourceRecord rrsigRecord in rrsigRecords) - jsonWriter.WriteValue(rrsigRecord.ToString()); + jsonWriter.WriteStringValue(rrsigRecord.ToString()); } if (nsecRecords is not null) { foreach (DnsResourceRecord nsecRecord in nsecRecords) - jsonWriter.WriteValue(nsecRecord.ToString()); + jsonWriter.WriteStringValue(nsecRecord.ToString()); } jsonWriter.WriteEndArray(); } - jsonWriter.WritePropertyName("dnssecStatus"); - jsonWriter.WriteValue(record.DnssecStatus.ToString()); + jsonWriter.WriteString("dnssecStatus", record.DnssecStatus.ToString()); NetworkAddress eDnsClientSubnet = recordInfo.EDnsClientSubnet; if (eDnsClientSubnet is not null) { - jsonWriter.WritePropertyName("eDnsClientSubnet"); - jsonWriter.WriteValue(eDnsClientSubnet.ToString()); + jsonWriter.WriteString("eDnsClientSubnet", eDnsClientSubnet.ToString()); } - jsonWriter.WritePropertyName("lastUsedOn"); - jsonWriter.WriteValue(recordInfo.LastUsedOn); + jsonWriter.WriteString("lastUsedOn", recordInfo.LastUsedOn); jsonWriter.WriteEndObject(); } - private static void WriteZoneInfoAsJson(AuthZoneInfo zoneInfo, JsonTextWriter jsonWriter) + private static void WriteZoneInfoAsJson(AuthZoneInfo zoneInfo, Utf8JsonWriter jsonWriter) { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(zoneInfo.Name); - - jsonWriter.WritePropertyName("type"); - jsonWriter.WriteValue(zoneInfo.Type.ToString()); + jsonWriter.WriteString("name", zoneInfo.Name); + jsonWriter.WriteString("type", zoneInfo.Type.ToString()); switch (zoneInfo.Type) { case AuthZoneType.Primary: - jsonWriter.WritePropertyName("internal"); - jsonWriter.WriteValue(zoneInfo.Internal); - - jsonWriter.WritePropertyName("dnssecStatus"); - jsonWriter.WriteValue(zoneInfo.DnssecStatus.ToString()); + jsonWriter.WriteBoolean("internal", zoneInfo.Internal); + jsonWriter.WriteString("dnssecStatus", zoneInfo.DnssecStatus.ToString()); if (!zoneInfo.Internal) - { - jsonWriter.WritePropertyName("notifyFailed"); - jsonWriter.WriteValue(zoneInfo.NotifyFailed); - } + jsonWriter.WriteBoolean("notifyFailed", zoneInfo.NotifyFailed); + break; case AuthZoneType.Secondary: - jsonWriter.WritePropertyName("dnssecStatus"); - jsonWriter.WriteValue(zoneInfo.DnssecStatus.ToString()); - - jsonWriter.WritePropertyName("expiry"); - jsonWriter.WriteValue(zoneInfo.Expiry); - - jsonWriter.WritePropertyName("isExpired"); - jsonWriter.WriteValue(zoneInfo.IsExpired); - - jsonWriter.WritePropertyName("notifyFailed"); - jsonWriter.WriteValue(zoneInfo.NotifyFailed); - - jsonWriter.WritePropertyName("syncFailed"); - jsonWriter.WriteValue(zoneInfo.SyncFailed); + jsonWriter.WriteString("dnssecStatus", zoneInfo.DnssecStatus.ToString()); + jsonWriter.WriteString("expiry", zoneInfo.Expiry); + jsonWriter.WriteBoolean("isExpired", zoneInfo.IsExpired); + jsonWriter.WriteBoolean("notifyFailed", zoneInfo.NotifyFailed); + jsonWriter.WriteBoolean("syncFailed", zoneInfo.SyncFailed); break; case AuthZoneType.Stub: - jsonWriter.WritePropertyName("expiry"); - jsonWriter.WriteValue(zoneInfo.Expiry); - - jsonWriter.WritePropertyName("isExpired"); - jsonWriter.WriteValue(zoneInfo.IsExpired); - - jsonWriter.WritePropertyName("syncFailed"); - jsonWriter.WriteValue(zoneInfo.SyncFailed); + jsonWriter.WriteString("expiry", zoneInfo.Expiry); + jsonWriter.WriteBoolean("isExpired", zoneInfo.IsExpired); + jsonWriter.WriteBoolean("syncFailed", zoneInfo.SyncFailed); break; } - jsonWriter.WritePropertyName("disabled"); - jsonWriter.WriteValue(zoneInfo.Disabled); + jsonWriter.WriteBoolean("disabled", zoneInfo.Disabled); jsonWriter.WriteEndObject(); } @@ -918,7 +679,7 @@ namespace DnsServerCore #region public - public void ListZones(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void ListZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { List zones = _dnsWebService.DnsServer.AuthZoneManager.ListZones(); zones.Sort(); @@ -939,7 +700,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public async Task CreateZoneAsync(HttpListenerRequest request, JsonTextWriter jsonWriter) + public async Task CreateZoneAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string zoneName = request.QueryString["zone"]; if (string.IsNullOrEmpty(zoneName)) @@ -1117,8 +878,7 @@ namespace DnsServerCore //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones _dnsWebService.DnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(string.IsNullOrEmpty(zoneInfo.Name) ? "." : zoneInfo.Name); + jsonWriter.WriteString("domain", string.IsNullOrEmpty(zoneInfo.Name) ? "." : zoneInfo.Name); } public void SignPrimaryZone(HttpListenerRequest request) @@ -1251,7 +1011,7 @@ namespace DnsServerCore _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void GetPrimaryZoneDnssecProperties(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetPrimaryZoneDnssecProperties(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string zoneName = request.QueryString["zone"]; if (string.IsNullOrEmpty(zoneName)) @@ -1274,35 +1034,22 @@ namespace DnsServerCore if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(zoneInfo.Name); - - jsonWriter.WritePropertyName("type"); - jsonWriter.WriteValue(zoneInfo.Type.ToString()); - - jsonWriter.WritePropertyName("internal"); - jsonWriter.WriteValue(zoneInfo.Internal); - - jsonWriter.WritePropertyName("disabled"); - jsonWriter.WriteValue(zoneInfo.Disabled); - - jsonWriter.WritePropertyName("dnssecStatus"); - jsonWriter.WriteValue(zoneInfo.DnssecStatus.ToString()); + jsonWriter.WriteString("name", zoneInfo.Name); + jsonWriter.WriteString("type", zoneInfo.Type.ToString()); + jsonWriter.WriteBoolean("internal", zoneInfo.Internal); + jsonWriter.WriteBoolean("disabled", zoneInfo.Disabled); + jsonWriter.WriteString("dnssecStatus", zoneInfo.DnssecStatus.ToString()); if (zoneInfo.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC3) { IReadOnlyList nsec3ParamRecords = zoneInfo.GetApexRecords(DnsResourceRecordType.NSEC3PARAM); DnsNSEC3PARAMRecordData nsec3Param = nsec3ParamRecords[0].RDATA as DnsNSEC3PARAMRecordData; - jsonWriter.WritePropertyName("nsec3Iterations"); - jsonWriter.WriteValue(nsec3Param.Iterations); - - jsonWriter.WritePropertyName("nsec3SaltLength"); - jsonWriter.WriteValue(nsec3Param.SaltValue.Length); + jsonWriter.WriteNumber("nsec3Iterations", nsec3Param.Iterations); + jsonWriter.WriteNumber("nsec3SaltLength", nsec3Param.Salt.Length); } - jsonWriter.WritePropertyName("dnsKeyTtl"); - jsonWriter.WriteValue(zoneInfo.DnsKeyTtl); + jsonWriter.WriteNumber("dnsKeyTtl", zoneInfo.DnsKeyTtl); jsonWriter.WritePropertyName("dnssecPrivateKeys"); jsonWriter.WriteStartArray(); @@ -1325,13 +1072,9 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("keyTag"); - jsonWriter.WriteValue(dnssecPrivateKey.KeyTag); + jsonWriter.WriteNumber("keyTag", dnssecPrivateKey.KeyTag); + jsonWriter.WriteString("keyType", dnssecPrivateKey.KeyType.ToString()); - jsonWriter.WritePropertyName("keyType"); - jsonWriter.WriteValue(dnssecPrivateKey.KeyType.ToString()); - - jsonWriter.WritePropertyName("algorithm"); switch (dnssecPrivateKey.Algorithm) { case DnssecAlgorithm.RSAMD5: @@ -1339,25 +1082,22 @@ namespace DnsServerCore case DnssecAlgorithm.RSASHA1_NSEC3_SHA1: case DnssecAlgorithm.RSASHA256: case DnssecAlgorithm.RSASHA512: - jsonWriter.WriteValue(dnssecPrivateKey.Algorithm.ToString() + " (" + (dnssecPrivateKey as DnssecRsaPrivateKey).KeySize + " bits)"); + jsonWriter.WriteString("algorithm", dnssecPrivateKey.Algorithm.ToString() + " (" + (dnssecPrivateKey as DnssecRsaPrivateKey).KeySize + " bits)"); break; default: - jsonWriter.WriteValue(dnssecPrivateKey.Algorithm.ToString()); + jsonWriter.WriteString("algorithm", dnssecPrivateKey.Algorithm.ToString()); break; } - jsonWriter.WritePropertyName("state"); - jsonWriter.WriteValue(dnssecPrivateKey.State.ToString()); + jsonWriter.WriteString("state", dnssecPrivateKey.State.ToString()); + jsonWriter.WriteString("stateChangedOn", dnssecPrivateKey.StateChangedOn); - jsonWriter.WritePropertyName("stateChangedOn"); - jsonWriter.WriteValue(dnssecPrivateKey.StateChangedOn); + if ((dnssecPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (dnssecPrivateKey.State == DnssecPrivateKeyState.Published)) + jsonWriter.WriteString("stateReadyBy", (zoneInfo.ApexZone as PrimaryZone).GetDnsKeyStateReadyBy(dnssecPrivateKey)); - jsonWriter.WritePropertyName("isRetiring"); - jsonWriter.WriteValue(dnssecPrivateKey.IsRetiring); - - jsonWriter.WritePropertyName("rolloverDays"); - jsonWriter.WriteValue(dnssecPrivateKey.RolloverDays); + jsonWriter.WriteBoolean("isRetiring", dnssecPrivateKey.IsRetiring); + jsonWriter.WriteNumber("rolloverDays", dnssecPrivateKey.RolloverDays); jsonWriter.WriteEndObject(); } @@ -1761,7 +1501,7 @@ namespace DnsServerCore _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } - public void GetZoneOptions(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetZoneOptions(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string zoneName = request.QueryString["zone"]; if (string.IsNullOrEmpty(zoneName)) @@ -1791,37 +1531,28 @@ namespace DnsServerCore if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - jsonWriter.WritePropertyName("name"); - jsonWriter.WriteValue(zoneInfo.Name); - - jsonWriter.WritePropertyName("type"); - jsonWriter.WriteValue(zoneInfo.Type.ToString()); + jsonWriter.WriteString("name", zoneInfo.Name); + jsonWriter.WriteString("type", zoneInfo.Type.ToString()); switch (zoneInfo.Type) { case AuthZoneType.Primary: - jsonWriter.WritePropertyName("internal"); - jsonWriter.WriteValue(zoneInfo.Internal); - - jsonWriter.WritePropertyName("dnssecStatus"); - jsonWriter.WriteValue(zoneInfo.DnssecStatus.ToString()); + jsonWriter.WriteBoolean("internal", zoneInfo.Internal); + jsonWriter.WriteString("dnssecStatus", zoneInfo.DnssecStatus.ToString()); break; case AuthZoneType.Secondary: - jsonWriter.WritePropertyName("dnssecStatus"); - jsonWriter.WriteValue(zoneInfo.DnssecStatus.ToString()); + jsonWriter.WriteString("dnssecStatus", zoneInfo.DnssecStatus.ToString()); break; } - jsonWriter.WritePropertyName("disabled"); - jsonWriter.WriteValue(zoneInfo.Disabled); + jsonWriter.WriteBoolean("disabled", zoneInfo.Disabled); switch (zoneInfo.Type) { case AuthZoneType.Primary: case AuthZoneType.Secondary: - jsonWriter.WritePropertyName("zoneTransfer"); - jsonWriter.WriteValue(zoneInfo.ZoneTransfer.ToString()); + jsonWriter.WriteString("zoneTransfer", zoneInfo.ZoneTransfer.ToString()); jsonWriter.WritePropertyName("zoneTransferNameServers"); { @@ -1830,7 +1561,7 @@ namespace DnsServerCore if (zoneInfo.ZoneTransferNameServers is not null) { foreach (IPAddress nameServer in zoneInfo.ZoneTransferNameServers) - jsonWriter.WriteValue(nameServer.ToString()); + jsonWriter.WriteStringValue(nameServer.ToString()); } jsonWriter.WriteEndArray(); @@ -1843,14 +1574,13 @@ namespace DnsServerCore if (zoneInfo.ZoneTransferTsigKeyNames is not null) { foreach (KeyValuePair tsigKeyName in zoneInfo.ZoneTransferTsigKeyNames) - jsonWriter.WriteValue(tsigKeyName.Key); + jsonWriter.WriteStringValue(tsigKeyName.Key); } jsonWriter.WriteEndArray(); } - jsonWriter.WritePropertyName("notify"); - jsonWriter.WriteValue(zoneInfo.Notify.ToString()); + jsonWriter.WriteString("notify", zoneInfo.Notify.ToString()); jsonWriter.WritePropertyName("notifyNameServers"); { @@ -1859,7 +1589,7 @@ namespace DnsServerCore if (zoneInfo.NotifyNameServers is not null) { foreach (IPAddress nameServer in zoneInfo.NotifyNameServers) - jsonWriter.WriteValue(nameServer.ToString()); + jsonWriter.WriteStringValue(nameServer.ToString()); } jsonWriter.WriteEndArray(); @@ -1871,8 +1601,7 @@ namespace DnsServerCore switch (zoneInfo.Type) { case AuthZoneType.Primary: - jsonWriter.WritePropertyName("update"); - jsonWriter.WriteValue(zoneInfo.Update.ToString()); + jsonWriter.WriteString("update", zoneInfo.Update.ToString()); jsonWriter.WritePropertyName("updateIpAddresses"); { @@ -1881,7 +1610,7 @@ namespace DnsServerCore if (zoneInfo.UpdateIpAddresses is not null) { foreach (IPAddress updateIpAddress in zoneInfo.UpdateIpAddresses) - jsonWriter.WriteValue(updateIpAddress.ToString()); + jsonWriter.WriteStringValue(updateIpAddress.ToString()); } jsonWriter.WriteEndArray(); @@ -1899,17 +1628,14 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("tsigKeyName"); - jsonWriter.WriteValue(updateSecurityPolicy.Key); - - jsonWriter.WritePropertyName("domain"); - jsonWriter.WriteValue(policy.Key); + jsonWriter.WriteString("tsigKeyName", updateSecurityPolicy.Key); + jsonWriter.WriteString("domain", policy.Key); jsonWriter.WritePropertyName("allowedTypes"); jsonWriter.WriteStartArray(); foreach (DnsResourceRecordType allowedType in policy.Value) - jsonWriter.WriteValue(allowedType.ToString()); + jsonWriter.WriteStringValue(allowedType.ToString()); jsonWriter.WriteEndArray(); @@ -1932,7 +1658,7 @@ namespace DnsServerCore if (_dnsWebService.DnsServer.TsigKeys is not null) { foreach (KeyValuePair tsigKey in _dnsWebService.DnsServer.TsigKeys) - jsonWriter.WriteValue(tsigKey.Key); + jsonWriter.WriteStringValue(tsigKey.Key); } jsonWriter.WriteEndArray(); @@ -2147,7 +1873,7 @@ namespace DnsServerCore } } - public void AddRecord(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void AddRecord(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string domain = request.QueryString["domain"]; if (string.IsNullOrEmpty(domain)) @@ -2716,7 +2442,7 @@ namespace DnsServerCore WriteRecordAsJson(newRecord, jsonWriter, true, null); } - public void GetRecords(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void GetRecords(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string domain = request.QueryString["domain"]; if (string.IsNullOrEmpty(domain)) @@ -3047,7 +2773,7 @@ namespace DnsServerCore _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } - public void UpdateRecord(HttpListenerRequest request, JsonTextWriter jsonWriter) + public void UpdateRecord(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { string strType = request.QueryString["type"]; if (string.IsNullOrEmpty(strType)) From 4c6cd4ea537073c81df9fe47db071c897ca2fda8 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 15:05:01 +0530 Subject: [PATCH 032/191] webapp: removed doh-json support. Updated OISD block list urls. Added support for new DHCP options. --- DnsServerCore/www/index.html | 76 ++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 79485261..d9c990ca 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -569,7 +569,7 @@

Note! The DNS Server local end point changes will be automatically applied and so you do not need to manually restart the main service.
@@ -1019,7 +1017,7 @@ Enable DNS-over-HTTP (TCP Port 8053)
-
Enable this option to accept DNS-over-HTTP requests for both wire and json response formats. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks.
+
Enable this option to accept DNS-over-HTTP requests. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks.
-
Enable this option to accept DNS-over-HTTPS requests for both wire and json response formats.
+
Enable this option to accept DNS-over-HTTPS requests.
@@ -1374,7 +1372,7 @@
- +
@@ -1407,6 +1405,7 @@ +
@@ -1530,7 +1529,6 @@ - @@ -1596,12 +1594,6 @@ DNS-over-HTTPS
-
- -
Select a protocol that this DNS server must use to query the forwarders specified above.
@@ -1991,7 +1983,7 @@
-
The bootstrap TFTP server IP address to be used by the clients. If not specified, the DHCP server's IP address is used.
+
The IP address of next server (TFTP) to use in bootstrap by the clients. If not specified, the DHCP server's IP address is used. (siaddr)
@@ -1999,15 +1991,15 @@
-
The optional bootstrap TFTP server host name to be used by the clients to identify the TFTP server.
+
The optional bootstrap server host name to be used by the clients to identify the TFTP server. (sname/Option 66)
- +
-
The boot file name stored on the bootstrap TFTP server to be used by the clients.
+
The boot file name stored on the bootstrap TFTP server to be used by the clients. (file/Option 67)
@@ -2026,7 +2018,7 @@ -
The vendor specific information option (43) to be sent to the clients that match the vendor class identifier option (60) in the request. The vendor class identifier can be empty string to match any identifier, or matched exactly, or match a substring, for example substring(vendor-class-identifier,0,9)=="PXEClient". The vendor specific information must be a colon (:) separated hex string, for example 06:01:03:0A:04:00:50:58:45:09:14:00:00:11:52:61:73:70:62:65:72:72:79:20:50:69:20:42:6F:6F:74:FF.
+
The Vendor Specific Information (option 43) to be sent to the clients that match the Vendor Class Identifier (option 60) in the request. The Cendor Class Identifier can be empty string to match any identifier, or matched exactly, or match a substring, for example substring(vendor-class-identifier,0,9)=="PXEClient". The Vendor Specific Information must be either a colon (:) separated hex string or a normal hex string, for example 06:01:03:0A:04:00:50:58:45:09:14:00:00:11:52:61:73:70:62:65:72:72:79:20:50:69:20:42:6F:6F:74:FF OR 0601030A0400505845091400001152617370626572727920506920426F6F74FF.
@@ -2040,6 +2032,35 @@ +
+
+ +
+ +
+
The TFTP Server Address or the VoIP Configuration Server Address. (Option 150)
+
+
+ +
+
+ +
+ + + + + + + + + +
CodeHex Value
+
+
This feature allows you to define DHCP options that are not yet directly supported. To add an option, use the DHCP option code defined for it and enter the value in either a colon (:) separated hex string or a normal hex string format, for example C0:A8:01:01 OR C0A80101.
+
+
+
@@ -2345,7 +2366,6 @@ -
@@ -2897,12 +2917,6 @@ ns1.example.com ([2001:db8::]) DNS-over-HTTPS
-
- -
@@ -3394,12 +3408,6 @@ MII... DNS-over-HTTPS -
- -
From 1f94b8d1156e1f8c5462de3136c25fd2ee5d9024 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 15:05:25 +0530 Subject: [PATCH 033/191] webapp: updated OISD block list urls. --- DnsServerCore/www/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index d9c990ca..b09fd8ae 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -1404,8 +1404,8 @@ - - + +
From 27458627923d09e289feb3f6b24becc78fbb6d95 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 15:06:07 +0530 Subject: [PATCH 034/191] common.js: updated serializeTableData() to support input number fields. --- DnsServerCore/www/js/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DnsServerCore/www/js/common.js b/DnsServerCore/www/js/common.js index b953a25b..b1618774 100644 --- a/DnsServerCore/www/js/common.js +++ b/DnsServerCore/www/js/common.js @@ -252,7 +252,7 @@ function sortTable(tableId, n) { } function serializeTableData(table, columns, objAlertPlaceholder) { - var data = table.find('input:text, input:checkbox, input:hidden, select'); + var data = table.find('input:text, :input[type="number"], input:checkbox, input:hidden, select'); var output = ""; for (var i = 0; i < data.length; i += columns) { From 60a9917a7704bf935de0de31658ad0746b8c5177 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 15:06:41 +0530 Subject: [PATCH 035/191] main.js: removed doh-json support. --- DnsServerCore/www/js/main.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index 28f3570c..28fbc7ca 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.js @@ -238,10 +238,8 @@ $(function () { if ((itemText.indexOf("TLS") !== -1) || (itemText.indexOf(":853") !== -1)) $("#optDnsClientProtocol").val("TLS"); - else if (itemText.indexOf("HTTPS-JSON") !== -1) - $("#optDnsClientProtocol").val("HttpsJson"); else if ((itemText.indexOf("HTTPS") !== -1) || (itemText.indexOf("http://") !== -1) || (itemText.indexOf("https://") !== -1)) - $("#optDnsClientProtocol").val("Https"); + $("#optDnsClientProtocol").val("HTTPS"); else { switch ($("#optDnsClientProtocol").val()) { case "UDP": @@ -471,11 +469,6 @@ $(function () { $("#rdForwarderProtocolHttps").prop("checked", true); break; - case "google-json": - $("#txtForwarders").val("https://dns.google/dns-query (8.8.8.8)\r\nhttps://dns.google/dns-query (8.8.4.4)"); - $("#rdForwarderProtocolHttpsJson").prop("checked", true); - break; - case "quad9-udp": $("#txtForwarders").val("9.9.9.9"); @@ -995,10 +988,6 @@ function loadDnsSettings() { $("#rdForwarderProtocolHttps").prop("checked", true); break; - case "httpsjson": - $("#rdForwarderProtocolHttpsJson").prop("checked", true); - break; - default: $("#rdForwarderProtocolUdp").prop("checked", true); break; From 40eea2cab42392c85159623bbd1e0fd431ee737c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 15:07:19 +0530 Subject: [PATCH 036/191] zone.js: removed doh-json support. Fixed minor ui issue. --- DnsServerCore/www/js/zone.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/DnsServerCore/www/js/zone.js b/DnsServerCore/www/js/zone.js index c50f6716..fc783dad 100644 --- a/DnsServerCore/www/js/zone.js +++ b/DnsServerCore/www/js/zone.js @@ -68,7 +68,6 @@ $(function () { break; case "Https": - case "HttpsJson": $("#txtAddZoneForwarder").attr("placeholder", "https://cloudflare-dns.com/dns-query (1.1.1.1)") break; } @@ -2221,9 +2220,9 @@ function modifyAddRecordFormByType(addMode) { $("#divAddEditRecordDataMx").hide(); $("#divAddEditRecordDataSrv").hide(); $("#divAddEditRecordDataDs").hide(); - $("#divAddEditRecordDataDs").hide(); $("#divAddEditRecordDataSshfp").hide(); $("#divAddEditRecordDataTlsa").hide(); + $("#divAddEditRecordDataCaa").hide(); $("#divAddEditRecordDataForwarder").hide(); $("#divAddEditRecordDataApplication").hide(); @@ -2768,7 +2767,6 @@ function updateAddEditFormForwarderPlaceholder() { break; case "Https": - case "HttpsJson": $("#txtAddEditRecordDataForwarder").attr("placeholder", "https://cloudflare-dns.com/dns-query (1.1.1.1)") break; } From 0030b5673a7d85affc0f651fbdd37d150acced60 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 15:08:19 +0530 Subject: [PATCH 037/191] dhcp.js: added support for generic options and TFTP server address option. --- DnsServerCore/www/js/dhcp.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/www/js/dhcp.js b/DnsServerCore/www/js/dhcp.js index 3e61fac4..a7313b45 100644 --- a/DnsServerCore/www/js/dhcp.js +++ b/DnsServerCore/www/js/dhcp.js @@ -250,6 +250,16 @@ function addDhcpScopeVendorInfoRow(identifier, information) { $("#tableDhcpScopeVendorInfo").append(tableHtmlRows); } +function addDhcpScopeGenericOptionsRow(optionCode, hexValue) { + var id = Math.floor(Math.random() * 10000); + + var tableHtmlRows = ""; + tableHtmlRows += ""; + tableHtmlRows += ""; + + $("#tableDhcpScopeGenericOptions").append(tableHtmlRows); +} + function addDhcpScopeExclusionRow(startingAddress, endingAddress) { var id = Math.floor(Math.random() * 10000); @@ -303,9 +313,12 @@ function clearDhcpScopeForm() { $("#tableDhcpScopeStaticRoutes").html(""); $("#tableDhcpScopeVendorInfo").html(""); $("#txtDhcpScopeCAPWAPApIpAddresses").val(""); + $("#txtDhcpScopeTftpServerAddresses").val(""); + $("#tableDhcpScopeGenericOptions").html(""); $("#tableDhcpScopeExclusions").html(""); $("#tableDhcpScopeReservedLeases").html(""); $("#chkAllowOnlyReservedLeases").prop("checked", false); + $("#chkBlockLocallyAdministeredMacAddresses").prop("checked", false); $("#btnSaveDhcpScope").button('reset'); } @@ -393,13 +406,22 @@ function showEditDhcpScope(scopeName) { if (responseJSON.response.vendorInfo != null) { for (var i = 0; i < responseJSON.response.vendorInfo.length; i++) { - addDhcpScopeVendorInfoRow(responseJSON.response.vendorInfo[i].identifier, responseJSON.response.vendorInfo[i].information) + addDhcpScopeVendorInfoRow(responseJSON.response.vendorInfo[i].identifier, responseJSON.response.vendorInfo[i].information); } } if (responseJSON.response.capwapAcIpAddresses != null) $("#txtDhcpScopeCAPWAPApIpAddresses").val(responseJSON.response.capwapAcIpAddresses.join("\n")); + if (responseJSON.response.tftpServerAddresses != null) + $("#txtDhcpScopeTftpServerAddresses").val(responseJSON.response.tftpServerAddresses.join("\n")); + + if (responseJSON.response.genericOptions != null) { + for (var i = 0; i < responseJSON.response.genericOptions.length; i++) { + addDhcpScopeGenericOptionsRow(responseJSON.response.genericOptions[i].code, responseJSON.response.genericOptions[i].value); + } + } + if (responseJSON.response.exclusions != null) { for (var i = 0; i < responseJSON.response.exclusions.length; i++) { addDhcpScopeExclusionRow(responseJSON.response.exclusions[i].startingAddress, responseJSON.response.exclusions[i].endingAddress); @@ -474,6 +496,12 @@ function saveDhcpScope() { var capwapAcIpAddresses = cleanTextList($("#txtDhcpScopeCAPWAPApIpAddresses").val()); + var tftpServerAddresses = cleanTextList($("#txtDhcpScopeTftpServerAddresses").val()); + + var genericOptions = serializeTableData($("#tableDhcpScopeGenericOptions"), 2); + if (genericOptions === false) + return; + var exclusions = serializeTableData($("#tableDhcpScopeExclusions"), 2); if (exclusions === false) return; @@ -492,7 +520,7 @@ function saveDhcpScope() { "&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) + "&exclusions=" + encodeURIComponent(exclusions) + "&reservedLeases=" + encodeURIComponent(reservedLeases) + "&allowOnlyReservedLeases=" + allowOnlyReservedLeases + "&blockLocallyAdministeredMacAddresses=" + blockLocallyAdministeredMacAddresses, + "&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, success: function (responseJSON) { refreshDhcpScopes(); btn.button('reset'); From a64ced8659e69fec8b6072f7b9e1fec00a0c8923 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 15:09:58 +0530 Subject: [PATCH 038/191] updated apidocs. --- APIDOCS.md | 103 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/APIDOCS.md b/APIDOCS.md index 647eae1a..74028eaa 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -2056,23 +2056,24 @@ RESPONSE: "internal": false, "disabled": false, "dnssecStatus": "SignedWithNSEC", - "dnsKeyTtl": 86400, + "dnsKeyTtl": 3600, "dnssecPrivateKeys": [ { - "keyTag": 19198, + "keyTag": 15048, "keyType": "KeySigningKey", "algorithm": "ECDSAP256SHA256", - "state": "Ready", - "stateChangedOn": "2022-02-19T06:53:21Z", + "state": "Published", + "stateChangedOn": "2022-12-18T14:39:50.0328321Z", + "stateReadyBy": "2022-12-18T16:14:50.0328321Z", "isRetiring": false, "rolloverDays": 0 }, { - "keyTag": 50617, + "keyTag": 46152, "keyType": "ZoneSigningKey", "algorithm": "ECDSAP256SHA256", "state": "Active", - "stateChangedOn": "2022-02-19T06:53:21Z", + "stateChangedOn": "2022-12-18T14:39:50.0661173Z", "isRetiring": false, "rolloverDays": 90 } @@ -2398,7 +2399,7 @@ WHERE: - `tag` (optional): This parameter is required for adding the `CAA` record. - `value` (optional): This parameter is required for adding the `CAA` record. - `aname` (optional): The ANAME domain name. This option is required for adding `ANAME` record. -- `protocol` (optional): This parameter is required for adding the `FWD` record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `HttpsJson`]. +- `protocol` (optional): This parameter is required for adding the `FWD` record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. - `forwarder` (optional): The forwarder address. A special value of `this-server` can be used to directly forward requests internally to the DNS server. This parameter is required for adding the `FWD` record. - `dnssecValidation` (optional): Set this boolean value to indicate if DNSSEC validation must be done. This optional parameter is to be used with FWD records. Default value is `false`. - `proxyType` (optional): The type of proxy that must be used for conditional forwarding. This optional parameter is to be used with FWD records. Valid values are [`None`, `Http`, `Socks5`]. Default value `None` is used when this parameter is missing. @@ -2626,10 +2627,6 @@ RESPONSE: "computedKeyTag": 65078, "dnsKeyState": "Ready", "computedDigests": [ - { - "digestType": "SHA1", - "digest": "3C2B05EBC20B77D8BC56EB9FFB36A6A1F07983F9" - }, { "digestType": "SHA256", "digest": "BBE017B17E5CB5FFFF1EC2C7815367DF80D8E7EAEE4832D3ED192159D79B1EEB" @@ -2661,30 +2658,28 @@ RESPONSE: "disabled": false, "name": "example.com", "type": "DNSKEY", - "ttl": 86400, + "ttl": 3600, "rData": { "flags": "SecureEntryPoint, ZoneKey", "protocol": 3, "algorithm": "ECDSAP256SHA256", - "publicKey": "KtXitZeC9ijbghCwQ5kjBfgLxCa0pBOOBGftudxGv/I= hlRGy7/Plea39T8n78xiHPaspYrTcdyidbKz6Z+ZSGw=", - "computedKeyTag": 52896, + "publicKey": "KOJWFitKm58EgjO43GDnsFbnkGoqVKeLRkP8FGPAdhqA2F758Ta1mkxieEu0YN0EoX+u5bVuc5DEBFSv+U63CA==", + "computedKeyTag": 15048, "dnsKeyState": "Published", + "dnsKeyStateReadyBy": "2022-12-18T16:14:50.0328321Z", "computedDigests": [ - { - "digestType": "SHA1", - "digest": "767EA31AD77C6AC2ACEB22B3FADB033679A6FB79" - }, { "digestType": "SHA256", - "digest": "BDBDB532C5809F890F8092DC9702D763D51A7318887B195CB52E888882FBE373" + "digest": "8EAFAE3305DB57A27CA5A261525515461CB7232A34A44AD96441B88BCA9B9849" }, { "digestType": "SHA384", - "digest": "A7EA4C7816ED5F011FDF90015D4A37BC7D1C773C22C3440B57D6717FA4ED71C5B95D09592AF48BD3ED59028D214A367E" + "digest": "4A6DA59E91872B5B835FCEE5987B17151A6F10FE409B595BEEEDB28FE64315C9C268493B59A0BF72EA84BE0F20A33F96" } ] }, - "dnssecStatus": "Unknown" + "dnssecStatus": "Unknown", + "lastUsedOn": "0001-01-01T00:00:00" }, { "disabled": false, @@ -3068,8 +3063,8 @@ WHERE: - `newValue` (optional): The new value in CAA record. This parameter is required when updating the `CAA` record. - `aname` (optional): The current ANAME domain name. This parameter is required when updating the `ANAME` record. - `newAName` (optional): The new ANAME domain name. This parameter is required when updating the `ANAME` record. -- `protocol` (optional): This is the current protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `HttpsJson`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. -- `newProtocol` (optional): This is the new protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `HttpsJson`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. +- `protocol` (optional): This is the current protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. +- `newProtocol` (optional): This is the new protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. - `forwarder` (optional): The current forwarder address. This parameter is required when updating the `FWD` record. - `newForwarder` (optional): The new forwarder address. This parameter is required when updating the `FWD` record. - `dnssecValidation` (optional): Set this boolean value to indicate if DNSSEC validation must be done. This optional parameter is to be used with FWD records. Default value is `false`. @@ -3160,7 +3155,7 @@ WHERE: - `tag` (optional): This is the tag parameter in the CAA record. This parameter is required when deleting the `CAA` record. - `value` (optional): This parameter is required when deleting the `CAA` record. - `aname` (optional): This parameter is required when deleting the `ANAME` record. -- `protocol` (optional): This is the protocol parameter in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `HttpsJson`]. This parameter is optional and default value `Udp` will be used when deleting the `FWD` record. +- `protocol` (optional): This is the protocol parameter in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. This parameter is optional and default value `Udp` will be used when deleting the `FWD` record. - `forwarder` (optional): This parameter is required when deleting the `FWD` record. RESPONSE: @@ -4003,7 +3998,7 @@ WHERE: - `server`: The name server to query using the DNS client. - `domain`: The domain name to query. - `type`: The type of the query. -- `protocol` (optional): The DNS transport protocol to be used to query. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `HttpsJson`]. The default value of `Udp` is used when the parameter is missing. +- `protocol` (optional): The DNS transport protocol to be used to query. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. The default value of `Udp` is used when the parameter is missing. - `dnssec` (optional): Set to `true` to enable DNSSEC validation. - `import` (optional): This parameter when set to `true` indicates that the response of the DNS query should be imported in the an authoritative zone on this DNS server. Default value is `false` when this parameter is missing. If a zone does not exists, a primary zone for the `domain` name is created and the records from the response are set into the zone. Import can be done only for primary and forwarder type of zones. When `type` is set to AXFR, then the import feature will work as if a zone transfer was requested and the complete zone will be updated as per the zone transfer response. Note that any existing record type for the given `type` will be overwritten when syncing the records. It is recommended to use `recursive-resolver` or the actual name server address for the `server` parameter when importing records. You must have Zones Modify permission to create a zone or Zone Modify permission to import records into an existing zone. @@ -4185,14 +4180,14 @@ WHERE: - `dnsServerLocalEndPoints` (optional): Local end points are the network interface IP addresses and ports you want the DNS Server to listen for requests. - `webServiceLocalAddresses` (optional): Local addresses are the network interface IP addresses you want the web service to listen for requests. - `webServiceHttpPort` (optional): Specify the TCP port number for the web console and this API web service. Default value is `5380`. -- `webServiceEnableTls` (optional): Set this to `true` to start the HTTPS service to acccess web service. +- `webServiceEnableTls` (optional): Set this to `true` to start the HTTPS service to access web service. - `webServiceTlsPort` (optional): Specified the TCP port number for the web console for HTTPS access. - `webServiceUseSelfSignedTlsCertificate` (optional): Set `true` for the web service to use an automatically generated self signed certificate when TLS certificate path is not specified. - `webServiceTlsCertificatePath` (optional): Specify a PKCS #12 certificate (.pfx) file path on the server. The certificate must contain private key. This certificate is used by the web console for HTTPS access. - `webServiceTlsCertificatePassword` (optional): Enter the certificate (.pfx) password, if any. -- `enableDnsOverHttp` (optional): Enable this option to accept DNS-over-HTTP requests for both wire and json response formats. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks. +- `enableDnsOverHttp` (optional): Enable this option to accept DNS-over-HTTP requests. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks. - `enableDnsOverTls` (optional): Enable this option to accept DNS-over-TLS requests. -- `enableDnsOverHttps` (optional): Enable this option to accept DNS-over-HTTPS requests for both wire and json response formats. +- `enableDnsOverHttps` (optional): Enable this option to accept DNS-over-HTTPS requests. - `dnsTlsCertificatePath` (optional): Specify a PKCS #12 certificate (.pfx) file path on the server. The certificate must contain private key. This certificate is used by the DNS-over-TLS and DNS-over-HTTPS optional protocols. - `dnsTlsCertificatePassword` (optional): Enter the certificate (.pfx) password, if any. - `tsigKeys` (optional): A pipe `|` separated multi row list of TSIG key name, shared secret, and algorithm. Set this parameter to `false` to remove all existing keys. Supported algorithms are [`hmac-md5.sig-alg.reg.int`, `hmac-sha1`, `hmac-sha256`, `hmac-sha256-128`, `hmac-sha384`, `hmac-sha384-192`, `hmac-sha512`, `hmac-sha512-256`]. @@ -4611,6 +4606,11 @@ RESPONSE: "pingCheckTimeout": 1000, "pingCheckRetries": 2, "domainName": "local", + "domainSearchList": [ + "home.arpa", + "lan" + ], + "dnsUpdates": true, "dnsTtl": 900, "serverAddress": "192.168.1.1", "serverHostName": "tftp-server-1", @@ -4639,6 +4639,19 @@ RESPONSE: "information": "06:01:03:0A:04:00:50:58:45:09:14:00:00:11:52:61:73:70:62:65:72:72:79:20:50:69:20:42:6F:6F:74:FF" } ], + "capwapAcIpAddresses": [ + "192.168.1.2" + ], + "tftpServerAddresses": [ + "192.168.1.5", + "192.168.1.6" + ], + "genericOptions": [ + { + "code": 150, + "value": "C0:A8:01:01" + } + ], "exclusions": [ { "startingAddress": "192.168.1.1", @@ -4653,7 +4666,8 @@ RESPONSE: "comments": "comments" } ], - "allowOnlyReservedLeases": false + "allowOnlyReservedLeases": false, + "blockLocallyAdministeredMacAddresses": true }, "status": "ok" } @@ -4682,25 +4696,32 @@ WHERE: - `leaseTimeDays` (optional): The lease time in number of days. - `leaseTimeHours` (optional): The lease time in number of hours. - `leaseTimeMinutes` (optional): The lease time in number of minutes. -- `offerDelayTime` (optional): The time duration in milli seconds that the DHCP server delays sending an DHCPOFFER message. +- `offerDelayTime` (optional): The time duration in milliseconds that the DHCP server delays sending an DHCPOFFER message. - `pingCheckEnabled` (optional): Set this option to `true` to allow the DHCP server to find out if an IP address is already in use to prevent IP address conflict when some of the devices on the network have manually configured IP addresses. - `pingCheckTimeout` (optional): The timeout interval to wait for an ping reply. - `pingCheckRetries` (optional): The maximum number of ping requests to try. -- `domainName` (optional): The domain name to be used by this network. The DHCP server automatically adds forward and reverse DNS entries for each IP address allocations when domain name is configured. +- `domainName` (optional): The domain name to be used by this network. The DHCP server automatically adds forward and reverse DNS entries for each IP address allocations when domain name is configured. (Option 15) +- `domainSearchList` (optional): A comma separated list of domain names that the clients can use as a suffix when searching a domain name. (Option 119) +- `dnsUpdates` (optional): Set this option to `true` to allow the DHCP server to automatically update forward and reverse DNS entries for clients. - `dnsTtl` (optional): The TTL value used for forward and reverse DNS records. -- `serverAddress` (optional): The bootstrap TFTP server IP address to be used by the clients. If not specified, the DHCP server's IP address is used. -- `serverHostName` (optional): The optional bootstrap TFTP server host name to be used by the clients to identify the TFTP server. -- `bootFileName` (optional): The boot file name stored on the bootstrap TFTP server to be used by the clients. -- `routerAddress` (optional): The default gateway or router IP address to be used by the clients. +- `serverAddress` (optional): The IP address of next server (TFTP) to use in bootstrap by the clients. If not specified, the DHCP server's IP address is used. (siaddr) +- `serverHostName` (optional): The optional bootstrap server host name to be used by the clients to identify the TFTP server. (sname/Option 66) +- `bootFileName` (optional): The boot file name stored on the bootstrap TFTP server to be used by the clients. (file/Option 67) +- `routerAddress` (optional): The default gateway IP address to be used by the clients. (Option 3) - `useThisDnsServer` (optional): Tells the DHCP server to use this DNS server's IP address to configure the DNS Servers DHCP option for clients. -- `dnsServers` (optional): A comma separated list of DNS server IP addresses to be used by the clients. This parameter is ignored when `useThisDnsServer` is set to `true`. -- `winsServers` (optional): A comma separated list of NBNS/WINS server IP addresses to be used by the clients. -- `ntpServers` (optional): A comma separated list of Network Time Protocol (NTP) server IP addresses to be used by the clients. -- `staticRoutes` (optional): A `|` separated list of static routes in format `{destination network address}|{subnet mask}|{router/gateway address}` to be used by the clients for accessing specified destination networks. -- `vendorInfo` (optional): A `|` separated list of vendor information in format `{vendor class identifier}|{vendor specific information}` where `{vendor specific information}` is a colon separated hex string. +- `dnsServers` (optional): A comma separated list of DNS server IP addresses to be used by the clients. This parameter is ignored when `useThisDnsServer` is set to `true`. (Option 6) +- `winsServers` (optional): A comma separated list of NBNS/WINS server IP addresses to be used by the clients. (Option 44) +- `ntpServers` (optional): A comma separated list of Network Time Protocol (NTP) server IP addresses to be used by the clients. (Option 42) +- `ntpServerDomainNames` (optional): Enter NTP server domain names (e.g. pool.ntp.org) above that the DHCP server should automatically resolve and pass the resolved IP addresses to clients as NTP server option. (Option 42) +- `staticRoutes` (optional): A `|` separated list of static routes in format `{destination network address}|{subnet mask}|{router/gateway address}` to be used by the clients for accessing specified destination networks. (Option 121) +- `vendorInfo` (optional): A `|` separated list of vendor information in format `{vendor class identifier}|{vendor specific information}` where `{vendor specific information}` is a colon separated hex string or a normal hex string. +- `capwapAcIpAddresses` (optional): A comma separated list of Control And Provisioning of Wireless Access Points (CAPWAP) Access Controller IP addresses to be used by Wireless Termination Points to discover the Access Controllers to which it is to connect. (Option 138) +- `tftpServerAddresses` (optional): A comma separated list of TFTP Server Address or the VoIP Configuration Server Address. (Option 150) +- `genericOptions` (optional): This feature allows you to define DHCP options that are not yet directly supported. Use a `|` separated list of DHCP option code defined for it and the value in either a colon (:) separated hex string or a normal hex string in format `{option-code}|{hex-string-value}`. - `exclusions` (optional): A `|` separated list of IP address range in format `{starting address}|{ending address}` that must be excluded or not assigned dynamically to any client by the DHCP server. - `reservedLeases` (optional): A `|` separated list of reserved IP addresses in format `{host name}|{MAC address}|{reserved IP address}|{comments}` to be assigned to specific clients based on their MAC address. - `allowOnlyReservedLeases` (optional): Set this parameter to `true` to stop dynamic IP address allocation and allocate only reserved IP addresses. +- `blockLocallyAdministeredMacAddresses` (optional): Set this parameter to `true` to stop dynamic IP address allocation for clients with locally administered MAC addresses. MAC address with 0x02 bit set in the first octet indicate a locally administered MAC address which usually means that the device is not using its original MAC address. RESPONSE: ``` @@ -5827,7 +5848,7 @@ WHERE: - `start` (optional): The start date time in ISO 8601 format to filter the logs. - `end` (optional): The end date time in ISO 8601 format to filter the logs. - `clientIpAddress` (optional): The client IP address to filter the logs. -- `protocol` (optional): The DNS transport protocol to filter the logs. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `HttpsJson`]. +- `protocol` (optional): The DNS transport protocol to filter the logs. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. - `responseType` (optional): The DNS server response type to filter the logs. Valid values are [`Authoritative`, `Recursive`, `Cached`, `Blocked`]. - `rcode` (optional): The DNS response code to filter the logs. - `qname` (optional): The query name (QNAME) in the request question section to filter the logs. From cecd7c14579235b5cee6584730e48289f91a6356 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 17:14:51 +0530 Subject: [PATCH 039/191] DnsWebService: code refactoring done to move settings related code into new WebServiceSettingsApi class. --- DnsServerCore/DnsWebService.cs | 2005 ++---------------------- DnsServerCore/WebServiceSettingsApi.cs | 1892 ++++++++++++++++++++++ 2 files changed, 1991 insertions(+), 1906 deletions(-) create mode 100644 DnsServerCore/WebServiceSettingsApi.cs diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index 24cf1cbd..8753c5f8 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -64,36 +64,35 @@ namespace DnsServerCore #region variables - readonly static RandomNumberGenerator _rng = RandomNumberGenerator.Create(); - - readonly LogManager _log; - readonly AuthManager _authManager; - - readonly WebServiceAuthApi _authApi; - readonly WebServiceDashboardApi _dashboardApi; - readonly WebServiceZonesApi _zonesApi; - readonly WebServiceOtherZonesApi _otherZonesApi; - readonly WebServiceAppsApi _appsApi; - readonly WebServiceDhcpApi _dhcpApi; - readonly WebServiceLogsApi _logsApi; - - readonly Version _currentVersion; + internal readonly Version _currentVersion; readonly string _appFolder; - readonly string _configFolder; + internal readonly string _configFolder; readonly Uri _updateCheckUri; - DnsServer _dnsServer; - DhcpServer _dhcpServer; + internal readonly LogManager _log; + internal readonly AuthManager _authManager; - IReadOnlyList _webServiceLocalAddresses = new IPAddress[] { IPAddress.Any, IPAddress.IPv6Any }; - int _webServiceHttpPort = 5380; - int _webServiceTlsPort = 53443; - bool _webServiceEnableTls; - bool _webServiceHttpToTlsRedirect; - bool _webServiceUseSelfSignedTlsCertificate; - string _webServiceTlsCertificatePath; - string _webServiceTlsCertificatePassword; - DateTime _webServiceTlsCertificateLastModifiedOn; + internal readonly WebServiceSettingsApi _settingsApi; + internal readonly WebServiceAuthApi _authApi; + internal readonly WebServiceDashboardApi _dashboardApi; + internal readonly WebServiceZonesApi _zonesApi; + internal readonly WebServiceOtherZonesApi _otherZonesApi; + internal readonly WebServiceAppsApi _appsApi; + internal readonly WebServiceDhcpApi _dhcpApi; + internal readonly WebServiceLogsApi _logsApi; + + internal DnsServer _dnsServer; + internal DhcpServer _dhcpServer; + + internal IReadOnlyList _webServiceLocalAddresses = new IPAddress[] { IPAddress.Any, IPAddress.IPv6Any }; + internal int _webServiceHttpPort = 5380; + internal int _webServiceTlsPort = 53443; + internal bool _webServiceEnableTls; + internal bool _webServiceHttpToTlsRedirect; + internal bool _webServiceUseSelfSignedTlsCertificate; + internal string _webServiceTlsCertificatePath; + internal string _webServiceTlsCertificatePassword; + internal DateTime _webServiceTlsCertificateLastModifiedOn; HttpListener _webService; IReadOnlyList _webServiceTlsListeners; @@ -102,8 +101,8 @@ namespace DnsServerCore string _webServiceHostname; IPEndPoint _webServiceHttpEP; - string _dnsTlsCertificatePath; - string _dnsTlsCertificatePassword; + internal string _dnsTlsCertificatePath; + internal string _dnsTlsCertificatePassword; DateTime _dnsTlsCertificateLastModifiedOn; Timer _tlsCertificateUpdateTimer; @@ -112,15 +111,6 @@ namespace DnsServerCore volatile ServiceState _state = ServiceState.Stopped; - Timer _blockListUpdateTimer; - DateTime _blockListLastUpdatedOn; - int _blockListUpdateIntervalHours = 24; - const int BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL = 5000; - const int BLOCK_LIST_UPDATE_TIMER_PERIODIC_INTERVAL = 900000; - - Timer _temporaryDisableBlockingTimer; - DateTime _temporaryDisableBlockingTill; - List _configDisabledZones; #endregion @@ -139,14 +129,15 @@ namespace DnsServerCore else _configFolder = configFolder; - if (!Directory.Exists(_configFolder)) - Directory.CreateDirectory(_configFolder); - _updateCheckUri = updateCheckUri; + Directory.CreateDirectory(_configFolder); + Directory.CreateDirectory(Path.Combine(_configFolder, "blocklists")); + _log = new LogManager(_configFolder); _authManager = new AuthManager(_configFolder, _log); + _settingsApi = new WebServiceSettingsApi(this); _authApi = new WebServiceAuthApi(this); _dashboardApi = new WebServiceDashboardApi(this); _zonesApi = new WebServiceZonesApi(this); @@ -154,11 +145,6 @@ namespace DnsServerCore _appsApi = new WebServiceAppsApi(this, appStoreUri); _dhcpApi = new WebServiceDhcpApi(this); _logsApi = new WebServiceLogsApi(this); - - string blockListsFolder = Path.Combine(_configFolder, "blocklists"); - - if (!Directory.Exists(blockListsFolder)) - Directory.CreateDirectory(blockListsFolder); } #endregion @@ -174,6 +160,9 @@ namespace DnsServerCore Stop(); + if (_settingsApi is not null) + _settingsApi.Dispose(); + if (_appsApi is not null) _appsApi.Dispose(); @@ -868,7 +857,7 @@ namespace DnsServerCore if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - GetDnsSettings(jsonWriter); + _settingsApi.GetDnsSettings(jsonWriter); break; case "/api/settings/set": @@ -876,7 +865,7 @@ namespace DnsServerCore if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - SetDnsSettings(request, jsonWriter); + _settingsApi.SetDnsSettings(request, jsonWriter); break; case "/api/settings/getTsigKeyNames": @@ -885,7 +874,7 @@ namespace DnsServerCore _authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify) ) { - GetTsigKeyNames(jsonWriter); + _settingsApi.GetTsigKeyNames(jsonWriter); } else { @@ -899,7 +888,7 @@ namespace DnsServerCore if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - ForceUpdateBlockLists(request); + _settingsApi.ForceUpdateBlockLists(request); break; case "/api/settings/temporaryDisableBlocking": @@ -907,7 +896,7 @@ namespace DnsServerCore if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - TemporaryDisableBlocking(request, jsonWriter); + _settingsApi.TemporaryDisableBlocking(request, jsonWriter); break; case "/api/settings/backup": @@ -915,7 +904,7 @@ namespace DnsServerCore if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - await BackupSettingsAsync(request, response); + await _settingsApi.BackupSettingsAsync(request, response); return; case "/api/settings/restore": @@ -923,7 +912,7 @@ namespace DnsServerCore if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - await RestoreSettingsAsync(request, jsonWriter); + await _settingsApi.RestoreSettingsAsync(request, jsonWriter); break; case "/api/dhcp/leases/list": @@ -1525,1763 +1514,6 @@ namespace DnsServerCore #endregion - #region settings api - - private void GetDnsSettings(Utf8JsonWriter jsonWriter) - { - //general - jsonWriter.WriteString("version", GetServerVersion()); - jsonWriter.WriteString("dnsServerDomain", _dnsServer.ServerDomain); - - jsonWriter.WritePropertyName("dnsServerLocalEndPoints"); - jsonWriter.WriteStartArray(); - - foreach (IPEndPoint localEP in _dnsServer.LocalEndPoints) - jsonWriter.WriteStringValue(localEP.ToString()); - - jsonWriter.WriteEndArray(); - - jsonWriter.WriteNumber("defaultRecordTtl", _zonesApi.DefaultRecordTtl); - jsonWriter.WriteBoolean("dnsAppsEnableAutomaticUpdate", _appsApi.EnableAutomaticUpdate); - - jsonWriter.WriteBoolean("preferIPv6", _dnsServer.PreferIPv6); - - jsonWriter.WriteNumber("udpPayloadSize", _dnsServer.UdpPayloadSize); - - jsonWriter.WriteBoolean("dnssecValidation", _dnsServer.DnssecValidation); - - jsonWriter.WriteBoolean("eDnsClientSubnet", _dnsServer.EDnsClientSubnet); - jsonWriter.WriteNumber("eDnsClientSubnetIPv4PrefixLength", _dnsServer.EDnsClientSubnetIPv4PrefixLength); - jsonWriter.WriteNumber("eDnsClientSubnetIPv6PrefixLength", _dnsServer.EDnsClientSubnetIPv6PrefixLength); - - jsonWriter.WriteNumber("qpmLimitRequests", _dnsServer.QpmLimitRequests); - jsonWriter.WriteNumber("qpmLimitErrors", _dnsServer.QpmLimitErrors); - jsonWriter.WriteNumber("qpmLimitSampleMinutes", _dnsServer.QpmLimitSampleMinutes); - jsonWriter.WriteNumber("qpmLimitIPv4PrefixLength", _dnsServer.QpmLimitIPv4PrefixLength); - jsonWriter.WriteNumber("qpmLimitIPv6PrefixLength", _dnsServer.QpmLimitIPv6PrefixLength); - - jsonWriter.WriteNumber("clientTimeout", _dnsServer.ClientTimeout); - jsonWriter.WriteNumber("tcpSendTimeout", _dnsServer.TcpSendTimeout); - jsonWriter.WriteNumber("tcpReceiveTimeout", _dnsServer.TcpReceiveTimeout); - - //web service - jsonWriter.WritePropertyName("webServiceLocalAddresses"); - jsonWriter.WriteStartArray(); - - foreach (IPAddress localAddress in _webServiceLocalAddresses) - { - if (localAddress.AddressFamily == AddressFamily.InterNetworkV6) - jsonWriter.WriteStringValue("[" + localAddress.ToString() + "]"); - else - jsonWriter.WriteStringValue(localAddress.ToString()); - } - - jsonWriter.WriteEndArray(); - - jsonWriter.WriteNumber("webServiceHttpPort", _webServiceHttpPort); - jsonWriter.WriteBoolean("webServiceEnableTls", _webServiceEnableTls); - jsonWriter.WriteBoolean("webServiceHttpToTlsRedirect", _webServiceHttpToTlsRedirect); - jsonWriter.WriteBoolean("webServiceUseSelfSignedTlsCertificate", _webServiceUseSelfSignedTlsCertificate); - jsonWriter.WriteNumber("webServiceTlsPort", _webServiceTlsPort); - jsonWriter.WriteString("webServiceTlsCertificatePath", _webServiceTlsCertificatePath); - jsonWriter.WriteString("webServiceTlsCertificatePassword", "************"); - - //optional protocols - jsonWriter.WriteBoolean("enableDnsOverHttp", _dnsServer.EnableDnsOverHttp); - jsonWriter.WriteBoolean("enableDnsOverTls", _dnsServer.EnableDnsOverTls); - jsonWriter.WriteBoolean("enableDnsOverHttps", _dnsServer.EnableDnsOverHttps); - jsonWriter.WriteString("dnsTlsCertificatePath", _dnsTlsCertificatePath); - jsonWriter.WriteString("dnsTlsCertificatePassword", "************"); - - //tsig - jsonWriter.WritePropertyName("tsigKeys"); - { - jsonWriter.WriteStartArray(); - - if (_dnsServer.TsigKeys is not null) - { - foreach (KeyValuePair tsigKey in _dnsServer.TsigKeys) - { - jsonWriter.WriteStartObject(); - - jsonWriter.WriteString("keyName", tsigKey.Key); - jsonWriter.WriteString("sharedSecret", tsigKey.Value.SharedSecret); - jsonWriter.WriteString("algorithmName", tsigKey.Value.AlgorithmName); - - jsonWriter.WriteEndObject(); - } - } - - jsonWriter.WriteEndArray(); - } - - //recursion - jsonWriter.WriteString("recursion", _dnsServer.Recursion.ToString()); - - jsonWriter.WritePropertyName("recursionDeniedNetworks"); - { - jsonWriter.WriteStartArray(); - - if (_dnsServer.RecursionDeniedNetworks is not null) - { - foreach (NetworkAddress networkAddress in _dnsServer.RecursionDeniedNetworks) - jsonWriter.WriteStringValue(networkAddress.ToString()); - } - - jsonWriter.WriteEndArray(); - } - - jsonWriter.WritePropertyName("recursionAllowedNetworks"); - { - jsonWriter.WriteStartArray(); - - if (_dnsServer.RecursionAllowedNetworks is not null) - { - foreach (NetworkAddress networkAddress in _dnsServer.RecursionAllowedNetworks) - jsonWriter.WriteStringValue(networkAddress.ToString()); - } - - jsonWriter.WriteEndArray(); - } - - jsonWriter.WriteBoolean("randomizeName", _dnsServer.RandomizeName); - jsonWriter.WriteBoolean("qnameMinimization", _dnsServer.QnameMinimization); - jsonWriter.WriteBoolean("nsRevalidation", _dnsServer.NsRevalidation); - - jsonWriter.WriteNumber("resolverRetries", _dnsServer.ResolverRetries); - jsonWriter.WriteNumber("resolverTimeout", _dnsServer.ResolverTimeout); - jsonWriter.WriteNumber("resolverMaxStackCount", _dnsServer.ResolverMaxStackCount); - - //cache - jsonWriter.WriteBoolean("serveStale", _dnsServer.ServeStale); - jsonWriter.WriteNumber("serveStaleTtl", _dnsServer.CacheZoneManager.ServeStaleTtl); - - jsonWriter.WriteNumber("cacheMaximumEntries", _dnsServer.CacheZoneManager.MaximumEntries); - jsonWriter.WriteNumber("cacheMinimumRecordTtl", _dnsServer.CacheZoneManager.MinimumRecordTtl); - jsonWriter.WriteNumber("cacheMaximumRecordTtl", _dnsServer.CacheZoneManager.MaximumRecordTtl); - jsonWriter.WriteNumber("cacheNegativeRecordTtl", _dnsServer.CacheZoneManager.NegativeRecordTtl); - jsonWriter.WriteNumber("cacheFailureRecordTtl", _dnsServer.CacheZoneManager.FailureRecordTtl); - - jsonWriter.WriteNumber("cachePrefetchEligibility", _dnsServer.CachePrefetchEligibility); - jsonWriter.WriteNumber("cachePrefetchTrigger", _dnsServer.CachePrefetchTrigger); - jsonWriter.WriteNumber("cachePrefetchSampleIntervalInMinutes", _dnsServer.CachePrefetchSampleIntervalInMinutes); - jsonWriter.WriteNumber("cachePrefetchSampleEligibilityHitsPerHour", _dnsServer.CachePrefetchSampleEligibilityHitsPerHour); - - //blocking - jsonWriter.WriteBoolean("enableBlocking", _dnsServer.EnableBlocking); - jsonWriter.WriteBoolean("allowTxtBlockingReport", _dnsServer.AllowTxtBlockingReport); - - if (!_dnsServer.EnableBlocking && (DateTime.UtcNow < _temporaryDisableBlockingTill)) - jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); - - jsonWriter.WriteString("blockingType", _dnsServer.BlockingType.ToString()); - - jsonWriter.WritePropertyName("customBlockingAddresses"); - jsonWriter.WriteStartArray(); - - foreach (DnsARecordData record in _dnsServer.CustomBlockingARecords) - jsonWriter.WriteStringValue(record.Address.ToString()); - - foreach (DnsAAAARecordData record in _dnsServer.CustomBlockingAAAARecords) - jsonWriter.WriteStringValue(record.Address.ToString()); - - jsonWriter.WriteEndArray(); - - jsonWriter.WritePropertyName("blockListUrls"); - - if ((_dnsServer.BlockListZoneManager.AllowListUrls.Count == 0) && (_dnsServer.BlockListZoneManager.BlockListUrls.Count == 0)) - { - jsonWriter.WriteNullValue(); - } - else - { - jsonWriter.WriteStartArray(); - - foreach (Uri allowListUrl in _dnsServer.BlockListZoneManager.AllowListUrls) - jsonWriter.WriteStringValue("!" + allowListUrl.AbsoluteUri); - - foreach (Uri blockListUrl in _dnsServer.BlockListZoneManager.BlockListUrls) - jsonWriter.WriteStringValue(blockListUrl.AbsoluteUri); - - jsonWriter.WriteEndArray(); - } - - jsonWriter.WriteNumber("blockListUpdateIntervalHours", _blockListUpdateIntervalHours); - - if (_blockListUpdateTimer is not null) - { - DateTime blockListNextUpdatedOn = _blockListLastUpdatedOn.AddHours(_blockListUpdateIntervalHours); - - jsonWriter.WriteString("blockListNextUpdatedOn", blockListNextUpdatedOn); - } - - //proxy & forwarders - jsonWriter.WritePropertyName("proxy"); - if (_dnsServer.Proxy == null) - { - jsonWriter.WriteNullValue(); - } - else - { - jsonWriter.WriteStartObject(); - - NetProxy proxy = _dnsServer.Proxy; - - jsonWriter.WriteString("type", proxy.Type.ToString()); - jsonWriter.WriteString("address", proxy.Address); - jsonWriter.WriteNumber("port", proxy.Port); - - NetworkCredential credential = proxy.Credential; - if (credential != null) - { - jsonWriter.WriteString("username", credential.UserName); - jsonWriter.WriteString("password", credential.Password); - } - - jsonWriter.WritePropertyName("bypass"); - jsonWriter.WriteStartArray(); - - foreach (NetProxyBypassItem item in proxy.BypassList) - jsonWriter.WriteStringValue(item.Value); - - jsonWriter.WriteEndArray(); - - jsonWriter.WriteEndObject(); - } - - jsonWriter.WritePropertyName("forwarders"); - - DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; - - if (_dnsServer.Forwarders == null) - { - jsonWriter.WriteNullValue(); - } - else - { - forwarderProtocol = _dnsServer.Forwarders[0].Protocol; - - jsonWriter.WriteStartArray(); - - foreach (NameServerAddress forwarder in _dnsServer.Forwarders) - jsonWriter.WriteStringValue(forwarder.OriginalAddress); - - jsonWriter.WriteEndArray(); - } - - jsonWriter.WriteString("forwarderProtocol", forwarderProtocol.ToString()); - - jsonWriter.WriteNumber("forwarderRetries", _dnsServer.ForwarderRetries); - jsonWriter.WriteNumber("forwarderTimeout", _dnsServer.ForwarderTimeout); - jsonWriter.WriteNumber("forwarderConcurrency", _dnsServer.ForwarderConcurrency); - - //logging - jsonWriter.WriteBoolean("enableLogging", _log.EnableLogging); - jsonWriter.WriteBoolean("logQueries", _dnsServer.QueryLogManager != null); - jsonWriter.WriteBoolean("useLocalTime", _log.UseLocalTime); - jsonWriter.WriteString("logFolder", _log.LogFolder); - jsonWriter.WriteNumber("maxLogFileDays", _log.MaxLogFileDays); - jsonWriter.WriteNumber("maxStatFileDays", _dnsServer.StatsManager.MaxStatFileDays); - } - - private void SetDnsSettings(HttpListenerRequest request, Utf8JsonWriter jsonWriter) - { - bool serverDomainChanged = false; - bool restartDnsService = false; - bool restartWebService = false; - int oldWebServiceHttpPort = _webServiceHttpPort; - - //general - string strDnsServerDomain = request.QueryString["dnsServerDomain"]; - if (!string.IsNullOrEmpty(strDnsServerDomain)) - { - serverDomainChanged = !_dnsServer.ServerDomain.Equals(strDnsServerDomain, StringComparison.OrdinalIgnoreCase); - _dnsServer.ServerDomain = strDnsServerDomain; - } - - string strDnsServerLocalEndPoints = request.QueryString["dnsServerLocalEndPoints"]; - if (strDnsServerLocalEndPoints != null) - { - if (string.IsNullOrEmpty(strDnsServerLocalEndPoints)) - strDnsServerLocalEndPoints = "0.0.0.0:53,[::]:53"; - - string[] strLocalEndPoints = strDnsServerLocalEndPoints.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List localEndPoints = new List(strLocalEndPoints.Length); - - for (int i = 0; i < strLocalEndPoints.Length; i++) - { - NameServerAddress nameServer = new NameServerAddress(strLocalEndPoints[i]); - if (nameServer.IPEndPoint != null) - localEndPoints.Add(nameServer.IPEndPoint); - } - - if (localEndPoints.Count > 0) - { - if (_dnsServer.LocalEndPoints.Count != localEndPoints.Count) - { - restartDnsService = true; - } - else - { - foreach (IPEndPoint currentLocalEP in _dnsServer.LocalEndPoints) - { - if (!localEndPoints.Contains(currentLocalEP)) - { - restartDnsService = true; - break; - } - } - } - - _dnsServer.LocalEndPoints = localEndPoints; - } - } - - string strDefaultRecordTtl = request.QueryString["defaultRecordTtl"]; - if (!string.IsNullOrEmpty(strDefaultRecordTtl)) - _zonesApi.DefaultRecordTtl = uint.Parse(strDefaultRecordTtl); - - string strDnsAppsEnableAutomaticUpdate = request.QueryString["dnsAppsEnableAutomaticUpdate"]; - if (!string.IsNullOrEmpty(strDnsAppsEnableAutomaticUpdate)) - _appsApi.EnableAutomaticUpdate = bool.Parse(strDnsAppsEnableAutomaticUpdate); - - string strPreferIPv6 = request.QueryString["preferIPv6"]; - if (!string.IsNullOrEmpty(strPreferIPv6)) - _dnsServer.PreferIPv6 = bool.Parse(strPreferIPv6); - - string strUdpPayloadSize = request.QueryString["udpPayloadSize"]; - if (!string.IsNullOrEmpty(strUdpPayloadSize)) - _dnsServer.UdpPayloadSize = ushort.Parse(strUdpPayloadSize); - - string strDnssecValidation = request.QueryString["dnssecValidation"]; - if (!string.IsNullOrEmpty(strDnssecValidation)) - _dnsServer.DnssecValidation = bool.Parse(strDnssecValidation); - - string strEDnsClientSubnet = request.QueryString["eDnsClientSubnet"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnet)) - _dnsServer.EDnsClientSubnet = bool.Parse(strEDnsClientSubnet); - - string strEDnsClientSubnetIPv4PrefixLength = request.QueryString["eDnsClientSubnetIPv4PrefixLength"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv4PrefixLength)) - _dnsServer.EDnsClientSubnetIPv4PrefixLength = byte.Parse(strEDnsClientSubnetIPv4PrefixLength); - - string strEDnsClientSubnetIPv6PrefixLength = request.QueryString["eDnsClientSubnetIPv6PrefixLength"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv6PrefixLength)) - _dnsServer.EDnsClientSubnetIPv6PrefixLength = byte.Parse(strEDnsClientSubnetIPv6PrefixLength); - - string strQpmLimitRequests = request.QueryString["qpmLimitRequests"]; - if (!string.IsNullOrEmpty(strQpmLimitRequests)) - _dnsServer.QpmLimitRequests = int.Parse(strQpmLimitRequests); - - string strQpmLimitErrors = request.QueryString["qpmLimitErrors"]; - if (!string.IsNullOrEmpty(strQpmLimitErrors)) - _dnsServer.QpmLimitErrors = int.Parse(strQpmLimitErrors); - - string strQpmLimitSampleMinutes = request.QueryString["qpmLimitSampleMinutes"]; - if (!string.IsNullOrEmpty(strQpmLimitSampleMinutes)) - _dnsServer.QpmLimitSampleMinutes = int.Parse(strQpmLimitSampleMinutes); - - string strQpmLimitIPv4PrefixLength = request.QueryString["qpmLimitIPv4PrefixLength"]; - if (!string.IsNullOrEmpty(strQpmLimitIPv4PrefixLength)) - _dnsServer.QpmLimitIPv4PrefixLength = int.Parse(strQpmLimitIPv4PrefixLength); - - string strQpmLimitIPv6PrefixLength = request.QueryString["qpmLimitIPv6PrefixLength"]; - if (!string.IsNullOrEmpty(strQpmLimitIPv6PrefixLength)) - _dnsServer.QpmLimitIPv6PrefixLength = int.Parse(strQpmLimitIPv6PrefixLength); - - string strClientTimeout = request.QueryString["clientTimeout"]; - if (!string.IsNullOrEmpty(strClientTimeout)) - _dnsServer.ClientTimeout = int.Parse(strClientTimeout); - - string strTcpSendTimeout = request.QueryString["tcpSendTimeout"]; - if (!string.IsNullOrEmpty(strTcpSendTimeout)) - _dnsServer.TcpSendTimeout = int.Parse(strTcpSendTimeout); - - string strTcpReceiveTimeout = request.QueryString["tcpReceiveTimeout"]; - if (!string.IsNullOrEmpty(strTcpReceiveTimeout)) - _dnsServer.TcpReceiveTimeout = int.Parse(strTcpReceiveTimeout); - - //web service - string strWebServiceLocalAddresses = request.QueryString["webServiceLocalAddresses"]; - if (strWebServiceLocalAddresses != null) - { - if (string.IsNullOrEmpty(strWebServiceLocalAddresses)) - strWebServiceLocalAddresses = "0.0.0.0,[::]"; - - string[] strLocalAddresses = strWebServiceLocalAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List localAddresses = new List(strLocalAddresses.Length); - - for (int i = 0; i < strLocalAddresses.Length; i++) - { - if (IPAddress.TryParse(strLocalAddresses[i], out IPAddress localAddress)) - localAddresses.Add(localAddress); - } - - if (localAddresses.Count > 0) - { - if (_webServiceLocalAddresses.Count != localAddresses.Count) - { - restartWebService = true; - } - else - { - foreach (IPAddress currentlocalAddress in _webServiceLocalAddresses) - { - if (!localAddresses.Contains(currentlocalAddress)) - { - restartWebService = true; - break; - } - } - } - - _webServiceLocalAddresses = localAddresses; - } - } - - string strWebServiceHttpPort = request.QueryString["webServiceHttpPort"]; - if (!string.IsNullOrEmpty(strWebServiceHttpPort)) - { - _webServiceHttpPort = int.Parse(strWebServiceHttpPort); - - if (oldWebServiceHttpPort != _webServiceHttpPort) - restartWebService = true; - } - - string strWebServiceEnableTls = request.QueryString["webServiceEnableTls"]; - if (!string.IsNullOrEmpty(strWebServiceEnableTls)) - { - bool oldWebServiceEnableTls = _webServiceEnableTls; - - _webServiceEnableTls = bool.Parse(strWebServiceEnableTls); - - if (oldWebServiceEnableTls != _webServiceEnableTls) - restartWebService = true; - } - - string strWebServiceHttpToTlsRedirect = request.QueryString["webServiceHttpToTlsRedirect"]; - if (!string.IsNullOrEmpty(strWebServiceHttpToTlsRedirect)) - _webServiceHttpToTlsRedirect = bool.Parse(strWebServiceHttpToTlsRedirect); - - string strWebServiceUseSelfSignedTlsCertificate = request.QueryString["webServiceUseSelfSignedTlsCertificate"]; - if (!string.IsNullOrEmpty(strWebServiceUseSelfSignedTlsCertificate)) - _webServiceUseSelfSignedTlsCertificate = bool.Parse(strWebServiceUseSelfSignedTlsCertificate); - - string strWebServiceTlsPort = request.QueryString["webServiceTlsPort"]; - if (!string.IsNullOrEmpty(strWebServiceTlsPort)) - { - int oldWebServiceTlsPort = _webServiceTlsPort; - - _webServiceTlsPort = int.Parse(strWebServiceTlsPort); - - if (oldWebServiceTlsPort != _webServiceTlsPort) - restartWebService = true; - } - - string strWebServiceTlsCertificatePath = request.QueryString["webServiceTlsCertificatePath"]; - string strWebServiceTlsCertificatePassword = request.QueryString["webServiceTlsCertificatePassword"]; - if (string.IsNullOrEmpty(strWebServiceTlsCertificatePath)) - { - _webServiceTlsCertificatePath = null; - _webServiceTlsCertificatePassword = ""; - } - else - { - if (strWebServiceTlsCertificatePassword == "************") - strWebServiceTlsCertificatePassword = _webServiceTlsCertificatePassword; - - if ((strWebServiceTlsCertificatePath != _webServiceTlsCertificatePath) || (strWebServiceTlsCertificatePassword != _webServiceTlsCertificatePassword)) - { - LoadWebServiceTlsCertificate(strWebServiceTlsCertificatePath, strWebServiceTlsCertificatePassword); - - _webServiceTlsCertificatePath = strWebServiceTlsCertificatePath; - _webServiceTlsCertificatePassword = strWebServiceTlsCertificatePassword; - - StartTlsCertificateUpdateTimer(); - } - } - - //optional protocols - string enableDnsOverHttp = request.QueryString["enableDnsOverHttp"]; - if (!string.IsNullOrEmpty(enableDnsOverHttp)) - { - bool oldEnableDnsOverHttp = _dnsServer.EnableDnsOverHttp; - - _dnsServer.EnableDnsOverHttp = bool.Parse(enableDnsOverHttp); - - if (oldEnableDnsOverHttp != _dnsServer.EnableDnsOverHttp) - restartDnsService = true; - } - - string strEnableDnsOverTls = request.QueryString["enableDnsOverTls"]; - if (!string.IsNullOrEmpty(strEnableDnsOverTls)) - { - bool oldEnableDnsOverTls = _dnsServer.EnableDnsOverTls; - - _dnsServer.EnableDnsOverTls = bool.Parse(strEnableDnsOverTls); - - if (oldEnableDnsOverTls != _dnsServer.EnableDnsOverTls) - restartDnsService = true; - } - - string strEnableDnsOverHttps = request.QueryString["enableDnsOverHttps"]; - if (!string.IsNullOrEmpty(strEnableDnsOverHttps)) - { - bool oldEnableDnsOverHttps = _dnsServer.EnableDnsOverHttps; - - _dnsServer.EnableDnsOverHttps = bool.Parse(strEnableDnsOverHttps); - - if (oldEnableDnsOverHttps != _dnsServer.EnableDnsOverHttps) - restartDnsService = true; - } - - string strDnsTlsCertificatePath = request.QueryString["dnsTlsCertificatePath"]; - string strDnsTlsCertificatePassword = request.QueryString["dnsTlsCertificatePassword"]; - if (string.IsNullOrEmpty(strDnsTlsCertificatePath)) - { - _dnsTlsCertificatePath = null; - _dnsTlsCertificatePassword = ""; - } - else - { - if (strDnsTlsCertificatePassword == "************") - strDnsTlsCertificatePassword = _dnsTlsCertificatePassword; - - if ((strDnsTlsCertificatePath != _dnsTlsCertificatePath) || (strDnsTlsCertificatePassword != _dnsTlsCertificatePassword)) - { - LoadDnsTlsCertificate(strDnsTlsCertificatePath, strDnsTlsCertificatePassword); - - _dnsTlsCertificatePath = strDnsTlsCertificatePath; - _dnsTlsCertificatePassword = strDnsTlsCertificatePassword; - - StartTlsCertificateUpdateTimer(); - } - } - - //tsig - string strTsigKeys = request.QueryString["tsigKeys"]; - if (!string.IsNullOrEmpty(strTsigKeys)) - { - if (strTsigKeys == "false") - { - _dnsServer.TsigKeys = null; - } - else - { - string[] strTsigKeyParts = strTsigKeys.Split('|'); - Dictionary tsigKeys = new Dictionary(strTsigKeyParts.Length); - - for (int i = 0; i < strTsigKeyParts.Length; i += 3) - { - string keyName = strTsigKeyParts[i + 0].ToLower(); - string sharedSecret = strTsigKeyParts[i + 1]; - string algorithmName = strTsigKeyParts[i + 2]; - - if (sharedSecret.Length == 0) - { - byte[] key = new byte[32]; - _rng.GetBytes(key); - - tsigKeys.Add(keyName, new TsigKey(keyName, Convert.ToBase64String(key), algorithmName)); - } - else - { - tsigKeys.Add(keyName, new TsigKey(keyName, sharedSecret, algorithmName)); - } - } - - _dnsServer.TsigKeys = tsigKeys; - } - } - - //recursion - string strRecursion = request.QueryString["recursion"]; - if (!string.IsNullOrEmpty(strRecursion)) - _dnsServer.Recursion = Enum.Parse(strRecursion, true); - - string strRecursionDeniedNetworks = request.QueryString["recursionDeniedNetworks"]; - if (!string.IsNullOrEmpty(strRecursionDeniedNetworks)) - { - if (strRecursionDeniedNetworks == "false") - { - _dnsServer.RecursionDeniedNetworks = null; - } - else - { - string[] strNetworks = strRecursionDeniedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - NetworkAddress[] networks = new NetworkAddress[strNetworks.Length]; - - for (int i = 0; i < networks.Length; i++) - networks[i] = NetworkAddress.Parse(strNetworks[i]); - - _dnsServer.RecursionDeniedNetworks = networks; - } - } - - string strRecursionAllowedNetworks = request.QueryString["recursionAllowedNetworks"]; - if (!string.IsNullOrEmpty(strRecursionAllowedNetworks)) - { - if (strRecursionAllowedNetworks == "false") - { - _dnsServer.RecursionAllowedNetworks = null; - } - else - { - string[] strNetworks = strRecursionAllowedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - NetworkAddress[] networks = new NetworkAddress[strNetworks.Length]; - - for (int i = 0; i < networks.Length; i++) - networks[i] = NetworkAddress.Parse(strNetworks[i]); - - _dnsServer.RecursionAllowedNetworks = networks; - } - } - - string strRandomizeName = request.QueryString["randomizeName"]; - if (!string.IsNullOrEmpty(strRandomizeName)) - _dnsServer.RandomizeName = bool.Parse(strRandomizeName); - - string strQnameMinimization = request.QueryString["qnameMinimization"]; - if (!string.IsNullOrEmpty(strQnameMinimization)) - _dnsServer.QnameMinimization = bool.Parse(strQnameMinimization); - - string strNsRevalidation = request.QueryString["nsRevalidation"]; - if (!string.IsNullOrEmpty(strNsRevalidation)) - _dnsServer.NsRevalidation = bool.Parse(strNsRevalidation); - - string strResolverRetries = request.QueryString["resolverRetries"]; - if (!string.IsNullOrEmpty(strResolverRetries)) - _dnsServer.ResolverRetries = int.Parse(strResolverRetries); - - string strResolverTimeout = request.QueryString["resolverTimeout"]; - if (!string.IsNullOrEmpty(strResolverTimeout)) - _dnsServer.ResolverTimeout = int.Parse(strResolverTimeout); - - string strResolverMaxStackCount = request.QueryString["resolverMaxStackCount"]; - if (!string.IsNullOrEmpty(strResolverMaxStackCount)) - _dnsServer.ResolverMaxStackCount = int.Parse(strResolverMaxStackCount); - - //cache - string strServeStale = request.QueryString["serveStale"]; - if (!string.IsNullOrEmpty(strServeStale)) - _dnsServer.ServeStale = bool.Parse(strServeStale); - - string strServeStaleTtl = request.QueryString["serveStaleTtl"]; - if (!string.IsNullOrEmpty(strServeStaleTtl)) - _dnsServer.CacheZoneManager.ServeStaleTtl = uint.Parse(strServeStaleTtl); - - string strCacheMaximumEntries = request.QueryString["cacheMaximumEntries"]; - if (!string.IsNullOrEmpty(strCacheMaximumEntries)) - _dnsServer.CacheZoneManager.MaximumEntries = long.Parse(strCacheMaximumEntries); - - string strCacheMinimumRecordTtl = request.QueryString["cacheMinimumRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheMinimumRecordTtl)) - _dnsServer.CacheZoneManager.MinimumRecordTtl = uint.Parse(strCacheMinimumRecordTtl); - - string strCacheMaximumRecordTtl = request.QueryString["cacheMaximumRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheMaximumRecordTtl)) - _dnsServer.CacheZoneManager.MaximumRecordTtl = uint.Parse(strCacheMaximumRecordTtl); - - string strCacheNegativeRecordTtl = request.QueryString["cacheNegativeRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheNegativeRecordTtl)) - _dnsServer.CacheZoneManager.NegativeRecordTtl = uint.Parse(strCacheNegativeRecordTtl); - - string strCacheFailureRecordTtl = request.QueryString["cacheFailureRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheFailureRecordTtl)) - _dnsServer.CacheZoneManager.FailureRecordTtl = uint.Parse(strCacheFailureRecordTtl); - - string strCachePrefetchEligibility = request.QueryString["cachePrefetchEligibility"]; - if (!string.IsNullOrEmpty(strCachePrefetchEligibility)) - _dnsServer.CachePrefetchEligibility = int.Parse(strCachePrefetchEligibility); - - string strCachePrefetchTrigger = request.QueryString["cachePrefetchTrigger"]; - if (!string.IsNullOrEmpty(strCachePrefetchTrigger)) - _dnsServer.CachePrefetchTrigger = int.Parse(strCachePrefetchTrigger); - - string strCachePrefetchSampleIntervalInMinutes = request.QueryString["cachePrefetchSampleIntervalInMinutes"]; - if (!string.IsNullOrEmpty(strCachePrefetchSampleIntervalInMinutes)) - _dnsServer.CachePrefetchSampleIntervalInMinutes = int.Parse(strCachePrefetchSampleIntervalInMinutes); - - string strCachePrefetchSampleEligibilityHitsPerHour = request.QueryString["cachePrefetchSampleEligibilityHitsPerHour"]; - if (!string.IsNullOrEmpty(strCachePrefetchSampleEligibilityHitsPerHour)) - _dnsServer.CachePrefetchSampleEligibilityHitsPerHour = int.Parse(strCachePrefetchSampleEligibilityHitsPerHour); - - //blocking - string strEnableBlocking = request.QueryString["enableBlocking"]; - if (!string.IsNullOrEmpty(strEnableBlocking)) - { - _dnsServer.EnableBlocking = bool.Parse(strEnableBlocking); - if (_dnsServer.EnableBlocking) - { - if (_temporaryDisableBlockingTimer is not null) - _temporaryDisableBlockingTimer.Dispose(); - } - } - - string strAllowTxtBlockingReport = request.QueryString["allowTxtBlockingReport"]; - if (!string.IsNullOrEmpty(strAllowTxtBlockingReport)) - _dnsServer.AllowTxtBlockingReport = bool.Parse(strAllowTxtBlockingReport); - - string strBlockingType = request.QueryString["blockingType"]; - if (!string.IsNullOrEmpty(strBlockingType)) - _dnsServer.BlockingType = Enum.Parse(strBlockingType, true); - - string strCustomBlockingAddresses = request.QueryString["customBlockingAddresses"]; - if (!string.IsNullOrEmpty(strCustomBlockingAddresses)) - { - if (strCustomBlockingAddresses == "false") - { - _dnsServer.CustomBlockingARecords = null; - _dnsServer.CustomBlockingAAAARecords = null; - } - else - { - string[] strAddresses = strCustomBlockingAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - List dnsARecords = new List(); - List dnsAAAARecords = new List(); - - foreach (string strAddress in strAddresses) - { - if (IPAddress.TryParse(strAddress, out IPAddress customAddress)) - { - switch (customAddress.AddressFamily) - { - case AddressFamily.InterNetwork: - dnsARecords.Add(new DnsARecordData(customAddress)); - break; - - case AddressFamily.InterNetworkV6: - dnsAAAARecords.Add(new DnsAAAARecordData(customAddress)); - break; - } - } - } - - _dnsServer.CustomBlockingARecords = dnsARecords; - _dnsServer.CustomBlockingAAAARecords = dnsAAAARecords; - } - } - - bool blockListUrlsUpdated = false; - string strBlockListUrls = request.QueryString["blockListUrls"]; - if (!string.IsNullOrEmpty(strBlockListUrls)) - { - if (strBlockListUrls == "false") - { - _dnsServer.BlockListZoneManager.AllowListUrls.Clear(); - _dnsServer.BlockListZoneManager.BlockListUrls.Clear(); - _dnsServer.BlockListZoneManager.Flush(); - } - else - { - string[] strBlockListUrlList = strBlockListUrls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - if (oldWebServiceHttpPort != _webServiceHttpPort) - { - for (int i = 0; i < strBlockListUrlList.Length; i++) - { - if (strBlockListUrlList[i].Contains("http://localhost:" + oldWebServiceHttpPort + "/blocklist.txt")) - { - strBlockListUrlList[i] = "http://localhost:" + _webServiceHttpPort + "/blocklist.txt"; - blockListUrlsUpdated = true; - break; - } - } - } - - if (!blockListUrlsUpdated) - { - if (strBlockListUrlList.Length != (_dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsServer.BlockListZoneManager.BlockListUrls.Count)) - { - blockListUrlsUpdated = true; - } - else - { - foreach (string strBlockListUrl in strBlockListUrlList) - { - if (strBlockListUrl.StartsWith("!")) - { - string strAllowListUrl = strBlockListUrl.Substring(1); - - if (!_dnsServer.BlockListZoneManager.AllowListUrls.Contains(new Uri(strAllowListUrl))) - { - blockListUrlsUpdated = true; - break; - } - } - else - { - if (!_dnsServer.BlockListZoneManager.BlockListUrls.Contains(new Uri(strBlockListUrl))) - { - blockListUrlsUpdated = true; - break; - } - } - } - } - } - - if (blockListUrlsUpdated) - { - _dnsServer.BlockListZoneManager.AllowListUrls.Clear(); - _dnsServer.BlockListZoneManager.BlockListUrls.Clear(); - - foreach (string strBlockListUrl in strBlockListUrlList) - { - if (strBlockListUrl.StartsWith("!")) - { - Uri allowListUrl = new Uri(strBlockListUrl.Substring(1)); - - if (!_dnsServer.BlockListZoneManager.AllowListUrls.Contains(allowListUrl)) - _dnsServer.BlockListZoneManager.AllowListUrls.Add(allowListUrl); - } - else - { - Uri blockListUrl = new Uri(strBlockListUrl); - - if (!_dnsServer.BlockListZoneManager.BlockListUrls.Contains(blockListUrl)) - _dnsServer.BlockListZoneManager.BlockListUrls.Add(blockListUrl); - } - } - } - } - } - - string strBlockListUpdateIntervalHours = request.QueryString["blockListUpdateIntervalHours"]; - if (!string.IsNullOrEmpty(strBlockListUpdateIntervalHours)) - { - int blockListUpdateIntervalHours = int.Parse(strBlockListUpdateIntervalHours); - - if ((blockListUpdateIntervalHours < 0) || (blockListUpdateIntervalHours > 168)) - throw new DnsWebServiceException("Parameter `blockListUpdateIntervalHours` must be between 1 hour and 168 hours (7 days) or 0 to disable automatic update."); - - _blockListUpdateIntervalHours = blockListUpdateIntervalHours; - } - - if ((_blockListUpdateIntervalHours > 0) && ((_dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsServer.BlockListZoneManager.BlockListUrls.Count) > 0)) - { - if (blockListUrlsUpdated || (_blockListUpdateTimer is null)) - ForceUpdateBlockLists(); - - StartBlockListUpdateTimer(); - } - else - { - StopBlockListUpdateTimer(); - } - - //proxy & forwarders - string strProxyType = request.QueryString["proxyType"]; - if (!string.IsNullOrEmpty(strProxyType)) - { - NetProxyType proxyType = Enum.Parse(strProxyType, true); - if (proxyType == NetProxyType.None) - { - _dnsServer.Proxy = null; - } - else - { - NetworkCredential credential = null; - - string strUsername = request.QueryString["proxyUsername"]; - if (!string.IsNullOrEmpty(strUsername)) - credential = new NetworkCredential(strUsername, request.QueryString["proxyPassword"]); - - _dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.QueryString["proxyAddress"], int.Parse(request.QueryString["proxyPort"]), credential); - - string strProxyBypass = request.QueryString["proxyBypass"]; - if (!string.IsNullOrEmpty(strProxyBypass)) - { - string[] strBypassList = strProxyBypass.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List bypassList = new List(strBypassList.Length); - - for (int i = 0; i < strBypassList.Length; i++) - bypassList.Add(new NetProxyBypassItem(strBypassList[i])); - - _dnsServer.Proxy.BypassList = bypassList; - } - } - } - - DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; - string strForwarderProtocol = request.QueryString["forwarderProtocol"]; - if (!string.IsNullOrEmpty(strForwarderProtocol)) - { - forwarderProtocol = Enum.Parse(strForwarderProtocol, true); - if (forwarderProtocol == DnsTransportProtocol.HttpsJson) - forwarderProtocol = DnsTransportProtocol.Https; - } - - string strForwarders = request.QueryString["forwarders"]; - if (!string.IsNullOrEmpty(strForwarders)) - { - if (strForwarders == "false") - { - _dnsServer.Forwarders = null; - } - else - { - string[] strForwardersList = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - NameServerAddress[] forwarders = new NameServerAddress[strForwardersList.Length]; - - for (int i = 0; i < strForwardersList.Length; i++) - { - NameServerAddress forwarder = new NameServerAddress(strForwardersList[i]); - - if (forwarder.Protocol != forwarderProtocol) - forwarder = forwarder.ChangeProtocol(forwarderProtocol); - - forwarders[i] = forwarder; - } - - _dnsServer.Forwarders = forwarders; - } - } - - string strForwarderRetries = request.QueryString["forwarderRetries"]; - if (!string.IsNullOrEmpty(strForwarderRetries)) - _dnsServer.ForwarderRetries = int.Parse(strForwarderRetries); - - string strForwarderTimeout = request.QueryString["forwarderTimeout"]; - if (!string.IsNullOrEmpty(strForwarderTimeout)) - _dnsServer.ForwarderTimeout = int.Parse(strForwarderTimeout); - - string strForwarderConcurrency = request.QueryString["forwarderConcurrency"]; - if (!string.IsNullOrEmpty(strForwarderConcurrency)) - _dnsServer.ForwarderConcurrency = int.Parse(strForwarderConcurrency); - - //logging - string strEnableLogging = request.QueryString["enableLogging"]; - if (!string.IsNullOrEmpty(strEnableLogging)) - _log.EnableLogging = bool.Parse(strEnableLogging); - - string strLogQueries = request.QueryString["logQueries"]; - if (!string.IsNullOrEmpty(strLogQueries)) - { - if (bool.Parse(strLogQueries)) - _dnsServer.QueryLogManager = _log; - else - _dnsServer.QueryLogManager = null; - } - - string strUseLocalTime = request.QueryString["useLocalTime"]; - if (!string.IsNullOrEmpty(strUseLocalTime)) - _log.UseLocalTime = bool.Parse(strUseLocalTime); - - string strLogFolder = request.QueryString["logFolder"]; - if (!string.IsNullOrEmpty(strLogFolder)) - _log.LogFolder = strLogFolder; - - string strMaxLogFileDays = request.QueryString["maxLogFileDays"]; - if (!string.IsNullOrEmpty(strMaxLogFileDays)) - _log.MaxLogFileDays = int.Parse(strMaxLogFileDays); - - string strMaxStatFileDays = request.QueryString["maxStatFileDays"]; - if (!string.IsNullOrEmpty(strMaxStatFileDays)) - _dnsServer.StatsManager.MaxStatFileDays = int.Parse(strMaxStatFileDays); - - //TLS actions - if ((_webServiceTlsCertificatePath == null) && (_dnsTlsCertificatePath == null)) - StopTlsCertificateUpdateTimer(); - - SelfSignedCertCheck(serverDomainChanged, true); - - if (_webServiceEnableTls && string.IsNullOrEmpty(_webServiceTlsCertificatePath) && !_webServiceUseSelfSignedTlsCertificate) - { - //disable TLS - _webServiceEnableTls = false; - restartWebService = true; - } - - //save config - SaveConfigFile(); - _log.Save(); - - _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).User.Username + "] DNS Settings were updated {dnsServerDomain: " + _dnsServer.ServerDomain + "; dnsServerLocalEndPoints: " + strDnsServerLocalEndPoints + "; webServiceLocalAddresses: " + strWebServiceLocalAddresses + "; webServiceHttpPort: " + _webServiceHttpPort + "; webServiceEnableTls: " + strWebServiceEnableTls + "; webServiceHttpToTlsRedirect: " + strWebServiceHttpToTlsRedirect + "; webServiceTlsPort: " + strWebServiceTlsPort + "; webServiceUseSelfSignedTlsCertificate: " + _webServiceUseSelfSignedTlsCertificate + "; webServiceTlsCertificatePath: " + strWebServiceTlsCertificatePath + "; enableDnsOverHttp: " + _dnsServer.EnableDnsOverHttp + "; enableDnsOverTls: " + _dnsServer.EnableDnsOverTls + "; enableDnsOverHttps: " + _dnsServer.EnableDnsOverHttps + "; dnsTlsCertificatePath: " + _dnsTlsCertificatePath + "; defaultRecordTtl: " + _zonesApi.DefaultRecordTtl + "; preferIPv6: " + _dnsServer.PreferIPv6 + "; enableLogging: " + strEnableLogging + "; logQueries: " + (_dnsServer.QueryLogManager != null) + "; useLocalTime: " + strUseLocalTime + "; logFolder: " + strLogFolder + "; maxLogFileDays: " + strMaxLogFileDays + "; recursion: " + _dnsServer.Recursion.ToString() + "; randomizeName: " + strRandomizeName + "; qnameMinimization: " + strQnameMinimization + "; serveStale: " + strServeStale + "; serveStaleTtl: " + strServeStaleTtl + "; cachePrefetchEligibility: " + strCachePrefetchEligibility + "; cachePrefetchTrigger: " + strCachePrefetchTrigger + "; cachePrefetchSampleIntervalInMinutes: " + strCachePrefetchSampleIntervalInMinutes + "; cachePrefetchSampleEligibilityHitsPerHour: " + strCachePrefetchSampleEligibilityHitsPerHour + "; proxyType: " + strProxyType + "; forwarders: " + strForwarders + "; forwarderProtocol: " + strForwarderProtocol + "; enableBlocking: " + _dnsServer.EnableBlocking + "; allowTxtBlockingReport: " + _dnsServer.AllowTxtBlockingReport + "; blockingType: " + _dnsServer.BlockingType.ToString() + "; blockListUrl: " + strBlockListUrls + "; blockListUpdateIntervalHours: " + strBlockListUpdateIntervalHours + ";}"); - - GetDnsSettings(jsonWriter); - - RestartService(restartDnsService, restartWebService); - } - - private void GetTsigKeyNames(Utf8JsonWriter jsonWriter) - { - jsonWriter.WritePropertyName("tsigKeyNames"); - { - jsonWriter.WriteStartArray(); - - if (_dnsServer.TsigKeys is not null) - { - foreach (KeyValuePair tsigKey in _dnsServer.TsigKeys) - jsonWriter.WriteStringValue(tsigKey.Key); - } - - jsonWriter.WriteEndArray(); - } - } - - private void SelfSignedCertCheck(bool generateNew, bool throwException) - { - string selfSignedCertificateFilePath = Path.Combine(_configFolder, "cert.pfx"); - - if (_webServiceUseSelfSignedTlsCertificate) - { - if (generateNew || !File.Exists(selfSignedCertificateFilePath)) - { - RSA rsa = RSA.Create(2048); - CertificateRequest req = new CertificateRequest("cn=" + _dnsServer.ServerDomain, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); - X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(5)); - - File.WriteAllBytes(selfSignedCertificateFilePath, cert.Export(X509ContentType.Pkcs12, null as string)); - } - - if (_webServiceEnableTls && string.IsNullOrEmpty(_webServiceTlsCertificatePath)) - { - try - { - LoadWebServiceTlsCertificate(selfSignedCertificateFilePath, null); - } - catch (Exception ex) - { - _log.Write("DNS Server encountered an error while loading self signed Web Service TLS certificate: " + selfSignedCertificateFilePath + "\r\n" + ex.ToString()); - - if (throwException) - throw; - } - } - } - else - { - File.Delete(selfSignedCertificateFilePath); - } - } - - private void RestartService(bool restartDnsService, bool restartWebService) - { - if (restartDnsService) - { - _ = Task.Run(delegate () - { - _log.Write("Attempting to restart DNS service."); - - try - { - _dnsServer.Stop(); - _dnsServer.Start(); - - _log.Write("DNS service was restarted successfully."); - } - catch (Exception ex) - { - _log.Write("Failed to restart DNS service."); - _log.Write(ex); - } - }); - } - - if (restartWebService) - { - _ = Task.Run(async delegate () - { - await Task.Delay(2000); //wait for this HTTP response to be delivered before stopping web server - - _log.Write("Attempting to restart web service."); - - try - { - StopDnsWebService(); - StartDnsWebService(); - - _log.Write("Web service was restarted successfully."); - } - catch (Exception ex) - { - _log.Write("Failed to restart web service."); - _log.Write(ex); - } - }); - } - } - - private async Task BackupSettingsAsync(HttpListenerRequest request, HttpListenerResponse response) - { - bool blockLists = false; - bool logs = false; - bool scopes = false; - bool apps = false; - bool stats = false; - bool zones = false; - bool allowedZones = false; - bool blockedZones = false; - bool dnsSettings = false; - bool authConfig = false; - bool logSettings = false; - - string strBlockLists = request.QueryString["blockLists"]; - if (!string.IsNullOrEmpty(strBlockLists)) - blockLists = bool.Parse(strBlockLists); - - string strLogs = request.QueryString["logs"]; - if (!string.IsNullOrEmpty(strLogs)) - logs = bool.Parse(strLogs); - - string strScopes = request.QueryString["scopes"]; - if (!string.IsNullOrEmpty(strScopes)) - scopes = bool.Parse(strScopes); - - string strApps = request.QueryString["apps"]; - if (!string.IsNullOrEmpty(strApps)) - apps = bool.Parse(strApps); - - string strStats = request.QueryString["stats"]; - if (!string.IsNullOrEmpty(strStats)) - stats = bool.Parse(strStats); - - string strZones = request.QueryString["zones"]; - if (!string.IsNullOrEmpty(strZones)) - zones = bool.Parse(strZones); - - string strAllowedZones = request.QueryString["allowedZones"]; - if (!string.IsNullOrEmpty(strAllowedZones)) - allowedZones = bool.Parse(strAllowedZones); - - string strBlockedZones = request.QueryString["blockedZones"]; - if (!string.IsNullOrEmpty(strBlockedZones)) - blockedZones = bool.Parse(strBlockedZones); - - string strDnsSettings = request.QueryString["dnsSettings"]; - if (!string.IsNullOrEmpty(strDnsSettings)) - dnsSettings = bool.Parse(strDnsSettings); - - string strAuthConfig = request.QueryString["authConfig"]; - if (!string.IsNullOrEmpty(strAuthConfig)) - authConfig = bool.Parse(strAuthConfig); - - string strLogSettings = request.QueryString["logSettings"]; - if (!string.IsNullOrEmpty(strLogSettings)) - logSettings = bool.Parse(strLogSettings); - - string tmpFile = Path.GetTempFileName(); - try - { - using (FileStream backupZipStream = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) - { - //create backup zip - using (ZipArchive backupZip = new ZipArchive(backupZipStream, ZipArchiveMode.Create, true, Encoding.UTF8)) - { - if (blockLists) - { - string[] blockListFiles = Directory.GetFiles(Path.Combine(_configFolder, "blocklists"), "*", SearchOption.TopDirectoryOnly); - foreach (string blockListFile in blockListFiles) - { - string entryName = "blocklists/" + Path.GetFileName(blockListFile); - backupZip.CreateEntryFromFile(blockListFile, entryName); - } - } - - if (logs) - { - string[] logFiles = Directory.GetFiles(_log.LogFolderAbsolutePath, "*.log", SearchOption.TopDirectoryOnly); - foreach (string logFile in logFiles) - { - string entryName = "logs/" + Path.GetFileName(logFile); - - if (logFile.Equals(_log.CurrentLogFile, StringComparison.OrdinalIgnoreCase)) - { - await CreateBackupEntryFromFileAsync(backupZip, logFile, entryName); - } - else - { - backupZip.CreateEntryFromFile(logFile, entryName); - } - } - } - - if (scopes) - { - string[] scopeFiles = Directory.GetFiles(Path.Combine(_configFolder, "scopes"), "*.scope", SearchOption.TopDirectoryOnly); - foreach (string scopeFile in scopeFiles) - { - string entryName = "scopes/" + Path.GetFileName(scopeFile); - backupZip.CreateEntryFromFile(scopeFile, entryName); - } - } - - if (apps) - { - string[] appFiles = Directory.GetFiles(Path.Combine(_configFolder, "apps"), "*", SearchOption.AllDirectories); - foreach (string appFile in appFiles) - { - string entryName = appFile.Substring(_configFolder.Length); - - if (Path.DirectorySeparatorChar != '/') - entryName = entryName.Replace(Path.DirectorySeparatorChar, '/'); - - entryName = entryName.TrimStart('/'); - - await CreateBackupEntryFromFileAsync(backupZip, appFile, entryName); - } - } - - if (stats) - { - string[] hourlyStatsFiles = Directory.GetFiles(Path.Combine(_configFolder, "stats"), "*.stat", SearchOption.TopDirectoryOnly); - foreach (string hourlyStatsFile in hourlyStatsFiles) - { - string entryName = "stats/" + Path.GetFileName(hourlyStatsFile); - backupZip.CreateEntryFromFile(hourlyStatsFile, entryName); - } - - string[] dailyStatsFiles = Directory.GetFiles(Path.Combine(_configFolder, "stats"), "*.dstat", SearchOption.TopDirectoryOnly); - foreach (string dailyStatsFile in dailyStatsFiles) - { - string entryName = "stats/" + Path.GetFileName(dailyStatsFile); - backupZip.CreateEntryFromFile(dailyStatsFile, entryName); - } - } - - if (zones) - { - string[] zoneFiles = Directory.GetFiles(Path.Combine(_configFolder, "zones"), "*.zone", SearchOption.TopDirectoryOnly); - foreach (string zoneFile in zoneFiles) - { - string entryName = "zones/" + Path.GetFileName(zoneFile); - backupZip.CreateEntryFromFile(zoneFile, entryName); - } - } - - if (allowedZones) - { - string allowedZonesFile = Path.Combine(_configFolder, "allowed.config"); - - if (File.Exists(allowedZonesFile)) - backupZip.CreateEntryFromFile(allowedZonesFile, "allowed.config"); - } - - if (blockedZones) - { - string blockedZonesFile = Path.Combine(_configFolder, "blocked.config"); - - if (File.Exists(blockedZonesFile)) - backupZip.CreateEntryFromFile(blockedZonesFile, "blocked.config"); - } - - if (dnsSettings) - { - string dnsSettingsFile = Path.Combine(_configFolder, "dns.config"); - - if (File.Exists(dnsSettingsFile)) - backupZip.CreateEntryFromFile(dnsSettingsFile, "dns.config"); - } - - if (authConfig) - { - string authSettingsFile = Path.Combine(_configFolder, "auth.config"); - - if (File.Exists(authSettingsFile)) - backupZip.CreateEntryFromFile(authSettingsFile, "auth.config"); - } - - if (logSettings) - { - string logSettingsFile = Path.Combine(_configFolder, "log.config"); - - if (File.Exists(logSettingsFile)) - backupZip.CreateEntryFromFile(logSettingsFile, "log.config"); - } - } - - //send zip file - backupZipStream.Position = 0; - - response.ContentType = "application/zip"; - response.ContentLength64 = backupZipStream.Length; - response.AddHeader("Content-Disposition", "attachment;filename=DnsServerBackup.zip"); - - using (Stream output = response.OutputStream) - { - await backupZipStream.CopyToAsync(output); - } - } - } - finally - { - try - { - File.Delete(tmpFile); - } - catch (Exception ex) - { - _log.Write(ex); - } - } - - _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).User.Username + "] Settings backup zip file was exported."); - } - - private static async Task CreateBackupEntryFromFileAsync(ZipArchive backupZip, string sourceFileName, string entryName) - { - using (FileStream fS = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - ZipArchiveEntry entry = backupZip.CreateEntry(entryName); - - DateTime lastWrite = File.GetLastWriteTime(sourceFileName); - - // If file to be archived has an invalid last modified time, use the first datetime representable in the Zip timestamp format - // (midnight on January 1, 1980): - if (lastWrite.Year < 1980 || lastWrite.Year > 2107) - lastWrite = new DateTime(1980, 1, 1, 0, 0, 0); - - entry.LastWriteTime = lastWrite; - - using (Stream sE = entry.Open()) - { - await fS.CopyToAsync(sE); - } - } - } - - private async Task RestoreSettingsAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) - { - bool blockLists = false; - bool logs = false; - bool scopes = false; - bool apps = false; - bool stats = false; - bool zones = false; - bool allowedZones = false; - bool blockedZones = false; - bool dnsSettings = false; - bool authConfig = false; - bool logSettings = false; - - bool deleteExistingFiles = false; - - string strBlockLists = request.QueryString["blockLists"]; - if (!string.IsNullOrEmpty(strBlockLists)) - blockLists = bool.Parse(strBlockLists); - - string strLogs = request.QueryString["logs"]; - if (!string.IsNullOrEmpty(strLogs)) - logs = bool.Parse(strLogs); - - string strScopes = request.QueryString["scopes"]; - if (!string.IsNullOrEmpty(strScopes)) - scopes = bool.Parse(strScopes); - - string strApps = request.QueryString["apps"]; - if (!string.IsNullOrEmpty(strApps)) - apps = bool.Parse(strApps); - - string strStats = request.QueryString["stats"]; - if (!string.IsNullOrEmpty(strStats)) - stats = bool.Parse(strStats); - - string strZones = request.QueryString["zones"]; - if (!string.IsNullOrEmpty(strZones)) - zones = bool.Parse(strZones); - - string strAllowedZones = request.QueryString["allowedZones"]; - if (!string.IsNullOrEmpty(strAllowedZones)) - allowedZones = bool.Parse(strAllowedZones); - - string strBlockedZones = request.QueryString["blockedZones"]; - if (!string.IsNullOrEmpty(strBlockedZones)) - blockedZones = bool.Parse(strBlockedZones); - - string strDnsSettings = request.QueryString["dnsSettings"]; - if (!string.IsNullOrEmpty(strDnsSettings)) - dnsSettings = bool.Parse(strDnsSettings); - - string strAuthConfig = request.QueryString["authConfig"]; - if (!string.IsNullOrEmpty(strAuthConfig)) - authConfig = bool.Parse(strAuthConfig); - - string strLogSettings = request.QueryString["logSettings"]; - if (!string.IsNullOrEmpty(strLogSettings)) - logSettings = bool.Parse(strLogSettings); - - string strDeleteExistingFiles = request.QueryString["deleteExistingFiles"]; - if (!string.IsNullOrEmpty(strDeleteExistingFiles)) - deleteExistingFiles = bool.Parse(strDeleteExistingFiles); - - #region skip to content - - int crlfCount = 0; - int byteRead; - - while (crlfCount != 4) - { - byteRead = await request.InputStream.ReadByteValueAsync(); - switch (byteRead) - { - case 13: //CR - case 10: //LF - crlfCount++; - break; - - default: - crlfCount = 0; - break; - } - } - - #endregion - - //write to temp file - string tmpFile = Path.GetTempFileName(); - try - { - using (FileStream fS = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) - { - await request.InputStream.CopyToAsync(fS); - - fS.Position = 0; - using (ZipArchive backupZip = new ZipArchive(fS, ZipArchiveMode.Read, false, Encoding.UTF8)) - { - UserSession session = GetSession(request); - - if (logSettings || logs) - { - //stop logging - _log.StopLogging(); - } - - try - { - if (logSettings) - { - ZipArchiveEntry entry = backupZip.GetEntry("log.config"); - if (entry != null) - entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true); - - //reload config - _log.LoadConfig(); - } - - if (logs) - { - if (deleteExistingFiles) - { - //delete existing log files - string[] logFiles = Directory.GetFiles(_log.LogFolderAbsolutePath, "*.log", SearchOption.TopDirectoryOnly); - foreach (string logFile in logFiles) - { - File.Delete(logFile); - } - } - - //extract log files from backup - foreach (ZipArchiveEntry entry in backupZip.Entries) - { - if (entry.FullName.StartsWith("logs/")) - entry.ExtractToFile(Path.Combine(_log.LogFolderAbsolutePath, entry.Name), true); - } - } - } - finally - { - if (logSettings || logs) - { - //start logging - if (_log.EnableLogging) - _log.StartLogging(); - } - } - - if (authConfig) - { - ZipArchiveEntry entry = backupZip.GetEntry("auth.config"); - if (entry != null) - entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true); - - //reload auth config - _authManager.LoadConfigFile(session); - } - - if (blockLists) - { - if (deleteExistingFiles) - { - //delete existing block list files - string[] blockListFiles = Directory.GetFiles(Path.Combine(_configFolder, "blocklists"), "*", SearchOption.TopDirectoryOnly); - foreach (string blockListFile in blockListFiles) - { - File.Delete(blockListFile); - } - } - - //extract block list files from backup - foreach (ZipArchiveEntry entry in backupZip.Entries) - { - if (entry.FullName.StartsWith("blocklists/")) - entry.ExtractToFile(Path.Combine(_configFolder, "blocklists", entry.Name), true); - } - } - - if (dnsSettings) - { - ZipArchiveEntry entry = backupZip.GetEntry("dns.config"); - if (entry != null) - entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true); - - //reload settings and block list zone - LoadConfigFile(); - - if ((_blockListUpdateIntervalHours > 0) && (_dnsServer.BlockListZoneManager.BlockListUrls.Count > 0)) - { - ThreadPool.QueueUserWorkItem(delegate (object state) - { - try - { - _dnsServer.BlockListZoneManager.LoadBlockLists(); - StartBlockListUpdateTimer(); - } - catch (Exception ex) - { - _log.Write(ex); - } - }); - } - else - { - StopBlockListUpdateTimer(); - } - } - - if (apps) - { - //unload apps - _dnsServer.DnsApplicationManager.UnloadAllApplications(); - - if (deleteExistingFiles) - { - //delete existing apps - string appFolder = Path.Combine(_configFolder, "apps"); - if (Directory.Exists(appFolder)) - Directory.Delete(appFolder, true); - - //create apps folder - Directory.CreateDirectory(appFolder); - } - - //extract apps files from backup - foreach (ZipArchiveEntry entry in backupZip.Entries) - { - if (entry.FullName.StartsWith("apps/")) - { - string entryPath = entry.FullName; - - if (Path.DirectorySeparatorChar != '/') - entryPath = entryPath.Replace('/', '\\'); - - string filePath = Path.Combine(_configFolder, entryPath); - - Directory.CreateDirectory(Path.GetDirectoryName(filePath)); - - entry.ExtractToFile(filePath, true); - } - } - - //reload apps - _dnsServer.DnsApplicationManager.LoadAllApplications(); - } - - if (zones) - { - if (deleteExistingFiles) - { - //delete existing zone files - string[] zoneFiles = Directory.GetFiles(Path.Combine(_configFolder, "zones"), "*.zone", SearchOption.TopDirectoryOnly); - foreach (string zoneFile in zoneFiles) - { - File.Delete(zoneFile); - } - } - - //extract zone files from backup - foreach (ZipArchiveEntry entry in backupZip.Entries) - { - if (entry.FullName.StartsWith("zones/")) - entry.ExtractToFile(Path.Combine(_configFolder, "zones", entry.Name), true); - } - - //reload zones - _dnsServer.AuthZoneManager.LoadAllZoneFiles(); - InspectAndFixZonePermissions(); - } - - if (allowedZones) - { - ZipArchiveEntry entry = backupZip.GetEntry("allowed.config"); - if (entry == null) - { - string fileName = Path.Combine(_configFolder, "allowed.config"); - if (File.Exists(fileName)) - File.Delete(fileName); - } - else - { - entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true); - } - - //reload - _dnsServer.AllowedZoneManager.LoadAllowedZoneFile(); - } - - if (blockedZones) - { - ZipArchiveEntry entry = backupZip.GetEntry("blocked.config"); - if (entry == null) - { - string fileName = Path.Combine(_configFolder, "allowed.config"); - if (File.Exists(fileName)) - File.Delete(fileName); - } - else - { - entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true); - } - - //reload - _dnsServer.BlockedZoneManager.LoadBlockedZoneFile(); - } - - if (scopes) - { - //stop dhcp server - _dhcpServer.Stop(); - - try - { - if (deleteExistingFiles) - { - //delete existing scope files - string[] scopeFiles = Directory.GetFiles(Path.Combine(_configFolder, "scopes"), "*.scope", SearchOption.TopDirectoryOnly); - foreach (string scopeFile in scopeFiles) - { - File.Delete(scopeFile); - } - } - - //extract scope files from backup - foreach (ZipArchiveEntry entry in backupZip.Entries) - { - if (entry.FullName.StartsWith("scopes/")) - entry.ExtractToFile(Path.Combine(_configFolder, "scopes", entry.Name), true); - } - } - finally - { - //start dhcp server - _dhcpServer.Start(); - } - } - - if (stats) - { - if (deleteExistingFiles) - { - //delete existing stats files - string[] hourlyStatsFiles = Directory.GetFiles(Path.Combine(_configFolder, "stats"), "*.stat", SearchOption.TopDirectoryOnly); - foreach (string hourlyStatsFile in hourlyStatsFiles) - { - File.Delete(hourlyStatsFile); - } - - string[] dailyStatsFiles = Directory.GetFiles(Path.Combine(_configFolder, "stats"), "*.dstat", SearchOption.TopDirectoryOnly); - foreach (string dailyStatsFile in dailyStatsFiles) - { - File.Delete(dailyStatsFile); - } - } - - //extract stats files from backup - foreach (ZipArchiveEntry entry in backupZip.Entries) - { - if (entry.FullName.StartsWith("stats/")) - entry.ExtractToFile(Path.Combine(_configFolder, "stats", entry.Name), true); - } - - //reload stats - _dnsServer.StatsManager.ReloadStats(); - } - - _log.Write(GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Settings backup zip file was restored."); - } - } - } - finally - { - try - { - File.Delete(tmpFile); - } - catch (Exception ex) - { - _log.Write(ex); - } - } - - if (dnsSettings) - RestartService(true, true); - - GetDnsSettings(jsonWriter); - } - - private void ForceUpdateBlockLists(HttpListenerRequest request) - { - ForceUpdateBlockLists(); - _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).User.Username + "] Block list update was triggered."); - } - - private void TemporaryDisableBlocking(HttpListenerRequest request, Utf8JsonWriter jsonWriter) - { - string strMinutes = request.QueryString["minutes"]; - if (string.IsNullOrEmpty(strMinutes)) - throw new DnsWebServiceException("Parameter 'minutes' missing."); - - int minutes = int.Parse(strMinutes); - - Timer temporaryDisableBlockingTimer = _temporaryDisableBlockingTimer; - if (temporaryDisableBlockingTimer is not null) - temporaryDisableBlockingTimer.Dispose(); - - Timer newTemporaryDisableBlockingTimer = new Timer(delegate (object state) - { - try - { - _dnsServer.EnableBlocking = true; - _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).User.Username + "] Blocking was enabled after " + minutes + " minute(s) being temporarily disabled."); - } - catch (Exception ex) - { - _log.Write(ex); - } - }); - - Timer originalTimer = Interlocked.CompareExchange(ref _temporaryDisableBlockingTimer, newTemporaryDisableBlockingTimer, temporaryDisableBlockingTimer); - if (ReferenceEquals(originalTimer, temporaryDisableBlockingTimer)) - { - newTemporaryDisableBlockingTimer.Change(minutes * 60 * 1000, Timeout.Infinite); - _dnsServer.EnableBlocking = false; - _temporaryDisableBlockingTill = DateTime.UtcNow.AddMinutes(minutes); - - _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).User.Username + "] Blocking was temporarily disabled for " + minutes + " minute(s)."); - } - else - { - newTemporaryDisableBlockingTimer.Dispose(); - } - - jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); - } - - #endregion - #region dns client api private async Task ResolveQueryAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -3530,64 +1762,9 @@ namespace DnsServerCore #endregion - #region block list - - private void ForceUpdateBlockLists() - { - Task.Run(async delegate () - { - if (await _dnsServer.BlockListZoneManager.UpdateBlockListsAsync()) - { - //block lists were updated - //save last updated on time - _blockListLastUpdatedOn = DateTime.UtcNow; - SaveConfigFile(); - } - }); - } - - private void StartBlockListUpdateTimer() - { - if (_blockListUpdateTimer is null) - { - _blockListUpdateTimer = new Timer(async delegate (object state) - { - try - { - if (DateTime.UtcNow > _blockListLastUpdatedOn.AddHours(_blockListUpdateIntervalHours)) - { - if (await _dnsServer.BlockListZoneManager.UpdateBlockListsAsync()) - { - //block lists were updated - //save last updated on time - _blockListLastUpdatedOn = DateTime.UtcNow; - SaveConfigFile(); - } - } - } - catch (Exception ex) - { - _log.Write("DNS Server encountered an error while updating block lists.\r\n" + ex.ToString()); - } - - }, null, BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL, BLOCK_LIST_UPDATE_TIMER_PERIODIC_INTERVAL); - } - } - - private void StopBlockListUpdateTimer() - { - if (_blockListUpdateTimer is not null) - { - _blockListUpdateTimer.Dispose(); - _blockListUpdateTimer = null; - } - } - - #endregion - #region tls - private void StartTlsCertificateUpdateTimer() + internal void StartTlsCertificateUpdateTimer() { if (_tlsCertificateUpdateTimer == null) { @@ -3627,7 +1804,7 @@ namespace DnsServerCore } } - private void StopTlsCertificateUpdateTimer() + internal void StopTlsCertificateUpdateTimer() { if (_tlsCertificateUpdateTimer != null) { @@ -3636,7 +1813,7 @@ namespace DnsServerCore } } - private void LoadWebServiceTlsCertificate(string tlsCertificatePath, string tlsCertificatePassword) + internal void LoadWebServiceTlsCertificate(string tlsCertificatePath, string tlsCertificatePassword) { FileInfo fileInfo = new FileInfo(tlsCertificatePath); @@ -3654,7 +1831,7 @@ namespace DnsServerCore _log.Write("Web Service TLS certificate was loaded: " + tlsCertificatePath); } - private void LoadDnsTlsCertificate(string tlsCertificatePath, string tlsCertificatePassword) + internal void LoadDnsTlsCertificate(string tlsCertificatePath, string tlsCertificatePassword) { FileInfo fileInfo = new FileInfo(tlsCertificatePath); @@ -3672,11 +1849,47 @@ namespace DnsServerCore _log.Write("DNS Server TLS certificate was loaded: " + tlsCertificatePath); } + internal void SelfSignedCertCheck(bool generateNew, bool throwException) + { + string selfSignedCertificateFilePath = Path.Combine(_configFolder, "cert.pfx"); + + if (_webServiceUseSelfSignedTlsCertificate) + { + if (generateNew || !File.Exists(selfSignedCertificateFilePath)) + { + RSA rsa = RSA.Create(2048); + CertificateRequest req = new CertificateRequest("cn=" + _dnsServer.ServerDomain, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(5)); + + File.WriteAllBytes(selfSignedCertificateFilePath, cert.Export(X509ContentType.Pkcs12, null as string)); + } + + if (_webServiceEnableTls && string.IsNullOrEmpty(_webServiceTlsCertificatePath)) + { + try + { + LoadWebServiceTlsCertificate(selfSignedCertificateFilePath, null); + } + catch (Exception ex) + { + _log.Write("DNS Server encountered an error while loading self signed Web Service TLS certificate: " + selfSignedCertificateFilePath + "\r\n" + ex.ToString()); + + if (throwException) + throw; + } + } + } + else + { + File.Delete(selfSignedCertificateFilePath); + } + } + #endregion #region config - private void LoadConfigFile() + internal void LoadConfigFile() { string configFile = Path.Combine(_configFolder, "dns.config"); @@ -3858,7 +2071,7 @@ namespace DnsServerCore } } - private void SaveConfigFile() + internal void SaveConfigFile() { string configFile = Path.Combine(_configFolder, "dns.config"); @@ -3879,7 +2092,7 @@ namespace DnsServerCore _log.Write("DNS Server config file was saved: " + configFile); } - private void InspectAndFixZonePermissions() + internal void InspectAndFixZonePermissions() { Permission permission = _authManager.GetPermission(PermissionSection.Zones); IReadOnlyDictionary subItemPermissions = permission.SubItemPermissions; @@ -4179,8 +2392,8 @@ namespace DnsServerCore _dnsServer.BlockListZoneManager.BlockListUrls.Add(new Uri(listUrl)); } - _blockListUpdateIntervalHours = bR.ReadInt32(); - _blockListLastUpdatedOn = bR.ReadDateTime(); + _settingsApi.BlockListUpdateIntervalHours = bR.ReadInt32(); + _settingsApi.BlockListLastUpdatedOn = bR.ReadDateTime(); } //proxy & forwarders @@ -4601,17 +2814,17 @@ namespace DnsServerCore _dnsServer.BlockListZoneManager.BlockListUrls.Add(new Uri(listUrl)); } - _blockListLastUpdatedOn = bR.ReadDateTime(); + _settingsApi.BlockListLastUpdatedOn = bR.ReadDateTime(); if (version >= 13) - _blockListUpdateIntervalHours = bR.ReadInt32(); + _settingsApi.BlockListUpdateIntervalHours = bR.ReadInt32(); } else { _dnsServer.BlockListZoneManager.AllowListUrls.Clear(); _dnsServer.BlockListZoneManager.BlockListUrls.Clear(); - _blockListLastUpdatedOn = DateTime.MinValue; - _blockListUpdateIntervalHours = 24; + _settingsApi.BlockListLastUpdatedOn = DateTime.MinValue; + _settingsApi.BlockListUpdateIntervalHours = 24; } if (version >= 11) @@ -4972,8 +3185,8 @@ namespace DnsServerCore foreach (Uri blockListUrl in _dnsServer.BlockListZoneManager.BlockListUrls) bW.WriteShortString(blockListUrl.AbsoluteUri); - bW.Write(_blockListUpdateIntervalHours); - bW.Write(_blockListLastUpdatedOn); + bW.Write(_settingsApi.BlockListUpdateIntervalHours); + bW.Write(_settingsApi.BlockListLastUpdatedOn); } //proxy & forwarders @@ -5035,7 +3248,7 @@ namespace DnsServerCore #region web service start stop - private void StartDnsWebService() + internal void StartDnsWebService() { int acceptTasks = Math.Max(1, Environment.ProcessorCount); @@ -5167,7 +3380,7 @@ namespace DnsServerCore } } - private void StopDnsWebService() + internal void StopDnsWebService() { _webService.Stop(); @@ -5189,7 +3402,7 @@ namespace DnsServerCore public void Start() { if (_disposed) - throw new ObjectDisposedException("WebService"); + throw new ObjectDisposedException(nameof(DnsWebService)); if (_state != ServiceState.Stopped) throw new InvalidOperationException("Web Service is already running."); @@ -5243,14 +3456,14 @@ namespace DnsServerCore _dnsServer.BlockedZoneManager.LoadBlockedZoneFile(); //load block list zone async - if ((_blockListUpdateIntervalHours > 0) && (_dnsServer.BlockListZoneManager.BlockListUrls.Count > 0)) + if ((_settingsApi.BlockListUpdateIntervalHours > 0) && (_dnsServer.BlockListZoneManager.BlockListUrls.Count > 0)) { ThreadPool.QueueUserWorkItem(delegate (object state) { try { _dnsServer.BlockListZoneManager.LoadBlockLists(); - StartBlockListUpdateTimer(); + _settingsApi.StartBlockListUpdateTimer(); } catch (Exception ex) { @@ -5290,12 +3503,10 @@ namespace DnsServerCore _dnsServer.Dispose(); _dhcpServer.Dispose(); - StopBlockListUpdateTimer(); + _settingsApi.StopBlockListUpdateTimer(); + _settingsApi.StopTemporaryDisableBlockingTimer(); StopTlsCertificateUpdateTimer(); - if (_temporaryDisableBlockingTimer is not null) - _temporaryDisableBlockingTimer.Dispose(); - _state = ServiceState.Stopped; _log.Write("DNS Server (v" + _currentVersion.ToString() + ") was stopped successfully."); @@ -5311,24 +3522,6 @@ namespace DnsServerCore #region properties - internal LogManager Log - { get { return _log; } } - - internal AuthManager AuthManager - { get { return _authManager; } } - - internal WebServiceZonesApi ZonesApi - { get { return _zonesApi; } } - - internal DnsServer DnsServer - { get { return _dnsServer; } } - - internal DhcpServer DhcpServer - { get { return _dhcpServer; } } - - internal Version ServerVersion - { get { return _currentVersion; } } - public string ConfigFolder { get { return _configFolder; } } diff --git a/DnsServerCore/WebServiceSettingsApi.cs b/DnsServerCore/WebServiceSettingsApi.cs new file mode 100644 index 00000000..7fec9519 --- /dev/null +++ b/DnsServerCore/WebServiceSettingsApi.cs @@ -0,0 +1,1892 @@ +/* +Technitium DNS Server +Copyright (C) 2022 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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using DnsServerCore.Auth; +using DnsServerCore.Dns; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using TechnitiumLibrary.IO; +using TechnitiumLibrary.Net; +using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.ResourceRecords; +using TechnitiumLibrary.Net.Proxy; + +namespace DnsServerCore +{ + sealed class WebServiceSettingsApi : IDisposable + { + #region variables + + readonly static RandomNumberGenerator _rng = RandomNumberGenerator.Create(); + + readonly DnsWebService _dnsWebService; + + Timer _blockListUpdateTimer; + DateTime _blockListLastUpdatedOn; + int _blockListUpdateIntervalHours = 24; + const int BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL = 5000; + const int BLOCK_LIST_UPDATE_TIMER_PERIODIC_INTERVAL = 900000; + + Timer _temporaryDisableBlockingTimer; + DateTime _temporaryDisableBlockingTill; + + #endregion + + #region constructor + + public WebServiceSettingsApi(DnsWebService dnsWebService) + { + _dnsWebService = dnsWebService; + } + + #endregion + + #region IDisposable + + bool _disposed; + + public void Dispose() + { + if (_disposed) + return; + + if (_blockListUpdateTimer is not null) + _blockListUpdateTimer.Dispose(); + + if (_temporaryDisableBlockingTimer is not null) + _temporaryDisableBlockingTimer.Dispose(); + + _disposed = true; + } + + #endregion + + #region block list + + private void ForceUpdateBlockLists() + { + Task.Run(async delegate () + { + if (await _dnsWebService._dnsServer.BlockListZoneManager.UpdateBlockListsAsync()) + { + //block lists were updated + //save last updated on time + _blockListLastUpdatedOn = DateTime.UtcNow; + _dnsWebService.SaveConfigFile(); + } + }); + } + + public void StartBlockListUpdateTimer() + { + if (_blockListUpdateTimer is null) + { + _blockListUpdateTimer = new Timer(async delegate (object state) + { + try + { + if (DateTime.UtcNow > _blockListLastUpdatedOn.AddHours(_blockListUpdateIntervalHours)) + { + if (await _dnsWebService._dnsServer.BlockListZoneManager.UpdateBlockListsAsync()) + { + //block lists were updated + //save last updated on time + _blockListLastUpdatedOn = DateTime.UtcNow; + _dnsWebService.SaveConfigFile(); + } + } + } + catch (Exception ex) + { + _dnsWebService._log.Write("DNS Server encountered an error while updating block lists.\r\n" + ex.ToString()); + } + + }, null, BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL, BLOCK_LIST_UPDATE_TIMER_PERIODIC_INTERVAL); + } + } + + public void StopBlockListUpdateTimer() + { + if (_blockListUpdateTimer is not null) + { + _blockListUpdateTimer.Dispose(); + _blockListUpdateTimer = null; + } + } + + public void StopTemporaryDisableBlockingTimer() + { + Timer temporaryDisableBlockingTimer = _temporaryDisableBlockingTimer; + if (temporaryDisableBlockingTimer is not null) + temporaryDisableBlockingTimer.Dispose(); + } + + #endregion + + #region private + + private void RestartService(bool restartDnsService, bool restartWebService) + { + if (restartDnsService) + { + _ = Task.Run(delegate () + { + _dnsWebService._log.Write("Attempting to restart DNS service."); + + try + { + _dnsWebService._dnsServer.Stop(); + _dnsWebService._dnsServer.Start(); + + _dnsWebService._log.Write("DNS service was restarted successfully."); + } + catch (Exception ex) + { + _dnsWebService._log.Write("Failed to restart DNS service."); + _dnsWebService._log.Write(ex); + } + }); + } + + if (restartWebService) + { + _ = Task.Run(async delegate () + { + await Task.Delay(2000); //wait for this HTTP response to be delivered before stopping web server + + _dnsWebService._log.Write("Attempting to restart web service."); + + try + { + _dnsWebService.StopDnsWebService(); + _dnsWebService.StartDnsWebService(); + + _dnsWebService._log.Write("Web service was restarted successfully."); + } + catch (Exception ex) + { + _dnsWebService._log.Write("Failed to restart web service."); + _dnsWebService._log.Write(ex); + } + }); + } + } + + private static async Task CreateBackupEntryFromFileAsync(ZipArchive backupZip, string sourceFileName, string entryName) + { + using (FileStream fS = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + ZipArchiveEntry entry = backupZip.CreateEntry(entryName); + + DateTime lastWrite = File.GetLastWriteTime(sourceFileName); + + // If file to be archived has an invalid last modified time, use the first datetime representable in the Zip timestamp format + // (midnight on January 1, 1980): + if (lastWrite.Year < 1980 || lastWrite.Year > 2107) + lastWrite = new DateTime(1980, 1, 1, 0, 0, 0); + + entry.LastWriteTime = lastWrite; + + using (Stream sE = entry.Open()) + { + await fS.CopyToAsync(sE); + } + } + } + + #endregion + + #region public + + public void GetDnsSettings(Utf8JsonWriter jsonWriter) + { + //general + jsonWriter.WriteString("version", _dnsWebService.GetServerVersion()); + jsonWriter.WriteString("dnsServerDomain", _dnsWebService._dnsServer.ServerDomain); + + jsonWriter.WritePropertyName("dnsServerLocalEndPoints"); + jsonWriter.WriteStartArray(); + + foreach (IPEndPoint localEP in _dnsWebService._dnsServer.LocalEndPoints) + jsonWriter.WriteStringValue(localEP.ToString()); + + jsonWriter.WriteEndArray(); + + jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService._zonesApi.DefaultRecordTtl); + jsonWriter.WriteBoolean("dnsAppsEnableAutomaticUpdate", _dnsWebService._appsApi.EnableAutomaticUpdate); + + jsonWriter.WriteBoolean("preferIPv6", _dnsWebService._dnsServer.PreferIPv6); + + jsonWriter.WriteNumber("udpPayloadSize", _dnsWebService._dnsServer.UdpPayloadSize); + + jsonWriter.WriteBoolean("dnssecValidation", _dnsWebService._dnsServer.DnssecValidation); + + jsonWriter.WriteBoolean("eDnsClientSubnet", _dnsWebService._dnsServer.EDnsClientSubnet); + jsonWriter.WriteNumber("eDnsClientSubnetIPv4PrefixLength", _dnsWebService._dnsServer.EDnsClientSubnetIPv4PrefixLength); + jsonWriter.WriteNumber("eDnsClientSubnetIPv6PrefixLength", _dnsWebService._dnsServer.EDnsClientSubnetIPv6PrefixLength); + + jsonWriter.WriteNumber("qpmLimitRequests", _dnsWebService._dnsServer.QpmLimitRequests); + jsonWriter.WriteNumber("qpmLimitErrors", _dnsWebService._dnsServer.QpmLimitErrors); + jsonWriter.WriteNumber("qpmLimitSampleMinutes", _dnsWebService._dnsServer.QpmLimitSampleMinutes); + jsonWriter.WriteNumber("qpmLimitIPv4PrefixLength", _dnsWebService._dnsServer.QpmLimitIPv4PrefixLength); + jsonWriter.WriteNumber("qpmLimitIPv6PrefixLength", _dnsWebService._dnsServer.QpmLimitIPv6PrefixLength); + + jsonWriter.WriteNumber("clientTimeout", _dnsWebService._dnsServer.ClientTimeout); + jsonWriter.WriteNumber("tcpSendTimeout", _dnsWebService._dnsServer.TcpSendTimeout); + jsonWriter.WriteNumber("tcpReceiveTimeout", _dnsWebService._dnsServer.TcpReceiveTimeout); + + //web service + jsonWriter.WritePropertyName("webServiceLocalAddresses"); + jsonWriter.WriteStartArray(); + + foreach (IPAddress localAddress in _dnsWebService._webServiceLocalAddresses) + { + if (localAddress.AddressFamily == AddressFamily.InterNetworkV6) + jsonWriter.WriteStringValue("[" + localAddress.ToString() + "]"); + else + jsonWriter.WriteStringValue(localAddress.ToString()); + } + + jsonWriter.WriteEndArray(); + + jsonWriter.WriteNumber("webServiceHttpPort", _dnsWebService._webServiceHttpPort); + jsonWriter.WriteBoolean("webServiceEnableTls", _dnsWebService._webServiceEnableTls); + jsonWriter.WriteBoolean("webServiceHttpToTlsRedirect", _dnsWebService._webServiceHttpToTlsRedirect); + jsonWriter.WriteBoolean("webServiceUseSelfSignedTlsCertificate", _dnsWebService._webServiceUseSelfSignedTlsCertificate); + jsonWriter.WriteNumber("webServiceTlsPort", _dnsWebService._webServiceTlsPort); + jsonWriter.WriteString("webServiceTlsCertificatePath", _dnsWebService._webServiceTlsCertificatePath); + jsonWriter.WriteString("webServiceTlsCertificatePassword", "************"); + + //optional protocols + jsonWriter.WriteBoolean("enableDnsOverHttp", _dnsWebService._dnsServer.EnableDnsOverHttp); + jsonWriter.WriteBoolean("enableDnsOverTls", _dnsWebService._dnsServer.EnableDnsOverTls); + jsonWriter.WriteBoolean("enableDnsOverHttps", _dnsWebService._dnsServer.EnableDnsOverHttps); + jsonWriter.WriteString("dnsTlsCertificatePath", _dnsWebService._dnsTlsCertificatePath); + jsonWriter.WriteString("dnsTlsCertificatePassword", "************"); + + //tsig + jsonWriter.WritePropertyName("tsigKeys"); + { + jsonWriter.WriteStartArray(); + + if (_dnsWebService._dnsServer.TsigKeys is not null) + { + foreach (KeyValuePair tsigKey in _dnsWebService._dnsServer.TsigKeys) + { + jsonWriter.WriteStartObject(); + + jsonWriter.WriteString("keyName", tsigKey.Key); + jsonWriter.WriteString("sharedSecret", tsigKey.Value.SharedSecret); + jsonWriter.WriteString("algorithmName", tsigKey.Value.AlgorithmName); + + jsonWriter.WriteEndObject(); + } + } + + jsonWriter.WriteEndArray(); + } + + //recursion + jsonWriter.WriteString("recursion", _dnsWebService._dnsServer.Recursion.ToString()); + + jsonWriter.WritePropertyName("recursionDeniedNetworks"); + { + jsonWriter.WriteStartArray(); + + if (_dnsWebService._dnsServer.RecursionDeniedNetworks is not null) + { + foreach (NetworkAddress networkAddress in _dnsWebService._dnsServer.RecursionDeniedNetworks) + jsonWriter.WriteStringValue(networkAddress.ToString()); + } + + jsonWriter.WriteEndArray(); + } + + jsonWriter.WritePropertyName("recursionAllowedNetworks"); + { + jsonWriter.WriteStartArray(); + + if (_dnsWebService._dnsServer.RecursionAllowedNetworks is not null) + { + foreach (NetworkAddress networkAddress in _dnsWebService._dnsServer.RecursionAllowedNetworks) + jsonWriter.WriteStringValue(networkAddress.ToString()); + } + + jsonWriter.WriteEndArray(); + } + + jsonWriter.WriteBoolean("randomizeName", _dnsWebService._dnsServer.RandomizeName); + jsonWriter.WriteBoolean("qnameMinimization", _dnsWebService._dnsServer.QnameMinimization); + jsonWriter.WriteBoolean("nsRevalidation", _dnsWebService._dnsServer.NsRevalidation); + + jsonWriter.WriteNumber("resolverRetries", _dnsWebService._dnsServer.ResolverRetries); + jsonWriter.WriteNumber("resolverTimeout", _dnsWebService._dnsServer.ResolverTimeout); + jsonWriter.WriteNumber("resolverMaxStackCount", _dnsWebService._dnsServer.ResolverMaxStackCount); + + //cache + jsonWriter.WriteBoolean("serveStale", _dnsWebService._dnsServer.ServeStale); + jsonWriter.WriteNumber("serveStaleTtl", _dnsWebService._dnsServer.CacheZoneManager.ServeStaleTtl); + + jsonWriter.WriteNumber("cacheMaximumEntries", _dnsWebService._dnsServer.CacheZoneManager.MaximumEntries); + jsonWriter.WriteNumber("cacheMinimumRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.MinimumRecordTtl); + jsonWriter.WriteNumber("cacheMaximumRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.MaximumRecordTtl); + jsonWriter.WriteNumber("cacheNegativeRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.NegativeRecordTtl); + jsonWriter.WriteNumber("cacheFailureRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.FailureRecordTtl); + + jsonWriter.WriteNumber("cachePrefetchEligibility", _dnsWebService._dnsServer.CachePrefetchEligibility); + jsonWriter.WriteNumber("cachePrefetchTrigger", _dnsWebService._dnsServer.CachePrefetchTrigger); + jsonWriter.WriteNumber("cachePrefetchSampleIntervalInMinutes", _dnsWebService._dnsServer.CachePrefetchSampleIntervalInMinutes); + jsonWriter.WriteNumber("cachePrefetchSampleEligibilityHitsPerHour", _dnsWebService._dnsServer.CachePrefetchSampleEligibilityHitsPerHour); + + //blocking + jsonWriter.WriteBoolean("enableBlocking", _dnsWebService._dnsServer.EnableBlocking); + jsonWriter.WriteBoolean("allowTxtBlockingReport", _dnsWebService._dnsServer.AllowTxtBlockingReport); + + if (!_dnsWebService._dnsServer.EnableBlocking && (DateTime.UtcNow < _temporaryDisableBlockingTill)) + jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); + + jsonWriter.WriteString("blockingType", _dnsWebService._dnsServer.BlockingType.ToString()); + + jsonWriter.WritePropertyName("customBlockingAddresses"); + jsonWriter.WriteStartArray(); + + foreach (DnsARecordData record in _dnsWebService._dnsServer.CustomBlockingARecords) + jsonWriter.WriteStringValue(record.Address.ToString()); + + foreach (DnsAAAARecordData record in _dnsWebService._dnsServer.CustomBlockingAAAARecords) + jsonWriter.WriteStringValue(record.Address.ToString()); + + jsonWriter.WriteEndArray(); + + jsonWriter.WritePropertyName("blockListUrls"); + + if ((_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count == 0) && (_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count == 0)) + { + jsonWriter.WriteNullValue(); + } + else + { + jsonWriter.WriteStartArray(); + + foreach (Uri allowListUrl in _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls) + jsonWriter.WriteStringValue("!" + allowListUrl.AbsoluteUri); + + foreach (Uri blockListUrl in _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls) + jsonWriter.WriteStringValue(blockListUrl.AbsoluteUri); + + jsonWriter.WriteEndArray(); + } + + jsonWriter.WriteNumber("blockListUpdateIntervalHours", _blockListUpdateIntervalHours); + + if (_blockListUpdateTimer is not null) + { + DateTime blockListNextUpdatedOn = _blockListLastUpdatedOn.AddHours(_blockListUpdateIntervalHours); + + jsonWriter.WriteString("blockListNextUpdatedOn", blockListNextUpdatedOn); + } + + //proxy & forwarders + jsonWriter.WritePropertyName("proxy"); + if (_dnsWebService._dnsServer.Proxy == null) + { + jsonWriter.WriteNullValue(); + } + else + { + jsonWriter.WriteStartObject(); + + NetProxy proxy = _dnsWebService._dnsServer.Proxy; + + jsonWriter.WriteString("type", proxy.Type.ToString()); + jsonWriter.WriteString("address", proxy.Address); + jsonWriter.WriteNumber("port", proxy.Port); + + NetworkCredential credential = proxy.Credential; + if (credential != null) + { + jsonWriter.WriteString("username", credential.UserName); + jsonWriter.WriteString("password", credential.Password); + } + + jsonWriter.WritePropertyName("bypass"); + jsonWriter.WriteStartArray(); + + foreach (NetProxyBypassItem item in proxy.BypassList) + jsonWriter.WriteStringValue(item.Value); + + jsonWriter.WriteEndArray(); + + jsonWriter.WriteEndObject(); + } + + jsonWriter.WritePropertyName("forwarders"); + + DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; + + if (_dnsWebService._dnsServer.Forwarders == null) + { + jsonWriter.WriteNullValue(); + } + else + { + forwarderProtocol = _dnsWebService._dnsServer.Forwarders[0].Protocol; + + jsonWriter.WriteStartArray(); + + foreach (NameServerAddress forwarder in _dnsWebService._dnsServer.Forwarders) + jsonWriter.WriteStringValue(forwarder.OriginalAddress); + + jsonWriter.WriteEndArray(); + } + + jsonWriter.WriteString("forwarderProtocol", forwarderProtocol.ToString()); + + jsonWriter.WriteNumber("forwarderRetries", _dnsWebService._dnsServer.ForwarderRetries); + jsonWriter.WriteNumber("forwarderTimeout", _dnsWebService._dnsServer.ForwarderTimeout); + jsonWriter.WriteNumber("forwarderConcurrency", _dnsWebService._dnsServer.ForwarderConcurrency); + + //logging + jsonWriter.WriteBoolean("enableLogging", _dnsWebService._log.EnableLogging); + jsonWriter.WriteBoolean("logQueries", _dnsWebService._dnsServer.QueryLogManager != null); + jsonWriter.WriteBoolean("useLocalTime", _dnsWebService._log.UseLocalTime); + jsonWriter.WriteString("logFolder", _dnsWebService._log.LogFolder); + jsonWriter.WriteNumber("maxLogFileDays", _dnsWebService._log.MaxLogFileDays); + jsonWriter.WriteNumber("maxStatFileDays", _dnsWebService._dnsServer.StatsManager.MaxStatFileDays); + } + + public void SetDnsSettings(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + { + bool serverDomainChanged = false; + bool restartDnsService = false; + bool restartWebService = false; + int oldWebServiceHttpPort = _dnsWebService._webServiceHttpPort; + + //general + string strDnsServerDomain = request.QueryString["dnsServerDomain"]; + if (!string.IsNullOrEmpty(strDnsServerDomain)) + { + serverDomainChanged = !_dnsWebService._dnsServer.ServerDomain.Equals(strDnsServerDomain, StringComparison.OrdinalIgnoreCase); + _dnsWebService._dnsServer.ServerDomain = strDnsServerDomain; + } + + string strDnsServerLocalEndPoints = request.QueryString["dnsServerLocalEndPoints"]; + if (strDnsServerLocalEndPoints != null) + { + if (string.IsNullOrEmpty(strDnsServerLocalEndPoints)) + strDnsServerLocalEndPoints = "0.0.0.0:53,[::]:53"; + + string[] strLocalEndPoints = strDnsServerLocalEndPoints.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + List localEndPoints = new List(strLocalEndPoints.Length); + + for (int i = 0; i < strLocalEndPoints.Length; i++) + { + NameServerAddress nameServer = new NameServerAddress(strLocalEndPoints[i]); + if (nameServer.IPEndPoint != null) + localEndPoints.Add(nameServer.IPEndPoint); + } + + if (localEndPoints.Count > 0) + { + if (_dnsWebService._dnsServer.LocalEndPoints.Count != localEndPoints.Count) + { + restartDnsService = true; + } + else + { + foreach (IPEndPoint currentLocalEP in _dnsWebService._dnsServer.LocalEndPoints) + { + if (!localEndPoints.Contains(currentLocalEP)) + { + restartDnsService = true; + break; + } + } + } + + _dnsWebService._dnsServer.LocalEndPoints = localEndPoints; + } + } + + string strDefaultRecordTtl = request.QueryString["defaultRecordTtl"]; + if (!string.IsNullOrEmpty(strDefaultRecordTtl)) + _dnsWebService._zonesApi.DefaultRecordTtl = uint.Parse(strDefaultRecordTtl); + + string strDnsAppsEnableAutomaticUpdate = request.QueryString["dnsAppsEnableAutomaticUpdate"]; + if (!string.IsNullOrEmpty(strDnsAppsEnableAutomaticUpdate)) + _dnsWebService._appsApi.EnableAutomaticUpdate = bool.Parse(strDnsAppsEnableAutomaticUpdate); + + string strPreferIPv6 = request.QueryString["preferIPv6"]; + if (!string.IsNullOrEmpty(strPreferIPv6)) + _dnsWebService._dnsServer.PreferIPv6 = bool.Parse(strPreferIPv6); + + string strUdpPayloadSize = request.QueryString["udpPayloadSize"]; + if (!string.IsNullOrEmpty(strUdpPayloadSize)) + _dnsWebService._dnsServer.UdpPayloadSize = ushort.Parse(strUdpPayloadSize); + + string strDnssecValidation = request.QueryString["dnssecValidation"]; + if (!string.IsNullOrEmpty(strDnssecValidation)) + _dnsWebService._dnsServer.DnssecValidation = bool.Parse(strDnssecValidation); + + string strEDnsClientSubnet = request.QueryString["eDnsClientSubnet"]; + if (!string.IsNullOrEmpty(strEDnsClientSubnet)) + _dnsWebService._dnsServer.EDnsClientSubnet = bool.Parse(strEDnsClientSubnet); + + string strEDnsClientSubnetIPv4PrefixLength = request.QueryString["eDnsClientSubnetIPv4PrefixLength"]; + if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv4PrefixLength)) + _dnsWebService._dnsServer.EDnsClientSubnetIPv4PrefixLength = byte.Parse(strEDnsClientSubnetIPv4PrefixLength); + + string strEDnsClientSubnetIPv6PrefixLength = request.QueryString["eDnsClientSubnetIPv6PrefixLength"]; + if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv6PrefixLength)) + _dnsWebService._dnsServer.EDnsClientSubnetIPv6PrefixLength = byte.Parse(strEDnsClientSubnetIPv6PrefixLength); + + string strQpmLimitRequests = request.QueryString["qpmLimitRequests"]; + if (!string.IsNullOrEmpty(strQpmLimitRequests)) + _dnsWebService._dnsServer.QpmLimitRequests = int.Parse(strQpmLimitRequests); + + string strQpmLimitErrors = request.QueryString["qpmLimitErrors"]; + if (!string.IsNullOrEmpty(strQpmLimitErrors)) + _dnsWebService._dnsServer.QpmLimitErrors = int.Parse(strQpmLimitErrors); + + string strQpmLimitSampleMinutes = request.QueryString["qpmLimitSampleMinutes"]; + if (!string.IsNullOrEmpty(strQpmLimitSampleMinutes)) + _dnsWebService._dnsServer.QpmLimitSampleMinutes = int.Parse(strQpmLimitSampleMinutes); + + string strQpmLimitIPv4PrefixLength = request.QueryString["qpmLimitIPv4PrefixLength"]; + if (!string.IsNullOrEmpty(strQpmLimitIPv4PrefixLength)) + _dnsWebService._dnsServer.QpmLimitIPv4PrefixLength = int.Parse(strQpmLimitIPv4PrefixLength); + + string strQpmLimitIPv6PrefixLength = request.QueryString["qpmLimitIPv6PrefixLength"]; + if (!string.IsNullOrEmpty(strQpmLimitIPv6PrefixLength)) + _dnsWebService._dnsServer.QpmLimitIPv6PrefixLength = int.Parse(strQpmLimitIPv6PrefixLength); + + string strClientTimeout = request.QueryString["clientTimeout"]; + if (!string.IsNullOrEmpty(strClientTimeout)) + _dnsWebService._dnsServer.ClientTimeout = int.Parse(strClientTimeout); + + string strTcpSendTimeout = request.QueryString["tcpSendTimeout"]; + if (!string.IsNullOrEmpty(strTcpSendTimeout)) + _dnsWebService._dnsServer.TcpSendTimeout = int.Parse(strTcpSendTimeout); + + string strTcpReceiveTimeout = request.QueryString["tcpReceiveTimeout"]; + if (!string.IsNullOrEmpty(strTcpReceiveTimeout)) + _dnsWebService._dnsServer.TcpReceiveTimeout = int.Parse(strTcpReceiveTimeout); + + //web service + string strWebServiceLocalAddresses = request.QueryString["webServiceLocalAddresses"]; + if (strWebServiceLocalAddresses != null) + { + if (string.IsNullOrEmpty(strWebServiceLocalAddresses)) + strWebServiceLocalAddresses = "0.0.0.0,[::]"; + + string[] strLocalAddresses = strWebServiceLocalAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + List localAddresses = new List(strLocalAddresses.Length); + + for (int i = 0; i < strLocalAddresses.Length; i++) + { + if (IPAddress.TryParse(strLocalAddresses[i], out IPAddress localAddress)) + localAddresses.Add(localAddress); + } + + if (localAddresses.Count > 0) + { + if (_dnsWebService._webServiceLocalAddresses.Count != localAddresses.Count) + { + restartWebService = true; + } + else + { + foreach (IPAddress currentlocalAddress in _dnsWebService._webServiceLocalAddresses) + { + if (!localAddresses.Contains(currentlocalAddress)) + { + restartWebService = true; + break; + } + } + } + + _dnsWebService._webServiceLocalAddresses = localAddresses; + } + } + + string strWebServiceHttpPort = request.QueryString["webServiceHttpPort"]; + if (!string.IsNullOrEmpty(strWebServiceHttpPort)) + { + _dnsWebService._webServiceHttpPort = int.Parse(strWebServiceHttpPort); + + if (oldWebServiceHttpPort != _dnsWebService._webServiceHttpPort) + restartWebService = true; + } + + string strWebServiceEnableTls = request.QueryString["webServiceEnableTls"]; + if (!string.IsNullOrEmpty(strWebServiceEnableTls)) + { + bool oldWebServiceEnableTls = _dnsWebService._webServiceEnableTls; + + _dnsWebService._webServiceEnableTls = bool.Parse(strWebServiceEnableTls); + + if (oldWebServiceEnableTls != _dnsWebService._webServiceEnableTls) + restartWebService = true; + } + + string strWebServiceHttpToTlsRedirect = request.QueryString["webServiceHttpToTlsRedirect"]; + if (!string.IsNullOrEmpty(strWebServiceHttpToTlsRedirect)) + _dnsWebService._webServiceHttpToTlsRedirect = bool.Parse(strWebServiceHttpToTlsRedirect); + + string strWebServiceUseSelfSignedTlsCertificate = request.QueryString["webServiceUseSelfSignedTlsCertificate"]; + if (!string.IsNullOrEmpty(strWebServiceUseSelfSignedTlsCertificate)) + _dnsWebService._webServiceUseSelfSignedTlsCertificate = bool.Parse(strWebServiceUseSelfSignedTlsCertificate); + + string strWebServiceTlsPort = request.QueryString["webServiceTlsPort"]; + if (!string.IsNullOrEmpty(strWebServiceTlsPort)) + { + int oldWebServiceTlsPort = _dnsWebService._webServiceTlsPort; + + _dnsWebService._webServiceTlsPort = int.Parse(strWebServiceTlsPort); + + if (oldWebServiceTlsPort != _dnsWebService._webServiceTlsPort) + restartWebService = true; + } + + string strWebServiceTlsCertificatePath = request.QueryString["webServiceTlsCertificatePath"]; + string strWebServiceTlsCertificatePassword = request.QueryString["webServiceTlsCertificatePassword"]; + if (string.IsNullOrEmpty(strWebServiceTlsCertificatePath)) + { + _dnsWebService._webServiceTlsCertificatePath = null; + _dnsWebService._webServiceTlsCertificatePassword = ""; + } + else + { + if (strWebServiceTlsCertificatePassword == "************") + strWebServiceTlsCertificatePassword = _dnsWebService._webServiceTlsCertificatePassword; + + if ((strWebServiceTlsCertificatePath != _dnsWebService._webServiceTlsCertificatePath) || (strWebServiceTlsCertificatePassword != _dnsWebService._webServiceTlsCertificatePassword)) + { + _dnsWebService.LoadWebServiceTlsCertificate(strWebServiceTlsCertificatePath, strWebServiceTlsCertificatePassword); + + _dnsWebService._webServiceTlsCertificatePath = strWebServiceTlsCertificatePath; + _dnsWebService._webServiceTlsCertificatePassword = strWebServiceTlsCertificatePassword; + + _dnsWebService.StartTlsCertificateUpdateTimer(); + } + } + + //optional protocols + string enableDnsOverHttp = request.QueryString["enableDnsOverHttp"]; + if (!string.IsNullOrEmpty(enableDnsOverHttp)) + { + bool oldEnableDnsOverHttp = _dnsWebService._dnsServer.EnableDnsOverHttp; + + _dnsWebService._dnsServer.EnableDnsOverHttp = bool.Parse(enableDnsOverHttp); + + if (oldEnableDnsOverHttp != _dnsWebService._dnsServer.EnableDnsOverHttp) + restartDnsService = true; + } + + string strEnableDnsOverTls = request.QueryString["enableDnsOverTls"]; + if (!string.IsNullOrEmpty(strEnableDnsOverTls)) + { + bool oldEnableDnsOverTls = _dnsWebService._dnsServer.EnableDnsOverTls; + + _dnsWebService._dnsServer.EnableDnsOverTls = bool.Parse(strEnableDnsOverTls); + + if (oldEnableDnsOverTls != _dnsWebService._dnsServer.EnableDnsOverTls) + restartDnsService = true; + } + + string strEnableDnsOverHttps = request.QueryString["enableDnsOverHttps"]; + if (!string.IsNullOrEmpty(strEnableDnsOverHttps)) + { + bool oldEnableDnsOverHttps = _dnsWebService._dnsServer.EnableDnsOverHttps; + + _dnsWebService._dnsServer.EnableDnsOverHttps = bool.Parse(strEnableDnsOverHttps); + + if (oldEnableDnsOverHttps != _dnsWebService._dnsServer.EnableDnsOverHttps) + restartDnsService = true; + } + + string strDnsTlsCertificatePath = request.QueryString["dnsTlsCertificatePath"]; + string strDnsTlsCertificatePassword = request.QueryString["dnsTlsCertificatePassword"]; + if (string.IsNullOrEmpty(strDnsTlsCertificatePath)) + { + _dnsWebService._dnsTlsCertificatePath = null; + _dnsWebService._dnsTlsCertificatePassword = ""; + } + else + { + if (strDnsTlsCertificatePassword == "************") + strDnsTlsCertificatePassword = _dnsWebService._dnsTlsCertificatePassword; + + if ((strDnsTlsCertificatePath != _dnsWebService._dnsTlsCertificatePath) || (strDnsTlsCertificatePassword != _dnsWebService._dnsTlsCertificatePassword)) + { + _dnsWebService.LoadDnsTlsCertificate(strDnsTlsCertificatePath, strDnsTlsCertificatePassword); + + _dnsWebService._dnsTlsCertificatePath = strDnsTlsCertificatePath; + _dnsWebService._dnsTlsCertificatePassword = strDnsTlsCertificatePassword; + + _dnsWebService.StartTlsCertificateUpdateTimer(); + } + } + + //tsig + string strTsigKeys = request.QueryString["tsigKeys"]; + if (!string.IsNullOrEmpty(strTsigKeys)) + { + if (strTsigKeys == "false") + { + _dnsWebService._dnsServer.TsigKeys = null; + } + else + { + string[] strTsigKeyParts = strTsigKeys.Split('|'); + Dictionary tsigKeys = new Dictionary(strTsigKeyParts.Length); + + for (int i = 0; i < strTsigKeyParts.Length; i += 3) + { + string keyName = strTsigKeyParts[i + 0].ToLower(); + string sharedSecret = strTsigKeyParts[i + 1]; + string algorithmName = strTsigKeyParts[i + 2]; + + if (sharedSecret.Length == 0) + { + byte[] key = new byte[32]; + _rng.GetBytes(key); + + tsigKeys.Add(keyName, new TsigKey(keyName, Convert.ToBase64String(key), algorithmName)); + } + else + { + tsigKeys.Add(keyName, new TsigKey(keyName, sharedSecret, algorithmName)); + } + } + + _dnsWebService._dnsServer.TsigKeys = tsigKeys; + } + } + + //recursion + string strRecursion = request.QueryString["recursion"]; + if (!string.IsNullOrEmpty(strRecursion)) + _dnsWebService._dnsServer.Recursion = Enum.Parse(strRecursion, true); + + string strRecursionDeniedNetworks = request.QueryString["recursionDeniedNetworks"]; + if (!string.IsNullOrEmpty(strRecursionDeniedNetworks)) + { + if (strRecursionDeniedNetworks == "false") + { + _dnsWebService._dnsServer.RecursionDeniedNetworks = null; + } + else + { + string[] strNetworks = strRecursionDeniedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + NetworkAddress[] networks = new NetworkAddress[strNetworks.Length]; + + for (int i = 0; i < networks.Length; i++) + networks[i] = NetworkAddress.Parse(strNetworks[i]); + + _dnsWebService._dnsServer.RecursionDeniedNetworks = networks; + } + } + + string strRecursionAllowedNetworks = request.QueryString["recursionAllowedNetworks"]; + if (!string.IsNullOrEmpty(strRecursionAllowedNetworks)) + { + if (strRecursionAllowedNetworks == "false") + { + _dnsWebService._dnsServer.RecursionAllowedNetworks = null; + } + else + { + string[] strNetworks = strRecursionAllowedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + NetworkAddress[] networks = new NetworkAddress[strNetworks.Length]; + + for (int i = 0; i < networks.Length; i++) + networks[i] = NetworkAddress.Parse(strNetworks[i]); + + _dnsWebService._dnsServer.RecursionAllowedNetworks = networks; + } + } + + string strRandomizeName = request.QueryString["randomizeName"]; + if (!string.IsNullOrEmpty(strRandomizeName)) + _dnsWebService._dnsServer.RandomizeName = bool.Parse(strRandomizeName); + + string strQnameMinimization = request.QueryString["qnameMinimization"]; + if (!string.IsNullOrEmpty(strQnameMinimization)) + _dnsWebService._dnsServer.QnameMinimization = bool.Parse(strQnameMinimization); + + string strNsRevalidation = request.QueryString["nsRevalidation"]; + if (!string.IsNullOrEmpty(strNsRevalidation)) + _dnsWebService._dnsServer.NsRevalidation = bool.Parse(strNsRevalidation); + + string strResolverRetries = request.QueryString["resolverRetries"]; + if (!string.IsNullOrEmpty(strResolverRetries)) + _dnsWebService._dnsServer.ResolverRetries = int.Parse(strResolverRetries); + + string strResolverTimeout = request.QueryString["resolverTimeout"]; + if (!string.IsNullOrEmpty(strResolverTimeout)) + _dnsWebService._dnsServer.ResolverTimeout = int.Parse(strResolverTimeout); + + string strResolverMaxStackCount = request.QueryString["resolverMaxStackCount"]; + if (!string.IsNullOrEmpty(strResolverMaxStackCount)) + _dnsWebService._dnsServer.ResolverMaxStackCount = int.Parse(strResolverMaxStackCount); + + //cache + string strServeStale = request.QueryString["serveStale"]; + if (!string.IsNullOrEmpty(strServeStale)) + _dnsWebService._dnsServer.ServeStale = bool.Parse(strServeStale); + + string strServeStaleTtl = request.QueryString["serveStaleTtl"]; + if (!string.IsNullOrEmpty(strServeStaleTtl)) + _dnsWebService._dnsServer.CacheZoneManager.ServeStaleTtl = uint.Parse(strServeStaleTtl); + + string strCacheMaximumEntries = request.QueryString["cacheMaximumEntries"]; + if (!string.IsNullOrEmpty(strCacheMaximumEntries)) + _dnsWebService._dnsServer.CacheZoneManager.MaximumEntries = long.Parse(strCacheMaximumEntries); + + string strCacheMinimumRecordTtl = request.QueryString["cacheMinimumRecordTtl"]; + if (!string.IsNullOrEmpty(strCacheMinimumRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.MinimumRecordTtl = uint.Parse(strCacheMinimumRecordTtl); + + string strCacheMaximumRecordTtl = request.QueryString["cacheMaximumRecordTtl"]; + if (!string.IsNullOrEmpty(strCacheMaximumRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.MaximumRecordTtl = uint.Parse(strCacheMaximumRecordTtl); + + string strCacheNegativeRecordTtl = request.QueryString["cacheNegativeRecordTtl"]; + if (!string.IsNullOrEmpty(strCacheNegativeRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.NegativeRecordTtl = uint.Parse(strCacheNegativeRecordTtl); + + string strCacheFailureRecordTtl = request.QueryString["cacheFailureRecordTtl"]; + if (!string.IsNullOrEmpty(strCacheFailureRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.FailureRecordTtl = uint.Parse(strCacheFailureRecordTtl); + + string strCachePrefetchEligibility = request.QueryString["cachePrefetchEligibility"]; + if (!string.IsNullOrEmpty(strCachePrefetchEligibility)) + _dnsWebService._dnsServer.CachePrefetchEligibility = int.Parse(strCachePrefetchEligibility); + + string strCachePrefetchTrigger = request.QueryString["cachePrefetchTrigger"]; + if (!string.IsNullOrEmpty(strCachePrefetchTrigger)) + _dnsWebService._dnsServer.CachePrefetchTrigger = int.Parse(strCachePrefetchTrigger); + + string strCachePrefetchSampleIntervalInMinutes = request.QueryString["cachePrefetchSampleIntervalInMinutes"]; + if (!string.IsNullOrEmpty(strCachePrefetchSampleIntervalInMinutes)) + _dnsWebService._dnsServer.CachePrefetchSampleIntervalInMinutes = int.Parse(strCachePrefetchSampleIntervalInMinutes); + + string strCachePrefetchSampleEligibilityHitsPerHour = request.QueryString["cachePrefetchSampleEligibilityHitsPerHour"]; + if (!string.IsNullOrEmpty(strCachePrefetchSampleEligibilityHitsPerHour)) + _dnsWebService._dnsServer.CachePrefetchSampleEligibilityHitsPerHour = int.Parse(strCachePrefetchSampleEligibilityHitsPerHour); + + //blocking + string strEnableBlocking = request.QueryString["enableBlocking"]; + if (!string.IsNullOrEmpty(strEnableBlocking)) + { + _dnsWebService._dnsServer.EnableBlocking = bool.Parse(strEnableBlocking); + if (_dnsWebService._dnsServer.EnableBlocking) + { + if (_temporaryDisableBlockingTimer is not null) + _temporaryDisableBlockingTimer.Dispose(); + } + } + + string strAllowTxtBlockingReport = request.QueryString["allowTxtBlockingReport"]; + if (!string.IsNullOrEmpty(strAllowTxtBlockingReport)) + _dnsWebService._dnsServer.AllowTxtBlockingReport = bool.Parse(strAllowTxtBlockingReport); + + string strBlockingType = request.QueryString["blockingType"]; + if (!string.IsNullOrEmpty(strBlockingType)) + _dnsWebService._dnsServer.BlockingType = Enum.Parse(strBlockingType, true); + + string strCustomBlockingAddresses = request.QueryString["customBlockingAddresses"]; + if (!string.IsNullOrEmpty(strCustomBlockingAddresses)) + { + if (strCustomBlockingAddresses == "false") + { + _dnsWebService._dnsServer.CustomBlockingARecords = null; + _dnsWebService._dnsServer.CustomBlockingAAAARecords = null; + } + else + { + string[] strAddresses = strCustomBlockingAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + List dnsARecords = new List(); + List dnsAAAARecords = new List(); + + foreach (string strAddress in strAddresses) + { + if (IPAddress.TryParse(strAddress, out IPAddress customAddress)) + { + switch (customAddress.AddressFamily) + { + case AddressFamily.InterNetwork: + dnsARecords.Add(new DnsARecordData(customAddress)); + break; + + case AddressFamily.InterNetworkV6: + dnsAAAARecords.Add(new DnsAAAARecordData(customAddress)); + break; + } + } + } + + _dnsWebService._dnsServer.CustomBlockingARecords = dnsARecords; + _dnsWebService._dnsServer.CustomBlockingAAAARecords = dnsAAAARecords; + } + } + + bool blockListUrlsUpdated = false; + string strBlockListUrls = request.QueryString["blockListUrls"]; + if (!string.IsNullOrEmpty(strBlockListUrls)) + { + if (strBlockListUrls == "false") + { + _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Clear(); + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Clear(); + _dnsWebService._dnsServer.BlockListZoneManager.Flush(); + } + else + { + string[] strBlockListUrlList = strBlockListUrls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + + if (oldWebServiceHttpPort != _dnsWebService._webServiceHttpPort) + { + for (int i = 0; i < strBlockListUrlList.Length; i++) + { + if (strBlockListUrlList[i].Contains("http://localhost:" + oldWebServiceHttpPort + "/blocklist.txt")) + { + strBlockListUrlList[i] = "http://localhost:" + _dnsWebService._webServiceHttpPort + "/blocklist.txt"; + blockListUrlsUpdated = true; + break; + } + } + } + + if (!blockListUrlsUpdated) + { + if (strBlockListUrlList.Length != (_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count)) + { + blockListUrlsUpdated = true; + } + else + { + foreach (string strBlockListUrl in strBlockListUrlList) + { + if (strBlockListUrl.StartsWith("!")) + { + string strAllowListUrl = strBlockListUrl.Substring(1); + + if (!_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Contains(new Uri(strAllowListUrl))) + { + blockListUrlsUpdated = true; + break; + } + } + else + { + if (!_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Contains(new Uri(strBlockListUrl))) + { + blockListUrlsUpdated = true; + break; + } + } + } + } + } + + if (blockListUrlsUpdated) + { + _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Clear(); + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Clear(); + + foreach (string strBlockListUrl in strBlockListUrlList) + { + if (strBlockListUrl.StartsWith("!")) + { + Uri allowListUrl = new Uri(strBlockListUrl.Substring(1)); + + if (!_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Contains(allowListUrl)) + _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Add(allowListUrl); + } + else + { + Uri blockListUrl = new Uri(strBlockListUrl); + + if (!_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Contains(blockListUrl)) + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Add(blockListUrl); + } + } + } + } + } + + string strBlockListUpdateIntervalHours = request.QueryString["blockListUpdateIntervalHours"]; + if (!string.IsNullOrEmpty(strBlockListUpdateIntervalHours)) + { + int blockListUpdateIntervalHours = int.Parse(strBlockListUpdateIntervalHours); + + if ((blockListUpdateIntervalHours < 0) || (blockListUpdateIntervalHours > 168)) + throw new DnsWebServiceException("Parameter `blockListUpdateIntervalHours` must be between 1 hour and 168 hours (7 days) or 0 to disable automatic update."); + + _blockListUpdateIntervalHours = blockListUpdateIntervalHours; + } + + if ((_blockListUpdateIntervalHours > 0) && ((_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count) > 0)) + { + if (blockListUrlsUpdated || (_blockListUpdateTimer is null)) + ForceUpdateBlockLists(); + + StartBlockListUpdateTimer(); + } + else + { + StopBlockListUpdateTimer(); + } + + //proxy & forwarders + string strProxyType = request.QueryString["proxyType"]; + if (!string.IsNullOrEmpty(strProxyType)) + { + NetProxyType proxyType = Enum.Parse(strProxyType, true); + if (proxyType == NetProxyType.None) + { + _dnsWebService._dnsServer.Proxy = null; + } + else + { + NetworkCredential credential = null; + + string strUsername = request.QueryString["proxyUsername"]; + if (!string.IsNullOrEmpty(strUsername)) + credential = new NetworkCredential(strUsername, request.QueryString["proxyPassword"]); + + _dnsWebService._dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.QueryString["proxyAddress"], int.Parse(request.QueryString["proxyPort"]), credential); + + string strProxyBypass = request.QueryString["proxyBypass"]; + if (!string.IsNullOrEmpty(strProxyBypass)) + { + string[] strBypassList = strProxyBypass.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + List bypassList = new List(strBypassList.Length); + + for (int i = 0; i < strBypassList.Length; i++) + bypassList.Add(new NetProxyBypassItem(strBypassList[i])); + + _dnsWebService._dnsServer.Proxy.BypassList = bypassList; + } + } + } + + DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; + string strForwarderProtocol = request.QueryString["forwarderProtocol"]; + if (!string.IsNullOrEmpty(strForwarderProtocol)) + { + forwarderProtocol = Enum.Parse(strForwarderProtocol, true); + if (forwarderProtocol == DnsTransportProtocol.HttpsJson) + forwarderProtocol = DnsTransportProtocol.Https; + } + + string strForwarders = request.QueryString["forwarders"]; + if (!string.IsNullOrEmpty(strForwarders)) + { + if (strForwarders == "false") + { + _dnsWebService._dnsServer.Forwarders = null; + } + else + { + string[] strForwardersList = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + NameServerAddress[] forwarders = new NameServerAddress[strForwardersList.Length]; + + for (int i = 0; i < strForwardersList.Length; i++) + { + NameServerAddress forwarder = new NameServerAddress(strForwardersList[i]); + + if (forwarder.Protocol != forwarderProtocol) + forwarder = forwarder.ChangeProtocol(forwarderProtocol); + + forwarders[i] = forwarder; + } + + _dnsWebService._dnsServer.Forwarders = forwarders; + } + } + + string strForwarderRetries = request.QueryString["forwarderRetries"]; + if (!string.IsNullOrEmpty(strForwarderRetries)) + _dnsWebService._dnsServer.ForwarderRetries = int.Parse(strForwarderRetries); + + string strForwarderTimeout = request.QueryString["forwarderTimeout"]; + if (!string.IsNullOrEmpty(strForwarderTimeout)) + _dnsWebService._dnsServer.ForwarderTimeout = int.Parse(strForwarderTimeout); + + string strForwarderConcurrency = request.QueryString["forwarderConcurrency"]; + if (!string.IsNullOrEmpty(strForwarderConcurrency)) + _dnsWebService._dnsServer.ForwarderConcurrency = int.Parse(strForwarderConcurrency); + + //logging + string strEnableLogging = request.QueryString["enableLogging"]; + if (!string.IsNullOrEmpty(strEnableLogging)) + _dnsWebService._log.EnableLogging = bool.Parse(strEnableLogging); + + string strLogQueries = request.QueryString["logQueries"]; + if (!string.IsNullOrEmpty(strLogQueries)) + { + if (bool.Parse(strLogQueries)) + _dnsWebService._dnsServer.QueryLogManager = _dnsWebService._log; + else + _dnsWebService._dnsServer.QueryLogManager = null; + } + + string strUseLocalTime = request.QueryString["useLocalTime"]; + if (!string.IsNullOrEmpty(strUseLocalTime)) + _dnsWebService._log.UseLocalTime = bool.Parse(strUseLocalTime); + + string strLogFolder = request.QueryString["logFolder"]; + if (!string.IsNullOrEmpty(strLogFolder)) + _dnsWebService._log.LogFolder = strLogFolder; + + string strMaxLogFileDays = request.QueryString["maxLogFileDays"]; + if (!string.IsNullOrEmpty(strMaxLogFileDays)) + _dnsWebService._log.MaxLogFileDays = int.Parse(strMaxLogFileDays); + + string strMaxStatFileDays = request.QueryString["maxStatFileDays"]; + if (!string.IsNullOrEmpty(strMaxStatFileDays)) + _dnsWebService._dnsServer.StatsManager.MaxStatFileDays = int.Parse(strMaxStatFileDays); + + //TLS actions + if ((_dnsWebService._webServiceTlsCertificatePath == null) && (_dnsWebService._dnsTlsCertificatePath == null)) + _dnsWebService.StopTlsCertificateUpdateTimer(); + + _dnsWebService.SelfSignedCertCheck(serverDomainChanged, true); + + if (_dnsWebService._webServiceEnableTls && string.IsNullOrEmpty(_dnsWebService._webServiceTlsCertificatePath) && !_dnsWebService._webServiceUseSelfSignedTlsCertificate) + { + //disable TLS + _dnsWebService._webServiceEnableTls = false; + restartWebService = true; + } + + //save config + _dnsWebService.SaveConfigFile(); + _dnsWebService._log.Save(); + + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS Settings were updated successfully."); + + GetDnsSettings(jsonWriter); + + RestartService(restartDnsService, restartWebService); + } + + public void GetTsigKeyNames(Utf8JsonWriter jsonWriter) + { + jsonWriter.WritePropertyName("tsigKeyNames"); + { + jsonWriter.WriteStartArray(); + + if (_dnsWebService._dnsServer.TsigKeys is not null) + { + foreach (KeyValuePair tsigKey in _dnsWebService._dnsServer.TsigKeys) + jsonWriter.WriteStringValue(tsigKey.Key); + } + + jsonWriter.WriteEndArray(); + } + } + + public async Task BackupSettingsAsync(HttpListenerRequest request, HttpListenerResponse response) + { + bool blockLists = false; + bool logs = false; + bool scopes = false; + bool apps = false; + bool stats = false; + bool zones = false; + bool allowedZones = false; + bool blockedZones = false; + bool dnsSettings = false; + bool authConfig = false; + bool logSettings = false; + + string strBlockLists = request.QueryString["blockLists"]; + if (!string.IsNullOrEmpty(strBlockLists)) + blockLists = bool.Parse(strBlockLists); + + string strLogs = request.QueryString["logs"]; + if (!string.IsNullOrEmpty(strLogs)) + logs = bool.Parse(strLogs); + + string strScopes = request.QueryString["scopes"]; + if (!string.IsNullOrEmpty(strScopes)) + scopes = bool.Parse(strScopes); + + string strApps = request.QueryString["apps"]; + if (!string.IsNullOrEmpty(strApps)) + apps = bool.Parse(strApps); + + string strStats = request.QueryString["stats"]; + if (!string.IsNullOrEmpty(strStats)) + stats = bool.Parse(strStats); + + string strZones = request.QueryString["zones"]; + if (!string.IsNullOrEmpty(strZones)) + zones = bool.Parse(strZones); + + string strAllowedZones = request.QueryString["allowedZones"]; + if (!string.IsNullOrEmpty(strAllowedZones)) + allowedZones = bool.Parse(strAllowedZones); + + string strBlockedZones = request.QueryString["blockedZones"]; + if (!string.IsNullOrEmpty(strBlockedZones)) + blockedZones = bool.Parse(strBlockedZones); + + string strDnsSettings = request.QueryString["dnsSettings"]; + if (!string.IsNullOrEmpty(strDnsSettings)) + dnsSettings = bool.Parse(strDnsSettings); + + string strAuthConfig = request.QueryString["authConfig"]; + if (!string.IsNullOrEmpty(strAuthConfig)) + authConfig = bool.Parse(strAuthConfig); + + string strLogSettings = request.QueryString["logSettings"]; + if (!string.IsNullOrEmpty(strLogSettings)) + logSettings = bool.Parse(strLogSettings); + + string tmpFile = Path.GetTempFileName(); + try + { + using (FileStream backupZipStream = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) + { + //create backup zip + using (ZipArchive backupZip = new ZipArchive(backupZipStream, ZipArchiveMode.Create, true, Encoding.UTF8)) + { + if (blockLists) + { + string[] blockListFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "blocklists"), "*", SearchOption.TopDirectoryOnly); + foreach (string blockListFile in blockListFiles) + { + string entryName = "blocklists/" + Path.GetFileName(blockListFile); + backupZip.CreateEntryFromFile(blockListFile, entryName); + } + } + + if (logs) + { + string[] logFiles = Directory.GetFiles(_dnsWebService._log.LogFolderAbsolutePath, "*.log", SearchOption.TopDirectoryOnly); + foreach (string logFile in logFiles) + { + string entryName = "logs/" + Path.GetFileName(logFile); + + if (logFile.Equals(_dnsWebService._log.CurrentLogFile, StringComparison.OrdinalIgnoreCase)) + { + await CreateBackupEntryFromFileAsync(backupZip, logFile, entryName); + } + else + { + backupZip.CreateEntryFromFile(logFile, entryName); + } + } + } + + if (scopes) + { + string[] scopeFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "scopes"), "*.scope", SearchOption.TopDirectoryOnly); + foreach (string scopeFile in scopeFiles) + { + string entryName = "scopes/" + Path.GetFileName(scopeFile); + backupZip.CreateEntryFromFile(scopeFile, entryName); + } + } + + if (apps) + { + string[] appFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "apps"), "*", SearchOption.AllDirectories); + foreach (string appFile in appFiles) + { + string entryName = appFile.Substring(_dnsWebService._configFolder.Length); + + if (Path.DirectorySeparatorChar != '/') + entryName = entryName.Replace(Path.DirectorySeparatorChar, '/'); + + entryName = entryName.TrimStart('/'); + + await CreateBackupEntryFromFileAsync(backupZip, appFile, entryName); + } + } + + if (stats) + { + string[] hourlyStatsFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "stats"), "*.stat", SearchOption.TopDirectoryOnly); + foreach (string hourlyStatsFile in hourlyStatsFiles) + { + string entryName = "stats/" + Path.GetFileName(hourlyStatsFile); + backupZip.CreateEntryFromFile(hourlyStatsFile, entryName); + } + + string[] dailyStatsFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "stats"), "*.dstat", SearchOption.TopDirectoryOnly); + foreach (string dailyStatsFile in dailyStatsFiles) + { + string entryName = "stats/" + Path.GetFileName(dailyStatsFile); + backupZip.CreateEntryFromFile(dailyStatsFile, entryName); + } + } + + if (zones) + { + string[] zoneFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "zones"), "*.zone", SearchOption.TopDirectoryOnly); + foreach (string zoneFile in zoneFiles) + { + string entryName = "zones/" + Path.GetFileName(zoneFile); + backupZip.CreateEntryFromFile(zoneFile, entryName); + } + } + + if (allowedZones) + { + string allowedZonesFile = Path.Combine(_dnsWebService._configFolder, "allowed.config"); + + if (File.Exists(allowedZonesFile)) + backupZip.CreateEntryFromFile(allowedZonesFile, "allowed.config"); + } + + if (blockedZones) + { + string blockedZonesFile = Path.Combine(_dnsWebService._configFolder, "blocked.config"); + + if (File.Exists(blockedZonesFile)) + backupZip.CreateEntryFromFile(blockedZonesFile, "blocked.config"); + } + + if (dnsSettings) + { + string dnsSettingsFile = Path.Combine(_dnsWebService._configFolder, "dns.config"); + + if (File.Exists(dnsSettingsFile)) + backupZip.CreateEntryFromFile(dnsSettingsFile, "dns.config"); + } + + if (authConfig) + { + string authSettingsFile = Path.Combine(_dnsWebService._configFolder, "auth.config"); + + if (File.Exists(authSettingsFile)) + backupZip.CreateEntryFromFile(authSettingsFile, "auth.config"); + } + + if (logSettings) + { + string logSettingsFile = Path.Combine(_dnsWebService._configFolder, "log.config"); + + if (File.Exists(logSettingsFile)) + backupZip.CreateEntryFromFile(logSettingsFile, "log.config"); + } + } + + //send zip file + backupZipStream.Position = 0; + + response.ContentType = "application/zip"; + response.ContentLength64 = backupZipStream.Length; + response.AddHeader("Content-Disposition", "attachment;filename=DnsServerBackup.zip"); + + using (Stream output = response.OutputStream) + { + await backupZipStream.CopyToAsync(output); + } + } + } + finally + { + try + { + File.Delete(tmpFile); + } + catch (Exception ex) + { + _dnsWebService._log.Write(ex); + } + } + + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Settings backup zip file was exported."); + } + + public async Task RestoreSettingsAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + { + bool blockLists = false; + bool logs = false; + bool scopes = false; + bool apps = false; + bool stats = false; + bool zones = false; + bool allowedZones = false; + bool blockedZones = false; + bool dnsSettings = false; + bool authConfig = false; + bool logSettings = false; + + bool deleteExistingFiles = false; + + string strBlockLists = request.QueryString["blockLists"]; + if (!string.IsNullOrEmpty(strBlockLists)) + blockLists = bool.Parse(strBlockLists); + + string strLogs = request.QueryString["logs"]; + if (!string.IsNullOrEmpty(strLogs)) + logs = bool.Parse(strLogs); + + string strScopes = request.QueryString["scopes"]; + if (!string.IsNullOrEmpty(strScopes)) + scopes = bool.Parse(strScopes); + + string strApps = request.QueryString["apps"]; + if (!string.IsNullOrEmpty(strApps)) + apps = bool.Parse(strApps); + + string strStats = request.QueryString["stats"]; + if (!string.IsNullOrEmpty(strStats)) + stats = bool.Parse(strStats); + + string strZones = request.QueryString["zones"]; + if (!string.IsNullOrEmpty(strZones)) + zones = bool.Parse(strZones); + + string strAllowedZones = request.QueryString["allowedZones"]; + if (!string.IsNullOrEmpty(strAllowedZones)) + allowedZones = bool.Parse(strAllowedZones); + + string strBlockedZones = request.QueryString["blockedZones"]; + if (!string.IsNullOrEmpty(strBlockedZones)) + blockedZones = bool.Parse(strBlockedZones); + + string strDnsSettings = request.QueryString["dnsSettings"]; + if (!string.IsNullOrEmpty(strDnsSettings)) + dnsSettings = bool.Parse(strDnsSettings); + + string strAuthConfig = request.QueryString["authConfig"]; + if (!string.IsNullOrEmpty(strAuthConfig)) + authConfig = bool.Parse(strAuthConfig); + + string strLogSettings = request.QueryString["logSettings"]; + if (!string.IsNullOrEmpty(strLogSettings)) + logSettings = bool.Parse(strLogSettings); + + string strDeleteExistingFiles = request.QueryString["deleteExistingFiles"]; + if (!string.IsNullOrEmpty(strDeleteExistingFiles)) + deleteExistingFiles = bool.Parse(strDeleteExistingFiles); + + #region skip to content + + int crlfCount = 0; + int byteRead; + + while (crlfCount != 4) + { + byteRead = await request.InputStream.ReadByteValueAsync(); + switch (byteRead) + { + case 13: //CR + case 10: //LF + crlfCount++; + break; + + default: + crlfCount = 0; + break; + } + } + + #endregion + + //write to temp file + string tmpFile = Path.GetTempFileName(); + try + { + using (FileStream fS = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) + { + await request.InputStream.CopyToAsync(fS); + + fS.Position = 0; + using (ZipArchive backupZip = new ZipArchive(fS, ZipArchiveMode.Read, false, Encoding.UTF8)) + { + UserSession session = _dnsWebService.GetSession(request); + + if (logSettings || logs) + { + //stop logging + _dnsWebService._log.StopLogging(); + } + + try + { + if (logSettings) + { + ZipArchiveEntry entry = backupZip.GetEntry("log.config"); + if (entry != null) + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, entry.Name), true); + + //reload config + _dnsWebService._log.LoadConfig(); + } + + if (logs) + { + if (deleteExistingFiles) + { + //delete existing log files + string[] logFiles = Directory.GetFiles(_dnsWebService._log.LogFolderAbsolutePath, "*.log", SearchOption.TopDirectoryOnly); + foreach (string logFile in logFiles) + { + File.Delete(logFile); + } + } + + //extract log files from backup + foreach (ZipArchiveEntry entry in backupZip.Entries) + { + if (entry.FullName.StartsWith("logs/")) + entry.ExtractToFile(Path.Combine(_dnsWebService._log.LogFolderAbsolutePath, entry.Name), true); + } + } + } + finally + { + if (logSettings || logs) + { + //start logging + if (_dnsWebService._log.EnableLogging) + _dnsWebService._log.StartLogging(); + } + } + + if (authConfig) + { + ZipArchiveEntry entry = backupZip.GetEntry("auth.config"); + if (entry != null) + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, entry.Name), true); + + //reload auth config + _dnsWebService._authManager.LoadConfigFile(session); + } + + if (blockLists) + { + if (deleteExistingFiles) + { + //delete existing block list files + string[] blockListFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "blocklists"), "*", SearchOption.TopDirectoryOnly); + foreach (string blockListFile in blockListFiles) + { + File.Delete(blockListFile); + } + } + + //extract block list files from backup + foreach (ZipArchiveEntry entry in backupZip.Entries) + { + if (entry.FullName.StartsWith("blocklists/")) + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, "blocklists", entry.Name), true); + } + } + + if (dnsSettings) + { + ZipArchiveEntry entry = backupZip.GetEntry("dns.config"); + if (entry != null) + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, entry.Name), true); + + //reload settings and block list zone + _dnsWebService.LoadConfigFile(); + + if ((_blockListUpdateIntervalHours > 0) && (_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count > 0)) + { + ThreadPool.QueueUserWorkItem(delegate (object state) + { + try + { + _dnsWebService._dnsServer.BlockListZoneManager.LoadBlockLists(); + StartBlockListUpdateTimer(); + } + catch (Exception ex) + { + _dnsWebService._log.Write(ex); + } + }); + } + else + { + StopBlockListUpdateTimer(); + } + } + + if (apps) + { + //unload apps + _dnsWebService._dnsServer.DnsApplicationManager.UnloadAllApplications(); + + if (deleteExistingFiles) + { + //delete existing apps + string appFolder = Path.Combine(_dnsWebService._configFolder, "apps"); + if (Directory.Exists(appFolder)) + Directory.Delete(appFolder, true); + + //create apps folder + Directory.CreateDirectory(appFolder); + } + + //extract apps files from backup + foreach (ZipArchiveEntry entry in backupZip.Entries) + { + if (entry.FullName.StartsWith("apps/")) + { + string entryPath = entry.FullName; + + if (Path.DirectorySeparatorChar != '/') + entryPath = entryPath.Replace('/', '\\'); + + string filePath = Path.Combine(_dnsWebService._configFolder, entryPath); + + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + + entry.ExtractToFile(filePath, true); + } + } + + //reload apps + _dnsWebService._dnsServer.DnsApplicationManager.LoadAllApplications(); + } + + if (zones) + { + if (deleteExistingFiles) + { + //delete existing zone files + string[] zoneFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "zones"), "*.zone", SearchOption.TopDirectoryOnly); + foreach (string zoneFile in zoneFiles) + { + File.Delete(zoneFile); + } + } + + //extract zone files from backup + foreach (ZipArchiveEntry entry in backupZip.Entries) + { + if (entry.FullName.StartsWith("zones/")) + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, "zones", entry.Name), true); + } + + //reload zones + _dnsWebService._dnsServer.AuthZoneManager.LoadAllZoneFiles(); + _dnsWebService.InspectAndFixZonePermissions(); + } + + if (allowedZones) + { + ZipArchiveEntry entry = backupZip.GetEntry("allowed.config"); + if (entry == null) + { + string fileName = Path.Combine(_dnsWebService._configFolder, "allowed.config"); + if (File.Exists(fileName)) + File.Delete(fileName); + } + else + { + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, entry.Name), true); + } + + //reload + _dnsWebService._dnsServer.AllowedZoneManager.LoadAllowedZoneFile(); + } + + if (blockedZones) + { + ZipArchiveEntry entry = backupZip.GetEntry("blocked.config"); + if (entry == null) + { + string fileName = Path.Combine(_dnsWebService._configFolder, "allowed.config"); + if (File.Exists(fileName)) + File.Delete(fileName); + } + else + { + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, entry.Name), true); + } + + //reload + _dnsWebService._dnsServer.BlockedZoneManager.LoadBlockedZoneFile(); + } + + if (scopes) + { + //stop dhcp server + _dnsWebService._dhcpServer.Stop(); + + try + { + if (deleteExistingFiles) + { + //delete existing scope files + string[] scopeFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "scopes"), "*.scope", SearchOption.TopDirectoryOnly); + foreach (string scopeFile in scopeFiles) + { + File.Delete(scopeFile); + } + } + + //extract scope files from backup + foreach (ZipArchiveEntry entry in backupZip.Entries) + { + if (entry.FullName.StartsWith("scopes/")) + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, "scopes", entry.Name), true); + } + } + finally + { + //start dhcp server + _dnsWebService._dhcpServer.Start(); + } + } + + if (stats) + { + if (deleteExistingFiles) + { + //delete existing stats files + string[] hourlyStatsFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "stats"), "*.stat", SearchOption.TopDirectoryOnly); + foreach (string hourlyStatsFile in hourlyStatsFiles) + { + File.Delete(hourlyStatsFile); + } + + string[] dailyStatsFiles = Directory.GetFiles(Path.Combine(_dnsWebService._configFolder, "stats"), "*.dstat", SearchOption.TopDirectoryOnly); + foreach (string dailyStatsFile in dailyStatsFiles) + { + File.Delete(dailyStatsFile); + } + } + + //extract stats files from backup + foreach (ZipArchiveEntry entry in backupZip.Entries) + { + if (entry.FullName.StartsWith("stats/")) + entry.ExtractToFile(Path.Combine(_dnsWebService._configFolder, "stats", entry.Name), true); + } + + //reload stats + _dnsWebService._dnsServer.StatsManager.ReloadStats(); + } + + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Settings backup zip file was restored."); + } + } + } + finally + { + try + { + File.Delete(tmpFile); + } + catch (Exception ex) + { + _dnsWebService._log.Write(ex); + } + } + + if (dnsSettings) + RestartService(true, true); + + GetDnsSettings(jsonWriter); + } + + public void ForceUpdateBlockLists(HttpListenerRequest request) + { + ForceUpdateBlockLists(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Block list update was triggered."); + } + + public void TemporaryDisableBlocking(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + { + string strMinutes = request.QueryString["minutes"]; + if (string.IsNullOrEmpty(strMinutes)) + throw new DnsWebServiceException("Parameter 'minutes' missing."); + + int minutes = int.Parse(strMinutes); + + Timer temporaryDisableBlockingTimer = _temporaryDisableBlockingTimer; + if (temporaryDisableBlockingTimer is not null) + temporaryDisableBlockingTimer.Dispose(); + + Timer newTemporaryDisableBlockingTimer = new Timer(delegate (object state) + { + try + { + _dnsWebService._dnsServer.EnableBlocking = true; + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocking was enabled after " + minutes + " minute(s) being temporarily disabled."); + } + catch (Exception ex) + { + _dnsWebService._log.Write(ex); + } + }); + + Timer originalTimer = Interlocked.CompareExchange(ref _temporaryDisableBlockingTimer, newTemporaryDisableBlockingTimer, temporaryDisableBlockingTimer); + if (ReferenceEquals(originalTimer, temporaryDisableBlockingTimer)) + { + newTemporaryDisableBlockingTimer.Change(minutes * 60 * 1000, Timeout.Infinite); + _dnsWebService._dnsServer.EnableBlocking = false; + _temporaryDisableBlockingTill = DateTime.UtcNow.AddMinutes(minutes); + + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocking was temporarily disabled for " + minutes + " minute(s)."); + } + else + { + newTemporaryDisableBlockingTimer.Dispose(); + } + + jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); + } + + #endregion + + #region properties + + public DateTime BlockListLastUpdatedOn + { + get { return _blockListLastUpdatedOn; } + set { _blockListLastUpdatedOn = value; } + } + + public int BlockListUpdateIntervalHours + { + get { return _blockListUpdateIntervalHours; } + set { _blockListUpdateIntervalHours = value; } + } + + #endregion + } +} From 2d5c5df0f140d1ea4c7b835a18d38bafeeee47c2 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 24 Dec 2022 17:15:06 +0530 Subject: [PATCH 040/191] code refactoring changes. --- DnsServerCore/WebServiceAppsApi.cs | 70 ++-- DnsServerCore/WebServiceAuthApi.cs | 150 ++++---- DnsServerCore/WebServiceDashboardApi.cs | 42 +-- DnsServerCore/WebServiceDhcpApi.cs | 66 ++-- DnsServerCore/WebServiceLogsApi.cs | 18 +- DnsServerCore/WebServiceOtherZonesApi.cs | 72 ++-- DnsServerCore/WebServiceZonesApi.cs | 422 +++++++++++------------ 7 files changed, 420 insertions(+), 420 deletions(-) diff --git a/DnsServerCore/WebServiceAppsApi.cs b/DnsServerCore/WebServiceAppsApi.cs index 04879045..e2edff93 100644 --- a/DnsServerCore/WebServiceAppsApi.cs +++ b/DnsServerCore/WebServiceAppsApi.cs @@ -86,16 +86,16 @@ namespace DnsServerCore { try { - if (_dnsWebService.DnsServer.DnsApplicationManager.Applications.Count < 1) + if (_dnsWebService._dnsServer.DnsApplicationManager.Applications.Count < 1) return; - _dnsWebService.Log.Write("DNS Server has started automatic update check for DNS Apps."); + _dnsWebService._log.Write("DNS Server has started automatic update check for DNS Apps."); string storeAppsJsonData = await GetStoreAppsJsonData().WithTimeout(5000); using JsonDocument jsonDocument = JsonDocument.Parse(storeAppsJsonData); JsonElement jsonStoreAppsArray = jsonDocument.RootElement; - foreach (DnsApplication application in _dnsWebService.DnsServer.DnsApplicationManager.Applications.Values) + foreach (DnsApplication application in _dnsWebService._dnsServer.DnsApplicationManager.Applications.Values) { foreach (JsonElement jsonStoreApp in jsonStoreAppsArray.EnumerateArray()) { @@ -111,7 +111,7 @@ namespace DnsServerCore string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); Version requiredServerVersion = new Version(strServerVersion); - if (_dnsWebService.ServerVersion < requiredServerVersion) + if (_dnsWebService._currentVersion < requiredServerVersion) continue; if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) @@ -130,11 +130,11 @@ namespace DnsServerCore { await DownloadAndUpdateAppAsync(application.Name, url); - _dnsWebService.Log.Write("DNS application '" + application.Name + "' was automatically updated successfully from: " + url); + _dnsWebService._log.Write("DNS application '" + application.Name + "' was automatically updated successfully from: " + url); } catch (Exception ex) { - _dnsWebService.Log.Write("Failed to automatically download and update DNS application '" + application.Name + "': " + ex.ToString()); + _dnsWebService._log.Write("Failed to automatically download and update DNS application '" + application.Name + "': " + ex.ToString()); } } @@ -145,7 +145,7 @@ namespace DnsServerCore } catch (Exception ex) { - _dnsWebService.Log.Write(ex); + _dnsWebService._log.Write(ex); } }); @@ -167,8 +167,8 @@ namespace DnsServerCore if ((_storeAppsJsonData == null) || (DateTime.UtcNow > _storeAppsJsonDataUpdatedOn.AddSeconds(STORE_APPS_JSON_DATA_CACHE_TIME_SECONDS))) { SocketsHttpHandler handler = new SocketsHttpHandler(); - handler.Proxy = _dnsWebService.DnsServer.Proxy; - handler.UseProxy = _dnsWebService.DnsServer.Proxy is not null; + handler.Proxy = _dnsWebService._dnsServer.Proxy; + handler.UseProxy = _dnsWebService._dnsServer.Proxy is not null; handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient http = new HttpClient(handler)) @@ -190,8 +190,8 @@ namespace DnsServerCore { //download to temp file SocketsHttpHandler handler = new SocketsHttpHandler(); - handler.Proxy = _dnsWebService.DnsServer.Proxy; - handler.UseProxy = _dnsWebService.DnsServer.Proxy is not null; + handler.Proxy = _dnsWebService._dnsServer.Proxy; + handler.UseProxy = _dnsWebService._dnsServer.Proxy is not null; handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient http = new HttpClient(handler)) @@ -204,7 +204,7 @@ namespace DnsServerCore //update app fS.Position = 0; - return await _dnsWebService.DnsServer.DnsApplicationManager.UpdateApplicationAsync(applicationName, fS); + return await _dnsWebService._dnsServer.DnsApplicationManager.UpdateApplicationAsync(applicationName, fS); } } finally @@ -215,7 +215,7 @@ namespace DnsServerCore } catch (Exception ex) { - _dnsWebService.Log.Write(ex); + _dnsWebService._log.Write(ex); } } } @@ -245,7 +245,7 @@ namespace DnsServerCore string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); Version requiredServerVersion = new Version(strServerVersion); - if (_dnsWebService.ServerVersion < requiredServerVersion) + if (_dnsWebService._currentVersion < requiredServerVersion) continue; if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) @@ -310,7 +310,7 @@ namespace DnsServerCore public async Task ListInstalledAppsAsync(Utf8JsonWriter jsonWriter) { - List apps = new List(_dnsWebService.DnsServer.DnsApplicationManager.Applications.Keys); + List apps = new List(_dnsWebService._dnsServer.DnsApplicationManager.Applications.Keys); apps.Sort(); JsonDocument jsonDocument = null; @@ -335,7 +335,7 @@ namespace DnsServerCore foreach (string app in apps) { - if (_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(app, out DnsApplication application)) + if (_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(app, out DnsApplication application)) WriteAppAsJson(jsonWriter, application, jsonStoreAppsArray); } @@ -372,7 +372,7 @@ namespace DnsServerCore string strServerVersion = jsonVersion.GetProperty("serverVersion").GetString(); Version requiredServerVersion = new Version(strServerVersion); - if (_dnsWebService.ServerVersion < requiredServerVersion) + if (_dnsWebService._currentVersion < requiredServerVersion) continue; if ((lastServerVersion is not null) && (lastServerVersion > requiredServerVersion)) @@ -397,7 +397,7 @@ namespace DnsServerCore jsonWriter.WriteString("url", url); jsonWriter.WriteString("size", size); - bool installed = _dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); + bool installed = _dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); jsonWriter.WriteBoolean("installed", installed); @@ -435,8 +435,8 @@ namespace DnsServerCore { //download to temp file SocketsHttpHandler handler = new SocketsHttpHandler(); - handler.Proxy = _dnsWebService.DnsServer.Proxy; - handler.UseProxy = _dnsWebService.DnsServer.Proxy is not null; + handler.Proxy = _dnsWebService._dnsServer.Proxy; + handler.UseProxy = _dnsWebService._dnsServer.Proxy is not null; handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient http = new HttpClient(handler)) @@ -449,9 +449,9 @@ namespace DnsServerCore //install app fS.Position = 0; - DnsApplication application = await _dnsWebService.DnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); + DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully from: " + url); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully from: " + url); jsonWriter.WritePropertyName("installedApp"); WriteAppAsJson(jsonWriter, application); @@ -465,7 +465,7 @@ namespace DnsServerCore } catch (Exception ex) { - _dnsWebService.Log.Write(ex); + _dnsWebService._log.Write(ex); } } } @@ -487,7 +487,7 @@ namespace DnsServerCore DnsApplication application = await DownloadAndUpdateAppAsync(name, url); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully from: " + url); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully from: " + url); jsonWriter.WritePropertyName("updatedApp"); WriteAppAsJson(jsonWriter, application); @@ -534,9 +534,9 @@ namespace DnsServerCore //install app fS.Position = 0; - DnsApplication application = await _dnsWebService.DnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); + DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully."); jsonWriter.WritePropertyName("installedApp"); WriteAppAsJson(jsonWriter, application); @@ -550,7 +550,7 @@ namespace DnsServerCore } catch (Exception ex) { - _dnsWebService.Log.Write(ex); + _dnsWebService._log.Write(ex); } } } @@ -596,9 +596,9 @@ namespace DnsServerCore //update app fS.Position = 0; - DnsApplication application = await _dnsWebService.DnsServer.DnsApplicationManager.UpdateApplicationAsync(name, fS); + DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.UpdateApplicationAsync(name, fS); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully."); jsonWriter.WritePropertyName("updatedApp"); WriteAppAsJson(jsonWriter, application); @@ -612,7 +612,7 @@ namespace DnsServerCore } catch (Exception ex) { - _dnsWebService.Log.Write(ex); + _dnsWebService._log.Write(ex); } } } @@ -625,8 +625,8 @@ namespace DnsServerCore name = name.Trim(); - _dnsWebService.DnsServer.DnsApplicationManager.UninstallApplication(name); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was uninstalled successfully."); + _dnsWebService._dnsServer.DnsApplicationManager.UninstallApplication(name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was uninstalled successfully."); } public async Task GetAppConfigAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -637,7 +637,7 @@ namespace DnsServerCore name = name.Trim(); - if (!_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) + if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); string config = await application.GetConfigAsync(); @@ -653,7 +653,7 @@ namespace DnsServerCore name = name.Trim(); - if (!_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) + if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); string formRequest; @@ -675,7 +675,7 @@ namespace DnsServerCore await application.SetConfigAsync(config); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' app config was saved successfully."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' app config was saved successfully."); return; } } diff --git a/DnsServerCore/WebServiceAuthApi.cs b/DnsServerCore/WebServiceAuthApi.cs index 139c6093..5badae00 100644 --- a/DnsServerCore/WebServiceAuthApi.cs +++ b/DnsServerCore/WebServiceAuthApi.cs @@ -66,8 +66,8 @@ namespace DnsServerCore jsonWriter.WriteStartObject(); jsonWriter.WriteString("version", _dnsWebService.GetServerVersion()); - jsonWriter.WriteString("dnsServerDomain", _dnsWebService.DnsServer.ServerDomain); - jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService.ZonesApi.DefaultRecordTtl); + jsonWriter.WriteString("dnsServerDomain", _dnsWebService._dnsServer.ServerDomain); + jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService._zonesApi.DefaultRecordTtl); jsonWriter.WritePropertyName("permissions"); jsonWriter.WriteStartObject(); @@ -79,9 +79,9 @@ namespace DnsServerCore jsonWriter.WritePropertyName(section.ToString()); jsonWriter.WriteStartObject(); - jsonWriter.WriteBoolean("canView", _dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.View)); - jsonWriter.WriteBoolean("canModify", _dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Modify)); - jsonWriter.WriteBoolean("canDelete", _dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Delete)); + jsonWriter.WriteBoolean("canView", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.View)); + jsonWriter.WriteBoolean("canModify", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.Modify)); + jsonWriter.WriteBoolean("canDelete", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } @@ -125,7 +125,7 @@ namespace DnsServerCore jsonWriter.WritePropertyName("sessions"); jsonWriter.WriteStartArray(); - List sessions = _dnsWebService.AuthManager.GetSessions(user); + List sessions = _dnsWebService._authManager.GetSessions(user); sessions.Sort(); foreach (UserSession session in sessions) @@ -136,7 +136,7 @@ namespace DnsServerCore if (includeGroups) { - List groups = new List(_dnsWebService.AuthManager.Groups); + List groups = new List(_dnsWebService._authManager.Groups); groups.Sort(); jsonWriter.WritePropertyName("groups"); @@ -180,7 +180,7 @@ namespace DnsServerCore jsonWriter.WritePropertyName("members"); jsonWriter.WriteStartArray(); - List members = _dnsWebService.AuthManager.GetGroupMembers(group); + List members = _dnsWebService._authManager.GetGroupMembers(group); members.Sort(); foreach (User user in members) @@ -191,7 +191,7 @@ namespace DnsServerCore if (includeUsers) { - List users = new List(_dnsWebService.AuthManager.Users); + List users = new List(_dnsWebService._authManager.Users); users.Sort(); jsonWriter.WritePropertyName("users"); @@ -261,10 +261,10 @@ namespace DnsServerCore if (includeUsersAndGroups) { - List users = new List(_dnsWebService.AuthManager.Users); + List users = new List(_dnsWebService._authManager.Users); users.Sort(); - List groups = new List(_dnsWebService.AuthManager.Groups); + List groups = new List(_dnsWebService._authManager.Groups); groups.Sort(); jsonWriter.WritePropertyName("users"); @@ -317,11 +317,11 @@ namespace DnsServerCore IPEndPoint remoteEP = DnsWebService.GetRequestRemoteEndPoint(request); - UserSession session = await _dnsWebService.AuthManager.CreateSessionAsync(sessionType, strTokenName, strUsername, strPassword, remoteEP.Address, request.UserAgent); + UserSession session = await _dnsWebService._authManager.CreateSessionAsync(sessionType, strTokenName, strUsername, strPassword, remoteEP.Address, request.UserAgent); - _dnsWebService.Log.Write(remoteEP, "[" + session.User.Username + "] User logged in."); + _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] User logged in."); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); WriteCurrentSessionDetails(jsonWriter, session, includeInfo); } @@ -332,12 +332,12 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strToken)) throw new DnsWebServiceException("Parameter 'token' missing."); - UserSession session = _dnsWebService.AuthManager.DeleteSession(strToken); + UserSession session = _dnsWebService._authManager.DeleteSession(strToken); if (session is not null) { - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User logged out."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User logged out."); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); } } @@ -362,9 +362,9 @@ namespace DnsServerCore session.User.ChangePassword(strPassword); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Password was changed successfully."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Password was changed successfully."); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); } public void GetProfile(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -389,9 +389,9 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(strSessionTimeoutSeconds)) session.User.SessionTimeoutSeconds = int.Parse(strSessionTimeoutSeconds); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User profile was updated successfully."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User profile was updated successfully."); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); WriteUserDetails(jsonWriter, session.User, session, true, false); } @@ -403,7 +403,7 @@ namespace DnsServerCore jsonWriter.WritePropertyName("sessions"); jsonWriter.WriteStartArray(); - List sessions = new List(_dnsWebService.AuthManager.Sessions); + List sessions = new List(_dnsWebService._authManager.Sessions); sessions.Sort(); foreach (UserSession activeSession in sessions) @@ -427,11 +427,11 @@ namespace DnsServerCore IPEndPoint remoteEP = DnsWebService.GetRequestRemoteEndPoint(request); - UserSession session = _dnsWebService.AuthManager.CreateApiToken(strTokenName, strUsername, remoteEP.Address, request.UserAgent); + UserSession session = _dnsWebService._authManager.CreateApiToken(strTokenName, strUsername, remoteEP.Address, request.UserAgent); - _dnsWebService.Log.Write(remoteEP, "[" + session.User.Username + "] API token [" + strTokenName + "] was created successfully for user: " + strUsername); + _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] API token [" + strTokenName + "] was created successfully for user: " + strUsername); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); jsonWriter.WriteString("username", session.User.Username); jsonWriter.WriteString("tokenName", session.TokenName); @@ -451,7 +451,7 @@ namespace DnsServerCore string token = null; - foreach (UserSession activeSession in _dnsWebService.AuthManager.Sessions) + foreach (UserSession activeSession in _dnsWebService._authManager.Sessions) { if (activeSession.Token.StartsWith(strPartialToken)) { @@ -465,21 +465,21 @@ namespace DnsServerCore if (!isAdminContext) { - UserSession sessionToDelete = _dnsWebService.AuthManager.GetSession(token); + UserSession sessionToDelete = _dnsWebService._authManager.GetSession(token); if (sessionToDelete.User != session.User) throw new DnsWebServiceException("Access was denied."); } - UserSession deletedSession = _dnsWebService.AuthManager.DeleteSession(token); + UserSession deletedSession = _dnsWebService._authManager.DeleteSession(token); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User session [" + strPartialToken + "] was deleted successfully for user: " + deletedSession.User.Username); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User session [" + strPartialToken + "] was deleted successfully for user: " + deletedSession.User.Username); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); } public void ListUsers(Utf8JsonWriter jsonWriter) { - List users = new List(_dnsWebService.AuthManager.Users); + List users = new List(_dnsWebService._authManager.Users); users.Sort(); jsonWriter.WritePropertyName("users"); @@ -509,13 +509,13 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strPassword)) throw new DnsWebServiceException("Parameter 'pass' missing."); - User user = _dnsWebService.AuthManager.CreateUser(strDisplayName, strUsername, strPassword); + User user = _dnsWebService._authManager.CreateUser(strDisplayName, strUsername, strPassword); UserSession session = _dnsWebService.GetSession(request); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was created successfully with username: " + user.Username); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was created successfully with username: " + user.Username); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); WriteUserDetails(jsonWriter, user, null, false, false); } @@ -533,7 +533,7 @@ namespace DnsServerCore else includeGroups = bool.Parse(strIncludeGroups); - User user = _dnsWebService.AuthManager.GetUser(strUsername); + User user = _dnsWebService._authManager.GetUser(strUsername); if (user is null) throw new DnsWebServiceException("No such user exists: " + strUsername); @@ -546,7 +546,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strUsername)) throw new DnsWebServiceException("Parameter 'user' missing."); - User user = _dnsWebService.AuthManager.GetUser(strUsername); + User user = _dnsWebService._authManager.GetUser(strUsername); if (user is null) throw new DnsWebServiceException("No such user exists: " + strUsername); @@ -556,7 +556,7 @@ namespace DnsServerCore string strNewUsername = request.QueryString["newUser"]; if (!string.IsNullOrEmpty(strNewUsername)) - _dnsWebService.AuthManager.ChangeUsername(user, strNewUsername); + _dnsWebService._authManager.ChangeUsername(user, strNewUsername); UserSession session = _dnsWebService.GetSession(request); @@ -567,13 +567,13 @@ namespace DnsServerCore if (user.Disabled) { - foreach (UserSession userSession in _dnsWebService.AuthManager.Sessions) + foreach (UserSession userSession in _dnsWebService._authManager.Sessions) { if (userSession.Type == UserSessionType.ApiToken) continue; if (userSession.User == user) - _dnsWebService.AuthManager.DeleteSession(userSession.Token); + _dnsWebService._authManager.DeleteSession(userSession.Token); } } } @@ -606,7 +606,7 @@ namespace DnsServerCore if (part.Length == 0) continue; - Group group = _dnsWebService.AuthManager.GetGroup(part); + Group group = _dnsWebService._authManager.GetGroup(part); if (group is null) throw new DnsWebServiceException("No such group exists: " + part); @@ -614,22 +614,22 @@ namespace DnsServerCore } //ensure user is member of everyone group - Group everyone = _dnsWebService.AuthManager.GetGroup(Group.EVERYONE); + Group everyone = _dnsWebService._authManager.GetGroup(Group.EVERYONE); groups[everyone.Name.ToLower()] = everyone; if (session.User == user) { //ensure current admin user is member of administrators group to avoid self lockout - Group admins = _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS); + Group admins = _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS); groups[admins.Name.ToLower()] = admins; } user.SyncGroups(groups); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account details were updated successfully for user: " + strUsername); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account details were updated successfully for user: " + strUsername); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); WriteUserDetails(jsonWriter, user, null, true, false); } @@ -645,17 +645,17 @@ namespace DnsServerCore if (session.User.Username.Equals(strUsername, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("Invalid operation: cannot delete current user."); - if (!_dnsWebService.AuthManager.DeleteUser(strUsername)) + if (!_dnsWebService._authManager.DeleteUser(strUsername)) throw new DnsWebServiceException("Failed to delete user: " + strUsername); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was deleted successfully with username: " + strUsername); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was deleted successfully with username: " + strUsername); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); } public void ListGroups(Utf8JsonWriter jsonWriter) { - List groups = new List(_dnsWebService.AuthManager.Groups); + List groups = new List(_dnsWebService._authManager.Groups); groups.Sort(); jsonWriter.WritePropertyName("groups"); @@ -686,13 +686,13 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strDescription)) strDescription = ""; - Group group = _dnsWebService.AuthManager.CreateGroup(strGroup, strDescription); + Group group = _dnsWebService._authManager.CreateGroup(strGroup, strDescription); UserSession session = _dnsWebService.GetSession(request); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was created successfully with name: " + group.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was created successfully with name: " + group.Name); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); WriteGroupDetails(jsonWriter, group, false, false); } @@ -710,7 +710,7 @@ namespace DnsServerCore else includeUsers = bool.Parse(strIncludeGroups); - Group group = _dnsWebService.AuthManager.GetGroup(strGroup); + Group group = _dnsWebService._authManager.GetGroup(strGroup); if (group is null) throw new DnsWebServiceException("No such group exists: " + strGroup); @@ -723,13 +723,13 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strGroup)) throw new DnsWebServiceException("Parameter 'group' missing."); - Group group = _dnsWebService.AuthManager.GetGroup(strGroup); + Group group = _dnsWebService._authManager.GetGroup(strGroup); if (group is null) throw new DnsWebServiceException("No such group exists: " + strGroup); string strNewGroup = request.QueryString["newGroup"]; if (!string.IsNullOrEmpty(strNewGroup)) - _dnsWebService.AuthManager.RenameGroup(group, strNewGroup); + _dnsWebService._authManager.RenameGroup(group, strNewGroup); string strDescription = request.QueryString["description"]; if (!string.IsNullOrEmpty(strDescription)) @@ -748,7 +748,7 @@ namespace DnsServerCore if (part.Length == 0) continue; - User user = _dnsWebService.AuthManager.GetUser(part); + User user = _dnsWebService._authManager.GetUser(part); if (user is null) throw new DnsWebServiceException("No such user exists: " + part); @@ -758,12 +758,12 @@ namespace DnsServerCore if (group.Name.Equals("administrators", StringComparison.OrdinalIgnoreCase)) users[session.User.Username] = session.User; //ensure current admin user is member of administrators group to avoid self lockout - _dnsWebService.AuthManager.SyncGroupMembers(group, users); + _dnsWebService._authManager.SyncGroupMembers(group, users); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group details were updated successfully for group: " + strGroup); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group details were updated successfully for group: " + strGroup); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); WriteGroupDetails(jsonWriter, group, true, false); } @@ -774,19 +774,19 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strGroup)) throw new DnsWebServiceException("Parameter 'group' missing."); - if (!_dnsWebService.AuthManager.DeleteGroup(strGroup)) + if (!_dnsWebService._authManager.DeleteGroup(strGroup)) throw new DnsWebServiceException("Failed to delete group: " + strGroup); UserSession session = _dnsWebService.GetSession(request); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was deleted successfully with name: " + strGroup); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was deleted successfully with name: " + strGroup); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); } public void ListPermissions(Utf8JsonWriter jsonWriter) { - List permissions = new List(_dnsWebService.AuthManager.Permissions); + List permissions = new List(_dnsWebService._authManager.Permissions); permissions.Sort(); jsonWriter.WritePropertyName("permissions"); @@ -844,16 +844,16 @@ namespace DnsServerCore { UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.View)) + if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); } Permission permission; if (strSubItem is null) - permission = _dnsWebService.AuthManager.GetPermission(section); + permission = _dnsWebService._authManager.GetPermission(section); else - permission = _dnsWebService.AuthManager.GetPermission(section, strSubItem); + permission = _dnsWebService._authManager.GetPermission(section, strSubItem); if (permission is null) throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem)); @@ -894,16 +894,16 @@ namespace DnsServerCore if (strSubItem is not null) { - if (!_dnsWebService.AuthManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); } Permission permission; if (strSubItem is null) - permission = _dnsWebService.AuthManager.GetPermission(section); + permission = _dnsWebService._authManager.GetPermission(section); else - permission = _dnsWebService.AuthManager.GetPermission(section, strSubItem); + permission = _dnsWebService._authManager.GetPermission(section, strSubItem); if (permission is null) throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem)); @@ -919,7 +919,7 @@ namespace DnsServerCore if (parts[i].Length == 0) continue; - User user = _dnsWebService.AuthManager.GetUser(parts[i]); + User user = _dnsWebService._authManager.GetUser(parts[i]); bool canView = bool.Parse(parts[i + 1]); bool canModify = bool.Parse(parts[i + 2]); bool canDelete = bool.Parse(parts[i + 3]); @@ -955,7 +955,7 @@ namespace DnsServerCore if (parts[i].Length == 0) continue; - Group group = _dnsWebService.AuthManager.GetGroup(parts[i]); + Group group = _dnsWebService._authManager.GetGroup(parts[i]); bool canView = bool.Parse(parts[i + 1]); bool canModify = bool.Parse(parts[i + 2]); bool canDelete = bool.Parse(parts[i + 3]); @@ -978,20 +978,20 @@ namespace DnsServerCore } //ensure administrators group always has all permissions - Group admins = _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS); + Group admins = _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS); groupPermissions[admins] = PermissionFlag.ViewModifyDelete; switch (section) { case PermissionSection.Zones: //ensure DNS administrators group always has all permissions - Group dnsAdmins = _dnsWebService.AuthManager.GetGroup(Group.DNS_ADMINISTRATORS); + Group dnsAdmins = _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS); groupPermissions[dnsAdmins] = PermissionFlag.ViewModifyDelete; break; case PermissionSection.DhcpServer: //ensure DHCP administrators group always has all permissions - Group dhcpAdmins = _dnsWebService.AuthManager.GetGroup(Group.DHCP_ADMINISTRATORS); + Group dhcpAdmins = _dnsWebService._authManager.GetGroup(Group.DHCP_ADMINISTRATORS); groupPermissions[dhcpAdmins] = PermissionFlag.ViewModifyDelete; break; } @@ -999,9 +999,9 @@ namespace DnsServerCore permission.SyncPermissions(groupPermissions); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Permissions were updated successfully for section: " + section.ToString() + (string.IsNullOrEmpty(strSubItem) ? "" : "/" + strSubItem)); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Permissions were updated successfully for section: " + section.ToString() + (string.IsNullOrEmpty(strSubItem) ? "" : "/" + strSubItem)); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SaveConfigFile(); WritePermissionDetails(jsonWriter, permission, strSubItem, false); } diff --git a/DnsServerCore/WebServiceDashboardApi.cs b/DnsServerCore/WebServiceDashboardApi.cs index 33d4a153..f93b0a34 100644 --- a/DnsServerCore/WebServiceDashboardApi.cs +++ b/DnsServerCore/WebServiceDashboardApi.cs @@ -71,7 +71,7 @@ namespace DnsServerCore private async Task> ResolvePtrTopClientsAsync(List> topClients) { - IDictionary dhcpClientIpMap = _dnsWebService.DhcpServer.GetAddressHostNameMap(); + IDictionary dhcpClientIpMap = _dnsWebService._dhcpServer.GetAddressHostNameMap(); async Task> ResolvePtrAsync(string ip) { @@ -83,7 +83,7 @@ namespace DnsServerCore if (IPAddress.IsLoopback(address)) return new KeyValuePair(ip, "localhost"); - DnsDatagram ptrResponse = await _dnsWebService.DnsServer.DirectQueryAsync(new DnsQuestionRecord(address, DnsClass.IN), 500); + DnsDatagram ptrResponse = await _dnsWebService._dnsServer.DirectQueryAsync(new DnsQuestionRecord(address, DnsClass.IN), 500); if (ptrResponse.Answer.Count > 0) { IReadOnlyList ptrDomains = DnsClient.ParseResponsePTR(ptrResponse); @@ -147,12 +147,12 @@ namespace DnsServerCore switch (strType.ToLower()) { case "lasthour": - data = _dnsWebService.DnsServer.StatsManager.GetLastHourMinuteWiseStats(utcFormat); + data = _dnsWebService._dnsServer.StatsManager.GetLastHourMinuteWiseStats(utcFormat); labelFormat = "HH:mm"; break; case "lastday": - data = _dnsWebService.DnsServer.StatsManager.GetLastDayHourWiseStats(utcFormat); + data = _dnsWebService._dnsServer.StatsManager.GetLastDayHourWiseStats(utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD HH:00"; @@ -162,7 +162,7 @@ namespace DnsServerCore break; case "lastweek": - data = _dnsWebService.DnsServer.StatsManager.GetLastWeekDayWiseStats(utcFormat); + data = _dnsWebService._dnsServer.StatsManager.GetLastWeekDayWiseStats(utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD"; @@ -172,7 +172,7 @@ namespace DnsServerCore break; case "lastmonth": - data = _dnsWebService.DnsServer.StatsManager.GetLastMonthDayWiseStats(utcFormat); + data = _dnsWebService._dnsServer.StatsManager.GetLastMonthDayWiseStats(utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD"; @@ -183,7 +183,7 @@ namespace DnsServerCore case "lastyear": labelFormat = "MM/YYYY"; - data = _dnsWebService.DnsServer.StatsManager.GetLastYearMonthWiseStats(utcFormat); + data = _dnsWebService._dnsServer.StatsManager.GetLastYearMonthWiseStats(utcFormat); break; case "custom": @@ -206,7 +206,7 @@ namespace DnsServerCore if ((Convert.ToInt32((endDate - startDate).TotalDays) + 1) > 7) { - data = _dnsWebService.DnsServer.StatsManager.GetDayWiseStats(startDate, endDate, utcFormat); + data = _dnsWebService._dnsServer.StatsManager.GetDayWiseStats(startDate, endDate, utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD"; @@ -215,7 +215,7 @@ namespace DnsServerCore } else { - data = _dnsWebService.DnsServer.StatsManager.GetHourWiseStats(startDate, endDate, utcFormat); + data = _dnsWebService._dnsServer.StatsManager.GetHourWiseStats(startDate, endDate, utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD HH:00"; @@ -239,11 +239,11 @@ namespace DnsServerCore foreach (KeyValuePair item in stats) jsonWriter.WriteNumber(item.Key, item.Value); - jsonWriter.WriteNumber("zones", _dnsWebService.DnsServer.AuthZoneManager.TotalZones); - jsonWriter.WriteNumber("cachedEntries", _dnsWebService.DnsServer.CacheZoneManager.TotalEntries); - jsonWriter.WriteNumber("allowedZones", _dnsWebService.DnsServer.AllowedZoneManager.TotalZonesAllowed); - jsonWriter.WriteNumber("blockedZones", _dnsWebService.DnsServer.BlockedZoneManager.TotalZonesBlocked); - jsonWriter.WriteNumber("blockListZones", _dnsWebService.DnsServer.BlockListZoneManager.TotalZonesBlocked); + jsonWriter.WriteNumber("zones", _dnsWebService._dnsServer.AuthZoneManager.TotalZones); + jsonWriter.WriteNumber("cachedEntries", _dnsWebService._dnsServer.CacheZoneManager.TotalEntries); + jsonWriter.WriteNumber("allowedZones", _dnsWebService._dnsServer.AllowedZoneManager.TotalZonesAllowed); + jsonWriter.WriteNumber("blockedZones", _dnsWebService._dnsServer.BlockedZoneManager.TotalZonesBlocked); + jsonWriter.WriteNumber("blockListZones", _dnsWebService._dnsServer.BlockListZoneManager.TotalZonesBlocked); jsonWriter.WriteEndObject(); } @@ -517,23 +517,23 @@ namespace DnsServerCore switch (strType.ToLower()) { case "lasthour": - topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastHourTopStats(statsType, limit); + topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastHourTopStats(statsType, limit); break; case "lastday": - topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastDayTopStats(statsType, limit); + topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastDayTopStats(statsType, limit); break; case "lastweek": - topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastWeekTopStats(statsType, limit); + topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastWeekTopStats(statsType, limit); break; case "lastmonth": - topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastMonthTopStats(statsType, limit); + topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastMonthTopStats(statsType, limit); break; case "lastyear": - topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastYearTopStats(statsType, limit); + topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastYearTopStats(statsType, limit); break; case "custom": @@ -555,9 +555,9 @@ namespace DnsServerCore throw new DnsWebServiceException("Start date must be less than or equal to end date."); if ((Convert.ToInt32((endDate - startDate).TotalDays) + 1) > 7) - topStatsData = _dnsWebService.DnsServer.StatsManager.GetDayWiseTopStats(startDate, endDate, statsType, limit); + topStatsData = _dnsWebService._dnsServer.StatsManager.GetDayWiseTopStats(startDate, endDate, statsType, limit); else - topStatsData = _dnsWebService.DnsServer.StatsManager.GetHourWiseTopStats(startDate, endDate, statsType, limit); + topStatsData = _dnsWebService._dnsServer.StatsManager.GetHourWiseTopStats(startDate, endDate, statsType, limit); break; diff --git a/DnsServerCore/WebServiceDhcpApi.cs b/DnsServerCore/WebServiceDhcpApi.cs index f42ead9e..43e37b2a 100644 --- a/DnsServerCore/WebServiceDhcpApi.cs +++ b/DnsServerCore/WebServiceDhcpApi.cs @@ -48,7 +48,7 @@ namespace DnsServerCore public void ListDhcpLeases(Utf8JsonWriter jsonWriter) { - IReadOnlyDictionary scopes = _dnsWebService.DhcpServer.Scopes; + IReadOnlyDictionary scopes = _dnsWebService._dhcpServer.Scopes; //sort by name List sortedScopes = new List(scopes.Count); @@ -95,7 +95,7 @@ namespace DnsServerCore public void ListDhcpScopes(Utf8JsonWriter jsonWriter) { - IReadOnlyDictionary scopes = _dnsWebService.DhcpServer.Scopes; + IReadOnlyDictionary scopes = _dnsWebService._dhcpServer.Scopes; //sort by name List sortedScopes = new List(scopes.Count); @@ -135,7 +135,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope == null) throw new DnsWebServiceException("DHCP scope was not found: " + scopeName); @@ -354,7 +354,7 @@ namespace DnsServerCore string strSubnetMask = request.QueryString["subnetMask"]; bool scopeExists; - Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope is null) { //scope does not exists; create new scope @@ -368,7 +368,7 @@ namespace DnsServerCore throw new DnsWebServiceException("Parameter 'subnetMask' missing."); scopeExists = false; - scope = new Scope(scopeName, true, IPAddress.Parse(strStartingAddress), IPAddress.Parse(strEndingAddress), IPAddress.Parse(strSubnetMask), _dnsWebService.Log); + scope = new Scope(scopeName, true, IPAddress.Parse(strStartingAddress), IPAddress.Parse(strEndingAddress), IPAddress.Parse(strSubnetMask), _dnsWebService._log); } else { @@ -393,7 +393,7 @@ namespace DnsServerCore subnetMask = IPAddress.Parse(strSubnetMask); //validate scope address - foreach (KeyValuePair entry in _dnsWebService.DhcpServer.Scopes) + foreach (KeyValuePair entry in _dnsWebService._dhcpServer.Scopes) { Scope existingScope = entry.Value; @@ -694,23 +694,23 @@ namespace DnsServerCore if (scopeExists) { - _dnsWebService.DhcpServer.SaveScope(scopeName); + _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was updated successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was updated successfully: " + scopeName); } else { - await _dnsWebService.DhcpServer.AddScopeAsync(scope); + await _dnsWebService._dhcpServer.AddScopeAsync(scope); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was added successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was added successfully: " + scopeName); } string newName = request.QueryString["newName"]; if (!string.IsNullOrEmpty(newName) && !newName.Equals(scopeName)) { - _dnsWebService.DhcpServer.RenameScope(scopeName, newName); + _dnsWebService._dhcpServer.RenameScope(scopeName, newName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was renamed successfully: '" + scopeName + "' to '" + newName + "'"); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was renamed successfully: '" + scopeName + "' to '" + newName + "'"); } } @@ -720,7 +720,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("No such scope exists: " + scopeName); @@ -741,9 +741,9 @@ namespace DnsServerCore if (!scope.AddReservedLease(reservedLease)) throw new DnsWebServiceException("Failed to add reserved lease for scope: " + scopeName); - _dnsWebService.DhcpServer.SaveScope(scopeName); + _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope reserved lease was added successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope reserved lease was added successfully: " + scopeName); } public void RemoveReservedLease(HttpListenerRequest request) @@ -752,7 +752,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("No such scope exists: " + scopeName); @@ -763,9 +763,9 @@ namespace DnsServerCore if (!scope.RemoveReservedLease(hardwareAddress)) throw new DnsWebServiceException("Failed to remove reserved lease for scope: " + scopeName); - _dnsWebService.DhcpServer.SaveScope(scopeName); + _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope reserved lease was removed successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope reserved lease was removed successfully: " + scopeName); } public async Task EnableDhcpScopeAsync(HttpListenerRequest request) @@ -774,9 +774,9 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - await _dnsWebService.DhcpServer.EnableScopeAsync(scopeName, true); + await _dnsWebService._dhcpServer.EnableScopeAsync(scopeName, true); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was enabled successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was enabled successfully: " + scopeName); } public void DisableDhcpScope(HttpListenerRequest request) @@ -785,9 +785,9 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - _dnsWebService.DhcpServer.DisableScope(scopeName, true); + _dnsWebService._dhcpServer.DisableScope(scopeName, true); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was disabled successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was disabled successfully: " + scopeName); } public void DeleteDhcpScope(HttpListenerRequest request) @@ -796,9 +796,9 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - _dnsWebService.DhcpServer.DeleteScope(scopeName); + _dnsWebService._dhcpServer.DeleteScope(scopeName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was deleted successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was deleted successfully: " + scopeName); } public void RemoveDhcpLease(HttpListenerRequest request) @@ -807,7 +807,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); @@ -821,9 +821,9 @@ namespace DnsServerCore else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); - _dnsWebService.DhcpServer.SaveScope(scopeName); + _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was removed successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was removed successfully: " + scopeName); } public void ConvertToReservedLease(HttpListenerRequest request) @@ -832,7 +832,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope == null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); @@ -846,9 +846,9 @@ namespace DnsServerCore else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); - _dnsWebService.DhcpServer.SaveScope(scopeName); + _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was reserved successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was reserved successfully: " + scopeName); } public void ConvertToDynamicLease(HttpListenerRequest request) @@ -857,7 +857,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(scopeName)) throw new DnsWebServiceException("Parameter 'name' missing."); - Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope == null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); @@ -871,9 +871,9 @@ namespace DnsServerCore else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); - _dnsWebService.DhcpServer.SaveScope(scopeName); + _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was unreserved successfully: " + scopeName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was unreserved successfully: " + scopeName); } #endregion diff --git a/DnsServerCore/WebServiceLogsApi.cs b/DnsServerCore/WebServiceLogsApi.cs index a3e31683..034ec070 100644 --- a/DnsServerCore/WebServiceLogsApi.cs +++ b/DnsServerCore/WebServiceLogsApi.cs @@ -52,7 +52,7 @@ namespace DnsServerCore public void ListLogs(Utf8JsonWriter jsonWriter) { - string[] logFiles = _dnsWebService.Log.ListLogFiles(); + string[] logFiles = _dnsWebService._log.ListLogFiles(); Array.Sort(logFiles); Array.Reverse(logFiles); @@ -86,7 +86,7 @@ namespace DnsServerCore else limit = int.Parse(strLimit); - return _dnsWebService.Log.DownloadLogAsync(request, response, strFileName, limit * 1024 * 1024); + return _dnsWebService._log.DownloadLogAsync(request, response, strFileName, limit * 1024 * 1024); } public void DeleteLog(HttpListenerRequest request) @@ -95,23 +95,23 @@ namespace DnsServerCore if (string.IsNullOrEmpty(log)) throw new DnsWebServiceException("Parameter 'log' missing."); - _dnsWebService.Log.DeleteLog(log); + _dnsWebService._log.DeleteLog(log); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Log file was deleted: " + log); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Log file was deleted: " + log); } public void DeleteAllLogs(HttpListenerRequest request) { - _dnsWebService.Log.DeleteAllLogs(); + _dnsWebService._log.DeleteAllLogs(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] All log files were deleted."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] All log files were deleted."); } public void DeleteAllStats(HttpListenerRequest request) { - _dnsWebService.DnsServer.StatsManager.DeleteAllStats(); + _dnsWebService._dnsServer.StatsManager.DeleteAllStats(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] All stats files were deleted."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] All stats files were deleted."); } public async Task QueryLogsAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -124,7 +124,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(classPath)) throw new DnsWebServiceException("Parameter 'classPath' missing."); - if (!_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) + if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); if (!application.DnsQueryLoggers.TryGetValue(classPath, out IDnsQueryLogger logger)) diff --git a/DnsServerCore/WebServiceOtherZonesApi.cs b/DnsServerCore/WebServiceOtherZonesApi.cs index e5b02e19..5a36bd0b 100644 --- a/DnsServerCore/WebServiceOtherZonesApi.cs +++ b/DnsServerCore/WebServiceOtherZonesApi.cs @@ -52,9 +52,9 @@ namespace DnsServerCore public void FlushCache(HttpListenerRequest request) { - _dnsWebService.DnsServer.CacheZoneManager.Flush(); + _dnsWebService._dnsServer.CacheZoneManager.Flush(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Cache was flushed."); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Cache was flushed."); } public void ListCachedZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -75,8 +75,8 @@ namespace DnsServerCore subZones.Clear(); records.Clear(); - _dnsWebService.DnsServer.CacheZoneManager.ListSubDomains(domain, subZones); - _dnsWebService.DnsServer.CacheZoneManager.ListAllRecords(domain, records); + _dnsWebService._dnsServer.CacheZoneManager.ListSubDomains(domain, subZones); + _dnsWebService._dnsServer.CacheZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; @@ -129,8 +129,8 @@ namespace DnsServerCore if (string.IsNullOrEmpty(domain)) throw new DnsWebServiceException("Parameter 'domain' missing."); - if (_dnsWebService.DnsServer.CacheZoneManager.DeleteZone(domain)) - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Cached zone was deleted: " + domain); + if (_dnsWebService._dnsServer.CacheZoneManager.DeleteZone(domain)) + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Cached zone was deleted: " + domain); } #endregion @@ -155,8 +155,8 @@ namespace DnsServerCore subZones.Clear(); records.Clear(); - _dnsWebService.DnsServer.AllowedZoneManager.ListSubDomains(domain, subZones); - _dnsWebService.DnsServer.AllowedZoneManager.ListAllRecords(domain, records); + _dnsWebService._dnsServer.AllowedZoneManager.ListSubDomains(domain, subZones); + _dnsWebService._dnsServer.AllowedZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; @@ -226,14 +226,14 @@ namespace DnsServerCore foreach (string allowedZone in allowedZones) { - if (_dnsWebService.DnsServer.AllowedZoneManager.AllowZone(allowedZone)) + if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(allowedZone)) added = true; } if (added) { - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Total " + allowedZones.Length + " zones were imported into allowed zone successfully."); - _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Total " + allowedZones.Length + " zones were imported into allowed zone successfully."); + _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } return; @@ -245,7 +245,7 @@ namespace DnsServerCore public void ExportAllowedZones(HttpListenerResponse response) { - IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.AllowedZoneManager.ListZones(); + IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.AllowedZoneManager.ListZones(); response.ContentType = "text/plain"; response.AddHeader("Content-Disposition", "attachment;filename=AllowedZones.txt"); @@ -263,19 +263,19 @@ namespace DnsServerCore if (string.IsNullOrEmpty(domain)) throw new DnsWebServiceException("Parameter 'domain' missing."); - if (_dnsWebService.DnsServer.AllowedZoneManager.DeleteZone(domain)) + if (_dnsWebService._dnsServer.AllowedZoneManager.DeleteZone(domain)) { - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Allowed zone was deleted: " + domain); - _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Allowed zone was deleted: " + domain); + _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } } public void FlushAllowedZone(HttpListenerRequest request) { - _dnsWebService.DnsServer.AllowedZoneManager.Flush(); + _dnsWebService._dnsServer.AllowedZoneManager.Flush(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Allowed zone was flushed successfully."); - _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Allowed zone was flushed successfully."); + _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } public void AllowZone(HttpListenerRequest request) @@ -287,10 +287,10 @@ namespace DnsServerCore if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); - if (_dnsWebService.DnsServer.AllowedZoneManager.AllowZone(domain)) + if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(domain)) { - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Zone was allowed: " + domain); - _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Zone was allowed: " + domain); + _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } } @@ -316,8 +316,8 @@ namespace DnsServerCore subZones.Clear(); records.Clear(); - _dnsWebService.DnsServer.BlockedZoneManager.ListSubDomains(domain, subZones); - _dnsWebService.DnsServer.BlockedZoneManager.ListAllRecords(domain, records); + _dnsWebService._dnsServer.BlockedZoneManager.ListSubDomains(domain, subZones); + _dnsWebService._dnsServer.BlockedZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; @@ -387,14 +387,14 @@ namespace DnsServerCore foreach (string blockedZone in blockedZones) { - if (_dnsWebService.DnsServer.BlockedZoneManager.BlockZone(blockedZone)) + if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(blockedZone)) added = true; } if (added) { - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Total " + blockedZones.Length + " zones were imported into blocked zone successfully."); - _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Total " + blockedZones.Length + " zones were imported into blocked zone successfully."); + _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } return; @@ -406,7 +406,7 @@ namespace DnsServerCore public void ExportBlockedZones(HttpListenerResponse response) { - IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.BlockedZoneManager.ListZones(); + IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.BlockedZoneManager.ListZones(); response.ContentType = "text/plain"; response.AddHeader("Content-Disposition", "attachment;filename=BlockedZones.txt"); @@ -424,19 +424,19 @@ namespace DnsServerCore if (string.IsNullOrEmpty(domain)) throw new DnsWebServiceException("Parameter 'domain' missing."); - if (_dnsWebService.DnsServer.BlockedZoneManager.DeleteZone(domain)) + if (_dnsWebService._dnsServer.BlockedZoneManager.DeleteZone(domain)) { - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocked zone was deleted: " + domain); - _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocked zone was deleted: " + domain); + _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } } public void FlushBlockedZone(HttpListenerRequest request) { - _dnsWebService.DnsServer.BlockedZoneManager.Flush(); + _dnsWebService._dnsServer.BlockedZoneManager.Flush(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocked zone was flushed successfully."); - _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocked zone was flushed successfully."); + _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } public void BlockZone(HttpListenerRequest request) @@ -448,10 +448,10 @@ namespace DnsServerCore if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); - if (_dnsWebService.DnsServer.BlockedZoneManager.BlockZone(domain)) + if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(domain)) { - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Domain was added to blocked zone: " + domain); - _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Domain was added to blocked zone: " + domain); + _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } } diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index 4c9a44d1..279b9800 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -681,7 +681,7 @@ namespace DnsServerCore public void ListZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) { - List zones = _dnsWebService.DnsServer.AuthZoneManager.ListZones(); + List zones = _dnsWebService._dnsServer.AuthZoneManager.ListZones(); zones.Sort(); UserSession session = _dnsWebService.GetSession(request); @@ -691,7 +691,7 @@ namespace DnsServerCore foreach (AuthZoneInfo zone in zones) { - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zone.Name, session.User, PermissionFlag.View)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zone.Name, session.User, PermissionFlag.View)) continue; WriteZoneInfoAsJson(zone, jsonWriter); @@ -738,20 +738,20 @@ namespace DnsServerCore { case AuthZoneType.Primary: { - zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(zoneName, _dnsWebService.DnsServer.ServerDomain, false); + zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(zoneName, _dnsWebService._dnsServer.ServerDomain, false); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); UserSession session = _dnsWebService.GetSession(request); //set permissions - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Authoritative primary zone was created: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Authoritative primary zone was created: " + zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; @@ -773,20 +773,20 @@ namespace DnsServerCore if (string.IsNullOrEmpty(tsigKeyName)) tsigKeyName = null; - zoneInfo = await _dnsWebService.DnsServer.AuthZoneManager.CreateSecondaryZoneAsync(zoneName, primaryNameServerAddresses, zoneTransferProtocol, tsigKeyName); + zoneInfo = await _dnsWebService._dnsServer.AuthZoneManager.CreateSecondaryZoneAsync(zoneName, primaryNameServerAddresses, zoneTransferProtocol, tsigKeyName); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); UserSession session = _dnsWebService.GetSession(request); //set permissions - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Authoritative secondary zone was created: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Authoritative secondary zone was created: " + zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; @@ -796,20 +796,20 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strPrimaryNameServerAddresses)) strPrimaryNameServerAddresses = null; - zoneInfo = await _dnsWebService.DnsServer.AuthZoneManager.CreateStubZoneAsync(zoneName, strPrimaryNameServerAddresses); + zoneInfo = await _dnsWebService._dnsServer.AuthZoneManager.CreateStubZoneAsync(zoneName, strPrimaryNameServerAddresses); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); UserSession session = _dnsWebService.GetSession(request); //set permissions - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Stub zone was created: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Stub zone was created: " + zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; @@ -854,20 +854,20 @@ namespace DnsServerCore proxyPassword = request.QueryString["proxyPassword"]; } - zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreateForwarderZone(zoneName, forwarderProtocol, strForwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, null); + zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreateForwarderZone(zoneName, forwarderProtocol, strForwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, null); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); UserSession session = _dnsWebService.GetSession(request); //set permissions - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Forwarder zone was created: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Forwarder zone was created: " + zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; @@ -876,7 +876,7 @@ namespace DnsServerCore } //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones - _dnsWebService.DnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); + _dnsWebService._dnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); jsonWriter.WriteString("domain", string.IsNullOrEmpty(zoneInfo.Name) ? "." : zoneInfo.Name); } @@ -891,7 +891,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string algorithm = request.QueryString["algorithm"]; @@ -964,9 +964,9 @@ namespace DnsServerCore int zskKeySize = int.Parse(strZSKKeySize); if (useNSEC3) - _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC3(zoneName, hashAlgorithm, kskKeySize, zskKeySize, iterations, saltLength, dnsKeyTtl, zskRolloverDays); + _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC3(zoneName, hashAlgorithm, kskKeySize, zskKeySize, iterations, saltLength, dnsKeyTtl, zskRolloverDays); else - _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC(zoneName, hashAlgorithm, kskKeySize, zskKeySize, dnsKeyTtl, zskRolloverDays); + _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC(zoneName, hashAlgorithm, kskKeySize, zskKeySize, dnsKeyTtl, zskRolloverDays); break; @@ -976,9 +976,9 @@ namespace DnsServerCore throw new DnsWebServiceException("Parameter 'curve' missing."); if (useNSEC3) - _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC3(zoneName, curve, iterations, saltLength, dnsKeyTtl, zskRolloverDays); + _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC3(zoneName, curve, iterations, saltLength, dnsKeyTtl, zskRolloverDays); else - _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC(zoneName, curve, dnsKeyTtl, zskRolloverDays); + _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC(zoneName, curve, dnsKeyTtl, zskRolloverDays); break; @@ -986,9 +986,9 @@ namespace DnsServerCore throw new NotSupportedException("Algorithm is not supported: " + algorithm); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was signed successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was signed successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UnsignPrimaryZone(HttpListenerRequest request) @@ -1001,14 +1001,14 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService.DnsServer.AuthZoneManager.UnsignPrimaryZone(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.UnsignPrimaryZone(zoneName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was unsigned successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was unsigned successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void GetPrimaryZoneDnssecProperties(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -1019,7 +1019,7 @@ namespace DnsServerCore zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No such zone was found: " + zoneName); @@ -1031,7 +1031,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); jsonWriter.WriteString("name", zoneInfo.Name); @@ -1116,14 +1116,14 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService.DnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC(zoneName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was converted to NSEC successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was converted to NSEC successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void ConvertPrimaryZoneToNSEC3(HttpListenerRequest request) @@ -1136,7 +1136,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); ushort iterations = 0; @@ -1149,11 +1149,11 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(strSaltLength)) saltLength = byte.Parse(strSaltLength); - _dnsWebService.DnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC3(zoneName, iterations, saltLength); + _dnsWebService._dnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC3(zoneName, iterations, saltLength); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was converted to NSEC3 successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was converted to NSEC3 successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UpdatePrimaryZoneNSEC3Parameters(HttpListenerRequest request) @@ -1166,7 +1166,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); ushort iterations = 0; @@ -1179,11 +1179,11 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(strSaltLength)) saltLength = byte.Parse(strSaltLength); - _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneNSEC3Parameters(zoneName, iterations, saltLength); + _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneNSEC3Parameters(zoneName, iterations, saltLength); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone NSEC3 parameters were updated successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone NSEC3 parameters were updated successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UpdatePrimaryZoneDnssecDnsKeyTtl(HttpListenerRequest request) @@ -1196,7 +1196,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strDnsKeyTtl = request.QueryString["ttl"]; @@ -1205,11 +1205,11 @@ namespace DnsServerCore uint dnsKeyTtl = uint.Parse(strDnsKeyTtl); - _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneDnsKeyTtl(zoneName, dnsKeyTtl); + _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneDnsKeyTtl(zoneName, dnsKeyTtl); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone DNSKEY TTL was updated successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone DNSKEY TTL was updated successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void GenerateAndAddPrimaryZoneDnssecPrivateKey(HttpListenerRequest request) @@ -1222,7 +1222,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strKeyType = request.QueryString["keyType"]; @@ -1255,7 +1255,7 @@ namespace DnsServerCore int keySize = int.Parse(strKeySize); - _dnsWebService.DnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecRsaPrivateKey(zoneName, keyType, hashAlgorithm, keySize, rolloverDays); + _dnsWebService._dnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecRsaPrivateKey(zoneName, keyType, hashAlgorithm, keySize, rolloverDays); break; case "ECDSA": @@ -1263,16 +1263,16 @@ namespace DnsServerCore if (string.IsNullOrEmpty(curve)) throw new DnsWebServiceException("Parameter 'curve' missing."); - _dnsWebService.DnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecEcdsaPrivateKey(zoneName, keyType, curve, rolloverDays); + _dnsWebService._dnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecEcdsaPrivateKey(zoneName, keyType, curve, rolloverDays); break; default: throw new NotSupportedException("Algorithm is not supported: " + algorithm); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] DNSSEC private key was generated and added to the primary zone successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] DNSSEC private key was generated and added to the primary zone successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UpdatePrimaryZoneDnssecPrivateKey(HttpListenerRequest request) @@ -1285,7 +1285,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strKeyTag = request.QueryString["keyTag"]; @@ -1300,11 +1300,11 @@ namespace DnsServerCore ushort rolloverDays = ushort.Parse(strRolloverDays); - _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneDnssecPrivateKey(zoneName, keyTag, rolloverDays); + _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneDnssecPrivateKey(zoneName, keyTag, rolloverDays); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone DNSSEC private key config was updated successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone DNSSEC private key config was updated successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void DeletePrimaryZoneDnssecPrivateKey(HttpListenerRequest request) @@ -1317,7 +1317,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strKeyTag = request.QueryString["keyTag"]; @@ -1326,11 +1326,11 @@ namespace DnsServerCore ushort keyTag = ushort.Parse(strKeyTag); - _dnsWebService.DnsServer.AuthZoneManager.DeletePrimaryZoneDnssecPrivateKey(zoneName, keyTag); + _dnsWebService._dnsServer.AuthZoneManager.DeletePrimaryZoneDnssecPrivateKey(zoneName, keyTag); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] DNSSEC private key was deleted from primary zone successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] DNSSEC private key was deleted from primary zone successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(HttpListenerRequest request) @@ -1343,14 +1343,14 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService.DnsServer.AuthZoneManager.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(zoneName); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] All DNSSEC private keys from the primary zone were published successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] All DNSSEC private keys from the primary zone were published successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void RolloverPrimaryZoneDnsKey(HttpListenerRequest request) @@ -1363,7 +1363,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strKeyTag = request.QueryString["keyTag"]; @@ -1372,11 +1372,11 @@ namespace DnsServerCore ushort keyTag = ushort.Parse(strKeyTag); - _dnsWebService.DnsServer.AuthZoneManager.RolloverPrimaryZoneDnsKey(zoneName, keyTag); + _dnsWebService._dnsServer.AuthZoneManager.RolloverPrimaryZoneDnsKey(zoneName, keyTag); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was rolled over successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was rolled over successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void RetirePrimaryZoneDnsKey(HttpListenerRequest request) @@ -1389,7 +1389,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strKeyTag = request.QueryString["keyTag"]; @@ -1398,11 +1398,11 @@ namespace DnsServerCore ushort keyTag = ushort.Parse(strKeyTag); - _dnsWebService.DnsServer.AuthZoneManager.RetirePrimaryZoneDnsKey(zoneName, keyTag); + _dnsWebService._dnsServer.AuthZoneManager.RetirePrimaryZoneDnsKey(zoneName, keyTag); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was retired successfully: " + zoneName); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was retired successfully: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void DeleteZone(HttpListenerRequest request) @@ -1416,7 +1416,7 @@ namespace DnsServerCore zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No such zone was found: " + zoneName); @@ -1425,17 +1425,17 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - if (!_dnsWebService.DnsServer.AuthZoneManager.DeleteZone(zoneInfo.Name)) + if (!_dnsWebService._dnsServer.AuthZoneManager.DeleteZone(zoneInfo.Name)) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneInfo.Name); - _dnsWebService.AuthManager.RemoveAllPermissions(PermissionSection.Zones, zoneInfo.Name); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.RemoveAllPermissions(PermissionSection.Zones, zoneInfo.Name); + _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was deleted: " + zoneName); - _dnsWebService.DnsServer.AuthZoneManager.DeleteZoneFile(zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was deleted: " + zoneName); + _dnsWebService._dnsServer.AuthZoneManager.DeleteZoneFile(zoneInfo.Name); } public void EnableZone(HttpListenerRequest request) @@ -1449,7 +1449,7 @@ namespace DnsServerCore zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1458,17 +1458,17 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); zoneInfo.Disabled = false; - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was enabled: " + zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was enabled: " + zoneInfo.Name); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones - _dnsWebService.DnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); + _dnsWebService._dnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); } public void DisableZone(HttpListenerRequest request) @@ -1482,7 +1482,7 @@ namespace DnsServerCore zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1491,14 +1491,14 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); zoneInfo.Disabled = true; - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was disabled: " + zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was disabled: " + zoneInfo.Name); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } public void GetZoneOptions(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -1519,7 +1519,7 @@ namespace DnsServerCore else includeAvailableTsigKeyNames = bool.Parse(strIncludeAvailableTsigKeyNames); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No such zone was found: " + zoneName); @@ -1528,7 +1528,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); jsonWriter.WriteString("name", zoneInfo.Name); @@ -1655,9 +1655,9 @@ namespace DnsServerCore { jsonWriter.WriteStartArray(); - if (_dnsWebService.DnsServer.TsigKeys is not null) + if (_dnsWebService._dnsServer.TsigKeys is not null) { - foreach (KeyValuePair tsigKey in _dnsWebService.DnsServer.TsigKeys) + foreach (KeyValuePair tsigKey in _dnsWebService._dnsServer.TsigKeys) jsonWriter.WriteStringValue(tsigKey.Key); } @@ -1677,7 +1677,7 @@ namespace DnsServerCore zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1686,7 +1686,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strDisabled = request.QueryString["disabled"]; @@ -1833,9 +1833,9 @@ namespace DnsServerCore break; } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone options were updated successfully: " + zoneInfo.Name); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone options were updated successfully: " + zoneInfo.Name); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } public void ResyncZone(HttpListenerRequest request) @@ -1849,7 +1849,7 @@ namespace DnsServerCore zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1858,7 +1858,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); switch (zoneInfo.Type) @@ -1885,7 +1885,7 @@ namespace DnsServerCore if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -1894,7 +1894,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); string strType = request.QueryString["type"]; @@ -1951,7 +1951,7 @@ namespace DnsServerCore { string ptrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); + AuthZoneInfo reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); if (reverseZoneInfo is null) { bool createPtrZone = false; @@ -1964,15 +1964,15 @@ namespace DnsServerCore string ptrZone = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 24 : 64); - reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService.DnsServer.ServerDomain, false); + reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService._dnsServer.ServerDomain, false); if (reverseZoneInfo == null) throw new DnsServerException("Failed to create reverse zone to add PTR record: " + ptrZone); //set permissions - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SaveConfigFile(); } if (reverseZoneInfo.Internal) @@ -1981,8 +1981,8 @@ namespace DnsServerCore if (reverseZoneInfo.Type != AuthZoneType.Primary) throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is not a primary zone."); - _dnsWebService.DnsServer.AuthZoneManager.SetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); } if (type == DnsResourceRecordType.A) @@ -1994,9 +1994,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2024,9 +2024,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2034,7 +2034,7 @@ namespace DnsServerCore { if (!overwrite) { - IReadOnlyList existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); + IReadOnlyList existingRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); if (existingRecords.Count > 0) throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } @@ -2053,7 +2053,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); } break; @@ -2074,9 +2074,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2101,9 +2101,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2124,9 +2124,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2159,9 +2159,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2169,7 +2169,7 @@ namespace DnsServerCore { if (!overwrite) { - IReadOnlyList existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); + IReadOnlyList existingRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); if (existingRecords.Count > 0) throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } @@ -2188,7 +2188,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); } break; @@ -2221,9 +2221,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2247,9 +2247,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2277,9 +2277,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2302,9 +2302,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2325,9 +2325,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2386,9 +2386,9 @@ namespace DnsServerCore newRecord.SetComments(comments); if (overwrite) - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -2413,7 +2413,7 @@ namespace DnsServerCore if (!overwrite) { - IReadOnlyList existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); + IReadOnlyList existingRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); if (existingRecords.Count > 0) throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } @@ -2423,7 +2423,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); } break; @@ -2431,9 +2431,9 @@ namespace DnsServerCore throw new DnsWebServiceException("Type not supported for AddRecords()."); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] New record was added to authoritative zone {domain: " + domain + "; type: " + type + "; value: " + value + "; ttl: " + ttl + ";}"); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] New record was added to authoritative zone {domain: " + domain + "; type: " + type + "; value: " + value + "; ttl: " + ttl + ";}"); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); jsonWriter.WritePropertyName("zone"); WriteZoneInfoAsJson(zoneInfo, jsonWriter); @@ -2450,20 +2450,20 @@ namespace DnsServerCore domain = domain.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(domain); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(domain); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); jsonWriter.WritePropertyName("zone"); WriteZoneInfoAsJson(zoneInfo, jsonWriter); List records = new List(); - _dnsWebService.DnsServer.AuthZoneManager.ListAllRecords(domain, records); + _dnsWebService._dnsServer.AuthZoneManager.ListAllRecords(domain, records); WriteRecordsAsJson(records, jsonWriter, true, zoneInfo); } @@ -2480,7 +2480,7 @@ namespace DnsServerCore if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -2489,7 +2489,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string strType = request.QueryString["type"]; @@ -2517,15 +2517,15 @@ namespace DnsServerCore IPAddress ipAddress = IPAddress.Parse(strIPAddress); if (type == DnsResourceRecordType.A) - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsARecordData(ipAddress)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsARecordData(ipAddress)); else - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsAAAARecordData(ipAddress)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsAAAARecordData(ipAddress)); string ptrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); + AuthZoneInfo reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); if ((reverseZoneInfo != null) && !reverseZoneInfo.Internal && (reverseZoneInfo.Type == AuthZoneType.Primary)) { - IReadOnlyList ptrRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR); + IReadOnlyList ptrRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR); if (ptrRecords.Count > 0) { foreach (DnsResourceRecord ptrRecord in ptrRecords) @@ -2533,8 +2533,8 @@ namespace DnsServerCore if ((ptrRecord.RDATA as DnsPTRRecordData).Domain.Equals(domain, StringComparison.OrdinalIgnoreCase)) { //delete PTR record and save reverse zone - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ptrRecord.RDATA); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ptrRecord.RDATA); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); break; } } @@ -2554,12 +2554,12 @@ namespace DnsServerCore nameServer = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsNSRecordData(nameServer)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsNSRecordData(nameServer)); } break; case DnsResourceRecordType.CNAME: - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); break; case DnsResourceRecordType.PTR: @@ -2573,7 +2573,7 @@ namespace DnsServerCore ptrName = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsPTRRecordData(ptrName)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsPTRRecordData(ptrName)); } break; @@ -2592,7 +2592,7 @@ namespace DnsServerCore exchange = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsMXRecordData(ushort.Parse(preference), exchange)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsMXRecordData(ushort.Parse(preference), exchange)); } break; @@ -2607,7 +2607,7 @@ namespace DnsServerCore text = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTXTRecordData(text)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTXTRecordData(text)); } break; @@ -2634,12 +2634,12 @@ namespace DnsServerCore target = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSRVRecordData(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), target)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSRVRecordData(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), target)); } break; case DnsResourceRecordType.DNAME: - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); break; case DnsResourceRecordType.DS: @@ -2665,7 +2665,7 @@ namespace DnsServerCore digest = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsDSRecordData(ushort.Parse(strKeyTag), Enum.Parse(strAlgorithm.Replace('-', '_'), true), Enum.Parse(strDigestType.Replace('-', '_'), true), Convert.FromHexString(digest))); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsDSRecordData(ushort.Parse(strKeyTag), Enum.Parse(strAlgorithm.Replace('-', '_'), true), Enum.Parse(strDigestType.Replace('-', '_'), true), Convert.FromHexString(digest))); } break; @@ -2683,7 +2683,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strFingerprint)) throw new DnsWebServiceException("Parameter 'sshfpFingerprint' missing."); - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(Enum.Parse(strAlgorithm, true), Enum.Parse(strFingerprintType, true), Convert.FromHexString(strFingerprint))); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(Enum.Parse(strAlgorithm, true), Enum.Parse(strFingerprintType, true), Convert.FromHexString(strFingerprint))); } break; @@ -2705,7 +2705,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(strCertificateAssociationData)) throw new DnsWebServiceException("Parameter 'tlsaCertificateAssociationData' missing."); - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTLSARecordData(Enum.Parse(strCertificateUsage.Replace('-', '_'), true), Enum.Parse(strSelector, true), Enum.Parse(strMatchingType.Replace('-', '_'), true), strCertificateAssociationData)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTLSARecordData(Enum.Parse(strCertificateUsage.Replace('-', '_'), true), Enum.Parse(strSelector, true), Enum.Parse(strMatchingType.Replace('-', '_'), true), strCertificateAssociationData)); } break; @@ -2722,7 +2722,7 @@ namespace DnsServerCore if (string.IsNullOrEmpty(value)) throw new DnsWebServiceException("Parameter 'value' missing."); - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsCAARecordData(byte.Parse(flags), tag, value)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsCAARecordData(byte.Parse(flags), tag, value)); } break; @@ -2737,7 +2737,7 @@ namespace DnsServerCore aname = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsANAMERecordData(aname)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsANAMERecordData(aname)); } break; @@ -2756,21 +2756,21 @@ namespace DnsServerCore forwarder = value; } - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsForwarderRecordData(Enum.Parse(strProtocol, true), forwarder)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsForwarderRecordData(Enum.Parse(strProtocol, true), forwarder)); } break; case DnsResourceRecordType.APP: - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); break; default: throw new DnsWebServiceException("Type not supported for DeleteRecord()."); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Record was deleted from authoritative zone {domain: " + domain + "; type: " + type + ";}"); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Record was deleted from authoritative zone {domain: " + domain + "; type: " + type + ";}"); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } public void UpdateRecord(HttpListenerRequest request, Utf8JsonWriter jsonWriter) @@ -2791,7 +2791,7 @@ namespace DnsServerCore if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); + AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -2800,7 +2800,7 @@ namespace DnsServerCore UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService.AuthManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); string newDomain = request.QueryString["newDomain"]; @@ -2863,7 +2863,7 @@ namespace DnsServerCore { string ptrDomain = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); + AuthZoneInfo reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); if (reverseZoneInfo == null) { bool createPtrZone = false; @@ -2876,15 +2876,15 @@ namespace DnsServerCore string ptrZone = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 24 : 64); - reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService.DnsServer.ServerDomain, false); + reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService._dnsServer.ServerDomain, false); if (reverseZoneInfo is null) throw new DnsServerException("Failed to create reverse zone to add PTR record: " + ptrZone); //set permissions - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService.AuthManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService.AuthManager.SaveConfigFile(); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SaveConfigFile(); } if (reverseZoneInfo.Internal) @@ -2895,17 +2895,17 @@ namespace DnsServerCore string oldPtrDomain = Zone.GetReverseZone(oldIpAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo oldReverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(oldPtrDomain); + AuthZoneInfo oldReverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(oldPtrDomain); if ((oldReverseZoneInfo != null) && !oldReverseZoneInfo.Internal && (oldReverseZoneInfo.Type == AuthZoneType.Primary)) { //delete old PTR record if any and save old reverse zone - _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(oldReverseZoneInfo.Name, oldPtrDomain, DnsResourceRecordType.PTR); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(oldReverseZoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(oldReverseZoneInfo.Name, oldPtrDomain, DnsResourceRecordType.PTR); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(oldReverseZoneInfo.Name); } //add new PTR record and save reverse zone - _dnsWebService.DnsServer.AuthZoneManager.SetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); } DnsResourceRecord oldRecord; @@ -2927,7 +2927,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -2964,7 +2964,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(glueAddresses)) newRecord.SetGlueRecords(glueAddresses); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -2988,7 +2988,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3053,7 +3053,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newSOARecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newSOARecord); + _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newSOARecord); newRecord = zoneInfo.GetApexRecords(DnsResourceRecordType.SOA)[0]; } @@ -3088,7 +3088,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3129,7 +3129,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3162,7 +3162,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3219,7 +3219,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3243,7 +3243,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3300,7 +3300,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3339,7 +3339,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3386,7 +3386,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3423,7 +3423,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3456,7 +3456,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3532,7 +3532,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3564,7 +3564,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -3572,9 +3572,9 @@ namespace DnsServerCore throw new DnsWebServiceException("Type not supported for UpdateRecords()."); } - _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Record was updated for authoritative zone {oldDomain: " + domain + "; domain: " + newDomain + "; type: " + type + "; oldValue: " + value + "; value: " + newValue + "; ttl: " + ttl + "; disabled: " + disable + ";}"); + _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Record was updated for authoritative zone {oldDomain: " + domain + "; domain: " + newDomain + "; type: " + type + "; oldValue: " + value + "; value: " + newValue + "; ttl: " + ttl + "; disabled: " + disable + ";}"); - _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); jsonWriter.WritePropertyName("zone"); WriteZoneInfoAsJson(zoneInfo, jsonWriter); From a225065ba589227b7670f8412970ab28959a1c81 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:30:58 +0530 Subject: [PATCH 041/191] User: minor fix for correcting the order. --- DnsServerCore/Auth/User.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Auth/User.cs b/DnsServerCore/Auth/User.cs index e13c1f7e..f1ae2b0d 100644 --- a/DnsServerCore/Auth/User.cs +++ b/DnsServerCore/Auth/User.cs @@ -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 @@ -66,8 +66,8 @@ namespace DnsServerCore.Auth public User(string displayName, string username, string password, int iterations = DEFAULT_ITERATIONS) { - DisplayName = displayName; Username = username; + DisplayName = displayName; ChangePassword(password, iterations); From 32474604f4559e7475d26adcae4e8b19f98221ac Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:31:51 +0530 Subject: [PATCH 042/191] DnsResourceRecordExtension: code refactoring changes. --- .../DnsResourceRecordExtension.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs index 54a71deb..ce5e017a 100644 --- a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs +++ b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2021 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 @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -42,13 +43,7 @@ namespace DnsServerCore.Dns.ResourceRecords public static void SetGlueRecords(this DnsResourceRecord record, string glueAddresses) { - string[] addresses = glueAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List ipAddresses = new List(addresses.Length); - - foreach (string address in addresses) - ipAddresses.Add(IPAddress.Parse(address.Trim())); - - SetGlueRecords(record, ipAddresses); + SetGlueRecords(record, glueAddresses.Split(IPAddress.Parse, ',')); } public static void SetGlueRecords(this DnsResourceRecord record, IReadOnlyList glueAddresses) @@ -234,13 +229,7 @@ namespace DnsServerCore.Dns.ResourceRecords public static void SetPrimaryNameServers(this DnsResourceRecord record, string primaryNameServers) { - string[] nameServerAddresses = primaryNameServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List nameServers = new List(nameServerAddresses.Length); - - foreach (string nameServerAddress in nameServerAddresses) - nameServers.Add(new NameServerAddress(nameServerAddress)); - - SetPrimaryNameServers(record, nameServers); + SetPrimaryNameServers(record, primaryNameServers.Split(NameServerAddress.Parse, ',')); } public static IReadOnlyList GetPrimaryNameServers(this DnsResourceRecord record) From 056eaba803d06e3e419b6d9d4c37dbef777cdec0 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:32:58 +0530 Subject: [PATCH 043/191] webapp: fixed file upload content type header issue. --- DnsServerCore/www/js/apps.js | 4 +++- DnsServerCore/www/js/main.js | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/www/js/apps.js b/DnsServerCore/www/js/apps.js index c601c4e3..c1ff2ef1 100644 --- a/DnsServerCore/www/js/apps.js +++ b/DnsServerCore/www/js/apps.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 @@ -344,6 +344,7 @@ function installApp() { url: "/api/apps/install?token=" + sessionData.token + "&name=" + encodeURIComponent(appName), method: "POST", data: formData, + dataContentType: false, processData: false, success: function (responseJSON) { $("#modalInstallApp").modal("hide"); @@ -385,6 +386,7 @@ function updateApp() { url: "/api/apps/update?token=" + sessionData.token + "&name=" + encodeURIComponent(appName), method: "POST", data: formData, + dataContentType: false, processData: false, success: function (responseJSON) { $("#modalUpdateApp").modal("hide"); diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index 28fbc7ca..f2c8c082 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.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 @@ -2300,6 +2300,7 @@ function restoreSettings() { url: "/api/settings/restore?token=" + sessionData.token + "&blockLists=" + blockLists + "&logs=" + logs + "&scopes=" + scopes + "&apps=" + apps + "&stats=" + stats + "&zones=" + zones + "&allowedZones=" + allowedZones + "&blockedZones=" + blockedZones + "&dnsSettings=" + dnsSettings + "&authConfig=" + authConfig + "&logSettings=" + logSettings + "&deleteExistingFiles=" + deleteExistingFiles, method: "POST", data: formData, + dataContentType: false, processData: false, success: function (responseJSON) { document.title = responseJSON.response.dnsServerDomain + " - " + "Technitium DNS Server v" + responseJSON.response.version; From 230ad2c13306b4ca9a13a79b5914efb37c0dc436 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:35:40 +0530 Subject: [PATCH 044/191] Extensions: implemented common extension methods. --- DnsServerCore/Extensions.cs | 212 ++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 DnsServerCore/Extensions.cs diff --git a/DnsServerCore/Extensions.cs b/DnsServerCore/Extensions.cs new file mode 100644 index 00000000..4b4cbc12 --- /dev/null +++ b/DnsServerCore/Extensions.cs @@ -0,0 +1,212 @@ +/* +Technitium DNS Server +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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using DnsServerCore.Auth; +using Microsoft.AspNetCore.Http; +using System; +using System.Net; +using System.Text.Json; +using TechnitiumLibrary.Net; + +namespace DnsServerCore +{ + static class Extensions + { + public static IPEndPoint GetRemoteEndPoint(this HttpContext context) + { + try + { + if (context.Connection.RemoteIpAddress is null) + return new IPEndPoint(IPAddress.Any, 0); + + if (NetUtilities.IsPrivateIP(context.Connection.RemoteIpAddress)) + { + string xRealIp = context.Request.Headers["X-Real-IP"]; + if (IPAddress.TryParse(xRealIp, out IPAddress address)) + { + //get the real IP address of the requesting client from X-Real-IP header set in nginx proxy_pass block + return new IPEndPoint(address, 0); + } + } + + return new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort); + } + catch + { + return new IPEndPoint(IPAddress.Any, 0); + } + } + + public static UserSession GetCurrentSession(this HttpContext context) + { + if (context.Items["session"] is UserSession userSession) + return userSession; + + throw new InvalidOperationException(); + } + + public static Utf8JsonWriter GetCurrentJsonWriter(this HttpContext context) + { + if (context.Items["jsonWriter"] is Utf8JsonWriter jsonWriter) + return jsonWriter; + + throw new InvalidOperationException(); + } + + public static string GetQuery(this HttpRequest request, string parameter) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); + + return value; + } + + public static string GetQuery(this HttpRequest request, string parameter, string defaultValue) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + return defaultValue; + + return value; + } + + public static T GetQuery(this HttpRequest request, string parameter, Func parse) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); + + return parse(value); + } + + public static T GetQuery(this HttpRequest request, string parameter) where T : struct + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); + + return Enum.Parse(value, true); + } + + public static T GetQuery(this HttpRequest request, string parameter, Func parse, T defaultValue) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + return defaultValue; + + return parse(value); + } + + public static T GetQuery(this HttpRequest request, string parameter, T defaultValue) where T : struct + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + return defaultValue; + + return Enum.Parse(value, true); + } + + public static bool TryGetQuery(this HttpRequest request, string parameter, out string value) + { + value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + return false; + + return true; + } + + public static bool TryGetQuery(this HttpRequest request, string parameter, Func parse, out T value) + { + string strValue = request.Query[parameter]; + if (string.IsNullOrEmpty(strValue)) + { + value = default; + return false; + } + + value = parse(strValue); + return true; + } + + public static bool TryGetQuery(this HttpRequest request, string parameter, out T value) where T : struct + { + string strValue = request.Query[parameter]; + if (string.IsNullOrEmpty(strValue)) + { + value = default; + return false; + } + + return Enum.TryParse(strValue, true, out value); + } + + public static string GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + { + value = request.Query[alternateParameter]; + if (string.IsNullOrEmpty(value)) + throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); + } + + return value; + } + + public static string GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter, string defaultValue) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + { + value = request.Query[alternateParameter]; + if (string.IsNullOrEmpty(value)) + return defaultValue; + } + + return value; + } + + public static T GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter, Func parse) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + { + value = request.Query[alternateParameter]; + if (string.IsNullOrEmpty(value)) + throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); + } + + return parse(value); + } + + public static T GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter, Func parse, T defaultValue) + { + string value = request.Query[parameter]; + if (string.IsNullOrEmpty(value)) + { + value = request.Query[alternateParameter]; + if (string.IsNullOrEmpty(value)) + return defaultValue; + } + + return parse(value); + } + } +} From 65669d9c9e1e4f9d6472c9dc0543efefc5cdf314 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:36:27 +0530 Subject: [PATCH 045/191] DnsServerApp: minor change. --- DnsServerApp/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerApp/Program.cs b/DnsServerApp/Program.cs index 0f7066a8..88359e8a 100644 --- a/DnsServerApp/Program.cs +++ b/DnsServerApp/Program.cs @@ -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 @@ -69,7 +69,7 @@ namespace DnsServerApp Console.WriteLine("Technitium DNS Server was started successfully."); Console.WriteLine("Using config folder: " + service.ConfigFolder); Console.WriteLine(""); - Console.WriteLine("Note: Open http://" + service.WebServiceHostname + ":" + service.WebServiceHttpPort + "/ in web browser to access web console."); + Console.WriteLine("Note: Open http://" + Environment.MachineName.ToLowerInvariant() + ":" + service.WebServiceHttpPort + "/ in web browser to access web console."); Console.WriteLine(""); Console.WriteLine("Press [CTRL + C] to stop..."); From 3e0ab54ba0bfc10249f99652b12981dc0cb857c5 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:37:28 +0530 Subject: [PATCH 046/191] DnsServerWindowsService: using async methods. --- DnsServerWindowsService/DnsServiceWorker.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/DnsServerWindowsService/DnsServiceWorker.cs b/DnsServerWindowsService/DnsServiceWorker.cs index 2f6d367d..ec8ce504 100644 --- a/DnsServerWindowsService/DnsServiceWorker.cs +++ b/DnsServerWindowsService/DnsServiceWorker.cs @@ -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 @@ -42,19 +42,16 @@ namespace DnsServerWindowsService _service = new DnsWebService(configFolder, new Uri("https://go.technitium.com/?id=43"), new Uri("https://go.technitium.com/?id=44")); } - public override Task StartAsync(CancellationToken cancellationToken) + public override async Task StartAsync(CancellationToken cancellationToken) { CheckFirewallEntries(); - _service.Start(); - - return Task.CompletedTask; + await _service.StartAsync(); } - public override Task StopAsync(CancellationToken cancellationToken) + public override async Task StopAsync(CancellationToken cancellationToken) { - _service.Stop(); - return Task.CompletedTask; + await _service.StopAsync(); } public override void Dispose() From 2c54e0e790ce6c782f3909ad47c0a8c149321b66 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:39:12 +0530 Subject: [PATCH 047/191] LogManager: updated DownloadLogAsync() implementation to support kestral and added support for built in compression. --- DnsServerCore/LogManager.cs | 50 +++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/DnsServerCore/LogManager.cs b/DnsServerCore/LogManager.cs index a6132626..4ba1994a 100644 --- a/DnsServerCore/LogManager.cs +++ b/DnsServerCore/LogManager.cs @@ -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 @@ -17,10 +17,13 @@ along with this program. If not, see . */ +using Microsoft.AspNetCore.Http; using System; using System.Collections.Concurrent; using System.Globalization; using System.IO; +using System.IO.Compression; +using System.Linq; using System.Net; using System.Text; using System.Threading; @@ -434,29 +437,60 @@ namespace DnsServerCore return Directory.GetFiles(ConvertToAbsolutePath(_logFolder), "*.log", SearchOption.TopDirectoryOnly); } - public async Task DownloadLogAsync(HttpListenerRequest request, HttpListenerResponse response, string logName, long limit) + public async Task DownloadLogAsync(HttpContext context, string logName, long limit) { string logFileName = logName + ".log"; using (FileStream fS = new FileStream(Path.Combine(ConvertToAbsolutePath(_logFolder), logFileName), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 64 * 1024, true)) { + HttpResponse response = context.Response; + response.ContentType = "text/plain"; - response.AddHeader("Content-Disposition", "attachment;filename=" + logFileName); + response.Headers.ContentDisposition = "attachment;filename=" + logFileName; if ((limit > fS.Length) || (limit < 1)) limit = fS.Length; OffsetStream oFS = new OffsetStream(fS, 0, limit); + HttpRequest request = context.Request; + Stream s; - using (Stream s = DnsWebService.GetOutputStream(request, response)) + string acceptEncoding = request.Headers["Accept-Encoding"]; + if (string.IsNullOrEmpty(acceptEncoding)) + { + s = response.Body; + } + else + { + string[] acceptEncodingParts = acceptEncoding.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + if (acceptEncodingParts.Contains("br")) + { + response.Headers.ContentEncoding = "br"; + s = new BrotliStream(response.Body, CompressionMode.Compress); + } + else if (acceptEncodingParts.Contains("gzip")) + { + response.Headers.ContentEncoding = "gzip"; + s = new GZipStream(response.Body, CompressionMode.Compress); + } + else if (acceptEncodingParts.Contains("deflate")) + { + response.Headers.ContentEncoding = "deflate"; + s = new DeflateStream(response.Body, CompressionMode.Compress); + } + else + { + s = response.Body; + } + } + + await using (s) { await oFS.CopyToAsync(s); if (fS.Length > limit) - { - byte[] buffer = Encoding.UTF8.GetBytes("\r\n####___TRUNCATED___####"); - s.Write(buffer, 0, buffer.Length); - } + await s.WriteAsync(Encoding.UTF8.GetBytes("\r\n####___TRUNCATED___####")); } } } From fe675929754a5d2c7e9dc8cf14ace5d17890997e Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:44:05 +0530 Subject: [PATCH 048/191] WebServiceAppsApi: updated code to support kestral. --- DnsServerCore/WebServiceAppsApi.cs | 219 ++++++++++++++--------------- 1 file changed, 106 insertions(+), 113 deletions(-) diff --git a/DnsServerCore/WebServiceAppsApi.cs b/DnsServerCore/WebServiceAppsApi.cs index e2edff93..a02657ef 100644 --- a/DnsServerCore/WebServiceAppsApi.cs +++ b/DnsServerCore/WebServiceAppsApi.cs @@ -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 @@ -18,7 +18,9 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; +using DnsServerCore.Auth; using DnsServerCore.Dns.Applications; +using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.IO; @@ -28,7 +30,6 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; using TechnitiumLibrary; -using TechnitiumLibrary.IO; namespace DnsServerCore { @@ -308,8 +309,19 @@ namespace DnsServerCore #region public - public async Task ListInstalledAppsAsync(Utf8JsonWriter jsonWriter) + public async Task ListInstalledAppsAsync(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if ( + !_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.View) && + !_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View) && + !_dnsWebService._authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View) + ) + { + throw new DnsWebServiceException("Access was denied."); + } + List apps = new List(_dnsWebService._dnsServer.DnsApplicationManager.Applications.Keys); apps.Sort(); @@ -330,6 +342,8 @@ namespace DnsServerCore { } } + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("apps"); jsonWriter.WriteStartArray(); @@ -348,12 +362,19 @@ namespace DnsServerCore } } - public async Task ListStoreApps(Utf8JsonWriter jsonWriter) + public async Task ListStoreApps(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + string storeAppsJsonData = await GetStoreAppsJsonData(); using JsonDocument jsonDocument = JsonDocument.Parse(storeAppsJsonData); JsonElement jsonStoreAppsArray = jsonDocument.RootElement; + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("storeApps"); jsonWriter.WriteStartArray(); @@ -413,17 +434,17 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public async Task DownloadAndInstallAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task DownloadAndInstallAppAsync(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - name = name.Trim(); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - string url = request.QueryString["url"]; - if (string.IsNullOrEmpty(url)) - throw new DnsWebServiceException("Parameter 'url' missing."); + HttpRequest request = context.Request; + + string name = request.GetQuery("name").Trim(); + string url = request.GetQuery("url"); if (!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) throw new DnsWebServiceException("Parameter 'url' value must start with 'https://'."); @@ -451,7 +472,9 @@ namespace DnsServerCore fS.Position = 0; DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully from: " + url); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was installed successfully from: " + url); + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("installedApp"); WriteAppAsJson(jsonWriter, application); @@ -470,59 +493,44 @@ namespace DnsServerCore } } - public async Task DownloadAndUpdateAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task DownloadAndUpdateAppAsync(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - name = name.Trim(); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - string url = request.QueryString["url"]; - if (string.IsNullOrEmpty(url)) - throw new DnsWebServiceException("Parameter 'url' missing."); + HttpRequest request = context.Request; + + string name = request.GetQuery("name").Trim(); + string url = request.GetQuery("url"); if (!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) throw new DnsWebServiceException("Parameter 'url' value must start with 'https://'."); DnsApplication application = await DownloadAndUpdateAppAsync(name, url); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully from: " + url); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was updated successfully from: " + url); + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("updatedApp"); WriteAppAsJson(jsonWriter, application); } - public async Task InstallAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task InstallAppAsync(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - name = name.Trim(); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - #region skip to content + HttpRequest request = context.Request; - int crlfCount = 0; - int byteRead; + string name = request.GetQuery("name").Trim(); - while (crlfCount != 4) - { - byteRead = await request.InputStream.ReadByteValueAsync(); - switch (byteRead) - { - case 13: //CR - case 10: //LF - crlfCount++; - break; - - default: - crlfCount = 0; - break; - } - } - - #endregion + if (request.Form.Files.Count == 0) + throw new DnsWebServiceException("DNS application zip file is missing."); string tmpFile = Path.GetTempFileName(); try @@ -530,13 +538,15 @@ namespace DnsServerCore using (FileStream fS = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) { //write to temp file - await request.InputStream.CopyToAsync(fS); + await request.Form.Files[0].CopyToAsync(fS); //install app fS.Position = 0; DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was installed successfully."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was installed successfully."); + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("installedApp"); WriteAppAsJson(jsonWriter, application); @@ -555,36 +565,19 @@ namespace DnsServerCore } } - public async Task UpdateAppAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task UpdateAppAsync(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - name = name.Trim(); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - #region skip to content + HttpRequest request = context.Request; - int crlfCount = 0; - int byteRead; + string name = request.GetQuery("name").Trim(); - while (crlfCount != 4) - { - byteRead = await request.InputStream.ReadByteValueAsync(); - switch (byteRead) - { - case 13: //CR - case 10: //LF - crlfCount++; - break; - - default: - crlfCount = 0; - break; - } - } - - #endregion + if (request.Form.Files.Count == 0) + throw new DnsWebServiceException("DNS application zip file is missing."); string tmpFile = Path.GetTempFileName(); try @@ -592,13 +585,15 @@ namespace DnsServerCore using (FileStream fS = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) { //write to temp file - await request.InputStream.CopyToAsync(fS); + await request.Form.Files[0].CopyToAsync(fS); //update app fS.Position = 0; DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.UpdateApplicationAsync(name, fS); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was updated successfully."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was updated successfully."); + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("updatedApp"); WriteAppAsJson(jsonWriter, application); @@ -617,70 +612,68 @@ namespace DnsServerCore } } - public void UninstallApp(HttpListenerRequest request) + public void UninstallApp(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - name = name.Trim(); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string name = request.GetQuery("name").Trim(); _dnsWebService._dnsServer.DnsApplicationManager.UninstallApplication(name); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' was uninstalled successfully."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was uninstalled successfully."); } - public async Task GetAppConfigAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task GetAppConfigAsync(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - name = name.Trim(); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string name = request.GetQuery("name").Trim(); if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); string config = await application.GetConfigAsync(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("config", config); } - public async Task SetAppConfigAsync(HttpListenerRequest request) + public async Task SetAppConfigAsync(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - name = name.Trim(); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string name = request.GetQuery("name").Trim(); if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); - string formRequest; - using (StreamReader sR = new StreamReader(request.InputStream, request.ContentEncoding)) - { - formRequest = await sR.ReadToEndAsync(); - } + if (!request.HasFormContentType) + throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); - string[] formParts = formRequest.Split('&'); + string config = request.Form["config"]; + if (config is null) + throw new DnsWebServiceException("Form parameter 'config' missing."); - foreach (string formPart in formParts) - { - if (formPart.StartsWith("config=")) - { - string config = Uri.UnescapeDataString(formPart.Substring(7)); + if (config.Length == 0) + config = null; - if (config.Length == 0) - config = null; + await application.SetConfigAsync(config); - await application.SetConfigAsync(config); - - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS application '" + name + "' app config was saved successfully."); - return; - } - } - - throw new DnsWebServiceException("Missing POST parameter: config"); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' app config was saved successfully."); } #endregion From 47bbe63d31904e204e3af6b26fe650893f13b835 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:52:06 +0530 Subject: [PATCH 049/191] WebServiceAuthApi: updated code to support kestral. --- DnsServerCore/WebServiceAuthApi.cs | 484 ++++++++++++++--------------- 1 file changed, 242 insertions(+), 242 deletions(-) diff --git a/DnsServerCore/WebServiceAuthApi.cs b/DnsServerCore/WebServiceAuthApi.cs index 5badae00..071ac901 100644 --- a/DnsServerCore/WebServiceAuthApi.cs +++ b/DnsServerCore/WebServiceAuthApi.cs @@ -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 @@ -18,6 +18,7 @@ along with this program. If not, see . */ using DnsServerCore.Auth; +using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Net; @@ -289,116 +290,100 @@ namespace DnsServerCore #region public - public async Task LoginAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter, UserSessionType sessionType) + public async Task LoginAsync(HttpContext context, UserSessionType sessionType) { - string strUsername = request.QueryString["user"]; - if (string.IsNullOrEmpty(strUsername)) - throw new DnsWebServiceException("Parameter 'user' missing."); + HttpRequest request = context.Request; - string strPassword = request.QueryString["pass"]; - if (string.IsNullOrEmpty(strPassword)) - throw new DnsWebServiceException("Parameter 'pass' missing."); + string username = request.GetQuery("user"); + string password = request.GetQuery("pass"); + string tokenName = (sessionType == UserSessionType.ApiToken) ? request.GetQuery("tokenName") : null; + bool includeInfo = request.GetQuery("includeInfo", bool.Parse, false); + IPEndPoint remoteEP = context.GetRemoteEndPoint(); - string strTokenName = null; - - if (sessionType == UserSessionType.ApiToken) - { - strTokenName = request.QueryString["tokenName"]; - if (string.IsNullOrEmpty(strTokenName)) - throw new DnsWebServiceException("Parameter 'tokenName' missing."); - } - - bool includeInfo; - string strIncludeInfo = request.QueryString["includeInfo"]; - if (string.IsNullOrEmpty(strIncludeInfo)) - includeInfo = false; - else - includeInfo = bool.Parse(strIncludeInfo); - - IPEndPoint remoteEP = DnsWebService.GetRequestRemoteEndPoint(request); - - UserSession session = await _dnsWebService._authManager.CreateSessionAsync(sessionType, strTokenName, strUsername, strPassword, remoteEP.Address, request.UserAgent); + UserSession session = await _dnsWebService._authManager.CreateSessionAsync(sessionType, tokenName, username, password, remoteEP.Address, request.Headers.UserAgent); _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] User logged in."); _dnsWebService._authManager.SaveConfigFile(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteCurrentSessionDetails(jsonWriter, session, includeInfo); } - public void Logout(HttpListenerRequest request) + public void Logout(HttpContext context) { - string strToken = request.QueryString["token"]; - if (string.IsNullOrEmpty(strToken)) - throw new DnsWebServiceException("Parameter 'token' missing."); + string token = context.Request.GetQuery("token"); - UserSession session = _dnsWebService._authManager.DeleteSession(strToken); + UserSession session = _dnsWebService._authManager.DeleteSession(token); if (session is not null) { - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User logged out."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] User logged out."); _dnsWebService._authManager.SaveConfigFile(); } } - public void GetCurrentSessionDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetCurrentSessionDetails(HttpContext context) { - if (!_dnsWebService.TryGetSession(request, out UserSession session)) - throw new InvalidTokenWebServiceException("Invalid token or session expired."); - + UserSession session = context.GetCurrentSession(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteCurrentSessionDetails(jsonWriter, session, true); } - public void ChangePassword(HttpListenerRequest request) + public void ChangePassword(HttpContext context) { - UserSession session = _dnsWebService.GetSession(request); + UserSession session = context.GetCurrentSession(); if (session.Type != UserSessionType.Standard) throw new DnsWebServiceException("Access was denied."); - string strPassword = request.QueryString["pass"]; - if (string.IsNullOrEmpty(strPassword)) - throw new DnsWebServiceException("Parameter 'pass' missing."); + string password = context.Request.GetQuery("pass"); - session.User.ChangePassword(strPassword); + session.User.ChangePassword(password); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Password was changed successfully."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Password was changed successfully."); _dnsWebService._authManager.SaveConfigFile(); } - public void GetProfile(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetProfile(HttpContext context) { - UserSession session = _dnsWebService.GetSession(request); - + UserSession session = context.GetCurrentSession(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, session.User, session, true, false); } - public void SetProfile(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void SetProfile(HttpContext context) { - UserSession session = _dnsWebService.GetSession(request); + UserSession session = context.GetCurrentSession(); if (session.Type != UserSessionType.Standard) throw new DnsWebServiceException("Access was denied."); - string strDisplayName = request.QueryString["displayName"]; - if (!string.IsNullOrEmpty(strDisplayName)) - session.User.DisplayName = strDisplayName; + HttpRequest request = context.Request; - string strSessionTimeoutSeconds = request.QueryString["sessionTimeoutSeconds"]; - if (!string.IsNullOrEmpty(strSessionTimeoutSeconds)) - session.User.SessionTimeoutSeconds = int.Parse(strSessionTimeoutSeconds); + if (request.TryGetQuery("displayName", out string displayName)) + session.User.DisplayName = displayName; - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User profile was updated successfully."); + if (request.TryGetQuery("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) + session.User.SessionTimeoutSeconds = sessionTimeoutSeconds; + + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] User profile was updated successfully."); _dnsWebService._authManager.SaveConfigFile(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, session.User, session, true, false); } - public void ListSessions(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void ListSessions(HttpContext context) { - UserSession session = _dnsWebService.GetSession(request); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("sessions"); jsonWriter.WriteStartArray(); @@ -415,37 +400,44 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void CreateApiToken(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void CreateApiToken(HttpContext context) { - string strUsername = request.QueryString["user"]; - if (string.IsNullOrEmpty(strUsername)) - throw new DnsWebServiceException("Parameter 'user' missing."); + UserSession session = context.GetCurrentSession(); - string strTokenName = request.QueryString["tokenName"]; - if (string.IsNullOrEmpty(strTokenName)) - throw new DnsWebServiceException("Parameter 'tokenName' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - IPEndPoint remoteEP = DnsWebService.GetRequestRemoteEndPoint(request); + HttpRequest request = context.Request; - UserSession session = _dnsWebService._authManager.CreateApiToken(strTokenName, strUsername, remoteEP.Address, request.UserAgent); + string username = request.GetQuery("user"); + string tokenName = request.GetQuery("tokenName"); - _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] API token [" + strTokenName + "] was created successfully for user: " + strUsername); + IPEndPoint remoteEP = context.GetRemoteEndPoint(); + + UserSession createdSession = _dnsWebService._authManager.CreateApiToken(tokenName, username, remoteEP.Address, request.Headers.UserAgent); + + _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] API token [" + tokenName + "] was created successfully for user: " + username); _dnsWebService._authManager.SaveConfigFile(); - jsonWriter.WriteString("username", session.User.Username); - jsonWriter.WriteString("tokenName", session.TokenName); - jsonWriter.WriteString("token", session.Token); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + + jsonWriter.WriteString("username", createdSession.User.Username); + jsonWriter.WriteString("tokenName", createdSession.TokenName); + jsonWriter.WriteString("token", createdSession.Token); } - public void DeleteSession(HttpListenerRequest request, bool isAdminContext) + public void DeleteSession(HttpContext context, bool isAdminContext) { - string strPartialToken = request.QueryString["partialToken"]; - if (string.IsNullOrEmpty(strPartialToken)) - throw new DnsWebServiceException("Parameter 'partialToken' missing."); + UserSession session = context.GetCurrentSession(); - UserSession session = _dnsWebService.GetSession(request); + if (isAdminContext) + { + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + } + string strPartialToken = context.Request.GetQuery("partialToken"); if (session.Token.StartsWith(strPartialToken)) throw new InvalidOperationException("Invalid operation: cannot delete current session."); @@ -472,16 +464,23 @@ namespace DnsServerCore UserSession deletedSession = _dnsWebService._authManager.DeleteSession(token); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User session [" + strPartialToken + "] was deleted successfully for user: " + deletedSession.User.Username); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] User session [" + strPartialToken + "] was deleted successfully for user: " + deletedSession.User.Username); _dnsWebService._authManager.SaveConfigFile(); } - public void ListUsers(Utf8JsonWriter jsonWriter) + public void ListUsers(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + List users = new List(_dnsWebService._authManager.Users); users.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("users"); jsonWriter.WriteStartArray(); @@ -497,73 +496,73 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void CreateUser(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void CreateUser(HttpContext context) { - string strDisplayName = request.QueryString["displayName"]; + UserSession session = context.GetCurrentSession(); - string strUsername = request.QueryString["user"]; - if (string.IsNullOrEmpty(strUsername)) - throw new DnsWebServiceException("Parameter 'user' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - string strPassword = request.QueryString["pass"]; - if (string.IsNullOrEmpty(strPassword)) - throw new DnsWebServiceException("Parameter 'pass' missing."); + HttpRequest request = context.Request; - User user = _dnsWebService._authManager.CreateUser(strDisplayName, strUsername, strPassword); + string displayName = request.Query["displayName"]; + string username = request.GetQuery("user"); + string password = request.GetQuery("pass"); - UserSession session = _dnsWebService.GetSession(request); + User user = _dnsWebService._authManager.CreateUser(displayName, username, password); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was created successfully with username: " + user.Username); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] User account was created successfully with username: " + user.Username); _dnsWebService._authManager.SaveConfigFile(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, user, null, false, false); } - public void GetUserDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetUserDetails(HttpContext context) { - string strUsername = request.QueryString["user"]; - if (string.IsNullOrEmpty(strUsername)) - throw new DnsWebServiceException("Parameter 'user' missing."); + UserSession session = context.GetCurrentSession(); - bool includeGroups; - string strIncludeGroups = request.QueryString["includeGroups"]; - if (string.IsNullOrEmpty(strIncludeGroups)) - includeGroups = false; - else - includeGroups = bool.Parse(strIncludeGroups); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); - User user = _dnsWebService._authManager.GetUser(strUsername); + HttpRequest request = context.Request; + + string username = request.GetQuery("user"); + bool includeGroups = request.GetQuery("includeGroups", bool.Parse, false); + + User user = _dnsWebService._authManager.GetUser(username); if (user is null) - throw new DnsWebServiceException("No such user exists: " + strUsername); + throw new DnsWebServiceException("No such user exists: " + username); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, user, null, true, includeGroups); } - public void SetUserDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void SetUserDetails(HttpContext context) { - string strUsername = request.QueryString["user"]; - if (string.IsNullOrEmpty(strUsername)) - throw new DnsWebServiceException("Parameter 'user' missing."); + UserSession session = context.GetCurrentSession(); - User user = _dnsWebService._authManager.GetUser(strUsername); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string username = request.GetQuery("user"); + + User user = _dnsWebService._authManager.GetUser(username); if (user is null) - throw new DnsWebServiceException("No such user exists: " + strUsername); + throw new DnsWebServiceException("No such user exists: " + username); - string strDisplayName = request.QueryString["displayName"]; - if (!string.IsNullOrEmpty(strDisplayName)) - user.DisplayName = strDisplayName; + if (request.TryGetQuery("displayName", out string displayName)) + user.DisplayName = displayName; - string strNewUsername = request.QueryString["newUser"]; - if (!string.IsNullOrEmpty(strNewUsername)) - _dnsWebService._authManager.ChangeUsername(user, strNewUsername); + if (request.TryGetQuery("newUser", out string newUsername)) + _dnsWebService._authManager.ChangeUsername(user, newUsername); - UserSession session = _dnsWebService.GetSession(request); - - string strDisabled = request.QueryString["disabled"]; - if (!string.IsNullOrEmpty(strDisabled) && (session.User != user)) //to avoid self lockout + if (request.TryGetQuery("disabled", bool.Parse, out bool disabled) && (session.User != user)) //to avoid self lockout { - user.Disabled = bool.Parse(strDisabled); + user.Disabled = disabled; if (user.Disabled) { @@ -578,27 +577,21 @@ namespace DnsServerCore } } - string strSessionTimeoutSeconds = request.QueryString["sessionTimeoutSeconds"]; - if (!string.IsNullOrEmpty(strSessionTimeoutSeconds)) - user.SessionTimeoutSeconds = int.Parse(strSessionTimeoutSeconds); + if (request.TryGetQuery("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) + user.SessionTimeoutSeconds = sessionTimeoutSeconds; - string strNewPassword = request.QueryString["newPass"]; - if (!string.IsNullOrWhiteSpace(strNewPassword)) + string newPassword = request.Query["newPass"]; + if (!string.IsNullOrWhiteSpace(newPassword)) { - int iterations; - string strIterations = request.QueryString["iterations"]; - if (string.IsNullOrEmpty(strIterations)) - iterations = User.DEFAULT_ITERATIONS; - else - iterations = int.Parse(strIterations); + int iterations = request.GetQuery("iterations", int.Parse, User.DEFAULT_ITERATIONS); - user.ChangePassword(strNewPassword, iterations); + user.ChangePassword(newPassword, iterations); } - string strMemberOfGroups = request.QueryString["memberOfGroups"]; - if (strMemberOfGroups is not null) + string memberOfGroups = request.Query["memberOfGroups"]; + if (memberOfGroups is not null) { - string[] parts = strMemberOfGroups.Split(','); + string[] parts = memberOfGroups.Split(','); Dictionary groups = new Dictionary(parts.Length); foreach (string part in parts) @@ -627,37 +620,46 @@ namespace DnsServerCore user.SyncGroups(groups); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account details were updated successfully for user: " + strUsername); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] User account details were updated successfully for user: " + username); _dnsWebService._authManager.SaveConfigFile(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, user, null, true, false); } - public void DeleteUser(HttpListenerRequest request) + public void DeleteUser(HttpContext context) { - string strUsername = request.QueryString["user"]; - if (string.IsNullOrEmpty(strUsername)) - throw new DnsWebServiceException("Parameter 'user' missing."); + UserSession session = context.GetCurrentSession(); - UserSession session = _dnsWebService.GetSession(request); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - if (session.User.Username.Equals(strUsername, StringComparison.OrdinalIgnoreCase)) + string username = context.Request.GetQuery("user"); + + if (session.User.Username.Equals(username, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("Invalid operation: cannot delete current user."); - if (!_dnsWebService._authManager.DeleteUser(strUsername)) - throw new DnsWebServiceException("Failed to delete user: " + strUsername); + if (!_dnsWebService._authManager.DeleteUser(username)) + throw new DnsWebServiceException("Failed to delete user: " + username); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was deleted successfully with username: " + strUsername); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] User account was deleted successfully with username: " + username); _dnsWebService._authManager.SaveConfigFile(); } - public void ListGroups(Utf8JsonWriter jsonWriter) + public void ListGroups(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + List groups = new List(_dnsWebService._authManager.Groups); groups.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("groups"); jsonWriter.WriteStartArray(); @@ -676,71 +678,73 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void CreateGroup(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void CreateGroup(HttpContext context) { - string strGroup = request.QueryString["group"]; - if (string.IsNullOrEmpty(strGroup)) - throw new DnsWebServiceException("Parameter 'group' missing."); + UserSession session = context.GetCurrentSession(); - string strDescription = request.QueryString["description"]; - if (string.IsNullOrEmpty(strDescription)) - strDescription = ""; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - Group group = _dnsWebService._authManager.CreateGroup(strGroup, strDescription); + HttpRequest request = context.Request; - UserSession session = _dnsWebService.GetSession(request); + string groupName = request.GetQuery("group"); + string description = request.GetQuery("description", ""); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was created successfully with name: " + group.Name); + Group group = _dnsWebService._authManager.CreateGroup(groupName, description); + + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Group was created successfully with name: " + group.Name); _dnsWebService._authManager.SaveConfigFile(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteGroupDetails(jsonWriter, group, false, false); } - public void GetGroupDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetGroupDetails(HttpContext context) { - string strGroup = request.QueryString["group"]; - if (string.IsNullOrEmpty(strGroup)) - throw new DnsWebServiceException("Parameter 'group' missing."); + UserSession session = context.GetCurrentSession(); - bool includeUsers; - string strIncludeGroups = request.QueryString["includeUsers"]; - if (string.IsNullOrEmpty(strIncludeGroups)) - includeUsers = false; - else - includeUsers = bool.Parse(strIncludeGroups); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); - Group group = _dnsWebService._authManager.GetGroup(strGroup); + HttpRequest request = context.Request; + + string groupName = request.GetQuery("group"); + bool includeUsers = request.GetQuery("includeUsers", bool.Parse, false); + + Group group = _dnsWebService._authManager.GetGroup(groupName); if (group is null) - throw new DnsWebServiceException("No such group exists: " + strGroup); + throw new DnsWebServiceException("No such group exists: " + groupName); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteGroupDetails(jsonWriter, group, true, includeUsers); } - public void SetGroupDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void SetGroupDetails(HttpContext context) { - string strGroup = request.QueryString["group"]; - if (string.IsNullOrEmpty(strGroup)) - throw new DnsWebServiceException("Parameter 'group' missing."); + UserSession session = context.GetCurrentSession(); - Group group = _dnsWebService._authManager.GetGroup(strGroup); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string groupName = request.GetQuery("group"); + + Group group = _dnsWebService._authManager.GetGroup(groupName); if (group is null) - throw new DnsWebServiceException("No such group exists: " + strGroup); + throw new DnsWebServiceException("No such group exists: " + groupName); - string strNewGroup = request.QueryString["newGroup"]; - if (!string.IsNullOrEmpty(strNewGroup)) - _dnsWebService._authManager.RenameGroup(group, strNewGroup); + if (request.TryGetQuery("newGroup", out string newGroup)) + _dnsWebService._authManager.RenameGroup(group, newGroup); - string strDescription = request.QueryString["description"]; - if (!string.IsNullOrEmpty(strDescription)) - group.Description = strDescription; + if (request.TryGetQuery("description", out string description)) + group.Description = description; - UserSession session = _dnsWebService.GetSession(request); - - string strMembers = request.QueryString["members"]; - if (strMembers is not null) + string members = request.Query["members"]; + if (members is not null) { - string[] parts = strMembers.Split(','); + string[] parts = members.Split(','); Dictionary users = new Dictionary(); foreach (string part in parts) @@ -761,34 +765,43 @@ namespace DnsServerCore _dnsWebService._authManager.SyncGroupMembers(group, users); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group details were updated successfully for group: " + strGroup); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Group details were updated successfully for group: " + groupName); _dnsWebService._authManager.SaveConfigFile(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteGroupDetails(jsonWriter, group, true, false); } - public void DeleteGroup(HttpListenerRequest request) + public void DeleteGroup(HttpContext context) { - string strGroup = request.QueryString["group"]; - if (string.IsNullOrEmpty(strGroup)) - throw new DnsWebServiceException("Parameter 'group' missing."); + UserSession session = context.GetCurrentSession(); - if (!_dnsWebService._authManager.DeleteGroup(strGroup)) - throw new DnsWebServiceException("Failed to delete group: " + strGroup); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + string groupName = context.Request.GetQuery("group"); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was deleted successfully with name: " + strGroup); + if (!_dnsWebService._authManager.DeleteGroup(groupName)) + throw new DnsWebServiceException("Failed to delete group: " + groupName); + + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Group was deleted successfully with name: " + groupName); _dnsWebService._authManager.SaveConfigFile(); } - public void ListPermissions(Utf8JsonWriter jsonWriter) + public void ListPermissions(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + List permissions = new List(_dnsWebService._authManager.Permissions); permissions.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("permissions"); jsonWriter.WriteStartArray(); @@ -804,46 +817,36 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void GetPermissionDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter, PermissionSection section) + public void GetPermissionDetails(HttpContext context, PermissionSection section) { - if (section == PermissionSection.Unknown) - { - string strSection = request.QueryString["section"]; - if (string.IsNullOrEmpty(strSection)) - throw new DnsWebServiceException("Parameter 'section' missing."); - - if (!Enum.TryParse(strSection, true, out section)) - throw new DnsWebServiceException("No such permission section exists: " + strSection); - } - - string strSubItem; + UserSession session = context.GetCurrentSession(); + HttpRequest request = context.Request; + string strSubItem = null; switch (section) { + case PermissionSection.Unknown: + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + section = request.GetQuery("section"); + break; + case PermissionSection.Zones: - strSubItem = request.QueryString["zone"]; - - if (strSubItem is not null) - strSubItem = strSubItem.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + strSubItem = request.GetQuery("zone").TrimEnd('.'); break; default: - strSubItem = null; - break; + throw new InvalidOperationException(); } - bool includeUsersAndGroups; - string strIncludeUsersAndGroups = request.QueryString["includeUsersAndGroups"]; - if (string.IsNullOrEmpty(strIncludeUsersAndGroups)) - includeUsersAndGroups = false; - else - includeUsersAndGroups = bool.Parse(strIncludeUsersAndGroups); + bool includeUsersAndGroups = request.GetQuery("includeUsersAndGroups", bool.Parse, false); if (strSubItem is not null) { - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); } @@ -858,40 +861,36 @@ namespace DnsServerCore if (permission is null) throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem)); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WritePermissionDetails(jsonWriter, permission, strSubItem, includeUsersAndGroups); } - public void SetPermissionsDetails(HttpListenerRequest request, Utf8JsonWriter jsonWriter, PermissionSection section) + public void SetPermissionsDetails(HttpContext context, PermissionSection section) { - if (section == PermissionSection.Unknown) - { - string strSection = request.QueryString["section"]; - if (string.IsNullOrEmpty(strSection)) - throw new DnsWebServiceException("Parameter 'section' missing."); - - if (!Enum.TryParse(strSection, true, out section)) - throw new DnsWebServiceException("No such permission section exists: " + strSection); - } - - string strSubItem; + UserSession session = context.GetCurrentSession(); + HttpRequest request = context.Request; + string strSubItem = null; switch (section) { + case PermissionSection.Unknown: + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + section = request.GetQuery("section"); + break; + case PermissionSection.Zones: - strSubItem = request.QueryString["zone"]; - - if (strSubItem is not null) - strSubItem = strSubItem.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + strSubItem = request.GetQuery("zone").TrimEnd('.'); break; default: - strSubItem = null; - break; + throw new InvalidOperationException(); } - UserSession session = _dnsWebService.GetSession(request); - if (strSubItem is not null) { if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.Delete)) @@ -908,7 +907,7 @@ namespace DnsServerCore if (permission is null) throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem)); - string strUserPermissions = request.QueryString["userPermissions"]; + string strUserPermissions = request.Query["userPermissions"]; if (strUserPermissions is not null) { string[] parts = strUserPermissions.Split('|'); @@ -944,7 +943,7 @@ namespace DnsServerCore permission.SyncPermissions(userPermissions); } - string strGroupPermissions = request.QueryString["groupPermissions"]; + string strGroupPermissions = request.Query["groupPermissions"]; if (strGroupPermissions is not null) { string[] parts = strGroupPermissions.Split('|'); @@ -999,10 +998,11 @@ namespace DnsServerCore permission.SyncPermissions(groupPermissions); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Permissions were updated successfully for section: " + section.ToString() + (string.IsNullOrEmpty(strSubItem) ? "" : "/" + strSubItem)); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Permissions were updated successfully for section: " + section.ToString() + (string.IsNullOrEmpty(strSubItem) ? "" : "/" + strSubItem)); _dnsWebService._authManager.SaveConfigFile(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WritePermissionDetails(jsonWriter, permission, strSubItem, false); } From ade2acf39ee9930d89666282d2fee6a7c7bca176 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 17:56:51 +0530 Subject: [PATCH 050/191] WebServiceDashboardApi: updated code to support kestral. --- DnsServerCore/WebServiceDashboardApi.cs | 75 ++++++++++--------------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/DnsServerCore/WebServiceDashboardApi.cs b/DnsServerCore/WebServiceDashboardApi.cs index f93b0a34..058ff85c 100644 --- a/DnsServerCore/WebServiceDashboardApi.cs +++ b/DnsServerCore/WebServiceDashboardApi.cs @@ -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 @@ -17,7 +17,9 @@ along with this program. If not, see . */ +using DnsServerCore.Auth; using DnsServerCore.Dns; +using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Globalization; @@ -121,28 +123,23 @@ namespace DnsServerCore #region public - public async Task GetStats(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task GetStats(HttpContext context) { - string strType = request.QueryString["type"]; - if (string.IsNullOrEmpty(strType)) - strType = "lastHour"; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Dashboard, context.GetCurrentSession().User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); - bool utcFormat; - string strUtcFormat = request.QueryString["utc"]; - if (string.IsNullOrEmpty(strUtcFormat)) - utcFormat = false; - else - utcFormat = bool.Parse(strUtcFormat); + HttpRequest request = context.Request; + + string strType = request.GetQuery("type", "lastHour"); + bool utcFormat = request.GetQuery("utc", bool.Parse, false); + + bool isLanguageEnUs = true; + string acceptLanguage = request.Headers["Accept-Language"]; + if (!string.IsNullOrEmpty(acceptLanguage)) + isLanguageEnUs = acceptLanguage.StartsWith("en-us", StringComparison.OrdinalIgnoreCase); Dictionary>> data; string labelFormat; - bool isLanguageEnUs; - - string acceptLanguage = request.Headers["Accept-Language"]; - if (string.IsNullOrEmpty(acceptLanguage)) - isLanguageEnUs = true; - else - isLanguageEnUs = acceptLanguage.StartsWith("en-us", StringComparison.OrdinalIgnoreCase); switch (strType.ToLower()) { @@ -187,13 +184,8 @@ namespace DnsServerCore break; case "custom": - string strStartDate = request.QueryString["start"]; - if (string.IsNullOrEmpty(strStartDate)) - throw new DnsWebServiceException("Parameter 'start' missing."); - - string strEndDate = request.QueryString["end"]; - if (string.IsNullOrEmpty(strEndDate)) - throw new DnsWebServiceException("Parameter 'end' missing."); + string strStartDate = request.GetQuery("start"); + string strEndDate = request.GetQuery("end"); if (!DateTime.TryParse(strStartDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out DateTime startDate)) throw new DnsWebServiceException("Invalid start date format."); @@ -229,6 +221,8 @@ namespace DnsServerCore throw new DnsWebServiceException("Unknown stats type requested: " + strType); } + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + //stats { List> stats = data["stats"]; @@ -495,22 +489,16 @@ namespace DnsServerCore } } - public async Task GetTopStats(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task GetTopStats(HttpContext context) { - string strType = request.QueryString["type"]; - if (string.IsNullOrEmpty(strType)) - strType = "lastHour"; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Dashboard, context.GetCurrentSession().User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); - string strStatsType = request.QueryString["statsType"]; - if (string.IsNullOrEmpty(strStatsType)) - throw new DnsWebServiceException("Parameter 'statsType' missing."); + HttpRequest request = context.Request; - string strLimit = request.QueryString["limit"]; - if (string.IsNullOrEmpty(strLimit)) - strLimit = "1000"; - - TopStatsType statsType = Enum.Parse(strStatsType, true); - int limit = int.Parse(strLimit); + string strType = request.GetQuery("type", "lastHour"); + TopStatsType statsType = request.GetQuery("statsType"); + int limit = request.GetQuery("limit", int.Parse, 1000); List> topStatsData; @@ -537,13 +525,8 @@ namespace DnsServerCore break; case "custom": - string strStartDate = request.QueryString["start"]; - if (string.IsNullOrEmpty(strStartDate)) - throw new DnsWebServiceException("Parameter 'start' missing."); - - string strEndDate = request.QueryString["end"]; - if (string.IsNullOrEmpty(strEndDate)) - throw new DnsWebServiceException("Parameter 'end' missing."); + string strStartDate = request.GetQuery("start"); + string strEndDate = request.GetQuery("end"); if (!DateTime.TryParseExact(strStartDate, "yyyy-M-d", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out DateTime startDate)) throw new DnsWebServiceException("Invalid start date format."); @@ -565,6 +548,8 @@ namespace DnsServerCore throw new DnsWebServiceException("Unknown stats type requested: " + strType); } + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + switch (statsType) { case TopStatsType.TopClients: From 6678b60de4fe84bad9e136127f04d9f8f9cedb1f Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 18:05:07 +0530 Subject: [PATCH 051/191] WebServiceDhcpApi: updated code to support kestral. --- DnsServerCore/WebServiceDhcpApi.cs | 474 ++++++++++++++--------------- 1 file changed, 221 insertions(+), 253 deletions(-) diff --git a/DnsServerCore/WebServiceDhcpApi.cs b/DnsServerCore/WebServiceDhcpApi.cs index 43e37b2a..dd3bde2a 100644 --- a/DnsServerCore/WebServiceDhcpApi.cs +++ b/DnsServerCore/WebServiceDhcpApi.cs @@ -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 @@ -17,13 +17,16 @@ along with this program. If not, see . */ +using DnsServerCore.Auth; using DnsServerCore.Dhcp; using DnsServerCore.Dhcp.Options; +using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Net; using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; namespace DnsServerCore { @@ -46,8 +49,13 @@ namespace DnsServerCore #region public - public void ListDhcpLeases(Utf8JsonWriter jsonWriter) + public void ListDhcpLeases(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + IReadOnlyDictionary scopes = _dnsWebService._dhcpServer.Scopes; //sort by name @@ -58,6 +66,8 @@ namespace DnsServerCore sortedScopes.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("leases"); jsonWriter.WriteStartArray(); @@ -93,8 +103,13 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void ListDhcpScopes(Utf8JsonWriter jsonWriter) + public void ListDhcpScopes(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + IReadOnlyDictionary scopes = _dnsWebService._dhcpServer.Scopes; //sort by name @@ -105,6 +120,8 @@ namespace DnsServerCore sortedScopes.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("scopes"); jsonWriter.WriteStartArray(); @@ -129,16 +146,21 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void GetDhcpScope(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetDhcpScope(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + string scopeName = context.Request.GetQuery("name"); Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); - if (scope == null) + if (scope is null) throw new DnsWebServiceException("DHCP scope was not found: " + scopeName); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WriteString("name", scope.Name); jsonWriter.WriteString("startingAddress", scope.StartingAddress.ToString()); jsonWriter.WriteString("endingAddress", scope.EndingAddress.ToString()); @@ -343,15 +365,19 @@ namespace DnsServerCore jsonWriter.WriteBoolean("blockLocallyAdministeredMacAddresses", scope.BlockLocallyAdministeredMacAddresses); } - public async Task SetDhcpScopeAsync(HttpListenerRequest request) + public async Task SetDhcpScopeAsync(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - string strStartingAddress = request.QueryString["startingAddress"]; - string strEndingAddress = request.QueryString["endingAddress"]; - string strSubnetMask = request.QueryString["subnetMask"]; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string scopeName = request.GetQuery("name"); + string strStartingAddress = request.Query["startingAddress"]; + string strEndingAddress = request.Query["endingAddress"]; + string strSubnetMask = request.Query["subnetMask"]; bool scopeExists; Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); @@ -374,23 +400,9 @@ namespace DnsServerCore { scopeExists = true; - IPAddress startingAddress; - if (string.IsNullOrEmpty(strStartingAddress)) - startingAddress = scope.StartingAddress; - else - startingAddress = IPAddress.Parse(strStartingAddress); - - IPAddress endingAddress; - if (string.IsNullOrEmpty(strEndingAddress)) - endingAddress = scope.EndingAddress; - else - endingAddress = IPAddress.Parse(strEndingAddress); - - IPAddress subnetMask; - if (string.IsNullOrEmpty(strSubnetMask)) - subnetMask = scope.SubnetMask; - else - subnetMask = IPAddress.Parse(strSubnetMask); + IPAddress startingAddress = string.IsNullOrEmpty(strStartingAddress) ? scope.StartingAddress : IPAddress.Parse(strStartingAddress); + IPAddress endingAddress = string.IsNullOrEmpty(strEndingAddress) ? scope.EndingAddress : IPAddress.Parse(strEndingAddress); + IPAddress subnetMask = string.IsNullOrEmpty(strSubnetMask) ? scope.SubnetMask : IPAddress.Parse(strSubnetMask); //validate scope address foreach (KeyValuePair entry in _dnsWebService._dhcpServer.Scopes) @@ -407,146 +419,106 @@ namespace DnsServerCore scope.ChangeNetwork(startingAddress, endingAddress, subnetMask); } - string strLeaseTimeDays = request.QueryString["leaseTimeDays"]; - if (!string.IsNullOrEmpty(strLeaseTimeDays)) - scope.LeaseTimeDays = ushort.Parse(strLeaseTimeDays); + if (request.TryGetQuery("leaseTimeDays", ushort.Parse, out ushort leaseTimeDays)) + scope.LeaseTimeDays = leaseTimeDays; - string strLeaseTimeHours = request.QueryString["leaseTimeHours"]; - if (!string.IsNullOrEmpty(strLeaseTimeHours)) - scope.LeaseTimeHours = byte.Parse(strLeaseTimeHours); + if (request.TryGetQuery("leaseTimeHours", byte.Parse, out byte leaseTimeHours)) + scope.LeaseTimeHours = leaseTimeHours; - string strLeaseTimeMinutes = request.QueryString["leaseTimeMinutes"]; - if (!string.IsNullOrEmpty(strLeaseTimeMinutes)) - scope.LeaseTimeMinutes = byte.Parse(strLeaseTimeMinutes); + if (request.TryGetQuery("leaseTimeMinutes", byte.Parse, out byte leaseTimeMinutes)) + scope.LeaseTimeMinutes = leaseTimeMinutes; - string strOfferDelayTime = request.QueryString["offerDelayTime"]; - if (!string.IsNullOrEmpty(strOfferDelayTime)) - scope.OfferDelayTime = ushort.Parse(strOfferDelayTime); + if (request.TryGetQuery("offerDelayTime", ushort.Parse, out ushort offerDelayTime)) + scope.OfferDelayTime = offerDelayTime; - string strPingCheckEnabled = request.QueryString["pingCheckEnabled"]; - if (!string.IsNullOrEmpty(strPingCheckEnabled)) - scope.PingCheckEnabled = bool.Parse(strPingCheckEnabled); + if (request.TryGetQuery("pingCheckEnabled", bool.Parse, out bool pingCheckEnabled)) + scope.PingCheckEnabled = pingCheckEnabled; - string strPingCheckTimeout = request.QueryString["pingCheckTimeout"]; - if (!string.IsNullOrEmpty(strPingCheckTimeout)) - scope.PingCheckTimeout = ushort.Parse(strPingCheckTimeout); + if (request.TryGetQuery("pingCheckTimeout", ushort.Parse, out ushort pingCheckTimeout)) + scope.PingCheckTimeout = pingCheckTimeout; - string strPingCheckRetries = request.QueryString["pingCheckRetries"]; - if (!string.IsNullOrEmpty(strPingCheckRetries)) - scope.PingCheckRetries = byte.Parse(strPingCheckRetries); + if (request.TryGetQuery("pingCheckRetries", byte.Parse, out byte pingCheckRetries)) + scope.PingCheckRetries = pingCheckRetries; - string strDomainName = request.QueryString["domainName"]; - if (strDomainName != null) - scope.DomainName = strDomainName.Length == 0 ? null : strDomainName; + string domainName = request.Query["domainName"]; + if (domainName is not null) + scope.DomainName = domainName.Length == 0 ? null : domainName; - string strDomainSearchList = request.QueryString["domainSearchList"]; - if (strDomainSearchList is not null) + string domainSearchList = request.Query["domainSearchList"]; + if (domainSearchList is not null) { - if (strDomainSearchList.Length == 0) + if (domainSearchList.Length == 0) scope.DomainSearchList = null; else - scope.DomainSearchList = strDomainSearchList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + scope.DomainSearchList = domainSearchList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } - string strDnsUpdates = request.QueryString["dnsUpdates"]; - if (!string.IsNullOrEmpty(strDnsUpdates)) - scope.DnsUpdates = bool.Parse(strDnsUpdates); + if (request.TryGetQuery("dnsUpdates", bool.Parse, out bool dnsUpdates)) + scope.DnsUpdates = dnsUpdates; - string strDnsTtl = request.QueryString["dnsTtl"]; - if (!string.IsNullOrEmpty(strDnsTtl)) - scope.DnsTtl = uint.Parse(strDnsTtl); + if (request.TryGetQuery("dnsTtl", uint.Parse, out uint dnsTtl)) + scope.DnsTtl = dnsTtl; - string strServerAddress = request.QueryString["serverAddress"]; - if (strServerAddress != null) - scope.ServerAddress = strServerAddress.Length == 0 ? null : IPAddress.Parse(strServerAddress); + string serverAddress = request.Query["serverAddress"]; + if (serverAddress is not null) + scope.ServerAddress = serverAddress.Length == 0 ? null : IPAddress.Parse(serverAddress); - string strServerHostName = request.QueryString["serverHostName"]; - if (strServerHostName != null) - scope.ServerHostName = strServerHostName.Length == 0 ? null : strServerHostName; + string serverHostName = request.Query["serverHostName"]; + if (serverHostName is not null) + scope.ServerHostName = serverHostName.Length == 0 ? null : serverHostName; - string strBootFileName = request.QueryString["bootFileName"]; - if (strBootFileName != null) - scope.BootFileName = strBootFileName.Length == 0 ? null : strBootFileName; + string bootFileName = request.Query["bootFileName"]; + if (bootFileName is not null) + scope.BootFileName = bootFileName.Length == 0 ? null : bootFileName; - string strRouterAddress = request.QueryString["routerAddress"]; - if (strRouterAddress != null) - scope.RouterAddress = strRouterAddress.Length == 0 ? null : IPAddress.Parse(strRouterAddress); + string routerAddress = request.Query["routerAddress"]; + if (routerAddress is not null) + scope.RouterAddress = routerAddress.Length == 0 ? null : IPAddress.Parse(routerAddress); - string strUseThisDnsServer = request.QueryString["useThisDnsServer"]; - if (!string.IsNullOrEmpty(strUseThisDnsServer)) - scope.UseThisDnsServer = bool.Parse(strUseThisDnsServer); + if (request.TryGetQuery("useThisDnsServer", bool.Parse, out bool useThisDnsServer)) + scope.UseThisDnsServer = useThisDnsServer; if (!scope.UseThisDnsServer) { - string strDnsServers = request.QueryString["dnsServers"]; - if (strDnsServers != null) + string dnsServers = request.Query["dnsServers"]; + if (dnsServers is not null) { - if (strDnsServers.Length == 0) - { + if (dnsServers.Length == 0) scope.DnsServers = null; - } else - { - string[] strDnsServerParts = strDnsServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] dnsServers = new IPAddress[strDnsServerParts.Length]; - - for (int i = 0; i < strDnsServerParts.Length; i++) - dnsServers[i] = IPAddress.Parse(strDnsServerParts[i]); - - scope.DnsServers = dnsServers; - } + scope.DnsServers = dnsServers.Split(IPAddress.Parse, ','); } } - string strWinsServers = request.QueryString["winsServers"]; - if (strWinsServers != null) + string winsServers = request.Query["winsServers"]; + if (winsServers is not null) { - if (strWinsServers.Length == 0) - { + if (winsServers.Length == 0) scope.WinsServers = null; - } else - { - string[] strWinsServerParts = strWinsServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] winsServers = new IPAddress[strWinsServerParts.Length]; - - for (int i = 0; i < strWinsServerParts.Length; i++) - winsServers[i] = IPAddress.Parse(strWinsServerParts[i]); - - scope.WinsServers = winsServers; - } + scope.WinsServers = winsServers.Split(IPAddress.Parse, ','); } - string strNtpServers = request.QueryString["ntpServers"]; - if (strNtpServers != null) + string ntpServers = request.Query["ntpServers"]; + if (ntpServers is not null) { - if (strNtpServers.Length == 0) - { + if (ntpServers.Length == 0) scope.NtpServers = null; - } else - { - string[] strNtpServerParts = strNtpServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] ntpServers = new IPAddress[strNtpServerParts.Length]; - - for (int i = 0; i < strNtpServerParts.Length; i++) - ntpServers[i] = IPAddress.Parse(strNtpServerParts[i]); - - scope.NtpServers = ntpServers; - } + scope.NtpServers = ntpServers.Split(IPAddress.Parse, ','); } - string strNtpServerDomainNames = request.QueryString["ntpServerDomainNames"]; - if (strNtpServerDomainNames is not null) + string ntpServerDomainNames = request.Query["ntpServerDomainNames"]; + if (ntpServerDomainNames is not null) { - if (strNtpServerDomainNames.Length == 0) + if (ntpServerDomainNames.Length == 0) scope.NtpServerDomainNames = null; else - scope.NtpServerDomainNames = strNtpServerDomainNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + scope.NtpServerDomainNames = ntpServerDomainNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } - string strStaticRoutes = request.QueryString["staticRoutes"]; - if (strStaticRoutes != null) + string strStaticRoutes = request.Query["staticRoutes"]; + if (strStaticRoutes is not null) { if (strStaticRoutes.Length == 0) { @@ -558,16 +530,14 @@ namespace DnsServerCore List staticRoutes = new List(); for (int i = 0; i < strStaticRoutesParts.Length; i += 3) - { staticRoutes.Add(new ClasslessStaticRouteOption.Route(IPAddress.Parse(strStaticRoutesParts[i + 0]), IPAddress.Parse(strStaticRoutesParts[i + 1]), IPAddress.Parse(strStaticRoutesParts[i + 2]))); - } scope.StaticRoutes = staticRoutes; } } - string strVendorInfo = request.QueryString["vendorInfo"]; - if (strVendorInfo != null) + string strVendorInfo = request.Query["vendorInfo"]; + if (strVendorInfo is not null) { if (strVendorInfo.Length == 0) { @@ -585,45 +555,25 @@ namespace DnsServerCore } } - string strCAPWAPAcIpAddresses = request.QueryString["capwapAcIpAddresses"]; - if (strCAPWAPAcIpAddresses is not null) + string capwapAcIpAddresses = request.Query["capwapAcIpAddresses"]; + if (capwapAcIpAddresses is not null) { - if (strCAPWAPAcIpAddresses.Length == 0) - { + if (capwapAcIpAddresses.Length == 0) scope.CAPWAPAcIpAddresses = null; - } else - { - string[] strCAPWAPAcIpAddressesParts = strCAPWAPAcIpAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] capwapAcIpAddresses = new IPAddress[strCAPWAPAcIpAddressesParts.Length]; - - for (int i = 0; i < strCAPWAPAcIpAddressesParts.Length; i++) - capwapAcIpAddresses[i] = IPAddress.Parse(strCAPWAPAcIpAddressesParts[i]); - - scope.CAPWAPAcIpAddresses = capwapAcIpAddresses; - } + scope.CAPWAPAcIpAddresses = capwapAcIpAddresses.Split(IPAddress.Parse, ','); } - string strTftpServerAddresses = request.QueryString["tftpServerAddresses"]; - if (strTftpServerAddresses is not null) + string tftpServerAddresses = request.Query["tftpServerAddresses"]; + if (tftpServerAddresses is not null) { - if (strTftpServerAddresses.Length == 0) - { + if (tftpServerAddresses.Length == 0) scope.TftpServerAddresses = null; - } else - { - string[] strTftpServerAddressesParts = strTftpServerAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] tftpServerAddresses = new IPAddress[strTftpServerAddressesParts.Length]; - - for (int i = 0; i < strTftpServerAddressesParts.Length; i++) - tftpServerAddresses[i] = IPAddress.Parse(strTftpServerAddressesParts[i]); - - scope.TftpServerAddresses = tftpServerAddresses; - } + scope.TftpServerAddresses = tftpServerAddresses.Split(IPAddress.Parse, ','); } - string strGenericOptions = request.QueryString["genericOptions"]; + string strGenericOptions = request.Query["genericOptions"]; if (strGenericOptions is not null) { if (strGenericOptions.Length == 0) @@ -642,8 +592,8 @@ namespace DnsServerCore } } - string strExclusions = request.QueryString["exclusions"]; - if (strExclusions != null) + string strExclusions = request.Query["exclusions"]; + if (strExclusions is not null) { if (strExclusions.Length == 0) { @@ -655,16 +605,14 @@ namespace DnsServerCore List exclusions = new List(); for (int i = 0; i < strExclusionsParts.Length; i += 2) - { exclusions.Add(new Exclusion(IPAddress.Parse(strExclusionsParts[i + 0]), IPAddress.Parse(strExclusionsParts[i + 1]))); - } scope.Exclusions = exclusions; } } - string strReservedLeases = request.QueryString["reservedLeases"]; - if (strReservedLeases != null) + string strReservedLeases = request.Query["reservedLeases"]; + if (strReservedLeases is not null) { if (strReservedLeases.Length == 0) { @@ -676,65 +624,58 @@ namespace DnsServerCore List reservedLeases = new List(); for (int i = 0; i < strReservedLeaseParts.Length; i += 4) - { reservedLeases.Add(new Lease(LeaseType.Reserved, strReservedLeaseParts[i + 0], DhcpMessageHardwareAddressType.Ethernet, strReservedLeaseParts[i + 1], IPAddress.Parse(strReservedLeaseParts[i + 2]), strReservedLeaseParts[i + 3])); - } scope.ReservedLeases = reservedLeases; } } - string strAllowOnlyReservedLeases = request.QueryString["allowOnlyReservedLeases"]; - if (!string.IsNullOrEmpty(strAllowOnlyReservedLeases)) - scope.AllowOnlyReservedLeases = bool.Parse(strAllowOnlyReservedLeases); + if (request.TryGetQuery("allowOnlyReservedLeases", bool.Parse, out bool allowOnlyReservedLeases)) + scope.AllowOnlyReservedLeases = allowOnlyReservedLeases; - string strBlockLocallyAdministeredMacAddresses = request.QueryString["blockLocallyAdministeredMacAddresses"]; - if (!string.IsNullOrEmpty(strBlockLocallyAdministeredMacAddresses)) - scope.BlockLocallyAdministeredMacAddresses = bool.Parse(strBlockLocallyAdministeredMacAddresses); + if (request.TryGetQuery("blockLocallyAdministeredMacAddresses", bool.Parse, out bool blockLocallyAdministeredMacAddresses)) + scope.BlockLocallyAdministeredMacAddresses = blockLocallyAdministeredMacAddresses; if (scopeExists) { _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was updated successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was updated successfully: " + scopeName); } else { await _dnsWebService._dhcpServer.AddScopeAsync(scope); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was added successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was added successfully: " + scopeName); } - string newName = request.QueryString["newName"]; - if (!string.IsNullOrEmpty(newName) && !newName.Equals(scopeName)) + if (request.TryGetQuery("newName", out string newName) && !newName.Equals(scopeName)) { _dnsWebService._dhcpServer.RenameScope(scopeName, newName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was renamed successfully: '" + scopeName + "' to '" + newName + "'"); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was renamed successfully: '" + scopeName + "' to '" + newName + "'"); } } - public void AddReservedLease(HttpListenerRequest request) + public void AddReservedLease(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string scopeName = request.GetQuery("name"); Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("No such scope exists: " + scopeName); - string hostName = request.QueryString["hostName"]; - - string hardwareAddress = request.QueryString["hardwareAddress"]; - if (string.IsNullOrEmpty(hardwareAddress)) - throw new DnsWebServiceException("Parameter 'hardwareAddress' missing."); - - string strIpAddress = request.QueryString["ipAddress"]; - if (string.IsNullOrEmpty(strIpAddress)) - throw new DnsWebServiceException("Parameter 'ipAddress' missing."); - - string comments = request.QueryString["comments"]; + string hostName = request.Query["hostName"]; + string hardwareAddress = request.GetQuery("hardwareAddress"); + string strIpAddress = request.GetQuery("ipAddress"); + string comments = request.Query["comments"]; Lease reservedLease = new Lease(LeaseType.Reserved, hostName, DhcpMessageHardwareAddressType.Ethernet, hardwareAddress, IPAddress.Parse(strIpAddress), comments); @@ -743,137 +684,164 @@ namespace DnsServerCore _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope reserved lease was added successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope reserved lease was added successfully: " + scopeName); } - public void RemoveReservedLease(HttpListenerRequest request) + public void RemoveReservedLease(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string scopeName = request.GetQuery("name"); Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("No such scope exists: " + scopeName); - string hardwareAddress = request.QueryString["hardwareAddress"]; - if (string.IsNullOrEmpty(hardwareAddress)) - throw new DnsWebServiceException("Parameter 'hardwareAddress' missing."); + string hardwareAddress = request.GetQuery("hardwareAddress"); if (!scope.RemoveReservedLease(hardwareAddress)) throw new DnsWebServiceException("Failed to remove reserved lease for scope: " + scopeName); _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope reserved lease was removed successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope reserved lease was removed successfully: " + scopeName); } - public async Task EnableDhcpScopeAsync(HttpListenerRequest request) + public async Task EnableDhcpScopeAsync(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + string scopeName = context.Request.GetQuery("name"); await _dnsWebService._dhcpServer.EnableScopeAsync(scopeName, true); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was enabled successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was enabled successfully: " + scopeName); } - public void DisableDhcpScope(HttpListenerRequest request) + public void DisableDhcpScope(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + string scopeName = context.Request.GetQuery("name"); _dnsWebService._dhcpServer.DisableScope(scopeName, true); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was disabled successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was disabled successfully: " + scopeName); } - public void DeleteDhcpScope(HttpListenerRequest request) + public void DeleteDhcpScope(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + string scopeName = context.Request.GetQuery("name"); _dnsWebService._dhcpServer.DeleteScope(scopeName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope was deleted successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was deleted successfully: " + scopeName); } - public void RemoveDhcpLease(HttpListenerRequest request) + public void RemoveDhcpLease(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string scopeName = request.GetQuery("name"); Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); - string strClientIdentifier = request.QueryString["clientIdentifier"]; - string strHardwareAddress = request.QueryString["hardwareAddress"]; + string clientIdentifier = request.Query["clientIdentifier"]; + string hardwareAddress = request.Query["hardwareAddress"]; - if (!string.IsNullOrEmpty(strClientIdentifier)) - scope.RemoveLease(ClientIdentifierOption.Parse(strClientIdentifier)); - else if (!string.IsNullOrEmpty(strHardwareAddress)) - scope.RemoveLease(strHardwareAddress); + if (!string.IsNullOrEmpty(clientIdentifier)) + scope.RemoveLease(ClientIdentifierOption.Parse(clientIdentifier)); + else if (!string.IsNullOrEmpty(hardwareAddress)) + scope.RemoveLease(hardwareAddress); else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was removed successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope's lease was removed successfully: " + scopeName); } - public void ConvertToReservedLease(HttpListenerRequest request) + public void ConvertToReservedLease(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string scopeName = request.GetQuery("name"); Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope == null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); - string strClientIdentifier = request.QueryString["clientIdentifier"]; - string strHardwareAddress = request.QueryString["hardwareAddress"]; + string clientIdentifier = request.Query["clientIdentifier"]; + string hardwareAddress = request.Query["hardwareAddress"]; - if (!string.IsNullOrEmpty(strClientIdentifier)) - scope.ConvertToReservedLease(ClientIdentifierOption.Parse(strClientIdentifier)); - else if (!string.IsNullOrEmpty(strHardwareAddress)) - scope.ConvertToReservedLease(strHardwareAddress); + if (!string.IsNullOrEmpty(clientIdentifier)) + scope.ConvertToReservedLease(ClientIdentifierOption.Parse(clientIdentifier)); + else if (!string.IsNullOrEmpty(hardwareAddress)) + scope.ConvertToReservedLease(hardwareAddress); else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was reserved successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope's lease was reserved successfully: " + scopeName); } - public void ConvertToDynamicLease(HttpListenerRequest request) + public void ConvertToDynamicLease(HttpContext context) { - string scopeName = request.QueryString["name"]; - if (string.IsNullOrEmpty(scopeName)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string scopeName = request.GetQuery("name"); Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); if (scope == null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); - string strClientIdentifier = request.QueryString["clientIdentifier"]; - string strHardwareAddress = request.QueryString["hardwareAddress"]; + string clientIdentifier = request.Query["clientIdentifier"]; + string hardwareAddress = request.Query["hardwareAddress"]; - if (!string.IsNullOrEmpty(strClientIdentifier)) - scope.ConvertToDynamicLease(ClientIdentifierOption.Parse(strClientIdentifier)); - else if (!string.IsNullOrEmpty(strHardwareAddress)) - scope.ConvertToDynamicLease(strHardwareAddress); + if (!string.IsNullOrEmpty(clientIdentifier)) + scope.ConvertToDynamicLease(ClientIdentifierOption.Parse(clientIdentifier)); + else if (!string.IsNullOrEmpty(hardwareAddress)) + scope.ConvertToDynamicLease(hardwareAddress); else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); _dnsWebService._dhcpServer.SaveScope(scopeName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DHCP scope's lease was unreserved successfully: " + scopeName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope's lease was unreserved successfully: " + scopeName); } #endregion From 30d30ab18971bccabd0fc94592f24a79a1654bbe Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 18:06:50 +0530 Subject: [PATCH 052/191] WebServiceLogsApi: updated code to support kestral. --- DnsServerCore/WebServiceLogsApi.cs | 175 ++++++++++++++--------------- 1 file changed, 82 insertions(+), 93 deletions(-) diff --git a/DnsServerCore/WebServiceLogsApi.cs b/DnsServerCore/WebServiceLogsApi.cs index 034ec070..6dec972e 100644 --- a/DnsServerCore/WebServiceLogsApi.cs +++ b/DnsServerCore/WebServiceLogsApi.cs @@ -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 @@ -18,7 +18,9 @@ along with this program. If not, see . */ using DnsServerCore.ApplicationCommon; +using DnsServerCore.Auth; using DnsServerCore.Dns.Applications; +using Microsoft.AspNetCore.Http; using System; using System.Globalization; using System.IO; @@ -50,13 +52,20 @@ namespace DnsServerCore #region public - public void ListLogs(Utf8JsonWriter jsonWriter) + public void ListLogs(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + string[] logFiles = _dnsWebService._log.ListLogFiles(); Array.Sort(logFiles); Array.Reverse(logFiles); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("logFiles"); jsonWriter.WriteStartArray(); @@ -73,56 +82,72 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public Task DownloadLogAsync(HttpListenerRequest request, HttpListenerResponse response) + public Task DownloadLogAsync(HttpContext context) { - string strFileName = request.QueryString["fileName"]; - if (string.IsNullOrEmpty(strFileName)) - throw new DnsWebServiceException("Parameter 'fileName' missing."); + UserSession session = context.GetCurrentSession(); - int limit; - string strLimit = request.QueryString["limit"]; - if (string.IsNullOrEmpty(strLimit)) - limit = 0; - else - limit = int.Parse(strLimit); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); - return _dnsWebService._log.DownloadLogAsync(request, response, strFileName, limit * 1024 * 1024); + HttpRequest request = context.Request; + + string fileName = request.GetQuery("fileName"); + int limit = request.GetQuery("limit", int.Parse, 0); + + return _dnsWebService._log.DownloadLogAsync(context, fileName, limit * 1024 * 1024); } - public void DeleteLog(HttpListenerRequest request) + public void DeleteLog(HttpContext context) { - string log = request.QueryString["log"]; - if (string.IsNullOrEmpty(log)) - throw new DnsWebServiceException("Parameter 'log' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string log = request.GetQuery("log"); _dnsWebService._log.DeleteLog(log); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Log file was deleted: " + log); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Log file was deleted: " + log); } - public void DeleteAllLogs(HttpListenerRequest request) + public void DeleteAllLogs(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + _dnsWebService._log.DeleteAllLogs(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] All log files were deleted."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] All log files were deleted."); } - public void DeleteAllStats(HttpListenerRequest request) + public void DeleteAllStats(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Dashboard, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + _dnsWebService._dnsServer.StatsManager.DeleteAllStats(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] All stats files were deleted."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] All stats files were deleted."); } - public async Task QueryLogsAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task QueryLogsAsync(HttpContext context) { - string name = request.QueryString["name"]; - if (string.IsNullOrEmpty(name)) - throw new DnsWebServiceException("Parameter 'name' missing."); + UserSession session = context.GetCurrentSession(); - string classPath = request.QueryString["classPath"]; - if (string.IsNullOrEmpty(classPath)) - throw new DnsWebServiceException("Parameter 'classPath' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string name = request.GetQuery("name"); + string classPath = request.GetQuery("classPath"); if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); @@ -130,89 +155,53 @@ namespace DnsServerCore if (!application.DnsQueryLoggers.TryGetValue(classPath, out IDnsQueryLogger logger)) throw new DnsWebServiceException("DNS application '" + classPath + "' class path was not found: " + name); - long pageNumber; - string strPageNumber = request.QueryString["pageNumber"]; - if (string.IsNullOrEmpty(strPageNumber)) - pageNumber = 1; - else - pageNumber = long.Parse(strPageNumber); + long pageNumber = request.GetQuery("pageNumber", long.Parse, 1); + int entriesPerPage = request.GetQuery("entriesPerPage", int.Parse, 25); + bool descendingOrder = request.GetQuery("descendingOrder", bool.Parse, true); - int entriesPerPage; - string strEntriesPerPage = request.QueryString["entriesPerPage"]; - if (string.IsNullOrEmpty(strEntriesPerPage)) - entriesPerPage = 25; - else - entriesPerPage = int.Parse(strEntriesPerPage); - - bool descendingOrder; - string strDescendingOrder = request.QueryString["descendingOrder"]; - if (string.IsNullOrEmpty(strDescendingOrder)) - descendingOrder = true; - else - descendingOrder = bool.Parse(strDescendingOrder); - - DateTime? start; - string strStart = request.QueryString["start"]; - if (string.IsNullOrEmpty(strStart)) - start = null; - else + DateTime? start = null; + string strStart = request.Query["start"]; + if (!string.IsNullOrEmpty(strStart)) start = DateTime.Parse(strStart, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); - DateTime? end; - string strEnd = request.QueryString["end"]; - if (string.IsNullOrEmpty(strEnd)) - end = null; - else + DateTime? end = null; + string strEnd = request.Query["end"]; + if (!string.IsNullOrEmpty(strEnd)) end = DateTime.Parse(strEnd, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); - IPAddress clientIpAddress; - string strClientIpAddress = request.QueryString["clientIpAddress"]; - if (string.IsNullOrEmpty(strClientIpAddress)) - clientIpAddress = null; - else - clientIpAddress = IPAddress.Parse(strClientIpAddress); + IPAddress clientIpAddress = request.GetQuery("clientIpAddress", IPAddress.Parse, null); - DnsTransportProtocol? protocol; - string strProtocol = request.QueryString["protocol"]; - if (string.IsNullOrEmpty(strProtocol)) - protocol = null; - else + DnsTransportProtocol? protocol = null; + string strProtocol = request.Query["protocol"]; + if (!string.IsNullOrEmpty(strProtocol)) protocol = Enum.Parse(strProtocol, true); - DnsServerResponseType? responseType; - string strResponseType = request.QueryString["responseType"]; - if (string.IsNullOrEmpty(strResponseType)) - responseType = null; - else + DnsServerResponseType? responseType = null; + string strResponseType = request.Query["responseType"]; + if (!string.IsNullOrEmpty(strResponseType)) responseType = Enum.Parse(strResponseType, true); - DnsResponseCode? rcode; - string strRcode = request.QueryString["rcode"]; - if (string.IsNullOrEmpty(strRcode)) - rcode = null; - else + DnsResponseCode? rcode = null; + string strRcode = request.Query["rcode"]; + if (!string.IsNullOrEmpty(strRcode)) rcode = Enum.Parse(strRcode, true); - string qname = request.QueryString["qname"]; - if (string.IsNullOrEmpty(qname)) - qname = null; + string qname = request.GetQuery("qname", null); - DnsResourceRecordType? qtype; - string strQtype = request.QueryString["qtype"]; - if (string.IsNullOrEmpty(strQtype)) - qtype = null; - else + DnsResourceRecordType? qtype = null; + string strQtype = request.Query["qtype"]; + if (!string.IsNullOrEmpty(strQtype)) qtype = Enum.Parse(strQtype, true); - DnsClass? qclass; - string strQclass = request.QueryString["qclass"]; - if (string.IsNullOrEmpty(strQclass)) - qclass = null; - else + DnsClass? qclass = null; + string strQclass = request.Query["qclass"]; + if (!string.IsNullOrEmpty(strQclass)) qclass = Enum.Parse(strQclass, true); DnsLogPage page = await logger.QueryLogsAsync(pageNumber, entriesPerPage, descendingOrder, start, end, clientIpAddress, protocol, responseType, rcode, qname, qtype, qclass); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WriteNumber("pageNumber", page.PageNumber); jsonWriter.WriteNumber("totalPages", page.TotalPages); jsonWriter.WriteNumber("totalEntries", page.TotalEntries); From 37dba9bfa191ede74fb97db88dd4a2eba72dedeb Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 18:10:10 +0530 Subject: [PATCH 053/191] WebServiceOtherZonesApi: updated code to support kestral. --- DnsServerCore/WebServiceOtherZonesApi.cs | 350 +++++++++++++---------- 1 file changed, 200 insertions(+), 150 deletions(-) diff --git a/DnsServerCore/WebServiceOtherZonesApi.cs b/DnsServerCore/WebServiceOtherZonesApi.cs index 5a36bd0b..4b2f4e71 100644 --- a/DnsServerCore/WebServiceOtherZonesApi.cs +++ b/DnsServerCore/WebServiceOtherZonesApi.cs @@ -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 @@ -17,8 +17,9 @@ along with this program. If not, see . */ +using DnsServerCore.Auth; using DnsServerCore.Dns.Zones; -using System; +using Microsoft.AspNetCore.Http; using System.Collections.Generic; using System.IO; using System.Net; @@ -50,20 +51,30 @@ namespace DnsServerCore #region cache api - public void FlushCache(HttpListenerRequest request) + public void FlushCache(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + _dnsWebService._dnsServer.CacheZoneManager.Flush(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Cache was flushed."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Cache was flushed."); } - public void ListCachedZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void ListCachedZones(HttpContext context) { - string domain = request.QueryString["domain"]; - if (domain == null) - domain = ""; + UserSession session = context.GetCurrentSession(); - string direction = request.QueryString["direction"]; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string domain = request.GetQuery("domain", ""); + + string direction = request.Query["direction"]; if (direction is not null) direction = direction.ToLower(); @@ -107,6 +118,8 @@ namespace DnsServerCore subZones.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); @@ -123,27 +136,35 @@ namespace DnsServerCore WebServiceZonesApi.WriteRecordsAsJson(records, jsonWriter, false); } - public void DeleteCachedZone(HttpListenerRequest request) + public void DeleteCachedZone(HttpContext context) { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + string domain = context.Request.GetQuery("domain"); if (_dnsWebService._dnsServer.CacheZoneManager.DeleteZone(domain)) - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Cached zone was deleted: " + domain); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Cached zone was deleted: " + domain); } #endregion #region allowed zones api - public void ListAllowedZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void ListAllowedZones(HttpContext context) { - string domain = request.QueryString["domain"]; - if (domain == null) - domain = ""; + UserSession session = context.GetCurrentSession(); - string direction = request.QueryString["direction"]; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string domain = request.GetQuery("domain", ""); + + string direction = request.Query["direction"]; if (direction is not null) direction = direction.ToLower(); @@ -187,6 +208,8 @@ namespace DnsServerCore subZones.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); @@ -203,93 +226,103 @@ namespace DnsServerCore WebServiceZonesApi.WriteRecordsAsJson(new List(records), jsonWriter, false); } - public async Task ImportAllowedZonesAsync(HttpListenerRequest request) + public void ImportAllowedZones(HttpContext context) { - if (!request.ContentType.StartsWith("application/x-www-form-urlencoded")) + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + if (!request.HasFormContentType) throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); - string formRequest; - using (StreamReader sR = new StreamReader(request.InputStream, request.ContentEncoding)) + string allowedZones = request.Form["allowedZones"]; + if (string.IsNullOrEmpty(allowedZones)) + throw new DnsWebServiceException("Form parameter 'allowedZones' missing."); + + string[] allowedZonesList = allowedZones.Split(','); + bool added = false; + + foreach (string allowedZone in allowedZonesList) { - formRequest = await sR.ReadToEndAsync(); + if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(allowedZone)) + added = true; } - string[] formParts = formRequest.Split('&'); - - foreach (string formPart in formParts) + if (added) { - if (formPart.StartsWith("allowedZones=")) - { - string value = Uri.UnescapeDataString(formPart.Substring(13)); - string[] allowedZones = value.Split(','); - bool added = false; - - foreach (string allowedZone in allowedZones) - { - if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(allowedZone)) - added = true; - } - - if (added) - { - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Total " + allowedZones.Length + " zones were imported into allowed zone successfully."); - _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); - } - - return; - } - } - - throw new DnsWebServiceException("Parameter 'allowedZones' missing."); - } - - public void ExportAllowedZones(HttpListenerResponse response) - { - IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.AllowedZoneManager.ListZones(); - - response.ContentType = "text/plain"; - response.AddHeader("Content-Disposition", "attachment;filename=AllowedZones.txt"); - - using (StreamWriter sW = new StreamWriter(new BufferedStream(response.OutputStream))) - { - foreach (AuthZoneInfo zoneInfo in zoneInfoList) - sW.WriteLine(zoneInfo.Name); - } - } - - public void DeleteAllowedZone(HttpListenerRequest request) - { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); - - if (_dnsWebService._dnsServer.AllowedZoneManager.DeleteZone(domain)) - { - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Allowed zone was deleted: " + domain); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Total " + allowedZonesList.Length + " zones were imported into allowed zone successfully."); _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } } - public void FlushAllowedZone(HttpListenerRequest request) + public async Task ExportAllowedZonesAsync(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.AllowedZoneManager.ListZones(); + + HttpResponse response = context.Response; + + response.ContentType = "text/plain"; + response.Headers.ContentDisposition = "attachment;filename=AllowedZones.txt"; + + await using (StreamWriter sW = new StreamWriter(response.Body)) + { + foreach (AuthZoneInfo zoneInfo in zoneInfoList) + await sW.WriteLineAsync(zoneInfo.Name); + } + } + + public void DeleteAllowedZone(HttpContext context) + { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + string domain = context.Request.GetQuery("domain"); + + if (_dnsWebService._dnsServer.AllowedZoneManager.DeleteZone(domain)) + { + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Allowed zone was deleted: " + domain); + _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); + } + } + + public void FlushAllowedZone(HttpContext context) + { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + _dnsWebService._dnsServer.AllowedZoneManager.Flush(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Allowed zone was flushed successfully."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Allowed zone was flushed successfully."); _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } - public void AllowZone(HttpListenerRequest request) + public void AllowZone(HttpContext context) { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + string domain = context.Request.GetQuery("domain"); if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(domain)) { - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Zone was allowed: " + domain); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Zone was allowed: " + domain); _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } } @@ -298,13 +331,18 @@ namespace DnsServerCore #region blocked zones api - public void ListBlockedZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void ListBlockedZones(HttpContext context) { - string domain = request.QueryString["domain"]; - if (domain == null) - domain = ""; + UserSession session = context.GetCurrentSession(); - string direction = request.QueryString["direction"]; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string domain = request.GetQuery("domain", ""); + + string direction = request.Query["direction"]; if (direction is not null) direction = direction.ToLower(); @@ -348,6 +386,8 @@ namespace DnsServerCore subZones.Sort(); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); @@ -364,93 +404,103 @@ namespace DnsServerCore WebServiceZonesApi.WriteRecordsAsJson(new List(records), jsonWriter, false); } - public async Task ImportBlockedZonesAsync(HttpListenerRequest request) + public void ImportBlockedZones(HttpContext context) { - if (!request.ContentType.StartsWith("application/x-www-form-urlencoded")) + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + if (!request.HasFormContentType) throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); - string formRequest; - using (StreamReader sR = new StreamReader(request.InputStream, request.ContentEncoding)) + string blockedZones = request.Form["blockedZones"]; + if (string.IsNullOrEmpty(blockedZones)) + throw new DnsWebServiceException("Form parameter 'blockedZones' missing."); + + string[] blockedZonesList = blockedZones.Split(','); + bool added = false; + + foreach (string blockedZone in blockedZonesList) { - formRequest = await sR.ReadToEndAsync(); + if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(blockedZone)) + added = true; } - string[] formParts = formRequest.Split('&'); - - foreach (string formPart in formParts) + if (added) { - if (formPart.StartsWith("blockedZones=")) - { - string value = Uri.UnescapeDataString(formPart.Substring(13)); - string[] blockedZones = value.Split(','); - bool added = false; - - foreach (string blockedZone in blockedZones) - { - if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(blockedZone)) - added = true; - } - - if (added) - { - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Total " + blockedZones.Length + " zones were imported into blocked zone successfully."); - _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); - } - - return; - } - } - - throw new DnsWebServiceException("Parameter 'blockedZones' missing."); - } - - public void ExportBlockedZones(HttpListenerResponse response) - { - IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.BlockedZoneManager.ListZones(); - - response.ContentType = "text/plain"; - response.AddHeader("Content-Disposition", "attachment;filename=BlockedZones.txt"); - - using (StreamWriter sW = new StreamWriter(new BufferedStream(response.OutputStream))) - { - foreach (AuthZoneInfo zoneInfo in zoneInfoList) - sW.WriteLine(zoneInfo.Name); - } - } - - public void DeleteBlockedZone(HttpListenerRequest request) - { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); - - if (_dnsWebService._dnsServer.BlockedZoneManager.DeleteZone(domain)) - { - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocked zone was deleted: " + domain); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Total " + blockedZonesList.Length + " zones were imported into blocked zone successfully."); _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } } - public void FlushBlockedZone(HttpListenerRequest request) + public async Task ExportBlockedZonesAsync(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.BlockedZoneManager.ListZones(); + + HttpResponse response = context.Response; + + response.ContentType = "text/plain"; + response.Headers.ContentDisposition = "attachment;filename=BlockedZones.txt"; + + await using (StreamWriter sW = new StreamWriter(response.Body)) + { + foreach (AuthZoneInfo zoneInfo in zoneInfoList) + await sW.WriteLineAsync(zoneInfo.Name); + } + } + + public void DeleteBlockedZone(HttpContext context) + { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + + string domain = context.Request.GetQuery("domain"); + + if (_dnsWebService._dnsServer.BlockedZoneManager.DeleteZone(domain)) + { + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocked zone was deleted: " + domain); + _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); + } + } + + public void FlushBlockedZone(HttpContext context) + { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); + _dnsWebService._dnsServer.BlockedZoneManager.Flush(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocked zone was flushed successfully."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocked zone was flushed successfully."); _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } - public void BlockZone(HttpListenerRequest request) + public void BlockZone(HttpContext context) { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + string domain = context.Request.GetQuery("domain"); if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(domain)) { - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Domain was added to blocked zone: " + domain); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Domain was added to blocked zone: " + domain); _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } } From 99354a21491048d49b407e56d779adb9f14b397e Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 18:27:19 +0530 Subject: [PATCH 054/191] WebServiceSettingsApi: updated code to support kestral. --- DnsServerCore/WebServiceSettingsApi.cs | 932 ++++++++++--------------- 1 file changed, 382 insertions(+), 550 deletions(-) diff --git a/DnsServerCore/WebServiceSettingsApi.cs b/DnsServerCore/WebServiceSettingsApi.cs index 7fec9519..c018ff0e 100644 --- a/DnsServerCore/WebServiceSettingsApi.cs +++ b/DnsServerCore/WebServiceSettingsApi.cs @@ -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 @@ -19,10 +19,12 @@ along with this program. If not, see . using DnsServerCore.Auth; using DnsServerCore.Dns; +using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; @@ -30,7 +32,7 @@ using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using TechnitiumLibrary.IO; +using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -183,8 +185,8 @@ namespace DnsServerCore try { - _dnsWebService.StopDnsWebService(); - _dnsWebService.StartDnsWebService(); + await _dnsWebService.StopWebServiceAsync(); + await _dnsWebService.StartWebServiceAsync(); _dnsWebService._log.Write("Web service was restarted successfully."); } @@ -219,11 +221,7 @@ namespace DnsServerCore } } - #endregion - - #region public - - public void GetDnsSettings(Utf8JsonWriter jsonWriter) + private void WriteDnsSettings(Utf8JsonWriter jsonWriter) { //general jsonWriter.WriteString("version", _dnsWebService.GetServerVersion()); @@ -480,40 +478,56 @@ namespace DnsServerCore jsonWriter.WriteNumber("maxStatFileDays", _dnsWebService._dnsServer.StatsManager.MaxStatFileDays); } - public void SetDnsSettings(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + #endregion + + #region public + + public void GetDnsSettings(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + WriteDnsSettings(jsonWriter); + } + + public void SetDnsSettings(HttpContext context) + { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + bool serverDomainChanged = false; bool restartDnsService = false; bool restartWebService = false; + bool blockListUrlsUpdated = false; int oldWebServiceHttpPort = _dnsWebService._webServiceHttpPort; + HttpRequest request = context.Request; + //general - string strDnsServerDomain = request.QueryString["dnsServerDomain"]; - if (!string.IsNullOrEmpty(strDnsServerDomain)) + if (request.TryGetQuery("dnsServerDomain", out string dnsServerDomain)) { - serverDomainChanged = !_dnsWebService._dnsServer.ServerDomain.Equals(strDnsServerDomain, StringComparison.OrdinalIgnoreCase); - _dnsWebService._dnsServer.ServerDomain = strDnsServerDomain; + if (!_dnsWebService._dnsServer.ServerDomain.Equals(dnsServerDomain, StringComparison.OrdinalIgnoreCase)) + { + _dnsWebService._dnsServer.ServerDomain = dnsServerDomain; + serverDomainChanged = true; + } } - string strDnsServerLocalEndPoints = request.QueryString["dnsServerLocalEndPoints"]; - if (strDnsServerLocalEndPoints != null) + string dnsServerLocalEndPoints = request.Query["dnsServerLocalEndPoints"]; + if (dnsServerLocalEndPoints is not null) { - if (string.IsNullOrEmpty(strDnsServerLocalEndPoints)) - strDnsServerLocalEndPoints = "0.0.0.0:53,[::]:53"; + if (dnsServerLocalEndPoints.Length == 0) + dnsServerLocalEndPoints = "0.0.0.0:53,[::]:53"; - string[] strLocalEndPoints = strDnsServerLocalEndPoints.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List localEndPoints = new List(strLocalEndPoints.Length); - - for (int i = 0; i < strLocalEndPoints.Length; i++) + IPEndPoint[] localEndPoints = dnsServerLocalEndPoints.Split(IPEndPoint.Parse, ','); + if (localEndPoints.Length > 0) { - NameServerAddress nameServer = new NameServerAddress(strLocalEndPoints[i]); - if (nameServer.IPEndPoint != null) - localEndPoints.Add(nameServer.IPEndPoint); - } - - if (localEndPoints.Count > 0) - { - if (_dnsWebService._dnsServer.LocalEndPoints.Count != localEndPoints.Count) + if (_dnsWebService._dnsServer.LocalEndPoints.Count != localEndPoints.Length) { restartDnsService = true; } @@ -533,89 +547,65 @@ namespace DnsServerCore } } - string strDefaultRecordTtl = request.QueryString["defaultRecordTtl"]; - if (!string.IsNullOrEmpty(strDefaultRecordTtl)) - _dnsWebService._zonesApi.DefaultRecordTtl = uint.Parse(strDefaultRecordTtl); + if (request.TryGetQuery("defaultRecordTtl", uint.Parse, out uint defaultRecordTtl)) + _dnsWebService._zonesApi.DefaultRecordTtl = defaultRecordTtl; - string strDnsAppsEnableAutomaticUpdate = request.QueryString["dnsAppsEnableAutomaticUpdate"]; - if (!string.IsNullOrEmpty(strDnsAppsEnableAutomaticUpdate)) - _dnsWebService._appsApi.EnableAutomaticUpdate = bool.Parse(strDnsAppsEnableAutomaticUpdate); + if (request.TryGetQuery("dnsAppsEnableAutomaticUpdate", bool.Parse, out bool dnsAppsEnableAutomaticUpdate)) + _dnsWebService._appsApi.EnableAutomaticUpdate = dnsAppsEnableAutomaticUpdate; - string strPreferIPv6 = request.QueryString["preferIPv6"]; - if (!string.IsNullOrEmpty(strPreferIPv6)) - _dnsWebService._dnsServer.PreferIPv6 = bool.Parse(strPreferIPv6); + if (request.TryGetQuery("preferIPv6", bool.Parse, out bool preferIPv6)) + _dnsWebService._dnsServer.PreferIPv6 = preferIPv6; - string strUdpPayloadSize = request.QueryString["udpPayloadSize"]; - if (!string.IsNullOrEmpty(strUdpPayloadSize)) - _dnsWebService._dnsServer.UdpPayloadSize = ushort.Parse(strUdpPayloadSize); + if (request.TryGetQuery("udpPayloadSize", ushort.Parse, out ushort udpPayloadSize)) + _dnsWebService._dnsServer.UdpPayloadSize = udpPayloadSize; - string strDnssecValidation = request.QueryString["dnssecValidation"]; - if (!string.IsNullOrEmpty(strDnssecValidation)) - _dnsWebService._dnsServer.DnssecValidation = bool.Parse(strDnssecValidation); + if (request.TryGetQuery("dnssecValidation", bool.Parse, out bool dnssecValidation)) + _dnsWebService._dnsServer.DnssecValidation = dnssecValidation; - string strEDnsClientSubnet = request.QueryString["eDnsClientSubnet"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnet)) - _dnsWebService._dnsServer.EDnsClientSubnet = bool.Parse(strEDnsClientSubnet); + if (request.TryGetQuery("eDnsClientSubnet", bool.Parse, out bool eDnsClientSubnet)) + _dnsWebService._dnsServer.EDnsClientSubnet = eDnsClientSubnet; - string strEDnsClientSubnetIPv4PrefixLength = request.QueryString["eDnsClientSubnetIPv4PrefixLength"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv4PrefixLength)) - _dnsWebService._dnsServer.EDnsClientSubnetIPv4PrefixLength = byte.Parse(strEDnsClientSubnetIPv4PrefixLength); + if (request.TryGetQuery("eDnsClientSubnetIPv4PrefixLength", byte.Parse, out byte eDnsClientSubnetIPv4PrefixLength)) + _dnsWebService._dnsServer.EDnsClientSubnetIPv4PrefixLength = eDnsClientSubnetIPv4PrefixLength; - string strEDnsClientSubnetIPv6PrefixLength = request.QueryString["eDnsClientSubnetIPv6PrefixLength"]; - if (!string.IsNullOrEmpty(strEDnsClientSubnetIPv6PrefixLength)) - _dnsWebService._dnsServer.EDnsClientSubnetIPv6PrefixLength = byte.Parse(strEDnsClientSubnetIPv6PrefixLength); + if (request.TryGetQuery("eDnsClientSubnetIPv6PrefixLength", byte.Parse, out byte eDnsClientSubnetIPv6PrefixLength)) + _dnsWebService._dnsServer.EDnsClientSubnetIPv6PrefixLength = eDnsClientSubnetIPv6PrefixLength; - string strQpmLimitRequests = request.QueryString["qpmLimitRequests"]; - if (!string.IsNullOrEmpty(strQpmLimitRequests)) - _dnsWebService._dnsServer.QpmLimitRequests = int.Parse(strQpmLimitRequests); + if (request.TryGetQuery("qpmLimitRequests", int.Parse, out int qpmLimitRequests)) + _dnsWebService._dnsServer.QpmLimitRequests = qpmLimitRequests; - string strQpmLimitErrors = request.QueryString["qpmLimitErrors"]; - if (!string.IsNullOrEmpty(strQpmLimitErrors)) - _dnsWebService._dnsServer.QpmLimitErrors = int.Parse(strQpmLimitErrors); + if (request.TryGetQuery("qpmLimitErrors", int.Parse, out int qpmLimitErrors)) + _dnsWebService._dnsServer.QpmLimitErrors = qpmLimitErrors; - string strQpmLimitSampleMinutes = request.QueryString["qpmLimitSampleMinutes"]; - if (!string.IsNullOrEmpty(strQpmLimitSampleMinutes)) - _dnsWebService._dnsServer.QpmLimitSampleMinutes = int.Parse(strQpmLimitSampleMinutes); + if (request.TryGetQuery("qpmLimitSampleMinutes", int.Parse, out int qpmLimitSampleMinutes)) + _dnsWebService._dnsServer.QpmLimitSampleMinutes = qpmLimitSampleMinutes; - string strQpmLimitIPv4PrefixLength = request.QueryString["qpmLimitIPv4PrefixLength"]; - if (!string.IsNullOrEmpty(strQpmLimitIPv4PrefixLength)) - _dnsWebService._dnsServer.QpmLimitIPv4PrefixLength = int.Parse(strQpmLimitIPv4PrefixLength); + if (request.TryGetQuery("qpmLimitIPv4PrefixLength", int.Parse, out int qpmLimitIPv4PrefixLength)) + _dnsWebService._dnsServer.QpmLimitIPv4PrefixLength = qpmLimitIPv4PrefixLength; - string strQpmLimitIPv6PrefixLength = request.QueryString["qpmLimitIPv6PrefixLength"]; - if (!string.IsNullOrEmpty(strQpmLimitIPv6PrefixLength)) - _dnsWebService._dnsServer.QpmLimitIPv6PrefixLength = int.Parse(strQpmLimitIPv6PrefixLength); + if (request.TryGetQuery("qpmLimitIPv6PrefixLength", int.Parse, out int qpmLimitIPv6PrefixLength)) + _dnsWebService._dnsServer.QpmLimitIPv6PrefixLength = qpmLimitIPv6PrefixLength; - string strClientTimeout = request.QueryString["clientTimeout"]; - if (!string.IsNullOrEmpty(strClientTimeout)) - _dnsWebService._dnsServer.ClientTimeout = int.Parse(strClientTimeout); + if (request.TryGetQuery("clientTimeout", int.Parse, out int clientTimeout)) + _dnsWebService._dnsServer.ClientTimeout = clientTimeout; - string strTcpSendTimeout = request.QueryString["tcpSendTimeout"]; - if (!string.IsNullOrEmpty(strTcpSendTimeout)) - _dnsWebService._dnsServer.TcpSendTimeout = int.Parse(strTcpSendTimeout); + if (request.TryGetQuery("tcpSendTimeout", int.Parse, out int tcpSendTimeout)) + _dnsWebService._dnsServer.TcpSendTimeout = tcpSendTimeout; - string strTcpReceiveTimeout = request.QueryString["tcpReceiveTimeout"]; - if (!string.IsNullOrEmpty(strTcpReceiveTimeout)) - _dnsWebService._dnsServer.TcpReceiveTimeout = int.Parse(strTcpReceiveTimeout); + if (request.TryGetQuery("tcpReceiveTimeout", int.Parse, out int tcpReceiveTimeout)) + _dnsWebService._dnsServer.TcpReceiveTimeout = tcpReceiveTimeout; //web service - string strWebServiceLocalAddresses = request.QueryString["webServiceLocalAddresses"]; - if (strWebServiceLocalAddresses != null) + string webServiceLocalAddresses = request.Query["webServiceLocalAddresses"]; + if (webServiceLocalAddresses is not null) { - if (string.IsNullOrEmpty(strWebServiceLocalAddresses)) - strWebServiceLocalAddresses = "0.0.0.0,[::]"; + if (webServiceLocalAddresses.Length == 0) + webServiceLocalAddresses = "0.0.0.0,[::]"; - string[] strLocalAddresses = strWebServiceLocalAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List localAddresses = new List(strLocalAddresses.Length); - - for (int i = 0; i < strLocalAddresses.Length; i++) + IPAddress[] localAddresses = webServiceLocalAddresses.Split(IPAddress.Parse, ','); + if (localAddresses.Length > 0) { - if (IPAddress.TryParse(strLocalAddresses[i], out IPAddress localAddress)) - localAddresses.Add(localAddress); - } - - if (localAddresses.Count > 0) - { - if (_dnsWebService._webServiceLocalAddresses.Count != localAddresses.Count) + if (_dnsWebService._webServiceLocalAddresses.Count != localAddresses.Length) { restartWebService = true; } @@ -635,130 +625,132 @@ namespace DnsServerCore } } - string strWebServiceHttpPort = request.QueryString["webServiceHttpPort"]; - if (!string.IsNullOrEmpty(strWebServiceHttpPort)) + if (request.TryGetQuery("webServiceHttpPort", int.Parse, out int webServiceHttpPort)) { - _dnsWebService._webServiceHttpPort = int.Parse(strWebServiceHttpPort); - - if (oldWebServiceHttpPort != _dnsWebService._webServiceHttpPort) - restartWebService = true; - } - - string strWebServiceEnableTls = request.QueryString["webServiceEnableTls"]; - if (!string.IsNullOrEmpty(strWebServiceEnableTls)) - { - bool oldWebServiceEnableTls = _dnsWebService._webServiceEnableTls; - - _dnsWebService._webServiceEnableTls = bool.Parse(strWebServiceEnableTls); - - if (oldWebServiceEnableTls != _dnsWebService._webServiceEnableTls) - restartWebService = true; - } - - string strWebServiceHttpToTlsRedirect = request.QueryString["webServiceHttpToTlsRedirect"]; - if (!string.IsNullOrEmpty(strWebServiceHttpToTlsRedirect)) - _dnsWebService._webServiceHttpToTlsRedirect = bool.Parse(strWebServiceHttpToTlsRedirect); - - string strWebServiceUseSelfSignedTlsCertificate = request.QueryString["webServiceUseSelfSignedTlsCertificate"]; - if (!string.IsNullOrEmpty(strWebServiceUseSelfSignedTlsCertificate)) - _dnsWebService._webServiceUseSelfSignedTlsCertificate = bool.Parse(strWebServiceUseSelfSignedTlsCertificate); - - string strWebServiceTlsPort = request.QueryString["webServiceTlsPort"]; - if (!string.IsNullOrEmpty(strWebServiceTlsPort)) - { - int oldWebServiceTlsPort = _dnsWebService._webServiceTlsPort; - - _dnsWebService._webServiceTlsPort = int.Parse(strWebServiceTlsPort); - - if (oldWebServiceTlsPort != _dnsWebService._webServiceTlsPort) - restartWebService = true; - } - - string strWebServiceTlsCertificatePath = request.QueryString["webServiceTlsCertificatePath"]; - string strWebServiceTlsCertificatePassword = request.QueryString["webServiceTlsCertificatePassword"]; - if (string.IsNullOrEmpty(strWebServiceTlsCertificatePath)) - { - _dnsWebService._webServiceTlsCertificatePath = null; - _dnsWebService._webServiceTlsCertificatePassword = ""; - } - else - { - if (strWebServiceTlsCertificatePassword == "************") - strWebServiceTlsCertificatePassword = _dnsWebService._webServiceTlsCertificatePassword; - - if ((strWebServiceTlsCertificatePath != _dnsWebService._webServiceTlsCertificatePath) || (strWebServiceTlsCertificatePassword != _dnsWebService._webServiceTlsCertificatePassword)) + if (_dnsWebService._webServiceHttpPort != webServiceHttpPort) { - _dnsWebService.LoadWebServiceTlsCertificate(strWebServiceTlsCertificatePath, strWebServiceTlsCertificatePassword); + _dnsWebService._webServiceHttpPort = webServiceHttpPort; + restartWebService = true; + } + } - _dnsWebService._webServiceTlsCertificatePath = strWebServiceTlsCertificatePath; - _dnsWebService._webServiceTlsCertificatePassword = strWebServiceTlsCertificatePassword; + if (request.TryGetQuery("webServiceEnableTls", bool.Parse, out bool webServiceEnableTls)) + { + if (_dnsWebService._webServiceEnableTls != webServiceEnableTls) + { + _dnsWebService._webServiceEnableTls = webServiceEnableTls; + restartWebService = true; + } + } - _dnsWebService.StartTlsCertificateUpdateTimer(); + if (request.TryGetQuery("webServiceHttpToTlsRedirect", bool.Parse, out bool webServiceHttpToTlsRedirect)) + { + if (_dnsWebService._webServiceHttpToTlsRedirect != webServiceHttpToTlsRedirect) + { + _dnsWebService._webServiceHttpToTlsRedirect = webServiceHttpToTlsRedirect; + restartWebService = true; + } + } + + if (request.TryGetQuery("webServiceUseSelfSignedTlsCertificate", bool.Parse, out bool webServiceUseSelfSignedTlsCertificate)) + _dnsWebService._webServiceUseSelfSignedTlsCertificate = webServiceUseSelfSignedTlsCertificate; + + if (request.TryGetQuery("webServiceTlsPort", int.Parse, out int webServiceTlsPort)) + { + if (_dnsWebService._webServiceTlsPort != webServiceTlsPort) + { + _dnsWebService._webServiceTlsPort = webServiceTlsPort; + restartWebService = true; + } + } + + string webServiceTlsCertificatePath = request.Query["webServiceTlsCertificatePath"]; + if (webServiceTlsCertificatePath is not null) + { + if (webServiceTlsCertificatePath.Length == 0) + { + _dnsWebService._webServiceTlsCertificatePath = null; + _dnsWebService._webServiceTlsCertificatePassword = ""; + } + else + { + string webServiceTlsCertificatePassword = request.Query["webServiceTlsCertificatePassword"]; + + if ((webServiceTlsCertificatePassword is null) || (webServiceTlsCertificatePassword == "************")) + webServiceTlsCertificatePassword = _dnsWebService._webServiceTlsCertificatePassword; + + if ((webServiceTlsCertificatePath != _dnsWebService._webServiceTlsCertificatePath) || (webServiceTlsCertificatePassword != _dnsWebService._webServiceTlsCertificatePassword)) + { + _dnsWebService.LoadWebServiceTlsCertificate(webServiceTlsCertificatePath, webServiceTlsCertificatePassword); + + _dnsWebService._webServiceTlsCertificatePath = webServiceTlsCertificatePath; + _dnsWebService._webServiceTlsCertificatePassword = webServiceTlsCertificatePassword; + + _dnsWebService.StartTlsCertificateUpdateTimer(); + } } } //optional protocols - string enableDnsOverHttp = request.QueryString["enableDnsOverHttp"]; - if (!string.IsNullOrEmpty(enableDnsOverHttp)) + if (request.TryGetQuery("enableDnsOverHttp", bool.Parse, out bool enableDnsOverHttp)) { - bool oldEnableDnsOverHttp = _dnsWebService._dnsServer.EnableDnsOverHttp; - - _dnsWebService._dnsServer.EnableDnsOverHttp = bool.Parse(enableDnsOverHttp); - - if (oldEnableDnsOverHttp != _dnsWebService._dnsServer.EnableDnsOverHttp) - restartDnsService = true; - } - - string strEnableDnsOverTls = request.QueryString["enableDnsOverTls"]; - if (!string.IsNullOrEmpty(strEnableDnsOverTls)) - { - bool oldEnableDnsOverTls = _dnsWebService._dnsServer.EnableDnsOverTls; - - _dnsWebService._dnsServer.EnableDnsOverTls = bool.Parse(strEnableDnsOverTls); - - if (oldEnableDnsOverTls != _dnsWebService._dnsServer.EnableDnsOverTls) - restartDnsService = true; - } - - string strEnableDnsOverHttps = request.QueryString["enableDnsOverHttps"]; - if (!string.IsNullOrEmpty(strEnableDnsOverHttps)) - { - bool oldEnableDnsOverHttps = _dnsWebService._dnsServer.EnableDnsOverHttps; - - _dnsWebService._dnsServer.EnableDnsOverHttps = bool.Parse(strEnableDnsOverHttps); - - if (oldEnableDnsOverHttps != _dnsWebService._dnsServer.EnableDnsOverHttps) - restartDnsService = true; - } - - string strDnsTlsCertificatePath = request.QueryString["dnsTlsCertificatePath"]; - string strDnsTlsCertificatePassword = request.QueryString["dnsTlsCertificatePassword"]; - if (string.IsNullOrEmpty(strDnsTlsCertificatePath)) - { - _dnsWebService._dnsTlsCertificatePath = null; - _dnsWebService._dnsTlsCertificatePassword = ""; - } - else - { - if (strDnsTlsCertificatePassword == "************") - strDnsTlsCertificatePassword = _dnsWebService._dnsTlsCertificatePassword; - - if ((strDnsTlsCertificatePath != _dnsWebService._dnsTlsCertificatePath) || (strDnsTlsCertificatePassword != _dnsWebService._dnsTlsCertificatePassword)) + if (_dnsWebService._dnsServer.EnableDnsOverHttp != enableDnsOverHttp) { - _dnsWebService.LoadDnsTlsCertificate(strDnsTlsCertificatePath, strDnsTlsCertificatePassword); + _dnsWebService._dnsServer.EnableDnsOverHttp = enableDnsOverHttp; + restartDnsService = true; + } + } - _dnsWebService._dnsTlsCertificatePath = strDnsTlsCertificatePath; - _dnsWebService._dnsTlsCertificatePassword = strDnsTlsCertificatePassword; + if (request.TryGetQuery("enableDnsOverTls", bool.Parse, out bool enableDnsOverTls)) + { + if (_dnsWebService._dnsServer.EnableDnsOverTls != enableDnsOverTls) + { + _dnsWebService._dnsServer.EnableDnsOverTls = enableDnsOverTls; + restartDnsService = true; + } + } - _dnsWebService.StartTlsCertificateUpdateTimer(); + if (request.TryGetQuery("enableDnsOverHttps", bool.Parse, out bool enableDnsOverHttps)) + { + if (_dnsWebService._dnsServer.EnableDnsOverHttps != enableDnsOverHttps) + { + _dnsWebService._dnsServer.EnableDnsOverHttps = enableDnsOverHttps; + restartDnsService = true; + } + } + + string dnsTlsCertificatePath = request.Query["dnsTlsCertificatePath"]; + if (dnsTlsCertificatePath is not null) + { + if (dnsTlsCertificatePath.Length == 0) + { + _dnsWebService._dnsTlsCertificatePath = null; + _dnsWebService._dnsTlsCertificatePassword = ""; + } + else + { + string strDnsTlsCertificatePassword = request.Query["dnsTlsCertificatePassword"]; + + if ((strDnsTlsCertificatePassword is null) || (strDnsTlsCertificatePassword == "************")) + strDnsTlsCertificatePassword = _dnsWebService._dnsTlsCertificatePassword; + + if ((dnsTlsCertificatePath != _dnsWebService._dnsTlsCertificatePath) || (strDnsTlsCertificatePassword != _dnsWebService._dnsTlsCertificatePassword)) + { + _dnsWebService.LoadDnsTlsCertificate(dnsTlsCertificatePath, strDnsTlsCertificatePassword); + + _dnsWebService._dnsTlsCertificatePath = dnsTlsCertificatePath; + _dnsWebService._dnsTlsCertificatePassword = strDnsTlsCertificatePassword; + + _dnsWebService.StartTlsCertificateUpdateTimer(); + } } } //tsig - string strTsigKeys = request.QueryString["tsigKeys"]; - if (!string.IsNullOrEmpty(strTsigKeys)) + string strTsigKeys = request.Query["tsigKeys"]; + if (strTsigKeys is not null) { - if (strTsigKeys == "false") + if ((strTsigKeys.Length == 0) || strTsigKeys.Equals("false", StringComparison.OrdinalIgnoreCase)) { _dnsWebService._dnsServer.TsigKeys = null; } @@ -791,124 +783,83 @@ namespace DnsServerCore } //recursion - string strRecursion = request.QueryString["recursion"]; - if (!string.IsNullOrEmpty(strRecursion)) - _dnsWebService._dnsServer.Recursion = Enum.Parse(strRecursion, true); + if (request.TryGetQuery("recursion", out DnsServerRecursion recursion)) + _dnsWebService._dnsServer.Recursion = recursion; - string strRecursionDeniedNetworks = request.QueryString["recursionDeniedNetworks"]; - if (!string.IsNullOrEmpty(strRecursionDeniedNetworks)) + string recursionDeniedNetworks = request.Query["recursionDeniedNetworks"]; + if (recursionDeniedNetworks is not null) { - if (strRecursionDeniedNetworks == "false") - { + if ((recursionDeniedNetworks.Length == 0) || recursionDeniedNetworks.Equals("false", StringComparison.OrdinalIgnoreCase)) _dnsWebService._dnsServer.RecursionDeniedNetworks = null; - } else - { - string[] strNetworks = strRecursionDeniedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - NetworkAddress[] networks = new NetworkAddress[strNetworks.Length]; - - for (int i = 0; i < networks.Length; i++) - networks[i] = NetworkAddress.Parse(strNetworks[i]); - - _dnsWebService._dnsServer.RecursionDeniedNetworks = networks; - } + _dnsWebService._dnsServer.RecursionDeniedNetworks = recursionDeniedNetworks.Split(NetworkAddress.Parse, ','); } - string strRecursionAllowedNetworks = request.QueryString["recursionAllowedNetworks"]; - if (!string.IsNullOrEmpty(strRecursionAllowedNetworks)) + string recursionAllowedNetworks = request.Query["recursionAllowedNetworks"]; + if (recursionAllowedNetworks is not null) { - if (strRecursionAllowedNetworks == "false") - { + if ((recursionAllowedNetworks.Length == 0) || recursionAllowedNetworks.Equals("false", StringComparison.OrdinalIgnoreCase)) _dnsWebService._dnsServer.RecursionAllowedNetworks = null; - } else - { - string[] strNetworks = strRecursionAllowedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - NetworkAddress[] networks = new NetworkAddress[strNetworks.Length]; - - for (int i = 0; i < networks.Length; i++) - networks[i] = NetworkAddress.Parse(strNetworks[i]); - - _dnsWebService._dnsServer.RecursionAllowedNetworks = networks; - } + _dnsWebService._dnsServer.RecursionAllowedNetworks = recursionAllowedNetworks.Split(NetworkAddress.Parse, ','); } - string strRandomizeName = request.QueryString["randomizeName"]; - if (!string.IsNullOrEmpty(strRandomizeName)) - _dnsWebService._dnsServer.RandomizeName = bool.Parse(strRandomizeName); + if (request.TryGetQuery("randomizeName", bool.Parse, out bool randomizeName)) + _dnsWebService._dnsServer.RandomizeName = randomizeName; - string strQnameMinimization = request.QueryString["qnameMinimization"]; - if (!string.IsNullOrEmpty(strQnameMinimization)) - _dnsWebService._dnsServer.QnameMinimization = bool.Parse(strQnameMinimization); + if (request.TryGetQuery("qnameMinimization", bool.Parse, out bool qnameMinimization)) + _dnsWebService._dnsServer.QnameMinimization = qnameMinimization; - string strNsRevalidation = request.QueryString["nsRevalidation"]; - if (!string.IsNullOrEmpty(strNsRevalidation)) - _dnsWebService._dnsServer.NsRevalidation = bool.Parse(strNsRevalidation); + if (request.TryGetQuery("nsRevalidation", bool.Parse, out bool nsRevalidation)) + _dnsWebService._dnsServer.NsRevalidation = nsRevalidation; - string strResolverRetries = request.QueryString["resolverRetries"]; - if (!string.IsNullOrEmpty(strResolverRetries)) - _dnsWebService._dnsServer.ResolverRetries = int.Parse(strResolverRetries); + if (request.TryGetQuery("resolverRetries", int.Parse, out int resolverRetries)) + _dnsWebService._dnsServer.ResolverRetries = resolverRetries; - string strResolverTimeout = request.QueryString["resolverTimeout"]; - if (!string.IsNullOrEmpty(strResolverTimeout)) - _dnsWebService._dnsServer.ResolverTimeout = int.Parse(strResolverTimeout); + if (request.TryGetQuery("resolverTimeout", int.Parse, out int resolverTimeout)) + _dnsWebService._dnsServer.ResolverTimeout = resolverTimeout; - string strResolverMaxStackCount = request.QueryString["resolverMaxStackCount"]; - if (!string.IsNullOrEmpty(strResolverMaxStackCount)) - _dnsWebService._dnsServer.ResolverMaxStackCount = int.Parse(strResolverMaxStackCount); + if (request.TryGetQuery("resolverMaxStackCount", int.Parse, out int resolverMaxStackCount)) + _dnsWebService._dnsServer.ResolverMaxStackCount = resolverMaxStackCount; //cache - string strServeStale = request.QueryString["serveStale"]; - if (!string.IsNullOrEmpty(strServeStale)) - _dnsWebService._dnsServer.ServeStale = bool.Parse(strServeStale); + if (request.TryGetQuery("serveStale", bool.Parse, out bool serveStale)) + _dnsWebService._dnsServer.ServeStale = serveStale; - string strServeStaleTtl = request.QueryString["serveStaleTtl"]; - if (!string.IsNullOrEmpty(strServeStaleTtl)) - _dnsWebService._dnsServer.CacheZoneManager.ServeStaleTtl = uint.Parse(strServeStaleTtl); + if (request.TryGetQuery("serveStaleTtl", uint.Parse, out uint serveStaleTtl)) + _dnsWebService._dnsServer.CacheZoneManager.ServeStaleTtl = serveStaleTtl; - string strCacheMaximumEntries = request.QueryString["cacheMaximumEntries"]; - if (!string.IsNullOrEmpty(strCacheMaximumEntries)) - _dnsWebService._dnsServer.CacheZoneManager.MaximumEntries = long.Parse(strCacheMaximumEntries); + if (request.TryGetQuery("cacheMaximumEntries", long.Parse, out long cacheMaximumEntries)) + _dnsWebService._dnsServer.CacheZoneManager.MaximumEntries = cacheMaximumEntries; - string strCacheMinimumRecordTtl = request.QueryString["cacheMinimumRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheMinimumRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.MinimumRecordTtl = uint.Parse(strCacheMinimumRecordTtl); + if (request.TryGetQuery("cacheMinimumRecordTtl", uint.Parse, out uint cacheMinimumRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.MinimumRecordTtl = cacheMinimumRecordTtl; - string strCacheMaximumRecordTtl = request.QueryString["cacheMaximumRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheMaximumRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.MaximumRecordTtl = uint.Parse(strCacheMaximumRecordTtl); + if (request.TryGetQuery("cacheMaximumRecordTtl", uint.Parse, out uint cacheMaximumRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.MaximumRecordTtl = cacheMaximumRecordTtl; - string strCacheNegativeRecordTtl = request.QueryString["cacheNegativeRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheNegativeRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.NegativeRecordTtl = uint.Parse(strCacheNegativeRecordTtl); + if (request.TryGetQuery("cacheNegativeRecordTtl", uint.Parse, out uint cacheNegativeRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.NegativeRecordTtl = cacheNegativeRecordTtl; - string strCacheFailureRecordTtl = request.QueryString["cacheFailureRecordTtl"]; - if (!string.IsNullOrEmpty(strCacheFailureRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.FailureRecordTtl = uint.Parse(strCacheFailureRecordTtl); + if (request.TryGetQuery("cacheFailureRecordTtl", uint.Parse, out uint cacheFailureRecordTtl)) + _dnsWebService._dnsServer.CacheZoneManager.FailureRecordTtl = cacheFailureRecordTtl; - string strCachePrefetchEligibility = request.QueryString["cachePrefetchEligibility"]; - if (!string.IsNullOrEmpty(strCachePrefetchEligibility)) - _dnsWebService._dnsServer.CachePrefetchEligibility = int.Parse(strCachePrefetchEligibility); + if (request.TryGetQuery("cachePrefetchEligibility", int.Parse, out int cachePrefetchEligibility)) + _dnsWebService._dnsServer.CachePrefetchEligibility = cachePrefetchEligibility; - string strCachePrefetchTrigger = request.QueryString["cachePrefetchTrigger"]; - if (!string.IsNullOrEmpty(strCachePrefetchTrigger)) - _dnsWebService._dnsServer.CachePrefetchTrigger = int.Parse(strCachePrefetchTrigger); + if (request.TryGetQuery("cachePrefetchTrigger", int.Parse, out int cachePrefetchTrigger)) + _dnsWebService._dnsServer.CachePrefetchTrigger = cachePrefetchTrigger; - string strCachePrefetchSampleIntervalInMinutes = request.QueryString["cachePrefetchSampleIntervalInMinutes"]; - if (!string.IsNullOrEmpty(strCachePrefetchSampleIntervalInMinutes)) - _dnsWebService._dnsServer.CachePrefetchSampleIntervalInMinutes = int.Parse(strCachePrefetchSampleIntervalInMinutes); + if (request.TryGetQuery("cachePrefetchSampleIntervalInMinutes", int.Parse, out int cachePrefetchSampleIntervalInMinutes)) + _dnsWebService._dnsServer.CachePrefetchSampleIntervalInMinutes = cachePrefetchSampleIntervalInMinutes; - string strCachePrefetchSampleEligibilityHitsPerHour = request.QueryString["cachePrefetchSampleEligibilityHitsPerHour"]; - if (!string.IsNullOrEmpty(strCachePrefetchSampleEligibilityHitsPerHour)) - _dnsWebService._dnsServer.CachePrefetchSampleEligibilityHitsPerHour = int.Parse(strCachePrefetchSampleEligibilityHitsPerHour); + if (request.TryGetQuery("cachePrefetchSampleEligibilityHitsPerHour", int.Parse, out int cachePrefetchSampleEligibilityHitsPerHour)) + _dnsWebService._dnsServer.CachePrefetchSampleEligibilityHitsPerHour = cachePrefetchSampleEligibilityHitsPerHour; //blocking - string strEnableBlocking = request.QueryString["enableBlocking"]; - if (!string.IsNullOrEmpty(strEnableBlocking)) + if (request.TryGetQuery("enableBlocking", bool.Parse, out bool enableBlocking)) { - _dnsWebService._dnsServer.EnableBlocking = bool.Parse(strEnableBlocking); + _dnsWebService._dnsServer.EnableBlocking = enableBlocking; if (_dnsWebService._dnsServer.EnableBlocking) { if (_temporaryDisableBlockingTimer is not null) @@ -916,25 +867,23 @@ namespace DnsServerCore } } - string strAllowTxtBlockingReport = request.QueryString["allowTxtBlockingReport"]; - if (!string.IsNullOrEmpty(strAllowTxtBlockingReport)) - _dnsWebService._dnsServer.AllowTxtBlockingReport = bool.Parse(strAllowTxtBlockingReport); + if (request.TryGetQuery("allowTxtBlockingReport", bool.Parse, out bool allowTxtBlockingReport)) + _dnsWebService._dnsServer.AllowTxtBlockingReport = allowTxtBlockingReport; - string strBlockingType = request.QueryString["blockingType"]; - if (!string.IsNullOrEmpty(strBlockingType)) - _dnsWebService._dnsServer.BlockingType = Enum.Parse(strBlockingType, true); + if (request.TryGetQuery("blockingType", out DnsServerBlockingType blockingType)) + _dnsWebService._dnsServer.BlockingType = blockingType; - string strCustomBlockingAddresses = request.QueryString["customBlockingAddresses"]; - if (!string.IsNullOrEmpty(strCustomBlockingAddresses)) + string customBlockingAddresses = request.Query["customBlockingAddresses"]; + if (customBlockingAddresses is not null) { - if (strCustomBlockingAddresses == "false") + if ((customBlockingAddresses.Length == 0) || customBlockingAddresses.Equals("false", StringComparison.OrdinalIgnoreCase)) { _dnsWebService._dnsServer.CustomBlockingARecords = null; _dnsWebService._dnsServer.CustomBlockingAAAARecords = null; } else { - string[] strAddresses = strCustomBlockingAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + string[] strAddresses = customBlockingAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); List dnsARecords = new List(); List dnsAAAARecords = new List(); @@ -961,11 +910,10 @@ namespace DnsServerCore } } - bool blockListUrlsUpdated = false; - string strBlockListUrls = request.QueryString["blockListUrls"]; - if (!string.IsNullOrEmpty(strBlockListUrls)) + string blockListUrls = request.Query["blockListUrls"]; + if (blockListUrls is not null) { - if (strBlockListUrls == "false") + if ((blockListUrls.Length == 0) || blockListUrls.Equals("false", StringComparison.OrdinalIgnoreCase)) { _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Clear(); _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Clear(); @@ -973,15 +921,15 @@ namespace DnsServerCore } else { - string[] strBlockListUrlList = strBlockListUrls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + string[] blockListUrlList = blockListUrls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (oldWebServiceHttpPort != _dnsWebService._webServiceHttpPort) { - for (int i = 0; i < strBlockListUrlList.Length; i++) + for (int i = 0; i < blockListUrlList.Length; i++) { - if (strBlockListUrlList[i].Contains("http://localhost:" + oldWebServiceHttpPort + "/blocklist.txt")) + if (blockListUrlList[i].Contains("http://localhost:" + oldWebServiceHttpPort + "/blocklist.txt")) { - strBlockListUrlList[i] = "http://localhost:" + _dnsWebService._webServiceHttpPort + "/blocklist.txt"; + blockListUrlList[i] = "http://localhost:" + _dnsWebService._webServiceHttpPort + "/blocklist.txt"; blockListUrlsUpdated = true; break; } @@ -990,13 +938,13 @@ namespace DnsServerCore if (!blockListUrlsUpdated) { - if (strBlockListUrlList.Length != (_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count)) + if (blockListUrlList.Length != (_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count)) { blockListUrlsUpdated = true; } else { - foreach (string strBlockListUrl in strBlockListUrlList) + foreach (string strBlockListUrl in blockListUrlList) { if (strBlockListUrl.StartsWith("!")) { @@ -1025,7 +973,7 @@ namespace DnsServerCore _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Clear(); _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Clear(); - foreach (string strBlockListUrl in strBlockListUrlList) + foreach (string strBlockListUrl in blockListUrlList) { if (strBlockListUrl.StartsWith("!")) { @@ -1046,34 +994,17 @@ namespace DnsServerCore } } - string strBlockListUpdateIntervalHours = request.QueryString["blockListUpdateIntervalHours"]; - if (!string.IsNullOrEmpty(strBlockListUpdateIntervalHours)) + if (request.TryGetQuery("blockListUpdateIntervalHours", int.Parse, out int blockListUpdateIntervalHours)) { - int blockListUpdateIntervalHours = int.Parse(strBlockListUpdateIntervalHours); - if ((blockListUpdateIntervalHours < 0) || (blockListUpdateIntervalHours > 168)) throw new DnsWebServiceException("Parameter `blockListUpdateIntervalHours` must be between 1 hour and 168 hours (7 days) or 0 to disable automatic update."); _blockListUpdateIntervalHours = blockListUpdateIntervalHours; } - if ((_blockListUpdateIntervalHours > 0) && ((_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count) > 0)) - { - if (blockListUrlsUpdated || (_blockListUpdateTimer is null)) - ForceUpdateBlockLists(); - - StartBlockListUpdateTimer(); - } - else - { - StopBlockListUpdateTimer(); - } - //proxy & forwarders - string strProxyType = request.QueryString["proxyType"]; - if (!string.IsNullOrEmpty(strProxyType)) + if (request.TryGetQuery("proxyType", out NetProxyType proxyType)) { - NetProxyType proxyType = Enum.Parse(strProxyType, true); if (proxyType == NetProxyType.None) { _dnsWebService._dnsServer.Proxy = null; @@ -1082,102 +1013,68 @@ namespace DnsServerCore { NetworkCredential credential = null; - string strUsername = request.QueryString["proxyUsername"]; - if (!string.IsNullOrEmpty(strUsername)) - credential = new NetworkCredential(strUsername, request.QueryString["proxyPassword"]); + if (request.TryGetQuery("proxyUsername", out string proxyUsername)) + credential = new NetworkCredential(proxyUsername, request.Query["proxyPassword"]); - _dnsWebService._dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.QueryString["proxyAddress"], int.Parse(request.QueryString["proxyPort"]), credential); + _dnsWebService._dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.Query["proxyAddress"], int.Parse(request.Query["proxyPort"]), credential); - string strProxyBypass = request.QueryString["proxyBypass"]; - if (!string.IsNullOrEmpty(strProxyBypass)) - { - string[] strBypassList = strProxyBypass.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - List bypassList = new List(strBypassList.Length); - - for (int i = 0; i < strBypassList.Length; i++) - bypassList.Add(new NetProxyBypassItem(strBypassList[i])); - - _dnsWebService._dnsServer.Proxy.BypassList = bypassList; - } + if (request.TryGetQuery("proxyBypass", out string proxyBypass)) + _dnsWebService._dnsServer.Proxy.BypassList = proxyBypass.Split(delegate (string value) { return new NetProxyBypassItem(value); }, ','); } } - DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; - string strForwarderProtocol = request.QueryString["forwarderProtocol"]; - if (!string.IsNullOrEmpty(strForwarderProtocol)) + string strForwarders = request.Query["forwarders"]; + if (strForwarders is not null) { - forwarderProtocol = Enum.Parse(strForwarderProtocol, true); - if (forwarderProtocol == DnsTransportProtocol.HttpsJson) - forwarderProtocol = DnsTransportProtocol.Https; - } - - string strForwarders = request.QueryString["forwarders"]; - if (!string.IsNullOrEmpty(strForwarders)) - { - if (strForwarders == "false") + if ((strForwarders.Length == 0) || strForwarders.Equals("false", StringComparison.OrdinalIgnoreCase)) { _dnsWebService._dnsServer.Forwarders = null; } else { - string[] strForwardersList = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - NameServerAddress[] forwarders = new NameServerAddress[strForwardersList.Length]; + DnsTransportProtocol forwarderProtocol = request.GetQuery("forwarderProtocol", DnsTransportProtocol.Udp); + if (forwarderProtocol == DnsTransportProtocol.HttpsJson) + forwarderProtocol = DnsTransportProtocol.Https; - for (int i = 0; i < strForwardersList.Length; i++) + _dnsWebService._dnsServer.Forwarders = strForwarders.Split(delegate (string value) { - NameServerAddress forwarder = new NameServerAddress(strForwardersList[i]); + NameServerAddress forwarder = NameServerAddress.Parse(value); if (forwarder.Protocol != forwarderProtocol) forwarder = forwarder.ChangeProtocol(forwarderProtocol); - forwarders[i] = forwarder; - } - - _dnsWebService._dnsServer.Forwarders = forwarders; + return forwarder; + }, ','); } } - string strForwarderRetries = request.QueryString["forwarderRetries"]; - if (!string.IsNullOrEmpty(strForwarderRetries)) - _dnsWebService._dnsServer.ForwarderRetries = int.Parse(strForwarderRetries); + if (request.TryGetQuery("forwarderRetries", int.Parse, out int forwarderRetries)) + _dnsWebService._dnsServer.ForwarderRetries = forwarderRetries; - string strForwarderTimeout = request.QueryString["forwarderTimeout"]; - if (!string.IsNullOrEmpty(strForwarderTimeout)) - _dnsWebService._dnsServer.ForwarderTimeout = int.Parse(strForwarderTimeout); + if (request.TryGetQuery("forwarderTimeout", int.Parse, out int forwarderTimeout)) + _dnsWebService._dnsServer.ForwarderTimeout = forwarderTimeout; - string strForwarderConcurrency = request.QueryString["forwarderConcurrency"]; - if (!string.IsNullOrEmpty(strForwarderConcurrency)) - _dnsWebService._dnsServer.ForwarderConcurrency = int.Parse(strForwarderConcurrency); + if (request.TryGetQuery("forwarderConcurrency", int.Parse, out int forwarderConcurrency)) + _dnsWebService._dnsServer.ForwarderConcurrency = forwarderConcurrency; //logging - string strEnableLogging = request.QueryString["enableLogging"]; - if (!string.IsNullOrEmpty(strEnableLogging)) - _dnsWebService._log.EnableLogging = bool.Parse(strEnableLogging); + if (request.TryGetQuery("enableLogging", bool.Parse, out bool enableLogging)) + _dnsWebService._log.EnableLogging = enableLogging; - string strLogQueries = request.QueryString["logQueries"]; - if (!string.IsNullOrEmpty(strLogQueries)) - { - if (bool.Parse(strLogQueries)) - _dnsWebService._dnsServer.QueryLogManager = _dnsWebService._log; - else - _dnsWebService._dnsServer.QueryLogManager = null; - } + if (request.TryGetQuery("logQueries", bool.Parse, out bool logQueries)) + _dnsWebService._dnsServer.QueryLogManager = logQueries ? _dnsWebService._log : null; - string strUseLocalTime = request.QueryString["useLocalTime"]; - if (!string.IsNullOrEmpty(strUseLocalTime)) - _dnsWebService._log.UseLocalTime = bool.Parse(strUseLocalTime); + if (request.TryGetQuery("useLocalTime", bool.Parse, out bool useLocalTime)) + _dnsWebService._log.UseLocalTime = useLocalTime; - string strLogFolder = request.QueryString["logFolder"]; - if (!string.IsNullOrEmpty(strLogFolder)) - _dnsWebService._log.LogFolder = strLogFolder; + if (request.TryGetQuery("logFolder", out string logFolder)) + _dnsWebService._log.LogFolder = logFolder; - string strMaxLogFileDays = request.QueryString["maxLogFileDays"]; - if (!string.IsNullOrEmpty(strMaxLogFileDays)) - _dnsWebService._log.MaxLogFileDays = int.Parse(strMaxLogFileDays); + if (request.TryGetQuery("maxLogFileDays", int.Parse, out int maxLogFileDays)) + _dnsWebService._log.MaxLogFileDays = maxLogFileDays; - string strMaxStatFileDays = request.QueryString["maxStatFileDays"]; - if (!string.IsNullOrEmpty(strMaxStatFileDays)) - _dnsWebService._dnsServer.StatsManager.MaxStatFileDays = int.Parse(strMaxStatFileDays); + if (request.TryGetQuery("maxStatFileDays", int.Parse, out int maxStatFileDays)) + _dnsWebService._dnsServer.StatsManager.MaxStatFileDays = maxStatFileDays; //TLS actions if ((_dnsWebService._webServiceTlsCertificatePath == null) && (_dnsWebService._dnsTlsCertificatePath == null)) @@ -1192,19 +1089,45 @@ namespace DnsServerCore restartWebService = true; } + //blocklist timers + if ((_blockListUpdateIntervalHours > 0) && ((_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count) > 0)) + { + if (blockListUrlsUpdated || (_blockListUpdateTimer is null)) + ForceUpdateBlockLists(); + + StartBlockListUpdateTimer(); + } + else + { + StopBlockListUpdateTimer(); + } + //save config _dnsWebService.SaveConfigFile(); _dnsWebService._log.Save(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] DNS Settings were updated successfully."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS Settings were updated successfully."); - GetDnsSettings(jsonWriter); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + WriteDnsSettings(jsonWriter); RestartService(restartDnsService, restartWebService); } - public void GetTsigKeyNames(Utf8JsonWriter jsonWriter) + public void GetTsigKeyNames(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if ( + !_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.View) && + !_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify) + ) + { + throw new DnsWebServiceException("Access was denied."); + } + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("tsigKeyNames"); { jsonWriter.WriteStartArray(); @@ -1219,63 +1142,26 @@ namespace DnsServerCore } } - public async Task BackupSettingsAsync(HttpListenerRequest request, HttpListenerResponse response) + public async Task BackupSettingsAsync(HttpContext context) { - bool blockLists = false; - bool logs = false; - bool scopes = false; - bool apps = false; - bool stats = false; - bool zones = false; - bool allowedZones = false; - bool blockedZones = false; - bool dnsSettings = false; - bool authConfig = false; - bool logSettings = false; + UserSession session = context.GetCurrentSession(); - string strBlockLists = request.QueryString["blockLists"]; - if (!string.IsNullOrEmpty(strBlockLists)) - blockLists = bool.Parse(strBlockLists); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - string strLogs = request.QueryString["logs"]; - if (!string.IsNullOrEmpty(strLogs)) - logs = bool.Parse(strLogs); + HttpRequest request = context.Request; - string strScopes = request.QueryString["scopes"]; - if (!string.IsNullOrEmpty(strScopes)) - scopes = bool.Parse(strScopes); - - string strApps = request.QueryString["apps"]; - if (!string.IsNullOrEmpty(strApps)) - apps = bool.Parse(strApps); - - string strStats = request.QueryString["stats"]; - if (!string.IsNullOrEmpty(strStats)) - stats = bool.Parse(strStats); - - string strZones = request.QueryString["zones"]; - if (!string.IsNullOrEmpty(strZones)) - zones = bool.Parse(strZones); - - string strAllowedZones = request.QueryString["allowedZones"]; - if (!string.IsNullOrEmpty(strAllowedZones)) - allowedZones = bool.Parse(strAllowedZones); - - string strBlockedZones = request.QueryString["blockedZones"]; - if (!string.IsNullOrEmpty(strBlockedZones)) - blockedZones = bool.Parse(strBlockedZones); - - string strDnsSettings = request.QueryString["dnsSettings"]; - if (!string.IsNullOrEmpty(strDnsSettings)) - dnsSettings = bool.Parse(strDnsSettings); - - string strAuthConfig = request.QueryString["authConfig"]; - if (!string.IsNullOrEmpty(strAuthConfig)) - authConfig = bool.Parse(strAuthConfig); - - string strLogSettings = request.QueryString["logSettings"]; - if (!string.IsNullOrEmpty(strLogSettings)) - logSettings = bool.Parse(strLogSettings); + bool blockLists = request.GetQuery("blockLists", bool.Parse, false); + bool logs = request.GetQuery("logs", bool.Parse, false); + bool scopes = request.GetQuery("scopes", bool.Parse, false); + bool apps = request.GetQuery("apps", bool.Parse, false); + bool stats = request.GetQuery("stats", bool.Parse, false); + bool zones = request.GetQuery("zones", bool.Parse, false); + bool allowedZones = request.GetQuery("allowedZones", bool.Parse, false); + bool blockedZones = request.GetQuery("blockedZones", bool.Parse, false); + bool dnsSettings = request.GetQuery("dnsSettings", bool.Parse, false); + bool authConfig = request.GetQuery("authConfig", bool.Parse, false); + bool logSettings = request.GetQuery("logSettings", bool.Parse, false); string tmpFile = Path.GetTempFileName(); try @@ -1410,11 +1296,13 @@ namespace DnsServerCore //send zip file backupZipStream.Position = 0; - response.ContentType = "application/zip"; - response.ContentLength64 = backupZipStream.Length; - response.AddHeader("Content-Disposition", "attachment;filename=DnsServerBackup.zip"); + HttpResponse response = context.Response; - using (Stream output = response.OutputStream) + response.ContentType = "application/zip"; + response.ContentLength = backupZipStream.Length; + response.Headers.ContentDisposition = "attachment;filename=DnsServerBackup.zip"; + + using (Stream output = response.Body) { await backupZipStream.CopyToAsync(output); } @@ -1432,95 +1320,33 @@ namespace DnsServerCore } } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Settings backup zip file was exported."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Settings backup zip file was exported."); } - public async Task RestoreSettingsAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task RestoreSettingsAsync(HttpContext context) { - bool blockLists = false; - bool logs = false; - bool scopes = false; - bool apps = false; - bool stats = false; - bool zones = false; - bool allowedZones = false; - bool blockedZones = false; - bool dnsSettings = false; - bool authConfig = false; - bool logSettings = false; + UserSession session = context.GetCurrentSession(); - bool deleteExistingFiles = false; + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - string strBlockLists = request.QueryString["blockLists"]; - if (!string.IsNullOrEmpty(strBlockLists)) - blockLists = bool.Parse(strBlockLists); + HttpRequest request = context.Request; - string strLogs = request.QueryString["logs"]; - if (!string.IsNullOrEmpty(strLogs)) - logs = bool.Parse(strLogs); + bool blockLists = request.GetQuery("blockLists", bool.Parse, false); + bool logs = request.GetQuery("logs", bool.Parse, false); + bool scopes = request.GetQuery("scopes", bool.Parse, false); + bool apps = request.GetQuery("apps", bool.Parse, false); + bool stats = request.GetQuery("stats", bool.Parse, false); + bool zones = request.GetQuery("zones", bool.Parse, false); + bool allowedZones = request.GetQuery("allowedZones", bool.Parse, false); + bool blockedZones = request.GetQuery("blockedZones", bool.Parse, false); + bool dnsSettings = request.GetQuery("dnsSettings", bool.Parse, false); + bool authConfig = request.GetQuery("authConfig", bool.Parse, false); + bool logSettings = request.GetQuery("logSettings", bool.Parse, false); + bool deleteExistingFiles = request.GetQuery("deleteExistingFiles", bool.Parse, false); - string strScopes = request.QueryString["scopes"]; - if (!string.IsNullOrEmpty(strScopes)) - scopes = bool.Parse(strScopes); - - string strApps = request.QueryString["apps"]; - if (!string.IsNullOrEmpty(strApps)) - apps = bool.Parse(strApps); - - string strStats = request.QueryString["stats"]; - if (!string.IsNullOrEmpty(strStats)) - stats = bool.Parse(strStats); - - string strZones = request.QueryString["zones"]; - if (!string.IsNullOrEmpty(strZones)) - zones = bool.Parse(strZones); - - string strAllowedZones = request.QueryString["allowedZones"]; - if (!string.IsNullOrEmpty(strAllowedZones)) - allowedZones = bool.Parse(strAllowedZones); - - string strBlockedZones = request.QueryString["blockedZones"]; - if (!string.IsNullOrEmpty(strBlockedZones)) - blockedZones = bool.Parse(strBlockedZones); - - string strDnsSettings = request.QueryString["dnsSettings"]; - if (!string.IsNullOrEmpty(strDnsSettings)) - dnsSettings = bool.Parse(strDnsSettings); - - string strAuthConfig = request.QueryString["authConfig"]; - if (!string.IsNullOrEmpty(strAuthConfig)) - authConfig = bool.Parse(strAuthConfig); - - string strLogSettings = request.QueryString["logSettings"]; - if (!string.IsNullOrEmpty(strLogSettings)) - logSettings = bool.Parse(strLogSettings); - - string strDeleteExistingFiles = request.QueryString["deleteExistingFiles"]; - if (!string.IsNullOrEmpty(strDeleteExistingFiles)) - deleteExistingFiles = bool.Parse(strDeleteExistingFiles); - - #region skip to content - - int crlfCount = 0; - int byteRead; - - while (crlfCount != 4) - { - byteRead = await request.InputStream.ReadByteValueAsync(); - switch (byteRead) - { - case 13: //CR - case 10: //LF - crlfCount++; - break; - - default: - crlfCount = 0; - break; - } - } - - #endregion + if (request.Form.Files.Count == 0) + throw new DnsWebServiceException("DNS backup zip file is missing."); //write to temp file string tmpFile = Path.GetTempFileName(); @@ -1528,13 +1354,11 @@ namespace DnsServerCore { using (FileStream fS = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite)) { - await request.InputStream.CopyToAsync(fS); + await request.Form.Files[0].CopyToAsync(fS); fS.Position = 0; using (ZipArchive backupZip = new ZipArchive(fS, ZipArchiveMode.Read, false, Encoding.UTF8)) { - UserSession session = _dnsWebService.GetSession(request); - if (logSettings || logs) { //stop logging @@ -1801,7 +1625,7 @@ namespace DnsServerCore _dnsWebService._dnsServer.StatsManager.ReloadStats(); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Settings backup zip file was restored."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Settings backup zip file was restored."); } } } @@ -1820,22 +1644,29 @@ namespace DnsServerCore if (dnsSettings) RestartService(true, true); - GetDnsSettings(jsonWriter); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + WriteDnsSettings(jsonWriter); } - public void ForceUpdateBlockLists(HttpListenerRequest request) + public void ForceUpdateBlockLists(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + ForceUpdateBlockLists(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Block list update was triggered."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Block list update was triggered."); } - public void TemporaryDisableBlocking(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void TemporaryDisableBlocking(HttpContext context) { - string strMinutes = request.QueryString["minutes"]; - if (string.IsNullOrEmpty(strMinutes)) - throw new DnsWebServiceException("Parameter 'minutes' missing."); + UserSession session = context.GetCurrentSession(); - int minutes = int.Parse(strMinutes); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + int minutes = context.Request.GetQuery("minutes", int.Parse); Timer temporaryDisableBlockingTimer = _temporaryDisableBlockingTimer; if (temporaryDisableBlockingTimer is not null) @@ -1846,7 +1677,7 @@ namespace DnsServerCore try { _dnsWebService._dnsServer.EnableBlocking = true; - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocking was enabled after " + minutes + " minute(s) being temporarily disabled."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocking was enabled after " + minutes + " minute(s) being temporarily disabled."); } catch (Exception ex) { @@ -1861,13 +1692,14 @@ namespace DnsServerCore _dnsWebService._dnsServer.EnableBlocking = false; _temporaryDisableBlockingTill = DateTime.UtcNow.AddMinutes(minutes); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + _dnsWebService.GetSession(request).User.Username + "] Blocking was temporarily disabled for " + minutes + " minute(s)."); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocking was temporarily disabled for " + minutes + " minute(s)."); } else { newTemporaryDisableBlockingTimer.Dispose(); } + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); } From 4449c30bfcd944d9b3f0a0a0eb79446f6acfe7fb Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 18:39:46 +0530 Subject: [PATCH 055/191] WebServiceZonesApi: updated code to support kestral. --- DnsServerCore/WebServiceZonesApi.cs | 1766 +++++++-------------------- 1 file changed, 474 insertions(+), 1292 deletions(-) diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index 279b9800..f25be4df 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -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 @@ -22,12 +22,14 @@ using DnsServerCore.Dns; using DnsServerCore.Dns.Dnssec; using DnsServerCore.Dns.ResourceRecords; using DnsServerCore.Dns.Zones; +using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text.Json; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -679,12 +681,17 @@ namespace DnsServerCore #region public - public void ListZones(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void ListZones(HttpContext context) { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + List zones = _dnsWebService._dnsServer.AuthZoneManager.ListZones(); zones.Sort(); - UserSession session = _dnsWebService.GetSession(request); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); @@ -700,15 +707,16 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public async Task CreateZoneAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public async Task CreateZoneAsync(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - zoneName = request.QueryString["domain"]; + UserSession session = context.GetCurrentSession(); - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + HttpRequest request = context.Request; + + string zoneName = request.GetQueryAlt("zone", "domain"); if (zoneName.Contains('*')) throw new DnsWebServiceException("Domain name for a zone cannot contain wildcard character."); @@ -727,11 +735,7 @@ namespace DnsServerCore zoneName = zoneName.Substring(0, zoneName.Length - 1); } - AuthZoneType type = AuthZoneType.Primary; - string strType = request.QueryString["type"]; - if (!string.IsNullOrEmpty(strType)) - type = Enum.Parse(strType, true); - + AuthZoneType type = request.GetQuery("type", AuthZoneType.Primary); AuthZoneInfo zoneInfo; switch (type) @@ -742,97 +746,63 @@ namespace DnsServerCore if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); - UserSession session = _dnsWebService.GetSession(request); - //set permissions _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Authoritative primary zone was created: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Authoritative primary zone was created: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; case AuthZoneType.Secondary: { - string primaryNameServerAddresses = request.QueryString["primaryNameServerAddresses"]; - if (string.IsNullOrEmpty(primaryNameServerAddresses)) - primaryNameServerAddresses = null; - - DnsTransportProtocol zoneTransferProtocol; - - string strZoneTransferProtocol = request.QueryString["zoneTransferProtocol"]; - if (string.IsNullOrEmpty(strZoneTransferProtocol)) - zoneTransferProtocol = DnsTransportProtocol.Tcp; - else - zoneTransferProtocol = Enum.Parse(strZoneTransferProtocol, true); - - string tsigKeyName = request.QueryString["tsigKeyName"]; - if (string.IsNullOrEmpty(tsigKeyName)) - tsigKeyName = null; + string primaryNameServerAddresses = request.GetQuery("primaryNameServerAddresses", null); + DnsTransportProtocol zoneTransferProtocol = request.GetQuery("zoneTransferProtocol", DnsTransportProtocol.Tcp); + string tsigKeyName = request.GetQuery("tsigKeyName", null); zoneInfo = await _dnsWebService._dnsServer.AuthZoneManager.CreateSecondaryZoneAsync(zoneName, primaryNameServerAddresses, zoneTransferProtocol, tsigKeyName); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); - UserSession session = _dnsWebService.GetSession(request); - //set permissions _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Authoritative secondary zone was created: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Authoritative secondary zone was created: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; case AuthZoneType.Stub: { - string strPrimaryNameServerAddresses = request.QueryString["primaryNameServerAddresses"]; - if (string.IsNullOrEmpty(strPrimaryNameServerAddresses)) - strPrimaryNameServerAddresses = null; + string primaryNameServerAddresses = request.GetQuery("primaryNameServerAddresses", null); - zoneInfo = await _dnsWebService._dnsServer.AuthZoneManager.CreateStubZoneAsync(zoneName, strPrimaryNameServerAddresses); + zoneInfo = await _dnsWebService._dnsServer.AuthZoneManager.CreateStubZoneAsync(zoneName, primaryNameServerAddresses); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); - UserSession session = _dnsWebService.GetSession(request); - //set permissions _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Stub zone was created: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Stub zone was created: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; case AuthZoneType.Forwarder: { - DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; - string strForwarderProtocol = request.QueryString["protocol"]; - if (!string.IsNullOrEmpty(strForwarderProtocol)) - forwarderProtocol = Enum.Parse(strForwarderProtocol, true); - - string strForwarder = request.QueryString["forwarder"]; - if (string.IsNullOrEmpty(strForwarder)) - throw new DnsWebServiceException("Parameter 'forwarder' missing."); - - bool dnssecValidation = false; - string strDnssecValidation = request.QueryString["dnssecValidation"]; - if (!string.IsNullOrEmpty(strDnssecValidation)) - dnssecValidation = bool.Parse(strDnssecValidation); - - NetProxyType proxyType = NetProxyType.None; - string strProxyType = request.QueryString["proxyType"]; - if (!string.IsNullOrEmpty(strProxyType)) - proxyType = Enum.Parse(strProxyType, true); + DnsTransportProtocol forwarderProtocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); + string forwarder = request.GetQuery("forwarder"); + bool dnssecValidation = request.GetQuery("dnssecValidation", bool.Parse, false); + NetProxyType proxyType = request.GetQuery("proxyType", NetProxyType.None); string proxyAddress = null; ushort proxyPort = 0; @@ -841,32 +811,23 @@ namespace DnsServerCore if (proxyType != NetProxyType.None) { - proxyAddress = request.QueryString["proxyAddress"]; - if (string.IsNullOrEmpty(proxyAddress)) - throw new DnsWebServiceException("Parameter 'proxyAddress' missing."); - - string strProxyPort = request.QueryString["proxyPort"]; - if (string.IsNullOrEmpty(strProxyPort)) - throw new DnsWebServiceException("Parameter 'proxyPort' missing."); - - proxyPort = ushort.Parse(strProxyPort); - proxyUsername = request.QueryString["proxyUsername"]; - proxyPassword = request.QueryString["proxyPassword"]; + proxyAddress = request.GetQuery("proxyAddress"); + proxyPort = request.GetQuery("proxyPort", ushort.Parse); + proxyUsername = request.Query["proxyUsername"]; + proxyPassword = request.Query["proxyPassword"]; } - zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreateForwarderZone(zoneName, forwarderProtocol, strForwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, null); + zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreateForwarderZone(zoneName, forwarderProtocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, null); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); - UserSession session = _dnsWebService.GetSession(request); - //set permissions _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Forwarder zone was created: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Forwarder zone was created: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; @@ -878,42 +839,30 @@ namespace DnsServerCore //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones _dnsWebService._dnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("domain", string.IsNullOrEmpty(zoneInfo.Name) ? "." : zoneInfo.Name); } - public void SignPrimaryZone(HttpListenerRequest request) + public void SignPrimaryZone(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string algorithm = request.QueryString["algorithm"]; - if (string.IsNullOrEmpty(algorithm)) - throw new DnsWebServiceException("Parameter 'algorithm' missing."); - - uint dnsKeyTtl; - string strDnsKeyTtl = request.QueryString["dnsKeyTtl"]; - if (string.IsNullOrEmpty(strDnsKeyTtl)) - dnsKeyTtl = 24 * 60 * 60; - else - dnsKeyTtl = uint.Parse(strDnsKeyTtl); - - ushort zskRolloverDays; - string strZskRolloverDays = request.QueryString["zskRolloverDays"]; - if (string.IsNullOrEmpty(strZskRolloverDays)) - zskRolloverDays = 90; - else - zskRolloverDays = ushort.Parse(strZskRolloverDays); + string algorithm = request.GetQuery("algorithm"); + uint dnsKeyTtl = request.GetQuery("dnsKeyTtl", uint.Parse, 24 * 60 * 60); + ushort zskRolloverDays = request.GetQuery("zskRolloverDays", ushort.Parse, 90); bool useNSEC3 = false; - string strNxProof = request.QueryString["nxProof"]; + string strNxProof = request.Query["nxProof"]; if (!string.IsNullOrEmpty(strNxProof)) { switch (strNxProof.ToUpper()) @@ -936,32 +885,16 @@ namespace DnsServerCore if (useNSEC3) { - string strIterations = request.QueryString["iterations"]; - if (!string.IsNullOrEmpty(strIterations)) - iterations = ushort.Parse(strIterations); - - string strSaltLength = request.QueryString["saltLength"]; - if (!string.IsNullOrEmpty(strSaltLength)) - saltLength = byte.Parse(strSaltLength); + iterations = request.GetQuery("iterations", ushort.Parse, 0); + saltLength = request.GetQuery("saltLength", byte.Parse, 0); } switch (algorithm.ToUpper()) { case "RSA": - string hashAlgorithm = request.QueryString["hashAlgorithm"]; - if (string.IsNullOrEmpty(hashAlgorithm)) - throw new DnsWebServiceException("Parameter 'hashAlgorithm' missing."); - - string strKSKKeySize = request.QueryString["kskKeySize"]; - if (string.IsNullOrEmpty(strKSKKeySize)) - throw new DnsWebServiceException("Parameter 'kskKeySize' missing."); - - string strZSKKeySize = request.QueryString["zskKeySize"]; - if (string.IsNullOrEmpty(strZSKKeySize)) - throw new DnsWebServiceException("Parameter 'zskKeySize' missing."); - - int kskKeySize = int.Parse(strKSKKeySize); - int zskKeySize = int.Parse(strZSKKeySize); + string hashAlgorithm = request.GetQuery("hashAlgorithm"); + int kskKeySize = request.GetQuery("kskKeySize", int.Parse); + int zskKeySize = request.GetQuery("zskKeySize", int.Parse); if (useNSEC3) _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC3(zoneName, hashAlgorithm, kskKeySize, zskKeySize, iterations, saltLength, dnsKeyTtl, zskRolloverDays); @@ -971,9 +904,7 @@ namespace DnsServerCore break; case "ECDSA": - string curve = request.QueryString["curve"]; - if (string.IsNullOrEmpty(curve)) - throw new DnsWebServiceException("Parameter 'curve' missing."); + string curve = request.GetQuery("curve"); if (useNSEC3) _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC3(zoneName, curve, iterations, saltLength, dnsKeyTtl, zskRolloverDays); @@ -986,38 +917,38 @@ namespace DnsServerCore throw new NotSupportedException("Algorithm is not supported: " + algorithm); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was signed successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was signed successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void UnsignPrimaryZone(HttpListenerRequest request) + public void UnsignPrimaryZone(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); _dnsWebService._dnsServer.AuthZoneManager.UnsignPrimaryZone(zoneName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was unsigned successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was unsigned successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void GetPrimaryZoneDnssecProperties(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetPrimaryZoneDnssecProperties(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) @@ -1029,11 +960,11 @@ namespace DnsServerCore if (zoneInfo.Type != AuthZoneType.Primary) throw new DnsWebServiceException("The zone must be a primary zone."); - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WriteString("name", zoneInfo.Name); jsonWriter.WriteString("type", zoneInfo.Type.ToString()); jsonWriter.WriteBoolean("internal", zoneInfo.Internal); @@ -1106,162 +1037,125 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); } - public void ConvertPrimaryZoneToNSEC(HttpListenerRequest request) + public void ConvertPrimaryZoneToNSEC(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); _dnsWebService._dnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC(zoneName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was converted to NSEC successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was converted to NSEC successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void ConvertPrimaryZoneToNSEC3(HttpListenerRequest request) + public void ConvertPrimaryZoneToNSEC3(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort iterations = 0; - string strIterations = request.QueryString["iterations"]; - if (!string.IsNullOrEmpty(strIterations)) - iterations = ushort.Parse(strIterations); - - byte saltLength = 0; - string strSaltLength = request.QueryString["saltLength"]; - if (!string.IsNullOrEmpty(strSaltLength)) - saltLength = byte.Parse(strSaltLength); + ushort iterations = request.GetQuery("iterations", ushort.Parse, 0); + byte saltLength = request.GetQuery("saltLength", byte.Parse, 0); _dnsWebService._dnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC3(zoneName, iterations, saltLength); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone was converted to NSEC3 successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was converted to NSEC3 successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void UpdatePrimaryZoneNSEC3Parameters(HttpListenerRequest request) + public void UpdatePrimaryZoneNSEC3Parameters(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort iterations = 0; - string strIterations = request.QueryString["iterations"]; - if (!string.IsNullOrEmpty(strIterations)) - iterations = ushort.Parse(strIterations); - - byte saltLength = 0; - string strSaltLength = request.QueryString["saltLength"]; - if (!string.IsNullOrEmpty(strSaltLength)) - saltLength = byte.Parse(strSaltLength); + ushort iterations = request.GetQuery("iterations", ushort.Parse, 0); + byte saltLength = request.GetQuery("saltLength", byte.Parse, 0); _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneNSEC3Parameters(zoneName, iterations, saltLength); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone NSEC3 parameters were updated successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone NSEC3 parameters were updated successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void UpdatePrimaryZoneDnssecDnsKeyTtl(HttpListenerRequest request) + public void UpdatePrimaryZoneDnssecDnsKeyTtl(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strDnsKeyTtl = request.QueryString["ttl"]; - if (string.IsNullOrEmpty(strDnsKeyTtl)) - throw new DnsWebServiceException("Parameter 'ttl' missing."); - - uint dnsKeyTtl = uint.Parse(strDnsKeyTtl); + uint dnsKeyTtl = request.GetQuery("ttl", uint.Parse); _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneDnsKeyTtl(zoneName, dnsKeyTtl); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone DNSKEY TTL was updated successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone DNSKEY TTL was updated successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void GenerateAndAddPrimaryZoneDnssecPrivateKey(HttpListenerRequest request) + public void GenerateAndAddPrimaryZoneDnssecPrivateKey(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strKeyType = request.QueryString["keyType"]; - if (string.IsNullOrEmpty(strKeyType)) - throw new DnsWebServiceException("Parameter 'keyType' missing."); - - DnssecPrivateKeyType keyType = Enum.Parse(strKeyType, true); - - ushort rolloverDays; - string strRolloverDays = request.QueryString["rolloverDays"]; - if (string.IsNullOrEmpty(strRolloverDays)) - rolloverDays = (ushort)(keyType == DnssecPrivateKeyType.ZoneSigningKey ? 90 : 0); - else - rolloverDays = ushort.Parse(strRolloverDays); - - string algorithm = request.QueryString["algorithm"]; - if (string.IsNullOrEmpty(algorithm)) - throw new DnsWebServiceException("Parameter 'algorithm' missing."); + DnssecPrivateKeyType keyType = request.GetQuery("keyType"); + ushort rolloverDays = request.GetQuery("rolloverDays", ushort.Parse, (ushort)(keyType == DnssecPrivateKeyType.ZoneSigningKey ? 90 : 0)); + string algorithm = request.GetQuery("algorithm"); switch (algorithm.ToUpper()) { case "RSA": - string hashAlgorithm = request.QueryString["hashAlgorithm"]; - if (string.IsNullOrEmpty(hashAlgorithm)) - throw new DnsWebServiceException("Parameter 'hashAlgorithm' missing."); - - string strKeySize = request.QueryString["keySize"]; - if (string.IsNullOrEmpty(strKeySize)) - throw new DnsWebServiceException("Parameter 'keySize' missing."); - - int keySize = int.Parse(strKeySize); + string hashAlgorithm = request.GetQuery("hashAlgorithm"); + int keySize = request.GetQuery("keySize", int.Parse); _dnsWebService._dnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecRsaPrivateKey(zoneName, keyType, hashAlgorithm, keySize, rolloverDays); break; case "ECDSA": - string curve = request.QueryString["curve"]; - if (string.IsNullOrEmpty(curve)) - throw new DnsWebServiceException("Parameter 'curve' missing."); + string curve = request.GetQuery("curve"); _dnsWebService._dnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecEcdsaPrivateKey(zoneName, keyType, curve, rolloverDays); break; @@ -1270,151 +1164,131 @@ namespace DnsServerCore throw new NotSupportedException("Algorithm is not supported: " + algorithm); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] DNSSEC private key was generated and added to the primary zone successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNSSEC private key was generated and added to the primary zone successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void UpdatePrimaryZoneDnssecPrivateKey(HttpListenerRequest request) + public void UpdatePrimaryZoneDnssecPrivateKey(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strKeyTag = request.QueryString["keyTag"]; - if (string.IsNullOrEmpty(strKeyTag)) - throw new DnsWebServiceException("Parameter 'keyTag' missing."); - - ushort keyTag = ushort.Parse(strKeyTag); - - string strRolloverDays = request.QueryString["rolloverDays"]; - if (string.IsNullOrEmpty(strRolloverDays)) - throw new DnsWebServiceException("Parameter 'rolloverDays' missing."); - - ushort rolloverDays = ushort.Parse(strRolloverDays); + ushort keyTag = request.GetQuery("keyTag", ushort.Parse); + ushort rolloverDays = request.GetQuery("rolloverDays", ushort.Parse); _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneDnssecPrivateKey(zoneName, keyTag, rolloverDays); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Primary zone DNSSEC private key config was updated successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone DNSSEC private key config was updated successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void DeletePrimaryZoneDnssecPrivateKey(HttpListenerRequest request) + public void DeletePrimaryZoneDnssecPrivateKey(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strKeyTag = request.QueryString["keyTag"]; - if (string.IsNullOrEmpty(strKeyTag)) - throw new DnsWebServiceException("Parameter 'keyTag' missing."); - - ushort keyTag = ushort.Parse(strKeyTag); + ushort keyTag = request.GetQuery("keyTag", ushort.Parse); _dnsWebService._dnsServer.AuthZoneManager.DeletePrimaryZoneDnssecPrivateKey(zoneName, keyTag); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] DNSSEC private key was deleted from primary zone successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNSSEC private key was deleted from primary zone successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(HttpListenerRequest request) + public void PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); _dnsWebService._dnsServer.AuthZoneManager.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(zoneName); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] All DNSSEC private keys from the primary zone were published successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] All DNSSEC private keys from the primary zone were published successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void RolloverPrimaryZoneDnsKey(HttpListenerRequest request) + public void RolloverPrimaryZoneDnsKey(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strKeyTag = request.QueryString["keyTag"]; - if (string.IsNullOrEmpty(strKeyTag)) - throw new DnsWebServiceException("Parameter 'keyTag' missing."); - - ushort keyTag = ushort.Parse(strKeyTag); + ushort keyTag = request.GetQuery("keyTag", ushort.Parse); _dnsWebService._dnsServer.AuthZoneManager.RolloverPrimaryZoneDnsKey(zoneName, keyTag); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was rolled over successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was rolled over successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void RetirePrimaryZoneDnsKey(HttpListenerRequest request) + public void RetirePrimaryZoneDnsKey(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + UserSession session = context.GetCurrentSession(); - zoneName = zoneName.TrimEnd('.'); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - UserSession session = _dnsWebService.GetSession(request); + HttpRequest request = context.Request; + + string zoneName = request.GetQuery("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strKeyTag = request.QueryString["keyTag"]; - if (string.IsNullOrEmpty(strKeyTag)) - throw new DnsWebServiceException("Parameter 'keyTag' missing."); - - ushort keyTag = ushort.Parse(strKeyTag); + ushort keyTag = request.GetQuery("keyTag", ushort.Parse); _dnsWebService._dnsServer.AuthZoneManager.RetirePrimaryZoneDnsKey(zoneName, keyTag); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was retired successfully: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was retired successfully: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); } - public void DeleteZone(HttpListenerRequest request) + public void DeleteZone(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - zoneName = request.QueryString["domain"]; + UserSession session = context.GetCurrentSession(); - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Delete)) + throw new DnsWebServiceException("Access was denied."); - zoneName = zoneName.TrimEnd('.'); + string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) @@ -1423,8 +1297,6 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); @@ -1434,20 +1306,18 @@ namespace DnsServerCore _dnsWebService._authManager.RemoveAllPermissions(PermissionSection.Zones, zoneInfo.Name); _dnsWebService._authManager.SaveConfigFile(); - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was deleted: " + zoneName); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was deleted: " + zoneName); _dnsWebService._dnsServer.AuthZoneManager.DeleteZoneFile(zoneInfo.Name); } - public void EnableZone(HttpListenerRequest request) + public void EnableZone(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - zoneName = request.QueryString["domain"]; + UserSession session = context.GetCurrentSession(); - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - zoneName = zoneName.TrimEnd('.'); + string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) @@ -1456,14 +1326,12 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); zoneInfo.Disabled = false; - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was enabled: " + zoneInfo.Name); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was enabled: " + zoneInfo.Name); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); @@ -1471,16 +1339,14 @@ namespace DnsServerCore _dnsWebService._dnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); } - public void DisableZone(HttpListenerRequest request) + public void DisableZone(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - zoneName = request.QueryString["domain"]; + UserSession session = context.GetCurrentSession(); - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - zoneName = zoneName.TrimEnd('.'); + string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) @@ -1489,35 +1355,27 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); zoneInfo.Disabled = true; - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was disabled: " + zoneInfo.Name); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was disabled: " + zoneInfo.Name); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } - public void GetZoneOptions(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetZoneOptions(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - zoneName = request.QueryString["domain"]; + UserSession session = context.GetCurrentSession(); - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - zoneName = zoneName.TrimEnd('.'); + HttpRequest request = context.Request; - bool includeAvailableTsigKeyNames; - string strIncludeAvailableTsigKeyNames = request.QueryString["includeAvailableTsigKeyNames"]; - if (string.IsNullOrEmpty(strIncludeAvailableTsigKeyNames)) - includeAvailableTsigKeyNames = false; - else - includeAvailableTsigKeyNames = bool.Parse(strIncludeAvailableTsigKeyNames); + string zoneName = request.GetQueryAlt("zone", "domain").TrimEnd('.'); + bool includeAvailableTsigKeyNames = request.GetQuery("includeAvailableTsigKeyNames", bool.Parse, false); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) @@ -1526,11 +1384,11 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WriteString("name", zoneInfo.Name); jsonWriter.WriteString("type", zoneInfo.Type.ToString()); @@ -1666,16 +1524,16 @@ namespace DnsServerCore } } - public void SetZoneOptions(HttpListenerRequest request) + public void SetZoneOptions(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - zoneName = request.QueryString["domain"]; + UserSession session = context.GetCurrentSession(); - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - zoneName = zoneName.TrimEnd('.'); + HttpRequest request = context.Request; + + string zoneName = request.GetQueryAlt("zone", "domain").TrimEnd('.'); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) @@ -1684,46 +1542,32 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strDisabled = request.QueryString["disabled"]; - if (!string.IsNullOrEmpty(strDisabled)) - zoneInfo.Disabled = bool.Parse(strDisabled); + if (request.TryGetQuery("disabled", bool.Parse, out bool disabled)) + zoneInfo.Disabled = disabled; switch (zoneInfo.Type) { case AuthZoneType.Primary: case AuthZoneType.Secondary: - string strZoneTransfer = request.QueryString["zoneTransfer"]; - if (!string.IsNullOrEmpty(strZoneTransfer)) - zoneInfo.ZoneTransfer = Enum.Parse(strZoneTransfer, true); + if (request.TryGetQuery("zoneTransfer", out AuthZoneTransfer zoneTransfer)) + zoneInfo.ZoneTransfer = zoneTransfer; - string strZoneTransferNameServers = request.QueryString["zoneTransferNameServers"]; - if (!string.IsNullOrEmpty(strZoneTransferNameServers)) + string strZoneTransferNameServers = request.Query["zoneTransferNameServers"]; + if (strZoneTransferNameServers is not null) { - if (strZoneTransferNameServers == "false") - { + if ((strZoneTransferNameServers.Length == 0) || strZoneTransferNameServers.Equals("false", StringComparison.OrdinalIgnoreCase)) zoneInfo.ZoneTransferNameServers = null; - } else - { - string[] strNameServers = strZoneTransferNameServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] nameServers = new IPAddress[strNameServers.Length]; - - for (int i = 0; i < strNameServers.Length; i++) - nameServers[i] = IPAddress.Parse(strNameServers[i]); - - zoneInfo.ZoneTransferNameServers = nameServers; - } + zoneInfo.ZoneTransferNameServers = strZoneTransferNameServers.Split(IPAddress.Parse, ','); } - string strZoneTransferTsigKeyNames = request.QueryString["zoneTransferTsigKeyNames"]; - if (!string.IsNullOrEmpty(strZoneTransferTsigKeyNames)) + string strZoneTransferTsigKeyNames = request.Query["zoneTransferTsigKeyNames"]; + if (strZoneTransferTsigKeyNames is not null) { - if (strZoneTransferTsigKeyNames == "false") + if ((strZoneTransferTsigKeyNames.Length == 0) || strZoneTransferTsigKeyNames.Equals("false", StringComparison.OrdinalIgnoreCase)) { zoneInfo.ZoneTransferTsigKeyNames = null; } @@ -1739,27 +1583,16 @@ namespace DnsServerCore } } - string strNotify = request.QueryString["notify"]; - if (!string.IsNullOrEmpty(strNotify)) - zoneInfo.Notify = Enum.Parse(strNotify, true); + if (request.TryGetQuery("notify", out AuthZoneNotify notify)) + zoneInfo.Notify = notify; - string strNotifyNameServers = request.QueryString["notifyNameServers"]; - if (!string.IsNullOrEmpty(strNotifyNameServers)) + string strNotifyNameServers = request.Query["notifyNameServers"]; + if (strNotifyNameServers is not null) { - if (strNotifyNameServers == "false") - { + if ((strNotifyNameServers.Length == 0) || strNotifyNameServers.Equals("false", StringComparison.OrdinalIgnoreCase)) zoneInfo.NotifyNameServers = null; - } else - { - string[] strNameServers = strNotifyNameServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] nameServers = new IPAddress[strNameServers.Length]; - - for (int i = 0; i < strNameServers.Length; i++) - nameServers[i] = IPAddress.Parse(strNameServers[i]); - - zoneInfo.NotifyNameServers = nameServers; - } + zoneInfo.NotifyNameServers = strNotifyNameServers.Split(IPAddress.Parse, ','); } break; } @@ -1767,33 +1600,22 @@ namespace DnsServerCore switch (zoneInfo.Type) { case AuthZoneType.Primary: - string strUpdate = request.QueryString["update"]; - if (!string.IsNullOrEmpty(strUpdate)) - zoneInfo.Update = Enum.Parse(strUpdate, true); + if (request.TryGetQuery("update", out AuthZoneUpdate update)) + zoneInfo.Update = update; - string strUpdateIpAddresses = request.QueryString["updateIpAddresses"]; - if (!string.IsNullOrEmpty(strUpdateIpAddresses)) + string strUpdateIpAddresses = request.Query["updateIpAddresses"]; + if (strUpdateIpAddresses is not null) { - if (strUpdateIpAddresses == "false") - { + if ((strUpdateIpAddresses.Length == 0) || strUpdateIpAddresses.Equals("false", StringComparison.OrdinalIgnoreCase)) zoneInfo.UpdateIpAddresses = null; - } else - { - string[] strIpAddresses = strUpdateIpAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - IPAddress[] ipAddresses = new IPAddress[strIpAddresses.Length]; - - for (int i = 0; i < strIpAddresses.Length; i++) - ipAddresses[i] = IPAddress.Parse(strIpAddresses[i]); - - zoneInfo.UpdateIpAddresses = ipAddresses; - } + zoneInfo.UpdateIpAddresses = strUpdateIpAddresses.Split(IPAddress.Parse, ','); } - string strUpdateSecurityPolicies = request.QueryString["updateSecurityPolicies"]; - if (!string.IsNullOrEmpty(strUpdateSecurityPolicies)) + string strUpdateSecurityPolicies = request.Query["updateSecurityPolicies"]; + if (strUpdateSecurityPolicies is not null) { - if (strUpdateSecurityPolicies == "false") + if ((strUpdateSecurityPolicies.Length == 0) || strUpdateSecurityPolicies.Equals("false", StringComparison.OrdinalIgnoreCase)) { zoneInfo.UpdateSecurityPolicies = null; } @@ -1833,21 +1655,19 @@ namespace DnsServerCore break; } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone options were updated successfully: " + zoneInfo.Name); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone options were updated successfully: " + zoneInfo.Name); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } - public void ResyncZone(HttpListenerRequest request) + public void ResyncZone(HttpContext context) { - string zoneName = request.QueryString["zone"]; - if (string.IsNullOrEmpty(zoneName)) - zoneName = request.QueryString["domain"]; + UserSession session = context.GetCurrentSession(); - if (string.IsNullOrEmpty(zoneName)) - throw new DnsWebServiceException("Parameter 'zone' missing."); + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); - zoneName = zoneName.TrimEnd('.'); + string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) @@ -1856,8 +1676,6 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); - if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); @@ -1873,15 +1691,13 @@ namespace DnsServerCore } } - public void AddRecord(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void AddRecord(HttpContext context) { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); + HttpRequest request = context.Request; - domain = domain.TrimEnd('.'); + string domain = request.GetQuery("domain").TrimEnd('.'); - string zoneName = request.QueryString["zone"]; + string zoneName = request.Query["zone"]; if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); @@ -1892,32 +1708,15 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); + UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string strType = request.QueryString["type"]; - if (string.IsNullOrEmpty(strType)) - throw new DnsWebServiceException("Parameter 'type' missing."); - - DnsResourceRecordType type = Enum.Parse(strType, true); - - string value = request.QueryString["value"]; - - uint ttl; - string strTtl = request.QueryString["ttl"]; - if (string.IsNullOrEmpty(strTtl)) - ttl = _defaultRecordTtl; - else - ttl = uint.Parse(strTtl); - - bool overwrite = false; - string strOverwrite = request.QueryString["overwrite"]; - if (!string.IsNullOrEmpty(strOverwrite)) - overwrite = bool.Parse(strOverwrite); - - string comments = request.QueryString["comments"]; + DnsResourceRecordType type = request.GetQuery("type"); + uint ttl = request.GetQuery("ttl", uint.Parse, _defaultRecordTtl); + bool overwrite = request.GetQuery("overwrite", bool.Parse, false); + string comments = request.Query["comments"]; DnsResourceRecord newRecord; @@ -1926,27 +1725,15 @@ namespace DnsServerCore case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: { - string strIPAddress = request.QueryString["ipAddress"]; - if (string.IsNullOrEmpty(strIPAddress)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'ipAddress' missing."); - - strIPAddress = value; - } - + string strIPAddress = request.GetQueryAlt("ipAddress", "value"); IPAddress ipAddress; if (strIPAddress.Equals("request-ip-address")) - ipAddress = DnsWebService.GetRequestRemoteEndPoint(request).Address; + ipAddress = context.GetRemoteEndPoint().Address; else ipAddress = IPAddress.Parse(strIPAddress); - bool ptr = false; - string strPtr = request.QueryString["ptr"]; - if (!string.IsNullOrEmpty(strPtr)) - ptr = bool.Parse(strPtr); - + bool ptr = request.GetQuery("ptr", bool.Parse, false); if (ptr) { string ptrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128); @@ -1954,11 +1741,7 @@ namespace DnsServerCore AuthZoneInfo reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); if (reverseZoneInfo is null) { - bool createPtrZone = false; - string strCreatePtrZone = request.QueryString["createPtrZone"]; - if (!string.IsNullOrEmpty(strCreatePtrZone)) - createPtrZone = bool.Parse(strCreatePtrZone); - + bool createPtrZone = request.GetQuery("createPtrZone", bool.Parse, false); if (!createPtrZone) throw new DnsServerException("No reverse zone available to add PTR record."); @@ -2002,20 +1785,10 @@ namespace DnsServerCore case DnsResourceRecordType.NS: { - string nameServer = request.QueryString["nameServer"]; - if (string.IsNullOrEmpty(nameServer)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'nameServer' missing."); + string nameServer = request.GetQueryAlt("nameServer", "value").TrimEnd('.'); + string glueAddresses = request.GetQuery("glue", null); - nameServer = value; - } - - string glueAddresses = request.QueryString["glue"]; - if (string.IsNullOrEmpty(glueAddresses)) - glueAddresses = null; - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNSRecordData(nameServer.TrimEnd('.'))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNSRecordData(nameServer)); if (glueAddresses != null) newRecord.SetGlueRecords(glueAddresses); @@ -2039,16 +1812,9 @@ namespace DnsServerCore throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } - string cname = request.QueryString["cname"]; - if (string.IsNullOrEmpty(cname)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'cname' missing."); + string cname = request.GetQueryAlt("cname", "value").TrimEnd('.'); - cname = value; - } - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname.TrimEnd('.'))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2059,16 +1825,9 @@ namespace DnsServerCore case DnsResourceRecordType.PTR: { - string ptrName = request.QueryString["ptrName"]; - if (string.IsNullOrEmpty(ptrName)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'ptrName' missing."); + string ptrName = request.GetQueryAlt("ptrName", "value").TrimEnd('.'); - ptrName = value; - } - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsPTRRecordData(ptrName.TrimEnd('.'))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsPTRRecordData(ptrName)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2082,20 +1841,10 @@ namespace DnsServerCore case DnsResourceRecordType.MX: { - string exchange = request.QueryString["exchange"]; - if (string.IsNullOrEmpty(exchange)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'exchange' missing."); + ushort preference = request.GetQuery("preference", ushort.Parse); + string exchange = request.GetQueryAlt("exchange", "value").TrimEnd('.'); - exchange = value; - } - - string preference = request.QueryString["preference"]; - if (string.IsNullOrEmpty(preference)) - throw new DnsWebServiceException("Parameter 'preference' missing."); - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsMXRecordData(ushort.Parse(preference), exchange.TrimEnd('.'))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsMXRecordData(preference, exchange)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2109,14 +1858,7 @@ namespace DnsServerCore case DnsResourceRecordType.TXT: { - string text = request.QueryString["text"]; - if (string.IsNullOrEmpty(text)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'text' missing."); - - text = value; - } + string text = request.GetQueryAlt("text", "value"); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTXTRecordData(text)); @@ -2132,28 +1874,12 @@ namespace DnsServerCore case DnsResourceRecordType.SRV: { - string priority = request.QueryString["priority"]; - if (string.IsNullOrEmpty(priority)) - throw new DnsWebServiceException("Parameter 'priority' missing."); + ushort priority = request.GetQuery("priority", ushort.Parse); + ushort weight = request.GetQuery("weight", ushort.Parse); + ushort port = request.GetQuery("port", ushort.Parse); + string target = request.GetQueryAlt("target", "value").TrimEnd('.'); - string weight = request.QueryString["weight"]; - if (string.IsNullOrEmpty(weight)) - throw new DnsWebServiceException("Parameter 'weight' missing."); - - string port = request.QueryString["port"]; - if (string.IsNullOrEmpty(port)) - throw new DnsWebServiceException("Parameter 'port' missing."); - - string target = request.QueryString["target"]; - if (string.IsNullOrEmpty(target)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'target' missing."); - - target = value; - } - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSRVRecordData(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), target.TrimEnd('.'))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSRVRecordData(priority, weight, port, target)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2174,16 +1900,9 @@ namespace DnsServerCore throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } - string dname = request.QueryString["dname"]; - if (string.IsNullOrEmpty(dname)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'dname' missing."); + string dname = request.GetQueryAlt("dname", "value").TrimEnd('.'); - dname = value; - } - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname.TrimEnd('.'))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2194,28 +1913,12 @@ namespace DnsServerCore case DnsResourceRecordType.DS: { - string strKeyTag = request.QueryString["keyTag"]; - if (string.IsNullOrEmpty(strKeyTag)) - throw new DnsWebServiceException("Parameter 'keyTag' missing."); + ushort keyTag = request.GetQuery("keyTag", ushort.Parse); + DnssecAlgorithm algorithm = Enum.Parse(request.GetQuery("algorithm").Replace('-', '_'), true); + DnssecDigestType digestType = Enum.Parse(request.GetQuery("digestType").Replace('-', '_'), true); + byte[] digest = request.GetQueryAlt("digest", "value", Convert.FromHexString); - string strAlgorithm = request.QueryString["algorithm"]; - if (string.IsNullOrEmpty(strAlgorithm)) - throw new DnsWebServiceException("Parameter 'algorithm' missing."); - - string strDigestType = request.QueryString["digestType"]; - if (string.IsNullOrEmpty(strDigestType)) - throw new DnsWebServiceException("Parameter 'digestType' missing."); - - string digest = request.QueryString["digest"]; - if (string.IsNullOrEmpty(digest)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'digest' missing."); - - digest = value; - } - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDSRecordData(ushort.Parse(strKeyTag), Enum.Parse(strAlgorithm.Replace('-', '_'), true), Enum.Parse(strDigestType.Replace('-', '_'), true), Convert.FromHexString(digest))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDSRecordData(keyTag, algorithm, digestType, digest)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2229,19 +1932,11 @@ namespace DnsServerCore case DnsResourceRecordType.SSHFP: { - string strAlgorithm = request.QueryString["sshfpAlgorithm"]; - if (string.IsNullOrEmpty(strAlgorithm)) - throw new DnsWebServiceException("Parameter 'sshfpAlgorithm' missing."); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQuery("sshfpAlgorithm"); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQuery("sshfpFingerprintType"); + byte[] sshfpFingerprint = request.GetQuery("sshfpFingerprint", Convert.FromHexString); - string strFingerprintType = request.QueryString["sshfpFingerprintType"]; - if (string.IsNullOrEmpty(strFingerprintType)) - throw new DnsWebServiceException("Parameter 'sshfpFingerprintType' missing."); - - string strFingerprint = request.QueryString["sshfpFingerprint"]; - if (string.IsNullOrEmpty(strFingerprint)) - throw new DnsWebServiceException("Parameter 'sshfpFingerprint' missing."); - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(Enum.Parse(strAlgorithm, true), Enum.Parse(strFingerprintType, true), Convert.FromHexString(strFingerprint))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2255,23 +1950,12 @@ namespace DnsServerCore case DnsResourceRecordType.TLSA: { - string strCertificateUsage = request.QueryString["tlsaCertificateUsage"]; - if (string.IsNullOrEmpty(strCertificateUsage)) - throw new DnsWebServiceException("Parameter 'tlsaCertificateUsage' missing."); + DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQuery("tlsaCertificateUsage").Replace('-', '_'), true); + DnsTLSASelector tlsaSelector = request.GetQuery("tlsaSelector"); + DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQuery("tlsaMatchingType").Replace('-', '_'), true); + string tlsaCertificateAssociationData = request.GetQuery("tlsaCertificateAssociationData"); - string strSelector = request.QueryString["tlsaSelector"]; - if (string.IsNullOrEmpty(strSelector)) - throw new DnsWebServiceException("Parameter 'tlsaSelector' missing."); - - string strMatchingType = request.QueryString["tlsaMatchingType"]; - if (string.IsNullOrEmpty(strMatchingType)) - throw new DnsWebServiceException("Parameter 'tlsaMatchingType' missing."); - - string strCertificateAssociationData = request.QueryString["tlsaCertificateAssociationData"]; - if (string.IsNullOrEmpty(strCertificateAssociationData)) - throw new DnsWebServiceException("Parameter 'tlsaCertificateAssociationData' missing."); - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTLSARecordData(Enum.Parse(strCertificateUsage.Replace('-', '_'), true), Enum.Parse(strSelector, true), Enum.Parse(strMatchingType.Replace('-', '_'), true), strCertificateAssociationData)); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2285,18 +1969,11 @@ namespace DnsServerCore case DnsResourceRecordType.CAA: { - string flags = request.QueryString["flags"]; - if (string.IsNullOrEmpty(flags)) - throw new DnsWebServiceException("Parameter 'flags' missing."); + byte flags = request.GetQuery("flags", byte.Parse); + string tag = request.GetQuery("tag"); + string value = request.GetQuery("value"); - string tag = request.QueryString["tag"]; - if (string.IsNullOrEmpty(tag)) - throw new DnsWebServiceException("Parameter 'tag' missing."); - - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'value' missing."); - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCAARecordData(byte.Parse(flags), tag, value)); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCAARecordData(flags, tag, value)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2310,16 +1987,9 @@ namespace DnsServerCore case DnsResourceRecordType.ANAME: { - string aname = request.QueryString["aname"]; - if (string.IsNullOrEmpty(aname)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'aname' missing."); + string aname = request.GetQueryAlt("aname", "value").TrimEnd('.'); - aname = value; - } - - newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsANAMERecordData(aname.TrimEnd('.'))); + newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsANAMERecordData(aname)); if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); @@ -2333,24 +2003,9 @@ namespace DnsServerCore case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = DnsTransportProtocol.Udp; - string strProtocol = request.QueryString["protocol"]; - if (!string.IsNullOrEmpty(strProtocol)) - protocol = Enum.Parse(strProtocol, true); - - string forwarder = request.QueryString["forwarder"]; - if (string.IsNullOrEmpty(forwarder)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'forwarder' missing."); - - forwarder = value; - } - - bool dnssecValidation = false; - string strDnssecValidation = request.QueryString["dnssecValidation"]; - if (!string.IsNullOrEmpty(strDnssecValidation)) - dnssecValidation = bool.Parse(strDnssecValidation); + DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); + string forwarder = request.GetQueryAlt("forwarder", "value"); + bool dnssecValidation = request.GetQuery("dnssecValidation", bool.Parse, false); NetProxyType proxyType = NetProxyType.None; string proxyAddress = null; @@ -2360,23 +2015,13 @@ namespace DnsServerCore if (!forwarder.Equals("this-server")) { - string strProxyType = request.QueryString["proxyType"]; - if (!string.IsNullOrEmpty(strProxyType)) - proxyType = Enum.Parse(strProxyType, true); - + proxyType = request.GetQuery("proxyType", NetProxyType.None); if (proxyType != NetProxyType.None) { - proxyAddress = request.QueryString["proxyAddress"]; - if (string.IsNullOrEmpty(proxyAddress)) - throw new DnsWebServiceException("Parameter 'proxyAddress' missing."); - - string strProxyPort = request.QueryString["proxyPort"]; - if (string.IsNullOrEmpty(strProxyPort)) - throw new DnsWebServiceException("Parameter 'proxyPort' missing."); - - proxyPort = ushort.Parse(strProxyPort); - proxyUsername = request.QueryString["proxyUsername"]; - proxyPassword = request.QueryString["proxyPassword"]; + proxyAddress = request.GetQuery("proxyAddress"); + proxyPort = request.GetQuery("proxyPort", ushort.Parse); + proxyUsername = request.Query["proxyUsername"]; + proxyPassword = request.Query["proxyPassword"]; } } @@ -2394,22 +2039,9 @@ namespace DnsServerCore case DnsResourceRecordType.APP: { - string appName = request.QueryString["appName"]; - if (string.IsNullOrEmpty(appName)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'appName' missing."); - - appName = value; - } - - string classPath = request.QueryString["classPath"]; - if (string.IsNullOrEmpty(classPath)) - throw new DnsWebServiceException("Parameter 'classPath' missing."); - - string recordData = request.QueryString["recordData"]; - if (string.IsNullOrEmpty(recordData)) - recordData = ""; + string appName = request.GetQueryAlt("appName", "value"); + string classPath = request.GetQuery("classPath"); + string recordData = request.GetQuery("recordData", ""); if (!overwrite) { @@ -2431,10 +2063,12 @@ namespace DnsServerCore throw new DnsWebServiceException("Type not supported for AddRecords()."); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] New record was added to authoritative zone {domain: " + domain + "; type: " + type + "; value: " + value + "; ttl: " + ttl + ";}"); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] New record was added to authoritative zone {record: " + newRecord.ToString() + "}"); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("zone"); WriteZoneInfoAsJson(zoneInfo, jsonWriter); @@ -2442,23 +2076,21 @@ namespace DnsServerCore WriteRecordAsJson(newRecord, jsonWriter, true, null); } - public void GetRecords(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void GetRecords(HttpContext context) { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); - - domain = domain.TrimEnd('.'); + string domain = context.Request.GetQuery("domain").TrimEnd('.'); AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(domain); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); - UserSession session = _dnsWebService.GetSession(request); + UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("zone"); WriteZoneInfoAsJson(zoneInfo, jsonWriter); @@ -2468,15 +2100,13 @@ namespace DnsServerCore WriteRecordsAsJson(records, jsonWriter, true, zoneInfo); } - public void DeleteRecord(HttpListenerRequest request) + public void DeleteRecord(HttpContext context) { - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); + HttpRequest request = context.Request; - domain = domain.TrimEnd('.'); + string domain = request.GetQuery("domain").TrimEnd('.'); - string zoneName = request.QueryString["zone"]; + string zoneName = request.Query["zone"]; if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); @@ -2487,34 +2117,18 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); + UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string strType = request.QueryString["type"]; - if (string.IsNullOrEmpty(strType)) - throw new DnsWebServiceException("Parameter 'type' missing."); - - DnsResourceRecordType type = Enum.Parse(strType, true); - - string value = request.QueryString["value"]; - + DnsResourceRecordType type = request.GetQuery("type"); switch (type) { case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: { - string strIPAddress = request.QueryString["ipAddress"]; - if (string.IsNullOrEmpty(strIPAddress)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'ipAddress' missing."); - - strIPAddress = value; - } - - IPAddress ipAddress = IPAddress.Parse(strIPAddress); + IPAddress ipAddress = IPAddress.Parse(request.GetQueryAlt("ipAddress", "value")); if (type == DnsResourceRecordType.A) _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsARecordData(ipAddress)); @@ -2545,14 +2159,7 @@ namespace DnsServerCore case DnsResourceRecordType.NS: { - string nameServer = request.QueryString["nameServer"]; - if (string.IsNullOrEmpty(nameServer)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'nameServer' missing."); - - nameServer = value; - } + string nameServer = request.GetQueryAlt("nameServer", "value").TrimEnd('.'); _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsNSRecordData(nameServer)); } @@ -2564,14 +2171,7 @@ namespace DnsServerCore case DnsResourceRecordType.PTR: { - string ptrName = request.QueryString["ptrName"]; - if (string.IsNullOrEmpty(ptrName)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'ptrName' missing."); - - ptrName = value; - } + string ptrName = request.GetQueryAlt("ptrName", "value").TrimEnd('.'); _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsPTRRecordData(ptrName)); } @@ -2579,33 +2179,16 @@ namespace DnsServerCore case DnsResourceRecordType.MX: { - string preference = request.QueryString["preference"]; - if (string.IsNullOrEmpty(preference)) - throw new DnsWebServiceException("Parameter 'preference' missing."); + ushort preference = request.GetQuery("preference", ushort.Parse); + string exchange = request.GetQueryAlt("exchange", "value").TrimEnd('.'); - string exchange = request.QueryString["exchange"]; - if (string.IsNullOrEmpty(exchange)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'exchange' missing."); - - exchange = value; - } - - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsMXRecordData(ushort.Parse(preference), exchange)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsMXRecordData(preference, exchange)); } break; case DnsResourceRecordType.TXT: { - string text = request.QueryString["text"]; - if (string.IsNullOrEmpty(text)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'text' missing."); - - text = value; - } + string text = request.GetQueryAlt("text", "value"); _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTXTRecordData(text)); } @@ -2613,28 +2196,12 @@ namespace DnsServerCore case DnsResourceRecordType.SRV: { - string priority = request.QueryString["priority"]; - if (string.IsNullOrEmpty(priority)) - throw new DnsWebServiceException("Parameter 'priority' missing."); + ushort priority = request.GetQuery("priority", ushort.Parse); + ushort weight = request.GetQuery("weight", ushort.Parse); + ushort port = request.GetQuery("port", ushort.Parse); + string target = request.GetQueryAlt("target", "value").TrimEnd('.'); - string weight = request.QueryString["weight"]; - if (string.IsNullOrEmpty(weight)) - throw new DnsWebServiceException("Parameter 'weight' missing."); - - string port = request.QueryString["port"]; - if (string.IsNullOrEmpty(port)) - throw new DnsWebServiceException("Parameter 'port' missing."); - - string target = request.QueryString["target"]; - if (string.IsNullOrEmpty(target)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'target' missing."); - - target = value; - } - - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSRVRecordData(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), target)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSRVRecordData(priority, weight, port, target)); } break; @@ -2644,98 +2211,49 @@ namespace DnsServerCore case DnsResourceRecordType.DS: { - string strKeyTag = request.QueryString["keyTag"]; - if (string.IsNullOrEmpty(strKeyTag)) - throw new DnsWebServiceException("Parameter 'keyTag' missing."); + ushort keyTag = request.GetQuery("keyTag", ushort.Parse); + DnssecAlgorithm algorithm = Enum.Parse(request.GetQuery("algorithm").Replace('-', '_'), true); + DnssecDigestType digestType = Enum.Parse(request.GetQuery("digestType").Replace('-', '_'), true); + byte[] digest = Convert.FromHexString(request.GetQueryAlt("digest", "value")); - string strAlgorithm = request.QueryString["algorithm"]; - if (string.IsNullOrEmpty(strAlgorithm)) - throw new DnsWebServiceException("Parameter 'algorithm' missing."); - - string strDigestType = request.QueryString["digestType"]; - if (string.IsNullOrEmpty(strDigestType)) - throw new DnsWebServiceException("Parameter 'digestType' missing."); - - string digest = request.QueryString["digest"]; - if (string.IsNullOrEmpty(digest)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'digest' missing."); - - digest = value; - } - - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsDSRecordData(ushort.Parse(strKeyTag), Enum.Parse(strAlgorithm.Replace('-', '_'), true), Enum.Parse(strDigestType.Replace('-', '_'), true), Convert.FromHexString(digest))); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsDSRecordData(keyTag, algorithm, digestType, digest)); } break; case DnsResourceRecordType.SSHFP: { - string strAlgorithm = request.QueryString["sshfpAlgorithm"]; - if (string.IsNullOrEmpty(strAlgorithm)) - throw new DnsWebServiceException("Parameter 'sshfpAlgorithm' missing."); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQuery("sshfpAlgorithm"); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQuery("sshfpFingerprintType"); + byte[] sshfpFingerprint = request.GetQuery("sshfpFingerprint", Convert.FromHexString); - string strFingerprintType = request.QueryString["sshfpFingerprintType"]; - if (string.IsNullOrEmpty(strFingerprintType)) - throw new DnsWebServiceException("Parameter 'sshfpFingerprintType' missing."); - - string strFingerprint = request.QueryString["sshfpFingerprint"]; - if (string.IsNullOrEmpty(strFingerprint)) - throw new DnsWebServiceException("Parameter 'sshfpFingerprint' missing."); - - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(Enum.Parse(strAlgorithm, true), Enum.Parse(strFingerprintType, true), Convert.FromHexString(strFingerprint))); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); } break; case DnsResourceRecordType.TLSA: { - string strCertificateUsage = request.QueryString["tlsaCertificateUsage"]; - if (string.IsNullOrEmpty(strCertificateUsage)) - throw new DnsWebServiceException("Parameter 'tlsaCertificateUsage' missing."); + DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQuery("tlsaCertificateUsage").Replace('-', '_'), true); + DnsTLSASelector tlsaSelector = request.GetQuery("tlsaSelector"); + DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQuery("tlsaMatchingType").Replace('-', '_'), true); + string tlsaCertificateAssociationData = request.GetQuery("tlsaCertificateAssociationData"); - string strSelector = request.QueryString["tlsaSelector"]; - if (string.IsNullOrEmpty(strSelector)) - throw new DnsWebServiceException("Parameter 'tlsaSelector' missing."); - - string strMatchingType = request.QueryString["tlsaMatchingType"]; - if (string.IsNullOrEmpty(strMatchingType)) - throw new DnsWebServiceException("Parameter 'tlsaMatchingType' missing."); - - string strCertificateAssociationData = request.QueryString["tlsaCertificateAssociationData"]; - if (string.IsNullOrEmpty(strCertificateAssociationData)) - throw new DnsWebServiceException("Parameter 'tlsaCertificateAssociationData' missing."); - - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTLSARecordData(Enum.Parse(strCertificateUsage.Replace('-', '_'), true), Enum.Parse(strSelector, true), Enum.Parse(strMatchingType.Replace('-', '_'), true), strCertificateAssociationData)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData)); } break; case DnsResourceRecordType.CAA: { - string flags = request.QueryString["flags"]; - if (string.IsNullOrEmpty(flags)) - throw new DnsWebServiceException("Parameter 'flags' missing."); + byte flags = request.GetQuery("flags", byte.Parse); + string tag = request.GetQuery("tag"); + string value = request.GetQuery("value"); - string tag = request.QueryString["tag"]; - if (string.IsNullOrEmpty(tag)) - throw new DnsWebServiceException("Parameter 'tag' missing."); - - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'value' missing."); - - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsCAARecordData(byte.Parse(flags), tag, value)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsCAARecordData(flags, tag, value)); } break; case DnsResourceRecordType.ANAME: { - string aname = request.QueryString["aname"]; - if (string.IsNullOrEmpty(aname)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'aname' missing."); - - aname = value; - } + string aname = request.GetQueryAlt("aname", "value").TrimEnd('.'); _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsANAMERecordData(aname)); } @@ -2743,20 +2261,10 @@ namespace DnsServerCore case DnsResourceRecordType.FWD: { - string strProtocol = request.QueryString["protocol"]; - if (string.IsNullOrEmpty(strProtocol)) - strProtocol = "Udp"; + DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); + string forwarder = request.GetQueryAlt("forwarder", "value"); - string forwarder = request.QueryString["forwarder"]; - if (string.IsNullOrEmpty(forwarder)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'forwarder' missing."); - - forwarder = value; - } - - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsForwarderRecordData(Enum.Parse(strProtocol, true), forwarder)); + _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsForwarderRecordData(protocol, forwarder)); } break; @@ -2768,26 +2276,18 @@ namespace DnsServerCore throw new DnsWebServiceException("Type not supported for DeleteRecord()."); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Record was deleted from authoritative zone {domain: " + domain + "; type: " + type + ";}"); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Record was deleted from authoritative zone {domain: " + domain + "; type: " + type + ";}"); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } - public void UpdateRecord(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + public void UpdateRecord(HttpContext context) { - string strType = request.QueryString["type"]; - if (string.IsNullOrEmpty(strType)) - throw new DnsWebServiceException("Parameter 'type' missing."); + HttpRequest request = context.Request; - DnsResourceRecordType type = Enum.Parse(strType, true); + string domain = request.GetQuery("domain").TrimEnd('.'); - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); - - domain = domain.TrimEnd('.'); - - string zoneName = request.QueryString["zone"]; + string zoneName = request.Query["zone"]; if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); @@ -2798,34 +2298,18 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); - UserSession session = _dnsWebService.GetSession(request); + UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string newDomain = request.QueryString["newDomain"]; - if (string.IsNullOrEmpty(newDomain)) - newDomain = domain; - - newDomain = newDomain.TrimEnd('.'); - - uint ttl; - string strTtl = request.QueryString["ttl"]; - if (string.IsNullOrEmpty(strTtl)) - ttl = _defaultRecordTtl; - else - ttl = uint.Parse(strTtl); - - string value = request.QueryString["value"]; - string newValue = request.QueryString["newValue"]; - - bool disable = false; - string strDisable = request.QueryString["disable"]; - if (!string.IsNullOrEmpty(strDisable)) - disable = bool.Parse(strDisable); - - string comments = request.QueryString["comments"]; + string newDomain = request.GetQuery("newDomain", domain).TrimEnd('.'); + uint ttl = request.GetQuery("ttl", uint.Parse, _defaultRecordTtl); + bool disable = request.GetQuery("disable", bool.Parse, false); + string comments = request.Query["comments"]; + DnsResourceRecordType type = request.GetQuery("type"); + DnsResourceRecord oldRecord = null; DnsResourceRecord newRecord; switch (type) @@ -2833,67 +2317,41 @@ namespace DnsServerCore case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: { - string strIPAddress = request.QueryString["ipAddress"]; - if (string.IsNullOrEmpty(strIPAddress)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'ipAddress' missing."); - - strIPAddress = value; - } - - IPAddress oldIpAddress = IPAddress.Parse(strIPAddress); - - string strNewIPAddress = request.QueryString["newIpAddress"]; - if (string.IsNullOrEmpty(strNewIPAddress)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = strIPAddress; - - strNewIPAddress = newValue; - } - IPAddress newIpAddress = IPAddress.Parse(strNewIPAddress); - - bool ptr = false; - string strPtr = request.QueryString["ptr"]; - if (!string.IsNullOrEmpty(strPtr)) - ptr = bool.Parse(strPtr); + IPAddress ipAddress = IPAddress.Parse(request.GetQueryAlt("ipAddress", "value")); + IPAddress newIpAddress = IPAddress.Parse(request.GetQueryAlt("newIpAddress", "newValue", ipAddress.ToString())); + bool ptr = request.GetQuery("ptr", bool.Parse, false); if (ptr) { - string ptrDomain = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 32 : 128); + string newPtrDomain = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); - if (reverseZoneInfo == null) + AuthZoneInfo newReverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(newPtrDomain); + if (newReverseZoneInfo is null) { - bool createPtrZone = false; - string strCreatePtrZone = request.QueryString["createPtrZone"]; - if (!string.IsNullOrEmpty(strCreatePtrZone)) - createPtrZone = bool.Parse(strCreatePtrZone); - + bool createPtrZone = request.GetQuery("createPtrZone", bool.Parse, false); if (!createPtrZone) throw new DnsServerException("No reverse zone available to add PTR record."); string ptrZone = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 24 : 64); - reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService._dnsServer.ServerDomain, false); - if (reverseZoneInfo is null) + newReverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService._dnsServer.ServerDomain, false); + if (newReverseZoneInfo is null) throw new DnsServerException("Failed to create reverse zone to add PTR record: " + ptrZone); //set permissions - _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, newReverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, newReverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, newReverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _dnsWebService._authManager.SaveConfigFile(); } - if (reverseZoneInfo.Internal) - throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is an internal zone."); + if (newReverseZoneInfo.Internal) + throw new DnsServerException("Reverse zone '" + newReverseZoneInfo.Name + "' is an internal zone."); - if (reverseZoneInfo.Type != AuthZoneType.Primary) - throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is not a primary zone."); + if (newReverseZoneInfo.Type != AuthZoneType.Primary) + throw new DnsServerException("Reverse zone '" + newReverseZoneInfo.Name + "' is not a primary zone."); - string oldPtrDomain = Zone.GetReverseZone(oldIpAddress, type == DnsResourceRecordType.A ? 32 : 128); + string oldPtrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128); AuthZoneInfo oldReverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(oldPtrDomain); if ((oldReverseZoneInfo != null) && !oldReverseZoneInfo.Internal && (oldReverseZoneInfo.Type == AuthZoneType.Primary)) @@ -2904,20 +2362,18 @@ namespace DnsServerCore } //add new PTR record and save reverse zone - _dnsWebService._dnsServer.AuthZoneManager.SetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); + _dnsWebService._dnsServer.AuthZoneManager.SetRecords(newReverseZoneInfo.Name, newPtrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); + _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(newReverseZoneInfo.Name); } - DnsResourceRecord oldRecord; - if (type == DnsResourceRecordType.A) { - oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsARecordData(oldIpAddress)); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsARecordData(ipAddress)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsARecordData(newIpAddress)); } else { - oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsAAAARecordData(oldIpAddress)); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsAAAARecordData(ipAddress)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsAAAARecordData(newIpAddress)); } @@ -2933,26 +2389,11 @@ namespace DnsServerCore case DnsResourceRecordType.NS: { - string nameServer = request.QueryString["nameServer"]; - if (string.IsNullOrEmpty(nameServer)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'nameServer' missing."); + string nameServer = request.GetQueryAlt("nameServer", "value").TrimEnd('.'); + string newNameServer = request.GetQueryAlt("newNameServer", "newValue", nameServer).TrimEnd('.'); - nameServer = value; - } - - string newNameServer = request.QueryString["newNameServer"]; - if (string.IsNullOrEmpty(newNameServer)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = nameServer; - - newNameServer = newValue; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsNSRecordData(nameServer.TrimEnd('.'))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsNSRecordData(newNameServer.TrimEnd('.'))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsNSRecordData(nameServer)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsNSRecordData(newNameServer)); if (disable) newRecord.Disable(); @@ -2960,8 +2401,7 @@ namespace DnsServerCore if (!string.IsNullOrEmpty(comments)) newRecord.SetComments(comments); - string glueAddresses = request.QueryString["glue"]; - if (!string.IsNullOrEmpty(glueAddresses)) + if (request.TryGetQuery("glue", out string glueAddresses)) newRecord.SetGlueRecords(glueAddresses); _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); @@ -2970,17 +2410,10 @@ namespace DnsServerCore case DnsResourceRecordType.CNAME: { - string cname = request.QueryString["cname"]; - if (string.IsNullOrEmpty(cname)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'cname' missing."); + string cname = request.GetQueryAlt("cname", "value").TrimEnd('.'); - cname = value; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCNAMERecordData(cname.TrimEnd('.'))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname.TrimEnd('.'))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCNAMERecordData(cname)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname)); if (disable) newRecord.Disable(); @@ -2994,42 +2427,21 @@ namespace DnsServerCore case DnsResourceRecordType.SOA: { - string primaryNameServer = request.QueryString["primaryNameServer"]; - if (string.IsNullOrEmpty(primaryNameServer)) - throw new DnsWebServiceException("Parameter 'primaryNameServer' missing."); + string primaryNameServer = request.GetQuery("primaryNameServer").TrimEnd('.'); + string responsiblePerson = request.GetQuery("responsiblePerson").TrimEnd('.'); + uint serial = request.GetQuery("serial", uint.Parse); + uint refresh = request.GetQuery("refresh", uint.Parse); + uint retry = request.GetQuery("retry", uint.Parse); + uint expire = request.GetQuery("expire", uint.Parse); + uint minimum = request.GetQuery("minimum", uint.Parse); - string responsiblePerson = request.QueryString["responsiblePerson"]; - if (string.IsNullOrEmpty(responsiblePerson)) - throw new DnsWebServiceException("Parameter 'responsiblePerson' missing."); - - string serial = request.QueryString["serial"]; - if (string.IsNullOrEmpty(serial)) - throw new DnsWebServiceException("Parameter 'serial' missing."); - - string refresh = request.QueryString["refresh"]; - if (string.IsNullOrEmpty(refresh)) - throw new DnsWebServiceException("Parameter 'refresh' missing."); - - string retry = request.QueryString["retry"]; - if (string.IsNullOrEmpty(retry)) - throw new DnsWebServiceException("Parameter 'retry' missing."); - - string expire = request.QueryString["expire"]; - if (string.IsNullOrEmpty(expire)) - throw new DnsWebServiceException("Parameter 'expire' missing."); - - string minimum = request.QueryString["minimum"]; - if (string.IsNullOrEmpty(minimum)) - throw new DnsWebServiceException("Parameter 'minimum' missing."); - - DnsResourceRecord newSOARecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSOARecordData(primaryNameServer.TrimEnd('.'), responsiblePerson.TrimEnd('.'), uint.Parse(serial), uint.Parse(refresh), uint.Parse(retry), uint.Parse(expire), uint.Parse(minimum))); + DnsResourceRecord newSOARecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSOARecordData(primaryNameServer, responsiblePerson, serial, refresh, retry, expire, minimum)); switch (zoneInfo.Type) { case AuthZoneType.Secondary: case AuthZoneType.Stub: - string primaryAddresses = request.QueryString["primaryAddresses"]; - if (!string.IsNullOrEmpty(primaryAddresses)) + if (request.TryGetQuery("primaryAddresses", out string primaryAddresses)) newSOARecord.SetPrimaryNameServers(primaryAddresses); break; @@ -3039,14 +2451,10 @@ namespace DnsServerCore { DnsResourceRecordInfo recordInfo = newSOARecord.GetRecordInfo(); - string zoneTransferProtocol = request.QueryString["zoneTransferProtocol"]; - if (string.IsNullOrEmpty(zoneTransferProtocol)) - recordInfo.ZoneTransferProtocol = DnsTransportProtocol.Tcp; - else - recordInfo.ZoneTransferProtocol = Enum.Parse(zoneTransferProtocol, true); + if (request.TryGetQuery("zoneTransferProtocol", out DnsTransportProtocol zoneTransferProtocol)) + recordInfo.ZoneTransferProtocol = zoneTransferProtocol; - string tsigKeyName = request.QueryString["tsigKeyName"]; - if (!string.IsNullOrEmpty(tsigKeyName)) + if (request.TryGetQuery("tsigKeyName", out string tsigKeyName)) recordInfo.TsigKeyName = tsigKeyName; } @@ -3061,26 +2469,11 @@ namespace DnsServerCore case DnsResourceRecordType.PTR: { - string ptrName = request.QueryString["ptrName"]; - if (string.IsNullOrEmpty(ptrName)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'ptrName' missing."); + string ptrName = request.GetQueryAlt("ptrName", "value").TrimEnd('.'); + string newPtrName = request.GetQueryAlt("newPtrName", "newValue", ptrName).TrimEnd('.'); - ptrName = value; - } - - string newPtrName = request.QueryString["newPtrName"]; - if (string.IsNullOrEmpty(newPtrName)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = ptrName; - - newPtrName = newValue; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsPTRRecordData(ptrName.TrimEnd('.'))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsPTRRecordData(newPtrName.TrimEnd('.'))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsPTRRecordData(ptrName)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsPTRRecordData(newPtrName)); if (disable) newRecord.Disable(); @@ -3094,34 +2487,14 @@ namespace DnsServerCore case DnsResourceRecordType.MX: { - string preference = request.QueryString["preference"]; - if (string.IsNullOrEmpty(preference)) - preference = "1"; + ushort preference = request.GetQuery("preference", ushort.Parse); + ushort newPreference = request.GetQuery("newPreference", ushort.Parse, preference); - string newPreference = request.QueryString["newPreference"]; - if (string.IsNullOrEmpty(newPreference)) - newPreference = preference; + string exchange = request.GetQueryAlt("exchange", "value").TrimEnd('.'); + string newExchange = request.GetQueryAlt("newExchange", "newValue", exchange).TrimEnd('.'); - string exchange = request.QueryString["exchange"]; - if (string.IsNullOrEmpty(exchange)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'exchange' missing."); - - exchange = value; - } - - string newExchange = request.QueryString["newExchange"]; - if (string.IsNullOrEmpty(newExchange)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = exchange; - - newExchange = newValue; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsMXRecordData(ushort.Parse(preference), exchange.TrimEnd('.'))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsMXRecordData(ushort.Parse(newPreference), newExchange.TrimEnd('.'))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsMXRecordData(preference, exchange)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsMXRecordData(newPreference, newExchange)); if (disable) newRecord.Disable(); @@ -3135,25 +2508,10 @@ namespace DnsServerCore case DnsResourceRecordType.TXT: { - string text = request.QueryString["text"]; - if (string.IsNullOrEmpty(text)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'text' missing."); + string text = request.GetQueryAlt("text", "value"); + string newText = request.GetQueryAlt("newText", "newValue", text); - text = value; - } - - string newText = request.QueryString["newText"]; - if (string.IsNullOrEmpty(newText)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = text; - - newText = newValue; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTXTRecordData(text)); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTXTRecordData(text)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTXTRecordData(newText)); if (disable) @@ -3168,50 +2526,20 @@ namespace DnsServerCore case DnsResourceRecordType.SRV: { - string priority = request.QueryString["priority"]; - if (string.IsNullOrEmpty(priority)) - throw new DnsWebServiceException("Parameter 'priority' missing."); + ushort priority = request.GetQuery("priority", ushort.Parse); + ushort newPriority = request.GetQuery("newPriority", ushort.Parse, priority); - string newPriority = request.QueryString["newPriority"]; - if (string.IsNullOrEmpty(newPriority)) - newPriority = priority; + ushort weight = request.GetQuery("weight", ushort.Parse); + ushort newWeight = request.GetQuery("newWeight", ushort.Parse, weight); - string weight = request.QueryString["weight"]; - if (string.IsNullOrEmpty(weight)) - throw new DnsWebServiceException("Parameter 'weight' missing."); + ushort port = request.GetQuery("port", ushort.Parse); + ushort newPort = request.GetQuery("newPort", ushort.Parse, port); - string newWeight = request.QueryString["newWeight"]; - if (string.IsNullOrEmpty(newWeight)) - newWeight = weight; + string target = request.GetQueryAlt("target", "value").TrimEnd('.'); + string newTarget = request.GetQueryAlt("newTarget", "newValue", target).TrimEnd('.'); - string port = request.QueryString["port"]; - if (string.IsNullOrEmpty(port)) - throw new DnsWebServiceException("Parameter 'port' missing."); - - string newPort = request.QueryString["newPort"]; - if (string.IsNullOrEmpty(newPort)) - newPort = port; - - string target = request.QueryString["target"]; - if (string.IsNullOrEmpty(target)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'target' missing."); - - target = value; - } - - string newTarget = request.QueryString["newTarget"]; - if (string.IsNullOrEmpty(newTarget)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = target; - - newTarget = newValue; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSRVRecordData(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), target.TrimEnd('.'))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSRVRecordData(ushort.Parse(newPriority), ushort.Parse(newWeight), ushort.Parse(newPort), newTarget.TrimEnd('.'))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSRVRecordData(priority, weight, port, target)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSRVRecordData(newPriority, newWeight, newPort, newTarget)); if (disable) newRecord.Disable(); @@ -3225,17 +2553,10 @@ namespace DnsServerCore case DnsResourceRecordType.DNAME: { - string dname = request.QueryString["dname"]; - if (string.IsNullOrEmpty(dname)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'dname' missing."); + string dname = request.GetQueryAlt("dname", "value").TrimEnd('.'); - dname = value; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDNAMERecordData(dname.TrimEnd('.'))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname.TrimEnd('.'))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDNAMERecordData(dname)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname)); if (disable) newRecord.Disable(); @@ -3249,50 +2570,20 @@ namespace DnsServerCore case DnsResourceRecordType.DS: { - string strKeyTag = request.QueryString["keyTag"]; - if (string.IsNullOrEmpty(strKeyTag)) - throw new DnsWebServiceException("Parameter 'keyTag' missing."); + ushort keyTag = request.GetQuery("keyTag", ushort.Parse); + ushort newKeyTag = request.GetQuery("newKeyTag", ushort.Parse, keyTag); - string strNewKeyTag = request.QueryString["newKeyTag"]; - if (string.IsNullOrEmpty(strNewKeyTag)) - strNewKeyTag = strKeyTag; + DnssecAlgorithm algorithm = Enum.Parse(request.GetQuery("algorithm").Replace('-', '_'), true); + DnssecAlgorithm newAlgorithm = Enum.Parse(request.GetQuery("newAlgorithm", algorithm.ToString()).Replace('-', '_'), true); - string strAlgorithm = request.QueryString["algorithm"]; - if (string.IsNullOrEmpty(strAlgorithm)) - throw new DnsWebServiceException("Parameter 'algorithm' missing."); + DnssecDigestType digestType = Enum.Parse(request.GetQuery("digestType").Replace('-', '_'), true); + DnssecDigestType newDigestType = Enum.Parse(request.GetQuery("newDigestType", digestType.ToString()).Replace('-', '_'), true); - string strNewAlgorithm = request.QueryString["newAlgorithm"]; - if (string.IsNullOrEmpty(strNewAlgorithm)) - strNewAlgorithm = strAlgorithm; + byte[] digest = request.GetQueryAlt("digest", "value", Convert.FromHexString); + byte[] newDigest = request.GetQueryAlt("newDigest", "newValue", Convert.FromHexString, digest); - string strDigestType = request.QueryString["digestType"]; - if (string.IsNullOrEmpty(strDigestType)) - throw new DnsWebServiceException("Parameter 'digestType' missing."); - - string strNewDigestType = request.QueryString["newDigestType"]; - if (string.IsNullOrEmpty(strNewDigestType)) - strNewDigestType = strDigestType; - - string digest = request.QueryString["digest"]; - if (string.IsNullOrEmpty(digest)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'digest' missing."); - - digest = value; - } - - string newDigest = request.QueryString["newDigest"]; - if (string.IsNullOrEmpty(newDigest)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = digest; - - newDigest = newValue; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDSRecordData(ushort.Parse(strKeyTag), Enum.Parse(strAlgorithm.Replace('-', '_'), true), Enum.Parse(strDigestType.Replace('-', '_'), true), Convert.FromHexString(digest))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDSRecordData(ushort.Parse(strNewKeyTag), Enum.Parse(strNewAlgorithm.Replace('-', '_'), true), Enum.Parse(strNewDigestType.Replace('-', '_'), true), Convert.FromHexString(newDigest))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDSRecordData(keyTag, algorithm, digestType, digest)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDSRecordData(newKeyTag, newAlgorithm, newDigestType, newDigest)); if (disable) newRecord.Disable(); @@ -3306,32 +2597,17 @@ namespace DnsServerCore case DnsResourceRecordType.SSHFP: { - string strAlgorithm = request.QueryString["sshfpAlgorithm"]; - if (string.IsNullOrEmpty(strAlgorithm)) - throw new DnsWebServiceException("Parameter 'sshfpAlgorithm' missing."); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQuery("sshfpAlgorithm"); + DnsSSHFPAlgorithm newSshfpAlgorithm = request.GetQuery("newSshfpAlgorithm", sshfpAlgorithm); - string strNewAlgorithm = request.QueryString["newSshfpAlgorithm"]; - if (string.IsNullOrEmpty(strNewAlgorithm)) - strNewAlgorithm = strAlgorithm; + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQuery("sshfpFingerprintType"); + DnsSSHFPFingerprintType newSshfpFingerprintType = request.GetQuery("newSshfpFingerprintType", sshfpFingerprintType); - string strFingerprintType = request.QueryString["sshfpFingerprintType"]; - if (string.IsNullOrEmpty(strFingerprintType)) - throw new DnsWebServiceException("Parameter 'sshfpFingerprintType' missing."); + byte[] sshfpFingerprint = request.GetQuery("sshfpFingerprint", Convert.FromHexString); + byte[] newSshfpFingerprint = request.GetQuery("newSshfpFingerprint", Convert.FromHexString, sshfpFingerprint); - string strNewFingerprintType = request.QueryString["newSshfpFingerprintType"]; - if (string.IsNullOrEmpty(strNewFingerprintType)) - strNewFingerprintType = strFingerprintType; - - string strFingerprint = request.QueryString["sshfpFingerprint"]; - if (string.IsNullOrEmpty(strFingerprint)) - throw new DnsWebServiceException("Parameter 'sshfpFingerprint' missing."); - - string strNewFingerprint = request.QueryString["newSshfpFingerprint"]; - if (string.IsNullOrEmpty(strNewFingerprint)) - strNewFingerprint = strFingerprint; - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSSHFPRecordData(Enum.Parse(strAlgorithm, true), Enum.Parse(strFingerprintType, true), Convert.FromHexString(strFingerprint))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(Enum.Parse(strNewAlgorithm, true), Enum.Parse(strNewFingerprintType, true), Convert.FromHexString(strNewFingerprint))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(newSshfpAlgorithm, newSshfpFingerprintType, newSshfpFingerprint)); if (disable) newRecord.Disable(); @@ -3345,40 +2621,20 @@ namespace DnsServerCore case DnsResourceRecordType.TLSA: { - string strCertificateUsage = request.QueryString["tlsaCertificateUsage"]; - if (string.IsNullOrEmpty(strCertificateUsage)) - throw new DnsWebServiceException("Parameter 'tlsaCertificateUsage' missing."); + DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQuery("tlsaCertificateUsage").Replace('-', '_'), true); + DnsTLSACertificateUsage newTlsaCertificateUsage = Enum.Parse(request.GetQuery("newTlsaCertificateUsage", tlsaCertificateUsage.ToString()).Replace('-', '_'), true); - string strNewCertificateUsage = request.QueryString["newTlsaCertificateUsage"]; - if (string.IsNullOrEmpty(strNewCertificateUsage)) - strNewCertificateUsage = strCertificateUsage; + DnsTLSASelector tlsaSelector = request.GetQuery("tlsaSelector"); + DnsTLSASelector newTlsaSelector = request.GetQuery("newTlsaSelector", tlsaSelector); - string strSelector = request.QueryString["tlsaSelector"]; - if (string.IsNullOrEmpty(strSelector)) - throw new DnsWebServiceException("Parameter 'tlsaSelector' missing."); + DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQuery("tlsaMatchingType").Replace('-', '_'), true); + DnsTLSAMatchingType newTlsaMatchingType = Enum.Parse(request.GetQuery("newTlsaMatchingType", tlsaMatchingType.ToString()).Replace('-', '_'), true); - string strNewSelector = request.QueryString["newTlsaSelector"]; - if (string.IsNullOrEmpty(strNewSelector)) - strNewSelector = strSelector; + string tlsaCertificateAssociationData = request.GetQuery("tlsaCertificateAssociationData"); + string newTlsaCertificateAssociationData = request.GetQuery("newTlsaCertificateAssociationData", tlsaCertificateAssociationData); - string strMatchingType = request.QueryString["tlsaMatchingType"]; - if (string.IsNullOrEmpty(strMatchingType)) - throw new DnsWebServiceException("Parameter 'tlsaMatchingType' missing."); - - string strNewMatchingType = request.QueryString["newTlsaMatchingType"]; - if (string.IsNullOrEmpty(strNewMatchingType)) - strNewMatchingType = strMatchingType; - - string strCertificateAssociationData = request.QueryString["tlsaCertificateAssociationData"]; - if (string.IsNullOrEmpty(strCertificateAssociationData)) - throw new DnsWebServiceException("Parameter 'tlsaCertificateAssociationData' missing."); - - string strNewCertificateAssociationData = request.QueryString["newTlsaCertificateAssociationData"]; - if (string.IsNullOrEmpty(strNewCertificateAssociationData)) - strNewCertificateAssociationData = strCertificateAssociationData; - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTLSARecordData(Enum.Parse(strCertificateUsage.Replace('-', '_'), true), Enum.Parse(strSelector, true), Enum.Parse(strMatchingType.Replace('-', '_'), true), strCertificateAssociationData)); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTLSARecordData(Enum.Parse(strNewCertificateUsage.Replace('-', '_'), true), Enum.Parse(strNewSelector, true), Enum.Parse(strNewMatchingType.Replace('-', '_'), true), strNewCertificateAssociationData)); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTLSARecordData(newTlsaCertificateUsage, newTlsaSelector, newTlsaMatchingType, newTlsaCertificateAssociationData)); if (disable) newRecord.Disable(); @@ -3392,30 +2648,17 @@ namespace DnsServerCore case DnsResourceRecordType.CAA: { - string flags = request.QueryString["flags"]; - if (string.IsNullOrEmpty(flags)) - throw new DnsWebServiceException("Parameter 'flags' missing."); + byte flags = request.GetQuery("flags", byte.Parse); + byte newFlags = request.GetQuery("newFlags", byte.Parse, flags); - string newFlags = request.QueryString["newFlags"]; - if (string.IsNullOrEmpty(newFlags)) - newFlags = flags; + string tag = request.GetQuery("tag"); + string newTag = request.GetQuery("newTag", tag); - string tag = request.QueryString["tag"]; - if (string.IsNullOrEmpty(tag)) - throw new DnsWebServiceException("Parameter 'tag' missing."); + string value = request.GetQuery("value"); + string newValue = request.GetQuery("newValue", value); - string newTag = request.QueryString["newTag"]; - if (string.IsNullOrEmpty(newTag)) - newTag = tag; - - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'value' missing."); - - if (string.IsNullOrEmpty(newValue)) - newValue = value; - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCAARecordData(byte.Parse(flags), tag, value)); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCAARecordData(byte.Parse(newFlags), newTag, newValue)); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCAARecordData(flags, tag, value)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCAARecordData(newFlags, newTag, newValue)); if (disable) newRecord.Disable(); @@ -3429,26 +2672,11 @@ namespace DnsServerCore case DnsResourceRecordType.ANAME: { - string aname = request.QueryString["aname"]; - if (string.IsNullOrEmpty(aname)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'aname' missing."); + string aname = request.GetQueryAlt("aname", "value").TrimEnd('.'); + string newAName = request.GetQueryAlt("newAName", "newValue", aname).TrimEnd('.'); - aname = value; - } - - string newAName = request.QueryString["newAName"]; - if (string.IsNullOrEmpty(newAName)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = aname; - - newAName = newValue; - } - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsANAMERecordData(aname.TrimEnd('.'))); - newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsANAMERecordData(newAName.TrimEnd('.'))); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsANAMERecordData(aname)); + newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsANAMERecordData(newAName)); if (disable) newRecord.Disable(); @@ -3462,38 +2690,13 @@ namespace DnsServerCore case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = DnsTransportProtocol.Udp; - string strProtocol = request.QueryString["protocol"]; - if (!string.IsNullOrEmpty(strProtocol)) - protocol = Enum.Parse(strProtocol, true); + DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); + DnsTransportProtocol newProtocol = request.GetQuery("newProtocol", protocol); - DnsTransportProtocol newProtocol = protocol; - string strNewProtocol = request.QueryString["newProtocol"]; - if (!string.IsNullOrEmpty(strNewProtocol)) - newProtocol = Enum.Parse(strNewProtocol, true); + string forwarder = request.GetQueryAlt("forwarder", "value"); + string newForwarder = request.GetQueryAlt("newForwarder", "newValue", forwarder); - string forwarder = request.QueryString["forwarder"]; - if (string.IsNullOrEmpty(forwarder)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'forwarder' missing."); - - forwarder = value; - } - - string newForwarder = request.QueryString["newForwarder"]; - if (string.IsNullOrEmpty(newForwarder)) - { - if (string.IsNullOrEmpty(newValue)) - newValue = forwarder; - - newForwarder = newValue; - } - - bool dnssecValidation = false; - string strDnssecValidation = request.QueryString["dnssecValidation"]; - if (!string.IsNullOrEmpty(strDnssecValidation)) - dnssecValidation = bool.Parse(strDnssecValidation); + bool dnssecValidation = request.GetQuery("dnssecValidation", bool.Parse, false); NetProxyType proxyType = NetProxyType.None; string proxyAddress = null; @@ -3503,27 +2706,17 @@ namespace DnsServerCore if (!newForwarder.Equals("this-server")) { - string strProxyType = request.QueryString["proxyType"]; - if (!string.IsNullOrEmpty(strProxyType)) - proxyType = Enum.Parse(strProxyType, true); - + proxyType = request.GetQuery("proxyType", NetProxyType.None); if (proxyType != NetProxyType.None) { - proxyAddress = request.QueryString["proxyAddress"]; - if (string.IsNullOrEmpty(proxyAddress)) - throw new DnsWebServiceException("Parameter 'proxyAddress' missing."); - - string strProxyPort = request.QueryString["proxyPort"]; - if (string.IsNullOrEmpty(strProxyPort)) - throw new DnsWebServiceException("Parameter 'proxyPort' missing."); - - proxyPort = ushort.Parse(strProxyPort); - proxyUsername = request.QueryString["proxyUsername"]; - proxyPassword = request.QueryString["proxyPassword"]; + proxyAddress = request.GetQuery("proxyAddress"); + proxyPort = request.GetQuery("proxyPort", ushort.Parse); + proxyUsername = request.Query["proxyUsername"]; + proxyPassword = request.Query["proxyPassword"]; } } - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecordData(protocol, forwarder)); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecordData(protocol, forwarder)); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecordData(newProtocol, newForwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword)); if (disable) @@ -3538,24 +2731,11 @@ namespace DnsServerCore case DnsResourceRecordType.APP: { - string appName = request.QueryString["appName"]; - if (string.IsNullOrEmpty(appName)) - { - if (string.IsNullOrEmpty(value)) - throw new DnsWebServiceException("Parameter 'appName' missing."); + string appName = request.GetQueryAlt("appName", "value"); + string classPath = request.GetQuery("classPath"); + string recordData = request.GetQuery("recordData", ""); - appName = value; - } - - string classPath = request.QueryString["classPath"]; - if (string.IsNullOrEmpty(classPath)) - throw new DnsWebServiceException("Parameter 'classPath' missing."); - - string recordData = request.QueryString["recordData"]; - if (string.IsNullOrEmpty(recordData)) - recordData = ""; - - DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsApplicationRecordData(appName, classPath, recordData)); + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsApplicationRecordData(appName, classPath, recordData)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsApplicationRecordData(appName, classPath, recordData)); if (disable) @@ -3572,10 +2752,12 @@ namespace DnsServerCore throw new DnsWebServiceException("Type not supported for UpdateRecords()."); } - _dnsWebService._log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Record was updated for authoritative zone {oldDomain: " + domain + "; domain: " + newDomain + "; type: " + type + "; oldValue: " + value + "; value: " + newValue + "; ttl: " + ttl + "; disabled: " + disable + ";}"); + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Record was updated for authoritative zone {" + (oldRecord is null ? "" : "oldRecord: " + oldRecord.ToString() + "; ") + "newRecord: " + newRecord.ToString() + "}"); _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + jsonWriter.WritePropertyName("zone"); WriteZoneInfoAsJson(zoneInfo, jsonWriter); From 2ba1948e69535523c031be660f3427350c9f4ce7 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 1 Jan 2023 18:48:08 +0530 Subject: [PATCH 056/191] DnsWebService: replaced HTTPListener with Kestral web server. Code refactoring done. --- DnsServerCore/DnsWebService.cs | 1805 +++++++------------------------- 1 file changed, 368 insertions(+), 1437 deletions(-) diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index 8753c5f8..a37de8ca 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -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 @@ -23,13 +23,21 @@ using DnsServerCore.Dns; using DnsServerCore.Dns.ResourceRecords; using DnsServerCore.Dns.ZoneManagers; using DnsServerCore.Dns.Zones; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.AspNetCore.Server.Kestrel.Https; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.IO; -using System.IO.Compression; using System.Net; using System.Net.Http; -using System.Net.Security; using System.Net.Sockets; using System.Reflection; using System.Security.Cryptography; @@ -43,25 +51,12 @@ using TechnitiumLibrary.IO; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; -using TechnitiumLibrary.Net.Http; using TechnitiumLibrary.Net.Proxy; namespace DnsServerCore { - public sealed class DnsWebService : IDisposable + public sealed class DnsWebService : IAsyncDisposable, IDisposable { - #region enum - - enum ServiceState - { - Stopped = 0, - Starting = 1, - Running = 2, - Stopping = 3 - } - - #endregion - #region variables internal readonly Version _currentVersion; @@ -94,12 +89,9 @@ namespace DnsServerCore internal string _webServiceTlsCertificatePassword; internal DateTime _webServiceTlsCertificateLastModifiedOn; - HttpListener _webService; - IReadOnlyList _webServiceTlsListeners; + WebApplication _webService; X509Certificate2 _webServiceTlsCertificate; readonly IndependentTaskScheduler _webServiceTaskScheduler = new IndependentTaskScheduler(ThreadPriority.AboveNormal); - string _webServiceHostname; - IPEndPoint _webServiceHttpEP; internal string _dnsTlsCertificatePath; internal string _dnsTlsCertificatePassword; @@ -109,8 +101,6 @@ namespace DnsServerCore const int TLS_CERTIFICATE_UPDATE_TIMER_INITIAL_INTERVAL = 60000; const int TLS_CERTIFICATE_UPDATE_TIMER_INTERVAL = 60000; - volatile ServiceState _state = ServiceState.Stopped; - List _configDisabledZones; #endregion @@ -153,12 +143,12 @@ namespace DnsServerCore bool _disposed; - public void Dispose() + public async ValueTask DisposeAsync() { if (_disposed) return; - Stop(); + await StopAsync(); if (_settingsApi is not null) _settingsApi.Dispose(); @@ -166,9 +156,6 @@ namespace DnsServerCore if (_appsApi is not null) _appsApi.Dispose(); - if (_webService is not null) - _webService.Close(); - if (_dnsServer is not null) _dnsServer.Dispose(); @@ -184,1224 +171,358 @@ namespace DnsServerCore _disposed = true; } + public void Dispose() + { + DisposeAsync().Sync(); + } + #endregion #region private #region web service - private async Task AcceptWebRequestAsync() + internal async Task StartWebServiceAsync() { - try + WebApplicationBuilder builder = WebApplication.CreateBuilder(); + + builder.Environment.ContentRootFileProvider = new PhysicalFileProvider(_appFolder) { - while (true) + UseActivePolling = true, + UsePollingFileWatcher = true + }; + + builder.Environment.WebRootFileProvider = new PhysicalFileProvider(Path.Combine(_appFolder, "www")) + { + UseActivePolling = true, + UsePollingFileWatcher = true + }; + + builder.WebHost.ConfigureKestrel(delegate (WebHostBuilderContext context, KestrelServerOptions serverOptions) + { + //http + foreach (IPAddress webServiceLocalAddress in _webServiceLocalAddresses) + serverOptions.Listen(webServiceLocalAddress, _webServiceHttpPort); + + //https + if (_webServiceEnableTls && (_webServiceTlsCertificate is not null)) { - HttpListenerContext context = await _webService.GetContextAsync(); - - if ((_webServiceTlsListeners != null) && (_webServiceTlsListeners.Count > 0) && _webServiceHttpToTlsRedirect) + serverOptions.ConfigureHttpsDefaults(delegate (HttpsConnectionAdapterOptions configureOptions) { - IPEndPoint remoteEP = context.Request.RemoteEndPoint; - - if ((remoteEP != null) && !IPAddress.IsLoopback(remoteEP.Address)) + configureOptions.ServerCertificateSelector = delegate (ConnectionContext context, string dnsName) { - string domain = _webServiceTlsCertificate.GetNameInfo(X509NameType.DnsName, false); - string redirectUri = "https://" + domain + ":" + _webServiceTlsPort + context.Request.Url.PathAndQuery; + return _webServiceTlsCertificate; + }; + }); - context.Response.Redirect(redirectUri); - context.Response.Close(); - - continue; - } - } - - _ = ProcessRequestAsync(context.Request, context.Response); - } - } - catch (HttpListenerException ex) - { - if (ex.ErrorCode == 995) - return; //web service stopping - - _log.Write(ex); - } - catch (ObjectDisposedException) - { - //web service stopped - } - catch (Exception ex) - { - if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) - return; //web service stopping - - _log.Write(ex); - } - } - - private async Task AcceptTlsWebRequestAsync(Socket tlsListener) - { - try - { - while (true) - { - Socket socket = await tlsListener.AcceptAsync(); - - _ = TlsToHttpTunnelAsync(socket); - } - } - catch (SocketException ex) - { - if (ex.SocketErrorCode == SocketError.OperationAborted) - return; //web service stopping - - _log.Write(ex); - } - catch (ObjectDisposedException) - { - //web service stopped - } - catch (Exception ex) - { - if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) - return; //web service stopping - - _log.Write(ex); - } - } - - private async Task TlsToHttpTunnelAsync(Socket socket) - { - Socket tunnel = null; - - try - { - if (_webServiceLocalAddresses.Count < 1) - return; - - string remoteIP = (socket.RemoteEndPoint as IPEndPoint).Address.ToString(); - - SslStream sslStream = new SslStream(new NetworkStream(socket, true)); - - await sslStream.AuthenticateAsServerAsync(_webServiceTlsCertificate); - - tunnel = new Socket(_webServiceHttpEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - tunnel.Connect(_webServiceHttpEP); - - NetworkStream tunnelStream = new NetworkStream(tunnel, true); - - //copy tunnel to ssl - _ = tunnelStream.CopyToAsync(sslStream).ContinueWith(delegate (Task prevTask) { sslStream.Dispose(); tunnelStream.Dispose(); }); - - //copy ssl to tunnel - try - { - while (true) + foreach (IPAddress webServiceLocalAddress in _webServiceLocalAddresses) { - HttpRequest httpRequest = await HttpRequest.ReadRequestAsync(sslStream); - if (httpRequest == null) - return; //connection closed gracefully by client - - //inject X-Real-IP & host header - httpRequest.Headers.Add("X-Real-IP", remoteIP); - httpRequest.Headers[HttpRequestHeader.Host] = "localhost:" + _webServiceHttpPort.ToString(); - - //relay request - await tunnelStream.WriteAsync(Encoding.ASCII.GetBytes(httpRequest.HttpMethod + " " + httpRequest.RequestPathAndQuery + " " + httpRequest.Protocol + "\r\n")); - await tunnelStream.WriteAsync(httpRequest.Headers.ToByteArray()); - - if (httpRequest.InputStream != null) - await httpRequest.InputStream.CopyToAsync(tunnelStream); - - await tunnelStream.FlushAsync(); + serverOptions.Listen(webServiceLocalAddress, _webServiceTlsPort, delegate (ListenOptions listenOptions) + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; + listenOptions.UseHttps(); + }); } } - finally - { - sslStream.Dispose(); - tunnelStream.Dispose(); - } - } - catch (IOException) - { - //ignore - } - catch (Exception ex) - { - _log.Write(ex); - } - finally - { - socket.Dispose(); - if (tunnel != null) - tunnel.Dispose(); + serverOptions.AddServerHeader = false; + }); + + builder.Logging.ClearProviders(); + + _webService = builder.Build(); + + if (_webServiceHttpToTlsRedirect) + _webService.UseHttpsRedirection(); + + _webService.UseDefaultFiles(); + _webService.UseStaticFiles(new StaticFileOptions() + { + OnPrepareResponse = delegate (StaticFileResponseContext ctx) + { + ctx.Context.Response.Headers.Add("X-Robots-Tag", "noindex, nofollow"); + ctx.Context.Response.Headers.Add("Cache-Control", "private, max-age=300"); + } + }); + + ConfigureWebServiceRoutes(); + + await _webService.StartAsync(); + + _log.Write(new IPEndPoint(IPAddress.Any, _webServiceHttpPort), "Web Service was started successfully."); + } + + internal async Task StopWebServiceAsync() + { + await _webService.DisposeAsync(); + } + + private void ConfigureWebServiceRoutes() + { + _webService.UseExceptionHandler(WebServiceExceptionHandler); + + _webService.Use(WebServiceApiMiddleware); + + _webService.UseRouting(); + + //user auth + _webService.MapGet("/api/user/login", delegate (HttpContext context) { return _authApi.LoginAsync(context, UserSessionType.Standard); }); + _webService.MapGet("/api/user/createToken", delegate (HttpContext context) { return _authApi.LoginAsync(context, UserSessionType.ApiToken); }); + _webService.MapGet("/api/user/logout", _authApi.Logout); + + //user + _webService.MapGet("/api/user/session/get", _authApi.GetCurrentSessionDetails); + _webService.MapGet("/api/user/session/delete", delegate (HttpContext context) { _authApi.DeleteSession(context, false); }); + _webService.MapGet("/api/user/changePassword", _authApi.ChangePassword); + _webService.MapGet("/api/user/profile/get", _authApi.GetProfile); + _webService.MapGet("/api/user/profile/set", _authApi.SetProfile); + _webService.MapGet("/api/user/checkForUpdate", CheckForUpdateAsync); + + //dashboard + _webService.MapGet("/api/dashboard/stats/get", _dashboardApi.GetStats); + _webService.MapGet("/api/dashboard/stats/getTop", _dashboardApi.GetTopStats); + _webService.MapGet("/api/dashboard/stats/deleteAll", _logsApi.DeleteAllStats); + + //zones + _webService.MapGet("/api/zones/list", _zonesApi.ListZones); + _webService.MapGet("/api/zones/create", _zonesApi.CreateZoneAsync); + _webService.MapGet("/api/zones/enable", _zonesApi.EnableZone); + _webService.MapGet("/api/zones/disable", _zonesApi.DisableZone); + _webService.MapGet("/api/zones/delete", _zonesApi.DeleteZone); + _webService.MapGet("/api/zones/resync", _zonesApi.ResyncZone); + _webService.MapGet("/api/zones/options/get", _zonesApi.GetZoneOptions); + _webService.MapGet("/api/zones/options/set", _zonesApi.SetZoneOptions); + _webService.MapGet("/api/zones/permissions/get", delegate (HttpContext context) { _authApi.GetPermissionDetails(context, PermissionSection.Zones); }); + _webService.MapGet("/api/zones/permissions/set", delegate (HttpContext context) { _authApi.SetPermissionsDetails(context, PermissionSection.Zones); }); + _webService.MapGet("/api/zones/dnssec/sign", _zonesApi.SignPrimaryZone); + _webService.MapGet("/api/zones/dnssec/unsign", _zonesApi.UnsignPrimaryZone); + _webService.MapGet("/api/zones/dnssec/properties/get", _zonesApi.GetPrimaryZoneDnssecProperties); + _webService.MapGet("/api/zones/dnssec/properties/convertToNSEC", _zonesApi.ConvertPrimaryZoneToNSEC); + _webService.MapGet("/api/zones/dnssec/properties/convertToNSEC3", _zonesApi.ConvertPrimaryZoneToNSEC3); + _webService.MapGet("/api/zones/dnssec/properties/updateNSEC3Params", _zonesApi.UpdatePrimaryZoneNSEC3Parameters); + _webService.MapGet("/api/zones/dnssec/properties/updateDnsKeyTtl", _zonesApi.UpdatePrimaryZoneDnssecDnsKeyTtl); + _webService.MapGet("/api/zones/dnssec/properties/generatePrivateKey", _zonesApi.GenerateAndAddPrimaryZoneDnssecPrivateKey); + _webService.MapGet("/api/zones/dnssec/properties/updatePrivateKey", _zonesApi.UpdatePrimaryZoneDnssecPrivateKey); + _webService.MapGet("/api/zones/dnssec/properties/deletePrivateKey", _zonesApi.DeletePrimaryZoneDnssecPrivateKey); + _webService.MapGet("/api/zones/dnssec/properties/publishAllPrivateKeys", _zonesApi.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys); + _webService.MapGet("/api/zones/dnssec/properties/rolloverDnsKey", _zonesApi.RolloverPrimaryZoneDnsKey); + _webService.MapGet("/api/zones/dnssec/properties/retireDnsKey", _zonesApi.RetirePrimaryZoneDnsKey); + _webService.MapGet("/api/zones/records/add", _zonesApi.AddRecord); + _webService.MapGet("/api/zones/records/get", _zonesApi.GetRecords); + _webService.MapGet("/api/zones/records/update", _zonesApi.UpdateRecord); + _webService.MapGet("/api/zones/records/delete", _zonesApi.DeleteRecord); + + //cache + _webService.MapGet("/api/cache/list", _otherZonesApi.ListCachedZones); + _webService.MapGet("/api/cache/delete", _otherZonesApi.DeleteCachedZone); + _webService.MapGet("/api/cache/flush", _otherZonesApi.FlushCache); + + //allowed + _webService.MapGet("/api/allowed/list", _otherZonesApi.ListAllowedZones); + _webService.MapGet("/api/allowed/add", _otherZonesApi.AllowZone); + _webService.MapGet("/api/allowed/delete", _otherZonesApi.DeleteAllowedZone); + _webService.MapGet("/api/allowed/flush", _otherZonesApi.FlushAllowedZone); + _webService.MapPost("/api/allowed/import", _otherZonesApi.ImportAllowedZones); + _webService.MapGet("/api/allowed/export", _otherZonesApi.ExportAllowedZonesAsync); + + //blocked + _webService.MapGet("/api/blocked/list", _otherZonesApi.ListBlockedZones); + _webService.MapGet("/api/blocked/add", _otherZonesApi.BlockZone); + _webService.MapGet("/api/blocked/delete", _otherZonesApi.DeleteBlockedZone); + _webService.MapGet("/api/blocked/flush", _otherZonesApi.FlushBlockedZone); + _webService.MapPost("/api/blocked/import", _otherZonesApi.ImportBlockedZones); + _webService.MapGet("/api/blocked/export", _otherZonesApi.ExportBlockedZonesAsync); + + //apps + _webService.MapGet("/api/apps/list", _appsApi.ListInstalledAppsAsync); + _webService.MapGet("/api/apps/listStoreApps", _appsApi.ListStoreApps); + _webService.MapGet("/api/apps/downloadAndInstall", _appsApi.DownloadAndInstallAppAsync); + _webService.MapGet("/api/apps/downloadAndUpdate", _appsApi.DownloadAndUpdateAppAsync); + _webService.MapPost("/api/apps/install", _appsApi.InstallAppAsync); + _webService.MapPost("/api/apps/update", _appsApi.UpdateAppAsync); + _webService.MapGet("/api/apps/uninstall", _appsApi.UninstallApp); + _webService.MapGet("/api/apps/config/get", _appsApi.GetAppConfigAsync); + _webService.MapPost("/api/apps/config/set", _appsApi.SetAppConfigAsync); + + //dns client + _webService.MapGet("/api/dnsClient/resolve", ResolveQueryAsync); + + //settings + _webService.MapGet("/api/settings/get", _settingsApi.GetDnsSettings); + _webService.MapGet("/api/settings/set", _settingsApi.SetDnsSettings); + _webService.MapGet("/api/settings/getTsigKeyNames", _settingsApi.GetTsigKeyNames); + _webService.MapGet("/api/settings/forceUpdateBlockLists", _settingsApi.ForceUpdateBlockLists); + _webService.MapGet("/api/settings/temporaryDisableBlocking", _settingsApi.TemporaryDisableBlocking); + _webService.MapGet("/api/settings/backup", _settingsApi.BackupSettingsAsync); + _webService.MapPost("/api/settings/restore", _settingsApi.RestoreSettingsAsync); + + //dhcp + _webService.MapGet("/api/dhcp/leases/list", _dhcpApi.ListDhcpLeases); + _webService.MapGet("/api/dhcp/leases/remove", _dhcpApi.RemoveDhcpLease); + _webService.MapGet("/api/dhcp/leases/convertToReserved", _dhcpApi.ConvertToReservedLease); + _webService.MapGet("/api/dhcp/leases/convertToDynamic", _dhcpApi.ConvertToDynamicLease); + _webService.MapGet("/api/dhcp/scopes/list", _dhcpApi.ListDhcpScopes); + _webService.MapGet("/api/dhcp/scopes/get", _dhcpApi.GetDhcpScope); + _webService.MapGet("/api/dhcp/scopes/set", _dhcpApi.SetDhcpScopeAsync); + _webService.MapGet("/api/dhcp/scopes/addReservedLease", _dhcpApi.AddReservedLease); + _webService.MapGet("/api/dhcp/scopes/removeReservedLease", _dhcpApi.RemoveReservedLease); + _webService.MapGet("/api/dhcp/scopes/enable", _dhcpApi.EnableDhcpScopeAsync); + _webService.MapGet("/api/dhcp/scopes/disable", _dhcpApi.DisableDhcpScope); + _webService.MapGet("/api/dhcp/scopes/delete", _dhcpApi.DeleteDhcpScope); + + //administration + _webService.MapGet("/api/admin/sessions/list", _authApi.ListSessions); + _webService.MapGet("/api/admin/sessions/createToken", _authApi.CreateApiToken); + _webService.MapGet("/api/admin/sessions/delete", delegate (HttpContext context) { _authApi.DeleteSession(context, true); }); + _webService.MapGet("/api/admin/users/list", _authApi.ListUsers); + _webService.MapGet("/api/admin/users/create", _authApi.CreateUser); + _webService.MapGet("/api/admin/users/get", _authApi.GetUserDetails); + _webService.MapGet("/api/admin/users/set", _authApi.SetUserDetails); + _webService.MapGet("/api/admin/users/delete", _authApi.DeleteUser); + _webService.MapGet("/api/admin/groups/list", _authApi.ListGroups); + _webService.MapGet("/api/admin/groups/create", _authApi.CreateGroup); + _webService.MapGet("/api/admin/groups/get", _authApi.GetGroupDetails); + _webService.MapGet("/api/admin/groups/set", _authApi.SetGroupDetails); + _webService.MapGet("/api/admin/groups/delete", _authApi.DeleteGroup); + _webService.MapGet("/api/admin/permissions/list", _authApi.ListPermissions); + _webService.MapGet("/api/admin/permissions/get", delegate (HttpContext context) { _authApi.GetPermissionDetails(context, PermissionSection.Unknown); }); + _webService.MapGet("/api/admin/permissions/set", delegate (HttpContext context) { _authApi.SetPermissionsDetails(context, PermissionSection.Unknown); }); + + //logs + _webService.MapGet("/api/logs/list", _logsApi.ListLogs); + _webService.MapGet("/api/logs/download", _logsApi.DownloadLogAsync); + _webService.MapGet("/api/logs/delete", _logsApi.DeleteLog); + _webService.MapGet("/api/logs/deleteAll", _logsApi.DeleteAllLogs); + _webService.MapGet("/api/logs/query", _logsApi.QueryLogsAsync); + } + + private async Task WebServiceApiMiddleware(HttpContext context, RequestDelegate next) + { + bool needsJsonResponseObject; + + switch (context.Request.Path) + { + case "/api/user/login": + case "/api/user/createToken": + case "/api/user/logout": + needsJsonResponseObject = false; + break; + + case "/api/user/session/get": + { + if (!TryGetSession(context, out UserSession session)) + throw new InvalidTokenWebServiceException("Invalid token or session expired."); + + context.Items["session"] = session; + + needsJsonResponseObject = false; + } + break; + + case "/api/allowed/export": + case "/api/blocked/export": + case "/api/settings/backup": + case "/api/logs/download": + { + if (!TryGetSession(context, out UserSession session)) + throw new InvalidTokenWebServiceException("Invalid token or session expired."); + + context.Items["session"] = session; + + await next(context); + } + return; + + default: + { + if (!TryGetSession(context, out UserSession session)) + throw new InvalidTokenWebServiceException("Invalid token or session expired."); + + context.Items["session"] = session; + needsJsonResponseObject = true; + } + break; + } + + using (MemoryStream mS = new MemoryStream()) + { + Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); + context.Items["jsonWriter"] = jsonWriter; + + jsonWriter.WriteStartObject(); + + if (needsJsonResponseObject) + { + jsonWriter.WritePropertyName("response"); + jsonWriter.WriteStartObject(); + + await next(context); + + jsonWriter.WriteEndObject(); + } + else + { + await next(context); + } + + jsonWriter.WriteString("status", "ok"); + + jsonWriter.WriteEndObject(); + jsonWriter.Flush(); + + mS.Position = 0; + + HttpResponse response = context.Response; + + response.StatusCode = StatusCodes.Status200OK; + response.ContentType = "application/json; charset=utf-8"; + response.ContentLength = mS.Length; + + await mS.CopyToAsync(response.Body); } } - private async Task ProcessRequestAsync(HttpListenerRequest request, HttpListenerResponse response) + private static void WebServiceExceptionHandler(IApplicationBuilder exceptionHandlerApp) { - response.AddHeader("Server", ""); - response.AddHeader("X-Robots-Tag", "noindex, nofollow"); - - try + exceptionHandlerApp.Run(async delegate (HttpContext context) { - Uri url = request.Url; - string path = url.AbsolutePath; - - if (!path.StartsWith("/") || path.Contains("/../") || path.Contains("/.../")) + IExceptionHandlerPathFeature exceptionHandlerPathFeature = context.Features.Get(); + if (exceptionHandlerPathFeature.Path.StartsWith("/api/")) { - await SendErrorAsync(response, 404); - return; - } + Exception ex = exceptionHandlerPathFeature.Error; - if (path.StartsWith("/api/")) - { - using (MemoryStream mS = new MemoryStream()) + context.Response.StatusCode = StatusCodes.Status200OK; + context.Response.ContentType = "application/json; charset=utf-8"; + + await using (Utf8JsonWriter jsonWriter = new Utf8JsonWriter(context.Response.Body)) { - try + jsonWriter.WriteStartObject(); + + if (ex is InvalidTokenWebServiceException) { - Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); - jsonWriter.WriteStartObject(); - - switch (path) - { - case "/api/user/login": - case "/api/login": - await _authApi.LoginAsync(request, jsonWriter, UserSessionType.Standard); - break; - - case "/api/user/createToken": - await _authApi.LoginAsync(request, jsonWriter, UserSessionType.ApiToken); - break; - - case "/api/user/logout": - case "/api/logout": - _authApi.Logout(request); - break; - - case "/api/user/session/get": - _authApi.GetCurrentSessionDetails(request, jsonWriter); - break; - - default: - if (!TryGetSession(request, out UserSession session)) - throw new InvalidTokenWebServiceException("Invalid token or session expired."); - - jsonWriter.WritePropertyName("response"); - jsonWriter.WriteStartObject(); - - try - { - switch (path) - { - case "/api/user/session/delete": - _authApi.DeleteSession(request, false); - break; - - case "/api/user/changePassword": - case "/api/changePassword": - _authApi.ChangePassword(request); - break; - - case "/api/user/profile/get": - _authApi.GetProfile(request, jsonWriter); - break; - - case "/api/user/profile/set": - _authApi.SetProfile(request, jsonWriter); - break; - - case "/api/user/checkForUpdate": - case "/api/checkForUpdate": - await CheckForUpdateAsync(request, jsonWriter); - break; - - case "/api/dashboard/stats/get": - case "/api/getStats": - if (!_authManager.IsPermitted(PermissionSection.Dashboard, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - await _dashboardApi.GetStats(request, jsonWriter); - break; - - case "/api/dashboard/stats/getTop": - case "/api/getTopStats": - if (!_authManager.IsPermitted(PermissionSection.Dashboard, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - await _dashboardApi.GetTopStats(request, jsonWriter); - break; - - case "/api/dashboard/stats/deleteAll": - case "/api/deleteAllStats": - if (!_authManager.IsPermitted(PermissionSection.Dashboard, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _logsApi.DeleteAllStats(request); - break; - - case "/api/zones/list": - case "/api/zone/list": - case "/api/listZones": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.ListZones(request, jsonWriter); - break; - - case "/api/zones/create": - case "/api/zone/create": - case "/api/createZone": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - await _zonesApi.CreateZoneAsync(request, jsonWriter); - break; - - case "/api/zones/enable": - case "/api/zone/enable": - case "/api/enableZone": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.EnableZone(request); - break; - - case "/api/zones/disable": - case "/api/zone/disable": - case "/api/disableZone": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.DisableZone(request); - break; - - case "/api/zones/delete": - case "/api/zone/delete": - case "/api/deleteZone": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.DeleteZone(request); - break; - - case "/api/zones/resync": - case "/api/zone/resync": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.ResyncZone(request); - break; - - case "/api/zones/options/get": - case "/api/zone/options/get": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.GetZoneOptions(request, jsonWriter); - break; - - case "/api/zones/options/set": - case "/api/zone/options/set": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.SetZoneOptions(request); - break; - - case "/api/zones/permissions/get": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.GetPermissionDetails(request, jsonWriter, PermissionSection.Zones); - break; - - case "/api/zones/permissions/set": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.SetPermissionsDetails(request, jsonWriter, PermissionSection.Zones); - break; - - case "/api/zones/dnssec/sign": - case "/api/zone/dnssec/sign": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.SignPrimaryZone(request); - break; - - case "/api/zones/dnssec/unsign": - case "/api/zone/dnssec/unsign": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.UnsignPrimaryZone(request); - break; - - case "/api/zones/dnssec/properties/get": - case "/api/zone/dnssec/getProperties": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.GetPrimaryZoneDnssecProperties(request, jsonWriter); - break; - - case "/api/zones/dnssec/properties/convertToNSEC": - case "/api/zone/dnssec/convertToNSEC": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.ConvertPrimaryZoneToNSEC(request); - break; - - case "/api/zones/dnssec/properties/convertToNSEC3": - case "/api/zone/dnssec/convertToNSEC3": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.ConvertPrimaryZoneToNSEC3(request); - break; - - case "/api/zones/dnssec/properties/updateNSEC3Params": - case "/api/zone/dnssec/updateNSEC3Params": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.UpdatePrimaryZoneNSEC3Parameters(request); - break; - - case "/api/zones/dnssec/properties/updateDnsKeyTtl": - case "/api/zone/dnssec/updateDnsKeyTtl": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.UpdatePrimaryZoneDnssecDnsKeyTtl(request); - break; - - case "/api/zones/dnssec/properties/generatePrivateKey": - case "/api/zone/dnssec/generatePrivateKey": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.GenerateAndAddPrimaryZoneDnssecPrivateKey(request); - break; - - case "/api/zones/dnssec/properties/updatePrivateKey": - case "/api/zone/dnssec/updatePrivateKey": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.UpdatePrimaryZoneDnssecPrivateKey(request); - break; - - case "/api/zones/dnssec/properties/deletePrivateKey": - case "/api/zone/dnssec/deletePrivateKey": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.DeletePrimaryZoneDnssecPrivateKey(request); - break; - - case "/api/zones/dnssec/properties/publishAllPrivateKeys": - case "/api/zone/dnssec/publishAllPrivateKeys": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(request); - break; - - case "/api/zones/dnssec/properties/rolloverDnsKey": - case "/api/zone/dnssec/rolloverDnsKey": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.RolloverPrimaryZoneDnsKey(request); - break; - - case "/api/zones/dnssec/properties/retireDnsKey": - case "/api/zone/dnssec/retireDnsKey": - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _zonesApi.RetirePrimaryZoneDnsKey(request); - break; - - case "/api/zones/records/add": - case "/api/zone/addRecord": - case "/api/addRecord": - _zonesApi.AddRecord(request, jsonWriter); - break; - - case "/api/zones/records/get": - case "/api/zone/getRecords": - case "/api/getRecords": - _zonesApi.GetRecords(request, jsonWriter); - break; - - case "/api/zones/records/update": - case "/api/zone/updateRecord": - case "/api/updateRecord": - _zonesApi.UpdateRecord(request, jsonWriter); - break; - - case "/api/zones/records/delete": - case "/api/zone/deleteRecord": - case "/api/deleteRecord": - _zonesApi.DeleteRecord(request); - break; - - case "/api/cache/list": - case "/api/listCachedZones": - if (!_authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.ListCachedZones(request, jsonWriter); - break; - - case "/api/cache/delete": - case "/api/deleteCachedZone": - if (!_authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.DeleteCachedZone(request); - break; - - case "/api/cache/flush": - case "/api/flushDnsCache": - if (!_authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.FlushCache(request); - break; - - case "/api/allowed/list": - case "/api/listAllowedZones": - if (!_authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.ListAllowedZones(request, jsonWriter); - break; - - case "/api/allowed/add": - case "/api/allowZone": - if (!_authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.AllowZone(request); - break; - - case "/api/allowed/delete": - case "/api/deleteAllowedZone": - if (!_authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.DeleteAllowedZone(request); - break; - - case "/api/allowed/flush": - case "/api/flushAllowedZone": - if (!_authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.FlushAllowedZone(request); - break; - - case "/api/allowed/import": - case "/api/importAllowedZones": - if (!_authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - await _otherZonesApi.ImportAllowedZonesAsync(request); - break; - - case "/api/allowed/export": - case "/api/exportAllowedZones": - if (!_authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.ExportAllowedZones(response); - return; - - case "/api/blocked/list": - case "/api/listBlockedZones": - if (!_authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.ListBlockedZones(request, jsonWriter); - break; - - case "/api/blocked/add": - case "/api/blockZone": - if (!_authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.BlockZone(request); - break; - - case "/api/blocked/delete": - case "/api/deleteBlockedZone": - if (!_authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.DeleteBlockedZone(request); - break; - - case "/api/blocked/flush": - case "/api/flushBlockedZone": - if (!_authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.FlushBlockedZone(request); - break; - - case "/api/blocked/import": - case "/api/importBlockedZones": - if (!_authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - await _otherZonesApi.ImportBlockedZonesAsync(request); - break; - - case "/api/blocked/export": - case "/api/exportBlockedZones": - if (!_authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _otherZonesApi.ExportBlockedZones(response); - return; - - case "/api/apps/list": - if ( - _authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.View) || - _authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View) || - _authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View) - ) - { - await _appsApi.ListInstalledAppsAsync(jsonWriter); - } - else - { - throw new DnsWebServiceException("Access was denied."); - } - - break; - - case "/api/apps/listStoreApps": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - await _appsApi.ListStoreApps(jsonWriter); - break; - - case "/api/apps/downloadAndInstall": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - await _appsApi.DownloadAndInstallAppAsync(request, jsonWriter); - break; - - case "/api/apps/downloadAndUpdate": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - await _appsApi.DownloadAndUpdateAppAsync(request, jsonWriter); - break; - - case "/api/apps/install": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - await _appsApi.InstallAppAsync(request, jsonWriter); - break; - - case "/api/apps/update": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - await _appsApi.UpdateAppAsync(request, jsonWriter); - break; - - case "/api/apps/uninstall": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _appsApi.UninstallApp(request); - break; - - case "/api/apps/config/get": - case "/api/apps/getConfig": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - await _appsApi.GetAppConfigAsync(request, jsonWriter); - break; - - case "/api/apps/config/set": - case "/api/apps/setConfig": - if (!_authManager.IsPermitted(PermissionSection.Apps, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - await _appsApi.SetAppConfigAsync(request); - break; - - case "/api/dnsClient/resolve": - case "/api/resolveQuery": - if (!_authManager.IsPermitted(PermissionSection.DnsClient, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - await ResolveQueryAsync(request, jsonWriter); - break; - - case "/api/settings/get": - case "/api/getDnsSettings": - if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _settingsApi.GetDnsSettings(jsonWriter); - break; - - case "/api/settings/set": - case "/api/setDnsSettings": - if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _settingsApi.SetDnsSettings(request, jsonWriter); - break; - - case "/api/settings/getTsigKeyNames": - if ( - _authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.View) || - _authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify) - ) - { - _settingsApi.GetTsigKeyNames(jsonWriter); - } - else - { - throw new DnsWebServiceException("Access was denied."); - } - - break; - - case "/api/settings/forceUpdateBlockLists": - case "/api/forceUpdateBlockLists": - if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _settingsApi.ForceUpdateBlockLists(request); - break; - - case "/api/settings/temporaryDisableBlocking": - case "/api/temporaryDisableBlocking": - if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _settingsApi.TemporaryDisableBlocking(request, jsonWriter); - break; - - case "/api/settings/backup": - case "/api/backupSettings": - if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - await _settingsApi.BackupSettingsAsync(request, response); - return; - - case "/api/settings/restore": - case "/api/restoreSettings": - if (!_authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - await _settingsApi.RestoreSettingsAsync(request, jsonWriter); - break; - - case "/api/dhcp/leases/list": - case "/api/listDhcpLeases": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.ListDhcpLeases(jsonWriter); - break; - - case "/api/dhcp/leases/remove": - case "/api/removeDhcpLease": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.RemoveDhcpLease(request); - break; - - case "/api/dhcp/leases/convertToReserved": - case "/api/convertToReservedLease": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.ConvertToReservedLease(request); - break; - - case "/api/dhcp/leases/convertToDynamic": - case "/api/convertToDynamicLease": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.ConvertToDynamicLease(request); - break; - - case "/api/dhcp/scopes/list": - case "/api/listDhcpScopes": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.ListDhcpScopes(jsonWriter); - break; - - case "/api/dhcp/scopes/get": - case "/api/getDhcpScope": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.GetDhcpScope(request, jsonWriter); - break; - - case "/api/dhcp/scopes/set": - case "/api/setDhcpScope": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - await _dhcpApi.SetDhcpScopeAsync(request); - break; - - case "/api/dhcp/scopes/addReservedLease": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.AddReservedLease(request); - break; - - case "/api/dhcp/scopes/removeReservedLease": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.RemoveReservedLease(request); - break; - - case "/api/dhcp/scopes/enable": - case "/api/enableDhcpScope": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - await _dhcpApi.EnableDhcpScopeAsync(request); - break; - - case "/api/dhcp/scopes/disable": - case "/api/disableDhcpScope": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.DisableDhcpScope(request); - break; - - case "/api/dhcp/scopes/delete": - case "/api/deleteDhcpScope": - if (!_authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _dhcpApi.DeleteDhcpScope(request); - break; - - case "/api/admin/sessions/list": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.ListSessions(request, jsonWriter); - break; - - case "/api/admin/sessions/createToken": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.CreateApiToken(request, jsonWriter); - break; - - case "/api/admin/sessions/delete": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.DeleteSession(request, true); - break; - - case "/api/admin/users/list": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.ListUsers(jsonWriter); - break; - - case "/api/admin/users/create": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.CreateUser(request, jsonWriter); - break; - - case "/api/admin/users/get": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.GetUserDetails(request, jsonWriter); - break; - - case "/api/admin/users/set": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.SetUserDetails(request, jsonWriter); - break; - - case "/api/admin/users/delete": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.DeleteUser(request); - break; - - case "/api/admin/groups/list": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.ListGroups(jsonWriter); - break; - - case "/api/admin/groups/create": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.CreateGroup(request, jsonWriter); - break; - - case "/api/admin/groups/get": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.GetGroupDetails(request, jsonWriter); - break; - - case "/api/admin/groups/set": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.SetGroupDetails(request, jsonWriter); - break; - - case "/api/admin/groups/delete": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.DeleteGroup(request); - break; - - case "/api/admin/permissions/list": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.ListPermissions(jsonWriter); - break; - - case "/api/admin/permissions/get": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.GetPermissionDetails(request, jsonWriter, PermissionSection.Unknown); - break; - - case "/api/admin/permissions/set": - if (!_authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _authApi.SetPermissionsDetails(request, jsonWriter, PermissionSection.Unknown); - break; - - case "/api/logs/list": - case "/api/listLogs": - if (!_authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - _logsApi.ListLogs(jsonWriter); - break; - - case "/api/logs/download": - if (!_authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - await _logsApi.DownloadLogAsync(request, response); - return; - - case "/api/logs/delete": - case "/api/deleteLog": - if (!_authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _logsApi.DeleteLog(request); - break; - - case "/api/logs/deleteAll": - case "/api/deleteAllLogs": - if (!_authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.Delete)) - throw new DnsWebServiceException("Access was denied."); - - _logsApi.DeleteAllLogs(request); - break; - - case "/api/logs/query": - case "/api/queryLogs": - if (!_authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - await _logsApi.QueryLogsAsync(request, jsonWriter); - break; - - default: - await SendErrorAsync(response, 404); - return; - } - } - finally - { - jsonWriter.WriteEndObject(); - } - break; - } - - jsonWriter.WriteString("status", "ok"); - - jsonWriter.WriteEndObject(); - jsonWriter.Flush(); - } - catch (InvalidTokenWebServiceException ex) - { - mS.SetLength(0); - Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); - jsonWriter.WriteStartObject(); - jsonWriter.WriteString("status", "invalid-token"); jsonWriter.WriteString("errorMessage", ex.Message); - - jsonWriter.WriteEndObject(); - jsonWriter.Flush(); } - catch (Exception ex) + else { - UserSession session = null; - - string strToken = request.QueryString["token"]; - if (!string.IsNullOrEmpty(strToken)) - session = _authManager.GetSession(strToken); - - if (session is null) - _log.Write(GetRequestRemoteEndPoint(request), ex); - else - _log.Write(GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + ex.ToString()); - - mS.SetLength(0); - Utf8JsonWriter jsonWriter = new Utf8JsonWriter(mS); - jsonWriter.WriteStartObject(); - jsonWriter.WriteString("status", "error"); jsonWriter.WriteString("errorMessage", ex.Message); jsonWriter.WriteString("stackTrace", ex.StackTrace); if (ex.InnerException is not null) jsonWriter.WriteString("innerErrorMessage", ex.InnerException.Message); - - jsonWriter.WriteEndObject(); - jsonWriter.Flush(); } - response.ContentType = "application/json; charset=utf-8"; - response.ContentEncoding = Encoding.UTF8; - response.ContentLength64 = mS.Length; - - mS.Position = 0; - using (Stream stream = response.OutputStream) - { - await mS.CopyToAsync(stream); - } + jsonWriter.WriteEndObject(); } } - else if (path.StartsWith("/log/")) - { - if (!TryGetSession(request, out UserSession session)) - { - await SendErrorAsync(response, 403, "Invalid token or session expired."); - return; - } - - if (!_authManager.IsPermitted(PermissionSection.Logs, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - string[] pathParts = path.Split('/'); - string logFileName = pathParts[2]; - - int limit = 0; - string strLimit = request.QueryString["limit"]; - if (!string.IsNullOrEmpty(strLimit)) - limit = int.Parse(strLimit); - - await _log.DownloadLogAsync(request, response, logFileName, limit * 1024 * 1024); - } - else - { - if (path == "/") - { - path = "/index.html"; - } - else if ((path == "/blocklist.txt") && !IPAddress.IsLoopback(GetRequestRemoteEndPoint(request).Address)) - { - await SendErrorAsync(response, 403); - return; - } - - string wwwroot = Path.Combine(_appFolder, "www"); - path = Path.GetFullPath(wwwroot + path.Replace('/', Path.DirectorySeparatorChar)); - - if (!path.StartsWith(wwwroot) || !File.Exists(path)) - { - await SendErrorAsync(response, 404); - return; - } - - await SendFileAsync(request, response, path); - } - } - catch (Exception ex) - { - if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) - return; //web service stopping - - UserSession session = null; - - string strToken = request.QueryString["token"]; - if (!string.IsNullOrEmpty(strToken)) - session = _authManager.GetSession(strToken); - - if (session is null) - _log.Write(GetRequestRemoteEndPoint(request), ex); - else - _log.Write(GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] " + ex.ToString()); - - await SendError(response, ex); - } + }); } - internal static IPEndPoint GetRequestRemoteEndPoint(HttpListenerRequest request) + private bool TryGetSession(HttpContext context, out UserSession session) { - try - { - if (request.RemoteEndPoint == null) - return new IPEndPoint(IPAddress.Any, 0); - - if (NetUtilities.IsPrivateIP(request.RemoteEndPoint.Address)) - { - string xRealIp = request.Headers["X-Real-IP"]; - if (IPAddress.TryParse(xRealIp, out IPAddress address)) - { - //get the real IP address of the requesting client from X-Real-IP header set in nginx proxy_pass block - return new IPEndPoint(address, 0); - } - } - - return request.RemoteEndPoint; - } - catch - { - return new IPEndPoint(IPAddress.Any, 0); - } - } - - public static Stream GetOutputStream(HttpListenerRequest request, HttpListenerResponse response) - { - string strAcceptEncoding = request.Headers["Accept-Encoding"]; - if (string.IsNullOrEmpty(strAcceptEncoding)) - { - return response.OutputStream; - } - else - { - if (strAcceptEncoding.Contains("gzip")) - { - response.AddHeader("Content-Encoding", "gzip"); - return new GZipStream(response.OutputStream, CompressionMode.Compress); - } - else if (strAcceptEncoding.Contains("deflate")) - { - response.AddHeader("Content-Encoding", "deflate"); - return new DeflateStream(response.OutputStream, CompressionMode.Compress); - } - else - { - return response.OutputStream; - } - } - } - - private static Task SendError(HttpListenerResponse response, Exception ex) - { - return SendErrorAsync(response, 500, ex.ToString()); - } - - private static async Task SendErrorAsync(HttpListenerResponse response, int statusCode, string message = null) - { - try - { - string statusString = statusCode + " " + DnsServer.GetHttpStatusString((HttpStatusCode)statusCode); - byte[] buffer = Encoding.UTF8.GetBytes("" + statusString + "

" + statusString + "

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

" + message + "

") + ""); - - response.StatusCode = statusCode; - response.ContentType = "text/html"; - response.ContentLength64 = buffer.Length; - - using (Stream stream = response.OutputStream) - { - await stream.WriteAsync(buffer); - } - } - catch - { } - } - - private static async Task SendFileAsync(HttpListenerRequest request, HttpListenerResponse response, string filePath) - { - using (FileStream fS = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - response.ContentType = WebUtilities.GetContentType(filePath).MediaType; - response.AddHeader("Cache-Control", "private, max-age=300"); - - using (Stream stream = GetOutputStream(request, response)) - { - try - { - await fS.CopyToAsync(stream); - } - catch (HttpListenerException) - { - //ignore this error - } - } - } - } - - internal UserSession GetSession(HttpListenerRequest request) - { - string strToken = request.QueryString["token"]; - if (string.IsNullOrEmpty(strToken)) - throw new DnsWebServiceException("Parameter 'token' missing."); - - return _authManager.GetSession(strToken); - } - - internal bool TryGetSession(HttpListenerRequest request, out UserSession session) - { - session = GetSession(request); + string token = context.Request.GetQuery("token"); + session = _authManager.GetSession(token); if ((session is null) || session.User.Disabled) return false; @@ -1412,9 +533,9 @@ namespace DnsServerCore return false; } - IPEndPoint remoteEP = GetRequestRemoteEndPoint(request); + IPEndPoint remoteEP = context.GetRemoteEndPoint(); - session.UpdateLastSeen(remoteEP.Address, request.UserAgent); + session.UpdateLastSeen(remoteEP.Address, context.Request.Headers.UserAgent); return true; } @@ -1422,8 +543,10 @@ namespace DnsServerCore #region update api - private async Task CheckForUpdateAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + private async Task CheckForUpdateAsync(HttpContext context) { + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + if (_updateCheckUri is null) { jsonWriter.WriteBoolean("updateAvailable", false); @@ -1483,12 +606,12 @@ namespace DnsServerCore strLog += "}"; - _log.Write(GetRequestRemoteEndPoint(request), strLog); + _log.Write(context.GetRemoteEndPoint(), strLog); } } catch (Exception ex) { - _log.Write(GetRequestRemoteEndPoint(request), "Check for update was done {updateAvailable: False;}\r\n" + ex.ToString()); + _log.Write(context.GetRemoteEndPoint(), "Check for update was done {updateAvailable: False;}\r\n" + ex.ToString()); jsonWriter.WriteBoolean("updateAvailable", false); } @@ -1516,44 +639,26 @@ namespace DnsServerCore #region dns client api - private async Task ResolveQueryAsync(HttpListenerRequest request, Utf8JsonWriter jsonWriter) + private async Task ResolveQueryAsync(HttpContext context) { - string server = request.QueryString["server"]; - if (string.IsNullOrEmpty(server)) - throw new DnsWebServiceException("Parameter 'server' missing."); + UserSession session = context.GetCurrentSession(); - string domain = request.QueryString["domain"]; - if (string.IsNullOrEmpty(domain)) - throw new DnsWebServiceException("Parameter 'domain' missing."); + if (!_authManager.IsPermitted(PermissionSection.DnsClient, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); - domain = domain.Trim(new char[] { '\t', ' ', '.' }); - - string strType = request.QueryString["type"]; - if (string.IsNullOrEmpty(strType)) - throw new DnsWebServiceException("Parameter 'type' missing."); - - DnsResourceRecordType type = Enum.Parse(strType, true); - - string strProtocol = request.QueryString["protocol"]; - if (string.IsNullOrEmpty(strProtocol)) - strProtocol = "Udp"; - - bool dnssecValidation = false; - string strDnssecValidation = request.QueryString["dnssec"]; - if (!string.IsNullOrEmpty(strDnssecValidation)) - dnssecValidation = bool.Parse(strDnssecValidation); - - bool importResponse = false; - string strImport = request.QueryString["import"]; - if (!string.IsNullOrEmpty(strImport)) - importResponse = bool.Parse(strImport); + HttpRequest request = context.Request; + string server = request.GetQuery("server"); + string domain = request.GetQuery("domain").Trim(new char[] { '\t', ' ', '.' }); + DnsResourceRecordType type = request.GetQuery("type"); + DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); + bool dnssecValidation = request.GetQuery("dnssec", bool.Parse, false); + bool importResponse = request.GetQuery("import", bool.Parse, false); NetProxy proxy = _dnsServer.Proxy; bool preferIPv6 = _dnsServer.PreferIPv6; ushort udpPayloadSize = _dnsServer.UdpPayloadSize; bool randomizeName = false; bool qnameMinimization = _dnsServer.QnameMinimization; - DnsTransportProtocol protocol = Enum.Parse(strProtocol, true); const int RETRIES = 1; const int TIMEOUT = 10000; @@ -1620,7 +725,7 @@ namespace DnsServerCore } else { - nameServer = new NameServerAddress(server); + nameServer = NameServerAddress.Parse(server); if (nameServer.Protocol != protocol) nameServer = nameServer.ChangeProtocol(protocol); @@ -1674,8 +779,6 @@ namespace DnsServerCore if (importResponse) { - UserSession session = GetSession(request); - AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.FindAuthZoneInfo(domain); if ((zoneInfo is null) || ((zoneInfo.Type == AuthZoneType.Secondary) && !zoneInfo.Name.Equals(domain, StringComparison.OrdinalIgnoreCase))) { @@ -1748,11 +851,13 @@ namespace DnsServerCore _dnsServer.AuthZoneManager.ImportRecords(zoneInfo.Name, importRecords); } - _log.Write(GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] DNS Client imported record(s) for authoritative zone {server: " + server + "; zone: " + zoneInfo.Name + "; type: " + type + ";}"); + _log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS Client imported record(s) for authoritative zone {server: " + server + "; zone: " + zoneInfo.Name + "; type: " + type + ";}"); _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + if (dnssecErrorMessage is not null) jsonWriter.WriteString("warningMessage", dnssecErrorMessage); @@ -1940,27 +1045,11 @@ namespace DnsServerCore string strRecursionDeniedNetworks = Environment.GetEnvironmentVariable("DNS_SERVER_RECURSION_DENIED_NETWORKS"); if (!string.IsNullOrEmpty(strRecursionDeniedNetworks)) - { - string[] strRecursionDeniedNetworkAddresses = strRecursionDeniedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - NetworkAddress[] networks = new NetworkAddress[strRecursionDeniedNetworkAddresses.Length]; - - for (int i = 0; i < networks.Length; i++) - networks[i] = NetworkAddress.Parse(strRecursionDeniedNetworkAddresses[i].Trim()); - - _dnsServer.RecursionDeniedNetworks = networks; - } + _dnsServer.RecursionDeniedNetworks = strRecursionDeniedNetworks.Split(NetworkAddress.Parse, ','); string strRecursionAllowedNetworks = Environment.GetEnvironmentVariable("DNS_SERVER_RECURSION_ALLOWED_NETWORKS"); if (!string.IsNullOrEmpty(strRecursionAllowedNetworks)) - { - string[] strRecursionAllowedNetworkAddresses = strRecursionAllowedNetworks.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - NetworkAddress[] networks = new NetworkAddress[strRecursionAllowedNetworkAddresses.Length]; - - for (int i = 0; i < networks.Length; i++) - networks[i] = NetworkAddress.Parse(strRecursionAllowedNetworkAddresses[i].Trim()); - - _dnsServer.RecursionAllowedNetworks = networks; - } + _dnsServer.RecursionAllowedNetworks = strRecursionAllowedNetworks.Split(NetworkAddress.Parse, ','); _dnsServer.RandomizeName = true; //default true to enable security feature _dnsServer.QnameMinimization = true; //default true to enable privacy feature @@ -2020,20 +1109,15 @@ namespace DnsServerCore forwarderProtocol = DnsTransportProtocol.Https; } - List forwarders = new List(); - string[] strForwardersAddresses = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - - foreach (string strForwarderAddress in strForwardersAddresses) + _dnsServer.Forwarders = strForwarders.Split(delegate (string value) { - NameServerAddress forwarder = new NameServerAddress(strForwarderAddress.Trim()); + NameServerAddress forwarder = NameServerAddress.Parse(value); if (forwarder.Protocol != forwarderProtocol) forwarder = forwarder.ChangeProtocol(forwarderProtocol); - forwarders.Add(forwarder); - } - - _dnsServer.Forwarders = forwarders; + return forwarder; + }, ','); } //logging @@ -3246,169 +2330,15 @@ namespace DnsServerCore #endregion - #region web service start stop - - internal void StartDnsWebService() - { - int acceptTasks = Math.Max(1, Environment.ProcessorCount); - - //HTTP service - try - { - string webServiceHostname = null; - - _webService = new HttpListener(); - IPAddress httpAddress = null; - - foreach (IPAddress webServiceLocalAddress in _webServiceLocalAddresses) - { - string host; - - if (webServiceLocalAddress.Equals(IPAddress.Any)) - { - host = "+"; - - httpAddress = IPAddress.Loopback; - } - else if (webServiceLocalAddress.Equals(IPAddress.IPv6Any)) - { - host = "+"; - - if ((httpAddress == null) || !IPAddress.IsLoopback(httpAddress)) - httpAddress = IPAddress.IPv6Loopback; - } - else - { - if (webServiceLocalAddress.AddressFamily == AddressFamily.InterNetworkV6) - host = "[" + webServiceLocalAddress.ToString() + "]"; - else - host = webServiceLocalAddress.ToString(); - - if (httpAddress == null) - httpAddress = webServiceLocalAddress; - - if (webServiceHostname == null) - webServiceHostname = host; - } - - _webService.Prefixes.Add("http://" + host + ":" + _webServiceHttpPort + "/"); - } - - _webService.Start(); - - if (httpAddress == null) - httpAddress = IPAddress.Loopback; - - _webServiceHttpEP = new IPEndPoint(httpAddress, _webServiceHttpPort); - - _webServiceHostname = webServiceHostname ?? Environment.MachineName.ToLower(); - } - catch (Exception ex) - { - _log.Write("Web Service failed to bind using default hostname. Attempting to bind again using 'localhost' hostname.\r\n" + ex.ToString()); - - try - { - _webService = new HttpListener(); - _webService.Prefixes.Add("http://localhost:" + _webServiceHttpPort + "/"); - _webService.Prefixes.Add("http://127.0.0.1:" + _webServiceHttpPort + "/"); - _webService.Start(); - } - catch - { - _webService = new HttpListener(); - _webService.Prefixes.Add("http://localhost:" + _webServiceHttpPort + "/"); - _webService.Start(); - } - - _webServiceHttpEP = new IPEndPoint(IPAddress.Loopback, _webServiceHttpPort); - - _webServiceHostname = "localhost"; - } - - _webService.IgnoreWriteExceptions = true; - - for (int i = 0; i < acceptTasks; i++) - { - _ = Task.Factory.StartNew(delegate () - { - return AcceptWebRequestAsync(); - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _webServiceTaskScheduler); - } - - _log.Write(new IPEndPoint(IPAddress.Any, _webServiceHttpPort), "HTTP Web Service was started successfully."); - - //TLS service - if (_webServiceEnableTls && (_webServiceTlsCertificate != null)) - { - List webServiceTlsListeners = new List(); - - try - { - foreach (IPAddress webServiceLocalAddress in _webServiceLocalAddresses) - { - Socket tlsListener = new Socket(webServiceLocalAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - - tlsListener.Bind(new IPEndPoint(webServiceLocalAddress, _webServiceTlsPort)); - tlsListener.Listen(10); - - webServiceTlsListeners.Add(tlsListener); - } - - foreach (Socket tlsListener in webServiceTlsListeners) - { - for (int i = 0; i < acceptTasks; i++) - { - _ = Task.Factory.StartNew(delegate () - { - return AcceptTlsWebRequestAsync(tlsListener); - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _webServiceTaskScheduler); - } - } - - _webServiceTlsListeners = webServiceTlsListeners; - - _log.Write(new IPEndPoint(IPAddress.Any, _webServiceHttpPort), "TLS Web Service was started successfully."); - } - catch (Exception ex) - { - _log.Write("TLS Web Service failed to start.\r\n" + ex.ToString()); - - foreach (Socket tlsListener in webServiceTlsListeners) - tlsListener.Dispose(); - } - } - } - - internal void StopDnsWebService() - { - _webService.Stop(); - - if (_webServiceTlsListeners != null) - { - foreach (Socket tlsListener in _webServiceTlsListeners) - tlsListener.Dispose(); - - _webServiceTlsListeners = null; - } - } - - #endregion - #endregion #region public - public void Start() + public async Task StartAsync() { if (_disposed) throw new ObjectDisposedException(nameof(DnsWebService)); - if (_state != ServiceState.Stopped) - throw new InvalidOperationException("Web Service is already running."); - - _state = ServiceState.Starting; - try { //get initial server domain @@ -3477,9 +2407,7 @@ namespace DnsServerCore _dhcpServer.Start(); //start web service - StartDnsWebService(); - - _state = ServiceState.Running; + await StartWebServiceAsync(); _log.Write("DNS Server (v" + _currentVersion.ToString() + ") was started successfully."); } @@ -3490,16 +2418,14 @@ namespace DnsServerCore } } - public void Stop() + public async Task StopAsync() { - if (_state != ServiceState.Running) + if (_disposed) return; - _state = ServiceState.Stopping; - try { - StopDnsWebService(); + await StopWebServiceAsync(); _dnsServer.Dispose(); _dhcpServer.Dispose(); @@ -3507,8 +2433,6 @@ namespace DnsServerCore _settingsApi.StopTemporaryDisableBlockingTimer(); StopTlsCertificateUpdateTimer(); - _state = ServiceState.Stopped; - _log.Write("DNS Server (v" + _currentVersion.ToString() + ") was stopped successfully."); } catch (Exception ex) @@ -3518,6 +2442,16 @@ namespace DnsServerCore } } + public void Start() + { + StartAsync().Sync(); + } + + public void Stop() + { + StopAsync().Sync(); + } + #endregion #region properties @@ -3531,9 +2465,6 @@ namespace DnsServerCore public int WebServiceTlsPort { get { return _webServiceTlsPort; } } - public string WebServiceHostname - { get { return _webServiceHostname; } } - #endregion } } From 88c45a1b4b4b2278bfe75db8ebafe29c6e5da5dc Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:14:46 +0530 Subject: [PATCH 057/191] AdvancedBlocking: updated DownloadListFileAsync() to support all decompression methods. --- Apps/AdvancedBlockingApp/App.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/AdvancedBlockingApp/App.cs b/Apps/AdvancedBlockingApp/App.cs index ae00fe35..46dd4396 100644 --- a/Apps/AdvancedBlockingApp/App.cs +++ b/Apps/AdvancedBlockingApp/App.cs @@ -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 @@ -884,7 +884,7 @@ namespace AdvancedBlocking SocketsHttpHandler handler = new SocketsHttpHandler(); handler.Proxy = _dnsServer.Proxy; handler.UseProxy = _dnsServer.Proxy is not null; - handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + handler.AutomaticDecompression = DecompressionMethods.All; using (HttpClient http = new HttpClient(handler)) { From f4e4d6dcd210b912aaa2f1583ef0577b9251ec7e Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:15:15 +0530 Subject: [PATCH 058/191] updated named.root --- DnsServerCore/named.root | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/named.root b/DnsServerCore/named.root index 6a8a4fd9..0e94324e 100644 --- a/DnsServerCore/named.root +++ b/DnsServerCore/named.root @@ -9,8 +9,8 @@ ; on server FTP.INTERNIC.NET ; -OR- RS.INTERNIC.NET ; -; last update: August 31, 2022 -; related version of root zone: 2022083101 +; last update: January 01, 2023 +; related version of root zone: 2023010101 ; ; FORMERLY NS.INTERNIC.NET ; From cdf503ef65edbe174d277a3c0b927ccfdcf306da Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:16:09 +0530 Subject: [PATCH 059/191] webapp: removed jquery-ui and bootstrap-datetimepicker. --- .../www/css/bootstrap-datetimepicker.min.css | 5 - .../css/images/ui-icons_444444_256x240.png | Bin 7090 -> 0 bytes .../css/images/ui-icons_555555_256x240.png | Bin 7074 -> 0 bytes .../css/images/ui-icons_777620_256x240.png | Bin 4618 -> 0 bytes .../css/images/ui-icons_777777_256x240.png | Bin 7111 -> 0 bytes .../css/images/ui-icons_cc0000_256x240.png | Bin 4618 -> 0 bytes .../css/images/ui-icons_ffffff_256x240.png | Bin 6487 -> 0 bytes DnsServerCore/www/css/jquery-ui.min.css | 7 - .../www/js/bootstrap-datetimepicker.min.js | 214 ------------------ DnsServerCore/www/js/jquery-ui.min.js | 6 - 10 files changed, 232 deletions(-) delete mode 100644 DnsServerCore/www/css/bootstrap-datetimepicker.min.css delete mode 100644 DnsServerCore/www/css/images/ui-icons_444444_256x240.png delete mode 100644 DnsServerCore/www/css/images/ui-icons_555555_256x240.png delete mode 100644 DnsServerCore/www/css/images/ui-icons_777620_256x240.png delete mode 100644 DnsServerCore/www/css/images/ui-icons_777777_256x240.png delete mode 100644 DnsServerCore/www/css/images/ui-icons_cc0000_256x240.png delete mode 100644 DnsServerCore/www/css/images/ui-icons_ffffff_256x240.png delete mode 100644 DnsServerCore/www/css/jquery-ui.min.css delete mode 100644 DnsServerCore/www/js/bootstrap-datetimepicker.min.js delete mode 100644 DnsServerCore/www/js/jquery-ui.min.js diff --git a/DnsServerCore/www/css/bootstrap-datetimepicker.min.css b/DnsServerCore/www/css/bootstrap-datetimepicker.min.css deleted file mode 100644 index 2ee13b0d..00000000 --- a/DnsServerCore/www/css/bootstrap-datetimepicker.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Datetimepicker for Bootstrap 3 - * version : 4.17.42 - * https://github.com/Eonasdan/bootstrap-datetimepicker/ - */.bootstrap-datetimepicker-widget{list-style:none}.bootstrap-datetimepicker-widget.dropdown-menu{margin:2px 0;padding:4px;width:19em}@media (min-width:768px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:992px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:1200px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}.bootstrap-datetimepicker-widget.dropdown-menu:before,.bootstrap-datetimepicker-widget.dropdown-menu:after{content:'';display:inline-block;position:absolute}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);top:-7px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after{border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;top:-6px;left:8px}.bootstrap-datetimepicker-widget.dropdown-menu.top:before{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.dropdown-menu.top:after{border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid white;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget .list-unstyled{margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:bold;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget .btn[data-action="incrementHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Increment Hours"}.bootstrap-datetimepicker-widget .btn[data-action="incrementMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Increment Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="decrementHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Decrement Hours"}.bootstrap-datetimepicker-widget .btn[data-action="decrementMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Decrement Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="showHours"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Show Hours"}.bootstrap-datetimepicker-widget .btn[data-action="showMinutes"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Show Minutes"}.bootstrap-datetimepicker-widget .btn[data-action="togglePeriod"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Toggle AM/PM"}.bootstrap-datetimepicker-widget .btn[data-action="clear"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Clear the picker"}.bootstrap-datetimepicker-widget .btn[data-action="today"]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Set the date to today"}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget .picker-switch::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Toggle Date and Time Screens"}.bootstrap-datetimepicker-widget .picker-switch td{padding:0;margin:0;height:auto;width:auto;line-height:inherit}.bootstrap-datetimepicker-widget .picker-switch td span{line-height:2.5;height:2.5em;width:100%}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget table td,.bootstrap-datetimepicker-widget table th{text-align:center;border-radius:4px}.bootstrap-datetimepicker-widget table th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table th.picker-switch{width:145px}.bootstrap-datetimepicker-widget table th.disabled,.bootstrap-datetimepicker-widget table th.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table th.prev::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Previous Month"}.bootstrap-datetimepicker-widget table th.next::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0;content:"Next Month"}.bootstrap-datetimepicker-widget table thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget table thead tr:first-child th:hover{background:#eee}.bootstrap-datetimepicker-widget table td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget table td.cw{font-size:.8em;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget table td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table td.day:hover,.bootstrap-datetimepicker-widget table td.hour:hover,.bootstrap-datetimepicker-widget table td.minute:hover,.bootstrap-datetimepicker-widget table td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget table td.old,.bootstrap-datetimepicker-widget table td.new{color:#777}.bootstrap-datetimepicker-widget table td.today{position:relative}.bootstrap-datetimepicker-widget table td.today:before{content:'';display:inline-block;border:solid transparent;border-width:0 0 7px 7px;border-bottom-color:#337ab7;border-top-color:rgba(0,0,0,0.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget table td.active,.bootstrap-datetimepicker-widget table td.active:hover{background-color:#337ab7;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget table td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget table td.disabled,.bootstrap-datetimepicker-widget table td.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:4px}.bootstrap-datetimepicker-widget table td span:hover{background:#eee}.bootstrap-datetimepicker-widget table td span.active{background-color:#337ab7;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.bootstrap-datetimepicker-widget table td span.old{color:#777}.bootstrap-datetimepicker-widget table td span.disabled,.bootstrap-datetimepicker-widget table td span.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget.usetwentyfour td.hour{height:27px;line-height:27px}.bootstrap-datetimepicker-widget.wider{width:21em}.bootstrap-datetimepicker-widget .datepicker-decades .decade{line-height:1.8em !important}.input-group.date .input-group-addon{cursor:pointer}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0} \ No newline at end of file diff --git a/DnsServerCore/www/css/images/ui-icons_444444_256x240.png b/DnsServerCore/www/css/images/ui-icons_444444_256x240.png deleted file mode 100644 index 156ebd16760f51290b311c40081cc87f770fba95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7090 zcmZvBcQ{;MxBr>ZdkIF5k?4%k+vo%#YLqY-o#?$YT0{^MB}A7fK@u&Z8-$47dr$Nd zy_f5I-~0TY_r3S`&sk^fv)8lt{;adse%5EjXltsF5YiI@06?Oqs-z15pu1OK4=&&L+Et?@P-4xCJF!~(*OYC zmRYZZxcdOMR98^~lx7fx4R;!zm)a9$ycIABi3km{TkCEjeTtfr{8PW_oh-*VHWlxm zq0Ukj`1{k)A7%@MFZGy%=mPPd0liG9w5xQKqwK|*#nDlXXxz?}z`fEGx$;mE zN|0XngHaW0oLmUgVlzG05BJ|bM$F#J3UV0k^2c&0)jCbOXj1t~QgVoZ3!Y@8c5ybZ zlB9gWnLE#j^uoz@x$V5EUQLQS5p)OC%aqHb;XEi4^s*?!$X>I+Y(|(wekytESV-|j z?$P7iI_mUkl<_D1nb*=do-@L0bF+AbTr(Hxd{GBr)Fbh|5{D|?XP90^?aYJ4o=L?c zW1vQIx-5<|aAyxZ=ysNZdC^WJ*S>_4yY!Fl2eKD$1cVv?LBo|SF+pnm%2lv?607zZ z_GGev^9O14If2i~Xa!z*X}j{g%45~;DXdxtOs{^i-Jne0H^*twlNnv}U%^{?_vswb z`O;`~hzNqzX88NYM$IJb1Sp(M&v8j`eMDQp6q+TO$*yM8R;IJottD-cMyu62U27pdzLJWf_EPjFm{Ei03)X(#ZtY8u@PGV9 z5)DEBpM&(%dEvewT>=cxx4x#N_TNez=bsi(;-*IozK_@}VF~O7B_o-^3h>Pf(<`h< zYEB!SW4f9vqH(;=r`v5hA~hxiNQIP_fvHp&gDXrPaB&u-vhx*{V@iq4w|1?vRCzCuIERLy;&-eBqXRp9w6S?#n(_3CG z7*Mp&%^1;Cw{yXrLgH%sP|`|PGn;TiHp<33=h7I&Ke|{Zs@Ll~Vn(q|hifL}!^~Di z;5*Amg-;Hvut8Yss<4x3nF++%QNE_AL4&ol4Yur4pBy15jW(Hh=9}l zp_c}+b~6k+7szl6cx zsmnDiq6iRw`y3Yi#Dd*<>z{D~YFj zk;_c@=NXnwTQ#eJFc?z4QWY9aD1;(6-s)G-GydjkAqSFER zr^!!bz@l^xWQqDz2EX3#JOnjVe%oEAwGJTnCWD5SDjXG3mu9n^GAp))_~RQr5iHom zDC6<>HjNsIOk>sBU+(NedsUr5qwLhHC0cmUCf_&W*4l61ljw})7V>L5VktV~?dJ22 zJpl*iIeAwZmq`wJr7MAHKuq+j^_bEK8{#JujnDRY!UX9%L->LC|D6JebAaj>>L#L_ zT}0>%*v!XDf~?|ta=!YE18z}!S$xF^kKJX{Sv5S3(JrlbMykf0Zu+LxAW8892Vt|2%oQC+8%Xmb0K31p7< z>HD5j$_7*1q*jxgw1I*Ogq56Tm7;>xXeY(IU+e2^w-{hE4<6MN^R|p@zMhHnF=f z##Pl>uyD@!x}slP3jJ;$+9?8dBSb^=XDz5G`5o~3lb!IZfIrFzv=@}qHdyRFOIs3# zAf&g5cY%fjF=8tqkw6K7a?M2$LXP4T!7;A5+)G|9rdUnCw5< zs*H_TNbG459_*FQea3X3QyK&HWxo}}{e&;`g}G)5 zct(KjdU+8X`;W*c{qO11O%Ep(g2KPk>=K;ZU-8FCf%4^BB4N2*H$fo&^1^-fUt@k@ zwp*aZ%9r~Io^)DV>s5#j=%Tx=NHChNrMDre6fwQMEPo<|mHDKLctDIcxz}C$*GJRz z1X8O>6wy9S6rkZwJJ~a2&-|^cn&qh>F7?Xg`M9|6qlMpu??2;_Yd~0Y14uGb)=SJ# zD!V57%J2yLwFC01Se&j#2(SGMP}n)W=~X}<`SXm|fh?4uuJVP4fM@!aWs#os?b;c` zh9Si&Y-kp%m&@$1dl1T;Km0d{dJZe{3Vax4Cs%X{6@7S9_W62bp(6Hjsq_GK$Bc{yi@qNL)~KcvejxTnFc31;oNsVlUmD~xuTYrvChKNh3I~RLXiO{h=r(o> zJ&pIi^f;4niP?QM>SC~d`I^1ugl4&6^LGc~f`a+Fdm3Q$c61J4B8AIC(sDCG&5M*F z;@!uL7W|y2T0uEX7$M~I;<*BQ0f+PfcXI;(`!Y)OGbb2&$vcm6c8s!=UE=V6kn<-V z@q_sZPM=4jq6W2Bz{Z=>&2~f6*RHqxu%&3^525WrCz-4~MOBP2k+CEyH#A+y>9=q4 zQSHUMuwQRQX!R1>V-Oi^9hUk~WQ3T1N<3ETLvU7VM7R(+%p<3x$$^0?Ti zkD99A3TIe~YHH3zqNRXPAoFJi$i5<#5OZ(%`31rgk*A-rS^lCg{jl%u6f*695B<$b z;jj#w>~@XgsOvq;o0Nq=vS%dCttQmmDZZeJiqUG;5Dh%yBj-2=V)N98oof>ZQjDs@ z5EE-iik8lA`kN?2yO2;Fi{S$w6i0b<&dC3qL2{3|9`k_*e+!_uRWS)PWPlL5K3OAQJKu2venMbn9T77 z<VG^W+t*`1bU)P0AND=36o0I$`VMAcO;^UB5A)Vr zlO5s(w`FLJW|Vb6K(m(9fu`ks5tHiKc5NwU5#p(QNg^UQZuO#Ocr0>WBAl3j-Tme7@BVHbH2o=h-0K@+ok;Q zd=KUoG<2lM9<}si^~c^|yDVEp&bIMI2E}C%?)UBT9E=nD2fkpPqsd?2kS|nGHODG? zw)l_?%XMW|Y3G^751($)qn^#+7&Y5=~lxu%NLr-uNxU%45NRRo|+c0PBosCc;rm=Md4E_ru#?r3?#;A#3^NEl|(@D z^_PEV_Ebd$^S7hbP+>gj*z81Lx9~a4Zsauw6&I2!xb%CGOb7qLy~Us#Ewx)hF~JTZ z%B+y{kb_P8YeA)Nn-V=im8IHak>h@FD`lPSrAU0U^g7tG*0}_*kl<<^jgAicy}gQ^ z!)Ypf`oKn`A|>l7IL|Jl7ilLzQ-QDz)!|rJ_U=Sn@ymi1IU3F6r8}vhgRdvek>gAQ zSDysF*3q2j;H}bGWx5wA%g0J%ppll}@v9pCqG3YYD9Aexhvz~M|B_H`-`5KuB=j^K zOO`I=ogR!amgVKSEUM7hGOTFfnL_-Tm~QDyk9&}56?OKt5Q`DTA(=HV+Mf*5d!_#N zFJ73eZsZw{+&a9FJV2HX`pJkoV}N%LYjG{JkJM#F$6YGW3{#cKpg)Hz#gi6fLA+$U zXC0tmp#Js!halX9GUee5h!uotIoz#!f=Atz+)mGt`da=Xi+Z|u;;dw1*{au{oO zZZ*!@9_M@|4Dn3~T~jmo_Kk}2;Ux|!q%rXtdiX|dp7Azw%Zik18)E$~_?%ohI^^*! zju}&C2lEa6Sz;kIzdN(9isjfc?N{!XMl{@@uJ;{N9qxLIckF|GHVmT}{y$ax8wgs_ zICRN(|C{xj6USMR^|-(z+ymXc7I%p~<1d_%m&w&KH-u)br1S9g-oR0n8ob(w9#Czj zltSX?sK_k&@;}_3VnZ?>O}lH;{k*wc=3)nJPrO z>bY@);S2%{j`o!AkeO=4|CqtRAwpaoWn}qQigu0EnXo+TTvheR5}|unl>Io94Vy$A zGdVD`1l9_lHz3-~;vK=DikAVpOR&0opGSVqd_3Gb@lh#*miJyarmNY!Oq62P`#R&F zAR0A7u+@{fUSUIV3S`+|{e2`^+Qaj@O)Kf5*D#OhN_9z=WB15=+qdJo%)KRyJG976 zz#<(-)ARkvV3E})Ty!m7SBd;9Zi-W83~oiVSWBINO+)r|#9xr6&5Nj!4}wJG(sI+& zCg}vIfYYAt+L8vQ9!6PhMq;v&H^Hwz9rHVWS!qb}y2p=Dz6h+%5^!0Q#xMw< zr1+97epvg%-xa0TAB3hF=-C0?jCdfK~F45onKA&CeP2 z|6!&M)@i-LOr@QuSSSwwWuT$f{`)$TmMVLZ;6amBwf?#hA6*UOA7&H>UYSDfBW?tr zGa-{G>l4N3_;CDR%f3qTvaAIkDdn%n55(v7kv5z;QkSM>?`yCRn!|B4D@%}X#{%z> z7WhHWMS^wwL4$dHn)^Naf!8j2Wj$CXB4nktt-mFGBNkcBJxwl;|#1#-;H&Tf>w_nG?>>s>^yw%%EBN#|q zC@23n=b&N+Xau@SKO+AGRG$e0kOR^9ufchCmt`+DE7&NAW=TzT2KQ?I2im^h0lyw-*Y5B;eM$LMO_^pXg@}z5h zG_C?*>~&570VTL)I)rpZy^?N(x`j8?C6M?$CxuflJ#8-e`M`H`M!dZyTy`hX(J#(X zkaS|~=qIK5759bs)(~D)iwhY}By92dVg`UD!if1Z8A50g?I{`_{N*{YzoUd`dP4w$ zRi0Hv6-W`~nZA>WgDCQosuRCJf)GWjp;CKqU*1sO`urw@0$Kq7z-+L;m)0Y^+8mfz zRqVZOox&oqq+0EZuHK(C(yPHUji0{*>@$Q$L3y3p&w(}tjk zLPMo1n!QhL{&hL2{aD57-|N!1#F`dX7=)Vy`NdkmUvnILG#Y@ z7}30iqmXy5gGcn_igKIhvJK9g`maiP501wE*iY#@Ut!1>QbS~-LVkQtSx61_yc!wq z6gCaIC!Im${YjnmFSo%C@$~9r(Yfme@U~);RISSeY=38?bk?GwlT6zcPNaTCD)fnJ zLj^Qh`nlz77q2cQdwWpVnWP6Iq@|)r_QCzTIP=;Ffyim!#taeTsa(xun86>U?!?Lf z+ckNWUD#HfL~V?T(Dq+~{!ckdxC1sf?^Nt}D0@byJ>XG#aaC~I6k^z z&dyhZ|ACF(RpVhvrI+01)mQteA-$Z5YJE#q#jfo4KppPUv6rQkF;*=t;klIQ>7W{oe@e zH~P3!nrlox^(r`B)0q7~&rRv-VRKgN+Kk}M3YWR}3QegDqnfRX3TA*4G16{MHDOL@ z9c7i<|IRnAJpaprVnibl7x5NJItf zOt8x_v*pPO+Md~--|*#`QJW=!7BlZu51L%84EEZ;U>FMSz^Kf%oM(ex}? z(dbN1vD}dVg}~)CV=hM`U$}vhjq+3t7$tJbg(r5pBXD_2w^15GI>^%nMs0#l*vevL zS0Yi(Zbg0{)uob}xxLe`L&(=bf11LMnVO<|1->G_7MNa ztYd2t-AXw3ue+WVo0qbYm$ikLjii-_&7A-Q;erBuZ~;C+!KZK$Nw|QdkOU7LE(wSG zz(0@thk>)JwS%ocARr+w!Y2Ud6BK<47nc;cvw{E1fVEc-@6LekpB406ZM}RgJZu1Y jYgbDf7By!JI~!da3u}M(UpD_V(f~DOO{FgisPO*+FY`9) diff --git a/DnsServerCore/www/css/images/ui-icons_555555_256x240.png b/DnsServerCore/www/css/images/ui-icons_555555_256x240.png deleted file mode 100644 index e2200d5bc3c8026804600f9095ea520c7e75a11b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7074 zcmZvBby(Ejv;TXSSUMLFB$ft|E-67mx}`fL1f*MG2?Ys35NQ^aa#0$jSsDo`QIPJC zUTR^1AD?^g?>^t}bHD$bbLN~gC+3-XX67|-^mJ57i5Q3g03cOYQ#Jqq(CrX7Ai%wC zRq}ikZaZA(N7|17pel(NYlnAB!yMEMv;iQ53jpBJ0B~_T1>Xb!e<1+awgmv`3;>|> z%4yPh<(C4LT=O!)5rsk4kz*$nRE8&m8AYh4QSPNWYgctIZ>IK zi4(cqVXYe^^6%j;a{JVnK+q z@)mB|GPiE#-gSLwj5vBPtNLq#1%Vm4?H*ud7lOarrRo=GNS$T)`OH1*HB5Ld+%4rVcWGtIO-Jy7GulWVip|VS3$gL2r79U z{yYu^&`dkShJDPaaLw&r3Fw=j!szDC`b+w2acdbN<) zd>c|-#mr-mkVgLccsV$4;Cl1SN;YM$D>s52G|jAVV%3W@6wD`c2!Cj`1JW8nSj-Sq}cjvi_Qzx6uT0SLl4;vm3e4Ce~A=MY>_>fcVkBz4~81 zkt4cELc-JuDnI&d!^fX{l%%mA=B#EAiKu0Y6WRt=&@^LMGB4!jO zS(2Of1A8a7ktBbIL&z^E#J#|B%50ZD&}|mQ>TihCSZGm)ua%Uq`R7!cr+=^o-^nUR zlc#QI7Vi(eyH3}yo+kgXdhY&!z;ty-qbc6!>6%hJ6F3e2xhGDI5e|YA6|(rfWWV_5 zP^?-;88NPCpfn-$E!XIx&?ck%+NDYCUlZ_MGF|xVuK&_{mj|*ShW}3{OU7{hFn~as z| z5UJ(+t&lOunLp3?Y`$~rPs$+|I4UU%zhOn(vj z#rq}7KBF4fs{)>{Z265bqil5T`n2`x;&R4*hQPK0#~0@hp)FVPYhZ02TuoH^v6>)S z?C0m0@sh1;qvW;bZN^T&vzJw3^c|DTxLRkr_Q(yO{=Mh|Y4O!C#_~fgM92s(8zD@y zkRxSCsqGr8Qj`7ia~4WR!I03{myE+$vt$w95M5r}H{Y<9Qmq8fmNIhjr?g|n``aB* zX6-LE+q-zdV*7E*EjR@VSXOY zW&+vJ1=8K6)V`KNPAZ^=x0O7K!oD?OyKH(@y0Y?#yq^GekEqORDj)@JHEkZ~M-t7fJg3x;KvJ{@#~B4C zhb9$lad)%YiVwd>;v`9*_s?o38hw(3$Ja0HF?S{m(JFWt*p*+nQ;dhwsVm}h7TL!l z@x@<8nBOhU?uEx!KanKdc~w0*{H$tQdEzP68&-(Lfe?KK*#}`UE3{Kb1@3^0DLND^ z#{4gK|BsZrRN=oW@25!M1cMv4s zXiL3ob;^3h!?zVujXuWv*S}?qbQ7jUFa%5>8wepN1u34X6%phT$#9aSJa)ozG=~mO zCRgNH_flyJROqUQZ@&vBrYqChx9twwe)YGCN;+6MqEaYH4chUn0_zhNvS!={;z83U z8&&<_8VTS?Re$(Sqgg?369Qh^Lq_zw>vA+F9jLJ)=xk-Yx*Y?|&N$-h#5~e}_oEKY zBaN_MY~I+35(tlgWJBKC$w>VS9LY{tn!pQkzxOZ7dWRD{RLnlwftWv|-Gd6s`SXq@v?!^Uy7imS1- zRmoCsz`jFna(6Z*+7dO}(Nc^Kx!wVQ;6_)18-W)QoX%+04w`b`74m~hI64yuj)Nrg z<8o>*3`1fMIlLkf2d+w|eapI6%gYiT&T!KCA7HbTV8R&Z4At?_&iyIDARbm&u0HC6Y|snE`Tvmm=K zgTyqavXo(S$=4hGAzTK?k^S@zgWJ3IN7+Z;uS1HnpY97ZL2f zLVft{8((4iD2NtLFTKM{0t(iCHtA6uAV^qGfmro;<))8jSqnxr1Iv%vqXqJ(uo$ql zt@et^xaSI9=2r-OaQSt3&R~!RD`Jh843s2VwuLivZZw}7Huz~+fZ0)A6g3?^bnqhT z(RW5jT4Jr{`Gg(GU3b=bBn$qH!sU^;!q%<%O1z(szk zB#0WZtS#Hktc^G9ldPmg;}^30OLvmV@~!8Mpum!n<9&Jn&t9;{Z^i<1aU*}N>F89-=-Nwf>~*GRz= z+;(RVPXW15~-@GmUpv(0Pc=LDvr{r=<5 zu|Ma6F;uCCQ;3>1KW=z-`Zeu$J-q-jO7Y6;E!}xARp~sK%YaV&S!6#?Tgi*$cJcM{ zx3VxXiT0Nax%vtx_+EGSS3u>Ew_Z%&&>;1uZVvK8Q7*JMTIXYRAg20(hMHQsfSo)2 z7r~DL{)QX!Bg35)*~C}hq56FbiGxB#$=P9D4?WP6>4Fy7@*?AL(x-$5sr-a)T5uk?g4)n>q z$j=UR=D+8*R8WW_b0I4>8=#Gz8@Ac*KElRV76h0Fk~GWNb0(`_>5ooHR2un}$0nlg zC%tRM*Qr6NGvm+qHh%t7lM%c7-eWU;@{%fbXw)tXujiwN-v)Jpcg|dvB?ob}q?ce% zTBk|T!pH$rkNGBH+W=J5Z`p5k&8t~j)~t2^9?kdlI+L`^q2~h1$qWNSe3oIawFra_ z`~!-~tYb~yB>4)A(4MxE;BZCYl{->p+^1N?ZH}08MI-bIz4Wo4=kqS0?L)c|XpDRj zwrsW^DyZgvv3B{rY~^H-ViLJ=AH7wsILThy8x={TQWX==6I68TBjnfU04%H#Mg}6s z>6;!Vd}!9>vZp$bVb3S?8Tu~I!{A)N{{Hi$LQK3ghPFa-eJLEn3&^jL5^V_=6GQ~e zVtby>c`qRt&{_NX*BcSRy?2}~UG+!p$-QFLsw|?X=K>Yd=>sa`H5!?EM`w4WZjpWbU@fkSc|3ddXiPxod6*H74w}2OqPcOzE0Csx?f0FrMeoO3U}r^! zI=suP^L_?qb+fdG&sCu=n;>?oYlKT=fb z0bYWH>d5F)_I(}+Rn_4e5{D`e_jzK4pV;CzGhZ$H!ohTWSuBf`#e`-XpZuo3)?q`{ zQZF8LxOQK6Uaxc=u3zljbTv}Q_+$^nTazhk^43kh?-W%u^H_x0;0(KrY0F%*RI-^U0FX~OiX1OI+cT6vBE^*S7d-lxmL9WEhOlrCM`zg%%)JZpUrq2GsJ^JUaA_&YqzX%pS>;^|}TRFzc zTi$KfGkE|(Z>eSK6fu#rE_S?SiUh&7K+583`kc%2I8zk6OT(Vehq9~|uu=OU9m1~8 zE&WV9WjTe@+HcW>wgD%60}aSBra?w|Jw_7piK>@xx3+A4y-2Un8P{$-fUfPY1@t!L zo-w@e@C-~z7$RYn64PK$l=ob@BHHTn2_3C@e=HYeo$J1j-PNIWXLUbHo|t8F+tP8( zJ4A9vknpmBa|}exch-$vHVVsj47<0yP!GbgcL?3RV{q8j0lNDKpkFEdhG1Fn%RmmiKY{ycApejGs9G&N9+a~_lUN?ec(PUU%sb=nay74LAq+f_W2%k zsvDp{a{S=C{U2<+ zA|BrTUX#G8e)SlrUuDk%V}kO8Di0OxS>%y)BZqZ7DJ`+{b1mx1etiDoy2QtJ&}>{ zYj~WWu!8LQe**d5al>8rzxLfGu?q1cfETOh@AE%N$L@#;HMx2YDsb&)@t&$+Ntyd9 zJ*`yl-!19;&<&buRi8Xml6&>6Qj{a>=7VO8NCn%fuccK6%}9qM41AZs4_-xSvup~x(3z9RTV+eZ9m$_A^sy)ah~NSb6M4{o^O>|gToh28c>{F zoSyMS+WXCWR7}P)ez}vzUvdj^T*gPgq}O&6FZje{T4&4`D=L!!(~ zmjihU4c@ch*;dqFr3zMZzYz^DQ0ExR6M{wvZ_-s=b}5H8wQ>Hk0HN2r-X71YAtcq= z=L9STCBqAsthR(fqLVT33#*og;XP2K|5EX>Hij>+T~CKuU%~yFnFKV(F&e-O&whcI z;V5#=HPDkk4Kd^9nC^p9;T8qwQBU2o7cwFEUfG&cDwn5vNGJk0H2D{ z@CEg|^luYH?rtkFug~j`(Y(j(ZC|nV*zDzvT$8jk9D|Jt0e^Mnzkr)%$DnVD(UK#g z=_m%1+iCY6vGg^Y>wlyj3mhcLCe<{EwS^=+y;dYLF}WshN%l3&ZudNZkIH7V{`Wo- zPl|D`AdmkDyT=Z|X0}?o1kOqUv%3%S!YoW)m-C(7k%q>=L$tp=*Djb(z57$ALrF0Y zsK>W-p5xJ-72ULTQ^*zE$F)(C4EW}&}mP2)a%`?w^`x-qtlFd{kW#A)4wIvrt+RIVCACS$SKAJ zuxU!B=OvGSwuCTn4exINauM#7wVn6)2Auf-W8d(##q~Bh*Xx&$F-Qc?F_8#JOAggm z>zdN;!;v9q$;-SoPCIT=Bp}(&f*S(2+Xi*7lh^v(9{$RWT#x0HJ!e2X+=BYYC+O=f zeweNJHJ{=nHjHc(r+=nv=F2$qzz^{RnJa9Gs&>!~K-%|f5-;c&_l7*1`kh1 zSEpb=Sn7c|zpxO$h{O}22hzf~JVO7?z&2zExn-dL=LSPhC%-^DpQpehM^F2wFm(?* b=cfiw?Hq%>zd!w_a0aNW=qQ&f+D86AD+6>Z diff --git a/DnsServerCore/www/css/images/ui-icons_777620_256x240.png b/DnsServerCore/www/css/images/ui-icons_777620_256x240.png deleted file mode 100644 index f8bf667754d29597de6786e81d746f55c7cb62f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4618 zcmeHL_cxqfw0_?iolz6LMlwN^K|~8ii_xQn2xjya8|zOXaO+!z4D;Q)Y(1AyPBQ@9lX2u1+F8U_GV zvH*a~Key5B>gi%^*NrT7LqmlBzx{6o94X~ur>fZonVVPuHhK}~|AYJcSJh=8a-PzF?@8OdZ*cwS}S}b2${T`icKRZ3wFgiKdF)}>n^v$0F>(BN) zP?F%}?+p7|*!|?oc*WM|)Wk|cSLxz|-qY{^pp&7V4v%voF^Bp~YW2Oh2|mCBL&WsiGxmq8A)vf2d6ROU$qN23S~ zc|rYn;fCYh(GBci|Kc z>W2xyhSrB!>e}R-O*&njfANs}=_bAJ1dD-9HO+9C=?c$f0^8ihGRSNMki(jm&tj02 z4?YAkqumrgbjDdB>9=&Amh6heii}3xeW2Ep$&=9$*hpstYUvX(L*P`*z0YosJbWG< z;yNThkG-z-0dJhoWt(bJCUu*x^TNp%@>qKWzM+p}nzRD_e}P`9~VmmYHv zGwQD$U$u*81tTDIN4#;S`!2F)%L1P$Uy@gq`qKA8Az>`8NdPr28Heyyp7wh+&)ZnU zwZ53CrZZ>Cl8%z5rIJD6A*`b+)5Vi5jCR|H^OG+BY13h>d*V~9HvO=pif`Kf&1V*v zv=w#9&rw{B#8%hNZJ&`rAYFQEVVKw9dG9*239+$hfUoC%(3oG6UooVmsx91%O#>oh zx;<)pg>caU0=fI)-pHp2raOm*l0$0ItF)rIKJD|%z%A8_oE`0shL`&VCs@5N6Z5=W zv(ill>c(+@g02DHpkH3L3Be`{xC_mF>R;}{i6GEdzAfK58~%eDV~-1ZjNz)>-|onc zm0h3aC+^rV8D&w^)oKX|pP*k#&SfLOeu56jE>sMT;v`4GTL@+Y%Wx&lJgue3w`_S=a`A=l8Q3tgDmt4lTLy9Iy z4&O#Pl;k|Zukm8u!fNe^r*QGy02ALE;dj-k_Xs%SGfk1>=Dg2Ye{J4;$Bra)eEguQ zR#eq!lU>H`kt?W`j9Ir?90siVSl4EQ0E}>PHuKw=6^rYa= z%pTAHH+T|hg!42PCM)_dsiQ_1t?pR2d4hiog0nVBVYssDlT5%${h3qg{UPdJY5$*s zn-D`0ndk^V)9&7}iu1@->>tV>UkG~uQcyqbnCc$F|IVEiK_~_-Crs|5O4pDAmxL4P z?%?~Qw(!dSmarH-9f2UoMV#6z5js$4;V|iNp*BLsj_M1;{A>22_Qgf#FYsPT;mH>! zOF5g6{B`(Ty;h`f&wTUMR;Y5+HM(Gtu(`S=Mw04FDkC}&V?(qf{S?7VZ7#BRe1}Vc z!;q?D_Rklb@}DiY3^8)4TiE z)=LdF>Yq(la6Tka&4LfpdP_cQW}>5QA$-mQ-eEI&w;JFC?>?=g^rz z)7t$#%YRh6#&%_i&aYYn(wS>0y^4OX(T%FP%5IP-8T8$H&FrRro?gE)*x$F$ zPQYhZdf!C4*Q+@|C{)pP)n$K-89_I+(phx1e}agMLB1kv{MK+g+oKxoK58a=!nWihoG zzTMsw9upjG`*C5h%l1a?Y=5XNJu8)0%5{mUCuvA{gU|?UG!(4qMAbLOt!=(hYL!f+ zT*aBbqb#gG4LHcb9#&sK?wt$=s#^s0)0hROWf*UBXy8ola!l;O5b9x?v*qlnZXgWuE4u8I0=TX4->@faD0qwWBN574g zKNSpd(LgCOT#Sw)eZ6MY^l8y&$sbv2evluvx7J*0eAWx$l&tq0dNiJ{=3-A(Iv7=R1Mc#|6}U;W60X9=i+}6YFNxu$1Y#Ml}nt6H>8$9r930 z^t#ElmoS#%q5=u?4R3cZbsDxUqw7eDD_@Z*O6h^)4&&bYu`LhmQkT(>FakSY-&q@qeQc~T9 z-)&$OZQtg`bifpHVa_$@rP#xrd7>%t@zDj z{xcg=YVMD@uiKK>aZSu&Nyp2uMmW zQ!q3^L#ruA6M;?v6`%$u?R0uSi}nQ9hOF=U$8cY#7I^7ck=^9E`{!WscLH}}AXAo` zySux8JP*FE&3Kktur%rBv>3k0bQS^D zdXFanG1X0bDSR5lD!niKj`=lBs1ej*lfD`@EelOL*K77V6Q2ESuVOor7;9-{YTJnZd?fVEegGaitcYURX9%#J97G5xJ@ zJZ%w^VX!GWysuSfs`N}tf<)n4T5nSWmNVbPAbg4$M$#KnZvXOw|vT3c`-Y9?U*q{r!zZ}lx3t<>s0!=J(bwsl0Ft-^(w! z=c_f5G<{0}N~YGA*5SApvAa(j`C^^?7`a1OC1Ln*kAmU(4EWsHUdsbU;%ajj&hfQ^ z%8J^^f<O^-zLsa5 zJvHy68Sx|Lf_8(}6=4ug4F|1kCzrRkQDhIASRl8b9^ZEE1rtJXky#6vVKSl@E7VxK zmMJ7ZwX6b#W8A)qm%S75-9Di$(*^vEn=lJ&^g+Li~b3TXmRcfjb_6TqLBX{ z6rbZyl&eU|yRDEY3jfA*xO5v7hi1n0PM3uRsx#Uqhp%+B{#M4UBo|!f81UhkR$_p@ABNw6^q% zYYIHYcXLMmESv70?d8IUO#W1+6Kmy_n(%8uv#_JsgYl2|M+~tic?M7Q(vBaqU$@0| zh_@_w+1cL>Y=k{-TRFpA$P9TqEu00-&C6YIY<-seMMV7e zfrec&?C@TbI+yi!@!`MH&)^4W<6Ih(N=m0{T3Q0=b`No>Ms;6$V#I$81X?SSus*3Uwk&&Q zYcb7A$YV)3zU2|Q`B6y52kvi=S4pVgzedIe$sjaC^l$k;ckXJDK!V{DJ(leg=!b2E z^S}{Rx=a~dP&)W>Z&qZ*zSSU>gA++^HvgT&dEM7f2F(olR-mx}LLgKSh!8~i z(ElO$__=txg#oh4N(xf42r0QMmIx&k*;5YUKf<|B7PO}Xp1(U-__+mzItI7`nl64$ huEP30j_$7Ju8uBY|Ma+?e$W7bzOISRTP;k?{{Ur9Q+oga diff --git a/DnsServerCore/www/css/images/ui-icons_777777_256x240.png b/DnsServerCore/www/css/images/ui-icons_777777_256x240.png deleted file mode 100644 index 0102da324d3ee0dbb34d27f76e64b650e6434d9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7111 zcmZvBby!qi*Y+7wKvH1n20>zmkd*E&DUlKoq`SLAN>D&zMo>U%C}|l40SN)=knZjw z2R?q^^IYHeKJWYfbM{&1oOSJe?zQ$_YuzheM@yLyp9UWQ076w21w8-&-QNO-53ug9 ziuoQg_XC!ltfnjgRHqQ!SYhAGOx7xTng9^M0RUl90C08xC~Ok|yrBTFZ3zJ4SpWcb z%Wc+ucK-t7mAbM5;A^wnQ*kfhdZ}tE;;vy35h{;G}|Q@wc0f~>r7wM&)v8H)RC200~N?^>)Clitx6=>8FqV9j14e%;k% z9l@jGkcnZf`!r>j?5PgLeq3C%yL#938TBz49ozmkBY$P+=Q#Gqp}9uqVrcP=zY^zz zlIXl<&ml?VzSJE0`fTO&U=m4GbYw3uNaKa`42J*$5XOQ5YG=8b$ibhlI|#z!gt^<* z(iPy77|;vUC`UP+C-zjV7S_8AT#If7IZD72m#Qd~V`?TvDuhb8@wiLXyvN6h$VRFg-jSP$X+F@}kMEdV`` z%FOwl%-%(@NI1*DVZ7d2`^R75-~J-!;U<0cA+Ob!a!2@`21boE(R`!%9Z!mGx!vN* zXfe7nlw;5a0bzfXa^CB{LeQH7G(yyy+V@4he zS7XZEG;n)j5?Lfoew4u0?5UTj6F3mi-yhI!=n-LkJF3;Dj8P*Qw*8{JR38E-vUY{> zp@1UP#s`t_7g2_ekpkK?WF-X;9co`WS$8@STaxja-lbqOsvihZw{E^`DZDY2}sZmjI*79mM+&gLh(Q1?OMLaIzzZKSpks zG6fERGF~!Z$U(QS%x*BFC^&6(Efl*@_Vew~UgbZ}}QYm9nAdd|ZYR&fz74>~=< zjK%lhlC#%AHLgOS!>b1#Ln@po8ffM)kIW}_;VGKxj8OLnZoF-SFM7;XWr@WvhD+k> zk_x;%NQ$a4*$sl4x4BeLMmCs*hJU}Y`ywcU$)5?z$is>us_3EYQxq@z<}R|1L-aL= zYW1DVI1TivY-Zh_w+=khpKzdAG*idnV-rE0dX*TVDR^f>arQ;(-WFf_uhOc-#yq|? zxCZg!g!e?w8cy1;hHzr(QU+kkyWGCFS>OIVYxzYm9>3_BS zJ&36yu^fYXxVSCShanwba9#=(j4w~4lv<>|kPCoRgq4~a0}+Ox@ABX3oWy*~KzyoT&I>L=^f zy9U)Pcfz-wH6c#J?;B#88uc5Te@r-&c-MZe-jK;mo{Mgg+;Ab<8mEb5ag3y!tFLZ# zK2@Ysn%U(kYcd@ zclYjypZXYDw45Vo_oRS}u-e|I7D7R=i(&udhr?jF0y1|!XR75RL*U8>^*$ny%lh+A z%`HQ+;*uHa3v-#pS9R~ zIMF5YMT*IWK=xJr?tDmMV$$-&FNfmL7Cxa!RcpIMdi&0JU+)>M(e*#W@!RGjn&AON za6xhCPFc;TPYHkI#yoak>jyC6FjqFW!GD^Kdm0Qi95^wk*nYJ0^ZVjV1HMtEX zW%ngxieMzMVdFyjr9{uR7g;?aPYsh$0N+eVOW*@R0aM_cYIM_ft*pv{856}Zn(q^zs-k!GeUTMV7kk4~FbapUe`uirV?NHWestKD;q zVZZ-&lJy+o$v7HQs^)~Z0*zZWnon|u<4Xzt6tr+5UPYoJp+cM+eDj(Vg1W5IW@OB7 zs5=e3O<-10S^xsm1Q;kATOZ&5Y|yazM3G4YtTrBaUQijzLilI=r*>tjm;pEtc1+Vx zs=xu%w4AdD1UC-a2FQ@qhH75&cuq2Sqa8Jj@>FVfOrwIP@67q&2(OsR~v{$1@gPtg`RN{g+$sO)qia1NR=^ zC7$zaHcf-$N+PCk3fg*0g z+F;c?f$n8wKaSbhJTqBXr+b&PTcd|s$_pX1aMUwq6M_ueWuB9*vsM9=6Yo*u+v3I# z-V;q9iZfWCj=#~jS4)`l=!`&_Os2P@` z>T$+~+}t@Tq%TK(IDN=j%KS~KN7<1I043<6l{`pOrInLus7hV`dyfnk2J_0+S#v?0 z#mbYV1|A@d!&2bOT0>m)fGP{Lr*$GS++}69@l*oV$v;7DhkJ-GHPEO8Xn_vjB}lxL zd&j=lp3M>iC6F=yiTR5%f^5R~1oY||UhZm7&`c`2`XUe^{8Lzd*ET-`iz$Uw?vq@y zN-#yctcs##a%2+&bD2!AqRUG4=@pGFgO3|22qLt440$NzNo;S}gPZWYFW$K07P%g| zyywJT<*2&ICe0U>R(rT?oC$ui>(6pi%8XWRdmVJUV$-+H`pldpOam(+FEq+ z=dD=Y5@XXNKZs!8MR9m>^bX5YEkech8Fw%=9Z7OiR)`SG4LWLIVKnY zn}b->el2XRs@dhN{vhlqj$1qB#r?n?Gt5c~ibr>@GQFboYdXB{Rh#oOi-KE*LiAIh zRNu}+l7He!jLf zMvjcz;}3+&o~MNg8woSV=wLWz&<{Q7yuVj+)U8stg4XfuAKo!8J6b04dA7H92!}?B zbaCsX96x~As(l>{{`kF}-@MO2%$BzidCk!rEOtZJ(Cu3|=AyfKo%{ufqFip-UMZw# zi*6fEhk~luzP5nG=`17opt2%&ZCZ(ZZf|$Q`pk9qVHZ*oVRlVpIxXr)uSNu58&bLe z3rcyWuHZq`ZvS36S73l&9qdrQHCy}WHN&fvqKMaGzpRSz#UC%OCi@tsfe;_24`f>k^mNiOI6fr~mt_HrN<9=wsp~ANbge zZz*s_=g*6)w`s}c`k8Jqk6w6dj$CoPAH(}P;YGVTHbIG8cf(yg4?pqa26!g~Kz?#B zG+}nhkLw)t=_jhhJlmpUr#kH}CEMC}D7tNH2Rx&`wpB5j_aP5+Zg7!5MEqOiz8o_! z@qf_cP37=vms#k}>OQnpeH9eKi|h;+Lfa?qvh4TQO&$)l8eX8;qgDGQ!t>f0umZ~z zfJzSjqPR9s|)AYg$YVY2yJ#g);kv}W!RKx&2>H53CdaM@2 z$KcQdKXm}5=>}6=%UoJp`P#Vf+L5jf*$%rV78 z=v<|@oa6Xm(*^oYMixt|5469;FyGbEn4W{rUpV6rz4c~rGrs{Zy_VAYRqZN)-RneFqYMfL0CdR9?;9 zXO`&1W!E#*Sn-8o2uAME9oLq{no^OUZs{mwLED@jVG&beC~23i?MqSmahQe}-;lhE zfsgD5_kD=Cje=nwqE}-?v7SB5wG?@LX|q+(#K>ixP_g@2Pa&XQb?L=V-Ky%u7FAzg-qtHkmvem+kpeHU*~eK~+34TKC% z?=A{6B)QmmhNW(Zic~fe`WQklJE%H-FZP~d>8c|>76!5I-@@&|k83Tu+TYw7UwDh0 zQ|DKbRsDLZB;=Q?+uWX=s~ zG9aq`p`{4U5sNcyNvIb~C-Mk=UAm1&z<*NXNQ!q|7;dR7+y~13G0XA@s}D811oG(# zRYY}SJobO!mtkL|`;!K?Mv&Xnq~=*JmKd2t&=?lj6lM{Bms4%(4#~!R8Q(0sx9sFo zooLqnTQ$zAIfAIFICwOCPL6eDB2$fVs}%BtM%FXtza05KBYFJp%K_(KnD z?&unL2hVy->p#dvcp=-< zBEU7$mQupKIV&)a-~p>>bi{5Agt1_ASbGcEUKXjiyMzcMc6@O}w&Cu}W5}C)@-ZSV zUI#DCp3)B7qZtkkiz)PP28i+g9WRy50U}3q^g`F#W3GIYj_;Sq(r$)Yg9}(AZZ$-Z za7Av6OIFvrG{mD5qzk-g$9hC=kc80fHkg}Z2ptoZzLm15Gk?fh zC0U^xDFSA*Q=%0h-K^0Xz>A~14~JzBX5&Bg$kg)k_^W~alw`L)FX-N-S~S4MUiSND zX2;DzN;YE~;~)L~$*hSF_dJ!VQNe;gO1Yaew)6Jy(!F>i0K0tR70$?Yv%!|vmW-}! zggxCC(OElq$j8A`+x|w&ljh2cXBCBAe;EDTk_F9Mgz=M z1L)TGsX@{>c0%9 zJnX?kaHGew5}_^W*rpF?C0B)fdtNl_e-t)9V@qXLWCMyb$asA`x$8W~3{YIlUZR$C zNKF)0ePd^M8aV*wIc(X=xpQx`f5vZ}@yGZ+ol^C4w)}t9$Nw++jyH{4FJ1X@NrdAt zNNTKfL1+6aak5Kz`OpywCDZ8S@po4Jvil$(kM<{64mKU5BSphjtP?_BQ=DS?eo5GcqnKqaE*@s~hp9=d1OZLV{O-P>;043VFRd@i&HFes1xoJdFmcOyyFkYBc zTdoqsxV$(fVQUi2$8Jk~a%#7I8~k88Gn%dICbKgEmf|6n)?ZSnve zkI_l&`IwP8r!1q`MKz9Aeixe{SDuLVrH5ovul=0H+`Gf=#h6Y6mhgXP{?fp}=)7qP zX;h=wsUYz3mxPe1JgemFMjfrPWIYoZ$o`M!T#C7tQST}>rPv_trZ^Az21SjsXMTH% zi@=^uxJXrBxrB&!!!a@J?nh0;Q^_F@f}RyhtU`TV9ct#TJk_r)(wGK zF#ODat9z%o>0R5VNT*c51j|8VP;u+NUkxu%4-nW7P-em0Vp_uhWu>sV+R*V@iW!p7-JD}4mIH`_ggxgGBePg7gxjJ zp(_VUUF+kWIIhIQZWq%Y|KZ^RpsGAvoy@lOOueg2@{QZGocV)e!jI;py{7HO1RHB1 zO5((DzPa_+l?$gKnXbd9eWKUifbY=+#u~o)Kc{-j8xozLuRf%oxxhcg#c5k!Wmm|ddfs~DdS&=zS znwFv3ZdzzItY?rLNXqaGYt|oHoE_RQ$vae|@Y88boSEN2Q7OavsPm8q#u)Q*XUy;r zFk;ApKia{pktpzeOlC`;qySGzQASXEv#} zIJZ1*J3HnOD&(}^9nfrR1l*&p=~IXh2UP_Ox0ih~5i1GYr2YXC747xHA@*^u>e4Vd z>E+oz*M1~d$h^OSi8zz@?LWxW5mj|lw6Z9hP-vmPs)uGR@X;w=kKFkCGRxE86MOTypRzJz7kktN&+G+<^(LVRfP;h@hg-A`Ho6VK`j&gj&l=5zv zky9TUxx*MScv8JIqsU1Z1`U+A;GLYO~% zgt``!(PlEms;KHqsBy+_ci7h_a@n7KggOu$F+$V9jZ(4O$1r!*P11w<@O}g>X&tF# z)~B{T@y-4x?q47)>>;2ki+m!_JVft38kJJ9;)92xU5lHvPC7Q2_Cv6qdNm#w(9 zhwc3U2tWn+d7=Eg0s_yWPsO49;(}t_P^dT*>I1D9{SO6aSDQDl{Q-V4(WkupP+kGy z=TK2`{(BwhzZ6&o^l|SMsQ;Nk-}SYZua$=_AZz3L%9csh*~-pV&(_Mu-@VuNpY9r< Ns;H${AYJcUJk))X?(Arc^YFgl^EtW5>eveMJpPL~zj7<%7jE;;ueeXVHtZRlr)t?~dQc^+S!sL?hB=D9&G5jh(mf9LTFw#rU_R zu#=MnCL&{k%C!#j0uR2Iw|n%kz~&;@1V!FVJO!I@w9Az7L=^=QKoh1Q4YpF~-H@(= znXFFHI1D>-%K2^S2$c|sIg2fX1VkSGz`->nQ#n$<>~XK|GRQ(!R+}K1N<69HSR|ey zFK7TK+;E&fC3|t!h>!XMW>z~ay5aua3Pc@X3XQJ=RK&`X)F2a+1fvcMWtq15F0A}P z{Rke|(EK<@U7MVZ*fQ(oh>fPuSiG>eJ+PUK6nM++%2hRlfaAs>>jXCgy)=&!TBk7EU6fZgaaXJ>ei^ z)axE!vx{d1!y$A>ym6-cE;47!0-q{fmQ#`Z()Ut6VLYx$05u^IhwxRJ@q0bb+gQZ4 zzL=@1O*CamM@i9ANuzKO)-mOo;;9x!yY0jIDVP7W=`hwg@hMiFdDKzGH)H?yGYd@0 zin`?I7`8@yt83@B&*%`4F158V!t3y&cb(aU(AYG{*YhA~+%L(m7}8SJ7G}n#4v{w9 z9<#lQzvuvg-1~Tcv_G8b?xCT?uxj)wt!S=K`}{I+OXVVGN4ulpl>xy?R_`l>JTKR* zbd$ll3GAOBUBDak%gZ*w+hhUvpt;Zd%Uw7Tc>2nBofd>9UCU2ENZ%1O(9_{Q_T4cnBglPe%sb1-ovLG<^HVoCR>7)Kwjwd4mcI520!-~ zP9ycxc*Q%G-EXQg<*t%!;vUBOPO7Z29ML6H%G@zyW46*4d58OnXC`}-qvlIhup68T z5nWzBLpwot38Qr`KtUzqwW+iSM*4#^xcLL$cYbgmIL5mWqdcRV1nfE zZKOj<%p?37FXk<*){c4#7ZV4W_}&V?uTH&>#~Pn$ikL9xeZl%`^X7YYB);R*M-|ng z;vOo_7ukdRw}z51q`fTGPo~&Z*7;+{ftAXY^lLKgi4IyhSj`<4%HbRDMAAF--@tW{ zb;COSTsZ5X;eA#kd=&ZLDV}14#(t+Tw5Pv3tGRiR^%*D2ha$I0Rmfit%;oQ&q1JK> zf2QdQDz{cjMax0DhJ3Jk(n0r{N9Ga-m>{@wZHey1iDYAp9hFVyoRWsv6EX0>!p2D< zNWv38Vbe(9n^*Rhl_jQARtQB3JU-BInzIa8v&B4s*$p>qS z536~jPGHNQ1~#smct)+c+D=Qi%eU~sVZ&?s%ungRbG!j#s5ycv%B_l+`+ekVHEhk! zcv5S2_X`6uK(F@2#!mvVz|GwjZIXeOGx(0YS)yo9q=Nr!xkrlt`<8}IsNxA!i2#VF ziN;y#(ViEfhrjj0=^sSL^g%ETD_T}|DIk{Dqxt}M?HI|iwRsQUDnnO)Z(nLk@MmTZ zXn-9$i7>)?nhTQ^e3;Zwql{K}t=l}oKL){Bo1{=|S@lUKV5Rolsr11xb+45FPr*%y zp@?*JxSwfv?|8*|T3}?P-x*W>2RSoT-uK63&Z>y_M-O1MdvT@UJ2o;mnKU& zn~?lg%SR|BKx5P+Nc|~PJ2V!gpcBG#oILXaL_KxpxNpJ*G zb4--ZrRa_%rQt^rK`tvkWNn1q z*vQTaL}a%FL#-7NE0X@?Bj5tg1;?7Bl__Zuv_7Zq1InR0kuOd#0|A zsrOxh$}Q>SeYZHX-VGnTW2-k{pi_{dUSj_%9t^F5-1L-H&9Q5U@$MTXd&pl(mwQ&b zzi0W6O4saf`Gy>)Pf#a)ksB>5XexLuBIE>o zezo^)gnPZJ1B5~qm08h>q0S(gy6}g0Puxwjn5)b1c2}zz->+o*s)&efzW*J^9`c+g zM}P|?U&2aYSSSoE!Le^C9=%ex!6=TGiLE5Dd}k-Hs{@jpL@n`XLTeA}mFl&4%Y3dd zW7l(vAe+_o9$F-WByqusJ+Un6Y0`K~O<^)U>Q!#A*Y_xb`!?CM+PQsYF+V(^`%?3I zE4z>qoyTkZhzIL?p=ihCZAA71Em4Q_R4#FjucPpy?dO4>mr((CLiW+CLe1 z_NK6y;Aq=V3yWR0H)`hw?%2|^QhB9Z7oUEbhJ-f=jl#z6fHj?{`o_4m&9{oJ5{Z;+ zSkw2Eh1F*P2RTuP)fbR^CnJGs7C{3vW`SuL#@ig~Sd)7klY20PTBruOuuj9wXKkow z=>cKmwW^Q}Jx#zr)Mi0+TQH$Z|5kOztc4`crQSA~z8$-h(4Je2Rx98vUTD`-gW>XF zOMBfi2lCzWpRG}AbQBDYTV5ACHtbg4oKCoCN~FAizgVyHDByd37=NRH_8al>Z)2tY zf?+NiC`Fo!(NUzY*Q}a8E&43^6HCnx^5gc_n#+yPdm)?>^`66zC(>12>}e~MQ-TEK zc-B`s+r%|!t$Sr0+8FzMC(-)YfSNBn2K(FNR{&!|-JEI^Wu~rC)dK8 zZle1N#!_5VAa1_l?e3*U!?tBqK041}{UDeNywdc2Ep4~TP~@R)M%9?Q{En6<3BR!_ z?K;HNP>K-YlkMN>3%;HXS`x(;m7*mvYF&RucRt9Sb?}0`r9h0M%|3ZnVz`o$>Nfmt z1FLBJHaDgNrjQFn*PK_E9_`E%ObJhpc2LJxdU^>3{)rM;?TW#?4Rw{+r?mvGlHd=Y z*^rXNKjyw}OJ2t{F^44`uR2(Z?B zA_0i0ZrV%XQzumEec^Y^uW3S!q7Iw%Rio0f(4=#{W^Xd#+0Tdip2PTNjFI0^sRMF z=K3UlOx|{KT=Sc1#G|-uTI;qq%AYtk=s+GUhjIBr7>1TW6N}tMsTq@5k&lp&%U$upH2K>qo+)RDV{jm+$pCasTX_Ryn8r&bqY~1 z`QY!ZJ~7cy7gYOI1_HO?b=SzH{-=Ky`dtTl&Q{ zd7k2XIir7;O?S`sa^XUzek##jYUP!j^lL%0u%p<6aZmO~4Wmx-44&zw9Y0~eZj0>@ zYgzEJv*E!%WdqTc9>z^?t||BT-XlUbLZ7s)oMA3xhP;~*&VuIVXV+RL+t@&S4H+4TGvo}ZzROC&nw|S%-EImWVO$v$(jM<@~yG9jS zH=6fzuW&0QE^!%&L`7;MD^*_~26ww>P;x{u(Jiq9n%IpG4>j9YT`j0KM#Ha~jct)OUTxW3#N`;8yX{|`Y`lQ0xvh3Nd z#WX7+k0s&wmdE7g#~~RXxxYPGC82`<8W|fTgF6|bf6M>5bJvOl5)7Z}v233}KW@vP z2ac%HrOR+z9KtK=s{9Hi73Zl^jOb#PKVNtn6{QfO%~=1-nPA+?_&0M-ahtbi^cPhO zURZ?G@>O2sM98BbrHw21W<^%)TMb2Va3aag=D%||ulxE*qnRP!Y7{Kcv0A}8D;unH+Y=T@IgItxJ16)rBKo%h@BZ-ial$Eta$SWgcl;xBzBM{06L{er`c`90Obd4HrKr hS7Ci0M|W3qS4Wr7e|lU`KWG3zU&loIohByce*m=vJN^Iw diff --git a/DnsServerCore/www/css/images/ui-icons_ffffff_256x240.png b/DnsServerCore/www/css/images/ui-icons_ffffff_256x240.png deleted file mode 100644 index 49083c89a1359f432a6bb3ebe791196b3cec6d1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6487 zcmZu$XH-*R(!L3y1f(lPkfwlufdJBx-m4%8B9RUv(nA$ODAELJ0@8c$9YG*UFVYb~ zA(0w-mnwd^yWcsxd-l(rJNKTs@64U&%*^||5f61#$w_aL0sug+uBN090HCW|V3!1P zbyd!Ele-cSJ9%w+0H}!}yRaa<(%G!k^tA!NmkR*UApmf8^$3jz01r3-teXRX40T*-#7K2*W#VNpIl0J+3lVD9DXOOv7!Nn|U6koj3Pt$H#7EXy`m$!fxKnR!1S6gt1ixfes(zpkZ@S0{7w3ql_NxjWlrphomvM z`Z^6Ekv4kFO!n5Kf2Hz%NUt3Fn7C8$gPVu99}##BZ%aDmJuEmayPNaOmzDH$ zoL55a`O0SLKTOi@QVnlR7ZH~P5S||bPMq#ADmh9V)4D9ddX=EqUKMd!5o)`M^qJ_hcWh$P_)=)X=yxrdy0PC6NEQ$hIDacdXygotfqqCd zyEUECI!0snco7I^n`ggntzUB!3rOUuOrCYti2RN)P0su!2L^fey#zdD&{e(d&uClE zDY2)(Er*%)`E2kG=t8l`miByfkmc%Q_%(L|=r2ZdDvQJD38W0Bc(9|Jy(O4H^*)5~ zAKpQ!#5q9Ve{+3tTaVs+Q%+6Adz<-a@L|n`mzbu^I~4{SXy20{19gu9ypBXr>R=NP z)TdBMngW`6^5sQ*Y4Ixxqti!I++R(9EET8CRuRe6@aE5PD!UlU?iHgY{1?XLWDMbE zIWlcw6%-NsPqvspbj^W(-JFFgy`4mFa3l=~%!B>PbcrHb&|bBjxHI72HMcC(!NQaX_XTT-tuW~G49}>^&tE(ynR6Rgx)E#by**3;N^nPLvQ(C z-t6oXXT1WaruqNM;?;jr0wd)Zj`p7?SGY9q+JjhQp0^#TetN#xR6f*1cyj0y_13Gj)B|t)6w?mZ;kOx}tMK{JjqJA9_s=qRBAkRZ>5{#- z3@@XRpgFCtz&_i$g4yU-ov)6U>r5)=df76+e>`nIFUAN^>VPBc++iu3L&$NP)D%7gFYt;0JS71&o_3Xnb*Ki|2nO&HAs@J-M1 z;bk>+X&$;3wC-I_!%ivV6))qsS`}RTG7;FKX*b+E|N3n1(?RogM$-Cx&?aTzuX;D03BHPjwck2R zvmBo*ySPfq?kkIc&!pu~CaU;Ber}cTRMRQhI09Tv{mkT)?uHlQFx3BzzTh5FrpF}* zAk%7}A^+0(e)5M_kt+pt6*@P2TlhTTt#f_0dmlmP{iOu)Nljc_<4qOkuJ#edJ9%r!Lot&X-j$Cahs!BNT!^jfcW0dr1 z?I`^ya&PLraT5O^(j&g{!L`2c)5!+n0~yIu9j|N-jB__Z`cmFAA&rJ7>E(wib`nNv zX_~*2O!X7sg&oyM~1uit|gT)QR96juj;6p zwbUlkzqKbd=)X%*6f0|jd-#}D+Msl z9<3SbYo=+po6Qr`{C-tp8}nL}qPd4X`!<*+Z_3ej@mN5SA|-HLo82@ji%f$;n!fv- z!2&rB=a3W}^lquF^66)intm-(er}c1kDh_SBTm0mT|oH{RF~=^P7tTd`zIeoIlyua zdH^&JK=njB0{D1Vp8PU^W=kcW#BP=4@zy~^SB7BjKH*6RTp{zuQxxm{AzkV(qo4E* z+TOaRQNr&XsWQNwAmQIEqp}3pEH(cPs^8Qhc)Fy}?T7oa=*M&vQ7xqekU+UNDel(6 zbPlaI_(hPlREPv-k-5mV*5S#yREeUWKwx1+_;bl~8$M9L+Y&8F8}YCw+Zs^GGRQe2 zDQr19Ak%k}FFd=nM%sx>?ZcUWcS~)bQha;v=XT{bU)t6sHz-28Q^eyyjru4yEZ#IbzsRs?vA0qK6-4)ssl< zfK1l?p5~GGGs7RTB-snsl#KQn10#8KK!k+0t{S<)-_R?eA1SNou>ldVPSi(M=yt=q z{bQKW)b0MkQ~HP8TKrRYlgj>#?5QsN9A|1?@54#97j?(I*`-YphT-0-fKysB1tqnOBtHF8~;>6*8iXeFTUH5B7*d&6x?LOZ`flDFYJyU!}&$ zpjps9fH3|ibc-(ASAT z^SRuQ08F6PUa~9TEWFP@-@}0(#NRvvq)-g30_`PubMUI*Yev8;5FY#rMyp}#8fiEl zvTLV6#@}ptL7|AI6(_){rw?Z4(ZMrFFQC~9tH*7__p^p&xEWK*h}9A^^>L22cjgn9 zOa-dVPM17-2+6}MXVo>=I z22Z|oS}?Hqa*6`}&B9zpjaOE?0AHKuNHG=q!N~_}{3?sVlKk}IK;B$eT2f{k$B)jU zLt%@jqQwY7;_Rkt!6Og4pBENt{ft5$-5w?;VUg;mr_v+%kI5(F^)z8XD7`hfUfu;Z zBpOVrsxpzIO#dVQ?GuX=$uf2NM2nqV4l}(az9F9?$mt~260pmudVV-sHs=&pXRgZX zfB42sA+0{5SQDW!eLP?hY?8wGlS6xg!-42S5+lcBd@4uNtJbVp%=I8lRjCTr{VirzOo|KL1>Grf~t15A?2epHT4+GVPmByU*;Bf zc-31+yT@=#9=Xqh9DbYT7yB-`9sQTXOiaa^Ymj%9>;V&lMhH?a@Ne!wCtCb1As9Ss z_|62KMEQQ_WNs&s&-{h|x{=c-X1;PiWzDwFnE`R(XOsM}h+HXgFa2SQ#;+={1vi~} z_Y>|DQBjv$X~vyi-xv@>7P6V2q!gcejio zCPqvJdyUtqOQy8W%XjNwsPRP-;DQuAcj5@hG0{If1g7gHJf?Y%0ZU@Lb#5(&m(GF$)e0JtPPJ=4*I=5HK`Gu;gaEyuy+#kf_r}co?Ezgf}e3CUedtr_f33 z^d8lf72$1_M$-bQAl{iWT2-UMGiEoA2J05IAZo|l_IAgbhL<87XHA3xB3WLLSa}oC%|~r8s`)FTNmJD7xn`#*u@27!zT^joz**%SAQ#dV+WN zi`JM9*=MsU#{x#Vub&E5ARiGVCa;GH_VGGBUFKS=*pz>mc+Asr>^#W{FtcNC7jH3U z8CClX{3;*E{J5KqFv#EzPeJosj_S2=xrtBiEV_;GV4{I%*-|sXSkk#1dIoTMQG4ds z<3p#{10y*X!o`l`wTR!mgtj6j4kk?q9qWKZO$G%VSN)%|O4o zPZQ)rwA6;91lBRX(XpwhOnu7U)2oJh2LAT}`L;AT-^t2JYl5#wh4rA%PVCjY>bcC) z*MdKhf-0GwQO1a#sFsqn5K-z1JM46H-trseTT^lSS=3{Ul8UT3F;rvR_3!LA(nnBR zbPB#pcl<-cGmBOu@WM!aO*0b(35T$c@GLb%c-0_6@bL9Td4_5wjtDl+(Po!})@tC$W$X3*8q95RxA*!2F8oU8qjaR`;KH7B~1 zFnhB#MJ()lG(t;HysV3ase9@mQ!gU#j-1or!bn_M+r^}N^K(7wv1hZot@dJDMQ!B@ zbWo*9KEJcZjW^tAA4=-n`WQT&V>vA_evdQ*u&?BMt(|lm<2+V#&)RK|5w`=BFH%)5 zCe9wy{C>48rAKX$FLP$~*^3%xN(?ZA0aH7_eMf00Smz(yIe^|-430V^)j8NVYC^2>3 zBp=TL&v%`cB@?}~PoybvMkx#d*VqvCzF>@0YWl-*jSjySpq&8s$A$jaVnXvf7CJ2b zF2RokkvSq3x6NkCBGUj?xf?uQq4q=cSUU#N3o;5iES5)tLe5aO2xEUyxVs^+SG&B) z{As*G@RAb%rnb*aJPUe*O?XTD?D5jRU(SZNPD(?f)6XoOqztRZ1MYN4HHhtq z%zAvE?y3>&5?lz=)dYsU=WqP+JOk^7kRIq(duN{PX7_&Noe_#Yu1vO#db1a%o>~?F zQjM*icBahg%(;hOCth*AWd^uFG3>TsY&h^Gi`i$VADueAsU9z@YlvUD(7oEtn+cGj z5bPa)gJ+`%>d5ADq341JLILi??;d;B_?tv;&+p>smffvBsOD!bUfZZw;M+vL@k)}+=zfFGG# z89!LoRi)q2OWTiNY;CC5Je2mhSD^$+9SFLamlzEm|FbTNd}>Y{4myM&3d#;cTVL|aM`D?a~3dh`*tk>c%aYDi^&4~ zR$;5iw3MpkBHF~U|o+pUfC-n5hN{NGANGlZqqrSxaGFih` z_1}x51TRTfv3EA3*!Z$P6861l9-zVTCghY6!wGAM7bapZ88OCF5~fhO%;)rOpsP>OIz>P&|4}%fY+`xiaN#y zTZLn-a31>BUwqD=EvWoAN4a9~D^BO1Y{&oa=+KcY#f?ZNg*$*nryzAOyx2$~igeoL z3-8X)nc49zXt#!Hy+ut=#5`aaU*y2#jvrH5Az2>_L@8-h*(UQ5bJWa1~^=}61D3h=^Kndv} zw)T36f=?y076e}8MVnn3`9-Qx(5x}6k=37}tUTVX8qMd; zT*k7~@aPK}UnJ;-&6{OvE^An$j?y0`wp;=IGdD=WUbQyU5~?VC<4fKT)M@9tUUQNU z`VmgFB!|lD)OgX9d7U<$ULKEu#^{uNsi{UhyrK3_SOej#QdmSSgFSB9IbmPbYUuMj(}dZfsN}q zFN=Kro6cloQGc#R{ug9_V?ul)N_WOr&g5vi@Svhw|}Q< z-a%a2D6>oaSe&o#i@iU-B!4Qic@}N*jQ&YxRb1qB{+{Kd4-RP`EC$069eRTfVTX(N zUBwYf4!mBD_a$DQR&R*C@ClBc2ea@=LiQ3XVg#{D#rw+(Q?-LVhY_4@d;ub17WrON zSVPpSvmFhAZjpkf{%-xXnyut}tE3$5x_(fM-dZ1S|5$xz*eps<#Q*aW zp(e`jOo$$Vq5yXDYku$Njr>et7~(JlyGmUQs9r3c`Zs-KEpyXH8GXqbA&@e29l(TrcG-lR&-o9<_)mf6VXj;U|SGwoTuSDSEh zUFP-0Ix7{CKN+6DoAk&T^rh9?{q&G|-Q#EDh2t{c4c&$%9zvxf%1t_)FRL66ea=Ag zT`xuf9=E-MN1R_7BqWxL<1TsAGRv~cE-g>X3X`1$rj}2&<&wo%2urGkPN4A#s>Bm-}Yy7E+loG zucvg#ADB!Q?oS-rvIisxT3-8CeuTTA?18s^3I3b4xGE_WV~qJyw``(XrE`g_opIKC zj?vL`1}uV}qgSCBG_4Hf%p|7WA7)nw(g2dd)77?#x|Z5_Vr296yE+jIaw7h}sfmgq z?;+)+>0SAT?V;*?@+7~YwE3r9*3Dc7N(Lb)viIe2Z_;No73(&pm9xVmsWRmAP?0ft zXlk~<9{q2c^m{Up@to==#2S3RsgAmZ4H@=qnpD|c^t9zR zqz_^|aH&EzJ#}kJR_^2%5c2ky5&2N*9l8?VFZYM0ShGMxU>}uHnxvYpXHTJMo8_vT zwr!Tn>#{Er1$yn!f$}YPrDn2N!X;-}S*tWJHcXIs*RBhTcb#sR3^yyt^LuFdN$TEP znSITUxi%@jJk`;aB;S6vD2y@3%@CXrxl`g28V9DFBk2_jvP-kq%2-mVFm&Qay=fQ> zbo3)J!{ffG3RKT1yo*sj(CYjQ%s~|NhnTV7Z);_~RrKm$ffK20jI_2u+DKZt*<1-g z2reWDgA2lhgbd&!l5jyuVF^AsToMlVgjY=bhk>KBwY{wmASfX&0uzM8ghUPC;*x?_ zHt>HMa11>nzA|9^yTT)9TcnqTn++gu?QChortWBAXQOXpVeRAEZ}a!G15j7iQL0oh G5BfhZO9?Ch diff --git a/DnsServerCore/www/css/jquery-ui.min.css b/DnsServerCore/www/css/jquery-ui.min.css deleted file mode 100644 index eca2e543..00000000 --- a/DnsServerCore/www/css/jquery-ui.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! jQuery UI - v1.12.1 - 2021-02-13 -* http://jqueryui.com -* Includes: core.css, datepicker.css, theme.css -* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=base&cornerRadiusShadow=8px&offsetLeftShadow=0px&offsetTopShadow=0px&thicknessShadow=5px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=666666&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cc0000&fcError=5f3f3f&borderColorError=f1a899&bgTextureError=flat&bgColorError=fddfdf&iconColorHighlight=777620&fcHighlight=777620&borderColorHighlight=dad55e&bgTextureHighlight=flat&bgColorHighlight=fffa90&iconColorActive=ffffff&fcActive=ffffff&borderColorActive=003eff&bgTextureActive=flat&bgColorActive=007fff&iconColorHover=555555&fcHover=2b2b2b&borderColorHover=cccccc&bgTextureHover=flat&bgColorHover=ededed&iconColorDefault=777777&fcDefault=454545&borderColorDefault=c5c5c5&bgTextureDefault=flat&bgColorDefault=f6f6f6&iconColorContent=444444&fcContent=333333&borderColorContent=dddddd&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=444444&fcHeader=333333&borderColorHeader=dddddd&bgTextureHeader=flat&bgColorHeader=e9e9e9&cornerRadius=3px&fwDefault=normal&fsDefault=1em&ffDefault=Arial%2CHelvetica%2Csans-serif -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} \ No newline at end of file diff --git a/DnsServerCore/www/js/bootstrap-datetimepicker.min.js b/DnsServerCore/www/js/bootstrap-datetimepicker.min.js deleted file mode 100644 index a953fe0c..00000000 --- a/DnsServerCore/www/js/bootstrap-datetimepicker.min.js +++ /dev/null @@ -1,214 +0,0 @@ -/*! version : 4.17.42 - ========================================================= - bootstrap-datetimejs - https://github.com/Eonasdan/bootstrap-datetimepicker - Copyright (c) 2015 Jonathan Peterson - ========================================================= - */ -/* - The MIT License (MIT) - - Copyright (c) 2015 Jonathan Peterson - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ -/*global define:false */ -/*global exports:false */ -/*global require:false */ -/*global jQuery:false */ -/*global moment:false */ -!function(a){"use strict";if("function"==typeof define&&define.amd) -// AMD is used - Register as an anonymous module. -define(["jquery","moment"],a);else if("object"==typeof exports)a(require("jquery"),require("moment"));else{ -// Neither AMD nor CommonJS used. Use global variables. -if("undefined"==typeof jQuery)throw"bootstrap-datetimepicker requires jQuery to be loaded first";if("undefined"==typeof moment)throw"bootstrap-datetimepicker requires Moment.js to be loaded first";a(jQuery,moment)}}(function(a,b){"use strict";if(!b)throw new Error("bootstrap-datetimepicker requires Moment.js to be loaded first");var c=function(c,d){var e,f,g,h,i,j,k,l={},m=!0,n=!1,o=!1,p=0,q=[{clsName:"days",navFnc:"M",navStep:1},{clsName:"months",navFnc:"y",navStep:1},{clsName:"years",navFnc:"y",navStep:10},{clsName:"decades",navFnc:"y",navStep:100}],r=["days","months","years","decades"],s=["top","bottom","auto"],t=["left","right","auto"],u=["default","top","bottom"],v={up:38,38:"up",down:40,40:"down",left:37,37:"left",right:39,39:"right",tab:9,9:"tab",escape:27,27:"escape",enter:13,13:"enter",pageUp:33,33:"pageUp",pageDown:34,34:"pageDown",shift:16,16:"shift",control:17,17:"control",space:32,32:"space",t:84,84:"t","delete":46,46:"delete"},w={},/******************************************************************************** - * - * Private functions - * - ********************************************************************************/ -x=function(){return void 0!==b.tz&&void 0!==d.timeZone&&null!==d.timeZone&&""!==d.timeZone},y=function(a){var c;return c=void 0===a||null===a?b():x()?b.tz(a,j,d.useStrict,d.timeZone):b(a,j,d.useStrict),x()&&c.tz(d.timeZone),c},z=function(a){if("string"!=typeof a||a.length>1)throw new TypeError("isEnabled expects a single character string parameter");switch(a){case"y":return-1!==i.indexOf("Y");case"M":return-1!==i.indexOf("M");case"d":return-1!==i.toLowerCase().indexOf("d");case"h":case"H":return-1!==i.toLowerCase().indexOf("h");case"m":return-1!==i.indexOf("m");case"s":return-1!==i.indexOf("s");default:return!1}},A=function(){return z("h")||z("m")||z("s")},B=function(){return z("y")||z("M")||z("d")},C=function(){var b=a("").append(a("").append(a("").addClass("prev").attr("data-action","previous").append(a("").addClass(d.icons.previous))).append(a("").addClass("picker-switch").attr("data-action","pickerSwitch").attr("colspan",d.calendarWeeks?"6":"5")).append(a("").addClass("next").attr("data-action","next").append(a("").addClass(d.icons.next)))),c=a("").append(a("").append(a("").attr("colspan",d.calendarWeeks?"8":"7")));return[a("
").addClass("datepicker-days").append(a("").addClass("table-condensed").append(b).append(a(""))),a("
").addClass("datepicker-months").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone())),a("
").addClass("datepicker-years").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone())),a("
").addClass("datepicker-decades").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone()))]},D=function(){var b=a(""),c=a(""),e=a("");return z("h")&&(b.append(a("
").append(a("").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementHour}).addClass("btn").attr("data-action","incrementHours").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-hour").attr({"data-time-component":"hours",title:d.tooltips.pickHour}).attr("data-action","showHours"))),e.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementHour}).addClass("btn").attr("data-action","decrementHours").append(a("").addClass(d.icons.down))))),z("m")&&(z("h")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementMinute}).addClass("btn").attr("data-action","incrementMinutes").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-minute").attr({"data-time-component":"minutes",title:d.tooltips.pickMinute}).attr("data-action","showMinutes"))),e.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementMinute}).addClass("btn").attr("data-action","decrementMinutes").append(a("").addClass(d.icons.down))))),z("s")&&(z("m")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementSecond}).addClass("btn").attr("data-action","incrementSeconds").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-second").attr({"data-time-component":"seconds",title:d.tooltips.pickSecond}).attr("data-action","showSeconds"))),e.append(a("").append(a("").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementSecond}).addClass("btn").attr("data-action","decrementSeconds").append(a("").addClass(d.icons.down))))),h||(b.append(a("").addClass("separator")),c.append(a("").append(a("").addClass("separator"))),a("
").addClass("timepicker-picker").append(a("").addClass("table-condensed").append([b,c,e]))},E=function(){var b=a("
").addClass("timepicker-hours").append(a("
").addClass("table-condensed")),c=a("
").addClass("timepicker-minutes").append(a("
").addClass("table-condensed")),d=a("
").addClass("timepicker-seconds").append(a("
").addClass("table-condensed")),e=[D()];return z("h")&&e.push(b),z("m")&&e.push(c),z("s")&&e.push(d),e},F=function(){var b=[];return d.showTodayButton&&b.push(a(" + - " + htmlEncode(responseJSON.response.entries[i].answer) + + ""; } var paginationHtml = ""; From 204ae2dac2f6c859f86f85bb2d0427ded9937ef7 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:47:27 +0530 Subject: [PATCH 178/191] main.js: removed unmaintained block lists from default settings. --- DnsServerCore/www/js/main.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index 4031a707..6523349f 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.js @@ -367,9 +367,7 @@ $(function () { case "default": var defaultList = ""; - defaultList += "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" + "\n"; - defaultList += "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt" + "\n"; - defaultList += "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt" + "\n"; + defaultList += "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts\n"; $("#txtBlockListUrls").val(defaultList); break; From df9373f59838e76a6254a9edbae144703d68e818 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:48:27 +0530 Subject: [PATCH 179/191] zone.js: implemented pagination support for zone records view. --- DnsServerCore/www/js/zone.js | 199 +++++++++++++++++++++++++---------- 1 file changed, 144 insertions(+), 55 deletions(-) diff --git a/DnsServerCore/www/js/zone.js b/DnsServerCore/www/js/zone.js index d5136471..555528c9 100644 --- a/DnsServerCore/www/js/zone.js +++ b/DnsServerCore/www/js/zone.js @@ -18,6 +18,7 @@ along with this program. If not, see . */ var zoneOptionsAvailableTsigKeyNames; +var editZoneRecords; $(function () { $("input[type=radio][name=rdAddZoneType]").change(function () { @@ -277,6 +278,14 @@ $(function () { var optZonesPerPage = localStorage.getItem("optZonesPerPage"); if (optZonesPerPage != null) $("#optZonesPerPage").val(optZonesPerPage); + + $("#optEditZoneRecordsPerPage").change(function () { + localStorage.setItem("optEditZoneRecordsPerPage", $("#optEditZoneRecordsPerPage").val()); + }); + + var optEditZoneRecordsPerPage = localStorage.getItem("optEditZoneRecordsPerPage"); + if (optEditZoneRecordsPerPage != null) + $("#optEditZoneRecordsPerPage").val(optEditZoneRecordsPerPage); }); function refreshZones(checkDisplay, pageNumber) { @@ -299,7 +308,9 @@ function refreshZones(checkDisplay, pageNumber) { pageNumber = 1; } - var zonesPerPage = $("#optZonesPerPage").val(); + var zonesPerPage = Number($("#optZonesPerPage").val()); + if (zonesPerPage < 1) + zonesPerPage = 10; var divViewZonesLoader = $("#divViewZonesLoader"); var divEditZone = $("#divEditZone"); @@ -1294,7 +1305,7 @@ function toggleHideDnssecRecords(hideDnssecRecords) { showEditZone($("#titleEditZone").attr("data-zone")); } -function showEditZone(zone) { +function showEditZone(zone, showPageNumber) { if (zone == null) { zone = $("#txtZonesEdit").val(); if (zone === "") { @@ -1304,6 +1315,9 @@ function showEditZone(zone) { } } + if (showPageNumber == null) + showPageNumber = 1; + var divViewZonesLoader = $("#divViewZonesLoader"); var divViewZones = $("#divViewZones"); var divEditZone = $("#divEditZone"); @@ -1316,6 +1330,8 @@ function showEditZone(zone) { url: "/api/zones/records/get?token=" + sessionData.token + "&domain=" + zone + "&zone=" + zone + "&listZone=true", success: function (responseJSON) { zone = responseJSON.response.zone.name; + if (zone === "") + zone = "."; var zoneType; if (responseJSON.response.zone.internal) @@ -1536,12 +1552,14 @@ function showEditZone(zone) { break; } - var records = responseJSON.response.records; - var tableHtmlRows = ""; - var recordCount = 0; + if (!zoneHideDnssecRecords || (responseJSON.response.zone.dnssecStatus === "Unsigned")) { + editZoneRecords = responseJSON.response.records; + } + else { + var records = responseJSON.response.records; + editZoneRecords = []; - for (var i = 0; i < records.length; i++) { - if (zoneHideDnssecRecords) { + for (var i = 0; i < records.length; i++) { switch (records[i].type.toUpperCase()) { case "RRSIG": case "NSEC": @@ -1549,21 +1567,19 @@ function showEditZone(zone) { case "NSEC3": case "NSEC3PARAM": continue; + + default: + editZoneRecords.push(records[i]); + break; } } - - recordCount++; - tableHtmlRows += getZoneRecordRowHtml(i, zone, zoneType, records[i]); } $("#titleEditZone").text(zone === "." ? "" : zone); $("#titleEditZone").attr("data-zone", zone); - $("#tableEditZoneBody").html(tableHtmlRows); + $("#titleEditZone").attr("data-zone-type", zoneType); - if (recordCount > 0) - $("#tableEditZoneFooter").html(""); - else - $("#tableEditZoneFooter").html(""); + showEditZonePage(showPageNumber); divViewZonesLoader.hide(); divEditZone.show(); @@ -1579,7 +1595,84 @@ function showEditZone(zone) { }); } -function getZoneRecordRowHtml(id, zone, zoneType, record) { +function showEditZonePage(pageNumber) { + if (pageNumber == null) + pageNumber = Number($("#txtEditZonePageNumber").val()); + + if (pageNumber == 0) + pageNumber = 1; + + var recordsPerPage = Number($("#optEditZoneRecordsPerPage").val()); + if (recordsPerPage < 1) + recordsPerPage = 10; + + var totalRecords = editZoneRecords.length; + var totalPages = Math.floor(totalRecords / recordsPerPage) + (totalRecords % recordsPerPage > 0 ? 1 : 0); + + if ((pageNumber > totalPages) || (pageNumber < 0)) + pageNumber = totalPages; + + var start = (pageNumber - 1) * recordsPerPage; + var end = Math.min(start + recordsPerPage, totalRecords); + + var tableHtmlRows = ""; + var zone = $("#titleEditZone").attr("data-zone"); + var zoneType = $("#titleEditZone").attr("data-zone-type"); + + for (var i = start; i < end; i++) + tableHtmlRows += getZoneRecordRowHtml(i, zone, zoneType, editZoneRecords[i]); + + var paginationHtml = ""; + + if (pageNumber > 1) { + paginationHtml += "
  • «
  • "; + paginationHtml += "
  • "; + } + + var pageStart = pageNumber - 5; + if (pageStart < 1) + pageStart = 1; + + var pageEnd = pageStart + 9; + if (pageEnd > totalPages) { + var endDiff = pageEnd - totalPages; + pageEnd = totalPages; + + pageStart -= endDiff; + if (pageStart < 1) + pageStart = 1; + } + + for (var i = pageStart; i <= pageEnd; i++) { + if (i == pageNumber) + paginationHtml += "
  • " + i + "
  • "; + else + paginationHtml += "
  • " + i + "
  • "; + } + + if (pageNumber < totalPages) { + paginationHtml += "
  • "; + paginationHtml += "
  • »
  • "; + } + + var statusHtml; + + if (editZoneRecords.length > 0) + statusHtml = (start + 1) + "-" + end + " (" + (end - start) + ") of " + editZoneRecords.length + " records (page " + pageNumber + " of " + totalPages + ")"; + else + statusHtml = "0 records"; + + $("#txtEditZonePageNumber").val(pageNumber); + $("#tableEditZoneBody").html(tableHtmlRows); + + $("#tableEditZoneTopStatus").html(statusHtml); + $("#tableEditZoneTopPagination").html(paginationHtml); + + $("#tableEditZoneFooterStatus").html(statusHtml); + $("#tableEditZoneFooterPagination").html(paginationHtml); +} + +function getZoneRecordRowHtml(index, zone, zoneType, record) { var name = record.name.toLowerCase(); if (name === "") name = "."; @@ -1589,7 +1682,7 @@ function getZoneRecordRowHtml(id, zone, zoneType, record) { else name = name.replace("." + zone, ""); - var tableHtmlRow = ""; + var tableHtmlRow = ""; tableHtmlRow += ""; tableHtmlRow += ""; @@ -2092,11 +2185,11 @@ function getZoneRecordRowHtml(id, zone, zoneType, record) { } else { tableHtmlRow += ""; + tableHtmlRow += "
    "; + tableHtmlRow += ""; + tableHtmlRow += ""; + tableHtmlRow += ""; + tableHtmlRow += ""; } tableHtmlRow += ""; @@ -2792,24 +2885,15 @@ function addRecord() { $("#modalAddEditRecord").modal("hide"); if (overwrite) { - showEditZone(zone); + var currentPageNumber = Number($("#txtEditZonePageNumber").val()); + showEditZone(zone, currentPageNumber); } else { - var zoneType; - if (responseJSON.response.zone.internal) - zoneType = "Internal"; - else - zoneType = responseJSON.response.zone.type; + //update local array + editZoneRecords.unshift(responseJSON.response.addedRecord); - var id = Math.floor(Math.random() * 1000000); - var tableHtmlRow = getZoneRecordRowHtml(id, zone, zoneType, responseJSON.response.addedRecord); - $("#tableEditZoneBody").prepend(tableHtmlRow); - - var recordCount = $('#tableEditZone >tbody >tr').length; - if (recordCount > 0) - $("#tableEditZoneFooter").html(""); - else - $("#tableEditZoneFooter").html(""); + //show page + showEditZonePage(1); } showAlert("success", "Record Added!", "Resource record was added successfully."); @@ -3136,8 +3220,8 @@ function updateRecord() { var btn = $("#btnAddEditRecord"); var divAddEditRecordAlert = $("#divAddEditRecordAlert"); - var id = btn.attr("data-id"); - var divData = $("#data" + id); + var index = Number(btn.attr("data-id")); + var divData = $("#data" + index); var zone = $("#titleEditZone").attr("data-zone"); var type = divData.attr("data-record-type"); @@ -3588,14 +3672,18 @@ function updateRecord() { success: function (responseJSON) { $("#modalAddEditRecord").modal("hide"); + //update local array + editZoneRecords[index] = responseJSON.response.updatedRecord; + + //show record var zoneType; if (responseJSON.response.zone.internal) zoneType = "Internal"; else zoneType = responseJSON.response.zone.type; - var tableHtmlRow = getZoneRecordRowHtml(id, zone, zoneType, responseJSON.response.updatedRecord); - $("#trZoneRecord" + id).replaceWith(tableHtmlRow); + var tableHtmlRow = getZoneRecordRowHtml(index, zone, zoneType, responseJSON.response.updatedRecord); + $("#trZoneRecord" + index).replaceWith(tableHtmlRow); showAlert("success", "Record Updated!", "Resource record was updated successfully."); }, @@ -3612,8 +3700,8 @@ function updateRecord() { function updateRecordState(objBtn, disable) { var btn = $(objBtn); - var id = btn.attr("data-id"); - var divData = $("#data" + id); + var index = Number(btn.attr("data-id")); + var divData = $("#data" + index); var type = divData.attr("data-record-type"); var domain = divData.attr("data-record-name"); @@ -3706,18 +3794,21 @@ function updateRecordState(objBtn, disable) { success: function (responseJSON) { btn.button('reset'); + //update local arrays + editZoneRecords[index] = responseJSON.response.updatedRecord; + //set new state divData.attr("data-record-disabled", disable); if (disable) { - $("#btnEnableRecord" + id).show(); - $("#btnDisableRecord" + id).hide(); + $("#btnEnableRecord" + index).show(); + $("#btnDisableRecord" + index).hide(); showAlert("success", "Record Disabled!", "Resource record was disabled successfully."); } else { - $("#btnEnableRecord" + id).hide(); - $("#btnDisableRecord" + id).show(); + $("#btnEnableRecord" + index).hide(); + $("#btnDisableRecord" + index).show(); showAlert("success", "Record Enabled!", "Resource record was enabled successfully."); } @@ -3733,8 +3824,8 @@ function updateRecordState(objBtn, disable) { function deleteRecord(objBtn) { var btn = $(objBtn); - var id = btn.attr("data-id"); - var divData = $("#data" + id); + var index = btn.attr("data-id"); + var divData = $("#data" + index); var zone = $("#titleEditZone").attr("data-zone"); var domain = divData.attr("data-record-name"); @@ -3804,13 +3895,11 @@ function deleteRecord(objBtn) { HTTPRequest({ url: apiUrl, success: function (responseJSON) { - $("#trZoneRecord" + id).remove(); + //update local array + editZoneRecords.splice(index, 1); - var recordCount = $('#tableEditZone >tbody >tr').length; - if (recordCount > 0) - $("#tableEditZoneFooter").html(""); - else - $("#tableEditZoneFooter").html(""); + //show page + showEditZonePage(); showAlert("success", "Record Deleted!", "Resource record was deleted successfully."); }, From 0e66b3908a6ab8bf201b4d4bf3d5922d80864be4 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:50:05 +0530 Subject: [PATCH 180/191] IDnsServer: added new DirectQueryAsync() method. --- DnsServerCore.ApplicationCommon/IDnsServer.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/DnsServerCore.ApplicationCommon/IDnsServer.cs b/DnsServerCore.ApplicationCommon/IDnsServer.cs index 17b74faa..ead3ceeb 100644 --- a/DnsServerCore.ApplicationCommon/IDnsServer.cs +++ b/DnsServerCore.ApplicationCommon/IDnsServer.cs @@ -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 @@ -33,10 +33,20 @@ namespace DnsServerCore.ApplicationCommon /// Allows querying the DNS server core directly. This call supports recursion even if its not enabled in the DNS server configuration. The request wont be routed to any of the installed DNS Apps except for processing APP records. The request and its response are not counted in any stats or logged. /// /// The question record containing the details to query. + /// The timeout value in milliseconds to wait for response. /// The DNS response for the DNS query. /// When request times out. Task DirectQueryAsync(DnsQuestionRecord question, int timeout = 4000); + /// + /// Allows querying the DNS server core directly. This call supports recursion even if its not enabled in the DNS server configuration. The request wont be routed to any of the installed DNS Apps except for processing APP records. The request and its response are not counted in any stats or logged. + /// + /// The DNS request to query. + /// The timeout value in milliseconds to wait for response. + /// The DNS response for the DNS query. + /// When request times out. + Task DirectQueryAsync(DnsDatagram request, int timeout = 4000); + /// /// Writes a log entry to the DNS server log file. /// From a2d3c63d6343c392fd05dfd62900b41c6aa99881 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:50:40 +0530 Subject: [PATCH 181/191] AdvancedForwarding: minor formatting changes. --- Apps/AdvancedForwardingApp/dnsApp.config | 116 +++++++++++------------ 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/Apps/AdvancedForwardingApp/dnsApp.config b/Apps/AdvancedForwardingApp/dnsApp.config index 96ca8daf..40479b5e 100644 --- a/Apps/AdvancedForwardingApp/dnsApp.config +++ b/Apps/AdvancedForwardingApp/dnsApp.config @@ -2,43 +2,43 @@ "enableForwarding": true, "proxyServers": [ { - "name": "local-proxy", - "type": "socks5", - "proxyAddress": "localhost", - "proxyPort": 1080, - "proxyUsername": null, - "proxyPassword": null - } + "name": "local-proxy", + "type": "socks5", + "proxyAddress": "localhost", + "proxyPort": 1080, + "proxyUsername": null, + "proxyPassword": null + } ], "forwarders": [ { - "name": "quad9-doh", - "proxy": null, - "dnssecValidation": true, - "forwarderProtocol": "Https", - "forwarderAddresses": [ - "https://dns.quad9.net/dns-query (9.9.9.9)" - ] - }, - { - "name": "cloudflare-google", - "proxy": null, - "dnssecValidation": true, - "forwarderProtocol": "Tls", - "forwarderAddresses": [ - "1.1.1.1", - "8.8.8.8" - ] - }, - { - "name": "quad9-tls-proxied", - "proxy": "local-proxy", - "dnssecValidation": true, - "forwarderProtocol": "Tls", - "forwarderAddresses": [ - "9.9.9.9" - ] - } + "name": "quad9-doh", + "proxy": null, + "dnssecValidation": true, + "forwarderProtocol": "Https", + "forwarderAddresses": [ + "https://dns.quad9.net/dns-query (9.9.9.9)" + ] + }, + { + "name": "cloudflare-google", + "proxy": null, + "dnssecValidation": true, + "forwarderProtocol": "Tls", + "forwarderAddresses": [ + "1.1.1.1", + "8.8.8.8" + ] + }, + { + "name": "quad9-tls-proxied", + "proxy": "local-proxy", + "dnssecValidation": true, + "forwarderProtocol": "Tls", + "forwarderAddresses": [ + "9.9.9.9" + ] + } ], "networkGroupMap": { "0.0.0.0/0": "everyone" @@ -47,31 +47,31 @@ { "name": "everyone", "enableForwarding": true, - "forwardings": [ + "forwardings": [ { - "forwarders": [ - "quad9-doh" - ], - "domains": [ - "example.com" - ] - }, - { - "forwarders": [ - "cloudflare-google" - ], - "domains": [ - "example.net" - ] - } - ], + "forwarders": [ + "quad9-doh" + ], + "domains": [ + "example.com" + ] + }, + { + "forwarders": [ + "cloudflare-google" + ], + "domains": [ + "example.net" + ] + } + ], "adguardUpstreams": [ - { - "proxy": null, - "dnssecValidation": true, - "configFile": "adguard-upstreams.txt" - } - ] - } + { + "proxy": null, + "dnssecValidation": true, + "configFile": "adguard-upstreams.txt" + } + ] + } ] } From 12db30dcb7094a090db06d5f29757b4312fdecf3 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:51:13 +0530 Subject: [PATCH 182/191] app assembly version updated for release --- Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj | 10 +++++----- Apps/BlockPageApp/BlockPageApp.csproj | 6 +----- Apps/Dns64App/Dns64App.csproj | 10 +++++----- Apps/DropRequestsApp/DropRequestsApp.csproj | 10 +++++----- Apps/FailoverApp/FailoverApp.csproj | 8 ++------ Apps/GeoContinentApp/GeoContinentApp.csproj | 5 ++--- Apps/GeoCountryApp/GeoCountryApp.csproj | 5 ++--- Apps/GeoDistanceApp/GeoDistanceApp.csproj | 5 ++--- Apps/NoDataApp/NoDataApp.csproj | 6 +----- Apps/NxDomainApp/NxDomainApp.csproj | 10 +++++----- Apps/QueryLogsSqliteApp/QueryLogsSqliteApp.csproj | 5 ++--- Apps/SplitHorizonApp/SplitHorizonApp.csproj | 8 ++------ Apps/WhatIsMyDnsApp/WhatIsMyDnsApp.csproj | 4 ++-- Apps/WildIpApp/WildIpApp.csproj | 4 ++-- 14 files changed, 38 insertions(+), 58 deletions(-) diff --git a/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj b/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj index e8e33de3..6cd8b4ab 100644 --- a/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj +++ b/Apps/AdvancedBlockingApp/AdvancedBlockingApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 4.0.1 + 5.0 Technitium Technitium DNS Server Shreyas Zare @@ -16,10 +16,6 @@ Library - - - - false @@ -27,6 +23,10 @@ + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll + false + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll false diff --git a/Apps/BlockPageApp/BlockPageApp.csproj b/Apps/BlockPageApp/BlockPageApp.csproj index eb68d450..8992c987 100644 --- a/Apps/BlockPageApp/BlockPageApp.csproj +++ b/Apps/BlockPageApp/BlockPageApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 3.0.1 + 4.0 Technitium Technitium DNS Server Shreyas Zare @@ -26,10 +26,6 @@ - - - - false diff --git a/Apps/Dns64App/Dns64App.csproj b/Apps/Dns64App/Dns64App.csproj index 967db31d..4195166c 100644 --- a/Apps/Dns64App/Dns64App.csproj +++ b/Apps/Dns64App/Dns64App.csproj @@ -3,7 +3,7 @@ net7.0 false - 1.0.1 + 2.0 Technitium Technitium DNS Server Shreyas Zare @@ -16,10 +16,6 @@ Library - - - - false @@ -27,6 +23,10 @@ + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll + false + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll false diff --git a/Apps/DropRequestsApp/DropRequestsApp.csproj b/Apps/DropRequestsApp/DropRequestsApp.csproj index 859d7b39..546d56c5 100644 --- a/Apps/DropRequestsApp/DropRequestsApp.csproj +++ b/Apps/DropRequestsApp/DropRequestsApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 3.0.1 + 4.0 Technitium Technitium DNS Server Shreyas Zare @@ -16,10 +16,6 @@ Library - - - - false @@ -27,6 +23,10 @@ + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll + false + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll false diff --git a/Apps/FailoverApp/FailoverApp.csproj b/Apps/FailoverApp/FailoverApp.csproj index 209c7eed..63a84a75 100644 --- a/Apps/FailoverApp/FailoverApp.csproj +++ b/Apps/FailoverApp/FailoverApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 5.1 + 6.0 Technitium Technitium DNS Server Shreyas Zare @@ -11,15 +11,11 @@ Failover https://technitium.com/dns/ https://github.com/TechnitiumSoftware/DnsServer - Allows creating APP records in a primary zone that can return A or AAAA records, or CNAME record based on the health status of the servers. The app supports email alerts and web hooks to relay the health status. + Allows creating APP records in a primary and forwarder zones that can return A or AAAA records, or CNAME record based on the health status of the servers. The app supports email alerts and web hooks to relay the health status. false Library - - - - false diff --git a/Apps/GeoContinentApp/GeoContinentApp.csproj b/Apps/GeoContinentApp/GeoContinentApp.csproj index fae5dc65..6b6cf7cf 100644 --- a/Apps/GeoContinentApp/GeoContinentApp.csproj +++ b/Apps/GeoContinentApp/GeoContinentApp.csproj @@ -4,7 +4,7 @@ net7.0 false true - 5.0.1 + 6.0 Technitium Technitium DNS Server Shreyas Zare @@ -12,14 +12,13 @@ GeoContinent https://technitium.com/dns/ https://github.com/TechnitiumSoftware/DnsServer - Allows creating APP records in a primary zone that can return A or AAAA records, or CNAME record based on the continent the client queries from using MaxMind GeoIP2 Country database. Supports EDNS Client Subnet (ECS). This app requires MaxMind GeoIP2 database and includes the GeoLite2 version for trial. \n\nTo update the MaxMind GeoIP2 database for your app, download the GeoIP2-Country.mmdb file from MaxMind and zip it. Use the zip file with the manual Update option. + Allows creating APP records in a primary and forwarder zones that can return A or AAAA records, or CNAME record based on the continent the client queries from using MaxMind GeoIP2 Country database. Supports EDNS Client Subnet (ECS). This app requires MaxMind GeoIP2 database and includes the GeoLite2 version for trial. \n\nTo update the MaxMind GeoIP2 database for your app, download the GeoIP2-Country.mmdb file from MaxMind and zip it. Use the zip file with the manual Update option. false Library - diff --git a/Apps/GeoCountryApp/GeoCountryApp.csproj b/Apps/GeoCountryApp/GeoCountryApp.csproj index a54fd377..1fec56aa 100644 --- a/Apps/GeoCountryApp/GeoCountryApp.csproj +++ b/Apps/GeoCountryApp/GeoCountryApp.csproj @@ -4,7 +4,7 @@ net7.0 false true - 5.0.1 + 6.0 Technitium Technitium DNS Server Shreyas Zare @@ -12,14 +12,13 @@ GeoCountry https://technitium.com/dns/ https://github.com/TechnitiumSoftware/DnsServer - Allows creating APP records in a primary zone that can return A or AAAA records, or CNAME record based on the country the client queries from using MaxMind GeoIP2 Country database. Supports EDNS Client Subnet (ECS). This app requires MaxMind GeoIP2 database and includes the GeoLite2 version for trial. \n\nTo update the MaxMind GeoIP2 database for your app, download the GeoIP2-Country.mmdb file from MaxMind and zip it. Use the zip file with the manual Update option. + Allows creating APP records in a primary and forwarder zones that can return A or AAAA records, or CNAME record based on the country the client queries from using MaxMind GeoIP2 Country database. Supports EDNS Client Subnet (ECS). This app requires MaxMind GeoIP2 database and includes the GeoLite2 version for trial. \n\nTo update the MaxMind GeoIP2 database for your app, download the GeoIP2-Country.mmdb file from MaxMind and zip it. Use the zip file with the manual Update option. false Library - diff --git a/Apps/GeoDistanceApp/GeoDistanceApp.csproj b/Apps/GeoDistanceApp/GeoDistanceApp.csproj index a6967219..65b478e1 100644 --- a/Apps/GeoDistanceApp/GeoDistanceApp.csproj +++ b/Apps/GeoDistanceApp/GeoDistanceApp.csproj @@ -4,7 +4,7 @@ net7.0 false true - 5.0.1 + 6.0 Technitium Technitium DNS Server Shreyas Zare @@ -12,14 +12,13 @@ GeoDistance https://technitium.com/dns/ https://github.com/TechnitiumSoftware/DnsServer - Allows creating APP records in a primary zone that can return A or AAAA records, or CNAME record of the server located geographically closest to the client using MaxMind GeoIP2 City database. Supports EDNS Client Subnet (ECS). This app requires MaxMind GeoIP2 database and includes the GeoLite2 version for trial. \n\nTo update the MaxMind GeoIP2 database for your app, download the GeoIP2-City.mmdb file from MaxMind and zip it. Use the zip file with the manual Update option. + Allows creating APP records in a primary and forwarder zones that can return A or AAAA records, or CNAME record of the server located geographically closest to the client using MaxMind GeoIP2 City database. Supports EDNS Client Subnet (ECS). This app requires MaxMind GeoIP2 database and includes the GeoLite2 version for trial. \n\nTo update the MaxMind GeoIP2 database for your app, download the GeoIP2-City.mmdb file from MaxMind and zip it. Use the zip file with the manual Update option. false Library - diff --git a/Apps/NoDataApp/NoDataApp.csproj b/Apps/NoDataApp/NoDataApp.csproj index 017e7cdc..8f867a97 100644 --- a/Apps/NoDataApp/NoDataApp.csproj +++ b/Apps/NoDataApp/NoDataApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 1.0.1 + 2.0 Technitium Technitium DNS Server Shreyas Zare @@ -16,10 +16,6 @@ Library - - - - false diff --git a/Apps/NxDomainApp/NxDomainApp.csproj b/Apps/NxDomainApp/NxDomainApp.csproj index 8e972fdd..d3cf276e 100644 --- a/Apps/NxDomainApp/NxDomainApp.csproj +++ b/Apps/NxDomainApp/NxDomainApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 3.0.1 + 4.0 Technitium Technitium DNS Server Shreyas Zare @@ -16,10 +16,6 @@ Library - - - - false @@ -27,6 +23,10 @@ + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll + false + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll false diff --git a/Apps/QueryLogsSqliteApp/QueryLogsSqliteApp.csproj b/Apps/QueryLogsSqliteApp/QueryLogsSqliteApp.csproj index 7c177cc3..61b75dd5 100644 --- a/Apps/QueryLogsSqliteApp/QueryLogsSqliteApp.csproj +++ b/Apps/QueryLogsSqliteApp/QueryLogsSqliteApp.csproj @@ -4,7 +4,7 @@ net7.0 false true - 3.1 + 4.0 Technitium Technitium DNS Server Shreyas Zare @@ -18,8 +18,7 @@ - - + diff --git a/Apps/SplitHorizonApp/SplitHorizonApp.csproj b/Apps/SplitHorizonApp/SplitHorizonApp.csproj index 35eff512..07111f5f 100644 --- a/Apps/SplitHorizonApp/SplitHorizonApp.csproj +++ b/Apps/SplitHorizonApp/SplitHorizonApp.csproj @@ -3,7 +3,7 @@ net7.0 false - 5.0.1 + 6.0 Technitium Technitium DNS Server Shreyas Zare @@ -11,15 +11,11 @@ SplitHorizon https://technitium.com/dns/ https://github.com/TechnitiumSoftware/DnsServer - Allows creating APP records in a primary zone that can return different set of A or AAAA records, or CNAME record for clients querying over public, private, or other specified networks.\n\nEnables Address Translation of IP addresses in a DNS response for A & AAAA type request based on the client's network address and the configured 1:1 translation. + Allows creating APP records in a primary and forwarder zones that can return different set of A or AAAA records, or CNAME record for clients querying over public, private, or other specified networks.\n\nEnables Address Translation of IP addresses in a DNS response for A & AAAA type request based on the client's network address and the configured 1:1 translation. false Library - - - - false diff --git a/Apps/WhatIsMyDnsApp/WhatIsMyDnsApp.csproj b/Apps/WhatIsMyDnsApp/WhatIsMyDnsApp.csproj index c193dc97..12682d73 100644 --- a/Apps/WhatIsMyDnsApp/WhatIsMyDnsApp.csproj +++ b/Apps/WhatIsMyDnsApp/WhatIsMyDnsApp.csproj @@ -4,7 +4,7 @@ net7.0 false true - 5.0 + 5.0.1 Technitium Technitium DNS Server Shreyas Zare @@ -12,7 +12,7 @@ WhatIsMyDns https://technitium.com/dns/ https://github.com/TechnitiumSoftware/DnsServer - Allows creating APP records in a primary zone that can return the IP address of the user's DNS Server for A, AAAA, and TXT queries. + Allows creating APP records in a primary and forwarder zones that can return the IP address of the user's DNS Server for A, AAAA, and TXT queries. false Library diff --git a/Apps/WildIpApp/WildIpApp.csproj b/Apps/WildIpApp/WildIpApp.csproj index 573ef1ab..00afeca9 100644 --- a/Apps/WildIpApp/WildIpApp.csproj +++ b/Apps/WildIpApp/WildIpApp.csproj @@ -4,7 +4,7 @@ net7.0 false true - 2.0 + 2.1 Technitium Technitium DNS Server Shreyas Zare @@ -12,7 +12,7 @@ WildIp https://technitium.com/dns/ https://github.com/TechnitiumSoftware/DnsServer - Allows creating APP records in a primary zone that can return the IP address embedded in the subdomain name for A and AAAA queries. It works similar to sslip.io. + Allows creating APP records in a primary and forwarder zones that can return the IP address embedded in the subdomain name for A and AAAA queries. It works similar to sslip.io. false Library From bb5d75b2589025c3dbb4ce92dd74523910115c31 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:51:55 +0530 Subject: [PATCH 183/191] install.sh: updated install script to install ASP.NET Core Runtime. --- DnsServerApp/install.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/DnsServerApp/install.sh b/DnsServerApp/install.sh index f5c00748..5b7a1885 100644 --- a/DnsServerApp/install.sh +++ b/DnsServerApp/install.sh @@ -14,7 +14,7 @@ echo "===============================" echo "Technitium DNS Server Installer" echo "===============================" -if dotnet --list-runtimes 2> /dev/null | grep -q "Microsoft.NETCore.App 7.0."; +if dotnet --list-runtimes 2> /dev/null | grep -q "Microsoft.AspNetCore.App 7.0."; then dotnetFound="yes" else @@ -24,36 +24,36 @@ fi if [ ! -d $dotnetDir ] && [ "$dotnetFound" = "yes" ] then echo "" - echo ".NET 7 Runtime is already installed." + echo "ASP.NET Core Runtime is already installed." else echo "" if [ -d $dotnetDir ] && [ "$dotnetFound" = "yes" ] then dotnetUpdate="yes" - echo "Updating .NET 7 Runtime..." + echo "Updating ASP.NET Core Runtime..." else dotnetUpdate="no" - echo "Installing .NET 7 Runtime..." + echo "Installing ASP.NET Core Runtime..." fi - curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin -c 7.0 --runtime dotnet --no-path --install-dir $dotnetDir --verbose >> $installLog 2>&1 + curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin -c 7.0 --runtime aspnetcore --no-path --install-dir $dotnetDir --verbose >> $installLog 2>&1 if [ ! -f "/usr/bin/dotnet" ] then ln -s $dotnetDir/dotnet /usr/bin >> $installLog 2>&1 fi - if dotnet --list-runtimes 2> /dev/null | grep -q "Microsoft.NETCore.App 7.0."; + if dotnet --list-runtimes 2> /dev/null | grep -q "Microsoft.AspNetCore.App 7.0."; then if [ "$dotnetUpdate" = "yes" ] then - echo ".NET 7 Runtime was updated successfully!" + echo "ASP.NET Core Runtime was updated successfully!" else - echo ".NET 7 Runtime was installed successfully!" + echo "ASP.NET Core Runtime was installed successfully!" fi else - echo "Failed to install .NET 7 Runtime. Please try again." + echo "Failed to install ASP.NET Core Runtime. Please try again." exit 1 fi fi From 6a1f543d7f0a9c4fc7cbd208437e26d53be37cd2 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:52:46 +0530 Subject: [PATCH 184/191] inno: updated setup to install ASP.NET Core Runtime. --- DnsServerWindowsSetup/dotnet.iss | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/DnsServerWindowsSetup/dotnet.iss b/DnsServerWindowsSetup/dotnet.iss index 92368de3..d88b8bb0 100644 --- a/DnsServerWindowsSetup/dotnet.iss +++ b/DnsServerWindowsSetup/dotnet.iss @@ -305,12 +305,24 @@ end; { Check if dotnet is installed } +function IsAspDotNetInstalled: Boolean; +var + ResultCode: Integer; +begin + Result := false; + Exec('cmd.exe', '/c dotnet --list-runtimes | find /n "Microsoft.AspNetCore.App 7.0.3"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + if ResultCode = 0 then + begin + Result := true; + end; +end; + function IsDotNetDesktopInstalled: Boolean; var ResultCode: Integer; begin Result := false; - Exec('cmd.exe', '/c dotnet --list-runtimes | find /n "Microsoft.WindowsDesktop.App 7.0.0"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); + Exec('cmd.exe', '/c dotnet --list-runtimes | find /n "Microsoft.WindowsDesktop.App 7.0.3"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); if ResultCode = 0 then begin Result := true; @@ -320,12 +332,21 @@ end; { if dotnet is not installed then add it for download } procedure CheckDotnetDependency; begin + if not IsAspDotNetInstalled then + begin + AddDependency('aspdotnet70' + GetArchitectureSuffix + '.exe', + '/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart', + 'ASP.NET Core Runtime 7.0.3' + GetArchitectureTitle, + GetString('https://download.visualstudio.microsoft.com/download/pr/4bf0f350-f947-408b-9ee4-539313b85634/b17087052d6192b5d59735ae6f208c19/aspnetcore-runtime-7.0.3-win-x86.exe', 'https://download.visualstudio.microsoft.com/download/pr/d37efccc-2ba1-4fc9-a1ef-a8e1e77fb681/b9a20fc29ff05f18d81620ec88ade699/aspnetcore-runtime-7.0.3-win-x64.exe'), + '', False, False, False); + end; + if not IsDotNetDesktopInstalled then begin AddDependency('dotnet70desktop' + GetArchitectureSuffix + '.exe', '/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart', - '.NET Desktop Runtime 7.0.0' + GetArchitectureTitle, - GetString('https://download.visualstudio.microsoft.com/download/pr/d05a833c-2cf9-4d06-89ae-a0f3e10c5c91/c668ff42e23c2f67aa3d80227860585f/windowsdesktop-runtime-7.0.0-win-x86.exe', 'https://download.visualstudio.microsoft.com/download/pr/5b2fbe00-507e-450e-8b52-43ab052aadf2/79d54c3a19ce3fce314f2367cf4e3b21/windowsdesktop-runtime-7.0.0-win-x64.exe'), + '.NET Desktop Runtime 7.0.3' + GetArchitectureTitle, + GetString('https://download.visualstudio.microsoft.com/download/pr/fb8bf100-9e1c-472c-8bc8-aa16fff44f53/8d36f5a56edff8620f9c63c1e73ba88c/windowsdesktop-runtime-7.0.3-win-x86.exe', 'https://download.visualstudio.microsoft.com/download/pr/3ebf014d-fcb9-4200-b3fe-76ba2000b027/840f2f95833ce400a9949e35f1581d28/windowsdesktop-runtime-7.0.3-win-x64.exe'), '', False, False, False); end; end; From 8bb51d8e6afd9bf257d00b7a9278108d5687cf9a Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:53:09 +0530 Subject: [PATCH 185/191] inno: updated version to 11.0 for release. --- DnsServerWindowsSetup/DnsServerSetup.iss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DnsServerWindowsSetup/DnsServerSetup.iss b/DnsServerWindowsSetup/DnsServerSetup.iss index acdac1f5..b4115872 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 "10.0.1" +#define MyAppVersion "11.0" #define MyAppPublisher "Technitium" #define MyAppURL "https://technitium.com/dns/" #define MyAppExeName "DnsServerSystemTrayApp.exe" @@ -18,8 +18,8 @@ AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} -VersionInfoVersion=2.1.0.0 -VersionInfoCopyright="Copyright (C) 2022 Technitium" +VersionInfoVersion=2.2.0.0 +VersionInfoCopyright="Copyright (C) 2023 Technitium" DefaultDirName={commonpf32}\Technitium\DNS Server DefaultGroupName={#MyAppName} DisableProgramGroupPage=yes From 71d97a6b1410624f4f213b193947ddd16e28f0ea Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:53:53 +0530 Subject: [PATCH 186/191] dockerfile: updated to use asp.net core and added QUIC related ports. --- Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 41da4498..59d7695c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/runtime:7.0 +FROM mcr.microsoft.com/dotnet/aspnet:7.0 LABEL product="Technitium DNS Server" LABEL vendor="Technitium" LABEL email="support@technitium.com" @@ -10,13 +10,16 @@ WORKDIR /etc/dns/ COPY ./DnsServerApp/bin/Release/publish/ . EXPOSE 5380/tcp +EXPOSE 53443/tcp EXPOSE 53/udp EXPOSE 53/tcp -EXPOSE 67/udp +EXPOSE 853/udp EXPOSE 853/tcp +EXPOSE 443/udp EXPOSE 443/tcp EXPOSE 80/tcp EXPOSE 8053/tcp +EXPOSE 67/udp VOLUME ["/etc/dns/config"] From 294fbc1efb327320f4cb9f1df7ea781d5d82f11c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:54:25 +0530 Subject: [PATCH 187/191] docker-compose: updated file to add QUIC ports. --- docker-compose.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7cc8cb55..036cf532 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,14 +7,17 @@ services: # For DHCP deployments, use "host" network mode and remove all the port mappings, including the ports array by commenting them # network_mode: "host" ports: - - "5380:5380/tcp" #DNS web console + - "5380:5380/tcp" #DNS web console (HTTP) + # - "53443:53443/tcp" #DNS web console (HTTPS) - "53:53/udp" #DNS service - "53:53/tcp" #DNS service - # - "67:67/udp" #DHCP service + # - "853:853/udp" #DNS-over-QUIC service # - "853:853/tcp" #DNS-over-TLS service - # - "443:443/tcp" #DNS-over-HTTPS service - # - "80:80/tcp" #DNS-over-HTTPS service certbot certificate renewal - # - "8053:8053/tcp" #DNS-over-HTTPS using reverse proxy + # - "443:443/udp" #DNS-over-HTTPS service (HTTP/3) + # - "443:443/tcp" #DNS-over-HTTPS service (HTTP/1.1, HTTP/2) + # - "80:80/tcp" #DNS-over-HTTP service (use with reverse proxy or certbot certificate renewal) + # - "8053:8053/tcp" #DNS-over-HTTP service (use with reverse proxy) + # - "67:67/udp" #DHCP service environment: - DNS_SERVER_DOMAIN=dns-server #The primary domain name used by this DNS Server to identify itself. # - DNS_SERVER_ADMIN_PASSWORD=password #DNS web console admin user password. From 8ff8681d92a1d2afa1293aaa8939321178b57659 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:55:46 +0530 Subject: [PATCH 188/191] updated readme --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a7cd591..9474c1d2 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,9 @@ Be it a home network or an organization's network, having a locally running DNS - Installs in just a minute and works out-of-the-box with zero configuration. - Block ads & malware using one or more block list URLs. - High performance DNS server based on async IO that can serve millions of requests per minute even on a commodity desktop PC hardware (load tested on Intel i7-8700 CPU with more than 100,000 request/second over Gigabit Ethernet). -- Self host [DNS-over-TLS](https://www.rfc-editor.org/rfc/rfc7858.html), [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.html), and [DNS-over-QUIC](https://www.ietf.org/rfc/rfc9250.html) DNS service on your network. -- Use public DNS resolvers like Cloudflare, Google, Quad9, & AdGuard with [DNS-over-TLS](https://www.rfc-editor.org/rfc/rfc7858.html), [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.html), or [DNS-over-QUIC](https://www.ietf.org/rfc/rfc9250.html) protocols as forwarders. +- Self host [DNS-over-TLS](https://www.rfc-editor.org/rfc/rfc7858.html), [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.html), and [DNS-over-QUIC](https://www.ietf.org/rfc/rfc9250.html) DNS services on your network. +- DNS-over-HTTPS implementation supports HTTP/1.1, HTTP/2, and HTTP/3 transport protocols. +- Use public DNS resolvers like Cloudflare, Google, Quad9, and AdGuard with [DNS-over-TLS](https://www.rfc-editor.org/rfc/rfc7858.html), [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.html), or [DNS-over-QUIC](https://www.ietf.org/rfc/rfc9250.html) protocols as forwarders. - Advanced caching with features like serve stale, prefetching and auto prefetching. - Supports working as an authoritative as well as a recursive DNS server. - DNSSEC validation support with RSA & ECDSA algorithms for recursive resolver, forwarders, and conditional forwarders with NSEC and NSEC3 support. @@ -39,7 +40,7 @@ Be it a home network or an organization's network, having a locally running DNS - SSHFP [RFC 4255](https://www.rfc-editor.org/rfc/rfc4255.html) record type support. - CNAME cloaking feature to block domain names that resolve to CNAME which are blocked. - QNAME minimization support in recursive resolver [RFC 9156](https://www.rfc-editor.org/rfc/rfc9156.html). -- QNAME randomization support for UDP transport protocol [draft-vixie-dnsext-dns0x20-00](https://datatracker.ietf.org/doc/html/draft-vixie-dnsext-dns0x20-00). +- QNAME case randomization support for UDP transport protocol [draft-vixie-dnsext-dns0x20-00](https://datatracker.ietf.org/doc/html/draft-vixie-dnsext-dns0x20-00). - DNAME record [RFC 6672](https://datatracker.ietf.org/doc/html/rfc6672) support. - ANAME propriety record support to allow using CNAME like feature at zone apex (CNAME flattening). Supports multiple ANAME records at both zone apex and sub domains. - APP propriety record support that allows custom DNS Apps to directly handle DNS requests and return a custom DNS response based on any business logic. @@ -47,6 +48,7 @@ Be it a home network or an organization's network, having a locally running DNS - Support for REGEX based block lists with different block lists for different client IP addresses or subnet using Advanced Blocking DNS App. - Primary, Secondary, Stub, and Conditional Forwarder zone support. - Static stub zone support implemented in Conditional Forwarder zone to force a domain name to resolve via given name servers using NS records. +- Bulk conditional forwarding support using Advanced Forwarding DNS App. - DNSSEC signed zones support with RSA & ECDSA algorithms. - DNSSEC support for both NSEC and NSEC3. - Zone transfer with AXFR and IXFR [RFC 1995](https://www.rfc-editor.org/rfc/rfc1995.html) support. @@ -58,6 +60,7 @@ Be it a home network or an organization's network, having a locally running DNS - EDNS Client Subnet (ECS) [RFC 7871](https://datatracker.ietf.org/doc/html/rfc7871) support for recursive resolution and forwarding. - Extended DNS Errors [RFC 8914](https://datatracker.ietf.org/doc/html/rfc8914) support. - DNS64 function [RFC 6147](https://www.rfc-editor.org/rfc/rfc6147) support for use by IPv6 only clients using the DNS64 App. +- Support to host DNSBL / RBL block lists [RFC 5782](https://www.rfc-editor.org/rfc/rfc5782). - Multi-user role based access with non-expiring API token support. - Self host your domain names on your own DNS server. - Wildcard sub domain support. From 2a4010dfbc8b73953c69a8b9b274f84437827661 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:56:44 +0530 Subject: [PATCH 189/191] assembly version updated for release --- .../DnsServerCore.ApplicationCommon.csproj | 4 ++-- DnsServerSystemTrayApp/DnsServerSystemTrayApp.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DnsServerCore.ApplicationCommon/DnsServerCore.ApplicationCommon.csproj b/DnsServerCore.ApplicationCommon/DnsServerCore.ApplicationCommon.csproj index 720dcf52..42f607a5 100644 --- a/DnsServerCore.ApplicationCommon/DnsServerCore.ApplicationCommon.csproj +++ b/DnsServerCore.ApplicationCommon/DnsServerCore.ApplicationCommon.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -11,7 +11,7 @@ DnsServerCore.ApplicationCommon - 5.0 + 5.1 diff --git a/DnsServerSystemTrayApp/DnsServerSystemTrayApp.csproj b/DnsServerSystemTrayApp/DnsServerSystemTrayApp.csproj index 2a3df257..d5c37327 100644 --- a/DnsServerSystemTrayApp/DnsServerSystemTrayApp.csproj +++ b/DnsServerSystemTrayApp/DnsServerSystemTrayApp.csproj @@ -11,7 +11,7 @@ DnsServerSystemTrayApp Shreyas Zare logo2.ico - 4.0 + 4.0.1 Technitium Technitium DNS Server From efe2bc5538d3f788befa21fbc3bfce3d3b4fdb23 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:57:17 +0530 Subject: [PATCH 190/191] assembly version updated to 11.0 for release. --- DnsServerApp/DnsServerApp.csproj | 2 +- DnsServerCore/DnsServerCore.csproj | 88 +++++-------------- .../DnsServerWindowsService.csproj | 4 +- 3 files changed, 27 insertions(+), 67 deletions(-) diff --git a/DnsServerApp/DnsServerApp.csproj b/DnsServerApp/DnsServerApp.csproj index 295865a9..827cb031 100644 --- a/DnsServerApp/DnsServerApp.csproj +++ b/DnsServerApp/DnsServerApp.csproj @@ -6,7 +6,7 @@ Exe net7.0 logo2.ico - 10.0.1 + 11.0 Technitium Technitium DNS Server Shreyas Zare diff --git a/DnsServerCore/DnsServerCore.csproj b/DnsServerCore/DnsServerCore.csproj index 7561cc4b..6e8ebc08 100644 --- a/DnsServerCore/DnsServerCore.csproj +++ b/DnsServerCore/DnsServerCore.csproj @@ -12,9 +12,32 @@ DnsServer - 10.0.1 + 11.0 + + + + + + + + + + + ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll + + + ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.ByteTree.dll + + + ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.IO.dll + + + ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll + + + @@ -28,19 +51,11 @@ - - - - - - - - @@ -61,12 +76,10 @@ - - @@ -113,30 +126,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - PreserveNewest @@ -206,9 +195,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -218,9 +204,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -247,27 +230,4 @@ - - - - - - - ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll - - - ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.ByteTree.dll - - - ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.IO.dll - - - ..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll - - - - - - - diff --git a/DnsServerWindowsService/DnsServerWindowsService.csproj b/DnsServerWindowsService/DnsServerWindowsService.csproj index f2b42956..c62ea5c5 100644 --- a/DnsServerWindowsService/DnsServerWindowsService.csproj +++ b/DnsServerWindowsService/DnsServerWindowsService.csproj @@ -8,7 +8,7 @@ DnsServerWindowsService DnsService logo2.ico - 10.0.1 + 11.0 Shreyas Zare Technitium Technitium DNS Server @@ -29,7 +29,7 @@ - + From 76e4ad73d728f50313fdb81f349175ce0d2920bf Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 17:57:42 +0530 Subject: [PATCH 191/191] updated changelog for v11.0 release. --- CHANGELOG.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a23c2faf..ff7a2177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Technitium DNS Server Change Log +## Version 11.0 +Release Date: 18 February 2022 + +- Added support for DNS-over-QUIC (DoQ) [RFC 9250](https://www.ietf.org/rfc/rfc9250.html). This allows you to run DoQ service as well as use it with Forwarders. DoQ implementation supports running over SOCKS5 proxy server that provides UDP transport. +- Added support for Zone Transfer over QUIC (XFR-over-QUIC) [RFC 9250](https://www.ietf.org/rfc/rfc9250.html). +- Updated DNS-over-HTTPS protocol implementation to support HTTP/2 and HTTP/3. DNS-over-HTTP/3 can be forced by using `h3` instead of `https` scheme for the URL. +- Updated DNS server's web service backend to use Kestrel web server and thus the DNS server now requires ASP.NET Core Runtime to be installed. With this change, the web service now supports both HTTP/2 and HTTP/3 protocols. If you are using HTTP API, it is recommended to test your code/script with the new release. +- Added support to save DNS cache data to disk on server shutdown and to reload it at startup. +- Updated DNS server domain name blocking feature to support Extended DNS Errors to show report on the blocked domain name. With this support added, the DNS Client tab on the web panel will show blocking report for any blocked domain name. +- Updated DNS server domain name blocking feature to support wildcard block lists file format and Adblock Plus file format. +- Updated DNS server to detect when an upstream server blocks a domain name to reflect it in dashboard stats and query logs. It will now detect blocking signal from Quad9 and show Extended DNS Error for it. +- Updated web panel Zones GUI to support pagination. +- Advanced Blocking App: Updated DNS app to support wildcard block lists file format. Updated the app to disable CNAME cloaking when a domain name is allowed in config. Implemented Extended DNS Errors support to show blocked domain report. +- Advanced Forwarding App: Added new DNS app to support bulk conditional forwarder. +- DNS Block List App: Added new DNS app to allow running your own DNSBL or RBL block lists [RFC 5782](https://www.rfc-editor.org/rfc/rfc5782). +- Added support for TFTP Server Address DHCP option (150). +- Added support for Generic DHCP option to allow configuring option currently not supported by the DHCP server. +- Removed support for non-standard DNS-over-HTTPS (JSON) protocol. +- Removed Newtonsoft.Json dependency from the DNS server and all DNS apps. +- Multiple other minor bug fixes and improvements. + ## Version 10.0.1 Release Date: 4 December 2022 @@ -18,7 +39,7 @@ Release Date: 26 November 2022 - Implemented EDNS Client Subnet (ECS) [RFC 7871](https://datatracker.ietf.org/doc/html/rfc7871) support for recursive resolution and forwarding. - Updated HTTP API to accept date time in ISO 8601 format for dashboard and query logs API calls. Any implementation that uses these API must test with new update before deploying to production. - Upgraded codebase to .NET 7 runtime. If you had manually installed the DNS Server or .NET 6 Runtime earlier then you must install .NET 7 Runtime manually before upgrading the DNS server. -- Fixed self-CNAME vulnerability reported by Xiang Li, [Network and Information Security Lab, Tsinghua University](https://netsec.ccert.edu.cn/) which caused the DNS server to follow CNAME in loop causing the answer to contain couple of hundred records before the loop limit was hit. +- Fixed self-CNAME vulnerability [CVE-2022-48256] reported by Xiang Li, [Network and Information Security Lab, Tsinghua University](https://netsec.ccert.edu.cn/) which caused the DNS server to follow CNAME in loop causing the answer to contain couple of hundred records before the loop limit was hit. - Updated DNS Apps framework with `IDnsPostProcessor` interface to allow manipulating outbound responses by DNS apps. - NO DATA App: Added new app to allow returning NO DATA response in Conditional Forwarder zones to allow overriding existing records from the forwarder for specified record types. - DNS64 App: Added new app to support DNS64 function [RFC 6147](https://www.rfc-editor.org/rfc/rfc6147) for use by IPv6 only clients.
    ").append(a("").attr({"data-action":"today",title:d.tooltips.today}).append(a("").addClass(d.icons.today)))),!d.sideBySide&&B()&&A()&&b.push(a("").append(a("").attr({"data-action":"togglePicker",title:d.tooltips.selectTime}).append(a("").addClass(d.icons.time)))),d.showClear&&b.push(a("").append(a("").attr({"data-action":"clear",title:d.tooltips.clear}).append(a("").addClass(d.icons.clear)))),d.showClose&&b.push(a("").append(a("").attr({"data-action":"close",title:d.tooltips.close}).append(a("").addClass(d.icons.close)))),a("").addClass("table-condensed").append(a("").append(a("").append(b)))},G=function(){var b=a("
    ").addClass("bootstrap-datetimepicker-widget dropdown-menu"),c=a("
    ").addClass("datepicker").append(C()),e=a("
    ").addClass("timepicker").append(E()),f=a("
      ").addClass("list-unstyled"),g=a("
    • ").addClass("picker-switch"+(d.collapse?" accordion-toggle":"")).append(F());return d.inline&&b.removeClass("dropdown-menu"),h&&b.addClass("usetwentyfour"),z("s")&&!h&&b.addClass("wider"),d.sideBySide&&B()&&A()?(b.addClass("timepicker-sbs"),"top"===d.toolbarPlacement&&b.append(g),b.append(a("
      ").addClass("row").append(c.addClass("col-md-6")).append(e.addClass("col-md-6"))),"bottom"===d.toolbarPlacement&&b.append(g),b):("top"===d.toolbarPlacement&&f.append(g),B()&&f.append(a("
    • ").addClass(d.collapse&&A()?"collapse in":"").append(c)),"default"===d.toolbarPlacement&&f.append(g),A()&&f.append(a("
    • ").addClass(d.collapse&&B()?"collapse":"").append(e)),"bottom"===d.toolbarPlacement&&f.append(g),b.append(f))},H=function(){var b,e={};return b=c.is("input")||d.inline?c.data():c.find("input").data(),b.dateOptions&&b.dateOptions instanceof Object&&(e=a.extend(!0,e,b.dateOptions)),a.each(d,function(a){var c="date"+a.charAt(0).toUpperCase()+a.slice(1);void 0!==b[c]&&(e[a]=b[c])}),e},I=function(){var b,e=(n||c).position(),f=(n||c).offset(),g=d.widgetPositioning.vertical,h=d.widgetPositioning.horizontal;if(d.widgetParent)b=d.widgetParent.append(o);else if(c.is("input"))b=c.after(o).parent();else{if(d.inline)return void(b=c.append(o));b=c,c.children().first().after(o)}if( -// Top and bottom logic -"auto"===g&&(g=f.top+1.5*o.height()>=a(window).height()+a(window).scrollTop()&&o.height()+c.outerHeight()a(window).width()?"right":"left"),"top"===g?o.addClass("top").removeClass("bottom"):o.addClass("bottom").removeClass("top"),"right"===h?o.addClass("pull-right"):o.removeClass("pull-right"), -// find the first parent element that has a relative css positioning -"relative"!==b.css("position")&&(b=b.parents().filter(function(){return"relative"===a(this).css("position")}).first()),0===b.length)throw new Error("datetimepicker component should be placed within a relative positioned container");o.css({top:"top"===g?"auto":e.top+c.outerHeight(),bottom:"top"===g?b.outerHeight()-(b===c?0:e.top):"auto",left:"left"===h?b===c?0:e.left:"auto",right:"left"===h?"auto":b.outerWidth()-c.outerWidth()-(b===c?0:e.left)})},J=function(a){"dp.change"===a.type&&(a.date&&a.date.isSame(a.oldDate)||!a.date&&!a.oldDate)||c.trigger(a)},K=function(a){"y"===a&&(a="YYYY"),J({type:"dp.update",change:a,viewDate:f.clone()})},L=function(a){o&&(a&&(k=Math.max(p,Math.min(3,k+a))),o.find(".datepicker > div").hide().filter(".datepicker-"+q[k].clsName).show())},M=function(){var b=a("
    "),c=f.clone().startOf("w").startOf("d");for(d.calendarWeeks===!0&&b.append(a(""),d.calendarWeeks&&c.append('"),k.push(c)),g="",b.isBefore(f,"M")&&(g+=" old"),b.isAfter(f,"M")&&(g+=" new"),b.isSame(e,"d")&&!m&&(g+=" active"),R(b,"d")||(g+=" disabled"),b.isSame(y(),"d")&&(g+=" today"),0!==b.day()&&6!==b.day()||(g+=" weekend"),c.append('"),b.add(1,"d");i.find("tbody").empty().append(k),T(),U(),V()}},X=function(){var b=o.find(".timepicker-hours table"),c=f.clone().startOf("d"),d=[],e=a("");for(f.hour()>11&&!h&&c.hour(12);c.isSame(f,"d")&&(h||f.hour()<12&&c.hour()<12||f.hour()>11);)c.hour()%4===0&&(e=a(""),d.push(e)),e.append('"),c.add(1,"h");b.empty().append(d)},Y=function(){for(var b=o.find(".timepicker-minutes table"),c=f.clone().startOf("h"),e=[],g=a(""),h=1===d.stepping?5:d.stepping;f.isSame(c,"h");)c.minute()%(4*h)===0&&(g=a(""),e.push(g)),g.append('"),c.add(h,"m");b.empty().append(e)},Z=function(){for(var b=o.find(".timepicker-seconds table"),c=f.clone().startOf("m"),d=[],e=a("");f.isSame(c,"m");)c.second()%20===0&&(e=a(""),d.push(e)),e.append('"),c.add(5,"s");b.empty().append(d)},$=function(){var a,b,c=o.find(".timepicker span[data-time-component]");h||(a=o.find(".timepicker [data-action=togglePeriod]"),b=e.clone().add(e.hours()>=12?-12:12,"h"),a.text(e.format("A")),R(b,"h")?a.removeClass("disabled"):a.addClass("disabled")),c.filter("[data-time-component=hours]").text(e.format(h?"HH":"hh")),c.filter("[data-time-component=minutes]").text(e.format("mm")),c.filter("[data-time-component=seconds]").text(e.format("ss")),X(),Y(),Z()},_=function(){o&&(W(),$())},aa=function(a){var b=m?null:e; -// case of calling setValue(null or false) -// case of calling setValue(null or false) -//viewDate = date.clone(); // TODO this doesn't work right on first use -return a?(a=a.clone().locale(d.locale),x()&&a.tz(d.timeZone),1!==d.stepping&&a.minutes(Math.round(a.minutes()/d.stepping)*d.stepping).seconds(0),void(R(a)?(e=a,g.val(e.format(i)),c.data("date",e.format(i)),m=!1,_(),J({type:"dp.change",date:e.clone(),oldDate:b})):(d.keepInvalid?J({type:"dp.change",date:a,oldDate:b}):g.val(m?"":e.format(i)),J({type:"dp.error",date:a,oldDate:b})))):(m=!0,g.val(""),c.data("date",""),J({type:"dp.change",date:!1,oldDate:b}),void _())},/** - * Hides the widget. Possibly will emit dp.hide - */ -ba=function(){var b=!1; -// Ignore event if in the middle of a picker transition -return o?(o.find(".collapse").each(function(){var c=a(this).data("collapse");return c&&c.transitioning?(b=!0,!1):!0}),b?l:(n&&n.hasClass("btn")&&n.toggleClass("active"),o.hide(),a(window).off("resize",I),o.off("click","[data-action]"),o.off("mousedown",!1),o.remove(),o=!1,J({type:"dp.hide",date:e.clone()}),g.blur(),k=0,f=e.clone(),l)):l},ca=function(){aa(null)},da=function(a){ -//inputDate.locale(options.locale); -return void 0===d.parseInputDate?b.isMoment(a)||(a=y(a)):a=d.parseInputDate(a),a},/******************************************************************************** - * - * Widget UI interaction functions - * - ********************************************************************************/ -ea={next:function(){var a=q[k].navFnc;f.add(q[k].navStep,a),W(),K(a)},previous:function(){var a=q[k].navFnc;f.subtract(q[k].navStep,a),W(),K(a)},pickerSwitch:function(){L(1)},selectMonth:function(b){var c=a(b.target).closest("tbody").find("span").index(a(b.target));f.month(c),k===p?(aa(e.clone().year(f.year()).month(f.month())),d.inline||ba()):(L(-1),W()),K("M")},selectYear:function(b){var c=parseInt(a(b.target).text(),10)||0;f.year(c),k===p?(aa(e.clone().year(f.year())),d.inline||ba()):(L(-1),W()),K("YYYY")},selectDecade:function(b){var c=parseInt(a(b.target).data("selection"),10)||0;f.year(c),k===p?(aa(e.clone().year(f.year())),d.inline||ba()):(L(-1),W()),K("YYYY")},selectDay:function(b){var c=f.clone();a(b.target).is(".old")&&c.subtract(1,"M"),a(b.target).is(".new")&&c.add(1,"M"),aa(c.date(parseInt(a(b.target).text(),10))),A()||d.keepOpen||d.inline||ba()},incrementHours:function(){var a=e.clone().add(1,"h");R(a,"h")&&aa(a)},incrementMinutes:function(){var a=e.clone().add(d.stepping,"m");R(a,"m")&&aa(a)},incrementSeconds:function(){var a=e.clone().add(1,"s");R(a,"s")&&aa(a)},decrementHours:function(){var a=e.clone().subtract(1,"h");R(a,"h")&&aa(a)},decrementMinutes:function(){var a=e.clone().subtract(d.stepping,"m");R(a,"m")&&aa(a)},decrementSeconds:function(){var a=e.clone().subtract(1,"s");R(a,"s")&&aa(a)},togglePeriod:function(){aa(e.clone().add(e.hours()>=12?-12:12,"h"))},togglePicker:function(b){var c,e=a(b.target),f=e.closest("ul"),g=f.find(".in"),h=f.find(".collapse:not(.in)");if(g&&g.length){if(c=g.data("collapse"),c&&c.transitioning)return;g.collapse?(// if collapse plugin is available through bootstrap.js then use it -g.collapse("hide"),h.collapse("show")):(// otherwise just toggle in class on the two views -g.removeClass("in"),h.addClass("in")),e.is("span")?e.toggleClass(d.icons.time+" "+d.icons.date):e.find("span").toggleClass(d.icons.time+" "+d.icons.date)}},showPicker:function(){o.find(".timepicker > div:not(.timepicker-picker)").hide(),o.find(".timepicker .timepicker-picker").show()},showHours:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-hours").show()},showMinutes:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-seconds").show()},selectHour:function(b){var c=parseInt(a(b.target).text(),10);h||(e.hours()>=12?12!==c&&(c+=12):12===c&&(c=0)),aa(e.clone().hours(c)),ea.showPicker.call(l)},selectMinute:function(b){aa(e.clone().minutes(parseInt(a(b.target).text(),10))),ea.showPicker.call(l)},selectSecond:function(b){aa(e.clone().seconds(parseInt(a(b.target).text(),10))),ea.showPicker.call(l)},clear:ca,today:function(){var a=y();R(a,"d")&&aa(a)},close:ba},fa=function(b){return a(b.currentTarget).is(".disabled")?!1:(ea[a(b.currentTarget).data("action")].apply(l,arguments),!1)},/** - * Shows the widget. Possibly will emit dp.show and dp.change - */ -ga=function(){var b,c={year:function(a){return a.month(0).date(1).hours(0).seconds(0).minutes(0)},month:function(a){return a.date(1).hours(0).seconds(0).minutes(0)},day:function(a){return a.hours(0).seconds(0).minutes(0)},hour:function(a){return a.seconds(0).minutes(0)},minute:function(a){return a.seconds(0)}};// this handles clicks on the widget -return g.prop("disabled")||!d.ignoreReadonly&&g.prop("readonly")||o?l:(void 0!==g.val()&&0!==g.val().trim().length?aa(da(g.val().trim())):m&&d.useCurrent&&(d.inline||g.is("input")&&0===g.val().trim().length)&&(b=y(),"string"==typeof d.useCurrent&&(b=c[d.useCurrent](b)),aa(b)),o=G(),M(),S(),o.find(".timepicker-hours").hide(),o.find(".timepicker-minutes").hide(),o.find(".timepicker-seconds").hide(),_(),L(),a(window).on("resize",I),o.on("click","[data-action]",fa),o.on("mousedown",!1),n&&n.hasClass("btn")&&n.toggleClass("active"),I(),o.show(),d.focusOnShow&&!g.is(":focus")&&g.focus(),J({type:"dp.show"}),l)},/** - * Shows or hides the widget - */ -ha=function(){return o?ba():ga()},ia=function(a){var b,c,e,f,g=null,h=[],i={},j=a.which,k="p";w[j]=k;for(b in w)w.hasOwnProperty(b)&&w[b]===k&&(h.push(b),parseInt(b,10)!==j&&(i[b]=!0));for(b in d.keyBinds)if(d.keyBinds.hasOwnProperty(b)&&"function"==typeof d.keyBinds[b]&&(e=b.split(" "),e.length===h.length&&v[j]===e[e.length-1])){for(f=!0,c=e.length-2;c>=0;c--)if(!(v[e[c]]in i)){f=!1;break}if(f){g=d.keyBinds[b];break}}g&&(g.call(l,o),a.stopPropagation(),a.preventDefault())},ja=function(a){w[a.which]="r",a.stopPropagation(),a.preventDefault()},ka=function(b){var c=a(b.target).val().trim(),d=c?da(c):null;return aa(d),b.stopImmediatePropagation(),!1},la=function(){g.on({change:ka,blur:d.debug?"":ba,keydown:ia,keyup:ja,focus:d.allowInputToggle?ga:""}),c.is("input")?g.on({focus:ga}):n&&(n.on("click",ha),n.on("mousedown",!1))},ma=function(){g.off({change:ka,blur:blur,keydown:ia,keyup:ja,focus:d.allowInputToggle?ba:""}),c.is("input")?g.off({focus:ga}):n&&(n.off("click",ha),n.off("mousedown",!1))},na=function(b){ -// Store given enabledDates and disabledDates as keys. -// This way we can check their existence in O(1) time instead of looping through whole array. -// (for example: options.enabledDates['2014-02-27'] === true) -var c={};return a.each(b,function(){var a=da(this);a.isValid()&&(c[a.format("YYYY-MM-DD")]=!0)}),Object.keys(c).length?c:!1},oa=function(b){ -// Store given enabledHours and disabledHours as keys. -// This way we can check their existence in O(1) time instead of looping through whole array. -// (for example: options.enabledHours['2014-02-27'] === true) -var c={};return a.each(b,function(){c[this]=!0}),Object.keys(c).length?c:!1},pa=function(){var a=d.format||"L LT";i=a.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){var b=e.localeData().longDateFormat(a)||a;return b.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){//temp fix for #740 -return e.localeData().longDateFormat(a)||a})}),j=d.extraFormats?d.extraFormats.slice():[],j.indexOf(a)<0&&j.indexOf(i)<0&&j.push(i),h=i.toLowerCase().indexOf("a")<1&&i.replace(/\[.*?\]/g,"").indexOf("h")<1,z("y")&&(p=2),z("M")&&(p=1),z("d")&&(p=0),k=Math.max(p,k),m||aa(e)}; -// initializing element and component attributes -if(/******************************************************************************** - * - * Public API functions - * ===================== - * - * Important: Do not expose direct references to private objects or the options - * object to the outer world. Always return a clone when returning values or make - * a clone when setting a private variable. - * - ********************************************************************************/ -l.destroy=function(){ -///Destroys the widget and removes all attached event listeners -ba(),ma(),c.removeData("DateTimePicker"),c.removeData("date")},l.toggle=ha,l.show=ga,l.hide=ba,l.disable=function(){ -///Disables the input element, the component is attached to, by adding a disabled="true" attribute to it. -///If the widget was visible before that call it is hidden. Possibly emits dp.hide -return ba(),n&&n.hasClass("btn")&&n.addClass("disabled"),g.prop("disabled",!0),l},l.enable=function(){ -///Enables the input element, the component is attached to, by removing disabled attribute from it. -return n&&n.hasClass("btn")&&n.removeClass("disabled"),g.prop("disabled",!1),l},l.ignoreReadonly=function(a){if(0===arguments.length)return d.ignoreReadonly;if("boolean"!=typeof a)throw new TypeError("ignoreReadonly () expects a boolean parameter");return d.ignoreReadonly=a,l},l.options=function(b){if(0===arguments.length)return a.extend(!0,{},d);if(!(b instanceof Object))throw new TypeError("options() options parameter should be an object");return a.extend(!0,d,b),a.each(d,function(a,b){if(void 0===l[a])throw new TypeError("option "+a+" is not recognized!");l[a](b)}),l},l.date=function(a){ -/// -///Returns the component's model current date, a moment object or null if not set. -///date.clone() -/// -/// -///Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration. -///Takes string, Date, moment, null parameter. -/// -if(0===arguments.length)return m?null:e.clone();if(!(null===a||"string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("date() parameter must be one of [null, string, moment or Date]");return aa(null===a?null:da(a)),l},l.format=function(a){ -///test su -///info about para -///returns foo -if(0===arguments.length)return d.format;if("string"!=typeof a&&("boolean"!=typeof a||a!==!1))throw new TypeError("format() expects a string or boolean:false parameter "+a);return d.format=a,i&&pa(),l},l.timeZone=function(a){if(0===arguments.length)return d.timeZone;if("string"!=typeof a)throw new TypeError("newZone() expects a string parameter");return d.timeZone=a,l},l.dayViewHeaderFormat=function(a){if(0===arguments.length)return d.dayViewHeaderFormat;if("string"!=typeof a)throw new TypeError("dayViewHeaderFormat() expects a string parameter");return d.dayViewHeaderFormat=a,l},l.extraFormats=function(a){if(0===arguments.length)return d.extraFormats;if(a!==!1&&!(a instanceof Array))throw new TypeError("extraFormats() expects an array or false parameter");return d.extraFormats=a,j&&pa(),l},l.disabledDates=function(b){ -/// -///Returns an array with the currently set disabled dates on the component. -///options.disabledDates -/// -/// -///Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of -///options.enabledDates if such exist. -///Takes an [ string or Date or moment ] of values and allows the user to select only from those days. -/// -if(0===arguments.length)return d.disabledDates?a.extend({},d.disabledDates):d.disabledDates;if(!b)return d.disabledDates=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledDates() expects an array parameter");return d.disabledDates=na(b),d.enabledDates=!1,_(),l},l.enabledDates=function(b){ -/// -///Returns an array with the currently set enabled dates on the component. -///options.enabledDates -/// -/// -///Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledDates if such exist. -///Takes an [ string or Date or moment ] of values and allows the user to select only from those days. -/// -if(0===arguments.length)return d.enabledDates?a.extend({},d.enabledDates):d.enabledDates;if(!b)return d.enabledDates=!1,_(),l;if(!(b instanceof Array))throw new TypeError("enabledDates() expects an array parameter");return d.enabledDates=na(b),d.disabledDates=!1,_(),l},l.daysOfWeekDisabled=function(a){if(0===arguments.length)return d.daysOfWeekDisabled.splice(0);if("boolean"==typeof a&&!a)return d.daysOfWeekDisabled=!1,_(),l;if(!(a instanceof Array))throw new TypeError("daysOfWeekDisabled() expects an array parameter");if(d.daysOfWeekDisabled=a.reduce(function(a,b){return b=parseInt(b,10),b>6||0>b||isNaN(b)?a:(-1===a.indexOf(b)&&a.push(b),a)},[]).sort(),d.useCurrent&&!d.keepInvalid){for(var b=0;!R(e,"d");){if(e.add(1,"d"),7===b)throw"Tried 7 times to find a valid date";b++}aa(e)}return _(),l},l.maxDate=function(a){if(0===arguments.length)return d.maxDate?d.maxDate.clone():d.maxDate;if("boolean"==typeof a&&a===!1)return d.maxDate=!1,_(),l;"string"==typeof a&&("now"!==a&&"moment"!==a||(a=y()));var b=da(a);if(!b.isValid())throw new TypeError("maxDate() Could not parse date parameter: "+a);if(d.minDate&&b.isBefore(d.minDate))throw new TypeError("maxDate() date parameter is before options.minDate: "+b.format(i));return d.maxDate=b,d.useCurrent&&!d.keepInvalid&&e.isAfter(a)&&aa(d.maxDate),f.isAfter(b)&&(f=b.clone().subtract(d.stepping,"m")),_(),l},l.minDate=function(a){if(0===arguments.length)return d.minDate?d.minDate.clone():d.minDate;if("boolean"==typeof a&&a===!1)return d.minDate=!1,_(),l;"string"==typeof a&&("now"!==a&&"moment"!==a||(a=y()));var b=da(a);if(!b.isValid())throw new TypeError("minDate() Could not parse date parameter: "+a);if(d.maxDate&&b.isAfter(d.maxDate))throw new TypeError("minDate() date parameter is after options.maxDate: "+b.format(i));return d.minDate=b,d.useCurrent&&!d.keepInvalid&&e.isBefore(a)&&aa(d.minDate),f.isBefore(b)&&(f=b.clone().add(d.stepping,"m")),_(),l},l.defaultDate=function(a){ -/// -///Returns a moment with the options.defaultDate option configuration or false if not set -///date.clone() -/// -/// -///Will set the picker's inital date. If a boolean:false value is passed the options.defaultDate parameter is cleared. -///Takes a string, Date, moment, boolean:false -/// -if(0===arguments.length)return d.defaultDate?d.defaultDate.clone():d.defaultDate;if(!a)return d.defaultDate=!1,l;"string"==typeof a&&(a="now"===a||"moment"===a?y():y(a));var b=da(a);if(!b.isValid())throw new TypeError("defaultDate() Could not parse date parameter: "+a);if(!R(b))throw new TypeError("defaultDate() date passed is invalid according to component setup validations");return d.defaultDate=b,(d.defaultDate&&d.inline||""===g.val().trim())&&aa(d.defaultDate),l},l.locale=function(a){if(0===arguments.length)return d.locale;if(!b.localeData(a))throw new TypeError("locale() locale "+a+" is not loaded from moment locales!");return d.locale=a,e.locale(d.locale),f.locale(d.locale),i&&pa(),o&&(ba(),ga()),l},l.stepping=function(a){return 0===arguments.length?d.stepping:(a=parseInt(a,10),(isNaN(a)||1>a)&&(a=1),d.stepping=a,l)},l.useCurrent=function(a){var b=["year","month","day","hour","minute"];if(0===arguments.length)return d.useCurrent;if("boolean"!=typeof a&&"string"!=typeof a)throw new TypeError("useCurrent() expects a boolean or string parameter");if("string"==typeof a&&-1===b.indexOf(a.toLowerCase()))throw new TypeError("useCurrent() expects a string parameter of "+b.join(", "));return d.useCurrent=a,l},l.collapse=function(a){if(0===arguments.length)return d.collapse;if("boolean"!=typeof a)throw new TypeError("collapse() expects a boolean parameter");return d.collapse===a?l:(d.collapse=a,o&&(ba(),ga()),l)},l.icons=function(b){if(0===arguments.length)return a.extend({},d.icons);if(!(b instanceof Object))throw new TypeError("icons() expects parameter to be an Object");return a.extend(d.icons,b),o&&(ba(),ga()),l},l.tooltips=function(b){if(0===arguments.length)return a.extend({},d.tooltips);if(!(b instanceof Object))throw new TypeError("tooltips() expects parameter to be an Object");return a.extend(d.tooltips,b),o&&(ba(),ga()),l},l.useStrict=function(a){if(0===arguments.length)return d.useStrict;if("boolean"!=typeof a)throw new TypeError("useStrict() expects a boolean parameter");return d.useStrict=a,l},l.sideBySide=function(a){if(0===arguments.length)return d.sideBySide;if("boolean"!=typeof a)throw new TypeError("sideBySide() expects a boolean parameter");return d.sideBySide=a,o&&(ba(),ga()),l},l.viewMode=function(a){if(0===arguments.length)return d.viewMode;if("string"!=typeof a)throw new TypeError("viewMode() expects a string parameter");if(-1===r.indexOf(a))throw new TypeError("viewMode() parameter must be one of ("+r.join(", ")+") value");return d.viewMode=a,k=Math.max(r.indexOf(a),p),L(),l},l.toolbarPlacement=function(a){if(0===arguments.length)return d.toolbarPlacement;if("string"!=typeof a)throw new TypeError("toolbarPlacement() expects a string parameter");if(-1===u.indexOf(a))throw new TypeError("toolbarPlacement() parameter must be one of ("+u.join(", ")+") value");return d.toolbarPlacement=a,o&&(ba(),ga()),l},l.widgetPositioning=function(b){if(0===arguments.length)return a.extend({},d.widgetPositioning);if("[object Object]"!=={}.toString.call(b))throw new TypeError("widgetPositioning() expects an object variable");if(b.horizontal){if("string"!=typeof b.horizontal)throw new TypeError("widgetPositioning() horizontal variable must be a string");if(b.horizontal=b.horizontal.toLowerCase(),-1===t.indexOf(b.horizontal))throw new TypeError("widgetPositioning() expects horizontal parameter to be one of ("+t.join(", ")+")");d.widgetPositioning.horizontal=b.horizontal}if(b.vertical){if("string"!=typeof b.vertical)throw new TypeError("widgetPositioning() vertical variable must be a string");if(b.vertical=b.vertical.toLowerCase(),-1===s.indexOf(b.vertical))throw new TypeError("widgetPositioning() expects vertical parameter to be one of ("+s.join(", ")+")");d.widgetPositioning.vertical=b.vertical}return _(),l},l.calendarWeeks=function(a){if(0===arguments.length)return d.calendarWeeks;if("boolean"!=typeof a)throw new TypeError("calendarWeeks() expects parameter to be a boolean value");return d.calendarWeeks=a,_(),l},l.showTodayButton=function(a){if(0===arguments.length)return d.showTodayButton;if("boolean"!=typeof a)throw new TypeError("showTodayButton() expects a boolean parameter");return d.showTodayButton=a,o&&(ba(),ga()),l},l.showClear=function(a){if(0===arguments.length)return d.showClear;if("boolean"!=typeof a)throw new TypeError("showClear() expects a boolean parameter");return d.showClear=a,o&&(ba(),ga()),l},l.widgetParent=function(b){if(0===arguments.length)return d.widgetParent;if("string"==typeof b&&(b=a(b)),null!==b&&"string"!=typeof b&&!(b instanceof a))throw new TypeError("widgetParent() expects a string or a jQuery object parameter");return d.widgetParent=b,o&&(ba(),ga()),l},l.keepOpen=function(a){if(0===arguments.length)return d.keepOpen;if("boolean"!=typeof a)throw new TypeError("keepOpen() expects a boolean parameter");return d.keepOpen=a,l},l.focusOnShow=function(a){if(0===arguments.length)return d.focusOnShow;if("boolean"!=typeof a)throw new TypeError("focusOnShow() expects a boolean parameter");return d.focusOnShow=a,l},l.inline=function(a){if(0===arguments.length)return d.inline;if("boolean"!=typeof a)throw new TypeError("inline() expects a boolean parameter");return d.inline=a,l},l.clear=function(){return ca(),l},l.keyBinds=function(a){return 0===arguments.length?d.keyBinds:(d.keyBinds=a,l)},l.getMoment=function(a){return y(a)},l.debug=function(a){if("boolean"!=typeof a)throw new TypeError("debug() expects a boolean parameter");return d.debug=a,l},l.allowInputToggle=function(a){if(0===arguments.length)return d.allowInputToggle;if("boolean"!=typeof a)throw new TypeError("allowInputToggle() expects a boolean parameter");return d.allowInputToggle=a,l},l.showClose=function(a){if(0===arguments.length)return d.showClose;if("boolean"!=typeof a)throw new TypeError("showClose() expects a boolean parameter");return d.showClose=a,l},l.keepInvalid=function(a){if(0===arguments.length)return d.keepInvalid;if("boolean"!=typeof a)throw new TypeError("keepInvalid() expects a boolean parameter");return d.keepInvalid=a,l},l.datepickerInput=function(a){if(0===arguments.length)return d.datepickerInput;if("string"!=typeof a)throw new TypeError("datepickerInput() expects a string parameter");return d.datepickerInput=a,l},l.parseInputDate=function(a){if(0===arguments.length)return d.parseInputDate;if("function"!=typeof a)throw new TypeError("parseInputDate() sholud be as function");return d.parseInputDate=a,l},l.disabledTimeIntervals=function(b){ -/// -///Returns an array with the currently set disabled dates on the component. -///options.disabledTimeIntervals -/// -/// -///Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of -///options.enabledDates if such exist. -///Takes an [ string or Date or moment ] of values and allows the user to select only from those days. -/// -if(0===arguments.length)return d.disabledTimeIntervals?a.extend({},d.disabledTimeIntervals):d.disabledTimeIntervals;if(!b)return d.disabledTimeIntervals=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledTimeIntervals() expects an array parameter");return d.disabledTimeIntervals=b,_(),l},l.disabledHours=function(b){ -/// -///Returns an array with the currently set disabled hours on the component. -///options.disabledHours -/// -/// -///Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of -///options.enabledHours if such exist. -///Takes an [ int ] of values and disallows the user to select only from those hours. -/// -if(0===arguments.length)return d.disabledHours?a.extend({},d.disabledHours):d.disabledHours;if(!b)return d.disabledHours=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledHours() expects an array parameter");if(d.disabledHours=oa(b),d.enabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!R(e,"h");){if(e.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}aa(e)}return _(),l},l.enabledHours=function(b){ -/// -///Returns an array with the currently set enabled hours on the component. -///options.enabledHours -/// -/// -///Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledHours if such exist. -///Takes an [ int ] of values and allows the user to select only from those hours. -/// -if(0===arguments.length)return d.enabledHours?a.extend({},d.enabledHours):d.enabledHours;if(!b)return d.enabledHours=!1,_(),l;if(!(b instanceof Array))throw new TypeError("enabledHours() expects an array parameter");if(d.enabledHours=oa(b),d.disabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!R(e,"h");){if(e.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}aa(e)}return _(),l},/** - * Returns the component's model current viewDate, a moment object or null if not set. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration. - * @param {Takes string, viewDate, moment, null parameter.} newDate - * @returns {viewDate.clone()} - */ -l.viewDate=function(a){if(0===arguments.length)return f.clone();if(!a)return f=e.clone(),l;if(!("string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("viewDate() parameter must be one of [string, moment or Date]");return f=da(a),K(),l},c.is("input"))g=c;else if(g=c.find(d.datepickerInput),0===g.length)g=c.find("input");else if(!g.is("input"))throw new Error('CSS class "'+d.datepickerInput+'" cannot be applied to non input element');if(c.hasClass("input-group")&&( -// in case there is more then one 'input-group-addon' Issue #48 -n=0===c.find(".datepickerbutton").length?c.find(".input-group-addon"):c.find(".datepickerbutton")),!d.inline&&!g.is("input"))throw new Error("Could not initialize DateTimePicker without an input element"); -// Set defaults for date here now instead of in var declaration -return e=y(),f=e.clone(),a.extend(!0,d,H()),l.options(d),pa(),la(),g.prop("disabled")&&l.disable(),g.is("input")&&0!==g.val().trim().length?aa(da(g.val().trim())):d.defaultDate&&void 0===g.attr("placeholder")&&aa(d.defaultDate),d.inline&&ga(),l};/******************************************************************************** - * - * jQuery plugin constructor and defaults object - * - ********************************************************************************/ -/** - * See (http://jquery.com/). - * @name jQuery - * @class - * See the jQuery Library (http://jquery.com/) for full details. This just - * documents the function and classes that are added to jQuery by this plug-in. - */ -/** - * See (http://jquery.com/) - * @name fn - * @class - * See the jQuery Library (http://jquery.com/) for full details. This just - * documents the function and classes that are added to jQuery by this plug-in. - * @memberOf jQuery - */ -/** - * Show comments - * @class datetimepicker - * @memberOf jQuery.fn - */ -a.fn.datetimepicker=function(b){b=b||{};var d,e=Array.prototype.slice.call(arguments,1),f=!0,g=["destroy","hide","show","toggle"];if("object"==typeof b)return this.each(function(){var d=a(this);d.data("DateTimePicker")||(b=a.extend(!0,{},a.fn.datetimepicker.defaults,b),d.data("DateTimePicker",c(d,b)))});if("string"==typeof b)return this.each(function(){var c=a(this),g=c.data("DateTimePicker");if(!g)throw new Error('bootstrap-datetimepicker("'+b+'") method was called on an element that is not using DateTimePicker');d=g[b].apply(g,e),f=d===g}),f||a.inArray(b,g)>-1?this:d;throw new TypeError("Invalid arguments for DateTimePicker: "+b)},a.fn.datetimepicker.defaults={timeZone:"",format:!1,dayViewHeaderFormat:"MMMM YYYY",extraFormats:!1,stepping:1,minDate:!1,maxDate:!1,useCurrent:!0,collapse:!0,locale:b.locale(),defaultDate:!1,disabledDates:!1,enabledDates:!1,icons:{time:"glyphicon glyphicon-time",date:"glyphicon glyphicon-calendar",up:"glyphicon glyphicon-chevron-up",down:"glyphicon glyphicon-chevron-down",previous:"glyphicon glyphicon-chevron-left",next:"glyphicon glyphicon-chevron-right",today:"glyphicon glyphicon-screenshot",clear:"glyphicon glyphicon-trash",close:"glyphicon glyphicon-remove"},tooltips:{today:"Go to today",clear:"Clear selection",close:"Close the picker",selectMonth:"Select Month",prevMonth:"Previous Month",nextMonth:"Next Month",selectYear:"Select Year",prevYear:"Previous Year",nextYear:"Next Year",selectDecade:"Select Decade",prevDecade:"Previous Decade",nextDecade:"Next Decade",prevCentury:"Previous Century",nextCentury:"Next Century",pickHour:"Pick Hour",incrementHour:"Increment Hour",decrementHour:"Decrement Hour",pickMinute:"Pick Minute",incrementMinute:"Increment Minute",decrementMinute:"Decrement Minute",pickSecond:"Pick Second",incrementSecond:"Increment Second",decrementSecond:"Decrement Second",togglePeriod:"Toggle Period",selectTime:"Select Time"},useStrict:!1,sideBySide:!1,daysOfWeekDisabled:!1,calendarWeeks:!1,viewMode:"days",toolbarPlacement:"default",showTodayButton:!1,showClear:!1,showClose:!1,widgetPositioning:{horizontal:"auto",vertical:"auto"},widgetParent:null,ignoreReadonly:!1,keepOpen:!1,focusOnShow:!0,inline:!1,keepInvalid:!1,datepickerInput:".datepickerinput",keyBinds:{up:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().subtract(7,"d")):this.date(b.clone().add(this.stepping(),"m"))}},down:function(a){if(!a)return void this.show();var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().add(7,"d")):this.date(b.clone().subtract(this.stepping(),"m"))},"control up":function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().subtract(1,"y")):this.date(b.clone().add(1,"h"))}},"control down":function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().add(1,"y")):this.date(b.clone().subtract(1,"h"))}},left:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().subtract(1,"d"))}},right:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().add(1,"d"))}},pageUp:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().subtract(1,"M"))}},pageDown:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().add(1,"M"))}},enter:function(){this.hide()},escape:function(){this.hide()}, -//tab: function (widget) { //this break the flow of the form. disabling for now -// var toggle = widget.find('.picker-switch a[data-action="togglePicker"]'); -// if(toggle.length > 0) toggle.click(); -//}, -"control space":function(a){a.find(".timepicker").is(":visible")&&a.find('.btn[data-action="togglePeriod"]').click()},t:function(){this.date(this.getMoment())},"delete":function(){this.clear()}},debug:!1,allowInputToggle:!1,disabledTimeIntervals:!1,disabledHours:!1,enabledHours:!1,viewDate:!1},"undefined"!=typeof module&&(module.exports=a.fn.datetimepicker)}); \ No newline at end of file diff --git a/DnsServerCore/www/js/jquery-ui.min.js b/DnsServerCore/www/js/jquery-ui.min.js deleted file mode 100644 index ab370a90..00000000 --- a/DnsServerCore/www/js/jquery-ui.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! jQuery UI - v1.12.1 - 2021-02-13 -* http://jqueryui.com -* Includes: keycode.js, widgets/datepicker.js -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e(jQuery)}(function(M){M.ui=M.ui||{};var r;M.ui.version="1.12.1",M.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38};function e(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},M.extend(this._defaults,this.regional[""]),this.regional.en=M.extend(!0,{},this.regional[""]),this.regional["en-US"]=M.extend(!0,{},this.regional.en),this.dpDiv=a(M("
    "))}function a(e){var t="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.on("mouseout",t,function(){M(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&M(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&M(this).removeClass("ui-datepicker-next-hover")}).on("mouseover",t,n)}function n(){M.datepicker._isDisabledDatepicker((r.inline?r.dpDiv.parent():r.input)[0])||(M(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),M(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&M(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&M(this).addClass("ui-datepicker-next-hover"))}function o(e,t){for(var a in M.extend(e,t),t)null==t[a]&&(e[a]=t[a]);return e}M.extend(M.ui,{datepicker:{version:"1.12.1"}}),M.extend(e.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(e){return o(this._defaults,e||{}),this},_attachDatepicker:function(e,t){var a,i=e.nodeName.toLowerCase(),s="div"===i||"span"===i;e.id||(this.uuid+=1,e.id="dp"+this.uuid),(a=this._newInst(M(e),s)).settings=M.extend({},t||{}),"input"===i?this._connectDatepicker(e,a):s&&this._inlineDatepicker(e,a)},_newInst:function(e,t){return{id:e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1"),input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:t,dpDiv:t?a(M("
    ")):this.dpDiv}},_connectDatepicker:function(e,t){var a=M(e);t.append=M([]),t.trigger=M([]),a.hasClass(this.markerClassName)||(this._attachments(a,t),a.addClass(this.markerClassName).on("keydown",this._doKeyDown).on("keypress",this._doKeyPress).on("keyup",this._doKeyUp),this._autoSize(t),M.data(e,"datepicker",t),t.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,t){var a,i=this._get(t,"appendText"),s=this._get(t,"isRTL");t.append&&t.append.remove(),i&&(t.append=M(""+i+""),e[s?"before":"after"](t.append)),e.off("focus",this._showDatepicker),t.trigger&&t.trigger.remove(),"focus"!==(a=this._get(t,"showOn"))&&"both"!==a||e.on("focus",this._showDatepicker),"button"!==a&&"both"!==a||(i=this._get(t,"buttonText"),a=this._get(t,"buttonImage"),t.trigger=M(this._get(t,"buttonImageOnly")?M("").addClass(this._triggerClass).attr({src:a,alt:i,title:i}):M("").addClass(this._triggerClass).html(a?M("").attr({src:a,alt:i,title:i}):i)),e[s?"before":"after"](t.trigger),t.trigger.on("click",function(){return M.datepicker._datepickerShowing&&M.datepicker._lastInput===e[0]?M.datepicker._hideDatepicker():(M.datepicker._datepickerShowing&&M.datepicker._lastInput!==e[0]&&M.datepicker._hideDatepicker(),M.datepicker._showDatepicker(e[0])),!1}))},_autoSize:function(e){var t,a,i,s,r,n;this._get(e,"autoSize")&&!e.inline&&(r=new Date(2009,11,20),(n=this._get(e,"dateFormat")).match(/[DM]/)&&(t=function(e){for(s=i=a=0;sa&&(a=e[s].length,i=s);return i},r.setMonth(t(this._get(e,n.match(/MM/)?"monthNames":"monthNamesShort"))),r.setDate(t(this._get(e,n.match(/DD/)?"dayNames":"dayNamesShort"))+20-r.getDay())),e.input.attr("size",this._formatDate(e,r).length))},_inlineDatepicker:function(e,t){var a=M(e);a.hasClass(this.markerClassName)||(a.addClass(this.markerClassName).append(t.dpDiv),M.data(e,"datepicker",t),this._setDate(t,this._getDefaultDate(t),!0),this._updateDatepicker(t),this._updateAlternate(t),t.settings.disabled&&this._disableDatepicker(e),t.dpDiv.css("display","block"))},_dialogDatepicker:function(e,t,a,i,s){var r,n=this._dialogInst;return n||(this.uuid+=1,r="dp"+this.uuid,this._dialogInput=M(""),this._dialogInput.on("keydown",this._doKeyDown),M("body").append(this._dialogInput),(n=this._dialogInst=this._newInst(this._dialogInput,!1)).settings={},M.data(this._dialogInput[0],"datepicker",n)),o(n.settings,i||{}),t=t&&t.constructor===Date?this._formatDate(n,t):t,this._dialogInput.val(t),this._pos=s?s.length?s:[s.pageX,s.pageY]:null,this._pos||(r=document.documentElement.clientWidth,i=document.documentElement.clientHeight,t=document.documentElement.scrollLeft||document.body.scrollLeft,s=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[r/2-100+t,i/2-150+s]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),n.settings.onSelect=a,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),M.blockUI&&M.blockUI(this.dpDiv),M.data(this._dialogInput[0],"datepicker",n),this},_destroyDatepicker:function(e){var t,a=M(e),i=M.data(e,"datepicker");a.hasClass(this.markerClassName)&&(t=e.nodeName.toLowerCase(),M.removeData(e,"datepicker"),"input"===t?(i.append.remove(),i.trigger.remove(),a.removeClass(this.markerClassName).off("focus",this._showDatepicker).off("keydown",this._doKeyDown).off("keypress",this._doKeyPress).off("keyup",this._doKeyUp)):"div"!==t&&"span"!==t||a.removeClass(this.markerClassName).empty(),r===i&&(r=null))},_enableDatepicker:function(t){var e,a=M(t),i=M.data(t,"datepicker");a.hasClass(this.markerClassName)&&("input"===(e=t.nodeName.toLowerCase())?(t.disabled=!1,i.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):"div"!==e&&"span"!==e||((a=a.children("."+this._inlineClass)).children().removeClass("ui-state-disabled"),a.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=M.map(this._disabledInputs,function(e){return e===t?null:e}))},_disableDatepicker:function(t){var e,a=M(t),i=M.data(t,"datepicker");a.hasClass(this.markerClassName)&&("input"===(e=t.nodeName.toLowerCase())?(t.disabled=!0,i.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):"div"!==e&&"span"!==e||((a=a.children("."+this._inlineClass)).children().addClass("ui-state-disabled"),a.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=M.map(this._disabledInputs,function(e){return e===t?null:e}),this._disabledInputs[this._disabledInputs.length]=t)},_isDisabledDatepicker:function(e){if(!e)return!1;for(var t=0;td&&io&&st;)--z<0&&(z=11,B--);for(e.drawMonth=z,e.drawYear=B,P=this._get(e,"prevText"),P=E?this.formatDate(P,this._daylightSavingAdjust(new Date(B,z-T,1)),this._getFormatConfig(e)):P,a=this._canAdjustMonth(e,-1,B,z)?""+P+"":O?"":""+P+"",P=this._get(e,"nextText"),P=E?this.formatDate(P,this._daylightSavingAdjust(new Date(B,z+T,1)),this._getFormatConfig(e)):P,i=this._canAdjustMonth(e,1,B,z)?""+P+"":O?"":""+P+"",O=this._get(e,"currentText"),P=this._get(e,"gotoCurrent")&&e.currentDay?W:A,O=E?this.formatDate(O,P,this._getFormatConfig(e)):O,E=e.inline?"":"",E=j?"
    "+(K?E:"")+(this._isInRange(e,P)?"":"")+(K?"":E)+"
    ":"",s=parseInt(this._get(e,"firstDay"),10),s=isNaN(s)?0:s,r=this._get(e,"showWeek"),n=this._get(e,"dayNames"),d=this._get(e,"dayNamesMin"),o=this._get(e,"monthNames"),c=this._get(e,"monthNamesShort"),l=this._get(e,"beforeShowDay"),h=this._get(e,"showOtherMonths"),u=this._get(e,"selectOtherMonths"),p=this._getDefaultDate(e),g="",f=0;f"+(/all|left/.test(b)&&0===f?K?i:a:"")+(/all|right/.test(b)&&0===f?K?a:i:"")+this._generateMonthYearHeader(e,z,B,H,U,0
    ").addClass("cw").text("#"));c.isBefore(f.clone().endOf("w"));)b.append(a("").addClass("dow").text(c.format("dd"))),c.add(1,"d");o.find(".datepicker-days thead").append(b)},N=function(a){return d.disabledDates[a.format("YYYY-MM-DD")]===!0},O=function(a){return d.enabledDates[a.format("YYYY-MM-DD")]===!0},P=function(a){return d.disabledHours[a.format("H")]===!0},Q=function(a){return d.enabledHours[a.format("H")]===!0},R=function(b,c){if(!b.isValid())return!1;if(d.disabledDates&&"d"===c&&N(b))return!1;if(d.enabledDates&&"d"===c&&!O(b))return!1;if(d.minDate&&b.isBefore(d.minDate,c))return!1;if(d.maxDate&&b.isAfter(d.maxDate,c))return!1;if(d.daysOfWeekDisabled&&"d"===c&&-1!==d.daysOfWeekDisabled.indexOf(b.day()))return!1;if(d.disabledHours&&("h"===c||"m"===c||"s"===c)&&P(b))return!1;if(d.enabledHours&&("h"===c||"m"===c||"s"===c)&&!Q(b))return!1;if(d.disabledTimeIntervals&&("h"===c||"m"===c||"s"===c)){var e=!1;if(a.each(d.disabledTimeIntervals,function(){return b.isBetween(this[0],this[1])?(e=!0,!1):void 0}),e)return!1}return!0},S=function(){for(var b=[],c=f.clone().startOf("y").startOf("d");c.isSame(f,"y");)b.push(a("").attr("data-action","selectMonth").addClass("month").text(c.format("MMM"))),c.add(1,"M");o.find(".datepicker-months td").empty().append(b)},T=function(){var b=o.find(".datepicker-months"),c=b.find("th"),g=b.find("tbody").find("span");c.eq(0).find("span").attr("title",d.tooltips.prevYear),c.eq(1).attr("title",d.tooltips.selectYear),c.eq(2).find("span").attr("title",d.tooltips.nextYear),b.find(".disabled").removeClass("disabled"),R(f.clone().subtract(1,"y"),"y")||c.eq(0).addClass("disabled"),c.eq(1).text(f.year()),R(f.clone().add(1,"y"),"y")||c.eq(2).addClass("disabled"),g.removeClass("active"),e.isSame(f,"y")&&!m&&g.eq(e.month()).addClass("active"),g.each(function(b){R(f.clone().month(b),"M")||a(this).addClass("disabled")})},U=function(){var a=o.find(".datepicker-years"),b=a.find("th"),c=f.clone().subtract(5,"y"),g=f.clone().add(6,"y"),h="";for(b.eq(0).find("span").attr("title",d.tooltips.prevDecade),b.eq(1).attr("title",d.tooltips.selectDecade),b.eq(2).find("span").attr("title",d.tooltips.nextDecade),a.find(".disabled").removeClass("disabled"),d.minDate&&d.minDate.isAfter(c,"y")&&b.eq(0).addClass("disabled"),b.eq(1).text(c.year()+"-"+g.year()),d.maxDate&&d.maxDate.isBefore(g,"y")&&b.eq(2).addClass("disabled");!c.isAfter(g,"y");)h+=''+c.year()+"",c.add(1,"y");a.find("td").html(h)},V=function(){var a,c=o.find(".datepicker-decades"),g=c.find("th"),h=b({y:f.year()-f.year()%100-1}),i=h.clone().add(100,"y"),j=h.clone(),k=!1,l=!1,m="";for(g.eq(0).find("span").attr("title",d.tooltips.prevCentury),g.eq(2).find("span").attr("title",d.tooltips.nextCentury),c.find(".disabled").removeClass("disabled"),(h.isSame(b({y:1900}))||d.minDate&&d.minDate.isAfter(h,"y"))&&g.eq(0).addClass("disabled"),g.eq(1).text(h.year()+"-"+i.year()),(h.isSame(b({y:2e3}))||d.maxDate&&d.maxDate.isBefore(i,"y"))&&g.eq(2).addClass("disabled");!h.isAfter(i,"y");)a=h.year()+12,k=d.minDate&&d.minDate.isAfter(h,"y")&&d.minDate.year()<=a,l=d.maxDate&&d.maxDate.isAfter(h,"y")&&d.maxDate.year()<=a,m+=''+(h.year()+1)+" - "+(h.year()+12)+"",h.add(12,"y");m+="",c.find("td").html(m),g.eq(1).text(j.year()+1+"-"+h.year())},W=function(){var b,c,g,h,i=o.find(".datepicker-days"),j=i.find("th"),k=[];if(B()){for(j.eq(0).find("span").attr("title",d.tooltips.prevMonth),j.eq(1).attr("title",d.tooltips.selectMonth),j.eq(2).find("span").attr("title",d.tooltips.nextMonth),i.find(".disabled").removeClass("disabled"),j.eq(1).text(f.format(d.dayViewHeaderFormat)),R(f.clone().subtract(1,"M"),"M")||j.eq(0).addClass("disabled"),R(f.clone().add(1,"M"),"M")||j.eq(2).addClass("disabled"),b=f.clone().startOf("M").startOf("w").startOf("d"),h=0;42>h;h++)//always display 42 days (should show 6 weeks) -0===b.weekday()&&(c=a("
    '+b.week()+"'+b.date()+"
    '+c.format(h?"HH":"hh")+"
    '+c.format("mm")+"
    '+c.format("ss")+"
    ",v=r?"":"",_=0;_<7;_++)v+="";for(y+=v+"",w=this._getDaysInMonth(B,z),B===e.selectedYear&&z===e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,w)),b=(this._getFirstDayOfMonth(B,z)-s+7)%7,w=Math.ceil((b+w)/7),C=L&&this.maxRows>w?this.maxRows:w,this.maxRows=C,I=this._daylightSavingAdjust(new Date(B,z,1-b)),x=0;x",Y=r?"":"",_=0;_<7;_++)S=l?l.apply(e.input?e.input[0]:null,[I]):[!0,""],F=(N=I.getMonth()!==z)&&!u||!S[0]||H&&I"+(N&&!h?" ":F?""+I.getDate()+"":""+I.getDate()+"")+"",I.setDate(I.getDate()+1),I=this._daylightSavingAdjust(I);y+=Y+""}11<++z&&(z=0,B++),k+=y+="
    "+this._get(e,"weekHeader")+""+d[M]+"
    "+this._get(e,"calculateWeek")(I)+"
    "+(L?""+(0":""):"")}g+=k}return g+=E,e._keyEvent=!1,g},_generateMonthYearHeader:function(e,t,a,i,s,r,n,d){var o,c,l,h,u,p,g,_=this._get(e,"changeMonth"),f=this._get(e,"changeYear"),k=this._get(e,"showMonthAfterYear"),D="
    ",m="";if(r||!_)m+=""+n[t]+"";else{for(o=i&&i.getFullYear()===a,c=s&&s.getFullYear()===a,m+=""}if(k||(D+=m+(!r&&_&&f?"":" ")),!e.yearshtml)if(e.yearshtml="",r||!f)D+=""+a+"";else{for(h=this._get(e,"yearRange").split(":"),u=(new Date).getFullYear(),p=(n=function(e){e=e.match(/c[+\-].*/)?a+parseInt(e.substring(1),10):e.match(/[+\-].*/)?u+parseInt(e,10):parseInt(e,10);return isNaN(e)?u:e})(h[0]),g=Math.max(p,n(h[1]||"")),p=i?Math.max(p,i.getFullYear()):p,g=s?Math.min(g,s.getFullYear()):g,e.yearshtml+="",D+=e.yearshtml,e.yearshtml=null}return D+=this._get(e,"yearSuffix"),k&&(D+=(!r&&_&&f?"":" ")+m),D+="
    "},_adjustInstDate:function(e,t,a){var i=e.selectedYear+("Y"===a?t:0),s=e.selectedMonth+("M"===a?t:0),t=Math.min(e.selectedDay,this._getDaysInMonth(i,s))+("D"===a?t:0),t=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(i,s,t)));e.selectedDay=t.getDate(),e.drawMonth=e.selectedMonth=t.getMonth(),e.drawYear=e.selectedYear=t.getFullYear(),"M"!==a&&"Y"!==a||this._notifyChange(e)},_restrictMinMax:function(e,t){var a=this._getMinMaxDate(e,"min"),e=this._getMinMaxDate(e,"max"),t=a&&t=a.getTime())&&(!i||t.getTime()<=i.getTime())&&(!s||t.getFullYear()>=s)&&(!r||t.getFullYear()<=r)},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return{shortYearCutoff:t="string"!=typeof t?t:(new Date).getFullYear()%100+parseInt(t,10),dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,a,i){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);t=t?"object"==typeof t?t:this._daylightSavingAdjust(new Date(i,a,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),t,this._getFormatConfig(e))}}),M.fn.datepicker=function(e){if(!this.length)return this;M.datepicker.initialized||(M(document).on("mousedown",M.datepicker._checkExternalClick),M.datepicker.initialized=!0),0===M("#"+M.datepicker._mainDivId).length&&M("body").append(M.datepicker.dpDiv);var t=Array.prototype.slice.call(arguments,1);return"string"==typeof e&&("isDisabled"===e||"getDate"===e||"widget"===e)||"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?M.datepicker["_"+e+"Datepicker"].apply(M.datepicker,[this[0]].concat(t)):this.each(function(){"string"==typeof e?M.datepicker["_"+e+"Datepicker"].apply(M.datepicker,[this].concat(t)):M.datepicker._attachDatepicker(this,e)})},M.datepicker=new e,M.datepicker.initialized=!1,M.datepicker.uuid=(new Date).getTime(),M.datepicker.version="1.12.1";M.datepicker}); \ No newline at end of file From 8101086ec1e42d317280e9b60c7551368f92d013 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:26:07 +0530 Subject: [PATCH 060/191] webapp: updated jquery. --- DnsServerCore/dohwww/js/jquery.min.js | 4 ++-- DnsServerCore/www/js/jquery.min.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DnsServerCore/dohwww/js/jquery.min.js b/DnsServerCore/dohwww/js/jquery.min.js index c4c6022f..b5329e9a 100644 --- a/DnsServerCore/dohwww/js/jquery.min.js +++ b/DnsServerCore/dohwww/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,S)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=E)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{if(d.cssSupportsSelector&&!CSS.supports("selector(:is("+c+"))"))throw new Error;return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===E&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[E]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,S=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.cssSupportsSelector=ce(function(){return CSS.supports("selector(*)")&&C.querySelectorAll(":is(:jqfake)")&&!CSS.supports("selector(:is(*,:jqfake))")}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=E,!C.getElementsByName||!C.getElementsByName(E).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&S)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+E+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+E+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),d.cssSupportsSelector||y.push(":has"),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType&&e.documentElement||e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&S&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:S,!0)),N.test(r[1])&&E.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=S.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,D=E(S);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=S.createDocumentFragment().appendChild(S.createElement("div")),(fe=S.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),S.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;E.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||E.expando+"_"+Ct.guid++;return this[e]=!0,e}}),E.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||E.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?E(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=S.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Ut.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=S.implementation.createHTMLDocument("")).createElement("base")).href=S.location.href,t.head.appendChild(r)):t=S),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(E.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},E.expr.pseudos.animated=function(t){return E.grep(E.timers,function(e){return t===e.elem}).length},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){E.fn[t]=function(e){return this.on(t,e)}}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,S)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=E)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{if(d.cssSupportsSelector&&!CSS.supports("selector(:is("+c+"))"))throw new Error;return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===E&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[E]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,S=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.cssSupportsSelector=ce(function(){return CSS.supports("selector(*)")&&C.querySelectorAll(":is(:jqfake)")&&!CSS.supports("selector(:is(*,:jqfake))")}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=E,!C.getElementsByName||!C.getElementsByName(E).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&S)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+E+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+E+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),d.cssSupportsSelector||y.push(":has"),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType&&e.documentElement||e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&S&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:S,!0)),N.test(r[1])&&E.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=S.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,D=E(S);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=S.createDocumentFragment().appendChild(S.createElement("div")),(fe=S.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),S.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;E.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||E.expando+"_"+Ct.guid++;return this[e]=!0,e}}),E.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||E.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?E(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=S.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Ut.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=S.implementation.createHTMLDocument("")).createElement("base")).href=S.location.href,t.head.appendChild(r)):t=S),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(E.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},E.expr.pseudos.animated=function(t){return E.grep(E.timers,function(e){return t===e.elem}).length},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){E.fn[t]=function(e){return this.on(t,e)}}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0 Date: Sat, 14 Jan 2023 13:32:31 +0530 Subject: [PATCH 061/191] User: updated LoggedInFrom() to convert ipv6 mapped ipv4 address. --- DnsServerCore/Auth/User.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DnsServerCore/Auth/User.cs b/DnsServerCore/Auth/User.cs index f1ae2b0d..32b6fd60 100644 --- a/DnsServerCore/Auth/User.cs +++ b/DnsServerCore/Auth/User.cs @@ -165,6 +165,9 @@ namespace DnsServerCore.Auth public void LoggedInFrom(IPAddress remoteAddress) { + if (remoteAddress.IsIPv4MappedToIPv6) + remoteAddress = remoteAddress.MapToIPv4(); + _previousSessionLoggedOn = _recentSessionLoggedOn; _previousSessionRemoteAddress = _recentSessionRemoteAddress; From 31f35a5a224d49ac1874bbe225dd1ccc477236b8 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:33:14 +0530 Subject: [PATCH 062/191] UserSession: updated code to convert ipv6 mapped ipv4 address. --- DnsServerCore/Auth/UserSession.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DnsServerCore/Auth/UserSession.cs b/DnsServerCore/Auth/UserSession.cs index 14d5d1aa..8aefa269 100644 --- a/DnsServerCore/Auth/UserSession.cs +++ b/DnsServerCore/Auth/UserSession.cs @@ -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 @@ -56,6 +56,9 @@ namespace DnsServerCore.Auth if ((tokenName is not null) && (tokenName.Length > 255)) throw new ArgumentOutOfRangeException(nameof(tokenName), "Token name length cannot exceed 255 characters."); + if (remoteAddress.IsIPv4MappedToIPv6) + remoteAddress = remoteAddress.MapToIPv4(); + byte[] tokenBytes = new byte[32]; _rng.GetBytes(tokenBytes); _token = Convert.ToHexString(tokenBytes).ToLower(); @@ -104,6 +107,9 @@ namespace DnsServerCore.Auth public void UpdateLastSeen(IPAddress remoteAddress, string lastSeenUserAgent) { + if (remoteAddress.IsIPv4MappedToIPv6) + remoteAddress = remoteAddress.MapToIPv4(); + _lastSeen = DateTime.UtcNow; _lastSeenRemoteAddress = remoteAddress; _lastSeenUserAgent = lastSeenUserAgent; From 45781d38186a067f8c135c8803ea6ea8de697a05 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:34:23 +0530 Subject: [PATCH 063/191] DhcpServer: code refactoring changes. --- DnsServerCore/Dhcp/DhcpServer.cs | 133 ++++++++++--------------------- 1 file changed, 40 insertions(+), 93 deletions(-) diff --git a/DnsServerCore/Dhcp/DhcpServer.cs b/DnsServerCore/Dhcp/DhcpServer.cs index b7567527..98639e03 100644 --- a/DnsServerCore/Dhcp/DhcpServer.cs +++ b/DnsServerCore/Dhcp/DhcpServer.cs @@ -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 @@ -130,11 +130,9 @@ namespace DnsServerCore.Dhcp { Stop(); - if (_saveModifiedDnsAuthZonesTimer is not null) - _saveModifiedDnsAuthZonesTimer.Dispose(); + _saveModifiedDnsAuthZonesTimer?.Dispose(); - if (_maintenanceTimer is not null) - _maintenanceTimer.Dispose(); + _maintenanceTimer?.Dispose(); if (_scopes is not null) { @@ -204,9 +202,7 @@ namespace DnsServerCore.Dhcp } catch (Exception ex) { - LogManager log = _log; - if (log != null) - log.Write(result.RemoteEndPoint as IPEndPoint, ex); + _log?.Write(result.RemoteEndPoint as IPEndPoint, ex); } } } @@ -224,9 +220,7 @@ namespace DnsServerCore.Dhcp break; //server stopping default: - LogManager log = _log; - if (log != null) - log.Write(ex); + _log?.Write(ex); throw; } @@ -236,9 +230,7 @@ namespace DnsServerCore.Dhcp if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) return; //server stopping - LogManager log = _log; - if (log != null) - log.Write(ex); + _log?.Write(ex); throw; } @@ -292,9 +284,7 @@ namespace DnsServerCore.Dhcp if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) return; //server stopping - LogManager log = _log; - if (log != null) - log.Write(remoteEP, ex); + _log?.Write(remoteEP, ex); } } @@ -343,9 +333,7 @@ namespace DnsServerCore.Dhcp return null; //log ip offer - LogManager log = _log; - if (log != null) - log.Write(remoteEP, "DHCP Server offered IP address [" + offer.Address.ToString() + "] to " + request.GetClientFullIdentifier() + " for scope: " + scope.Name); + _log?.Write(remoteEP, "DHCP Server offered IP address [" + offer.Address.ToString() + "] to " + request.GetClientFullIdentifier() + " for scope: " + scope.Name); return DhcpMessage.CreateReply(request, offer.Address, scope.ServerAddress ?? serverIdentifierAddress, scope.ServerHostName, scope.BootFileName, options); } @@ -481,9 +469,7 @@ namespace DnsServerCore.Dhcp scope.CommitLease(leaseOffer); //log ip lease - LogManager log = _log; - if (log != null) - log.Write(remoteEP, "DHCP Server leased IP address [" + leaseOffer.Address.ToString() + "] to " + request.GetClientFullIdentifier() + " for scope: " + scope.Name); + _log?.Write(remoteEP, "DHCP Server leased IP address [" + leaseOffer.Address.ToString() + "] to " + request.GetClientFullIdentifier() + " for scope: " + scope.Name); if (string.IsNullOrWhiteSpace(scope.DomainName)) { @@ -553,9 +539,7 @@ namespace DnsServerCore.Dhcp scope.ReleaseLease(lease); //log issue - LogManager log = _log; - if (log != null) - log.Write(remoteEP, "DHCP Server received DECLINE message for scope '" + scope.Name + "': " + lease.GetClientInfo() + " detected that IP address [" + lease.Address + "] is already in use."); + _log?.Write(remoteEP, "DHCP Server received DECLINE message for scope '" + scope.Name + "': " + lease.GetClientInfo() + " detected that IP address [" + lease.Address + "] is already in use."); //update dns UpdateDnsAuthZone(false, scope, lease); @@ -591,9 +575,7 @@ namespace DnsServerCore.Dhcp scope.ReleaseLease(lease); //log ip lease release - LogManager log = _log; - if (log != null) - log.Write(remoteEP, "DHCP Server released IP address [" + lease.Address.ToString() + "] that was leased to " + lease.GetClientInfo() + " for scope: " + scope.Name); + _log?.Write(remoteEP, "DHCP Server released IP address [" + lease.Address.ToString() + "] that was leased to " + lease.GetClientInfo() + " for scope: " + scope.Name); //update dns UpdateDnsAuthZone(false, scope, lease); @@ -613,9 +595,7 @@ namespace DnsServerCore.Dhcp IPAddress serverIdentifierAddress = scope.InterfaceAddress.Equals(IPAddress.Any) ? ipPacketInformation.Address : scope.InterfaceAddress; //log inform - LogManager log = _log; - if (log != null) - log.Write(remoteEP, "DHCP Server received INFORM message from " + request.GetClientFullIdentifier() + " for scope: " + scope.Name); + _log?.Write(remoteEP, "DHCP Server received INFORM message from " + request.GetClientFullIdentifier() + " for scope: " + scope.Name); List options = await scope.GetOptionsAsync(request, serverIdentifierAddress, null, _dnsServer); if (options is null) @@ -752,7 +732,6 @@ namespace DnsServerCore.Dhcp string zoneName = null; string reverseDomain = Zone.GetReverseZone(address, 32); string reverseZoneName = null; - LogManager log = _log; if (add) { @@ -764,7 +743,7 @@ namespace DnsServerCore.Dhcp zoneInfo = _dnsServer.AuthZoneManager.CreatePrimaryZone(scope.DomainName, _dnsServer.ServerDomain, false); if (zoneInfo is null) { - log?.Write("DHCP Server failed to create DNS primary zone '" + scope.DomainName + "'."); + _log?.Write("DHCP Server failed to create DNS primary zone '" + scope.DomainName + "'."); return; } @@ -774,7 +753,7 @@ namespace DnsServerCore.Dhcp _authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _authManager.GetGroup(Group.DHCP_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _authManager.SaveConfigFile(); - log?.Write("DHCP Server create DNS primary zone '" + zoneInfo.Name + "'."); + _log?.Write("DHCP Server create DNS primary zone '" + zoneInfo.Name + "'."); _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } else if ((zoneInfo.Type != AuthZoneType.Primary) && (zoneInfo.Type != AuthZoneType.Forwarder)) @@ -786,7 +765,7 @@ namespace DnsServerCore.Dhcp zoneInfo = _dnsServer.AuthZoneManager.CreatePrimaryZone(scope.DomainName, _dnsServer.ServerDomain, false); if (zoneInfo is null) { - log?.Write("DHCP Server failed to create DNS primary zone '" + scope.DomainName + "'."); + _log?.Write("DHCP Server failed to create DNS primary zone '" + scope.DomainName + "'."); return; } @@ -796,7 +775,7 @@ namespace DnsServerCore.Dhcp _authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _authManager.GetGroup(Group.DHCP_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _authManager.SaveConfigFile(); - log?.Write("DHCP Server create DNS primary zone '" + zoneInfo.Name + "'."); + _log?.Write("DHCP Server create DNS primary zone '" + zoneInfo.Name + "'."); _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } @@ -821,7 +800,7 @@ namespace DnsServerCore.Dhcp } _dnsServer.AuthZoneManager.SetRecords(zoneName, domain, DnsResourceRecordType.A, scope.DnsTtl, new DnsResourceRecordData[] { new DnsARecordData(address) }); - log?.Write("DHCP Server updated DNS A record '" + domain + "' with IP address [" + address.ToString() + "]."); + _log?.Write("DHCP Server updated DNS A record '" + domain + "' with IP address [" + address.ToString() + "]."); //update reverse zone AuthZoneInfo reverseZoneInfo = _dnsServer.AuthZoneManager.FindAuthZoneInfo(reverseDomain); @@ -833,7 +812,7 @@ namespace DnsServerCore.Dhcp reverseZoneInfo = _dnsServer.AuthZoneManager.CreatePrimaryZone(reverseZone, _dnsServer.ServerDomain, false); if (reverseZoneInfo is null) { - log?.Write("DHCP Server failed to create DNS primary zone '" + reverseZone + "'."); + _log?.Write("DHCP Server failed to create DNS primary zone '" + reverseZone + "'."); return; } @@ -843,7 +822,7 @@ namespace DnsServerCore.Dhcp _authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _authManager.GetGroup(Group.DHCP_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _authManager.SaveConfigFile(); - log?.Write("DHCP Server create DNS primary zone '" + reverseZoneInfo.Name + "'."); + _log?.Write("DHCP Server create DNS primary zone '" + reverseZoneInfo.Name + "'."); _dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); } else if ((reverseZoneInfo.Type != AuthZoneType.Primary) && (reverseZoneInfo.Type != AuthZoneType.Forwarder)) @@ -857,7 +836,7 @@ namespace DnsServerCore.Dhcp reverseZoneInfo = _dnsServer.AuthZoneManager.CreatePrimaryZone(reverseZone, _dnsServer.ServerDomain, false); if (reverseZoneInfo is null) { - log?.Write("DHCP Server failed to create DNS primary zone '" + reverseZone + "'."); + _log?.Write("DHCP Server failed to create DNS primary zone '" + reverseZone + "'."); return; } @@ -867,13 +846,13 @@ namespace DnsServerCore.Dhcp _authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _authManager.GetGroup(Group.DHCP_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); _authManager.SaveConfigFile(); - log?.Write("DHCP Server create DNS primary zone '" + reverseZoneInfo.Name + "'."); + _log?.Write("DHCP Server create DNS primary zone '" + reverseZoneInfo.Name + "'."); _dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); } reverseZoneName = reverseZoneInfo.Name; _dnsServer.AuthZoneManager.SetRecords(reverseZoneName, reverseDomain, DnsResourceRecordType.PTR, scope.DnsTtl, new DnsResourceRecordData[] { new DnsPTRRecordData(domain) }); - log?.Write("DHCP Server updated DNS PTR record '" + reverseDomain + "' with domain name '" + domain + "'."); + _log?.Write("DHCP Server updated DNS PTR record '" + reverseDomain + "' with domain name '" + domain + "'."); } else { @@ -884,7 +863,7 @@ namespace DnsServerCore.Dhcp //primary zone exists zoneName = zoneInfo.Name; _dnsServer.AuthZoneManager.DeleteRecord(zoneName, domain, DnsResourceRecordType.A, new DnsARecordData(address)); - log?.Write("DHCP Server deleted DNS A record '" + domain + "' with address [" + address.ToString() + "]."); + _log?.Write("DHCP Server deleted DNS A record '" + domain + "' with address [" + address.ToString() + "]."); } //remove from reverse zone @@ -894,7 +873,7 @@ namespace DnsServerCore.Dhcp //primary reverse zone exists reverseZoneName = reverseZoneInfo.Name; _dnsServer.AuthZoneManager.DeleteRecord(reverseZoneName, reverseDomain, DnsResourceRecordType.PTR, new DnsPTRRecordData(domain)); - log?.Write("DHCP Server deleted DNS PTR record '" + reverseDomain + "' with domain '" + domain + "'."); + _log?.Write("DHCP Server deleted DNS PTR record '" + reverseDomain + "' with domain '" + domain + "'."); } } @@ -908,9 +887,7 @@ namespace DnsServerCore.Dhcp } catch (Exception ex) { - LogManager log = _log; - if (log != null) - log.Write(ex); + _log?.Write(ex); } } @@ -936,9 +913,7 @@ namespace DnsServerCore.Dhcp } catch (Exception ex) { - LogManager log = _log; - if (log != null) - log.Write(ex); + _log?.Write(ex); } } } @@ -1076,17 +1051,13 @@ namespace DnsServerCore.Dhcp UpdateDnsAuthZone(utcNow < lease.Value.LeaseExpires, scope, lease.Value); //lease valid } - LogManager log = _log; - if (log != null) - log.Write(dhcpEP, "DHCP Server successfully activated scope: " + scope.Name); + _log?.Write(dhcpEP, "DHCP Server successfully activated scope: " + scope.Name); return true; } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(dhcpEP, "DHCP Server failed to activate scope: " + scope.Name + "\r\n" + ex.ToString()); + _log?.Write(dhcpEP, "DHCP Server failed to activate scope: " + scope.Name + "\r\n" + ex.ToString()); if (throwException) throw; @@ -1116,17 +1087,13 @@ namespace DnsServerCore.Dhcp UpdateDnsAuthZone(false, scope, lease.Value); } - LogManager log = _log; - if (log != null) - log.Write(dhcpEP, "DHCP Server successfully deactivated scope: " + scope.Name); + _log?.Write(dhcpEP, "DHCP Server successfully deactivated scope: " + scope.Name); return true; } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(dhcpEP, "DHCP Server failed to deactivate scope: " + scope.Name + "\r\n" + ex.ToString()); + _log?.Write(dhcpEP, "DHCP Server failed to deactivate scope: " + scope.Name + "\r\n" + ex.ToString()); if (throwException) throw; @@ -1154,9 +1121,7 @@ namespace DnsServerCore.Dhcp scope.SetEnabled(false); } - LogManager log = _log; - if (log != null) - log.Write("DHCP Server successfully loaded scope: " + scope.Name); + _log?.Write("DHCP Server successfully loaded scope: " + scope.Name); } private void UnloadScope(Scope scope) @@ -1168,9 +1133,7 @@ namespace DnsServerCore.Dhcp { removedScope.Dispose(); - LogManager log = _log; - if (log != null) - log.Write("DHCP Server successfully unloaded scope: " + scope.Name); + _log?.Write("DHCP Server successfully unloaded scope: " + scope.Name); } } @@ -1194,15 +1157,11 @@ namespace DnsServerCore.Dhcp await LoadScopeAsync(new Scope(new BinaryReader(fS), _log), true); } - LogManager log = _log; - if (log != null) - log.Write("DHCP Server successfully loaded scope file: " + scopeFile); + _log?.Write("DHCP Server successfully loaded scope file: " + scopeFile); } catch (Exception ex) { - LogManager log = _log; - if (log != null) - log.Write("DHCP Server failed to load scope file: " + scopeFile + "\r\n" + ex.ToString()); + _log?.Write("DHCP Server failed to load scope file: " + scopeFile + "\r\n" + ex.ToString()); } } @@ -1217,15 +1176,11 @@ namespace DnsServerCore.Dhcp scope.WriteTo(new BinaryWriter(fS)); } - LogManager log = _log; - if (log != null) - log.Write("DHCP Server successfully saved scope file: " + scopeFile); + _log?.Write("DHCP Server successfully saved scope file: " + scopeFile); } catch (Exception ex) { - LogManager log = _log; - if (log != null) - log.Write("DHCP Server failed to save scope file: " + scopeFile + "\r\n" + ex.ToString()); + _log?.Write("DHCP Server failed to save scope file: " + scopeFile + "\r\n" + ex.ToString()); } } @@ -1237,15 +1192,11 @@ namespace DnsServerCore.Dhcp { File.Delete(scopeFile); - LogManager log = _log; - if (log != null) - log.Write("DHCP Server successfully deleted scope file: " + scopeFile); + _log?.Write("DHCP Server successfully deleted scope file: " + scopeFile); } catch (Exception ex) { - LogManager log = _log; - if (log != null) - log.Write("DHCP Server failed to delete scope file: " + scopeFile + "\r\n" + ex.ToString()); + _log?.Write("DHCP Server failed to delete scope file: " + scopeFile + "\r\n" + ex.ToString()); } } @@ -1277,9 +1228,7 @@ namespace DnsServerCore.Dhcp List expiredLeases = scope.Value.RemoveExpiredLeases(); if (expiredLeases.Count > 0) { - LogManager log = _log; - if (log != null) - log.Write("DHCP Server removed " + expiredLeases.Count + " lease(s) from scope: " + scope.Value.Name); + _log?.Write("DHCP Server removed " + expiredLeases.Count + " lease(s) from scope: " + scope.Value.Name); foreach (Lease expiredLease in expiredLeases) UpdateDnsAuthZone(false, scope.Value, expiredLease); @@ -1290,9 +1239,7 @@ namespace DnsServerCore.Dhcp } catch (Exception ex) { - LogManager log = _log; - if (log != null) - log.Write(ex); + _log?.Write(ex); } finally { From f1437de06d72ef63228bd8b6981b50c0d8548a1c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:35:11 +0530 Subject: [PATCH 064/191] DnssecPrivateKey: code refactoring changes. --- DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs b/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs index eb750bf8..59041496 100644 --- a/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs +++ b/DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs @@ -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 @@ -201,7 +201,7 @@ namespace DnsServerCore.Dns.Dnssec } } - public static DnssecPrivateKey Parse(BinaryReader bR) + public static DnssecPrivateKey ReadFrom(BinaryReader bR) { if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "DK") throw new InvalidDataException("DNSSEC private key format is invalid."); From 23e944410d45a08cd0f07787cbe1336d76a95d21 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:37:32 +0530 Subject: [PATCH 065/191] DnsResourceRecordInfo: renamed to AuthRecordInfo. updated code to remove variables used by cache records. Added xfr-over-quic support. Minor changes done. --- ...esourceRecordInfo.cs => AuthRecordInfo.cs} | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) rename DnsServerCore/Dns/ResourceRecords/{DnsResourceRecordInfo.cs => AuthRecordInfo.cs} (88%) diff --git a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/AuthRecordInfo.cs similarity index 88% rename from DnsServerCore/Dns/ResourceRecords/DnsResourceRecordInfo.cs rename to DnsServerCore/Dns/ResourceRecords/AuthRecordInfo.cs index c561518b..1648df49 100644 --- a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordInfo.cs +++ b/DnsServerCore/Dns/ResourceRecords/AuthRecordInfo.cs @@ -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 @@ -22,16 +22,17 @@ using System.Collections.Generic; using System.IO; using System.Net; using TechnitiumLibrary.IO; -using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore.Dns.ResourceRecords { - class DnsResourceRecordInfo + class AuthRecordInfo { #region variables + public static readonly AuthRecordInfo Default = new AuthRecordInfo(); + bool _disabled; IReadOnlyList _glueRecords; string _comments; @@ -40,19 +41,16 @@ namespace DnsServerCore.Dns.ResourceRecords DnsTransportProtocol _zoneTransferProtocol; string _tsigKeyName = string.Empty; - IReadOnlyList _rrsigRecords; //not serialized - IReadOnlyList _nsecRecords; //not serialized - NetworkAddress _eDnsClientSubnet; //not serialized DateTime _lastUsedOn; //not serialized #endregion #region constructor - public DnsResourceRecordInfo() + public AuthRecordInfo() { } - public DnsResourceRecordInfo(BinaryReader bR, bool isSoa) + public AuthRecordInfo(BinaryReader bR, bool isSoa) { byte version = bR.ReadByte(); switch (version) @@ -155,7 +153,7 @@ namespace DnsServerCore.Dns.ResourceRecords break; default: - throw new InvalidDataException("DnsResourceRecordInfo format version not supported."); + throw new InvalidDataException("AuthRecordInfo format version not supported."); } } @@ -217,7 +215,13 @@ namespace DnsServerCore.Dns.ResourceRecords public IReadOnlyList GlueRecords { get { return _glueRecords; } - set { _glueRecords = value; } + set + { + if ((value is null) || (value.Count == 0)) + _glueRecords = null; + else + _glueRecords = value; + } } public string Comments @@ -241,7 +245,13 @@ namespace DnsServerCore.Dns.ResourceRecords public IReadOnlyList PrimaryNameServers { get { return _primaryNameServers; } - set { _primaryNameServers = value; } + set + { + if ((value is null) || (value.Count == 0)) + _primaryNameServers = null; + else + _primaryNameServers = value; + } } public DnsTransportProtocol ZoneTransferProtocol @@ -253,6 +263,7 @@ namespace DnsServerCore.Dns.ResourceRecords { case DnsTransportProtocol.Tcp: case DnsTransportProtocol.Tls: + case DnsTransportProtocol.Quic: _zoneTransferProtocol = value; break; @@ -274,24 +285,6 @@ namespace DnsServerCore.Dns.ResourceRecords } } - public IReadOnlyList RRSIGRecords - { - get { return _rrsigRecords; } - set { _rrsigRecords = value; } - } - - public IReadOnlyList NSECRecords - { - get { return _nsecRecords; } - set { _nsecRecords = value; } - } - - public NetworkAddress EDnsClientSubnet - { - get { return _eDnsClientSubnet; } - set { _eDnsClientSubnet = value; } - } - public DateTime LastUsedOn { get { return _lastUsedOn; } From 09e479eb55c9d6acf9d272eee941dbe2b394f0ab Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:38:42 +0530 Subject: [PATCH 066/191] CacheRecordInfo: added class to hold record info for cache records. --- .../Dns/ResourceRecords/CacheRecordInfo.cs | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 DnsServerCore/Dns/ResourceRecords/CacheRecordInfo.cs diff --git a/DnsServerCore/Dns/ResourceRecords/CacheRecordInfo.cs b/DnsServerCore/Dns/ResourceRecords/CacheRecordInfo.cs new file mode 100644 index 00000000..bcbaa383 --- /dev/null +++ b/DnsServerCore/Dns/ResourceRecords/CacheRecordInfo.cs @@ -0,0 +1,199 @@ +/* +Technitium DNS Server +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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using TechnitiumLibrary.Net; +using TechnitiumLibrary.Net.Dns.ResourceRecords; + +namespace DnsServerCore.Dns.ResourceRecords +{ + class CacheRecordInfo + { + #region variables + + public static readonly CacheRecordInfo Default = new CacheRecordInfo(); + + IReadOnlyList _glueRecords; + IReadOnlyList _rrsigRecords; + IReadOnlyList _nsecRecords; + NetworkAddress _eDnsClientSubnet; + + DateTime _lastUsedOn; //not serialized + + #endregion + + #region constructor + + public CacheRecordInfo() + { } + + public CacheRecordInfo(BinaryReader bR) + { + byte version = bR.ReadByte(); + switch (version) + { + case 1: + _glueRecords = ReadRecordsFrom(bR, true); + _rrsigRecords = ReadRecordsFrom(bR, false); + _nsecRecords = ReadRecordsFrom(bR, true); + + if (bR.ReadBoolean()) + _eDnsClientSubnet = NetworkAddress.ReadFrom(bR); + + break; + + default: + throw new InvalidDataException("CacheRecordInfo format version not supported."); + } + } + + #endregion + + #region private + + private static IReadOnlyList ReadRecordsFrom(BinaryReader bR, bool includeInnerRRSigRecords) + { + int count = bR.ReadByte(); + if (count == 0) + return null; + + DnsResourceRecord[] records = new DnsResourceRecord[count]; + + for (int i = 0; i < count; i++) + { + records[i] = DnsResourceRecord.ReadCacheRecordFrom(bR, delegate (DnsResourceRecord record) + { + if (includeInnerRRSigRecords) + { + IReadOnlyList rrsigRecords = ReadRecordsFrom(bR, false); + if (rrsigRecords is not null) + record.GetCacheRecordInfo()._rrsigRecords = rrsigRecords; + } + }); + } + + return records; + } + + private static void WriteRecordsTo(IReadOnlyList records, BinaryWriter bW, bool includeInnerRRSigRecords) + { + if (records is null) + { + bW.Write((byte)0); + } + else + { + bW.Write(Convert.ToByte(records.Count)); + + foreach (DnsResourceRecord record in records) + { + record.WriteCacheRecordTo(bW, delegate () + { + if (includeInnerRRSigRecords) + { + if (record.Tag is CacheRecordInfo cacheRecordInfo) + WriteRecordsTo(cacheRecordInfo._rrsigRecords, bW, false); + else + bW.Write((byte)0); + } + }); + } + } + } + + #endregion + + #region public + + public void WriteTo(BinaryWriter bW) + { + bW.Write((byte)1); //version + + WriteRecordsTo(_glueRecords, bW, true); + WriteRecordsTo(_rrsigRecords, bW, false); + WriteRecordsTo(_nsecRecords, bW, true); + + if (_eDnsClientSubnet is null) + { + bW.Write(false); + } + else + { + bW.Write(true); + _eDnsClientSubnet.WriteTo(bW); + } + } + + #endregion + + #region properties + + public IReadOnlyList GlueRecords + { + get { return _glueRecords; } + set + { + if ((value is null) || (value.Count == 0)) + _glueRecords = null; + else + _glueRecords = value; + } + } + + public IReadOnlyList RRSIGRecords + { + get { return _rrsigRecords; } + set + { + if ((value is null) || (value.Count == 0)) + _rrsigRecords = null; + else + _rrsigRecords = value; + } + } + + public IReadOnlyList NSECRecords + { + get { return _nsecRecords; } + set + { + if ((value is null) || (value.Count == 0)) + _nsecRecords = null; + else + _nsecRecords = value; + } + } + + public NetworkAddress EDnsClientSubnet + { + get { return _eDnsClientSubnet; } + set { _eDnsClientSubnet = value; } + } + + public DateTime LastUsedOn + { + get { return _lastUsedOn; } + set { _lastUsedOn = value; } + } + + #endregion + } +} From bbe9aebfa0c79b7dae9067a6cf4992ad0eeed1aa Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:41:02 +0530 Subject: [PATCH 067/191] DnsResourceRecordExtension: removed get/set type of extension methods. --- .../DnsResourceRecordExtension.cs | 161 +++--------------- 1 file changed, 24 insertions(+), 137 deletions(-) diff --git a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs index ce5e017a..05d9492d 100644 --- a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs +++ b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs @@ -23,53 +23,37 @@ using System.Linq; using System.Net; using System.Net.Sockets; using TechnitiumLibrary; -using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore.Dns.ResourceRecords { static class DnsResourceRecordExtension { - public static void SetGlueRecords(this DnsResourceRecord record, IReadOnlyList glueRecords) - { - if (record.Tag is not DnsResourceRecordInfo rrInfo) - { - rrInfo = new DnsResourceRecordInfo(); - record.Tag = rrInfo; - } - - rrInfo.GlueRecords = glueRecords; - } - public static void SetGlueRecords(this DnsResourceRecord record, string glueAddresses) - { - SetGlueRecords(record, glueAddresses.Split(IPAddress.Parse, ',')); - } - - public static void SetGlueRecords(this DnsResourceRecord record, IReadOnlyList glueAddresses) { if (record.RDATA is not DnsNSRecordData nsRecord) throw new InvalidOperationException(); string domain = nsRecord.NameServer; - DnsResourceRecord[] glueRecords = new DnsResourceRecord[glueAddresses.Count]; + IReadOnlyList glueAddressesList = glueAddresses.Split(IPAddress.Parse, ','); + DnsResourceRecord[] glueRecords = new DnsResourceRecord[glueAddressesList.Count]; for (int i = 0; i < glueRecords.Length; i++) { - switch (glueAddresses[i].AddressFamily) + switch (glueAddressesList[i].AddressFamily) { case AddressFamily.InterNetwork: - glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.A, DnsClass.IN, record.TTL, new DnsARecordData(glueAddresses[i])); + glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.A, DnsClass.IN, record.TTL, new DnsARecordData(glueAddressesList[i])); break; case AddressFamily.InterNetworkV6: - glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN, record.TTL, new DnsAAAARecordData(glueAddresses[i])); + glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN, record.TTL, new DnsAAAARecordData(glueAddressesList[i])); break; } } - SetGlueRecords(record, glueRecords); + record.GetAuthRecordInfo().GlueRecords = glueRecords; } public static void SyncGlueRecords(this DnsResourceRecord record, IReadOnlyList allGlueRecords) @@ -94,10 +78,7 @@ namespace DnsServerCore.Dns.ResourceRecords } } - if (foundGlueRecords.Count > 0) - SetGlueRecords(record, foundGlueRecords); - else - SetGlueRecords(record, Array.Empty()); + record.GetAuthRecordInfo().GlueRecords = foundGlueRecords; } public static void SyncGlueRecords(this DnsResourceRecord record, IReadOnlyCollection deletedGlueRecords, IReadOnlyCollection addedGlueRecords) @@ -108,14 +89,16 @@ namespace DnsServerCore.Dns.ResourceRecords bool updated = false; List updatedGlueRecords = new List(); - IReadOnlyList existingGlueRecords = GetGlueRecords(record); - - foreach (DnsResourceRecord existingGlueRecord in existingGlueRecords) + IReadOnlyList existingGlueRecords = record.GetAuthRecordInfo().GlueRecords; + if (existingGlueRecords is not null) { - if (deletedGlueRecords.Contains(existingGlueRecord)) - updated = true; //skipped to delete existing glue record - else - updatedGlueRecords.Add(existingGlueRecord); + foreach (DnsResourceRecord existingGlueRecord in existingGlueRecords) + { + if (deletedGlueRecords.Contains(existingGlueRecord)) + updated = true; //skipped to delete existing glue record + else + updatedGlueRecords.Add(existingGlueRecord); + } } string domain = nsRecord.NameServer; @@ -136,121 +119,25 @@ namespace DnsServerCore.Dns.ResourceRecords } if (updated) - SetGlueRecords(record, updatedGlueRecords); + record.GetAuthRecordInfo().GlueRecords = updatedGlueRecords; } - public static IReadOnlyList GetGlueRecords(this DnsResourceRecord record) + public static AuthRecordInfo GetAuthRecordInfo(this DnsResourceRecord record) { - if (record.Tag is DnsResourceRecordInfo rrInfo) + if (record.Tag is not AuthRecordInfo rrInfo) { - IReadOnlyList glueRecords = rrInfo.GlueRecords; - if (glueRecords is null) - return Array.Empty(); - - return glueRecords; - } - - return Array.Empty(); - } - - public static bool IsDisabled(this DnsResourceRecord record) - { - if (record.Tag is DnsResourceRecordInfo rrInfo) - return rrInfo.Disabled; - - return false; - } - - public static void Disable(this DnsResourceRecord record) - { - if (record.Tag is not DnsResourceRecordInfo rrInfo) - { - rrInfo = new DnsResourceRecordInfo(); + rrInfo = new AuthRecordInfo(); record.Tag = rrInfo; } - rrInfo.Disabled = true; + return rrInfo; } - public static void Enable(this DnsResourceRecord record) + public static CacheRecordInfo GetCacheRecordInfo(this DnsResourceRecord record) { - if (record.Tag is DnsResourceRecordInfo rrInfo) - rrInfo.Disabled = false; - } - - public static string GetComments(this DnsResourceRecord record) - { - if (record.Tag is DnsResourceRecordInfo rrInfo) - return rrInfo.Comments; - - return null; - } - - public static void SetComments(this DnsResourceRecord record, string value) - { - if (record.Tag is not DnsResourceRecordInfo rrInfo) + if (record.Tag is not CacheRecordInfo rrInfo) { - rrInfo = new DnsResourceRecordInfo(); - record.Tag = rrInfo; - } - - rrInfo.Comments = value; - } - - public static DateTime GetDeletedOn(this DnsResourceRecord record) - { - if (record.Tag is DnsResourceRecordInfo rrInfo) - return rrInfo.DeletedOn; - - return DateTime.MinValue; - } - - public static void SetDeletedOn(this DnsResourceRecord record, DateTime value) - { - if (record.Tag is not DnsResourceRecordInfo rrInfo) - { - rrInfo = new DnsResourceRecordInfo(); - record.Tag = rrInfo; - } - - rrInfo.DeletedOn = value; - } - - public static void SetPrimaryNameServers(this DnsResourceRecord record, IReadOnlyList primaryNameServers) - { - if (record.Tag is not DnsResourceRecordInfo rrInfo) - { - rrInfo = new DnsResourceRecordInfo(); - record.Tag = rrInfo; - } - - rrInfo.PrimaryNameServers = primaryNameServers; - } - - public static void SetPrimaryNameServers(this DnsResourceRecord record, string primaryNameServers) - { - SetPrimaryNameServers(record, primaryNameServers.Split(NameServerAddress.Parse, ',')); - } - - public static IReadOnlyList GetPrimaryNameServers(this DnsResourceRecord record) - { - if (record.Tag is DnsResourceRecordInfo rrInfo) - { - IReadOnlyList primaryNameServers = rrInfo.PrimaryNameServers; - if (primaryNameServers is null) - return Array.Empty(); - - return primaryNameServers; - } - - return Array.Empty(); - } - - public static DnsResourceRecordInfo GetRecordInfo(this DnsResourceRecord record) - { - if (record.Tag is not DnsResourceRecordInfo rrInfo) - { - rrInfo = new DnsResourceRecordInfo(); + rrInfo = new CacheRecordInfo(); record.Tag = rrInfo; } From a09582d0e1dc1087f2d34845cd2083beaf4df4d8 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:41:44 +0530 Subject: [PATCH 068/191] minor refactoring change. --- ...esourceRecordExtension.cs => DnsResourceRecordExtensions.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename DnsServerCore/Dns/ResourceRecords/{DnsResourceRecordExtension.cs => DnsResourceRecordExtensions.cs} (99%) diff --git a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtensions.cs similarity index 99% rename from DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs rename to DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtensions.cs index 05d9492d..671823d1 100644 --- a/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtension.cs +++ b/DnsServerCore/Dns/ResourceRecords/DnsResourceRecordExtensions.cs @@ -27,7 +27,7 @@ using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore.Dns.ResourceRecords { - static class DnsResourceRecordExtension + static class DnsResourceRecordExtensions { public static void SetGlueRecords(this DnsResourceRecord record, string glueAddresses) { From a9e457fa6e12545ec9fa4937d2404e53c0857629 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 13:44:35 +0530 Subject: [PATCH 069/191] AuthZoneManager: updated code as per refactoring changes for record info. --- .../Dns/ZoneManagers/AuthZoneManager.cs | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs index 327cd7f0..f55d5c23 100644 --- a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs @@ -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 @@ -329,8 +329,8 @@ namespace DnsServerCore.Dns.ZoneManagers switch (refRecord.Type) { case DnsResourceRecordType.NS: - IReadOnlyList glueRecords = refRecord.GetGlueRecords(); - if (glueRecords.Count > 0) + IReadOnlyList glueRecords = refRecord.GetAuthRecordInfo().GlueRecords; + if (glueRecords is not null) { additionalRecords.AddRange(glueRecords); } @@ -383,7 +383,7 @@ namespace DnsServerCore.Dns.ZoneManagers DateTime utcNow = DateTime.UtcNow; foreach (DnsResourceRecord record in authority) - record.GetRecordInfo().LastUsedOn = utcNow; + record.GetAuthRecordInfo().LastUsedOn = utcNow; } else { @@ -1027,7 +1027,8 @@ namespace DnsServerCore.Dns.ZoneManagers foreach (DnsResourceRecord record in records) { - if (record.IsDisabled()) + AuthRecordInfo authRecordInfo = record.GetAuthRecordInfo(); + if (authRecordInfo.Disabled) continue; switch (record.Type) @@ -1038,9 +1039,12 @@ namespace DnsServerCore.Dns.ZoneManagers case DnsResourceRecordType.NS: xfrRecords.Add(record); - foreach (DnsResourceRecord glueRecord in record.GetGlueRecords()) - xfrRecords.Add(glueRecord); - + IReadOnlyList glueRecords = authRecordInfo.GlueRecords; + if (glueRecords is not null) + { + foreach (DnsResourceRecord glueRecord in glueRecords) + xfrRecords.Add(glueRecord); + } break; default: @@ -2078,7 +2082,7 @@ namespace DnsServerCore.Dns.ZoneManagers for (int i = 0; i < records.Length; i++) { records[i] = new DnsResourceRecord(s); - records[i].Tag = new DnsResourceRecordInfo(bR, records[i].Type == DnsResourceRecordType.SOA); + records[i].Tag = new AuthRecordInfo(bR, records[i].Type == DnsResourceRecordType.SOA); if (records[i].Type == DnsResourceRecordType.SOA) soaRecord = records[i]; @@ -2136,7 +2140,7 @@ namespace DnsServerCore.Dns.ZoneManagers for (int i = 0; i < records.Length; i++) { records[i] = new DnsResourceRecord(s); - records[i].Tag = new DnsResourceRecordInfo(bR, records[i].Type == DnsResourceRecordType.SOA); + records[i].Tag = new AuthRecordInfo(bR, records[i].Type == DnsResourceRecordType.SOA); } try @@ -2205,8 +2209,8 @@ namespace DnsServerCore.Dns.ZoneManagers { record.WriteTo(s); - if (record.Tag is not DnsResourceRecordInfo rrInfo) - rrInfo = new DnsResourceRecordInfo(); //default info + if (record.Tag is not AuthRecordInfo rrInfo) + rrInfo = AuthRecordInfo.Default; //default info rrInfo.WriteTo(bW); } From b6dae0ad7d5c373f503bf5542ee6ea2b22457098 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:18:48 +0530 Subject: [PATCH 070/191] BlockListZoneManager: updated UpdateBlockListsAsync() to use all decompression methods. --- DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs index 656e220f..bc09a64f 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs @@ -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 @@ -322,7 +322,7 @@ namespace DnsServerCore.Dns.ZoneManagers SocketsHttpHandler handler = new SocketsHttpHandler(); handler.Proxy = _dnsServer.Proxy; handler.UseProxy = _dnsServer.Proxy is not null; - handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + handler.AutomaticDecompression = DecompressionMethods.All; using (HttpClient http = new HttpClient(handler)) { From b8622f2055549bf35d017abff8c704eac04b8e83 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:21:45 +0530 Subject: [PATCH 071/191] CacheZoneManager: updated implementation to use CacheRecordInfo. Implemented LoadCacheZoneFile(), SaveCacheZoneFile(), and DeleteCacheZoneFile() to add support for saving dns cache on disk. --- .../Dns/ZoneManagers/CacheZoneManager.cs | 97 ++++++++++++++++--- 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs index fe06fe96..75470fc1 100644 --- a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs @@ -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 @@ -22,6 +22,8 @@ using DnsServerCore.Dns.Trees; using DnsServerCore.Dns.Zones; using System; using System.Collections.Generic; +using System.IO; +using System.Text; using System.Threading; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; @@ -80,7 +82,7 @@ namespace DnsServerCore.Dns.ZoneManagers if ((glueRecords is not null) || (rrsigRecords is not null) || (nsecRecords is not null) || (eDnsClientSubnet is not null)) { - DnsResourceRecordInfo rrInfo = resourceRecord.GetRecordInfo(); + CacheRecordInfo rrInfo = resourceRecord.GetCacheRecordInfo(); rrInfo.GlueRecords = glueRecords; rrInfo.RRSIGRecords = rrsigRecords; @@ -93,7 +95,7 @@ namespace DnsServerCore.Dns.ZoneManagers { IReadOnlyList glueRRSIGRecords = GetRRSIGRecordsFrom(glueRecord); if (glueRRSIGRecords is not null) - glueRecord.GetRecordInfo().RRSIGRecords = glueRRSIGRecords; + glueRecord.GetCacheRecordInfo().RRSIGRecords = glueRRSIGRecords; } } @@ -103,7 +105,7 @@ namespace DnsServerCore.Dns.ZoneManagers { IReadOnlyList nsecRRSIGRecords = GetRRSIGRecordsFrom(nsecRecord); if (nsecRRSIGRecords is not null) - nsecRecord.GetRecordInfo().RRSIGRecords = nsecRRSIGRecords; + nsecRecord.GetCacheRecordInfo().RRSIGRecords = nsecRRSIGRecords; } } } @@ -191,7 +193,7 @@ namespace DnsServerCore.Dns.ZoneManagers } //no DS records found check for NSEC records - IReadOnlyList nsecRecords = nsRecords[0].GetRecordInfo().NSECRecords; + IReadOnlyList nsecRecords = nsRecords[0].GetCacheRecordInfo().NSECRecords; if (nsecRecords is not null) { List newNSRecords = new List(nsRecords.Count + nsecRecords.Count); @@ -215,7 +217,7 @@ namespace DnsServerCore.Dns.ZoneManagers { newAnswerList.Add(record); - DnsResourceRecordInfo rrInfo = record.GetRecordInfo(); + CacheRecordInfo rrInfo = record.GetCacheRecordInfo(); IReadOnlyList rrsigRecords = rrInfo.RRSIGRecords; if (rrsigRecords is not null) @@ -238,7 +240,7 @@ namespace DnsServerCore.Dns.ZoneManagers { newAuthorityList.Add(nsecRecord); - IReadOnlyList nsecRRSIGRecords = nsecRecord.GetRecordInfo().RRSIGRecords; + IReadOnlyList nsecRRSIGRecords = nsecRecord.GetCacheRecordInfo().RRSIGRecords; if (nsecRRSIGRecords is not null) newAuthorityList.AddRange(nsecRRSIGRecords); } @@ -355,8 +357,8 @@ namespace DnsServerCore.Dns.ZoneManagers private void ResolveAdditionalRecords(DnsResourceRecord refRecord, string domain, bool serveStale, bool dnssecOk, List additionalRecords) { - IReadOnlyList glueRecords = refRecord.GetGlueRecords(); - if (glueRecords.Count > 0) + IReadOnlyList glueRecords = refRecord.GetCacheRecordInfo().GlueRecords; + if (glueRecords is not null) { bool added = false; @@ -369,7 +371,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (dnssecOk) { - IReadOnlyList rrsigRecords = glueRecord.GetRecordInfo().RRSIGRecords; + IReadOnlyList rrsigRecords = glueRecord.GetCacheRecordInfo().RRSIGRecords; if (rrsigRecords is not null) additionalRecords.AddRange(rrsigRecords); } @@ -668,7 +670,7 @@ namespace DnsServerCore.Dns.ZoneManagers EDnsClientSubnetOptionData requestECS = request.GetEDnsClientSubnetOption(true); if (requestECS is not null) { - NetworkAddress recordECS = firstRR.GetRecordInfo().EDnsClientSubnet; + NetworkAddress recordECS = firstRR.GetCacheRecordInfo().EDnsClientSubnet; if (recordECS is not null) { EDnsOption[] ecsOption = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, recordECS.PrefixLength, requestECS.Address); @@ -798,7 +800,7 @@ namespace DnsServerCore.Dns.ZoneManagers foreach (DnsResourceRecord record in answer) { - NetworkAddress recordECS = record.GetRecordInfo().EDnsClientSubnet; + NetworkAddress recordECS = record.GetCacheRecordInfo().EDnsClientSubnet; if (recordECS is not null) { if ((suitableECS is null) || (recordECS.PrefixLength > suitableECS.PrefixLength)) @@ -950,6 +952,77 @@ namespace DnsServerCore.Dns.ZoneManagers return null; } + public void LoadCacheZoneFile() + { + string cacheZoneFile = Path.Combine(_dnsServer.ConfigFolder, "cache.bin"); + + if (!File.Exists(cacheZoneFile)) + return; + + using (FileStream fS = new FileStream(cacheZoneFile, FileMode.Open, FileAccess.Read)) + { + BinaryReader bR = new BinaryReader(fS); + + if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "CZ") + throw new InvalidDataException("CacheZoneManager format is invalid."); + + int version = bR.ReadByte(); + switch (version) + { + case 1: + int addedEntries = 0; + + try + { + while (bR.BaseStream.Position < bR.BaseStream.Length) + { + CacheZone zone = CacheZone.ReadFrom(bR); + + if (_root.TryAdd(zone.Name, zone)) + addedEntries += zone.TotalEntries; + } + } + finally + { + if (addedEntries > 0) + Interlocked.Add(ref _totalEntries, addedEntries); + } + break; + + default: + throw new InvalidDataException("CacheZoneManager format version not supported: " + version); + } + } + + _dnsServer.LogManager?.Write("DNS Cache was loaded from disk successfully."); + } + + public void SaveCacheZoneFile() + { + string cacheZoneFile = Path.Combine(_dnsServer.ConfigFolder, "cache.bin"); + + using (FileStream fS = new FileStream(cacheZoneFile, FileMode.Create, FileAccess.Write)) + { + BinaryWriter bW = new BinaryWriter(fS); + + bW.Write(Encoding.ASCII.GetBytes("CZ")); //format + bW.Write((byte)1); //version + + foreach (CacheZone zone in _root) + zone.WriteTo(bW); + } + + _dnsServer.LogManager?.Write("DNS Cache was saved to disk successfully."); + } + + public void DeleteCacheZoneFile() + { + string cacheZoneFile = Path.Combine(_dnsServer.ConfigFolder, "cache.bin"); + + if (File.Exists(cacheZoneFile)) + File.Delete(cacheZoneFile); + } + #endregion #region properties From 62c55aa76c663af2eda4a2a239fb1727ef2e3f3c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:24:44 +0530 Subject: [PATCH 072/191] ApexZone: code refactoring changes done. --- DnsServerCore/Dns/Zones/ApexZone.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/DnsServerCore/Dns/Zones/ApexZone.cs b/DnsServerCore/Dns/Zones/ApexZone.cs index 14911e68..3017cfc9 100644 --- a/DnsServerCore/Dns/Zones/ApexZone.cs +++ b/DnsServerCore/Dns/Zones/ApexZone.cs @@ -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 @@ -146,7 +146,7 @@ namespace DnsServerCore.Dns.Zones while (index < history.Count) { //check difference sequence - if (history[index].GetDeletedOn() > expiry) + if (history[index].GetAuthRecordInfo().DeletedOn > expiry) break; //found record to keep //skip to next difference sequence @@ -207,7 +207,7 @@ namespace DnsServerCore.Dns.Zones //notify all secondary name servers foreach (DnsResourceRecord nsRecord in nsRecords) { - if (nsRecord.IsDisabled()) + if (nsRecord.GetAuthRecordInfo().Disabled) continue; string nameServerHost = (nsRecord.RDATA as DnsNSRecordData).NameServer; @@ -430,8 +430,8 @@ namespace DnsServerCore.Dns.Zones { string nsDomain = (nsRecord.RDATA as DnsNSRecordData).NameServer; - IReadOnlyList glueRecords = nsRecord.GetGlueRecords(); - if (glueRecords.Count > 0) + IReadOnlyList glueRecords = nsRecord.GetAuthRecordInfo().GlueRecords; + if (glueRecords is not null) { foreach (DnsResourceRecord glueRecord in glueRecords) { @@ -514,8 +514,8 @@ namespace DnsServerCore.Dns.Zones { DnsResourceRecord soaRecord = _entries[DnsResourceRecordType.SOA][0]; - IReadOnlyList primaryNameServers = soaRecord.GetPrimaryNameServers(); - if (primaryNameServers.Count > 0) + IReadOnlyList primaryNameServers = soaRecord.GetAuthRecordInfo().PrimaryNameServers; + if (primaryNameServers is not null) { List resolvedNameServers = new List(primaryNameServers.Count * 2); @@ -537,7 +537,7 @@ namespace DnsServerCore.Dns.Zones foreach (DnsResourceRecord nsRecord in nsRecords) { - if (nsRecord.IsDisabled()) + if (nsRecord.GetAuthRecordInfo().Disabled) continue; if (primaryNameServer.Equals((nsRecord.RDATA as DnsNSRecordData).NameServer, StringComparison.OrdinalIgnoreCase)) @@ -563,7 +563,7 @@ namespace DnsServerCore.Dns.Zones foreach (DnsResourceRecord nsRecord in nsRecords) { - if (nsRecord.IsDisabled()) + if (nsRecord.GetAuthRecordInfo().Disabled) continue; if (primaryNameServer.Equals((nsRecord.RDATA as DnsNSRecordData).NameServer, StringComparison.OrdinalIgnoreCase)) From 00927c92ddc0edfd6e800f8f9eaad83b7e09edf1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:26:41 +0530 Subject: [PATCH 073/191] AuthZone: code refactoring changes. --- DnsServerCore/Dns/Zones/AuthZone.cs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/DnsServerCore/Dns/Zones/AuthZone.cs b/DnsServerCore/Dns/Zones/AuthZone.cs index acd73d3e..faf0ed70 100644 --- a/DnsServerCore/Dns/Zones/AuthZone.cs +++ b/DnsServerCore/Dns/Zones/AuthZone.cs @@ -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 @@ -56,22 +56,30 @@ namespace DnsServerCore.Dns.Zones if (records.Count == 1) { - if (records[0].IsDisabled()) + AuthRecordInfo authRecordInfo = records[0].GetAuthRecordInfo(); + + if (authRecordInfo.Disabled) return Array.Empty(); //record disabled //update last used on - records[0].GetRecordInfo().LastUsedOn = DateTime.UtcNow; + authRecordInfo.LastUsedOn = DateTime.UtcNow; return records; } List newRecords = new List(records.Count); + DateTime utcNow = DateTime.UtcNow; foreach (DnsResourceRecord record in records) { - if (record.IsDisabled()) + AuthRecordInfo authRecordInfo = record.GetAuthRecordInfo(); + + if (authRecordInfo.Disabled) continue; //record disabled + //update last used on + authRecordInfo.LastUsedOn = utcNow; + newRecords.Add(record); } @@ -87,12 +95,6 @@ namespace DnsServerCore.Dns.Zones } } - //update last used on - DateTime utcNow = DateTime.UtcNow; - - foreach (DnsResourceRecord record in newRecords) - record.GetRecordInfo().LastUsedOn = utcNow; - return newRecords; } @@ -112,7 +114,7 @@ namespace DnsServerCore.Dns.Zones { if ((rrsigRecord.RDATA as DnsRRSIGRecordData).TypeCovered == type) { - rrsigRecord.GetRecordInfo().LastUsedOn = utcNow; + rrsigRecord.GetAuthRecordInfo().LastUsedOn = utcNow; newRecords.Add(rrsigRecord); } } @@ -901,7 +903,7 @@ namespace DnsServerCore.Dns.Zones foreach (DnsResourceRecord record in records) { - if (record.IsDisabled()) + if (record.GetAuthRecordInfo().Disabled) continue; return true; From b1fe727dec762f7fbad82931222c207a23bf0767 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:28:48 +0530 Subject: [PATCH 074/191] AuthZoneInfo: code refactoring changes. --- DnsServerCore/Dns/Zones/AuthZoneInfo.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs index 3df2fe0d..6d0b6bd4 100644 --- a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs +++ b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs @@ -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 @@ -183,7 +183,7 @@ namespace DnsServerCore.Dns.Zones for (int i = 0; i < count; i++) { zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); - zoneHistory[i].Tag = new DnsResourceRecordInfo(bR, zoneHistory[i].Type == DnsResourceRecordType.SOA); + zoneHistory[i].Tag = new AuthRecordInfo(bR, zoneHistory[i].Type == DnsResourceRecordType.SOA); } _zoneHistory = zoneHistory; @@ -259,7 +259,7 @@ namespace DnsServerCore.Dns.Zones List dnssecPrivateKeys = new List(count); for (int i = 0; i < count; i++) - dnssecPrivateKeys.Add(DnssecPrivateKey.Parse(bR)); + dnssecPrivateKeys.Add(DnssecPrivateKey.ReadFrom(bR)); _dnssecPrivateKeys = dnssecPrivateKeys; } @@ -278,7 +278,7 @@ namespace DnsServerCore.Dns.Zones for (int i = 0; i < count; i++) { zoneHistory[i] = new DnsResourceRecord(bR.BaseStream); - zoneHistory[i].Tag = new DnsResourceRecordInfo(bR, zoneHistory[i].Type == DnsResourceRecordType.SOA); + zoneHistory[i].Tag = new AuthRecordInfo(bR, zoneHistory[i].Type == DnsResourceRecordType.SOA); } _zoneHistory = zoneHistory; @@ -527,8 +527,8 @@ namespace DnsServerCore.Dns.Zones { record.WriteTo(bW.BaseStream); - if (record.Tag is not DnsResourceRecordInfo rrInfo) - rrInfo = new DnsResourceRecordInfo(); //default info + if (record.Tag is not AuthRecordInfo rrInfo) + rrInfo = AuthRecordInfo.Default; //default info rrInfo.WriteTo(bW); } @@ -598,8 +598,8 @@ namespace DnsServerCore.Dns.Zones { record.WriteTo(bW.BaseStream); - if (record.Tag is not DnsResourceRecordInfo rrInfo) - rrInfo = new DnsResourceRecordInfo(); //default info + if (record.Tag is not AuthRecordInfo rrInfo) + rrInfo = AuthRecordInfo.Default; //default info rrInfo.WriteTo(bW); } From d1b2e1c1926673d91fcd9619aeadfe93c78543e1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:32:43 +0530 Subject: [PATCH 075/191] CacheZone: updated implementation to support serializing cached records. Code refactoring changes done. --- DnsServerCore/Dns/Zones/CacheZone.cs | 148 ++++++++++++++++++++++++--- 1 file changed, 133 insertions(+), 15 deletions(-) diff --git a/DnsServerCore/Dns/Zones/CacheZone.cs b/DnsServerCore/Dns/Zones/CacheZone.cs index 866476b1..01fdabc2 100644 --- a/DnsServerCore/Dns/Zones/CacheZone.cs +++ b/DnsServerCore/Dns/Zones/CacheZone.cs @@ -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 @@ -21,6 +21,7 @@ using DnsServerCore.Dns.ResourceRecords; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; @@ -42,6 +43,63 @@ namespace DnsServerCore.Dns.Zones : base(name, capacity) { } + private CacheZone(string name, ConcurrentDictionary> entries) + : base(name, entries) + { } + + #endregion + + #region static + + public static CacheZone ReadFrom(BinaryReader bR) + { + byte version = bR.ReadByte(); + switch (version) + { + case 1: + string name = bR.ReadString(); + ConcurrentDictionary> entries = ReadEntriesFrom(bR); + + CacheZone cacheZone = new CacheZone(name, entries); + + //write all ECS cache records + { + int ecsCount = bR.ReadInt32(); + if (ecsCount > 0) + { + cacheZone._ecsEntries = new ConcurrentDictionary>>(1, ecsCount); + + for (int i = 0; i < ecsCount; i++) + { + NetworkAddress key = NetworkAddress.ReadFrom(bR); + ConcurrentDictionary> ecsEntries = ReadEntriesFrom(bR); + + cacheZone._ecsEntries.TryAdd(key, ecsEntries); + } + } + } + + return cacheZone; + + default: + throw new InvalidDataException("CacheZone format version not supported."); + } + } + + public static bool IsTypeSupportedForEDnsClientSubnet(DnsResourceRecordType type) + { + switch (type) + { + case DnsResourceRecordType.A: + case DnsResourceRecordType.AAAA: + case DnsResourceRecordType.CNAME: + return true; + + default: + return false; + } + } + #endregion #region private @@ -73,22 +131,55 @@ namespace DnsServerCore.Dns.Zones DateTime utcNow = DateTime.UtcNow; foreach (DnsResourceRecord record in records) - record.GetRecordInfo().LastUsedOn = utcNow; + record.GetCacheRecordInfo().LastUsedOn = utcNow; return records; } - public static bool IsTypeSupportedForEDnsClientSubnet(DnsResourceRecordType type) + private static ConcurrentDictionary> ReadEntriesFrom(BinaryReader bR) { - switch (type) - { - case DnsResourceRecordType.A: - case DnsResourceRecordType.AAAA: - case DnsResourceRecordType.CNAME: - return true; + int count = bR.ReadInt32(); + ConcurrentDictionary> entries = new ConcurrentDictionary>(1, count); - default: - return false; + for (int i = 0; i < count; i++) + { + DnsResourceRecordType key = (DnsResourceRecordType)bR.ReadUInt16(); + int rrCount = bR.ReadInt32(); + DnsResourceRecord[] records = new DnsResourceRecord[rrCount]; + + for (int j = 0; j < rrCount; j++) + { + records[j] = DnsResourceRecord.ReadCacheRecordFrom(bR, delegate (DnsResourceRecord record) + { + record.Tag = new CacheRecordInfo(bR); + }); + } + + entries.TryAdd(key, records); + } + + return entries; + } + + private static void WriteEntriesTo(ConcurrentDictionary> entries, BinaryWriter bW) + { + bW.Write(entries.Count); + + foreach (KeyValuePair> entry in entries) + { + bW.Write((ushort)entry.Key); + bW.Write(entry.Value.Count); + + foreach (DnsResourceRecord record in entry.Value) + { + record.WriteCacheRecordTo(bW, delegate () + { + if (record.Tag is not CacheRecordInfo rrInfo) + rrInfo = CacheRecordInfo.Default; //default info + + rrInfo.WriteTo(bW); + }); + } } } @@ -103,7 +194,7 @@ namespace DnsServerCore.Dns.Zones ConcurrentDictionary> entries; - NetworkAddress eDnsClientSubnet = records[0].GetRecordInfo().EDnsClientSubnet; + NetworkAddress eDnsClientSubnet = records[0].GetCacheRecordInfo().EDnsClientSubnet; if ((eDnsClientSubnet is null) || !IsTypeSupportedForEDnsClientSubnet(type)) { entries = _entries; @@ -163,7 +254,7 @@ namespace DnsServerCore.Dns.Zones DateTime utcNow = DateTime.UtcNow; foreach (DnsResourceRecord record in records) - record.GetRecordInfo().LastUsedOn = utcNow; + record.GetCacheRecordInfo().LastUsedOn = utcNow; //set records bool added = true; @@ -250,7 +341,7 @@ namespace DnsServerCore.Dns.Zones { foreach (KeyValuePair> entry in ecsEntry.Value) { - if ((entry.Value.Count == 0) || (entry.Value[0].GetRecordInfo().LastUsedOn < cutoff)) + if ((entry.Value.Count == 0) || (entry.Value[0].GetCacheRecordInfo().LastUsedOn < cutoff)) { if (ecsEntry.Value.TryRemove(entry.Key, out _)) //RR Set was last used before cutoff; remove entry removedEntries++; @@ -264,7 +355,7 @@ namespace DnsServerCore.Dns.Zones foreach (KeyValuePair> entry in _entries) { - if ((entry.Value.Count == 0) || (entry.Value[0].GetRecordInfo().LastUsedOn < cutoff)) + if ((entry.Value.Count == 0) || (entry.Value[0].GetCacheRecordInfo().LastUsedOn < cutoff)) { if (_entries.TryRemove(entry.Key, out _)) //RR Set was last used before cutoff; remove entry removedEntries++; @@ -420,6 +511,33 @@ namespace DnsServerCore.Dns.Zones return false; } + public void WriteTo(BinaryWriter bW) + { + bW.Write((byte)1); //version + + //cache zone info + bW.Write(_name); + + //write all cache records + WriteEntriesTo(_entries, bW); + + //write all ECS cache records + if (_ecsEntries is null) + { + bW.Write(0); + } + else + { + bW.Write(_ecsEntries.Count); + + foreach (KeyValuePair>> ecsEntry in _ecsEntries) + { + ecsEntry.Key.WriteTo(bW); + WriteEntriesTo(ecsEntry.Value, bW); + } + } + } + #endregion #region properties From d2fc9cab6e75b09a533c714c81a043b20cd45935 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:33:28 +0530 Subject: [PATCH 076/191] ForwarderZone: code refactoring changes. --- DnsServerCore/Dns/Zones/ForwarderZone.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/Zones/ForwarderZone.cs b/DnsServerCore/Dns/Zones/ForwarderZone.cs index d99cedf0..df84d621 100644 --- a/DnsServerCore/Dns/Zones/ForwarderZone.cs +++ b/DnsServerCore/Dns/Zones/ForwarderZone.cs @@ -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 @@ -44,7 +44,7 @@ namespace DnsServerCore.Dns.Zones DnsResourceRecord fwdRecord = new DnsResourceRecord(name, DnsResourceRecordType.FWD, DnsClass.IN, 0, new DnsForwarderRecordData(forwarderProtocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword)); if (!string.IsNullOrEmpty(fwdRecordComments)) - fwdRecord.SetComments(fwdRecordComments); + fwdRecord.GetAuthRecordInfo().Comments = fwdRecordComments; _entries[DnsResourceRecordType.FWD] = new DnsResourceRecord[] { fwdRecord }; } From d867e5f71e2e4d039cfc4f5787b801ac45cdff27 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:34:06 +0530 Subject: [PATCH 077/191] PrimarySubDomainZone: code refactoring changes. --- DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs b/DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs index f1318aaa..394f76a2 100644 --- a/DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs +++ b/DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs @@ -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 @@ -66,7 +66,7 @@ namespace DnsServerCore.Dns.Zones default: foreach (DnsResourceRecord record in records) { - if (record.IsDisabled()) + if (record.GetAuthRecordInfo().Disabled) throw new DnsServerException("Cannot set records: disabling records in a signed zones is not supported."); } @@ -117,7 +117,7 @@ namespace DnsServerCore.Dns.Zones throw new DnsServerException("The record type is not supported by DNSSEC signed primary zones."); default: - if (record.IsDisabled()) + if (record.GetAuthRecordInfo().Disabled) throw new DnsServerException("Cannot add record: disabling records in a signed zones is not supported."); break; @@ -226,7 +226,7 @@ namespace DnsServerCore.Dns.Zones if (oldRecord.Type != newRecord.Type) throw new InvalidOperationException("Old and new record types do not match."); - if ((_primaryZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.IsDisabled()) + if ((_primaryZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.GetAuthRecordInfo().Disabled) throw new DnsServerException("Cannot update record: disabling records in a signed zones is not supported."); if (newRecord.OriginalTtlValue > _primaryZone.GetZoneSoaExpire()) From 5692e5e16668d20f1c1f45068fd4ef085299f723 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:36:41 +0530 Subject: [PATCH 078/191] PrimaryZone: code refactoring changes. --- DnsServerCore/Dns/Zones/PrimaryZone.cs | 34 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/DnsServerCore/Dns/Zones/PrimaryZone.cs b/DnsServerCore/Dns/Zones/PrimaryZone.cs index 05408116..90856f0b 100644 --- a/DnsServerCore/Dns/Zones/PrimaryZone.cs +++ b/DnsServerCore/Dns/Zones/PrimaryZone.cs @@ -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 @@ -2646,7 +2646,7 @@ namespace DnsServerCore.Dns.Zones oldSoaRecord.Tag = null; //start commit - oldSoaRecord.SetDeletedOn(DateTime.UtcNow); + oldSoaRecord.GetAuthRecordInfo().DeletedOn = DateTime.UtcNow; //write removed _zoneHistory.Add(oldSoaRecord); @@ -2655,13 +2655,17 @@ namespace DnsServerCore.Dns.Zones { foreach (DnsResourceRecord deletedRecord in deletedRecords) { - if (deletedRecord.IsDisabled()) + if (deletedRecord.GetAuthRecordInfo().Disabled) continue; _zoneHistory.Add(deletedRecord); if (deletedRecord.Type == DnsResourceRecordType.NS) - _zoneHistory.AddRange(deletedRecord.GetGlueRecords()); + { + IReadOnlyList glueRecords = deletedRecord.GetAuthRecordInfo().GlueRecords; + if (glueRecords is not null) + _zoneHistory.AddRange(glueRecords); + } } } @@ -2675,13 +2679,17 @@ namespace DnsServerCore.Dns.Zones { foreach (DnsResourceRecord addedRecord in addedRecords) { - if (addedRecord.IsDisabled()) + if (addedRecord.GetAuthRecordInfo().Disabled) continue; _zoneHistory.Add(addedRecord); if (addedRecord.Type == DnsResourceRecordType.NS) - _zoneHistory.AddRange(addedRecord.GetGlueRecords()); + { + IReadOnlyList glueRecords = addedRecord.GetAuthRecordInfo().GlueRecords; + if (glueRecords is not null) + _zoneHistory.AddRange(glueRecords); + } } } @@ -2711,7 +2719,7 @@ namespace DnsServerCore.Dns.Zones default: foreach (DnsResourceRecord record in records) { - if (record.IsDisabled()) + if (record.GetAuthRecordInfo().Disabled) throw new DnsServerException("Cannot set records: disabling records in a signed zones is not supported."); } @@ -2741,10 +2749,10 @@ namespace DnsServerCore.Dns.Zones if (newSoa.Refresh > newSoa.Expire) throw new DnsServerException("Failed to set records: SOA REFRESH cannot be greater than SOA EXPIRE."); - //remove any resource record info except comments - string comments = newSoaRecord.GetComments(); - newSoaRecord.Tag = null; - newSoaRecord.SetComments(comments); + //remove any record info except comments + string comments = newSoaRecord.GetAuthRecordInfo().Comments; + newSoaRecord.Tag = null; //remove old record info + newSoaRecord.GetAuthRecordInfo().Comments = comments; uint oldSoaMinimum = GetZoneSoaMinimum(); @@ -2806,7 +2814,7 @@ namespace DnsServerCore.Dns.Zones throw new DnsServerException("The record type is not supported by DNSSEC signed primary zones."); default: - if (record.IsDisabled()) + if (record.GetAuthRecordInfo().Disabled) throw new DnsServerException("Cannot add record: disabling records in a signed zones is not supported."); break; @@ -2930,7 +2938,7 @@ namespace DnsServerCore.Dns.Zones if (oldRecord.Type != newRecord.Type) throw new InvalidOperationException("Old and new record types do not match."); - if ((_dnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.IsDisabled()) + if ((_dnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.GetAuthRecordInfo().Disabled) throw new DnsServerException("Cannot update record: disabling records in a signed zones is not supported."); if (newRecord.OriginalTtlValue > GetZoneSoaExpire()) From d1e8d081b98a6bd9fb5aa56ad01a14f6db7374b1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:39:20 +0530 Subject: [PATCH 079/191] SecondaryZone: added xfr-over-quic support. Code refactoring done. --- DnsServerCore/Dns/Zones/SecondaryZone.cs | 73 +++++++++++++----------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/DnsServerCore/Dns/Zones/SecondaryZone.cs b/DnsServerCore/Dns/Zones/SecondaryZone.cs index 973ed368..6e70fb9c 100644 --- a/DnsServerCore/Dns/Zones/SecondaryZone.cs +++ b/DnsServerCore/Dns/Zones/SecondaryZone.cs @@ -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 @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -88,6 +89,7 @@ namespace DnsServerCore.Dns.Zones { case DnsTransportProtocol.Tcp: case DnsTransportProtocol.Tls: + case DnsTransportProtocol.Quic: break; default: @@ -134,13 +136,13 @@ namespace DnsServerCore.Dns.Zones DnsSOARecordData soa = new DnsSOARecordData(receivedSoa.PrimaryNameServer, receivedSoa.ResponsiblePerson, 0u, receivedSoa.Refresh, receivedSoa.Retry, receivedSoa.Expire, receivedSoa.Minimum); DnsResourceRecord[] soaRR = new DnsResourceRecord[] { new DnsResourceRecord(secondaryZone._name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Refresh, soa) }; + AuthRecordInfo authRecordInfo = soaRR[0].GetAuthRecordInfo(); + if (!string.IsNullOrEmpty(primaryNameServerAddresses)) - soaRR[0].SetPrimaryNameServers(primaryNameServerAddresses); + authRecordInfo.PrimaryNameServers = primaryNameServerAddresses.Split(NameServerAddress.Parse, ','); - DnsResourceRecordInfo recordInfo = soaRR[0].GetRecordInfo(); - - recordInfo.ZoneTransferProtocol = zoneTransferProtocol; - recordInfo.TsigKeyName = tsigKeyName; + authRecordInfo.ZoneTransferProtocol = zoneTransferProtocol; + authRecordInfo.TsigKeyName = tsigKeyName; secondaryZone._entries[DnsResourceRecordType.SOA] = soaRR; @@ -214,7 +216,7 @@ namespace DnsServerCore.Dns.Zones return; } - DnsResourceRecordInfo recordInfo = currentSoaRecord.GetRecordInfo(); + AuthRecordInfo recordInfo = currentSoaRecord.GetAuthRecordInfo(); TsigKey key = null; if (!string.IsNullOrEmpty(recordInfo.TsigKeyName) && ((_dnsServer.TsigKeys is null) || !_dnsServer.TsigKeys.TryGetValue(recordInfo.TsigKeyName, out key))) @@ -339,35 +341,42 @@ namespace DnsServerCore.Dns.Zones //update available; do zone transfer with TLS or TCP transport - if (zoneTransferProtocol == DnsTransportProtocol.Tls) + switch (zoneTransferProtocol) { - //change name server protocol to TLS - List tlsNameServers = new List(primaryNameServers.Count); + case DnsTransportProtocol.Tls: + case DnsTransportProtocol.Quic: + { + //change name server protocol to TLS/QUIC + List updatedNameServers = new List(primaryNameServers.Count); - foreach (NameServerAddress primaryNameServer in primaryNameServers) - { - if (primaryNameServer.Protocol == DnsTransportProtocol.Tls) - tlsNameServers.Add(primaryNameServer); - else - tlsNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tls)); - } + foreach (NameServerAddress primaryNameServer in primaryNameServers) + { + if (primaryNameServer.Protocol == zoneTransferProtocol) + updatedNameServers.Add(primaryNameServer); + else + updatedNameServers.Add(primaryNameServer.ChangeProtocol(zoneTransferProtocol)); + } - primaryNameServers = tlsNameServers; - } - else - { - //change name server protocol to TCP - List tcpNameServers = new List(primaryNameServers.Count); + primaryNameServers = updatedNameServers; + break; + } - foreach (NameServerAddress primaryNameServer in primaryNameServers) - { - if (primaryNameServer.Protocol == DnsTransportProtocol.Tcp) - tcpNameServers.Add(primaryNameServer); - else - tcpNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tcp)); - } + default: + { + //change name server protocol to TCP + List updatedNameServers = new List(primaryNameServers.Count); - primaryNameServers = tcpNameServers; + foreach (NameServerAddress primaryNameServer in primaryNameServers) + { + if (primaryNameServer.Protocol == DnsTransportProtocol.Tcp) + updatedNameServers.Add(primaryNameServer); + else + updatedNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tcp)); + } + + primaryNameServers = updatedNameServers; + break; + } } DnsClient xfrClient = new DnsClient(primaryNameServers); @@ -499,7 +508,7 @@ namespace DnsServerCore.Dns.Zones { lock (_zoneHistory) { - historyRecords[0].SetDeletedOn(DateTime.UtcNow); + historyRecords[0].GetAuthRecordInfo().DeletedOn = DateTime.UtcNow; //write history _zoneHistory.AddRange(historyRecords); From 8b3ddf113c31c8a19b0358e12c5ea98a6db82a30 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:40:04 +0530 Subject: [PATCH 080/191] StubZone: Code refactoring changes. --- DnsServerCore/Dns/Zones/StubZone.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/Zones/StubZone.cs b/DnsServerCore/Dns/Zones/StubZone.cs index a7a05abf..90329837 100644 --- a/DnsServerCore/Dns/Zones/StubZone.cs +++ b/DnsServerCore/Dns/Zones/StubZone.cs @@ -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 @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using TechnitiumLibrary; using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns.ResourceRecords; @@ -113,7 +114,7 @@ namespace DnsServerCore.Dns.Zones DnsResourceRecord[] soaRR = new DnsResourceRecord[] { new DnsResourceRecord(stubZone._name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Refresh, soa) }; if (!string.IsNullOrEmpty(primaryNameServerAddresses)) - soaRR[0].SetPrimaryNameServers(primaryNameServerAddresses); + soaRR[0].GetAuthRecordInfo().PrimaryNameServers = primaryNameServerAddresses.Split(NameServerAddress.Parse, ','); stubZone._entries[DnsResourceRecordType.SOA] = soaRR; From 1dd35f68e9b77ac3c53439b585a942a82e54e747 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:40:36 +0530 Subject: [PATCH 081/191] SubDomainZone: code refactoring changes. --- DnsServerCore/Dns/Zones/SubDomainZone.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/Zones/SubDomainZone.cs b/DnsServerCore/Dns/Zones/SubDomainZone.cs index 737802b2..19011441 100644 --- a/DnsServerCore/Dns/Zones/SubDomainZone.cs +++ b/DnsServerCore/Dns/Zones/SubDomainZone.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2021 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 @@ -49,7 +49,7 @@ namespace DnsServerCore.Dns.Zones { foreach (DnsResourceRecord record in entry.Value) { - if (!record.IsDisabled()) + if (!record.GetAuthRecordInfo().Disabled) { _disabled = false; return; From 507f596fc8d997a703380cba7f1d1138472ff145 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:41:42 +0530 Subject: [PATCH 082/191] Zone: added another protected constructor to allow reloading cache zone. --- DnsServerCore/Dns/Zones/Zone.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DnsServerCore/Dns/Zones/Zone.cs b/DnsServerCore/Dns/Zones/Zone.cs index d8c1a5c1..40bf1064 100644 --- a/DnsServerCore/Dns/Zones/Zone.cs +++ b/DnsServerCore/Dns/Zones/Zone.cs @@ -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 @@ -50,6 +50,12 @@ namespace DnsServerCore.Dns.Zones _entries = new ConcurrentDictionary>(1, capacity); } + protected Zone(string name, ConcurrentDictionary> entries) + { + _name = name.ToLower(); + _entries = entries; + } + #endregion #region static From d1ab424f57b91bc61bb5f3fefecf5e52b06edead Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:52:00 +0530 Subject: [PATCH 083/191] DnsServer: Implemented IAsyncDisposable. Implemented DNS-over-QUIC optional protocol support. Replaced old DNS-over-HTTPS web server with Kestrel to support HTTP/2 and HTTP/3. Code refactoring done. --- DnsServerCore/Dns/DnsServer.cs | 1793 ++++++++++++++++++-------------- 1 file changed, 989 insertions(+), 804 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 71c22fe5..40415fdc 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -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 @@ -23,28 +23,40 @@ using DnsServerCore.Dns.ResourceRecords; using DnsServerCore.Dns.Trees; using DnsServerCore.Dns.ZoneManagers; using DnsServerCore.Dns.Zones; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.AspNetCore.Server.Kestrel.Https; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Net; +using System.Net.Quic; using System.Net.Security; using System.Net.Sockets; using System.Runtime.ExceptionServices; using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Threading; using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.ClientConnection; using TechnitiumLibrary.Net.Dns.EDnsOptions; using TechnitiumLibrary.Net.Dns.ResourceRecords; -using TechnitiumLibrary.Net.Http; using TechnitiumLibrary.Net.Proxy; namespace DnsServerCore.Dns { +#pragma warning disable CA2252 // This API requires opting into preview features +#pragma warning disable CA1416 // Validate platform compatibility + public enum DnsServerRecursion : byte { Deny = 0, @@ -60,7 +72,7 @@ namespace DnsServerCore.Dns CustomAddress = 2 } - public sealed class DnsServer : IDisposable, IDnsClient + public sealed class DnsServer : IAsyncDisposable, IDisposable, IDnsClient { #region enum @@ -81,6 +93,8 @@ namespace DnsServerCore.Dns const int SERVE_STALE_WAIT_TIME = 1800; static readonly IPEndPoint IPENDPOINT_ANY_0 = new IPEndPoint(IPAddress.Any, 0); + static readonly IReadOnlyCollection _aRecords = new DnsARecordData[] { new DnsARecordData(IPAddress.Any) }; + static readonly IReadOnlyCollection _aaaaRecords = new DnsAAAARecordData[] { new DnsAAAARecordData(IPAddress.IPv6Any) }; string _serverDomain; readonly string _configFolder; @@ -92,16 +106,11 @@ namespace DnsServerCore.Dns readonly List _udpListeners = new List(); readonly List _tcpListeners = new List(); - readonly List _httpListeners = new List(); readonly List _tlsListeners = new List(); - readonly List _httpsListeners = new List(); + readonly List _quicListeners = new List(); - bool _enableDnsOverHttp; - bool _enableDnsOverTls; - bool _enableDnsOverHttps; - bool _isDnsOverHttpsEnabled; - X509Certificate2 _certificate; - IReadOnlyDictionary _tsigKeys; + WebApplication _dohPrivateWebService; + WebApplication _dohWebService; readonly AuthZoneManager _authZoneManager; readonly AllowedZoneManager _allowedZoneManager; @@ -111,51 +120,73 @@ namespace DnsServerCore.Dns readonly DnsApplicationManager _dnsApplicationManager; readonly ResolverDnsCache _dnsCache; + readonly StatsManager _stats; - readonly IReadOnlyCollection _aRecords = new DnsARecordData[] { new DnsARecordData(IPAddress.Any) }; - readonly IReadOnlyCollection _aaaaRecords = new DnsAAAARecordData[] { new DnsAAAARecordData(IPAddress.IPv6Any) }; - - DnsServerRecursion _recursion; - IReadOnlyCollection _recursionDeniedNetworks; - IReadOnlyCollection _recursionAllowedNetworks; - NetProxy _proxy; - IReadOnlyList _forwarders; bool _preferIPv6; ushort _udpPayloadSize = DnsDatagram.EDNS_DEFAULT_UDP_PAYLOAD_SIZE; - bool _randomizeName; - bool _qnameMinimization; - bool _nsRevalidation; bool _dnssecValidation = true; + bool _eDnsClientSubnet; byte _eDnsClientSubnetIPv4PrefixLength = 24; byte _eDnsClientSubnetIPv6PrefixLength = 56; + int _qpmLimitRequests = 0; int _qpmLimitErrors = 0; int _qpmLimitSampleMinutes = 5; int _qpmLimitIPv4PrefixLength = 24; int _qpmLimitIPv6PrefixLength = 56; - int _forwarderRetries = 3; - int _resolverRetries = 2; - int _forwarderTimeout = 2000; - int _resolverTimeout = 2000; + int _clientTimeout = 4000; - int _forwarderConcurrency = 2; + int _tcpSendTimeout = 10000; + int _tcpReceiveTimeout = 10000; + int _quicIdleTimeout = 60000; + int _quicMaxInboundStreams = 100; + int _listenBacklog = 100; + + bool _enableDnsOverHttp; + bool _enableDnsOverTls; + bool _enableDnsOverHttps; + bool _enableDnsOverHttpPort80; + bool _enableDnsOverQuic; + int _dnsOverHttpPort = 8053; + int _dnsOverTlsPort = 853; + int _dnsOverHttpsPort = 443; + int _dnsOverQuicPort = 853; + X509Certificate2 _certificate; + + IReadOnlyDictionary _tsigKeys; + + DnsServerRecursion _recursion; + IReadOnlyCollection _recursionDeniedNetworks; + IReadOnlyCollection _recursionAllowedNetworks; + + bool _randomizeName; + bool _qnameMinimization; + bool _nsRevalidation; + + int _resolverRetries = 2; + int _resolverTimeout = 2000; int _resolverMaxStackCount = 16; + bool _serveStale = true; int _cachePrefetchEligibility = 2; int _cachePrefetchTrigger = 9; int _cachePrefetchSampleIntervalInMinutes = 5; int _cachePrefetchSampleEligibilityHitsPerHour = 30; + bool _enableBlocking = true; bool _allowTxtBlockingReport = true; DnsServerBlockingType _blockingType = DnsServerBlockingType.AnyAddress; IReadOnlyCollection _customBlockingARecords = Array.Empty(); IReadOnlyCollection _customBlockingAAAARecords = Array.Empty(); - LogManager _queryLog; - readonly StatsManager _stats; - int _tcpSendTimeout = 10000; - int _tcpReceiveTimeout = 10000; + NetProxy _proxy; + IReadOnlyList _forwarders; + int _forwarderRetries = 3; + int _forwarderTimeout = 2000; + int _forwarderConcurrency = 2; + + LogManager _queryLog; Timer _cachePrefetchSamplingTimer; readonly object _cachePrefetchSamplingTimerLock = new object(); @@ -203,9 +234,6 @@ namespace DnsServerCore.Dns ThreadPool.SetMinThreads(minWorker, minIOC); } - - if (ServicePointManager.DefaultConnectionLimit < 10) - ServicePointManager.DefaultConnectionLimit = 10; //concurrent http request limit required when using DNS-over-HTTPS forwarders } public DnsServer(string serverDomain, string configFolder, string dohwwwFolder, LogManager log = null) @@ -243,31 +271,25 @@ namespace DnsServerCore.Dns bool _disposed; - private void Dispose(bool disposing) + public async ValueTask DisposeAsync() { if (_disposed) return; - if (disposing) - { - Stop(); + await StopAsync(); - if (_authZoneManager is not null) - _authZoneManager.Dispose(); + _authZoneManager?.Dispose(); - if (_dnsApplicationManager is not null) - _dnsApplicationManager.Dispose(); + _dnsApplicationManager?.Dispose(); - if (_stats is not null) - _stats.Dispose(); - } + _stats?.Dispose(); _disposed = true; } public void Dispose() { - Dispose(true); + DisposeAsync().Sync(); } #endregion @@ -328,7 +350,7 @@ namespace DnsServerCore.Dns if (result.RemoteEndPoint is not IPEndPoint remoteEP) continue; - if (IsQpmLimitCrossed(remoteEP)) + if (IsQpmLimitCrossed(remoteEP.Address)) continue; try @@ -346,9 +368,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, DnsTransportProtocol.Udp, ex); + _log?.Write(remoteEP, DnsTransportProtocol.Udp, ex); } } } @@ -369,10 +389,7 @@ namespace DnsServerCore.Dns if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) return; //server stopping - LogManager log = _log; - if (log != null) - log.Write(ex); - + _log?.Write(ex); break; } } @@ -381,9 +398,7 @@ namespace DnsServerCore.Dns if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) return; //server stopping - LogManager log = _log; - if (log is not null) - log.Write(ex); + _log?.Write(ex); } } @@ -391,7 +406,7 @@ namespace DnsServerCore.Dns { try { - DnsDatagram response = await PreProcessQueryAsync(request, remoteEP, DnsTransportProtocol.Udp, IsRecursionAllowed(remoteEP)); + DnsDatagram response = await PreProcessQueryAsync(request, remoteEP, DnsTransportProtocol.Udp, IsRecursionAllowed(remoteEP.Address)); if (response is null) return; //drop request @@ -434,10 +449,7 @@ namespace DnsServerCore.Dns await udpListener.SendToAsync(new ArraySegment(sendBuffer, 0, (int)sendBufferStream.Position), SocketFlags.None, remoteEP); } - LogManager queryLog = _queryLog; - if (queryLog is not null) - queryLog.Write(remoteEP, DnsTransportProtocol.Udp, request, response); - + _queryLog?.Write(remoteEP, DnsTransportProtocol.Udp, request, response); _stats.QueueUpdate(request, remoteEP, DnsTransportProtocol.Udp, response); } catch (Exception ex) @@ -445,17 +457,12 @@ namespace DnsServerCore.Dns if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) return; //server stopping - LogManager queryLog = _queryLog; - if (queryLog is not null) - queryLog.Write(remoteEP, DnsTransportProtocol.Udp, request, null); - - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, DnsTransportProtocol.Udp, ex); + _queryLog?.Write(remoteEP, DnsTransportProtocol.Udp, request, null); + _log?.Write(remoteEP, DnsTransportProtocol.Udp, ex); } } - private async Task AcceptConnectionAsync(Socket tcpListener, DnsTransportProtocol protocol, bool usingHttps) + private async Task AcceptConnectionAsync(Socket tcpListener, DnsTransportProtocol protocol) { IPEndPoint localEP = tcpListener.LocalEndPoint as IPEndPoint; @@ -469,7 +476,7 @@ namespace DnsServerCore.Dns { Socket socket = await tcpListener.AcceptAsync(); - _ = ProcessConnectionAsync(socket, protocol, usingHttps); + _ = ProcessConnectionAsync(socket, protocol); } } catch (SocketException ex) @@ -477,9 +484,7 @@ namespace DnsServerCore.Dns if (ex.SocketErrorCode == SocketError.OperationAborted) return; //server stopping - LogManager log = _log; - if (log is not null) - log.Write(localEP, protocol, ex); + _log?.Write(localEP, protocol, ex); } catch (ObjectDisposedException) { @@ -490,13 +495,11 @@ namespace DnsServerCore.Dns if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) return; //server stopping - LogManager log = _log; - if (log is not null) - log.Write(localEP, protocol, ex); + _log?.Write(localEP, protocol, ex); } } - private async Task ProcessConnectionAsync(Socket socket, DnsTransportProtocol protocol, bool usingHttps) + private async Task ProcessConnectionAsync(Socket socket, DnsTransportProtocol protocol) { IPEndPoint remoteEP = null; @@ -507,29 +510,18 @@ namespace DnsServerCore.Dns switch (protocol) { case DnsTransportProtocol.Tcp: - await ReadStreamRequestAsync(new NetworkStream(socket), _tcpReceiveTimeout, remoteEP, protocol); + await ReadStreamRequestAsync(new NetworkStream(socket), remoteEP, protocol); break; case DnsTransportProtocol.Tls: SslStream tlsStream = new SslStream(new NetworkStream(socket)); await tlsStream.AuthenticateAsServerAsync(_certificate); - await ReadStreamRequestAsync(tlsStream, _tcpReceiveTimeout, remoteEP, protocol); + await ReadStreamRequestAsync(tlsStream, remoteEP, protocol); break; - case DnsTransportProtocol.Https: - Stream stream = new NetworkStream(socket); - - if (usingHttps) - { - SslStream httpsStream = new SslStream(stream); - await httpsStream.AuthenticateAsServerAsync(_certificate); - - stream = httpsStream; - } - - await ProcessDoHRequestAsync(stream, _tcpReceiveTimeout, remoteEP, usingHttps); - break; + default: + throw new InvalidOperationException(); } } catch (IOException) @@ -538,28 +530,25 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, ex); + _log?.Write(remoteEP, protocol, ex); } finally { - if (socket is not null) - socket.Dispose(); + socket.Dispose(); } } - private async Task ReadStreamRequestAsync(Stream stream, int receiveTimeout, IPEndPoint remoteEP, DnsTransportProtocol protocol) + private async Task ReadStreamRequestAsync(Stream stream, IPEndPoint remoteEP, DnsTransportProtocol protocol) { try { using MemoryStream readBuffer = new MemoryStream(64); - using MemoryStream writeBuffer = new MemoryStream(4096); + using MemoryStream writeBuffer = new MemoryStream(2048); using SemaphoreSlim writeSemaphore = new SemaphoreSlim(1, 1); while (true) { - if (IsQpmLimitCrossed(remoteEP)) + if (IsQpmLimitCrossed(remoteEP.Address)) break; DnsDatagram request; @@ -569,7 +558,7 @@ namespace DnsServerCore.Dns { Task task = DnsDatagram.ReadFromTcpAsync(stream, readBuffer, cancellationTokenSource.Token); - if (await Task.WhenAny(task, Task.Delay(receiveTimeout, cancellationTokenSource.Token)) != task) + if (await Task.WhenAny(task, Task.Delay(_tcpReceiveTimeout, cancellationTokenSource.Token)) != task) { //read timed out await stream.DisposeAsync(); @@ -595,9 +584,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, ex); + _log?.Write(remoteEP, protocol, ex); } } @@ -605,7 +592,7 @@ namespace DnsServerCore.Dns { try { - DnsDatagram response = await PreProcessQueryAsync(request, remoteEP, protocol, IsRecursionAllowed(remoteEP)); + DnsDatagram response = await PreProcessQueryAsync(request, remoteEP, protocol, IsRecursionAllowed(remoteEP.Address)); if (response is null) { await stream.DisposeAsync(); @@ -625,10 +612,7 @@ namespace DnsServerCore.Dns writeSemaphore.Release(); } - LogManager queryLog = _queryLog; - if (queryLog is not null) - queryLog.Write(remoteEP, protocol, request, response); - + _queryLog?.Write(remoteEP, protocol, request, response); _stats.QueueUpdate(request, remoteEP, protocol, response); } catch (IOException) @@ -637,294 +621,258 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager queryLog = _queryLog; - if ((queryLog is not null) && (request is not null)) - queryLog.Write(remoteEP, protocol, request, null); + if (request is not null) + _queryLog.Write(remoteEP, protocol, request, null); - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, ex); + _log?.Write(remoteEP, protocol, ex); } } - private async Task ProcessDoHRequestAsync(Stream stream, int receiveTimeout, IPEndPoint remoteEP, bool usingHttps) + private async Task AcceptQuicConnectionAsync(QuicListener quicListener) { - DnsDatagram dnsRequest = null; - DnsTransportProtocol dnsProtocol = DnsTransportProtocol.Https; - try { while (true) { - bool isSocketRemoteIpPrivate = NetUtilities.IsPrivateIP(remoteEP.Address); - HttpRequest httpRequest; + QuicConnection quicConnection = await quicListener.AcceptConnectionAsync(); - if (usingHttps || !isSocketRemoteIpPrivate) - { - //is HTTPS request or is over public IP - if (IsQpmLimitCrossed(remoteEP)) - break; - - httpRequest = await HttpRequest.ReadRequestAsync(stream, 512).WithTimeout(receiveTimeout); - if (httpRequest is null) - return; //connection closed gracefully by client - } - else - { - //is HTTP request (probably via reverse proxy) and is over private IP - httpRequest = await HttpRequest.ReadRequestAsync(stream, 512).WithTimeout(receiveTimeout); - if (httpRequest is null) - return; //connection closed gracefully by client - - string xRealIp = httpRequest.Headers["X-Real-IP"]; - if (IPAddress.TryParse(xRealIp, out IPAddress address)) - { - //get the real IP address of the requesting client from X-Real-IP header set in nginx proxy_pass block - remoteEP = new IPEndPoint(address, 0); - } - - if (IsQpmLimitCrossed(remoteEP)) - break; - } - - string requestConnection = httpRequest.Headers[HttpRequestHeader.Connection]; - if (string.IsNullOrEmpty(requestConnection)) - requestConnection = "close"; - - switch (httpRequest.RequestPath) - { - case "/dns-query": - if (!usingHttps && !isSocketRemoteIpPrivate) - { - //intentionally blocking public IP addresses from using DNS-over-HTTP (without TLS) - //this feature is intended to be used with an SSL terminated reverse proxy like nginx on private network - await SendErrorAsync(stream, "close", 403, "DNS-over-HTTPS (DoH) queries are supported only on HTTPS."); - return; - } - - DnsTransportProtocol protocol = DnsTransportProtocol.Udp; - - string strRequestAcceptTypes = httpRequest.Headers[HttpRequestHeader.Accept]; - if (string.IsNullOrEmpty(strRequestAcceptTypes)) - { - string strContentType = httpRequest.Headers[HttpRequestHeader.ContentType]; - if (strContentType == "application/dns-message") - protocol = DnsTransportProtocol.Https; - } - else - { - foreach (string acceptType in strRequestAcceptTypes.Split(',')) - { - if (acceptType == "application/dns-message") - { - protocol = DnsTransportProtocol.Https; - break; - } - } - } - - switch (protocol) - { - case DnsTransportProtocol.Https: - #region https wire format - { - switch (httpRequest.HttpMethod) - { - case "GET": - string strRequest = httpRequest.QueryString["dns"]; - if (string.IsNullOrEmpty(strRequest)) - throw new DnsServerException("Missing query string parameter: dns"); - - //convert from base64url to base64 - strRequest = strRequest.Replace('-', '+'); - strRequest = strRequest.Replace('_', '/'); - - //add padding - int x = strRequest.Length % 4; - if (x > 0) - strRequest = strRequest.PadRight(strRequest.Length - x + 4, '='); - - using (MemoryStream mS = new MemoryStream(Convert.FromBase64String(strRequest))) - { - dnsRequest = DnsDatagram.ReadFrom(mS); - } - - break; - - case "POST": - string strContentType = httpRequest.Headers[HttpRequestHeader.ContentType]; - if (string.IsNullOrEmpty(strContentType)) - throw new DnsServerException("Missing Content-Type header."); - - if (strContentType != "application/dns-message") - throw new NotSupportedException("DNS request type not supported: " + strContentType); - - using (MemoryStream mS = new MemoryStream(32)) - { - await httpRequest.InputStream.CopyToAsync(mS, 32); - - mS.Position = 0; - dnsRequest = DnsDatagram.ReadFrom(mS); - } - - break; - - default: - throw new NotSupportedException("DoH request type not supported."); - } - - DnsDatagram dnsResponse = await PreProcessQueryAsync(dnsRequest, remoteEP, protocol, IsRecursionAllowed(remoteEP)); - if (dnsResponse is null) - return; //drop request - - using (MemoryStream mS = new MemoryStream(512)) - { - dnsResponse.WriteTo(mS); - - mS.Position = 0; - await SendContentAsync(stream, requestConnection, "application/dns-message", mS); - } - - LogManager queryLog = _queryLog; - if (queryLog is not null) - queryLog.Write(remoteEP, protocol, dnsRequest, dnsResponse); - - _stats.QueueUpdate(dnsRequest, remoteEP, protocol, dnsResponse); - } - #endregion - break; - - default: - await RedirectAsync(stream, httpRequest.Protocol, requestConnection, (usingHttps ? "https://" : "http://") + httpRequest.Headers[HttpRequestHeader.Host]); - break; - } - - if (requestConnection.Equals("close", StringComparison.OrdinalIgnoreCase)) - return; - - break; - - default: - string path = httpRequest.RequestPath; - - if (!path.StartsWith("/") || path.Contains("/../") || path.Contains("/.../")) - { - await SendErrorAsync(stream, requestConnection, 404); - break; - } - - if (path == "/") - path = "/index.html"; - - path = Path.GetFullPath(_dohwwwFolder + path.Replace('/', Path.DirectorySeparatorChar)); - - if (!path.StartsWith(_dohwwwFolder) || !File.Exists(path)) - { - await SendErrorAsync(stream, requestConnection, 404); - break; - } - - await SendFileAsync(stream, requestConnection, path); - break; - } + _ = ProcessQuicConnectionAsync(quicConnection); } } - catch (TimeoutException) + catch (ObjectDisposedException) { - //ignore timeout exception - } - catch (IOException) - { - //ignore IO exceptions + //server stopped } catch (Exception ex) { - LogManager queryLog = _queryLog; - if ((queryLog is not null) && (dnsRequest is not null)) - queryLog.Write(remoteEP, dnsProtocol, dnsRequest, null); + if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped)) + return; //server stopping - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, dnsProtocol, ex); - - await SendErrorAsync(stream, "close", ex); + _log?.Write(quicListener.LocalEndPoint, DnsTransportProtocol.Quic, ex); } } - private static async Task SendContentAsync(Stream outputStream, string connection, string contentType, Stream content) - { - byte[] bufferHeader = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nDate: " + DateTime.UtcNow.ToString("r") + "\r\nContent-Type: " + contentType + "\r\nContent-Length: " + content.Length + "\r\nX-Robots-Tag: noindex, nofollow\r\nConnection: " + connection + "\r\n\r\n"); - - await outputStream.WriteAsync(bufferHeader); - await content.CopyToAsync(outputStream); - await outputStream.FlushAsync(); - } - - private static Task SendErrorAsync(Stream outputStream, string connection, Exception ex) - { - return SendErrorAsync(outputStream, connection, 500, ex.ToString()); - } - - private static async Task SendErrorAsync(Stream outputStream, string connection, int statusCode, string message = null) + private async Task ProcessQuicConnectionAsync(QuicConnection quicConnection) { try { - string statusString = statusCode + " " + GetHttpStatusString((HttpStatusCode)statusCode); - byte[] bufferContent = Encoding.UTF8.GetBytes("" + statusString + "

    " + statusString + "

    " + (message is 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\nConnection: " + connection + "\r\n\r\n"); + while (true) + { + if (IsQpmLimitCrossed(quicConnection.RemoteEndPoint.Address)) + break; - await outputStream.WriteAsync(bufferHeader); - await outputStream.WriteAsync(bufferContent); - await outputStream.FlushAsync(); + QuicStream quicStream = await quicConnection.AcceptInboundStreamAsync(); + + _ = ProcessQuicStreamRequestAsync(quicStream, quicConnection.RemoteEndPoint); + } + } + catch (QuicException ex) + { + switch (ex.QuicError) + { + case QuicError.ConnectionIdle: + case QuicError.ConnectionAborted: + case QuicError.ConnectionTimeout: + break; + + default: + _log?.Write(quicConnection.RemoteEndPoint, DnsTransportProtocol.Quic, ex); + break; + } + } + catch (Exception ex) + { + _log?.Write(quicConnection.RemoteEndPoint, DnsTransportProtocol.Quic, ex); + } + finally + { + await quicConnection.DisposeAsync(); } - catch - { } } - private static async Task RedirectAsync(Stream outputStream, string protocol, string connection, string location) + private async Task ProcessQuicStreamRequestAsync(QuicStream quicStream, IPEndPoint remoteEP) { + MemoryStream sharedBuffer = new MemoryStream(512); + DnsDatagram request = null; + try { - string statusString = "302 Found"; - byte[] bufferContent = Encoding.UTF8.GetBytes("" + statusString + "

    " + statusString + "

    Location: " + location + "

    "); - byte[] bufferHeader = Encoding.UTF8.GetBytes(protocol + " " + statusString + "\r\nDate: " + DateTime.UtcNow.ToString("r") + "\r\nLocation: " + location + "\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: " + bufferContent.Length + "\r\nX-Robots-Tag: noindex, nofollow\r\nConnection: " + connection + "\r\n\r\n"); + //read dns datagram with timeout + using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource()) + { + Task task = DnsDatagram.ReadFromTcpAsync(quicStream, sharedBuffer, cancellationTokenSource.Token); - await outputStream.WriteAsync(bufferHeader); - await outputStream.WriteAsync(bufferContent); - await outputStream.FlushAsync(); + if (await Task.WhenAny(task, Task.Delay(_tcpReceiveTimeout, cancellationTokenSource.Token)) != task) + { + //read timed out + quicStream.Abort(QuicAbortDirection.Both, (long)DnsOverQuicErrorCodes.DOQ_UNSPECIFIED_ERROR); + return; + } + + cancellationTokenSource.Cancel(); //cancel delay task + + request = await task; + } + + //process request async + DnsDatagram response = await PreProcessQueryAsync(request, remoteEP, DnsTransportProtocol.Quic, IsRecursionAllowed(remoteEP.Address)); + if (response is null) + return; //drop request + + //send response + await response.WriteToTcpAsync(quicStream, sharedBuffer); + + _queryLog?.Write(remoteEP, DnsTransportProtocol.Quic, request, response); + _stats.QueueUpdate(request, remoteEP, DnsTransportProtocol.Quic, response); } - catch - { } - } - - private static async Task SendFileAsync(Stream outputStream, string connection, string filePath) - { - using (FileStream fS = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + catch (IOException) { - byte[] bufferHeader = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nDate: " + DateTime.UtcNow.ToString("r") + "\r\nContent-Type: " + WebUtilities.GetContentType(filePath).MediaType + "\r\nContent-Length: " + fS.Length + "\r\nCache-Control: private, max-age=300\r\nX-Robots-Tag: noindex, nofollow\r\nConnection: " + connection + "\r\n\r\n"); - - await outputStream.WriteAsync(bufferHeader); - await fS.CopyToAsync(outputStream); - await outputStream.FlushAsync(); + //ignore QuicException / IOException } - } - - internal static string GetHttpStatusString(HttpStatusCode statusCode) - { - StringBuilder sb = new StringBuilder(); - - foreach (char c in statusCode.ToString().ToCharArray()) + catch (Exception ex) { - if (char.IsUpper(c) && sb.Length > 0) - sb.Append(' '); + if (request is not null) + _queryLog.Write(remoteEP, DnsTransportProtocol.Quic, request, null); - sb.Append(c); + _log?.Write(remoteEP, DnsTransportProtocol.Quic, ex); + } + finally + { + await sharedBuffer.DisposeAsync(); + await quicStream.DisposeAsync(); } - - return sb.ToString(); } - private bool IsRecursionAllowed(IPEndPoint remoteEP) + private async Task ProcessDoHRequestAsync(HttpContext context) + { + IPEndPoint remoteEP = context.GetRemoteEndPoint(); + DnsDatagram dnsRequest = null; + + try + { + HttpRequest request = context.Request; + HttpResponse response = context.Response; + + if (IsQpmLimitCrossed(remoteEP.Address)) + { + response.StatusCode = 429; + await response.WriteAsync("Too Many Requests"); + return; + } + + if (!request.IsHttps && !NetUtilities.IsPrivateIP(remoteEP.Address)) + { + //intentionally blocking public IP addresses from using DNS-over-HTTP (without TLS) + //this feature is intended to be used with an SSL terminated reverse proxy like nginx on private network + response.StatusCode = 403; + await response.WriteAsync("DNS-over-HTTPS (DoH) queries are supported only on HTTPS."); + return; + } + + switch (request.Method) + { + case "GET": + bool acceptsDoH = false; + string requestAccept = request.Headers["Accept"]; + if (!string.IsNullOrEmpty(requestAccept)) + { + foreach (string mediaType in requestAccept.Split(',')) + { + if (mediaType.Equals("application/dns-message", StringComparison.OrdinalIgnoreCase)) + { + acceptsDoH = true; + break; + } + } + } + + if (!acceptsDoH) + { + response.Redirect((request.IsHttps ? "https://" : "http://") + request.Headers["Host"]); + return; + } + + string dnsRequestBase64Url = request.Query["dns"]; + if (string.IsNullOrEmpty(dnsRequestBase64Url)) + { + response.StatusCode = 400; + await response.WriteAsync("Bad Request"); + return; + } + + //convert from base64url to base64 + dnsRequestBase64Url = dnsRequestBase64Url.Replace('-', '+'); + dnsRequestBase64Url = dnsRequestBase64Url.Replace('_', '/'); + + //add padding + int x = dnsRequestBase64Url.Length % 4; + if (x > 0) + dnsRequestBase64Url = dnsRequestBase64Url.PadRight(dnsRequestBase64Url.Length - x + 4, '='); + + using (MemoryStream mS = new MemoryStream(Convert.FromBase64String(dnsRequestBase64Url))) + { + dnsRequest = DnsDatagram.ReadFrom(mS); + } + + break; + + case "POST": + if (!string.Equals(request.Headers["Content-Type"], "application/dns-message", StringComparison.OrdinalIgnoreCase)) + { + response.StatusCode = 415; + await response.WriteAsync("Unsupported Media Type"); + return; + } + + using (MemoryStream mS = new MemoryStream(32)) + { + await request.Body.CopyToAsync(mS, 32); + + mS.Position = 0; + dnsRequest = DnsDatagram.ReadFrom(mS); + } + + break; + + default: + throw new InvalidOperationException(); + } + + DnsDatagram dnsResponse = await PreProcessQueryAsync(dnsRequest, remoteEP, DnsTransportProtocol.Https, IsRecursionAllowed(remoteEP.Address)); + if (dnsResponse is null) + { + //drop request + context.Connection.RequestClose(); + return; + } + + using (MemoryStream mS = new MemoryStream(512)) + { + dnsResponse.WriteTo(mS); + + mS.Position = 0; + response.ContentType = "application/dns-message"; + response.ContentLength = mS.Length; + + using (Stream s = response.Body) + { + await mS.CopyToAsync(s, 512); + } + } + + _queryLog?.Write(remoteEP, DnsTransportProtocol.Https, dnsRequest, dnsResponse); + _stats.QueueUpdate(dnsRequest, remoteEP, DnsTransportProtocol.Https, dnsResponse); + } + catch (Exception ex) + { + if (dnsRequest is not null) + _queryLog?.Write(remoteEP, DnsTransportProtocol.Https, dnsRequest, null); + + _log?.Write(remoteEP, DnsTransportProtocol.Https, ex); + } + } + + private bool IsRecursionAllowed(IPAddress remoteIP) { switch (_recursion) { @@ -932,24 +880,22 @@ namespace DnsServerCore.Dns return true; case DnsServerRecursion.AllowOnlyForPrivateNetworks: - switch (remoteEP.AddressFamily) + switch (remoteIP.AddressFamily) { case AddressFamily.InterNetwork: case AddressFamily.InterNetworkV6: - return NetUtilities.IsPrivateIP(remoteEP.Address); + return NetUtilities.IsPrivateIP(remoteIP); default: return false; } case DnsServerRecursion.UseSpecifiedNetworks: - IPAddress address = remoteEP.Address; - if (_recursionDeniedNetworks is not null) { foreach (NetworkAddress deniedNetworkAddress in _recursionDeniedNetworks) { - if (deniedNetworkAddress.Contains(address)) + if (deniedNetworkAddress.Contains(remoteIP)) return false; } } @@ -958,12 +904,12 @@ namespace DnsServerCore.Dns { foreach (NetworkAddress allowedNetworkAddress in _recursionAllowedNetworks) { - if (allowedNetworkAddress.Contains(address)) + if (allowedNetworkAddress.Contains(remoteIP)) return true; } } - if (IPAddress.IsLoopback(address)) + if (IPAddress.IsLoopback(remoteIP)) return true; return false; @@ -991,9 +937,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, ex); + _log?.Write(remoteEP, protocol, ex); } } @@ -1001,11 +945,7 @@ namespace DnsServerCore.Dns { //format error if (request.ParsingException is not IOException) - { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, request.ParsingException); - } + _log?.Write(remoteEP, protocol, request.ParsingException); //format error response return new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.FormatError, request.Question, null, null, null, request.EDNS is null ? ushort.MinValue : _udpPayloadSize, request.DnssecOk ? EDnsHeaderFlags.DNSSEC_OK : EDnsHeaderFlags.None) { Tag = DnsServerResponseType.Authoritative }; @@ -1015,9 +955,7 @@ namespace DnsServerCore.Dns { if (!request.VerifySignedRequest(_tsigKeys, out DnsDatagram unsignedRequest, out DnsDatagram errorResponse)) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server received a request that failed TSIG signature verification (RCODE: " + errorResponse.RCODE + "; TSIG Error: " + errorResponse.TsigError + ")"); + _log?.Write(remoteEP, protocol, "DNS Server received a request that failed TSIG signature verification (RCODE: " + errorResponse.RCODE + "; TSIG Error: " + errorResponse.TsigError + ")"); errorResponse.Tag = DnsServerResponseType.Authoritative; return errorResponse; @@ -1046,9 +984,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, ex); + _log?.Write(remoteEP, protocol, ex); } } @@ -1145,9 +1081,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, ex); + _log?.Write(remoteEP, protocol, ex); return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.ServerFailure, request.Question) { Tag = DnsServerResponseType.Authoritative }; } @@ -1183,18 +1117,14 @@ namespace DnsServerCore.Dns } } - LogManager log = _log; - if (!remoteVerified) { - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a NOTIFY request since the request IP address was not recognized by the secondary zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a NOTIFY request since the request IP address was not recognized by the secondary zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return new DnsDatagram(request.Identifier, true, DnsOpcode.Notify, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; } - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server received a NOTIFY request for secondary zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server received a NOTIFY request for secondary zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); if ((request.Answer.Count > 0) && (request.Answer[0].Type == DnsResourceRecordType.SOA)) { @@ -1223,9 +1153,7 @@ namespace DnsServerCore.Dns if ((authZoneInfo is null) || authZoneInfo.Disabled) return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NotAuth, request.Question) { Tag = DnsServerResponseType.Authoritative }; - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server received a zone UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server received a zone UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); async Task IsZoneNameServerAllowedAsync() { @@ -1287,8 +1215,7 @@ namespace DnsServerCore.Dns if (!isUpdateAllowed) { - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request since the request IP address is not allowed by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request since the request IP address is not allowed by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return false; } @@ -1298,8 +1225,7 @@ namespace DnsServerCore.Dns { if ((tsigAuthenticatedKeyName is null) || !authZoneInfo.UpdateSecurityPolicies.TryGetValue(tsigAuthenticatedKeyName.ToLower(), out IReadOnlyDictionary> policyMap)) { - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request since the request is missing TSIG auth required by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request since the request is missing TSIG auth required by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return false; } @@ -1464,8 +1390,7 @@ namespace DnsServerCore.Dns //check for permissions if (!await IsUpdatePermittedAsync()) { - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request due to Dynamic Updates Security Policy for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a zone UPDATE request due to Dynamic Updates Security Policy for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; } @@ -1707,8 +1632,7 @@ namespace DnsServerCore.Dns _authZoneManager.SaveZoneFile(authZoneInfo.Name); - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server successfully processed a zone UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server successfully processed a zone UPDATE request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); //NOERROR return new DnsDatagram(request.Identifier, true, DnsOpcode.Update, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question) { Tag = DnsServerResponseType.Authoritative }; @@ -1720,37 +1644,45 @@ namespace DnsServerCore.Dns IReadOnlyList primaryNameServers = await authZoneInfo.GetPrimaryNameServerAddressesAsync(this); DnsResourceRecord soaRecord = authZoneInfo.GetApexRecords(DnsResourceRecordType.SOA)[0]; - DnsResourceRecordInfo recordInfo = soaRecord.GetRecordInfo(); + AuthRecordInfo recordInfo = soaRecord.GetAuthRecordInfo(); - if (recordInfo.ZoneTransferProtocol == DnsTransportProtocol.Tls) + switch (recordInfo.ZoneTransferProtocol) { - //change name server protocol to TLS - List tcpNameServers = new List(primaryNameServers.Count); + case DnsTransportProtocol.Tls: + case DnsTransportProtocol.Quic: + { + //change name server protocol to TLS/QUIC + List updatedNameServers = new List(primaryNameServers.Count); - foreach (NameServerAddress primaryNameServer in primaryNameServers) - { - if (primaryNameServer.Protocol == DnsTransportProtocol.Tls) - tcpNameServers.Add(primaryNameServer); - else - tcpNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tls)); - } + foreach (NameServerAddress primaryNameServer in primaryNameServers) + { + if (primaryNameServer.Protocol == recordInfo.ZoneTransferProtocol) + updatedNameServers.Add(primaryNameServer); + else + updatedNameServers.Add(primaryNameServer.ChangeProtocol(recordInfo.ZoneTransferProtocol)); + } - primaryNameServers = tcpNameServers; - } - else if (protocol == DnsTransportProtocol.Tcp) - { - //change name server protocol to TCP - List tcpNameServers = new List(primaryNameServers.Count); + primaryNameServers = updatedNameServers; + } + break; - foreach (NameServerAddress primaryNameServer in primaryNameServers) - { - if (primaryNameServer.Protocol == DnsTransportProtocol.Tcp) - tcpNameServers.Add(primaryNameServer); - else - tcpNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tcp)); - } + default: + if (protocol == DnsTransportProtocol.Tcp) + { + //change name server protocol to TCP + List updatedNameServers = new List(primaryNameServers.Count); - primaryNameServers = tcpNameServers; + foreach (NameServerAddress primaryNameServer in primaryNameServers) + { + if (primaryNameServer.Protocol == DnsTransportProtocol.Tcp) + updatedNameServers.Add(primaryNameServer); + else + updatedNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tcp)); + } + + primaryNameServers = updatedNameServers; + } + break; } TsigKey key = null; @@ -1788,13 +1720,10 @@ namespace DnsServerCore.Dns private async Task ProcessZoneTransferQueryAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, string tsigAuthenticatedKeyName) { - LogManager log = _log; - AuthZoneInfo authZoneInfo = _authZoneManager.GetAuthZoneInfo(request.Question[0].Name); if ((authZoneInfo is null) || authZoneInfo.Disabled || authZoneInfo.IsExpired) { - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a zone transfer request due to zone not found, zone disabled, or zone expired reasons for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a zone transfer request due to zone not found, zone disabled, or zone expired reasons for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; } @@ -1806,8 +1735,7 @@ namespace DnsServerCore.Dns break; default: - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a zone transfer request since the DNS server is not authoritative for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a zone transfer request since the DNS server is not authoritative for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; } @@ -1868,8 +1796,7 @@ namespace DnsServerCore.Dns if (!isZoneTransferAllowed) { - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a zone transfer request since the request IP address is not allowed by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a zone transfer request since the request IP address is not allowed by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; } @@ -1878,15 +1805,13 @@ namespace DnsServerCore.Dns { if ((tsigAuthenticatedKeyName is null) || !authZoneInfo.ZoneTransferTsigKeyNames.ContainsKey(tsigAuthenticatedKeyName.ToLower())) { - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server refused a zone transfer request since the request is missing TSIG auth required by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server refused a zone transfer request since the request is missing TSIG auth required by the zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = DnsServerResponseType.Authoritative }; } } - if (log is not null) - log.Write(remoteEP, protocol, "DNS Server received zone transfer request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); + _log?.Write(remoteEP, protocol, "DNS Server received zone transfer request for zone: " + (authZoneInfo.Name == "" ? "" : authZoneInfo.Name)); IReadOnlyList xfrRecords; @@ -1929,9 +1854,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, ex); + _log?.Write(remoteEP, protocol, ex); } } } @@ -2055,16 +1978,12 @@ namespace DnsServerCore.Dns } else { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, "DNS request handler '" + appRecord.ClassPath + "' was not found in the application '" + appRecord.AppName + "': " + appResourceRecord.Name); + _log?.Write(remoteEP, protocol, "DNS request handler '" + appRecord.ClassPath + "' was not found in the application '" + appRecord.AppName + "': " + appResourceRecord.Name); } } else { - LogManager log = _log; - if (log is not null) - log.Write(remoteEP, protocol, "DNS application '" + appRecord.AppName + "' was not found: " + appResourceRecord.Name); + _log?.Write(remoteEP, protocol, "DNS application '" + appRecord.AppName + "' was not found: " + appResourceRecord.Name); } //return server failure response with SOA @@ -2426,7 +2345,7 @@ namespace DnsServerCore.Dns DateTime utcNow = DateTime.UtcNow; foreach (DnsResourceRecord record in authority) - record.GetRecordInfo().LastUsedOn = utcNow; + record.GetAuthRecordInfo().LastUsedOn = utcNow; } } @@ -2951,8 +2870,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) + if (_log is not null) { string strForwarders = null; @@ -2979,7 +2897,7 @@ namespace DnsServerCore.Dns } } - log.Write("DNS Server failed to resolve the request with QNAME: " + question.Name + "; QTYPE: " + question.Type.ToString() + "; QCLASS: " + question.Class.ToString() + (strForwarders is null ? "" : "; Forwarders: " + strForwarders) + ";\r\n" + ex.ToString()); + _log.Write("DNS Server failed to resolve the request with QNAME: " + question.Name + "; QTYPE: " + question.Type.ToString() + "; QCLASS: " + question.Class.ToString() + (strForwarders is null ? "" : "; Forwarders: " + strForwarders) + ";\r\n" + ex.ToString()); } if (_serveStale) @@ -3359,9 +3277,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(ex); + _log?.Write(ex); } } @@ -3391,9 +3307,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(ex); + _log?.Write(ex); cacheRefreshSampleList[sampleQuestionIndex] = sample; //put back into sample list to allow refreshing it again } @@ -3535,9 +3449,7 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(ex); + _log?.Write(ex); } finally { @@ -3577,16 +3489,13 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(ex); + _log?.Write(ex); } finally { lock (_cachePrefetchRefreshTimerLock) { - if (_cachePrefetchRefreshTimer is not null) - _cachePrefetchRefreshTimer.Change((_cachePrefetchTrigger + 1) * 1000, Timeout.Infinite); + _cachePrefetchRefreshTimer?.Change((_cachePrefetchTrigger + 1) * 1000, Timeout.Infinite); } } } @@ -3602,16 +3511,13 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(ex); + _log?.Write(ex); } finally { lock (_cacheMaintenanceTimerLock) { - if (_cacheMaintenanceTimer is not null) - _cacheMaintenanceTimer.Change(CACHE_MAINTENANCE_TIMER_PERIODIC_INTERVAL, Timeout.Infinite); + _cacheMaintenanceTimer?.Change(CACHE_MAINTENANCE_TIMER_PERIODIC_INTERVAL, Timeout.Infinite); } } } @@ -3622,14 +3528,12 @@ namespace DnsServerCore.Dns { lock (_cachePrefetchSamplingTimerLock) { - if (_cachePrefetchSamplingTimer is not null) - _cachePrefetchSamplingTimer.Change(Timeout.Infinite, Timeout.Infinite); + _cachePrefetchSamplingTimer?.Change(Timeout.Infinite, Timeout.Infinite); } lock (_cachePrefetchRefreshTimerLock) { - if (_cachePrefetchRefreshTimer is not null) - _cachePrefetchRefreshTimer.Change(Timeout.Infinite, Timeout.Infinite); + _cachePrefetchRefreshTimer?.Change(Timeout.Infinite, Timeout.Infinite); } } else if (_state == ServiceState.Running) @@ -3645,19 +3549,16 @@ namespace DnsServerCore.Dns lock (_cachePrefetchRefreshTimerLock) { - if (_cachePrefetchRefreshTimer is not null) - _cachePrefetchRefreshTimer.Change(CACHE_PREFETCH_REFRESH_TIMER_INITIAL_INTEVAL, Timeout.Infinite); + _cachePrefetchRefreshTimer?.Change(CACHE_PREFETCH_REFRESH_TIMER_INITIAL_INTEVAL, Timeout.Infinite); } } } - private bool IsQpmLimitCrossed(IPEndPoint remoteEP) + private bool IsQpmLimitCrossed(IPAddress remoteIP) { if ((_qpmLimitRequests < 1) && (_qpmLimitErrors < 1)) return false; - IPAddress remoteIP = remoteEP.Address; - if (IPAddress.IsLoopback(remoteIP)) return false; @@ -3702,16 +3603,13 @@ namespace DnsServerCore.Dns } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(ex); + _log?.Write(ex); } finally { lock (_qpmLimitSamplingTimerLock) { - if (_qpmLimitSamplingTimer is not null) - _qpmLimitSamplingTimer.Change(QPM_LIMIT_SAMPLING_TIMER_INTERVAL, Timeout.Infinite); + _qpmLimitSamplingTimer?.Change(QPM_LIMIT_SAMPLING_TIMER_INTERVAL, Timeout.Infinite); } } } @@ -3722,8 +3620,7 @@ namespace DnsServerCore.Dns { lock (_qpmLimitSamplingTimerLock) { - if (_qpmLimitSamplingTimer is not null) - _qpmLimitSamplingTimer.Change(Timeout.Infinite, Timeout.Infinite); + _qpmLimitSamplingTimer?.Change(Timeout.Infinite, Timeout.Infinite); _qpmLimitClientSubnetStats = null; _qpmLimitErrorClientSubnetStats = null; @@ -3733,8 +3630,7 @@ namespace DnsServerCore.Dns { lock (_qpmLimitSamplingTimerLock) { - if (_qpmLimitSamplingTimer is not null) - _qpmLimitSamplingTimer.Change(0, Timeout.Infinite); + _qpmLimitSamplingTimer?.Change(0, Timeout.Infinite); } } } @@ -3768,9 +3664,301 @@ namespace DnsServerCore.Dns #endregion + #region doh web service + + private async Task StartDoHPrivateAsync() + { + WebApplicationBuilder builder = WebApplication.CreateBuilder(); + + builder.Environment.ContentRootFileProvider = new PhysicalFileProvider(Path.GetDirectoryName(_dohwwwFolder)) + { + UseActivePolling = true, + UsePollingFileWatcher = true + }; + + builder.Environment.WebRootFileProvider = new PhysicalFileProvider(_dohwwwFolder) + { + UseActivePolling = true, + UsePollingFileWatcher = true + }; + + IReadOnlyList localAddresses = GetValidKestralLocalAddresses(_localEndPoints.Convert(delegate (IPEndPoint ep) { return ep.Address; })); + + builder.WebHost.ConfigureKestrel(delegate (WebHostBuilderContext context, KestrelServerOptions serverOptions) + { + foreach (IPAddress localAddress in localAddresses) + serverOptions.Listen(localAddress, _dnsOverHttpPort); + + serverOptions.AddServerHeader = false; + serverOptions.Limits.RequestHeadersTimeout = TimeSpan.FromMilliseconds(_tcpReceiveTimeout); + serverOptions.Limits.KeepAliveTimeout = TimeSpan.FromMilliseconds(_tcpReceiveTimeout); + serverOptions.Limits.MaxRequestHeadersTotalSize = 4096; + serverOptions.Limits.MaxRequestLineSize = serverOptions.Limits.MaxRequestHeadersTotalSize; + serverOptions.Limits.MaxRequestBufferSize = serverOptions.Limits.MaxRequestLineSize; + serverOptions.Limits.MaxRequestBodySize = 64 * 1024; + serverOptions.Limits.MaxResponseBufferSize = 4096; + }); + + builder.Logging.ClearProviders(); + + _dohPrivateWebService = builder.Build(); + + _dohPrivateWebService.UseDefaultFiles(); + _dohPrivateWebService.UseStaticFiles(new StaticFileOptions() + { + OnPrepareResponse = delegate (StaticFileResponseContext ctx) + { + ctx.Context.Response.Headers.Add("X-Robots-Tag", "noindex, nofollow"); + ctx.Context.Response.Headers.Add("Cache-Control", "private, max-age=300"); + } + }); + + _dohPrivateWebService.UseRouting(); + _dohPrivateWebService.MapGet("/dns-query", ProcessDoHRequestAsync); + _dohPrivateWebService.MapPost("/dns-query", ProcessDoHRequestAsync); + + try + { + await _dohPrivateWebService.StartAsync(); + + if (_log is not null) + { + foreach (IPAddress localAddress in localAddresses) + _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server was bound successfully."); + } + } + catch (Exception ex) + { + await StopDoHPrivateAsync(); + + if (_log is not null) + { + foreach (IPAddress localAddress in localAddresses) + _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server failed to bind."); + + _log?.Write(ex); + } + } + } + + private async Task StopDoHPrivateAsync() + { + if (_dohPrivateWebService is not null) + { + await _dohPrivateWebService.DisposeAsync(); + _dohPrivateWebService = null; + } + } + + private async Task StartDoHAsync() + { + WebApplicationBuilder builder = WebApplication.CreateBuilder(); + + builder.Environment.ContentRootFileProvider = new PhysicalFileProvider(Path.GetDirectoryName(_dohwwwFolder)) + { + UseActivePolling = true, + UsePollingFileWatcher = true + }; + + builder.Environment.WebRootFileProvider = new PhysicalFileProvider(_dohwwwFolder) + { + UseActivePolling = true, + UsePollingFileWatcher = true + }; + + IReadOnlyList localAddresses = GetValidKestralLocalAddresses(_localEndPoints.Convert(delegate (IPEndPoint ep) { return ep.Address; })); + + builder.WebHost.ConfigureKestrel(delegate (WebHostBuilderContext context, KestrelServerOptions serverOptions) + { + //bind to http port 80 for certbot webroot support + if (_enableDnsOverHttpPort80) + { + foreach (IPAddress localAddress in localAddresses) + serverOptions.Listen(localAddress, 80); + } + + //bind to https port + if (_certificate is not null) + { + serverOptions.ConfigureHttpsDefaults(delegate (HttpsConnectionAdapterOptions configureOptions) + { + configureOptions.ServerCertificateSelector = delegate (ConnectionContext context, string dnsName) + { + return _certificate; + }; + }); + + foreach (IPAddress localAddress in localAddresses) + { + serverOptions.Listen(localAddress, _dnsOverHttpsPort, delegate (ListenOptions listenOptions) + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; + listenOptions.UseHttps(); + }); + } + } + + serverOptions.AddServerHeader = false; + serverOptions.Limits.RequestHeadersTimeout = TimeSpan.FromMilliseconds(_tcpReceiveTimeout); + serverOptions.Limits.KeepAliveTimeout = TimeSpan.FromMilliseconds(_tcpReceiveTimeout); + serverOptions.Limits.MaxRequestHeadersTotalSize = 4096; + serverOptions.Limits.MaxRequestLineSize = serverOptions.Limits.MaxRequestHeadersTotalSize; + serverOptions.Limits.MaxRequestBufferSize = serverOptions.Limits.MaxRequestLineSize; + serverOptions.Limits.MaxRequestBodySize = 64 * 1024; + serverOptions.Limits.MaxResponseBufferSize = 4096; + }); + + builder.Logging.ClearProviders(); + + _dohWebService = builder.Build(); + + _dohWebService.UseDefaultFiles(); + _dohWebService.UseStaticFiles(new StaticFileOptions() + { + OnPrepareResponse = delegate (StaticFileResponseContext ctx) + { + ctx.Context.Response.Headers.Add("X-Robots-Tag", "noindex, nofollow"); + ctx.Context.Response.Headers.Add("Cache-Control", "private, max-age=300"); + } + }); + + _dohWebService.UseRouting(); + _dohWebService.MapGet("/dns-query", ProcessDoHRequestAsync); + _dohWebService.MapPost("/dns-query", ProcessDoHRequestAsync); + + try + { + await _dohWebService.StartAsync(); + + if (_log is not null) + { + foreach (IPAddress localAddress in localAddresses) + { + if (_enableDnsOverHttpPort80) + _log?.Write(new IPEndPoint(localAddress, 80), "Http", "DNS Server was bound successfully."); + + if (_certificate is not null) + _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpsPort), "Https", "DNS Server was bound successfully."); + } + } + } + catch (Exception ex) + { + await StopDoHAsync(); + + if (_log is not null) + { + foreach (IPAddress localAddress in localAddresses) + { + if (_enableDnsOverHttpPort80) + _log?.Write(new IPEndPoint(localAddress, 80), "Http", "DNS Server failed to bind."); + + if (_certificate is not null) + _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpsPort), "Https", "DNS Server failed to bind."); + } + + _log?.Write(ex); + } + } + } + + private async Task StopDoHAsync() + { + if (_dohWebService is not null) + { + await _dohWebService.DisposeAsync(); + _dohWebService = null; + } + } + + internal static IReadOnlyList GetValidKestralLocalAddresses(IReadOnlyList localAddresses) + { + List supportedLocalAddresses = new List(localAddresses.Count); + + foreach (IPAddress localAddress in localAddresses) + { + switch (localAddress.AddressFamily) + { + case AddressFamily.InterNetwork: + if (Socket.OSSupportsIPv4) + { + if (!supportedLocalAddresses.Contains(localAddress)) + supportedLocalAddresses.Add(localAddress); + } + + break; + + case AddressFamily.InterNetworkV6: + if (Socket.OSSupportsIPv6) + { + if (!supportedLocalAddresses.Contains(localAddress)) + supportedLocalAddresses.Add(localAddress); + } + + break; + } + } + + bool containsUnicastAddress = false; + + foreach (IPAddress localAddress in supportedLocalAddresses) + { + if (!localAddress.Equals(IPAddress.Any) && !localAddress.Equals(IPAddress.IPv6Any)) + { + containsUnicastAddress = true; + break; + } + } + + List newLocalAddresses = new List(supportedLocalAddresses.Count); + + if (containsUnicastAddress) + { + //replace any with loopback address + foreach (IPAddress localAddress in supportedLocalAddresses) + { + if (localAddress.Equals(IPAddress.Any)) + { + if (!newLocalAddresses.Contains(IPAddress.Loopback)) + newLocalAddresses.Add(IPAddress.Loopback); + } + else if (localAddress.Equals(IPAddress.IPv6Any)) + { + if (!newLocalAddresses.Contains(IPAddress.IPv6Loopback)) + newLocalAddresses.Add(IPAddress.IPv6Loopback); + } + else + { + if (!newLocalAddresses.Contains(localAddress)) + newLocalAddresses.Add(localAddress); + } + } + } + else + { + //remove "0.0.0.0" if [::] exists + foreach (IPAddress localAddress in supportedLocalAddresses) + { + if (localAddress.Equals(IPAddress.Any)) + { + if (!supportedLocalAddresses.Contains(IPAddress.IPv6Any)) + newLocalAddresses.Add(localAddress); + } + else + { + newLocalAddresses.Add(localAddress); + } + } + } + + return newLocalAddresses; + } + + #endregion + #region public - public void Start() + public async Task StartAsync() { if (_disposed) throw new ObjectDisposedException("DnsServer"); @@ -3809,18 +3997,13 @@ namespace DnsServerCore.Dns _udpListeners.Add(udpListener); - LogManager log = _log; - if (log is not null) - log.Write(localEP, DnsTransportProtocol.Udp, "DNS Server was bound successfully."); + _log?.Write(localEP, DnsTransportProtocol.Udp, "DNS Server was bound successfully."); } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(localEP, DnsTransportProtocol.Udp, "DNS Server failed to bind.\r\n" + ex.ToString()); + _log?.Write(localEP, DnsTransportProtocol.Udp, "DNS Server failed to bind.\r\n" + ex.ToString()); - if (udpListener is not null) - udpListener.Dispose(); + udpListener?.Dispose(); } Socket tcpListener = null; @@ -3830,58 +4013,22 @@ namespace DnsServerCore.Dns tcpListener = new Socket(localEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); tcpListener.Bind(localEP); - tcpListener.Listen(100); + tcpListener.Listen(_listenBacklog); _tcpListeners.Add(tcpListener); - LogManager log = _log; - if (log is not null) - log.Write(localEP, DnsTransportProtocol.Tcp, "DNS Server was bound successfully."); + _log?.Write(localEP, DnsTransportProtocol.Tcp, "DNS Server was bound successfully."); } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(localEP, DnsTransportProtocol.Tcp, "DNS Server failed to bind.\r\n" + ex.ToString()); + _log?.Write(localEP, DnsTransportProtocol.Tcp, "DNS Server failed to bind.\r\n" + ex.ToString()); - if (tcpListener is not null) - tcpListener.Dispose(); - } - - if (_enableDnsOverHttp) - { - IPEndPoint httpEP = new IPEndPoint(localEP.Address, 8053); - Socket httpListener = null; - - try - { - httpListener = new Socket(httpEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - - httpListener.Bind(httpEP); - httpListener.Listen(100); - - _httpListeners.Add(httpListener); - - _isDnsOverHttpsEnabled = true; - - LogManager log = _log; - if (log is not null) - log.Write(httpEP, "Http", "DNS Server was bound successfully."); - } - catch (Exception ex) - { - LogManager log = _log; - if (log is not null) - log.Write(httpEP, "Http", "DNS Server failed to bind.\r\n" + ex.ToString()); - - if (httpListener is not null) - httpListener.Dispose(); - } + tcpListener?.Dispose(); } if (_enableDnsOverTls && (_certificate is not null)) { - IPEndPoint tlsEP = new IPEndPoint(localEP.Address, 853); + IPEndPoint tlsEP = new IPEndPoint(localEP.Address, _dnsOverTlsPort); Socket tlsListener = null; try @@ -3889,86 +4036,64 @@ namespace DnsServerCore.Dns tlsListener = new Socket(tlsEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); tlsListener.Bind(tlsEP); - tlsListener.Listen(100); + tlsListener.Listen(_listenBacklog); _tlsListeners.Add(tlsListener); - LogManager log = _log; - if (log is not null) - log.Write(tlsEP, DnsTransportProtocol.Tls, "DNS Server was bound successfully."); + _log?.Write(tlsEP, DnsTransportProtocol.Tls, "DNS Server was bound successfully."); } catch (Exception ex) { - LogManager log = _log; - if (log is not null) - log.Write(tlsEP, DnsTransportProtocol.Tls, "DNS Server failed to bind.\r\n" + ex.ToString()); + _log?.Write(tlsEP, DnsTransportProtocol.Tls, "DNS Server failed to bind.\r\n" + ex.ToString()); - if (tlsListener is not null) - tlsListener.Dispose(); + tlsListener?.Dispose(); } } - if (_enableDnsOverHttps) + if (_enableDnsOverQuic && (_certificate is not null)) { - //bind to http port 80 for certbot webroot support + IPEndPoint quicEP = new IPEndPoint(localEP.Address, _dnsOverQuicPort); + QuicListener quicListener = null; + + try { - IPEndPoint httpEP = new IPEndPoint(localEP.Address, 80); - Socket httpListener = null; - - try + QuicListenerOptions listenerOptions = new QuicListenerOptions() { - httpListener = new Socket(httpEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + ListenEndPoint = quicEP, + ListenBacklog = _listenBacklog, + ApplicationProtocols = new List() { new SslApplicationProtocol("doq") }, + ConnectionOptionsCallback = delegate (QuicConnection quicConnection, SslClientHelloInfo sslClientHello, CancellationToken cancellationToken) + { + QuicServerConnectionOptions serverConnectionOptions = new QuicServerConnectionOptions() + { + DefaultCloseErrorCode = (long)DnsOverQuicErrorCodes.DOQ_NO_ERROR, + DefaultStreamErrorCode = (long)DnsOverQuicErrorCodes.DOQ_UNSPECIFIED_ERROR, + MaxInboundUnidirectionalStreams = 0, + MaxInboundBidirectionalStreams = _quicMaxInboundStreams, + IdleTimeout = TimeSpan.FromMilliseconds(_quicIdleTimeout), + ServerAuthenticationOptions = new SslServerAuthenticationOptions + { + ApplicationProtocols = new List() { new SslApplicationProtocol("doq") }, + ServerCertificate = _certificate + } + }; - httpListener.Bind(httpEP); - httpListener.Listen(100); + return ValueTask.FromResult(serverConnectionOptions); + } + }; - _httpListeners.Add(httpListener); + quicListener = await QuicListener.ListenAsync(listenerOptions); - LogManager log = _log; - if (log is not null) - log.Write(httpEP, "Http", "DNS Server was bound successfully."); - } - catch (Exception ex) - { - LogManager log = _log; - if (log is not null) - log.Write(httpEP, "Http", "DNS Server failed to bind.\r\n" + ex.ToString()); + _quicListeners.Add(quicListener); - if (httpListener is not null) - httpListener.Dispose(); - } + _log?.Write(quicEP, DnsTransportProtocol.Quic, "DNS Server was bound successfully."); } - - //bind to https port 443 - if (_certificate is not null) + catch (Exception ex) { - IPEndPoint httpsEP = new IPEndPoint(localEP.Address, 443); - Socket httpsListener = null; + _log?.Write(quicEP, DnsTransportProtocol.Quic, "DNS Server failed to bind.\r\n" + ex.ToString()); - try - { - httpsListener = new Socket(httpsEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - - httpsListener.Bind(httpsEP); - httpsListener.Listen(100); - - _httpsListeners.Add(httpsListener); - - _isDnsOverHttpsEnabled = true; - - LogManager log = _log; - if (log is not null) - log.Write(httpsEP, DnsTransportProtocol.Https, "DNS Server was bound successfully."); - } - catch (Exception ex) - { - LogManager log = _log; - if (log is not null) - log.Write(httpsEP, DnsTransportProtocol.Https, "DNS Server failed to bind.\r\n" + ex.ToString()); - - if (httpsListener is not null) - httpsListener.Dispose(); - } + if (quicListener is not null) + await quicListener.DisposeAsync(); } } } @@ -3993,18 +4118,7 @@ namespace DnsServerCore.Dns { _ = Task.Factory.StartNew(delegate () { - return AcceptConnectionAsync(tcpListener, DnsTransportProtocol.Tcp, false); - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); - } - } - - foreach (Socket httpListener in _httpListeners) - { - for (int i = 0; i < listenerTaskCount; i++) - { - _ = Task.Factory.StartNew(delegate () - { - return AcceptConnectionAsync(httpListener, DnsTransportProtocol.Https, false); + return AcceptConnectionAsync(tcpListener, DnsTransportProtocol.Tcp); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); } } @@ -4015,22 +4129,28 @@ namespace DnsServerCore.Dns { _ = Task.Factory.StartNew(delegate () { - return AcceptConnectionAsync(tlsListener, DnsTransportProtocol.Tls, false); + return AcceptConnectionAsync(tlsListener, DnsTransportProtocol.Tls); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); } } - foreach (Socket httpsListener in _httpsListeners) + foreach (QuicListener quicListener in _quicListeners) { for (int i = 0; i < listenerTaskCount; i++) { _ = Task.Factory.StartNew(delegate () { - return AcceptConnectionAsync(httpsListener, DnsTransportProtocol.Https, true); + return AcceptQuicConnectionAsync(quicListener); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); } } + if (_enableDnsOverHttp) + await StartDoHPrivateAsync(); + + if (_enableDnsOverHttps) + await StartDoHAsync(); + _cachePrefetchSamplingTimer = new Timer(CachePrefetchSamplingTimerCallback, null, Timeout.Infinite, Timeout.Infinite); _cachePrefetchRefreshTimer = new Timer(CachePrefetchRefreshTimerCallback, null, Timeout.Infinite, Timeout.Infinite); _cacheMaintenanceTimer = new Timer(CacheMaintenanceTimerCallback, null, CACHE_MAINTENANCE_TIMER_INITIAL_INTEVAL, Timeout.Infinite); @@ -4043,7 +4163,7 @@ namespace DnsServerCore.Dns ResetQpsLimitTimer(); } - public void Stop() + public async Task StopAsync() { if (_state != ServiceState.Running) return; @@ -4092,20 +4212,19 @@ namespace DnsServerCore.Dns foreach (Socket tcpListener in _tcpListeners) tcpListener.Dispose(); - foreach (Socket httpListener in _httpListeners) - httpListener.Dispose(); - foreach (Socket tlsListener in _tlsListeners) tlsListener.Dispose(); - foreach (Socket httpsListener in _httpsListeners) - httpsListener.Dispose(); + foreach (QuicListener quicListener in _quicListeners) + await quicListener.DisposeAsync(); _udpListeners.Clear(); _tcpListeners.Clear(); - _httpListeners.Clear(); _tlsListeners.Clear(); - _httpsListeners.Clear(); + _quicListeners.Clear(); + + await StopDoHPrivateAsync(); + await StopDoHAsync(); _state = ServiceState.Stopped; } @@ -4152,48 +4271,15 @@ namespace DnsServerCore.Dns set { _localEndPoints = value; } } + public LogManager LogManager + { + get { return _log; } + set { _log = value; } + } + public NameServerAddress ThisServer { get { return _thisServer; } } - public bool EnableDnsOverHttp - { - get { return _enableDnsOverHttp; } - set { _enableDnsOverHttp = value; } - } - - public bool EnableDnsOverTls - { - get { return _enableDnsOverTls; } - set { _enableDnsOverTls = value; } - } - - public bool EnableDnsOverHttps - { - get { return _enableDnsOverHttps; } - set { _enableDnsOverHttps = value; } - } - - public bool IsDnsOverHttpsEnabled - { get { return _isDnsOverHttpsEnabled; } } - - public X509Certificate2 Certificate - { - get { return _certificate; } - set - { - if (!value.HasPrivateKey) - throw new ArgumentException("Tls certificate does not contain private key."); - - _certificate = value; - } - } - - public IReadOnlyDictionary TsigKeys - { - get { return _tsigKeys; } - set { _tsigKeys = value; } - } - public AuthZoneManager AuthZoneManager { get { return _authZoneManager; } } @@ -4215,61 +4301,8 @@ namespace DnsServerCore.Dns public IDnsCache DnsCache { get { return _dnsCache; } } - public DnsServerRecursion Recursion - { - get { return _recursion; } - set - { - if (_recursion != value) - { - if ((_recursion == DnsServerRecursion.Deny) || (value == DnsServerRecursion.Deny)) - { - _recursion = value; - ResetPrefetchTimers(); - } - else - { - _recursion = value; - } - } - } - } - - public IReadOnlyCollection RecursionDeniedNetworks - { - get { return _recursionDeniedNetworks; } - set - { - if ((value is not null) && (value.Count > byte.MaxValue)) - throw new ArgumentOutOfRangeException(nameof(RecursionDeniedNetworks), "Networks cannot be more than 255."); - - _recursionDeniedNetworks = value; - } - } - - public IReadOnlyCollection RecursionAllowedNetworks - { - get { return _recursionAllowedNetworks; } - set - { - if ((value is not null) && (value.Count > byte.MaxValue)) - throw new ArgumentOutOfRangeException(nameof(RecursionAllowedNetworks), "Networks cannot be more than 255."); - - _recursionAllowedNetworks = value; - } - } - - public NetProxy Proxy - { - get { return _proxy; } - set { _proxy = value; } - } - - public IReadOnlyList Forwarders - { - get { return _forwarders; } - set { _forwarders = value; } - } + public StatsManager StatsManager + { get { return _stats; } } public bool PreferIPv6 { @@ -4289,24 +4322,6 @@ namespace DnsServerCore.Dns } } - public bool RandomizeName - { - get { return _randomizeName; } - set { _randomizeName = value; } - } - - public bool QnameMinimization - { - get { return _qnameMinimization; } - set { _qnameMinimization = value; } - } - - public bool NsRevalidation - { - get { return _nsRevalidation; } - set { _nsRevalidation = value; } - } - public bool DnssecValidation { get { return _dnssecValidation; } @@ -4445,18 +4460,206 @@ namespace DnsServerCore.Dns } } - public int ForwarderRetries + public int ClientTimeout { - get { return _forwarderRetries; } + get { return _clientTimeout; } set { - if ((value < 1) || (value > 10)) - throw new ArgumentOutOfRangeException(nameof(ForwarderRetries), "Valid range is from 1 to 10."); + if ((value < 1000) || (value > 10000)) + throw new ArgumentOutOfRangeException(nameof(ClientTimeout), "Valid range is from 1000 to 10000."); - _forwarderRetries = value; + _clientTimeout = value; } } + public int TcpSendTimeout + { + get { return _tcpSendTimeout; } + set + { + if ((value < 1000) || (value > 90000)) + throw new ArgumentOutOfRangeException(nameof(TcpSendTimeout), "Valid range is from 1000 to 90000."); + + _tcpSendTimeout = value; + } + } + + public int TcpReceiveTimeout + { + get { return _tcpReceiveTimeout; } + set + { + if ((value < 1000) || (value > 90000)) + throw new ArgumentOutOfRangeException(nameof(TcpReceiveTimeout), "Valid range is from 1000 to 90000."); + + _tcpReceiveTimeout = value; + } + } + + public int QuicIdleTimeout + { + get { return _quicIdleTimeout; } + set + { + if ((value < 1000) || (value > 90000)) + throw new ArgumentOutOfRangeException(nameof(QuicIdleTimeout), "Valid range is from 1000 to 90000."); + + _quicIdleTimeout = value; + } + } + + public int QuicMaxInboundStreams + { + get { return _quicMaxInboundStreams; } + set + { + if ((value < 0) || (value > 1000)) + throw new ArgumentOutOfRangeException(nameof(QuicMaxInboundStreams), "Valid range is from 1 to 1000."); + + _quicMaxInboundStreams = value; + } + } + + public int ListenBacklog + { + get { return _listenBacklog; } + set { _listenBacklog = value; } + } + + public bool EnableDnsOverHttp + { + get { return _enableDnsOverHttp; } + set { _enableDnsOverHttp = value; } + } + + public bool EnableDnsOverTls + { + get { return _enableDnsOverTls; } + set { _enableDnsOverTls = value; } + } + + public bool EnableDnsOverHttps + { + get { return _enableDnsOverHttps; } + set { _enableDnsOverHttps = value; } + } + + public bool EnableDnsOverHttpPort80 + { + get { return _enableDnsOverHttpPort80; } + set { _enableDnsOverHttpPort80 = value; } + } + + public bool EnableDnsOverQuic + { + get { return _enableDnsOverQuic; } + set { _enableDnsOverQuic = value; } + } + + public int DnsOverHttpPort + { + get { return _dnsOverHttpPort; } + set { _dnsOverHttpPort = value; } + } + + public int DnsOverTlsPort + { + get { return _dnsOverTlsPort; } + set { _dnsOverTlsPort = value; } + } + + public int DnsOverHttpsPort + { + get { return _dnsOverHttpsPort; } + set { _dnsOverHttpsPort = value; } + } + + public int DnsOverQuicPort + { + get { return _dnsOverQuicPort; } + set { _dnsOverQuicPort = value; } + } + + public X509Certificate2 Certificate + { + get { return _certificate; } + set + { + if ((value is not null) && !value.HasPrivateKey) + throw new ArgumentException("Tls certificate does not contain private key."); + + _certificate = value; + } + } + + public IReadOnlyDictionary TsigKeys + { + get { return _tsigKeys; } + set { _tsigKeys = value; } + } + + public DnsServerRecursion Recursion + { + get { return _recursion; } + set + { + if (_recursion != value) + { + if ((_recursion == DnsServerRecursion.Deny) || (value == DnsServerRecursion.Deny)) + { + _recursion = value; + ResetPrefetchTimers(); + } + else + { + _recursion = value; + } + } + } + } + + public IReadOnlyCollection RecursionDeniedNetworks + { + get { return _recursionDeniedNetworks; } + set + { + if ((value is not null) && (value.Count > byte.MaxValue)) + throw new ArgumentOutOfRangeException(nameof(RecursionDeniedNetworks), "Networks cannot be more than 255."); + + _recursionDeniedNetworks = value; + } + } + + public IReadOnlyCollection RecursionAllowedNetworks + { + get { return _recursionAllowedNetworks; } + set + { + if ((value is not null) && (value.Count > byte.MaxValue)) + throw new ArgumentOutOfRangeException(nameof(RecursionAllowedNetworks), "Networks cannot be more than 255."); + + _recursionAllowedNetworks = value; + } + } + + public bool RandomizeName + { + get { return _randomizeName; } + set { _randomizeName = value; } + } + + public bool QnameMinimization + { + get { return _qnameMinimization; } + set { _qnameMinimization = value; } + } + + public bool NsRevalidation + { + get { return _nsRevalidation; } + set { _nsRevalidation = value; } + } + public int ResolverRetries { get { return _resolverRetries; } @@ -4469,18 +4672,6 @@ namespace DnsServerCore.Dns } } - public int ForwarderTimeout - { - get { return _forwarderTimeout; } - set - { - if ((value < 1000) || (value > 10000)) - throw new ArgumentOutOfRangeException(nameof(ForwarderTimeout), "Valid range is from 1000 to 10000."); - - _forwarderTimeout = value; - } - } - public int ResolverTimeout { get { return _resolverTimeout; } @@ -4493,30 +4684,6 @@ namespace DnsServerCore.Dns } } - public int ClientTimeout - { - get { return _clientTimeout; } - set - { - if ((value < 1000) || (value > 10000)) - throw new ArgumentOutOfRangeException(nameof(ClientTimeout), "Valid range is from 1000 to 10000."); - - _clientTimeout = value; - } - } - - public int ForwarderConcurrency - { - get { return _forwarderConcurrency; } - set - { - if ((value < 1) || (value > 10)) - throw new ArgumentOutOfRangeException(nameof(ForwarderConcurrency), "Valid range is from 1 to 10."); - - _forwarderConcurrency = value; - } - } - public int ResolverMaxStackCount { get { return _resolverMaxStackCount; } @@ -4636,10 +4803,52 @@ namespace DnsServerCore.Dns } } - public LogManager LogManager + public NetProxy Proxy { - get { return _log; } - set { _log = value; } + get { return _proxy; } + set { _proxy = value; } + } + + public IReadOnlyList Forwarders + { + get { return _forwarders; } + set { _forwarders = value; } + } + + public int ForwarderRetries + { + get { return _forwarderRetries; } + set + { + if ((value < 1) || (value > 10)) + throw new ArgumentOutOfRangeException(nameof(ForwarderRetries), "Valid range is from 1 to 10."); + + _forwarderRetries = value; + } + } + + public int ForwarderTimeout + { + get { return _forwarderTimeout; } + set + { + if ((value < 1000) || (value > 10000)) + throw new ArgumentOutOfRangeException(nameof(ForwarderTimeout), "Valid range is from 1000 to 10000."); + + _forwarderTimeout = value; + } + } + + public int ForwarderConcurrency + { + get { return _forwarderConcurrency; } + set + { + if ((value < 1) || (value > 10)) + throw new ArgumentOutOfRangeException(nameof(ForwarderConcurrency), "Valid range is from 1 to 10."); + + _forwarderConcurrency = value; + } } public LogManager QueryLogManager @@ -4648,33 +4857,6 @@ namespace DnsServerCore.Dns set { _queryLog = value; } } - public StatsManager StatsManager - { get { return _stats; } } - - public int TcpSendTimeout - { - get { return _tcpSendTimeout; } - set - { - if ((value < 1000) || (value > 90000)) - throw new ArgumentOutOfRangeException(nameof(TcpSendTimeout), "Valid range is from 1000 to 60000."); - - _tcpSendTimeout = value; - } - } - - public int TcpReceiveTimeout - { - get { return _tcpReceiveTimeout; } - set - { - if ((value < 1000) || (value > 90000)) - throw new ArgumentOutOfRangeException(nameof(TcpReceiveTimeout), "Valid range is from 1000 to 60000."); - - _tcpReceiveTimeout = value; - } - } - #endregion class CacheRefreshSample @@ -4703,4 +4885,7 @@ namespace DnsServerCore.Dns public DnsDatagram CheckingDisabledResponse { get; } } } + +#pragma warning restore CA2252 // This API requires opting into preview features +#pragma warning restore CA1416 // Validate platform compatibility } From 72793febe501f01cefc3f17778e83d1eaa886a87 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:54:20 +0530 Subject: [PATCH 084/191] Extensions: Updated all query methods to read from both querystring and form. Added MapGetAndPost() methods. --- DnsServerCore/Extensions.cs | 88 +++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/DnsServerCore/Extensions.cs b/DnsServerCore/Extensions.cs index 4b4cbc12..9bd1b403 100644 --- a/DnsServerCore/Extensions.cs +++ b/DnsServerCore/Extensions.cs @@ -18,7 +18,9 @@ along with this program. If not, see . */ using DnsServerCore.Auth; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; using System; using System.Net; using System.Text.Json; @@ -28,14 +30,17 @@ namespace DnsServerCore { static class Extensions { + readonly static string[] HTTP_METHODS = new string[] { "GET", "POST" }; + public static IPEndPoint GetRemoteEndPoint(this HttpContext context) { try { - if (context.Connection.RemoteIpAddress is null) + IPAddress remoteIP = context.Connection.RemoteIpAddress; + if (remoteIP is null) return new IPEndPoint(IPAddress.Any, 0); - if (NetUtilities.IsPrivateIP(context.Connection.RemoteIpAddress)) + if (NetUtilities.IsPrivateIP(remoteIP)) { string xRealIp = context.Request.Headers["X-Real-IP"]; if (IPAddress.TryParse(xRealIp, out IPAddress address)) @@ -45,7 +50,7 @@ namespace DnsServerCore } } - return new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort); + return new IPEndPoint(remoteIP, context.Connection.RemotePort); } catch { @@ -69,72 +74,91 @@ namespace DnsServerCore throw new InvalidOperationException(); } - public static string GetQuery(this HttpRequest request, string parameter) + public static IEndpointConventionBuilder MapGetAndPost(this IEndpointRouteBuilder endpoints, string pattern, RequestDelegate requestDelegate) + { + return endpoints.MapMethods(pattern, HTTP_METHODS, requestDelegate); + } + + public static IEndpointConventionBuilder MapGetAndPost(this IEndpointRouteBuilder endpoints, string pattern, Delegate handler) + { + return endpoints.MapMethods(pattern, HTTP_METHODS, handler); + } + + public static string QueryOrForm(this HttpRequest request, string parameter) { string value = request.Query[parameter]; + if ((value is null) && request.HasFormContentType) + value = request.Form[parameter]; + + return value; + } + + public static string GetQueryOrForm(this HttpRequest request, string parameter) + { + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); return value; } - public static string GetQuery(this HttpRequest request, string parameter, string defaultValue) + public static string GetQueryOrForm(this HttpRequest request, string parameter, string defaultValue) { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) return defaultValue; return value; } - public static T GetQuery(this HttpRequest request, string parameter, Func parse) + public static T GetQueryOrForm(this HttpRequest request, string parameter, Func parse) { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); return parse(value); } - public static T GetQuery(this HttpRequest request, string parameter) where T : struct + public static T GetQueryOrForm(this HttpRequest request, string parameter) where T : struct { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); return Enum.Parse(value, true); } - public static T GetQuery(this HttpRequest request, string parameter, Func parse, T defaultValue) + public static T GetQueryOrForm(this HttpRequest request, string parameter, Func parse, T defaultValue) { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) return defaultValue; return parse(value); } - public static T GetQuery(this HttpRequest request, string parameter, T defaultValue) where T : struct + public static T GetQueryOrForm(this HttpRequest request, string parameter, T defaultValue) where T : struct { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) return defaultValue; return Enum.Parse(value, true); } - public static bool TryGetQuery(this HttpRequest request, string parameter, out string value) + public static bool TryGetQueryOrForm(this HttpRequest request, string parameter, out string value) { - value = request.Query[parameter]; + value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) return false; return true; } - public static bool TryGetQuery(this HttpRequest request, string parameter, Func parse, out T value) + public static bool TryGetQueryOrForm(this HttpRequest request, string parameter, Func parse, out T value) { - string strValue = request.Query[parameter]; + string strValue = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(strValue)) { value = default; @@ -145,9 +169,9 @@ namespace DnsServerCore return true; } - public static bool TryGetQuery(this HttpRequest request, string parameter, out T value) where T : struct + public static bool TryGetQueryOrForm(this HttpRequest request, string parameter, out T value) where T : struct { - string strValue = request.Query[parameter]; + string strValue = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(strValue)) { value = default; @@ -157,12 +181,12 @@ namespace DnsServerCore return Enum.TryParse(strValue, true, out value); } - public static string GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter) + public static string GetQueryOrFormAlt(this HttpRequest request, string parameter, string alternateParameter) { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) { - value = request.Query[alternateParameter]; + value = request.QueryOrForm(alternateParameter); if (string.IsNullOrEmpty(value)) throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); } @@ -170,12 +194,12 @@ namespace DnsServerCore return value; } - public static string GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter, string defaultValue) + public static string GetQueryOrFormAlt(this HttpRequest request, string parameter, string alternateParameter, string defaultValue) { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) { - value = request.Query[alternateParameter]; + value = request.QueryOrForm(alternateParameter); if (string.IsNullOrEmpty(value)) return defaultValue; } @@ -183,12 +207,12 @@ namespace DnsServerCore return value; } - public static T GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter, Func parse) + public static T GetQueryOrFormAlt(this HttpRequest request, string parameter, string alternateParameter, Func parse) { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) { - value = request.Query[alternateParameter]; + value = request.QueryOrForm(alternateParameter); if (string.IsNullOrEmpty(value)) throw new DnsWebServiceException("Parameter '" + parameter + "' missing."); } @@ -196,12 +220,12 @@ namespace DnsServerCore return parse(value); } - public static T GetQueryAlt(this HttpRequest request, string parameter, string alternateParameter, Func parse, T defaultValue) + public static T GetQueryOrFormAlt(this HttpRequest request, string parameter, string alternateParameter, Func parse, T defaultValue) { - string value = request.Query[parameter]; + string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) { - value = request.Query[alternateParameter]; + value = request.QueryOrForm(alternateParameter); if (string.IsNullOrEmpty(value)) return defaultValue; } From 0d00100cd2e63dc622b58b800a8d0048bca21dbd Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 14:59:50 +0530 Subject: [PATCH 085/191] DnsWebService: Implemented support for save dns cache feature. Added TryStartWebServiceAsync() to handle web service startup failures. Updated ConfigureWebServiceRoutes() to use MapGetAndPost() to allow all API calls to read from query string and form data. Updated config serializers to support new dns options. Code refactoring done. --- DnsServerCore/DnsWebService.cs | 818 ++++++++++++++------------------- 1 file changed, 334 insertions(+), 484 deletions(-) diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index a37de8ca..ff20f45c 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -20,7 +20,6 @@ along with this program. If not, see . using DnsServerCore.Auth; using DnsServerCore.Dhcp; using DnsServerCore.Dns; -using DnsServerCore.Dns.ResourceRecords; using DnsServerCore.Dns.ZoneManagers; using DnsServerCore.Dns.Zones; using Microsoft.AspNetCore.Builder; @@ -37,7 +36,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; -using System.Net.Http; +using System.Net.Quic; using System.Net.Sockets; using System.Reflection; using System.Security.Cryptography; @@ -62,23 +61,27 @@ namespace DnsServerCore internal readonly Version _currentVersion; readonly string _appFolder; internal readonly string _configFolder; - readonly Uri _updateCheckUri; internal readonly LogManager _log; internal readonly AuthManager _authManager; - internal readonly WebServiceSettingsApi _settingsApi; - internal readonly WebServiceAuthApi _authApi; - internal readonly WebServiceDashboardApi _dashboardApi; + readonly WebServiceApi _api; + readonly WebServiceDashboardApi _dashboardApi; internal readonly WebServiceZonesApi _zonesApi; - internal readonly WebServiceOtherZonesApi _otherZonesApi; + readonly WebServiceOtherZonesApi _otherZonesApi; internal readonly WebServiceAppsApi _appsApi; - internal readonly WebServiceDhcpApi _dhcpApi; - internal readonly WebServiceLogsApi _logsApi; + readonly WebServiceSettingsApi _settingsApi; + readonly WebServiceDhcpApi _dhcpApi; + readonly WebServiceAuthApi _authApi; + readonly WebServiceLogsApi _logsApi; - internal DnsServer _dnsServer; - internal DhcpServer _dhcpServer; + WebApplication _webService; + X509Certificate2 _webServiceTlsCertificate; + DnsServer _dnsServer; + DhcpServer _dhcpServer; + + //web service internal IReadOnlyList _webServiceLocalAddresses = new IPAddress[] { IPAddress.Any, IPAddress.IPv6Any }; internal int _webServiceHttpPort = 5380; internal int _webServiceTlsPort = 53443; @@ -87,16 +90,16 @@ namespace DnsServerCore internal bool _webServiceUseSelfSignedTlsCertificate; internal string _webServiceTlsCertificatePath; internal string _webServiceTlsCertificatePassword; - internal DateTime _webServiceTlsCertificateLastModifiedOn; - - WebApplication _webService; - X509Certificate2 _webServiceTlsCertificate; - readonly IndependentTaskScheduler _webServiceTaskScheduler = new IndependentTaskScheduler(ThreadPriority.AboveNormal); + DateTime _webServiceTlsCertificateLastModifiedOn; + //optional protocols internal string _dnsTlsCertificatePath; internal string _dnsTlsCertificatePassword; DateTime _dnsTlsCertificateLastModifiedOn; + //cache + internal bool _saveCache; + Timer _tlsCertificateUpdateTimer; const int TLS_CERTIFICATE_UPDATE_TIMER_INITIAL_INTERVAL = 60000; const int TLS_CERTIFICATE_UPDATE_TIMER_INTERVAL = 60000; @@ -119,21 +122,20 @@ namespace DnsServerCore else _configFolder = configFolder; - _updateCheckUri = updateCheckUri; - Directory.CreateDirectory(_configFolder); Directory.CreateDirectory(Path.Combine(_configFolder, "blocklists")); _log = new LogManager(_configFolder); _authManager = new AuthManager(_configFolder, _log); - _settingsApi = new WebServiceSettingsApi(this); - _authApi = new WebServiceAuthApi(this); + _api = new WebServiceApi(this, updateCheckUri); _dashboardApi = new WebServiceDashboardApi(this); _zonesApi = new WebServiceZonesApi(this); _otherZonesApi = new WebServiceOtherZonesApi(this); _appsApi = new WebServiceAppsApi(this, appStoreUri); + _settingsApi = new WebServiceSettingsApi(this); _dhcpApi = new WebServiceDhcpApi(this); + _authApi = new WebServiceAuthApi(this); _logsApi = new WebServiceLogsApi(this); } @@ -150,17 +152,11 @@ namespace DnsServerCore await StopAsync(); - if (_settingsApi is not null) - _settingsApi.Dispose(); - if (_appsApi is not null) _appsApi.Dispose(); - if (_dnsServer is not null) - _dnsServer.Dispose(); - - if (_dhcpServer is not null) - _dhcpServer.Dispose(); + if (_settingsApi is not null) + _settingsApi.Dispose(); if (_authManager is not null) _authManager.Dispose(); @@ -178,11 +174,59 @@ namespace DnsServerCore #endregion - #region private + #region server version + + internal string GetServerVersion() + { + return GetCleanVersion(_currentVersion); + } + + internal static string GetCleanVersion(Version version) + { + string strVersion = version.Major + "." + version.Minor; + + if (version.Build > 0) + strVersion += "." + version.Build; + + if (version.Revision > 0) + strVersion += "." + version.Revision; + + return strVersion; + } + + #endregion #region web service - internal async Task StartWebServiceAsync() + internal async Task TryStartWebServiceAsync() + { + try + { + _webServiceLocalAddresses = DnsServer.GetValidKestralLocalAddresses(_webServiceLocalAddresses); + await StartWebServiceAsync(); + } + catch (Exception ex) + { + _log.Write("Web Service failed to start: " + ex.ToString()); + _log.Write("Attempting to start Web Service on ANY (0.0.0.0) fallback address..."); + + try + { + _webServiceLocalAddresses = new IPAddress[] { IPAddress.Any }; + await StartWebServiceAsync(); + } + catch (Exception ex2) + { + _log.Write("Web Service failed to start: " + ex2.ToString()); + _log.Write("Attempting to start Web Service on loopback (127.0.0.1) fallback address..."); + + _webServiceLocalAddresses = new IPAddress[] { IPAddress.Loopback }; + await StartWebServiceAsync(); + } + } + } + + private async Task StartWebServiceAsync() { WebApplicationBuilder builder = WebApplication.CreateBuilder(); @@ -247,14 +291,41 @@ namespace DnsServerCore ConfigureWebServiceRoutes(); - await _webService.StartAsync(); + try + { + await _webService.StartAsync(); - _log.Write(new IPEndPoint(IPAddress.Any, _webServiceHttpPort), "Web Service was started successfully."); + foreach (IPAddress webServiceLocalAddress in _webServiceLocalAddresses) + { + _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Http", "Web Service was bound successfully."); + + if (_webServiceEnableTls && (_webServiceTlsCertificate is not null)) + _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Https", "Web Service was bound successfully."); + } + } + catch + { + await StopWebServiceAsync(); + + foreach (IPAddress webServiceLocalAddress in _webServiceLocalAddresses) + { + _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Http", "Web Service failed to bind."); + + if (_webServiceEnableTls && (_webServiceTlsCertificate is not null)) + _log?.Write(new IPEndPoint(webServiceLocalAddress, _webServiceHttpPort), "Https", "Web Service failed to bind."); + } + + throw; + } } internal async Task StopWebServiceAsync() { - await _webService.DisposeAsync(); + if (_webService is not null) + { + await _webService.DisposeAsync(); + _webService = null; + } } private void ConfigureWebServiceRoutes() @@ -266,134 +337,134 @@ namespace DnsServerCore _webService.UseRouting(); //user auth - _webService.MapGet("/api/user/login", delegate (HttpContext context) { return _authApi.LoginAsync(context, UserSessionType.Standard); }); - _webService.MapGet("/api/user/createToken", delegate (HttpContext context) { return _authApi.LoginAsync(context, UserSessionType.ApiToken); }); - _webService.MapGet("/api/user/logout", _authApi.Logout); + _webService.MapGetAndPost("/api/user/login", delegate (HttpContext context) { return _authApi.LoginAsync(context, UserSessionType.Standard); }); + _webService.MapGetAndPost("/api/user/createToken", delegate (HttpContext context) { return _authApi.LoginAsync(context, UserSessionType.ApiToken); }); + _webService.MapGetAndPost("/api/user/logout", _authApi.Logout); //user - _webService.MapGet("/api/user/session/get", _authApi.GetCurrentSessionDetails); - _webService.MapGet("/api/user/session/delete", delegate (HttpContext context) { _authApi.DeleteSession(context, false); }); - _webService.MapGet("/api/user/changePassword", _authApi.ChangePassword); - _webService.MapGet("/api/user/profile/get", _authApi.GetProfile); - _webService.MapGet("/api/user/profile/set", _authApi.SetProfile); - _webService.MapGet("/api/user/checkForUpdate", CheckForUpdateAsync); + _webService.MapGetAndPost("/api/user/session/get", _authApi.GetCurrentSessionDetails); + _webService.MapGetAndPost("/api/user/session/delete", delegate (HttpContext context) { _authApi.DeleteSession(context, false); }); + _webService.MapGetAndPost("/api/user/changePassword", _authApi.ChangePassword); + _webService.MapGetAndPost("/api/user/profile/get", _authApi.GetProfile); + _webService.MapGetAndPost("/api/user/profile/set", _authApi.SetProfile); + _webService.MapGetAndPost("/api/user/checkForUpdate", _api.CheckForUpdateAsync); //dashboard - _webService.MapGet("/api/dashboard/stats/get", _dashboardApi.GetStats); - _webService.MapGet("/api/dashboard/stats/getTop", _dashboardApi.GetTopStats); - _webService.MapGet("/api/dashboard/stats/deleteAll", _logsApi.DeleteAllStats); + _webService.MapGetAndPost("/api/dashboard/stats/get", _dashboardApi.GetStats); + _webService.MapGetAndPost("/api/dashboard/stats/getTop", _dashboardApi.GetTopStats); + _webService.MapGetAndPost("/api/dashboard/stats/deleteAll", _logsApi.DeleteAllStats); //zones - _webService.MapGet("/api/zones/list", _zonesApi.ListZones); - _webService.MapGet("/api/zones/create", _zonesApi.CreateZoneAsync); - _webService.MapGet("/api/zones/enable", _zonesApi.EnableZone); - _webService.MapGet("/api/zones/disable", _zonesApi.DisableZone); - _webService.MapGet("/api/zones/delete", _zonesApi.DeleteZone); - _webService.MapGet("/api/zones/resync", _zonesApi.ResyncZone); - _webService.MapGet("/api/zones/options/get", _zonesApi.GetZoneOptions); - _webService.MapGet("/api/zones/options/set", _zonesApi.SetZoneOptions); - _webService.MapGet("/api/zones/permissions/get", delegate (HttpContext context) { _authApi.GetPermissionDetails(context, PermissionSection.Zones); }); - _webService.MapGet("/api/zones/permissions/set", delegate (HttpContext context) { _authApi.SetPermissionsDetails(context, PermissionSection.Zones); }); - _webService.MapGet("/api/zones/dnssec/sign", _zonesApi.SignPrimaryZone); - _webService.MapGet("/api/zones/dnssec/unsign", _zonesApi.UnsignPrimaryZone); - _webService.MapGet("/api/zones/dnssec/properties/get", _zonesApi.GetPrimaryZoneDnssecProperties); - _webService.MapGet("/api/zones/dnssec/properties/convertToNSEC", _zonesApi.ConvertPrimaryZoneToNSEC); - _webService.MapGet("/api/zones/dnssec/properties/convertToNSEC3", _zonesApi.ConvertPrimaryZoneToNSEC3); - _webService.MapGet("/api/zones/dnssec/properties/updateNSEC3Params", _zonesApi.UpdatePrimaryZoneNSEC3Parameters); - _webService.MapGet("/api/zones/dnssec/properties/updateDnsKeyTtl", _zonesApi.UpdatePrimaryZoneDnssecDnsKeyTtl); - _webService.MapGet("/api/zones/dnssec/properties/generatePrivateKey", _zonesApi.GenerateAndAddPrimaryZoneDnssecPrivateKey); - _webService.MapGet("/api/zones/dnssec/properties/updatePrivateKey", _zonesApi.UpdatePrimaryZoneDnssecPrivateKey); - _webService.MapGet("/api/zones/dnssec/properties/deletePrivateKey", _zonesApi.DeletePrimaryZoneDnssecPrivateKey); - _webService.MapGet("/api/zones/dnssec/properties/publishAllPrivateKeys", _zonesApi.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys); - _webService.MapGet("/api/zones/dnssec/properties/rolloverDnsKey", _zonesApi.RolloverPrimaryZoneDnsKey); - _webService.MapGet("/api/zones/dnssec/properties/retireDnsKey", _zonesApi.RetirePrimaryZoneDnsKey); - _webService.MapGet("/api/zones/records/add", _zonesApi.AddRecord); - _webService.MapGet("/api/zones/records/get", _zonesApi.GetRecords); - _webService.MapGet("/api/zones/records/update", _zonesApi.UpdateRecord); - _webService.MapGet("/api/zones/records/delete", _zonesApi.DeleteRecord); + _webService.MapGetAndPost("/api/zones/list", _zonesApi.ListZones); + _webService.MapGetAndPost("/api/zones/create", _zonesApi.CreateZoneAsync); + _webService.MapGetAndPost("/api/zones/enable", _zonesApi.EnableZone); + _webService.MapGetAndPost("/api/zones/disable", _zonesApi.DisableZone); + _webService.MapGetAndPost("/api/zones/delete", _zonesApi.DeleteZone); + _webService.MapGetAndPost("/api/zones/resync", _zonesApi.ResyncZone); + _webService.MapGetAndPost("/api/zones/options/get", _zonesApi.GetZoneOptions); + _webService.MapGetAndPost("/api/zones/options/set", _zonesApi.SetZoneOptions); + _webService.MapGetAndPost("/api/zones/permissions/get", delegate (HttpContext context) { _authApi.GetPermissionDetails(context, PermissionSection.Zones); }); + _webService.MapGetAndPost("/api/zones/permissions/set", delegate (HttpContext context) { _authApi.SetPermissionsDetails(context, PermissionSection.Zones); }); + _webService.MapGetAndPost("/api/zones/dnssec/sign", _zonesApi.SignPrimaryZone); + _webService.MapGetAndPost("/api/zones/dnssec/unsign", _zonesApi.UnsignPrimaryZone); + _webService.MapGetAndPost("/api/zones/dnssec/properties/get", _zonesApi.GetPrimaryZoneDnssecProperties); + _webService.MapGetAndPost("/api/zones/dnssec/properties/convertToNSEC", _zonesApi.ConvertPrimaryZoneToNSEC); + _webService.MapGetAndPost("/api/zones/dnssec/properties/convertToNSEC3", _zonesApi.ConvertPrimaryZoneToNSEC3); + _webService.MapGetAndPost("/api/zones/dnssec/properties/updateNSEC3Params", _zonesApi.UpdatePrimaryZoneNSEC3Parameters); + _webService.MapGetAndPost("/api/zones/dnssec/properties/updateDnsKeyTtl", _zonesApi.UpdatePrimaryZoneDnssecDnsKeyTtl); + _webService.MapGetAndPost("/api/zones/dnssec/properties/generatePrivateKey", _zonesApi.GenerateAndAddPrimaryZoneDnssecPrivateKey); + _webService.MapGetAndPost("/api/zones/dnssec/properties/updatePrivateKey", _zonesApi.UpdatePrimaryZoneDnssecPrivateKey); + _webService.MapGetAndPost("/api/zones/dnssec/properties/deletePrivateKey", _zonesApi.DeletePrimaryZoneDnssecPrivateKey); + _webService.MapGetAndPost("/api/zones/dnssec/properties/publishAllPrivateKeys", _zonesApi.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys); + _webService.MapGetAndPost("/api/zones/dnssec/properties/rolloverDnsKey", _zonesApi.RolloverPrimaryZoneDnsKey); + _webService.MapGetAndPost("/api/zones/dnssec/properties/retireDnsKey", _zonesApi.RetirePrimaryZoneDnsKey); + _webService.MapGetAndPost("/api/zones/records/add", _zonesApi.AddRecord); + _webService.MapGetAndPost("/api/zones/records/get", _zonesApi.GetRecords); + _webService.MapGetAndPost("/api/zones/records/update", _zonesApi.UpdateRecord); + _webService.MapGetAndPost("/api/zones/records/delete", _zonesApi.DeleteRecord); //cache - _webService.MapGet("/api/cache/list", _otherZonesApi.ListCachedZones); - _webService.MapGet("/api/cache/delete", _otherZonesApi.DeleteCachedZone); - _webService.MapGet("/api/cache/flush", _otherZonesApi.FlushCache); + _webService.MapGetAndPost("/api/cache/list", _otherZonesApi.ListCachedZones); + _webService.MapGetAndPost("/api/cache/delete", _otherZonesApi.DeleteCachedZone); + _webService.MapGetAndPost("/api/cache/flush", _otherZonesApi.FlushCache); //allowed - _webService.MapGet("/api/allowed/list", _otherZonesApi.ListAllowedZones); - _webService.MapGet("/api/allowed/add", _otherZonesApi.AllowZone); - _webService.MapGet("/api/allowed/delete", _otherZonesApi.DeleteAllowedZone); - _webService.MapGet("/api/allowed/flush", _otherZonesApi.FlushAllowedZone); - _webService.MapPost("/api/allowed/import", _otherZonesApi.ImportAllowedZones); - _webService.MapGet("/api/allowed/export", _otherZonesApi.ExportAllowedZonesAsync); + _webService.MapGetAndPost("/api/allowed/list", _otherZonesApi.ListAllowedZones); + _webService.MapGetAndPost("/api/allowed/add", _otherZonesApi.AllowZone); + _webService.MapGetAndPost("/api/allowed/delete", _otherZonesApi.DeleteAllowedZone); + _webService.MapGetAndPost("/api/allowed/flush", _otherZonesApi.FlushAllowedZone); + _webService.MapGetAndPost("/api/allowed/import", _otherZonesApi.ImportAllowedZones); + _webService.MapGetAndPost("/api/allowed/export", _otherZonesApi.ExportAllowedZonesAsync); //blocked - _webService.MapGet("/api/blocked/list", _otherZonesApi.ListBlockedZones); - _webService.MapGet("/api/blocked/add", _otherZonesApi.BlockZone); - _webService.MapGet("/api/blocked/delete", _otherZonesApi.DeleteBlockedZone); - _webService.MapGet("/api/blocked/flush", _otherZonesApi.FlushBlockedZone); - _webService.MapPost("/api/blocked/import", _otherZonesApi.ImportBlockedZones); - _webService.MapGet("/api/blocked/export", _otherZonesApi.ExportBlockedZonesAsync); + _webService.MapGetAndPost("/api/blocked/list", _otherZonesApi.ListBlockedZones); + _webService.MapGetAndPost("/api/blocked/add", _otherZonesApi.BlockZone); + _webService.MapGetAndPost("/api/blocked/delete", _otherZonesApi.DeleteBlockedZone); + _webService.MapGetAndPost("/api/blocked/flush", _otherZonesApi.FlushBlockedZone); + _webService.MapGetAndPost("/api/blocked/import", _otherZonesApi.ImportBlockedZones); + _webService.MapGetAndPost("/api/blocked/export", _otherZonesApi.ExportBlockedZonesAsync); //apps - _webService.MapGet("/api/apps/list", _appsApi.ListInstalledAppsAsync); - _webService.MapGet("/api/apps/listStoreApps", _appsApi.ListStoreApps); - _webService.MapGet("/api/apps/downloadAndInstall", _appsApi.DownloadAndInstallAppAsync); - _webService.MapGet("/api/apps/downloadAndUpdate", _appsApi.DownloadAndUpdateAppAsync); + _webService.MapGetAndPost("/api/apps/list", _appsApi.ListInstalledAppsAsync); + _webService.MapGetAndPost("/api/apps/listStoreApps", _appsApi.ListStoreApps); + _webService.MapGetAndPost("/api/apps/downloadAndInstall", _appsApi.DownloadAndInstallAppAsync); + _webService.MapGetAndPost("/api/apps/downloadAndUpdate", _appsApi.DownloadAndUpdateAppAsync); _webService.MapPost("/api/apps/install", _appsApi.InstallAppAsync); _webService.MapPost("/api/apps/update", _appsApi.UpdateAppAsync); - _webService.MapGet("/api/apps/uninstall", _appsApi.UninstallApp); - _webService.MapGet("/api/apps/config/get", _appsApi.GetAppConfigAsync); - _webService.MapPost("/api/apps/config/set", _appsApi.SetAppConfigAsync); + _webService.MapGetAndPost("/api/apps/uninstall", _appsApi.UninstallApp); + _webService.MapGetAndPost("/api/apps/config/get", _appsApi.GetAppConfigAsync); + _webService.MapGetAndPost("/api/apps/config/set", _appsApi.SetAppConfigAsync); //dns client - _webService.MapGet("/api/dnsClient/resolve", ResolveQueryAsync); + _webService.MapGetAndPost("/api/dnsClient/resolve", _api.ResolveQueryAsync); //settings - _webService.MapGet("/api/settings/get", _settingsApi.GetDnsSettings); - _webService.MapGet("/api/settings/set", _settingsApi.SetDnsSettings); - _webService.MapGet("/api/settings/getTsigKeyNames", _settingsApi.GetTsigKeyNames); - _webService.MapGet("/api/settings/forceUpdateBlockLists", _settingsApi.ForceUpdateBlockLists); - _webService.MapGet("/api/settings/temporaryDisableBlocking", _settingsApi.TemporaryDisableBlocking); - _webService.MapGet("/api/settings/backup", _settingsApi.BackupSettingsAsync); + _webService.MapGetAndPost("/api/settings/get", _settingsApi.GetDnsSettings); + _webService.MapGetAndPost("/api/settings/set", _settingsApi.SetDnsSettings); + _webService.MapGetAndPost("/api/settings/getTsigKeyNames", _settingsApi.GetTsigKeyNames); + _webService.MapGetAndPost("/api/settings/forceUpdateBlockLists", _settingsApi.ForceUpdateBlockLists); + _webService.MapGetAndPost("/api/settings/temporaryDisableBlocking", _settingsApi.TemporaryDisableBlocking); + _webService.MapGetAndPost("/api/settings/backup", _settingsApi.BackupSettingsAsync); _webService.MapPost("/api/settings/restore", _settingsApi.RestoreSettingsAsync); //dhcp - _webService.MapGet("/api/dhcp/leases/list", _dhcpApi.ListDhcpLeases); - _webService.MapGet("/api/dhcp/leases/remove", _dhcpApi.RemoveDhcpLease); - _webService.MapGet("/api/dhcp/leases/convertToReserved", _dhcpApi.ConvertToReservedLease); - _webService.MapGet("/api/dhcp/leases/convertToDynamic", _dhcpApi.ConvertToDynamicLease); - _webService.MapGet("/api/dhcp/scopes/list", _dhcpApi.ListDhcpScopes); - _webService.MapGet("/api/dhcp/scopes/get", _dhcpApi.GetDhcpScope); - _webService.MapGet("/api/dhcp/scopes/set", _dhcpApi.SetDhcpScopeAsync); - _webService.MapGet("/api/dhcp/scopes/addReservedLease", _dhcpApi.AddReservedLease); - _webService.MapGet("/api/dhcp/scopes/removeReservedLease", _dhcpApi.RemoveReservedLease); - _webService.MapGet("/api/dhcp/scopes/enable", _dhcpApi.EnableDhcpScopeAsync); - _webService.MapGet("/api/dhcp/scopes/disable", _dhcpApi.DisableDhcpScope); - _webService.MapGet("/api/dhcp/scopes/delete", _dhcpApi.DeleteDhcpScope); + _webService.MapGetAndPost("/api/dhcp/leases/list", _dhcpApi.ListDhcpLeases); + _webService.MapGetAndPost("/api/dhcp/leases/remove", _dhcpApi.RemoveDhcpLease); + _webService.MapGetAndPost("/api/dhcp/leases/convertToReserved", _dhcpApi.ConvertToReservedLease); + _webService.MapGetAndPost("/api/dhcp/leases/convertToDynamic", _dhcpApi.ConvertToDynamicLease); + _webService.MapGetAndPost("/api/dhcp/scopes/list", _dhcpApi.ListDhcpScopes); + _webService.MapGetAndPost("/api/dhcp/scopes/get", _dhcpApi.GetDhcpScope); + _webService.MapGetAndPost("/api/dhcp/scopes/set", _dhcpApi.SetDhcpScopeAsync); + _webService.MapGetAndPost("/api/dhcp/scopes/addReservedLease", _dhcpApi.AddReservedLease); + _webService.MapGetAndPost("/api/dhcp/scopes/removeReservedLease", _dhcpApi.RemoveReservedLease); + _webService.MapGetAndPost("/api/dhcp/scopes/enable", _dhcpApi.EnableDhcpScopeAsync); + _webService.MapGetAndPost("/api/dhcp/scopes/disable", _dhcpApi.DisableDhcpScope); + _webService.MapGetAndPost("/api/dhcp/scopes/delete", _dhcpApi.DeleteDhcpScope); //administration - _webService.MapGet("/api/admin/sessions/list", _authApi.ListSessions); - _webService.MapGet("/api/admin/sessions/createToken", _authApi.CreateApiToken); - _webService.MapGet("/api/admin/sessions/delete", delegate (HttpContext context) { _authApi.DeleteSession(context, true); }); - _webService.MapGet("/api/admin/users/list", _authApi.ListUsers); - _webService.MapGet("/api/admin/users/create", _authApi.CreateUser); - _webService.MapGet("/api/admin/users/get", _authApi.GetUserDetails); - _webService.MapGet("/api/admin/users/set", _authApi.SetUserDetails); - _webService.MapGet("/api/admin/users/delete", _authApi.DeleteUser); - _webService.MapGet("/api/admin/groups/list", _authApi.ListGroups); - _webService.MapGet("/api/admin/groups/create", _authApi.CreateGroup); - _webService.MapGet("/api/admin/groups/get", _authApi.GetGroupDetails); - _webService.MapGet("/api/admin/groups/set", _authApi.SetGroupDetails); - _webService.MapGet("/api/admin/groups/delete", _authApi.DeleteGroup); - _webService.MapGet("/api/admin/permissions/list", _authApi.ListPermissions); - _webService.MapGet("/api/admin/permissions/get", delegate (HttpContext context) { _authApi.GetPermissionDetails(context, PermissionSection.Unknown); }); - _webService.MapGet("/api/admin/permissions/set", delegate (HttpContext context) { _authApi.SetPermissionsDetails(context, PermissionSection.Unknown); }); + _webService.MapGetAndPost("/api/admin/sessions/list", _authApi.ListSessions); + _webService.MapGetAndPost("/api/admin/sessions/createToken", _authApi.CreateApiToken); + _webService.MapGetAndPost("/api/admin/sessions/delete", delegate (HttpContext context) { _authApi.DeleteSession(context, true); }); + _webService.MapGetAndPost("/api/admin/users/list", _authApi.ListUsers); + _webService.MapGetAndPost("/api/admin/users/create", _authApi.CreateUser); + _webService.MapGetAndPost("/api/admin/users/get", _authApi.GetUserDetails); + _webService.MapGetAndPost("/api/admin/users/set", _authApi.SetUserDetails); + _webService.MapGetAndPost("/api/admin/users/delete", _authApi.DeleteUser); + _webService.MapGetAndPost("/api/admin/groups/list", _authApi.ListGroups); + _webService.MapGetAndPost("/api/admin/groups/create", _authApi.CreateGroup); + _webService.MapGetAndPost("/api/admin/groups/get", _authApi.GetGroupDetails); + _webService.MapGetAndPost("/api/admin/groups/set", _authApi.SetGroupDetails); + _webService.MapGetAndPost("/api/admin/groups/delete", _authApi.DeleteGroup); + _webService.MapGetAndPost("/api/admin/permissions/list", _authApi.ListPermissions); + _webService.MapGetAndPost("/api/admin/permissions/get", delegate (HttpContext context) { _authApi.GetPermissionDetails(context, PermissionSection.Unknown); }); + _webService.MapGetAndPost("/api/admin/permissions/set", delegate (HttpContext context) { _authApi.SetPermissionsDetails(context, PermissionSection.Unknown); }); //logs - _webService.MapGet("/api/logs/list", _logsApi.ListLogs); - _webService.MapGet("/api/logs/download", _logsApi.DownloadLogAsync); - _webService.MapGet("/api/logs/delete", _logsApi.DeleteLog); - _webService.MapGet("/api/logs/deleteAll", _logsApi.DeleteAllLogs); - _webService.MapGet("/api/logs/query", _logsApi.QueryLogsAsync); + _webService.MapGetAndPost("/api/logs/list", _logsApi.ListLogs); + _webService.MapGetAndPost("/api/logs/download", _logsApi.DownloadLogAsync); + _webService.MapGetAndPost("/api/logs/delete", _logsApi.DeleteLog); + _webService.MapGetAndPost("/api/logs/deleteAll", _logsApi.DeleteAllLogs); + _webService.MapGetAndPost("/api/logs/query", _logsApi.QueryLogsAsync); } private async Task WebServiceApiMiddleware(HttpContext context, RequestDelegate next) @@ -521,7 +592,7 @@ namespace DnsServerCore private bool TryGetSession(HttpContext context, out UserSession session) { - string token = context.Request.GetQuery("token"); + string token = context.Request.GetQueryOrForm("token"); session = _authManager.GetSession(token); if ((session is null) || session.User.Disabled) return false; @@ -541,337 +612,11 @@ namespace DnsServerCore #endregion - #region update api - - private async Task CheckForUpdateAsync(HttpContext context) - { - Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); - - if (_updateCheckUri is null) - { - jsonWriter.WriteBoolean("updateAvailable", false); - return; - } - - try - { - SocketsHttpHandler handler = new SocketsHttpHandler(); - handler.Proxy = _dnsServer.Proxy; - handler.UseProxy = _dnsServer.Proxy is not null; - - using (HttpClient http = new HttpClient(handler)) - { - Stream response = await http.GetStreamAsync(_updateCheckUri); - using JsonDocument jsonDocument = await JsonDocument.ParseAsync(response); - JsonElement jsonResponse = jsonDocument.RootElement; - - string updateVersion = jsonResponse.GetProperty("updateVersion").GetString(); - string updateTitle = jsonResponse.GetPropertyValue("updateTitle", null); - string updateMessage = jsonResponse.GetPropertyValue("updateMessage", null); - string downloadLink = jsonResponse.GetPropertyValue("downloadLink", null); - string instructionsLink = jsonResponse.GetPropertyValue("instructionsLink", null); - string changeLogLink = jsonResponse.GetPropertyValue("changeLogLink", null); - - bool updateAvailable = new Version(updateVersion) > _currentVersion; - - jsonWriter.WriteBoolean("updateAvailable", updateAvailable); - jsonWriter.WriteString("updateVersion", updateVersion); - jsonWriter.WriteString("currentVersion", GetCleanVersion(_currentVersion)); - - if (updateAvailable) - { - jsonWriter.WriteString("updateTitle", updateTitle); - jsonWriter.WriteString("updateMessage", updateMessage); - jsonWriter.WriteString("downloadLink", downloadLink); - jsonWriter.WriteString("instructionsLink", instructionsLink); - jsonWriter.WriteString("changeLogLink", changeLogLink); - } - - string strLog = "Check for update was done {updateAvailable: " + updateAvailable + "; updateVersion: " + updateVersion + ";"; - - if (!string.IsNullOrEmpty(updateTitle)) - strLog += " updateTitle: " + updateTitle + ";"; - - if (!string.IsNullOrEmpty(updateMessage)) - strLog += " updateMessage: " + updateMessage + ";"; - - if (!string.IsNullOrEmpty(downloadLink)) - strLog += " downloadLink: " + downloadLink + ";"; - - if (!string.IsNullOrEmpty(instructionsLink)) - strLog += " instructionsLink: " + instructionsLink + ";"; - - if (!string.IsNullOrEmpty(changeLogLink)) - strLog += " changeLogLink: " + changeLogLink + ";"; - - strLog += "}"; - - _log.Write(context.GetRemoteEndPoint(), strLog); - } - } - catch (Exception ex) - { - _log.Write(context.GetRemoteEndPoint(), "Check for update was done {updateAvailable: False;}\r\n" + ex.ToString()); - - jsonWriter.WriteBoolean("updateAvailable", false); - } - } - - internal static string GetCleanVersion(Version version) - { - string strVersion = version.Major + "." + version.Minor; - - if (version.Build > 0) - strVersion += "." + version.Build; - - if (version.Revision > 0) - strVersion += "." + version.Revision; - - return strVersion; - } - - internal string GetServerVersion() - { - return GetCleanVersion(_currentVersion); - } - - #endregion - - #region dns client api - - private async Task ResolveQueryAsync(HttpContext context) - { - UserSession session = context.GetCurrentSession(); - - if (!_authManager.IsPermitted(PermissionSection.DnsClient, session.User, PermissionFlag.View)) - throw new DnsWebServiceException("Access was denied."); - - HttpRequest request = context.Request; - - string server = request.GetQuery("server"); - string domain = request.GetQuery("domain").Trim(new char[] { '\t', ' ', '.' }); - DnsResourceRecordType type = request.GetQuery("type"); - DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); - bool dnssecValidation = request.GetQuery("dnssec", bool.Parse, false); - bool importResponse = request.GetQuery("import", bool.Parse, false); - NetProxy proxy = _dnsServer.Proxy; - bool preferIPv6 = _dnsServer.PreferIPv6; - ushort udpPayloadSize = _dnsServer.UdpPayloadSize; - bool randomizeName = false; - bool qnameMinimization = _dnsServer.QnameMinimization; - const int RETRIES = 1; - const int TIMEOUT = 10000; - - DnsDatagram dnsResponse; - string dnssecErrorMessage = null; - - if (server.Equals("recursive-resolver", StringComparison.OrdinalIgnoreCase)) - { - if (type == DnsResourceRecordType.AXFR) - throw new DnsServerException("Cannot do zone transfer (AXFR) for 'recursive-resolver'."); - - DnsQuestionRecord question; - - if ((type == DnsResourceRecordType.PTR) && IPAddress.TryParse(domain, out IPAddress address)) - question = new DnsQuestionRecord(address, DnsClass.IN); - else - question = new DnsQuestionRecord(domain, type, DnsClass.IN); - - DnsCache dnsCache = new DnsCache(); - dnsCache.MinimumRecordTtl = 0; - dnsCache.MaximumRecordTtl = 7 * 24 * 60 * 60; - - try - { - dnsResponse = await DnsClient.RecursiveResolveAsync(question, dnsCache, proxy, preferIPv6, udpPayloadSize, randomizeName, qnameMinimization, false, dnssecValidation, null, RETRIES, TIMEOUT); - } - catch (DnsClientResponseDnssecValidationException ex) - { - dnsResponse = ex.Response; - dnssecErrorMessage = ex.Message; - importResponse = false; - } - } - else - { - if ((type == DnsResourceRecordType.AXFR) && (protocol == DnsTransportProtocol.Udp)) - protocol = DnsTransportProtocol.Tcp; - - NameServerAddress nameServer; - - if (server.Equals("this-server", StringComparison.OrdinalIgnoreCase)) - { - switch (protocol) - { - case DnsTransportProtocol.Udp: - nameServer = _dnsServer.ThisServer; - break; - - case DnsTransportProtocol.Tcp: - nameServer = _dnsServer.ThisServer.ChangeProtocol(DnsTransportProtocol.Tcp); - break; - - case DnsTransportProtocol.Tls: - throw new DnsServerException("Cannot use DNS-over-TLS protocol for 'this-server'. Please use the TLS certificate domain name as the server."); - - case DnsTransportProtocol.Https: - throw new DnsServerException("Cannot use DNS-over-HTTPS protocol for 'this-server'. Please use the TLS certificate domain name with a url as the server."); - - default: - throw new NotSupportedException("DNS transport protocol is not supported: " + protocol.ToString()); - } - - proxy = null; //no proxy required for this server - } - else - { - nameServer = NameServerAddress.Parse(server); - - if (nameServer.Protocol != protocol) - nameServer = nameServer.ChangeProtocol(protocol); - - if (nameServer.IsIPEndPointStale) - { - if (proxy is null) - await nameServer.ResolveIPAddressAsync(_dnsServer, _dnsServer.PreferIPv6); - } - else if ((nameServer.DomainEndPoint is null) && ((protocol == DnsTransportProtocol.Udp) || (protocol == DnsTransportProtocol.Tcp))) - { - try - { - await nameServer.ResolveDomainNameAsync(_dnsServer); - } - catch - { } - } - } - - DnsClient dnsClient = new DnsClient(nameServer); - - dnsClient.Proxy = proxy; - dnsClient.PreferIPv6 = preferIPv6; - dnsClient.RandomizeName = randomizeName; - dnsClient.Retries = RETRIES; - dnsClient.Timeout = TIMEOUT; - dnsClient.UdpPayloadSize = udpPayloadSize; - dnsClient.DnssecValidation = dnssecValidation; - - if (dnssecValidation) - { - //load trust anchors into dns client if domain is locally hosted - _dnsServer.AuthZoneManager.LoadTrustAnchorsTo(dnsClient, domain, type); - } - - try - { - dnsResponse = await dnsClient.ResolveAsync(domain, type); - } - catch (DnsClientResponseDnssecValidationException ex) - { - dnsResponse = ex.Response; - dnssecErrorMessage = ex.Message; - importResponse = false; - } - - if (type == DnsResourceRecordType.AXFR) - dnsResponse = dnsResponse.Join(); - } - - if (importResponse) - { - AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.FindAuthZoneInfo(domain); - if ((zoneInfo is null) || ((zoneInfo.Type == AuthZoneType.Secondary) && !zoneInfo.Name.Equals(domain, StringComparison.OrdinalIgnoreCase))) - { - if (!_authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - zoneInfo = _dnsServer.AuthZoneManager.CreatePrimaryZone(domain, _dnsServer.ServerDomain, false); - if (zoneInfo is null) - throw new DnsServerException("Cannot import records: failed to create primary zone."); - - //set permissions - _authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); - _authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); - _authManager.SaveConfigFile(); - } - else - { - if (!_authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) - throw new DnsWebServiceException("Access was denied."); - - switch (zoneInfo.Type) - { - case AuthZoneType.Primary: - break; - - case AuthZoneType.Forwarder: - if (type == DnsResourceRecordType.AXFR) - throw new DnsServerException("Cannot import records via zone transfer: import zone must be of primary type."); - - break; - - default: - throw new DnsServerException("Cannot import records: import zone must be of primary or forwarder type."); - } - } - - if (type == DnsResourceRecordType.AXFR) - { - _dnsServer.AuthZoneManager.SyncZoneTransferRecords(zoneInfo.Name, dnsResponse.Answer); - } - else - { - List importRecords = new List(dnsResponse.Answer.Count + dnsResponse.Authority.Count); - - foreach (DnsResourceRecord record in dnsResponse.Answer) - { - if (record.Name.Equals(zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || record.Name.EndsWith("." + zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || (zoneInfo.Name.Length == 0)) - { - record.RemoveExpiry(); - importRecords.Add(record); - - if (record.Type == DnsResourceRecordType.NS) - record.SyncGlueRecords(dnsResponse.Additional); - } - } - - foreach (DnsResourceRecord record in dnsResponse.Authority) - { - if (record.Name.Equals(zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || record.Name.EndsWith("." + zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || (zoneInfo.Name.Length == 0)) - { - record.RemoveExpiry(); - importRecords.Add(record); - - if (record.Type == DnsResourceRecordType.NS) - record.SyncGlueRecords(dnsResponse.Additional); - } - } - - _dnsServer.AuthZoneManager.ImportRecords(zoneInfo.Name, importRecords); - } - - _log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS Client imported record(s) for authoritative zone {server: " + server + "; zone: " + zoneInfo.Name + "; type: " + type + ";}"); - - _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); - } - - Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); - - if (dnssecErrorMessage is not null) - jsonWriter.WriteString("warningMessage", dnssecErrorMessage); - - jsonWriter.WritePropertyName("result"); - dnsResponse.SerializeTo(jsonWriter); - } - - #endregion - #region tls internal void StartTlsCertificateUpdateTimer() { - if (_tlsCertificateUpdateTimer == null) + if (_tlsCertificateUpdateTimer is null) { _tlsCertificateUpdateTimer = new Timer(delegate (object state) { @@ -911,7 +656,7 @@ namespace DnsServerCore internal void StopTlsCertificateUpdateTimer() { - if (_tlsCertificateUpdateTimer != null) + if (_tlsCertificateUpdateTimer is not null) { _tlsCertificateUpdateTimer.Dispose(); _tlsCertificateUpdateTimer = null; @@ -928,9 +673,7 @@ namespace DnsServerCore if (Path.GetExtension(tlsCertificatePath) != ".pfx") throw new ArgumentException("Web Service TLS certificate file must be PKCS #12 formatted with .pfx extension: " + tlsCertificatePath); - X509Certificate2 certificate = new X509Certificate2(tlsCertificatePath, tlsCertificatePassword); - - _webServiceTlsCertificate = certificate; + _webServiceTlsCertificate = new X509Certificate2(tlsCertificatePath, tlsCertificatePassword); _webServiceTlsCertificateLastModifiedOn = fileInfo.LastWriteTimeUtc; _log.Write("Web Service TLS certificate was loaded: " + tlsCertificatePath); @@ -946,9 +689,7 @@ namespace DnsServerCore if (Path.GetExtension(tlsCertificatePath) != ".pfx") throw new ArgumentException("DNS Server TLS certificate file must be PKCS #12 formatted with .pfx extension: " + tlsCertificatePath); - X509Certificate2 certificate = new X509Certificate2(tlsCertificatePath, tlsCertificatePassword); - - _dnsServer.Certificate = certificate; + _dnsServer.Certificate = new X509Certificate2(tlsCertificatePath, tlsCertificatePassword); _dnsTlsCertificateLastModifiedOn = fileInfo.LastWriteTimeUtc; _log.Write("DNS Server TLS certificate was loaded: " + tlsCertificatePath); @@ -992,6 +733,22 @@ namespace DnsServerCore #endregion + #region quic + + internal static void ValidateQuicSupport() + { +#pragma warning disable CA2252 // This API requires opting into preview features +#pragma warning disable CA1416 // Validate platform compatibility + + if (!QuicConnection.IsSupported) + throw new DnsWebServiceException("DNS-over-QUIC is supported only on Windows 11, Windows Server 2022, and Linux. On Linux, you must install 'libmsquic' and OpenSSL v1.1.1 manually."); + +#pragma warning restore CA1416 // Validate platform compatibility +#pragma warning restore CA2252 // This API requires opting into preview features + } + + #endregion + #region config internal void LoadConfigFile() @@ -1219,7 +976,7 @@ namespace DnsServerCore int version = bR.ReadByte(); - if ((version >= 28) && (version <= 29)) + if ((version >= 28) && (version <= 30)) { ReadConfigFrom(bR, version); } @@ -1333,11 +1090,45 @@ namespace DnsServerCore _dnsServer.TcpSendTimeout = bR.ReadInt32(); _dnsServer.TcpReceiveTimeout = bR.ReadInt32(); + if (version >= 30) + { + _dnsServer.QuicIdleTimeout = bR.ReadInt32(); + _dnsServer.QuicMaxInboundStreams = bR.ReadInt32(); + _dnsServer.ListenBacklog = bR.ReadInt32(); + } + else + { + _dnsServer.QuicIdleTimeout = 60000; + _dnsServer.QuicMaxInboundStreams = 100; + _dnsServer.ListenBacklog = 100; + } + //optional protocols _dnsServer.EnableDnsOverHttp = bR.ReadBoolean(); _dnsServer.EnableDnsOverTls = bR.ReadBoolean(); _dnsServer.EnableDnsOverHttps = bR.ReadBoolean(); + if (version >= 30) + { + _dnsServer.EnableDnsOverHttpPort80 = bR.ReadBoolean(); + _dnsServer.EnableDnsOverQuic = bR.ReadBoolean(); + + _dnsServer.DnsOverHttpPort = bR.ReadInt32(); + _dnsServer.DnsOverTlsPort = bR.ReadInt32(); + _dnsServer.DnsOverHttpsPort = bR.ReadInt32(); + _dnsServer.DnsOverQuicPort = bR.ReadInt32(); + } + else + { + _dnsServer.EnableDnsOverHttpPort80 = _dnsServer.EnableDnsOverHttps; + _dnsServer.EnableDnsOverQuic = false; + + _dnsServer.DnsOverHttpPort = 8053; + _dnsServer.DnsOverTlsPort = 853; + _dnsServer.DnsOverHttpsPort = 443; + _dnsServer.DnsOverQuicPort = 853; + } + _dnsTlsCertificatePath = bR.ReadShortString(); _dnsTlsCertificatePassword = bR.ReadShortString(); @@ -1413,6 +1204,11 @@ namespace DnsServerCore _dnsServer.ResolverMaxStackCount = bR.ReadInt32(); //cache + if (version >= 30) + _saveCache = bR.ReadBoolean(); + else + _saveCache = false; + _dnsServer.ServeStale = bR.ReadBoolean(); _dnsServer.CacheZoneManager.ServeStaleTtl = bR.ReadUInt32(); @@ -2102,7 +1898,7 @@ namespace DnsServerCore private void WriteConfigTo(BinaryWriter bW) { bW.Write(Encoding.ASCII.GetBytes("DS")); //format - bW.Write((byte)29); //version + bW.Write((byte)30); //version //web service { @@ -2163,11 +1959,21 @@ namespace DnsServerCore bW.Write(_dnsServer.ClientTimeout); bW.Write(_dnsServer.TcpSendTimeout); bW.Write(_dnsServer.TcpReceiveTimeout); + bW.Write(_dnsServer.QuicIdleTimeout); + bW.Write(_dnsServer.QuicMaxInboundStreams); + bW.Write(_dnsServer.ListenBacklog); //optional protocols bW.Write(_dnsServer.EnableDnsOverHttp); bW.Write(_dnsServer.EnableDnsOverTls); bW.Write(_dnsServer.EnableDnsOverHttps); + bW.Write(_dnsServer.EnableDnsOverHttpPort80); + bW.Write(_dnsServer.EnableDnsOverQuic); + + bW.Write(_dnsServer.DnsOverHttpPort); + bW.Write(_dnsServer.DnsOverTlsPort); + bW.Write(_dnsServer.DnsOverHttpsPort); + bW.Write(_dnsServer.DnsOverQuicPort); if (_dnsTlsCertificatePath == null) bW.WriteShortString(string.Empty); @@ -2230,6 +2036,7 @@ namespace DnsServerCore bW.Write(_dnsServer.ResolverMaxStackCount); //cache + bW.Write(_saveCache); bW.Write(_dnsServer.ServeStale); bW.Write(_dnsServer.CacheZoneManager.ServeStaleTtl); @@ -2330,8 +2137,6 @@ namespace DnsServerCore #endregion - #endregion - #region public public async Task StartAsync() @@ -2402,12 +2207,28 @@ namespace DnsServerCore }); } - //start dns and dhcp - _dnsServer.Start(); - _dhcpServer.Start(); + //load dns cache async + if (_saveCache) + { + ThreadPool.QueueUserWorkItem(delegate (object state) + { + try + { + _dnsServer.CacheZoneManager.LoadCacheZoneFile(); + } + catch (Exception ex) + { + _log.Write(ex); + } + }); + } //start web service - await StartWebServiceAsync(); + await TryStartWebServiceAsync(); + + //start dns and dhcp + await _dnsServer.StartAsync(); + _dhcpServer.Start(); _log.Write("DNS Server (v" + _currentVersion.ToString() + ") was started successfully."); } @@ -2425,19 +2246,42 @@ namespace DnsServerCore try { - await StopWebServiceAsync(); - _dnsServer.Dispose(); - _dhcpServer.Dispose(); + //stop dns + if (_dnsServer is not null) + await _dnsServer.DisposeAsync(); + + //stop dhcp + if (_dhcpServer is not null) + _dhcpServer.Dispose(); + + //stop web service + if (_settingsApi is not null) + { + _settingsApi.StopBlockListUpdateTimer(); + _settingsApi.StopTemporaryDisableBlockingTimer(); + } - _settingsApi.StopBlockListUpdateTimer(); - _settingsApi.StopTemporaryDisableBlockingTimer(); StopTlsCertificateUpdateTimer(); - _log.Write("DNS Server (v" + _currentVersion.ToString() + ") was stopped successfully."); + await StopWebServiceAsync(); + + if (_saveCache) + { + try + { + _dnsServer.CacheZoneManager.SaveCacheZoneFile(); + } + catch (Exception ex) + { + _log.Write(ex); + } + } + + _log?.Write("DNS Server (v" + _currentVersion.ToString() + ") was stopped successfully."); } catch (Exception ex) { - _log.Write("Failed to stop DNS Server (v" + _currentVersion.ToString() + ")\r\n" + ex.ToString()); + _log?.Write("Failed to stop DNS Server (v" + _currentVersion.ToString() + ")\r\n" + ex.ToString()); throw; } } @@ -2456,6 +2300,12 @@ namespace DnsServerCore #region properties + internal DnsServer DnsServer + { get { return _dnsServer; } } + + internal DhcpServer DhcpServer + { get { return _dhcpServer; } } + public string ConfigFolder { get { return _configFolder; } } From d98796275c5e5b2bbe585222c755325e665c2927 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:00:44 +0530 Subject: [PATCH 086/191] WebServiceApi: create new class to move generic API handlers from main web service class. --- DnsServerCore/WebServiceApi.cs | 384 +++++++++++++++++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 DnsServerCore/WebServiceApi.cs diff --git a/DnsServerCore/WebServiceApi.cs b/DnsServerCore/WebServiceApi.cs new file mode 100644 index 00000000..2ba8eea9 --- /dev/null +++ b/DnsServerCore/WebServiceApi.cs @@ -0,0 +1,384 @@ +/* +Technitium DNS Server +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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using DnsServerCore.Auth; +using DnsServerCore.Dns; +using DnsServerCore.Dns.ResourceRecords; +using DnsServerCore.Dns.Zones; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using TechnitiumLibrary; +using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.ResourceRecords; +using TechnitiumLibrary.Net.Proxy; + +namespace DnsServerCore +{ + class WebServiceApi + { + #region variables + + readonly DnsWebService _dnsWebService; + readonly Uri _updateCheckUri; + + string _checkForUpdateJsonData; + DateTime _checkForUpdateJsonDataUpdatedOn; + const int CHECK_FOR_UPDATE_JSON_DATA_CACHE_TIME_SECONDS = 3600; + + #endregion + + #region constructor + + public WebServiceApi(DnsWebService dnsWebService, Uri updateCheckUri) + { + _dnsWebService = dnsWebService; + _updateCheckUri = updateCheckUri; + } + + #endregion + + #region private + + private async Task GetCheckForUpdateJsonData() + { + if ((_checkForUpdateJsonData is null) || (DateTime.UtcNow > _checkForUpdateJsonDataUpdatedOn.AddSeconds(CHECK_FOR_UPDATE_JSON_DATA_CACHE_TIME_SECONDS))) + { + SocketsHttpHandler handler = new SocketsHttpHandler(); + handler.Proxy = _dnsWebService.DnsServer.Proxy; + handler.UseProxy = _dnsWebService.DnsServer.Proxy is not null; + handler.AutomaticDecompression = DecompressionMethods.All; + + using (HttpClient http = new HttpClient(handler)) + { + _checkForUpdateJsonData = await http.GetStringAsync(_updateCheckUri); + _checkForUpdateJsonDataUpdatedOn = DateTime.UtcNow; + } + } + + return _checkForUpdateJsonData; + } + + #endregion + + #region public + + public async Task CheckForUpdateAsync(HttpContext context) + { + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + + if (_updateCheckUri is null) + { + jsonWriter.WriteBoolean("updateAvailable", false); + return; + } + + try + { + string jsonData = await GetCheckForUpdateJsonData(); + using JsonDocument jsonDocument = JsonDocument.Parse(jsonData); + JsonElement jsonResponse = jsonDocument.RootElement; + + string updateVersion = jsonResponse.GetProperty("updateVersion").GetString(); + string updateTitle = jsonResponse.GetPropertyValue("updateTitle", null); + string updateMessage = jsonResponse.GetPropertyValue("updateMessage", null); + string downloadLink = jsonResponse.GetPropertyValue("downloadLink", null); + string instructionsLink = jsonResponse.GetPropertyValue("instructionsLink", null); + string changeLogLink = jsonResponse.GetPropertyValue("changeLogLink", null); + + bool updateAvailable = new Version(updateVersion) > _dnsWebService._currentVersion; + + jsonWriter.WriteBoolean("updateAvailable", updateAvailable); + jsonWriter.WriteString("updateVersion", updateVersion); + jsonWriter.WriteString("currentVersion", _dnsWebService.GetServerVersion()); + + if (updateAvailable) + { + jsonWriter.WriteString("updateTitle", updateTitle); + jsonWriter.WriteString("updateMessage", updateMessage); + jsonWriter.WriteString("downloadLink", downloadLink); + jsonWriter.WriteString("instructionsLink", instructionsLink); + jsonWriter.WriteString("changeLogLink", changeLogLink); + } + + string strLog = "Check for update was done {updateAvailable: " + updateAvailable + "; updateVersion: " + updateVersion + ";"; + + if (!string.IsNullOrEmpty(updateTitle)) + strLog += " updateTitle: " + updateTitle + ";"; + + if (!string.IsNullOrEmpty(updateMessage)) + strLog += " updateMessage: " + updateMessage + ";"; + + if (!string.IsNullOrEmpty(downloadLink)) + strLog += " downloadLink: " + downloadLink + ";"; + + if (!string.IsNullOrEmpty(instructionsLink)) + strLog += " instructionsLink: " + instructionsLink + ";"; + + if (!string.IsNullOrEmpty(changeLogLink)) + strLog += " changeLogLink: " + changeLogLink + ";"; + + strLog += "}"; + + _dnsWebService._log.Write(context.GetRemoteEndPoint(), strLog); + } + catch (Exception ex) + { + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "Check for update was done {updateAvailable: False;}\r\n" + ex.ToString()); + + jsonWriter.WriteBoolean("updateAvailable", false); + } + } + + public async Task ResolveQueryAsync(HttpContext context) + { + UserSession session = context.GetCurrentSession(); + + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DnsClient, session.User, PermissionFlag.View)) + throw new DnsWebServiceException("Access was denied."); + + HttpRequest request = context.Request; + + string server = request.GetQueryOrForm("server"); + string domain = request.GetQueryOrForm("domain").Trim(new char[] { '\t', ' ', '.' }); + DnsResourceRecordType type = request.GetQueryOrForm("type"); + DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + bool dnssecValidation = request.GetQueryOrForm("dnssec", bool.Parse, false); + bool importResponse = request.GetQueryOrForm("import", bool.Parse, false); + NetProxy proxy = _dnsWebService.DnsServer.Proxy; + bool preferIPv6 = _dnsWebService.DnsServer.PreferIPv6; + ushort udpPayloadSize = _dnsWebService.DnsServer.UdpPayloadSize; + bool randomizeName = false; + bool qnameMinimization = _dnsWebService.DnsServer.QnameMinimization; + const int RETRIES = 1; + const int TIMEOUT = 10000; + + DnsDatagram dnsResponse; + string dnssecErrorMessage = null; + + if (server.Equals("recursive-resolver", StringComparison.OrdinalIgnoreCase)) + { + if (type == DnsResourceRecordType.AXFR) + throw new DnsServerException("Cannot do zone transfer (AXFR) for 'recursive-resolver'."); + + DnsQuestionRecord question; + + if ((type == DnsResourceRecordType.PTR) && IPAddress.TryParse(domain, out IPAddress address)) + question = new DnsQuestionRecord(address, DnsClass.IN); + else + question = new DnsQuestionRecord(domain, type, DnsClass.IN); + + DnsCache dnsCache = new DnsCache(); + dnsCache.MinimumRecordTtl = 0; + dnsCache.MaximumRecordTtl = 7 * 24 * 60 * 60; + + try + { + dnsResponse = await DnsClient.RecursiveResolveAsync(question, dnsCache, proxy, preferIPv6, udpPayloadSize, randomizeName, qnameMinimization, false, dnssecValidation, null, RETRIES, TIMEOUT); + } + catch (DnsClientResponseDnssecValidationException ex) + { + dnsResponse = ex.Response; + dnssecErrorMessage = ex.Message; + importResponse = false; + } + } + else + { + if ((type == DnsResourceRecordType.AXFR) && (protocol == DnsTransportProtocol.Udp)) + protocol = DnsTransportProtocol.Tcp; + + NameServerAddress nameServer; + + if (server.Equals("this-server", StringComparison.OrdinalIgnoreCase)) + { + switch (protocol) + { + case DnsTransportProtocol.Udp: + nameServer = _dnsWebService.DnsServer.ThisServer; + break; + + case DnsTransportProtocol.Tcp: + nameServer = _dnsWebService.DnsServer.ThisServer.ChangeProtocol(DnsTransportProtocol.Tcp); + break; + + case DnsTransportProtocol.Tls: + throw new DnsServerException("Cannot use DNS-over-TLS protocol for 'this-server'. Please use the TLS certificate domain name as the server."); + + case DnsTransportProtocol.Https: + throw new DnsServerException("Cannot use DNS-over-HTTPS protocol for 'this-server'. Please use the TLS certificate domain name with a url as the server."); + + case DnsTransportProtocol.Quic: + throw new DnsServerException("Cannot use DNS-over-QUIC protocol for 'this-server'. Please use the TLS certificate domain name as the server."); + + default: + throw new NotSupportedException("DNS transport protocol is not supported: " + protocol.ToString()); + } + + proxy = null; //no proxy required for this server + } + else + { + nameServer = NameServerAddress.Parse(server); + + if (nameServer.Protocol != protocol) + nameServer = nameServer.ChangeProtocol(protocol); + + if (nameServer.IsIPEndPointStale) + { + if (proxy is null) + await nameServer.ResolveIPAddressAsync(_dnsWebService.DnsServer, _dnsWebService.DnsServer.PreferIPv6); + } + else if ((nameServer.DomainEndPoint is null) && ((protocol == DnsTransportProtocol.Udp) || (protocol == DnsTransportProtocol.Tcp))) + { + try + { + await nameServer.ResolveDomainNameAsync(_dnsWebService.DnsServer); + } + catch + { } + } + } + + DnsClient dnsClient = new DnsClient(nameServer); + + dnsClient.Proxy = proxy; + dnsClient.PreferIPv6 = preferIPv6; + dnsClient.RandomizeName = randomizeName; + dnsClient.Retries = RETRIES; + dnsClient.Timeout = TIMEOUT; + dnsClient.UdpPayloadSize = udpPayloadSize; + dnsClient.DnssecValidation = dnssecValidation; + + if (dnssecValidation) + { + //load trust anchors into dns client if domain is locally hosted + _dnsWebService.DnsServer.AuthZoneManager.LoadTrustAnchorsTo(dnsClient, domain, type); + } + + try + { + dnsResponse = await dnsClient.ResolveAsync(domain, type); + } + catch (DnsClientResponseDnssecValidationException ex) + { + dnsResponse = ex.Response; + dnssecErrorMessage = ex.Message; + importResponse = false; + } + + if (type == DnsResourceRecordType.AXFR) + dnsResponse = dnsResponse.Join(); + } + + if (importResponse) + { + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(domain); + if ((zoneInfo is null) || ((zoneInfo.Type == AuthZoneType.Secondary) && !zoneInfo.Name.Equals(domain, StringComparison.OrdinalIgnoreCase))) + { + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(domain, _dnsWebService.DnsServer.ServerDomain, false); + if (zoneInfo is null) + throw new DnsServerException("Cannot import records: failed to create primary zone."); + + //set permissions + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete); + _dnsWebService._authManager.SaveConfigFile(); + } + else + { + if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) + throw new DnsWebServiceException("Access was denied."); + + switch (zoneInfo.Type) + { + case AuthZoneType.Primary: + break; + + case AuthZoneType.Forwarder: + if (type == DnsResourceRecordType.AXFR) + throw new DnsServerException("Cannot import records via zone transfer: import zone must be of primary type."); + + break; + + default: + throw new DnsServerException("Cannot import records: import zone must be of primary or forwarder type."); + } + } + + if (type == DnsResourceRecordType.AXFR) + { + _dnsWebService.DnsServer.AuthZoneManager.SyncZoneTransferRecords(zoneInfo.Name, dnsResponse.Answer); + } + else + { + List importRecords = new List(dnsResponse.Answer.Count + dnsResponse.Authority.Count); + + foreach (DnsResourceRecord record in dnsResponse.Answer) + { + if (record.Name.Equals(zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || record.Name.EndsWith("." + zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || (zoneInfo.Name.Length == 0)) + { + record.RemoveExpiry(); + importRecords.Add(record); + + if (record.Type == DnsResourceRecordType.NS) + record.SyncGlueRecords(dnsResponse.Additional); + } + } + + foreach (DnsResourceRecord record in dnsResponse.Authority) + { + if (record.Name.Equals(zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || record.Name.EndsWith("." + zoneInfo.Name, StringComparison.OrdinalIgnoreCase) || (zoneInfo.Name.Length == 0)) + { + record.RemoveExpiry(); + importRecords.Add(record); + + if (record.Type == DnsResourceRecordType.NS) + record.SyncGlueRecords(dnsResponse.Additional); + } + } + + _dnsWebService.DnsServer.AuthZoneManager.ImportRecords(zoneInfo.Name, importRecords); + } + + _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS Client imported record(s) for authoritative zone {server: " + server + "; zone: " + zoneInfo.Name + "; type: " + type + ";}"); + + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + } + + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + + if (dnssecErrorMessage is not null) + jsonWriter.WriteString("warningMessage", dnssecErrorMessage); + + jsonWriter.WritePropertyName("result"); + dnsResponse.SerializeTo(jsonWriter); + } + + #endregion + } +} From 553031f7668f6800116c3e97b156a4a860d29dca Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:02:38 +0530 Subject: [PATCH 087/191] WebServiceAppsApi: Updated cache time to 15 mins. Added support for all http decompression methods. Code refactoring done. --- DnsServerCore/WebServiceAppsApi.cs | 75 ++++++++++++++---------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/DnsServerCore/WebServiceAppsApi.cs b/DnsServerCore/WebServiceAppsApi.cs index a02657ef..ed87c093 100644 --- a/DnsServerCore/WebServiceAppsApi.cs +++ b/DnsServerCore/WebServiceAppsApi.cs @@ -42,7 +42,7 @@ namespace DnsServerCore string _storeAppsJsonData; DateTime _storeAppsJsonDataUpdatedOn; - const int STORE_APPS_JSON_DATA_CACHE_TIME_SECONDS = 300; + const int STORE_APPS_JSON_DATA_CACHE_TIME_SECONDS = 900; Timer _appUpdateTimer; const int APP_UPDATE_TIMER_INITIAL_INTERVAL = 10000; @@ -87,7 +87,7 @@ namespace DnsServerCore { try { - if (_dnsWebService._dnsServer.DnsApplicationManager.Applications.Count < 1) + if (_dnsWebService.DnsServer.DnsApplicationManager.Applications.Count < 1) return; _dnsWebService._log.Write("DNS Server has started automatic update check for DNS Apps."); @@ -96,7 +96,7 @@ namespace DnsServerCore using JsonDocument jsonDocument = JsonDocument.Parse(storeAppsJsonData); JsonElement jsonStoreAppsArray = jsonDocument.RootElement; - foreach (DnsApplication application in _dnsWebService._dnsServer.DnsApplicationManager.Applications.Values) + foreach (DnsApplication application in _dnsWebService.DnsServer.DnsApplicationManager.Applications.Values) { foreach (JsonElement jsonStoreApp in jsonStoreAppsArray.EnumerateArray()) { @@ -165,12 +165,12 @@ namespace DnsServerCore private async Task GetStoreAppsJsonData() { - if ((_storeAppsJsonData == null) || (DateTime.UtcNow > _storeAppsJsonDataUpdatedOn.AddSeconds(STORE_APPS_JSON_DATA_CACHE_TIME_SECONDS))) + if ((_storeAppsJsonData is null) || (DateTime.UtcNow > _storeAppsJsonDataUpdatedOn.AddSeconds(STORE_APPS_JSON_DATA_CACHE_TIME_SECONDS))) { SocketsHttpHandler handler = new SocketsHttpHandler(); - handler.Proxy = _dnsWebService._dnsServer.Proxy; - handler.UseProxy = _dnsWebService._dnsServer.Proxy is not null; - handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + handler.Proxy = _dnsWebService.DnsServer.Proxy; + handler.UseProxy = _dnsWebService.DnsServer.Proxy is not null; + handler.AutomaticDecompression = DecompressionMethods.All; using (HttpClient http = new HttpClient(handler)) { @@ -191,9 +191,9 @@ namespace DnsServerCore { //download to temp file SocketsHttpHandler handler = new SocketsHttpHandler(); - handler.Proxy = _dnsWebService._dnsServer.Proxy; - handler.UseProxy = _dnsWebService._dnsServer.Proxy is not null; - handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + handler.Proxy = _dnsWebService.DnsServer.Proxy; + handler.UseProxy = _dnsWebService.DnsServer.Proxy is not null; + handler.AutomaticDecompression = DecompressionMethods.All; using (HttpClient http = new HttpClient(handler)) { @@ -205,7 +205,7 @@ namespace DnsServerCore //update app fS.Position = 0; - return await _dnsWebService._dnsServer.DnsApplicationManager.UpdateApplicationAsync(applicationName, fS); + return await _dnsWebService.DnsServer.DnsApplicationManager.UpdateApplicationAsync(applicationName, fS); } } finally @@ -322,7 +322,7 @@ namespace DnsServerCore throw new DnsWebServiceException("Access was denied."); } - List apps = new List(_dnsWebService._dnsServer.DnsApplicationManager.Applications.Keys); + List apps = new List(_dnsWebService.DnsServer.DnsApplicationManager.Applications.Keys); apps.Sort(); JsonDocument jsonDocument = null; @@ -349,7 +349,7 @@ namespace DnsServerCore foreach (string app in apps) { - if (_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(app, out DnsApplication application)) + if (_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(app, out DnsApplication application)) WriteAppAsJson(jsonWriter, application, jsonStoreAppsArray); } @@ -418,7 +418,7 @@ namespace DnsServerCore jsonWriter.WriteString("url", url); jsonWriter.WriteString("size", size); - bool installed = _dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); + bool installed = _dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication installedApp); jsonWriter.WriteBoolean("installed", installed); @@ -443,8 +443,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name").Trim(); - string url = request.GetQuery("url"); + string name = request.GetQueryOrForm("name").Trim(); + string url = request.GetQueryOrForm("url"); if (!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) throw new DnsWebServiceException("Parameter 'url' value must start with 'https://'."); @@ -456,9 +456,9 @@ namespace DnsServerCore { //download to temp file SocketsHttpHandler handler = new SocketsHttpHandler(); - handler.Proxy = _dnsWebService._dnsServer.Proxy; - handler.UseProxy = _dnsWebService._dnsServer.Proxy is not null; - handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + handler.Proxy = _dnsWebService.DnsServer.Proxy; + handler.UseProxy = _dnsWebService.DnsServer.Proxy is not null; + handler.AutomaticDecompression = DecompressionMethods.All; using (HttpClient http = new HttpClient(handler)) { @@ -470,7 +470,7 @@ namespace DnsServerCore //install app fS.Position = 0; - DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); + DnsApplication application = await _dnsWebService.DnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was installed successfully from: " + url); @@ -502,8 +502,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name").Trim(); - string url = request.GetQuery("url"); + string name = request.GetQueryOrForm("name").Trim(); + string url = request.GetQueryOrForm("url"); if (!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) throw new DnsWebServiceException("Parameter 'url' value must start with 'https://'."); @@ -527,9 +527,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name").Trim(); + string name = request.GetQueryOrForm("name").Trim(); - if (request.Form.Files.Count == 0) + if (!request.HasFormContentType || (request.Form.Files.Count == 0)) throw new DnsWebServiceException("DNS application zip file is missing."); string tmpFile = Path.GetTempFileName(); @@ -542,7 +542,7 @@ namespace DnsServerCore //install app fS.Position = 0; - DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); + DnsApplication application = await _dnsWebService.DnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was installed successfully."); @@ -574,9 +574,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name").Trim(); + string name = request.GetQueryOrForm("name").Trim(); - if (request.Form.Files.Count == 0) + if (!request.HasFormContentType || (request.Form.Files.Count == 0)) throw new DnsWebServiceException("DNS application zip file is missing."); string tmpFile = Path.GetTempFileName(); @@ -589,7 +589,7 @@ namespace DnsServerCore //update app fS.Position = 0; - DnsApplication application = await _dnsWebService._dnsServer.DnsApplicationManager.UpdateApplicationAsync(name, fS); + DnsApplication application = await _dnsWebService.DnsServer.DnsApplicationManager.UpdateApplicationAsync(name, fS); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was updated successfully."); @@ -621,9 +621,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name").Trim(); + string name = request.GetQueryOrForm("name").Trim(); - _dnsWebService._dnsServer.DnsApplicationManager.UninstallApplication(name); + _dnsWebService.DnsServer.DnsApplicationManager.UninstallApplication(name); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNS application '" + name + "' was uninstalled successfully."); } @@ -636,9 +636,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name").Trim(); + string name = request.GetQueryOrForm("name").Trim(); - if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) + if (!_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); string config = await application.GetConfigAsync(); @@ -656,17 +656,14 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name").Trim(); + string name = request.GetQueryOrForm("name").Trim(); - if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) + if (!_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); - if (!request.HasFormContentType) - throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); - - string config = request.Form["config"]; + string config = request.QueryOrForm("config"); if (config is null) - throw new DnsWebServiceException("Form parameter 'config' missing."); + throw new DnsWebServiceException("Parameter 'config' missing."); if (config.Length == 0) config = null; From 0e968443fc9800aefb506d55eed850cb8c6c0ee3 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:03:40 +0530 Subject: [PATCH 088/191] WebServiceAuthApi: code refactoring changes done. --- DnsServerCore/WebServiceAuthApi.cs | 84 +++++++++++++++--------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/DnsServerCore/WebServiceAuthApi.cs b/DnsServerCore/WebServiceAuthApi.cs index 071ac901..89638001 100644 --- a/DnsServerCore/WebServiceAuthApi.cs +++ b/DnsServerCore/WebServiceAuthApi.cs @@ -67,7 +67,7 @@ namespace DnsServerCore jsonWriter.WriteStartObject(); jsonWriter.WriteString("version", _dnsWebService.GetServerVersion()); - jsonWriter.WriteString("dnsServerDomain", _dnsWebService._dnsServer.ServerDomain); + jsonWriter.WriteString("dnsServerDomain", _dnsWebService.DnsServer.ServerDomain); jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService._zonesApi.DefaultRecordTtl); jsonWriter.WritePropertyName("permissions"); @@ -294,10 +294,10 @@ namespace DnsServerCore { HttpRequest request = context.Request; - string username = request.GetQuery("user"); - string password = request.GetQuery("pass"); - string tokenName = (sessionType == UserSessionType.ApiToken) ? request.GetQuery("tokenName") : null; - bool includeInfo = request.GetQuery("includeInfo", bool.Parse, false); + string username = request.GetQueryOrForm("user"); + string password = request.GetQueryOrForm("pass"); + string tokenName = (sessionType == UserSessionType.ApiToken) ? request.GetQueryOrForm("tokenName") : null; + bool includeInfo = request.GetQueryOrForm("includeInfo", bool.Parse, false); IPEndPoint remoteEP = context.GetRemoteEndPoint(); UserSession session = await _dnsWebService._authManager.CreateSessionAsync(sessionType, tokenName, username, password, remoteEP.Address, request.Headers.UserAgent); @@ -312,7 +312,7 @@ namespace DnsServerCore public void Logout(HttpContext context) { - string token = context.Request.GetQuery("token"); + string token = context.Request.GetQueryOrForm("token"); UserSession session = _dnsWebService._authManager.DeleteSession(token); if (session is not null) @@ -337,7 +337,7 @@ namespace DnsServerCore if (session.Type != UserSessionType.Standard) throw new DnsWebServiceException("Access was denied."); - string password = context.Request.GetQuery("pass"); + string password = context.Request.GetQueryOrForm("pass"); session.User.ChangePassword(password); @@ -362,10 +362,10 @@ namespace DnsServerCore HttpRequest request = context.Request; - if (request.TryGetQuery("displayName", out string displayName)) + if (request.TryGetQueryOrForm("displayName", out string displayName)) session.User.DisplayName = displayName; - if (request.TryGetQuery("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) + if (request.TryGetQueryOrForm("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) session.User.SessionTimeoutSeconds = sessionTimeoutSeconds; _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] User profile was updated successfully."); @@ -409,8 +409,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string username = request.GetQuery("user"); - string tokenName = request.GetQuery("tokenName"); + string username = request.GetQueryOrForm("user"); + string tokenName = request.GetQueryOrForm("tokenName"); IPEndPoint remoteEP = context.GetRemoteEndPoint(); @@ -437,7 +437,7 @@ namespace DnsServerCore throw new DnsWebServiceException("Access was denied."); } - string strPartialToken = context.Request.GetQuery("partialToken"); + string strPartialToken = context.Request.GetQueryOrForm("partialToken"); if (session.Token.StartsWith(strPartialToken)) throw new InvalidOperationException("Invalid operation: cannot delete current session."); @@ -505,9 +505,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string displayName = request.Query["displayName"]; - string username = request.GetQuery("user"); - string password = request.GetQuery("pass"); + string displayName = request.QueryOrForm("displayName"); + string username = request.GetQueryOrForm("user"); + string password = request.GetQueryOrForm("pass"); User user = _dnsWebService._authManager.CreateUser(displayName, username, password); @@ -528,8 +528,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string username = request.GetQuery("user"); - bool includeGroups = request.GetQuery("includeGroups", bool.Parse, false); + string username = request.GetQueryOrForm("user"); + bool includeGroups = request.GetQueryOrForm("includeGroups", bool.Parse, false); User user = _dnsWebService._authManager.GetUser(username); if (user is null) @@ -548,19 +548,19 @@ namespace DnsServerCore HttpRequest request = context.Request; - string username = request.GetQuery("user"); + string username = request.GetQueryOrForm("user"); User user = _dnsWebService._authManager.GetUser(username); if (user is null) throw new DnsWebServiceException("No such user exists: " + username); - if (request.TryGetQuery("displayName", out string displayName)) + if (request.TryGetQueryOrForm("displayName", out string displayName)) user.DisplayName = displayName; - if (request.TryGetQuery("newUser", out string newUsername)) + if (request.TryGetQueryOrForm("newUser", out string newUsername)) _dnsWebService._authManager.ChangeUsername(user, newUsername); - if (request.TryGetQuery("disabled", bool.Parse, out bool disabled) && (session.User != user)) //to avoid self lockout + if (request.TryGetQueryOrForm("disabled", bool.Parse, out bool disabled) && (session.User != user)) //to avoid self lockout { user.Disabled = disabled; @@ -577,18 +577,18 @@ namespace DnsServerCore } } - if (request.TryGetQuery("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) + if (request.TryGetQueryOrForm("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) user.SessionTimeoutSeconds = sessionTimeoutSeconds; - string newPassword = request.Query["newPass"]; + string newPassword = request.QueryOrForm("newPass"); if (!string.IsNullOrWhiteSpace(newPassword)) { - int iterations = request.GetQuery("iterations", int.Parse, User.DEFAULT_ITERATIONS); + int iterations = request.GetQueryOrForm("iterations", int.Parse, User.DEFAULT_ITERATIONS); user.ChangePassword(newPassword, iterations); } - string memberOfGroups = request.Query["memberOfGroups"]; + string memberOfGroups = request.QueryOrForm("memberOfGroups"); if (memberOfGroups is not null) { string[] parts = memberOfGroups.Split(','); @@ -635,7 +635,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string username = context.Request.GetQuery("user"); + string username = context.Request.GetQueryOrForm("user"); if (session.User.Username.Equals(username, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("Invalid operation: cannot delete current user."); @@ -687,8 +687,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string groupName = request.GetQuery("group"); - string description = request.GetQuery("description", ""); + string groupName = request.GetQueryOrForm("group"); + string description = request.GetQueryOrForm("description", ""); Group group = _dnsWebService._authManager.CreateGroup(groupName, description); @@ -709,8 +709,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string groupName = request.GetQuery("group"); - bool includeUsers = request.GetQuery("includeUsers", bool.Parse, false); + string groupName = request.GetQueryOrForm("group"); + bool includeUsers = request.GetQueryOrForm("includeUsers", bool.Parse, false); Group group = _dnsWebService._authManager.GetGroup(groupName); if (group is null) @@ -729,19 +729,19 @@ namespace DnsServerCore HttpRequest request = context.Request; - string groupName = request.GetQuery("group"); + string groupName = request.GetQueryOrForm("group"); Group group = _dnsWebService._authManager.GetGroup(groupName); if (group is null) throw new DnsWebServiceException("No such group exists: " + groupName); - if (request.TryGetQuery("newGroup", out string newGroup)) + if (request.TryGetQueryOrForm("newGroup", out string newGroup)) _dnsWebService._authManager.RenameGroup(group, newGroup); - if (request.TryGetQuery("description", out string description)) + if (request.TryGetQueryOrForm("description", out string description)) group.Description = description; - string members = request.Query["members"]; + string members = request.QueryOrForm("members"); if (members is not null) { string[] parts = members.Split(','); @@ -780,7 +780,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string groupName = context.Request.GetQuery("group"); + string groupName = context.Request.GetQueryOrForm("group"); if (!_dnsWebService._authManager.DeleteGroup(groupName)) throw new DnsWebServiceException("Failed to delete group: " + groupName); @@ -829,21 +829,21 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - section = request.GetQuery("section"); + section = request.GetQueryOrForm("section"); break; case PermissionSection.Zones: if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - strSubItem = request.GetQuery("zone").TrimEnd('.'); + strSubItem = request.GetQueryOrForm("zone").TrimEnd('.'); break; default: throw new InvalidOperationException(); } - bool includeUsersAndGroups = request.GetQuery("includeUsersAndGroups", bool.Parse, false); + bool includeUsersAndGroups = request.GetQueryOrForm("includeUsersAndGroups", bool.Parse, false); if (strSubItem is not null) { @@ -877,14 +877,14 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - section = request.GetQuery("section"); + section = request.GetQueryOrForm("section"); break; case PermissionSection.Zones: if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - strSubItem = request.GetQuery("zone").TrimEnd('.'); + strSubItem = request.GetQueryOrForm("zone").TrimEnd('.'); break; default: @@ -907,7 +907,7 @@ namespace DnsServerCore if (permission is null) throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem)); - string strUserPermissions = request.Query["userPermissions"]; + string strUserPermissions = request.QueryOrForm("userPermissions"); if (strUserPermissions is not null) { string[] parts = strUserPermissions.Split('|'); @@ -943,7 +943,7 @@ namespace DnsServerCore permission.SyncPermissions(userPermissions); } - string strGroupPermissions = request.Query["groupPermissions"]; + string strGroupPermissions = request.QueryOrForm("groupPermissions"); if (strGroupPermissions is not null) { string[] parts = strGroupPermissions.Split('|'); From 4d1804a4289170e980d7825e31a893eeace772d1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:04:15 +0530 Subject: [PATCH 089/191] WebServiceDashboardApi: code refactoring changes. --- DnsServerCore/WebServiceDashboardApi.cs | 60 ++++++++++++------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/DnsServerCore/WebServiceDashboardApi.cs b/DnsServerCore/WebServiceDashboardApi.cs index 058ff85c..c54443b2 100644 --- a/DnsServerCore/WebServiceDashboardApi.cs +++ b/DnsServerCore/WebServiceDashboardApi.cs @@ -73,7 +73,7 @@ namespace DnsServerCore private async Task> ResolvePtrTopClientsAsync(List> topClients) { - IDictionary dhcpClientIpMap = _dnsWebService._dhcpServer.GetAddressHostNameMap(); + IDictionary dhcpClientIpMap = _dnsWebService.DhcpServer.GetAddressHostNameMap(); async Task> ResolvePtrAsync(string ip) { @@ -85,7 +85,7 @@ namespace DnsServerCore if (IPAddress.IsLoopback(address)) return new KeyValuePair(ip, "localhost"); - DnsDatagram ptrResponse = await _dnsWebService._dnsServer.DirectQueryAsync(new DnsQuestionRecord(address, DnsClass.IN), 500); + DnsDatagram ptrResponse = await _dnsWebService.DnsServer.DirectQueryAsync(new DnsQuestionRecord(address, DnsClass.IN), 500); if (ptrResponse.Answer.Count > 0) { IReadOnlyList ptrDomains = DnsClient.ParseResponsePTR(ptrResponse); @@ -130,8 +130,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string strType = request.GetQuery("type", "lastHour"); - bool utcFormat = request.GetQuery("utc", bool.Parse, false); + string strType = request.GetQueryOrForm("type", "lastHour"); + bool utcFormat = request.GetQueryOrForm("utc", bool.Parse, false); bool isLanguageEnUs = true; string acceptLanguage = request.Headers["Accept-Language"]; @@ -144,12 +144,12 @@ namespace DnsServerCore switch (strType.ToLower()) { case "lasthour": - data = _dnsWebService._dnsServer.StatsManager.GetLastHourMinuteWiseStats(utcFormat); + data = _dnsWebService.DnsServer.StatsManager.GetLastHourMinuteWiseStats(utcFormat); labelFormat = "HH:mm"; break; case "lastday": - data = _dnsWebService._dnsServer.StatsManager.GetLastDayHourWiseStats(utcFormat); + data = _dnsWebService.DnsServer.StatsManager.GetLastDayHourWiseStats(utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD HH:00"; @@ -159,7 +159,7 @@ namespace DnsServerCore break; case "lastweek": - data = _dnsWebService._dnsServer.StatsManager.GetLastWeekDayWiseStats(utcFormat); + data = _dnsWebService.DnsServer.StatsManager.GetLastWeekDayWiseStats(utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD"; @@ -169,7 +169,7 @@ namespace DnsServerCore break; case "lastmonth": - data = _dnsWebService._dnsServer.StatsManager.GetLastMonthDayWiseStats(utcFormat); + data = _dnsWebService.DnsServer.StatsManager.GetLastMonthDayWiseStats(utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD"; @@ -180,12 +180,12 @@ namespace DnsServerCore case "lastyear": labelFormat = "MM/YYYY"; - data = _dnsWebService._dnsServer.StatsManager.GetLastYearMonthWiseStats(utcFormat); + data = _dnsWebService.DnsServer.StatsManager.GetLastYearMonthWiseStats(utcFormat); break; case "custom": - string strStartDate = request.GetQuery("start"); - string strEndDate = request.GetQuery("end"); + string strStartDate = request.GetQueryOrForm("start"); + string strEndDate = request.GetQueryOrForm("end"); if (!DateTime.TryParse(strStartDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out DateTime startDate)) throw new DnsWebServiceException("Invalid start date format."); @@ -198,7 +198,7 @@ namespace DnsServerCore if ((Convert.ToInt32((endDate - startDate).TotalDays) + 1) > 7) { - data = _dnsWebService._dnsServer.StatsManager.GetDayWiseStats(startDate, endDate, utcFormat); + data = _dnsWebService.DnsServer.StatsManager.GetDayWiseStats(startDate, endDate, utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD"; @@ -207,7 +207,7 @@ namespace DnsServerCore } else { - data = _dnsWebService._dnsServer.StatsManager.GetHourWiseStats(startDate, endDate, utcFormat); + data = _dnsWebService.DnsServer.StatsManager.GetHourWiseStats(startDate, endDate, utcFormat); if (isLanguageEnUs) labelFormat = "MM/DD HH:00"; @@ -233,11 +233,11 @@ namespace DnsServerCore foreach (KeyValuePair item in stats) jsonWriter.WriteNumber(item.Key, item.Value); - jsonWriter.WriteNumber("zones", _dnsWebService._dnsServer.AuthZoneManager.TotalZones); - jsonWriter.WriteNumber("cachedEntries", _dnsWebService._dnsServer.CacheZoneManager.TotalEntries); - jsonWriter.WriteNumber("allowedZones", _dnsWebService._dnsServer.AllowedZoneManager.TotalZonesAllowed); - jsonWriter.WriteNumber("blockedZones", _dnsWebService._dnsServer.BlockedZoneManager.TotalZonesBlocked); - jsonWriter.WriteNumber("blockListZones", _dnsWebService._dnsServer.BlockListZoneManager.TotalZonesBlocked); + jsonWriter.WriteNumber("zones", _dnsWebService.DnsServer.AuthZoneManager.TotalZones); + jsonWriter.WriteNumber("cachedEntries", _dnsWebService.DnsServer.CacheZoneManager.TotalEntries); + jsonWriter.WriteNumber("allowedZones", _dnsWebService.DnsServer.AllowedZoneManager.TotalZonesAllowed); + jsonWriter.WriteNumber("blockedZones", _dnsWebService.DnsServer.BlockedZoneManager.TotalZonesBlocked); + jsonWriter.WriteNumber("blockListZones", _dnsWebService.DnsServer.BlockListZoneManager.TotalZonesBlocked); jsonWriter.WriteEndObject(); } @@ -496,37 +496,37 @@ namespace DnsServerCore HttpRequest request = context.Request; - string strType = request.GetQuery("type", "lastHour"); - TopStatsType statsType = request.GetQuery("statsType"); - int limit = request.GetQuery("limit", int.Parse, 1000); + string strType = request.GetQueryOrForm("type", "lastHour"); + TopStatsType statsType = request.GetQueryOrForm("statsType"); + int limit = request.GetQueryOrForm("limit", int.Parse, 1000); List> topStatsData; switch (strType.ToLower()) { case "lasthour": - topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastHourTopStats(statsType, limit); + topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastHourTopStats(statsType, limit); break; case "lastday": - topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastDayTopStats(statsType, limit); + topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastDayTopStats(statsType, limit); break; case "lastweek": - topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastWeekTopStats(statsType, limit); + topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastWeekTopStats(statsType, limit); break; case "lastmonth": - topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastMonthTopStats(statsType, limit); + topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastMonthTopStats(statsType, limit); break; case "lastyear": - topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastYearTopStats(statsType, limit); + topStatsData = _dnsWebService.DnsServer.StatsManager.GetLastYearTopStats(statsType, limit); break; case "custom": - string strStartDate = request.GetQuery("start"); - string strEndDate = request.GetQuery("end"); + string strStartDate = request.GetQueryOrForm("start"); + string strEndDate = request.GetQueryOrForm("end"); if (!DateTime.TryParseExact(strStartDate, "yyyy-M-d", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out DateTime startDate)) throw new DnsWebServiceException("Invalid start date format."); @@ -538,9 +538,9 @@ namespace DnsServerCore throw new DnsWebServiceException("Start date must be less than or equal to end date."); if ((Convert.ToInt32((endDate - startDate).TotalDays) + 1) > 7) - topStatsData = _dnsWebService._dnsServer.StatsManager.GetDayWiseTopStats(startDate, endDate, statsType, limit); + topStatsData = _dnsWebService.DnsServer.StatsManager.GetDayWiseTopStats(startDate, endDate, statsType, limit); else - topStatsData = _dnsWebService._dnsServer.StatsManager.GetHourWiseTopStats(startDate, endDate, statsType, limit); + topStatsData = _dnsWebService.DnsServer.StatsManager.GetHourWiseTopStats(startDate, endDate, statsType, limit); break; From d0c4b9c6225b869bc1587cf04e837e7843bc8671 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:05:13 +0530 Subject: [PATCH 090/191] WebServiceDhcpApi: code refactoring changes. --- DnsServerCore/WebServiceDhcpApi.cs | 150 ++++++++++++++--------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/DnsServerCore/WebServiceDhcpApi.cs b/DnsServerCore/WebServiceDhcpApi.cs index dd3bde2a..0759fc10 100644 --- a/DnsServerCore/WebServiceDhcpApi.cs +++ b/DnsServerCore/WebServiceDhcpApi.cs @@ -56,7 +56,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - IReadOnlyDictionary scopes = _dnsWebService._dhcpServer.Scopes; + IReadOnlyDictionary scopes = _dnsWebService.DhcpServer.Scopes; //sort by name List sortedScopes = new List(scopes.Count); @@ -110,7 +110,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - IReadOnlyDictionary scopes = _dnsWebService._dhcpServer.Scopes; + IReadOnlyDictionary scopes = _dnsWebService.DhcpServer.Scopes; //sort by name List sortedScopes = new List(scopes.Count); @@ -153,9 +153,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - string scopeName = context.Request.GetQuery("name"); + string scopeName = context.Request.GetQueryOrForm("name"); - Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("DHCP scope was not found: " + scopeName); @@ -374,13 +374,13 @@ namespace DnsServerCore HttpRequest request = context.Request; - string scopeName = request.GetQuery("name"); - string strStartingAddress = request.Query["startingAddress"]; - string strEndingAddress = request.Query["endingAddress"]; - string strSubnetMask = request.Query["subnetMask"]; + string scopeName = request.GetQueryOrForm("name"); + string strStartingAddress = request.QueryOrForm("startingAddress"); + string strEndingAddress = request.QueryOrForm("endingAddress"); + string strSubnetMask = request.QueryOrForm("subnetMask"); bool scopeExists; - Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); if (scope is null) { //scope does not exists; create new scope @@ -405,7 +405,7 @@ namespace DnsServerCore IPAddress subnetMask = string.IsNullOrEmpty(strSubnetMask) ? scope.SubnetMask : IPAddress.Parse(strSubnetMask); //validate scope address - foreach (KeyValuePair entry in _dnsWebService._dhcpServer.Scopes) + foreach (KeyValuePair entry in _dnsWebService.DhcpServer.Scopes) { Scope existingScope = entry.Value; @@ -419,32 +419,32 @@ namespace DnsServerCore scope.ChangeNetwork(startingAddress, endingAddress, subnetMask); } - if (request.TryGetQuery("leaseTimeDays", ushort.Parse, out ushort leaseTimeDays)) + if (request.TryGetQueryOrForm("leaseTimeDays", ushort.Parse, out ushort leaseTimeDays)) scope.LeaseTimeDays = leaseTimeDays; - if (request.TryGetQuery("leaseTimeHours", byte.Parse, out byte leaseTimeHours)) + if (request.TryGetQueryOrForm("leaseTimeHours", byte.Parse, out byte leaseTimeHours)) scope.LeaseTimeHours = leaseTimeHours; - if (request.TryGetQuery("leaseTimeMinutes", byte.Parse, out byte leaseTimeMinutes)) + if (request.TryGetQueryOrForm("leaseTimeMinutes", byte.Parse, out byte leaseTimeMinutes)) scope.LeaseTimeMinutes = leaseTimeMinutes; - if (request.TryGetQuery("offerDelayTime", ushort.Parse, out ushort offerDelayTime)) + if (request.TryGetQueryOrForm("offerDelayTime", ushort.Parse, out ushort offerDelayTime)) scope.OfferDelayTime = offerDelayTime; - if (request.TryGetQuery("pingCheckEnabled", bool.Parse, out bool pingCheckEnabled)) + if (request.TryGetQueryOrForm("pingCheckEnabled", bool.Parse, out bool pingCheckEnabled)) scope.PingCheckEnabled = pingCheckEnabled; - if (request.TryGetQuery("pingCheckTimeout", ushort.Parse, out ushort pingCheckTimeout)) + if (request.TryGetQueryOrForm("pingCheckTimeout", ushort.Parse, out ushort pingCheckTimeout)) scope.PingCheckTimeout = pingCheckTimeout; - if (request.TryGetQuery("pingCheckRetries", byte.Parse, out byte pingCheckRetries)) + if (request.TryGetQueryOrForm("pingCheckRetries", byte.Parse, out byte pingCheckRetries)) scope.PingCheckRetries = pingCheckRetries; - string domainName = request.Query["domainName"]; + string domainName = request.QueryOrForm("domainName"); if (domainName is not null) scope.DomainName = domainName.Length == 0 ? null : domainName; - string domainSearchList = request.Query["domainSearchList"]; + string domainSearchList = request.QueryOrForm("domainSearchList"); if (domainSearchList is not null) { if (domainSearchList.Length == 0) @@ -453,34 +453,34 @@ namespace DnsServerCore scope.DomainSearchList = domainSearchList.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } - if (request.TryGetQuery("dnsUpdates", bool.Parse, out bool dnsUpdates)) + if (request.TryGetQueryOrForm("dnsUpdates", bool.Parse, out bool dnsUpdates)) scope.DnsUpdates = dnsUpdates; - if (request.TryGetQuery("dnsTtl", uint.Parse, out uint dnsTtl)) + if (request.TryGetQueryOrForm("dnsTtl", uint.Parse, out uint dnsTtl)) scope.DnsTtl = dnsTtl; - string serverAddress = request.Query["serverAddress"]; + string serverAddress = request.QueryOrForm("serverAddress"); if (serverAddress is not null) scope.ServerAddress = serverAddress.Length == 0 ? null : IPAddress.Parse(serverAddress); - string serverHostName = request.Query["serverHostName"]; + string serverHostName = request.QueryOrForm("serverHostName"); if (serverHostName is not null) scope.ServerHostName = serverHostName.Length == 0 ? null : serverHostName; - string bootFileName = request.Query["bootFileName"]; + string bootFileName = request.QueryOrForm("bootFileName"); if (bootFileName is not null) scope.BootFileName = bootFileName.Length == 0 ? null : bootFileName; - string routerAddress = request.Query["routerAddress"]; + string routerAddress = request.QueryOrForm("routerAddress"); if (routerAddress is not null) scope.RouterAddress = routerAddress.Length == 0 ? null : IPAddress.Parse(routerAddress); - if (request.TryGetQuery("useThisDnsServer", bool.Parse, out bool useThisDnsServer)) + if (request.TryGetQueryOrForm("useThisDnsServer", bool.Parse, out bool useThisDnsServer)) scope.UseThisDnsServer = useThisDnsServer; if (!scope.UseThisDnsServer) { - string dnsServers = request.Query["dnsServers"]; + string dnsServers = request.QueryOrForm("dnsServers"); if (dnsServers is not null) { if (dnsServers.Length == 0) @@ -490,7 +490,7 @@ namespace DnsServerCore } } - string winsServers = request.Query["winsServers"]; + string winsServers = request.QueryOrForm("winsServers"); if (winsServers is not null) { if (winsServers.Length == 0) @@ -499,7 +499,7 @@ namespace DnsServerCore scope.WinsServers = winsServers.Split(IPAddress.Parse, ','); } - string ntpServers = request.Query["ntpServers"]; + string ntpServers = request.QueryOrForm("ntpServers"); if (ntpServers is not null) { if (ntpServers.Length == 0) @@ -508,7 +508,7 @@ namespace DnsServerCore scope.NtpServers = ntpServers.Split(IPAddress.Parse, ','); } - string ntpServerDomainNames = request.Query["ntpServerDomainNames"]; + string ntpServerDomainNames = request.QueryOrForm("ntpServerDomainNames"); if (ntpServerDomainNames is not null) { if (ntpServerDomainNames.Length == 0) @@ -517,7 +517,7 @@ namespace DnsServerCore scope.NtpServerDomainNames = ntpServerDomainNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } - string strStaticRoutes = request.Query["staticRoutes"]; + string strStaticRoutes = request.QueryOrForm("staticRoutes"); if (strStaticRoutes is not null) { if (strStaticRoutes.Length == 0) @@ -536,7 +536,7 @@ namespace DnsServerCore } } - string strVendorInfo = request.Query["vendorInfo"]; + string strVendorInfo = request.QueryOrForm("vendorInfo"); if (strVendorInfo is not null) { if (strVendorInfo.Length == 0) @@ -555,7 +555,7 @@ namespace DnsServerCore } } - string capwapAcIpAddresses = request.Query["capwapAcIpAddresses"]; + string capwapAcIpAddresses = request.QueryOrForm("capwapAcIpAddresses"); if (capwapAcIpAddresses is not null) { if (capwapAcIpAddresses.Length == 0) @@ -564,7 +564,7 @@ namespace DnsServerCore scope.CAPWAPAcIpAddresses = capwapAcIpAddresses.Split(IPAddress.Parse, ','); } - string tftpServerAddresses = request.Query["tftpServerAddresses"]; + string tftpServerAddresses = request.QueryOrForm("tftpServerAddresses"); if (tftpServerAddresses is not null) { if (tftpServerAddresses.Length == 0) @@ -573,7 +573,7 @@ namespace DnsServerCore scope.TftpServerAddresses = tftpServerAddresses.Split(IPAddress.Parse, ','); } - string strGenericOptions = request.Query["genericOptions"]; + string strGenericOptions = request.QueryOrForm("genericOptions"); if (strGenericOptions is not null) { if (strGenericOptions.Length == 0) @@ -592,7 +592,7 @@ namespace DnsServerCore } } - string strExclusions = request.Query["exclusions"]; + string strExclusions = request.QueryOrForm("exclusions"); if (strExclusions is not null) { if (strExclusions.Length == 0) @@ -611,7 +611,7 @@ namespace DnsServerCore } } - string strReservedLeases = request.Query["reservedLeases"]; + string strReservedLeases = request.QueryOrForm("reservedLeases"); if (strReservedLeases is not null) { if (strReservedLeases.Length == 0) @@ -630,28 +630,28 @@ namespace DnsServerCore } } - if (request.TryGetQuery("allowOnlyReservedLeases", bool.Parse, out bool allowOnlyReservedLeases)) + if (request.TryGetQueryOrForm("allowOnlyReservedLeases", bool.Parse, out bool allowOnlyReservedLeases)) scope.AllowOnlyReservedLeases = allowOnlyReservedLeases; - if (request.TryGetQuery("blockLocallyAdministeredMacAddresses", bool.Parse, out bool blockLocallyAdministeredMacAddresses)) + if (request.TryGetQueryOrForm("blockLocallyAdministeredMacAddresses", bool.Parse, out bool blockLocallyAdministeredMacAddresses)) scope.BlockLocallyAdministeredMacAddresses = blockLocallyAdministeredMacAddresses; if (scopeExists) { - _dnsWebService._dhcpServer.SaveScope(scopeName); + _dnsWebService.DhcpServer.SaveScope(scopeName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was updated successfully: " + scopeName); } else { - await _dnsWebService._dhcpServer.AddScopeAsync(scope); + await _dnsWebService.DhcpServer.AddScopeAsync(scope); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was added successfully: " + scopeName); } - if (request.TryGetQuery("newName", out string newName) && !newName.Equals(scopeName)) + if (request.TryGetQueryOrForm("newName", out string newName) && !newName.Equals(scopeName)) { - _dnsWebService._dhcpServer.RenameScope(scopeName, newName); + _dnsWebService.DhcpServer.RenameScope(scopeName, newName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was renamed successfully: '" + scopeName + "' to '" + newName + "'"); } @@ -666,23 +666,23 @@ namespace DnsServerCore HttpRequest request = context.Request; - string scopeName = request.GetQuery("name"); + string scopeName = request.GetQueryOrForm("name"); - Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("No such scope exists: " + scopeName); - string hostName = request.Query["hostName"]; - string hardwareAddress = request.GetQuery("hardwareAddress"); - string strIpAddress = request.GetQuery("ipAddress"); - string comments = request.Query["comments"]; + string hostName = request.QueryOrForm("hostName"); + string hardwareAddress = request.GetQueryOrForm("hardwareAddress"); + string strIpAddress = request.GetQueryOrForm("ipAddress"); + string comments = request.QueryOrForm("comments"); Lease reservedLease = new Lease(LeaseType.Reserved, hostName, DhcpMessageHardwareAddressType.Ethernet, hardwareAddress, IPAddress.Parse(strIpAddress), comments); if (!scope.AddReservedLease(reservedLease)) throw new DnsWebServiceException("Failed to add reserved lease for scope: " + scopeName); - _dnsWebService._dhcpServer.SaveScope(scopeName); + _dnsWebService.DhcpServer.SaveScope(scopeName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope reserved lease was added successfully: " + scopeName); } @@ -696,18 +696,18 @@ namespace DnsServerCore HttpRequest request = context.Request; - string scopeName = request.GetQuery("name"); + string scopeName = request.GetQueryOrForm("name"); - Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("No such scope exists: " + scopeName); - string hardwareAddress = request.GetQuery("hardwareAddress"); + string hardwareAddress = request.GetQueryOrForm("hardwareAddress"); if (!scope.RemoveReservedLease(hardwareAddress)) throw new DnsWebServiceException("Failed to remove reserved lease for scope: " + scopeName); - _dnsWebService._dhcpServer.SaveScope(scopeName); + _dnsWebService.DhcpServer.SaveScope(scopeName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope reserved lease was removed successfully: " + scopeName); } @@ -719,9 +719,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string scopeName = context.Request.GetQuery("name"); + string scopeName = context.Request.GetQueryOrForm("name"); - await _dnsWebService._dhcpServer.EnableScopeAsync(scopeName, true); + await _dnsWebService.DhcpServer.EnableScopeAsync(scopeName, true); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was enabled successfully: " + scopeName); } @@ -733,9 +733,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string scopeName = context.Request.GetQuery("name"); + string scopeName = context.Request.GetQueryOrForm("name"); - _dnsWebService._dhcpServer.DisableScope(scopeName, true); + _dnsWebService.DhcpServer.DisableScope(scopeName, true); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was disabled successfully: " + scopeName); } @@ -747,9 +747,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.DhcpServer, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string scopeName = context.Request.GetQuery("name"); + string scopeName = context.Request.GetQueryOrForm("name"); - _dnsWebService._dhcpServer.DeleteScope(scopeName); + _dnsWebService.DhcpServer.DeleteScope(scopeName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope was deleted successfully: " + scopeName); } @@ -763,14 +763,14 @@ namespace DnsServerCore HttpRequest request = context.Request; - string scopeName = request.GetQuery("name"); + string scopeName = request.GetQueryOrForm("name"); - Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); if (scope is null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); - string clientIdentifier = request.Query["clientIdentifier"]; - string hardwareAddress = request.Query["hardwareAddress"]; + string clientIdentifier = request.QueryOrForm("clientIdentifier"); + string hardwareAddress = request.QueryOrForm("hardwareAddress"); if (!string.IsNullOrEmpty(clientIdentifier)) scope.RemoveLease(ClientIdentifierOption.Parse(clientIdentifier)); @@ -779,7 +779,7 @@ namespace DnsServerCore else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); - _dnsWebService._dhcpServer.SaveScope(scopeName); + _dnsWebService.DhcpServer.SaveScope(scopeName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope's lease was removed successfully: " + scopeName); } @@ -793,14 +793,14 @@ namespace DnsServerCore HttpRequest request = context.Request; - string scopeName = request.GetQuery("name"); + string scopeName = request.GetQueryOrForm("name"); - Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); if (scope == null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); - string clientIdentifier = request.Query["clientIdentifier"]; - string hardwareAddress = request.Query["hardwareAddress"]; + string clientIdentifier = request.QueryOrForm("clientIdentifier"); + string hardwareAddress = request.QueryOrForm("hardwareAddress"); if (!string.IsNullOrEmpty(clientIdentifier)) scope.ConvertToReservedLease(ClientIdentifierOption.Parse(clientIdentifier)); @@ -809,7 +809,7 @@ namespace DnsServerCore else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); - _dnsWebService._dhcpServer.SaveScope(scopeName); + _dnsWebService.DhcpServer.SaveScope(scopeName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope's lease was reserved successfully: " + scopeName); } @@ -823,14 +823,14 @@ namespace DnsServerCore HttpRequest request = context.Request; - string scopeName = request.GetQuery("name"); + string scopeName = request.GetQueryOrForm("name"); - Scope scope = _dnsWebService._dhcpServer.GetScope(scopeName); + Scope scope = _dnsWebService.DhcpServer.GetScope(scopeName); if (scope == null) throw new DnsWebServiceException("DHCP scope does not exists: " + scopeName); - string clientIdentifier = request.Query["clientIdentifier"]; - string hardwareAddress = request.Query["hardwareAddress"]; + string clientIdentifier = request.QueryOrForm("clientIdentifier"); + string hardwareAddress = request.QueryOrForm("hardwareAddress"); if (!string.IsNullOrEmpty(clientIdentifier)) scope.ConvertToDynamicLease(ClientIdentifierOption.Parse(clientIdentifier)); @@ -839,7 +839,7 @@ namespace DnsServerCore else throw new DnsWebServiceException("Parameter 'hardwareAddress' or 'clientIdentifier' missing. At least one of them must be specified."); - _dnsWebService._dhcpServer.SaveScope(scopeName); + _dnsWebService.DhcpServer.SaveScope(scopeName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DHCP scope's lease was unreserved successfully: " + scopeName); } From a83d9cf451c5a9e3b1fa8011697aac07d7f538f4 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:05:44 +0530 Subject: [PATCH 091/191] WebServiceLogsApi: code refactoring changes. --- DnsServerCore/WebServiceLogsApi.cs | 38 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/DnsServerCore/WebServiceLogsApi.cs b/DnsServerCore/WebServiceLogsApi.cs index 6dec972e..9fb8d902 100644 --- a/DnsServerCore/WebServiceLogsApi.cs +++ b/DnsServerCore/WebServiceLogsApi.cs @@ -91,8 +91,8 @@ namespace DnsServerCore HttpRequest request = context.Request; - string fileName = request.GetQuery("fileName"); - int limit = request.GetQuery("limit", int.Parse, 0); + string fileName = request.GetQueryOrForm("fileName"); + int limit = request.GetQueryOrForm("limit", int.Parse, 0); return _dnsWebService._log.DownloadLogAsync(context, fileName, limit * 1024 * 1024); } @@ -106,7 +106,7 @@ namespace DnsServerCore HttpRequest request = context.Request; - string log = request.GetQuery("log"); + string log = request.GetQueryOrForm("log"); _dnsWebService._log.DeleteLog(log); @@ -132,7 +132,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Dashboard, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService._dnsServer.StatsManager.DeleteAllStats(); + _dnsWebService.DnsServer.StatsManager.DeleteAllStats(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] All stats files were deleted."); } @@ -146,55 +146,55 @@ namespace DnsServerCore HttpRequest request = context.Request; - string name = request.GetQuery("name"); - string classPath = request.GetQuery("classPath"); + string name = request.GetQueryOrForm("name"); + string classPath = request.GetQueryOrForm("classPath"); - if (!_dnsWebService._dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) + if (!_dnsWebService.DnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application)) throw new DnsWebServiceException("DNS application was not found: " + name); if (!application.DnsQueryLoggers.TryGetValue(classPath, out IDnsQueryLogger logger)) throw new DnsWebServiceException("DNS application '" + classPath + "' class path was not found: " + name); - long pageNumber = request.GetQuery("pageNumber", long.Parse, 1); - int entriesPerPage = request.GetQuery("entriesPerPage", int.Parse, 25); - bool descendingOrder = request.GetQuery("descendingOrder", bool.Parse, true); + long pageNumber = request.GetQueryOrForm("pageNumber", long.Parse, 1); + int entriesPerPage = request.GetQueryOrForm("entriesPerPage", int.Parse, 25); + bool descendingOrder = request.GetQueryOrForm("descendingOrder", bool.Parse, true); DateTime? start = null; - string strStart = request.Query["start"]; + string strStart = request.QueryOrForm("start"); if (!string.IsNullOrEmpty(strStart)) start = DateTime.Parse(strStart, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); DateTime? end = null; - string strEnd = request.Query["end"]; + string strEnd = request.QueryOrForm("end"); if (!string.IsNullOrEmpty(strEnd)) end = DateTime.Parse(strEnd, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal); - IPAddress clientIpAddress = request.GetQuery("clientIpAddress", IPAddress.Parse, null); + IPAddress clientIpAddress = request.GetQueryOrForm("clientIpAddress", IPAddress.Parse, null); DnsTransportProtocol? protocol = null; - string strProtocol = request.Query["protocol"]; + string strProtocol = request.QueryOrForm("protocol"); if (!string.IsNullOrEmpty(strProtocol)) protocol = Enum.Parse(strProtocol, true); DnsServerResponseType? responseType = null; - string strResponseType = request.Query["responseType"]; + string strResponseType = request.QueryOrForm("responseType"); if (!string.IsNullOrEmpty(strResponseType)) responseType = Enum.Parse(strResponseType, true); DnsResponseCode? rcode = null; - string strRcode = request.Query["rcode"]; + string strRcode = request.QueryOrForm("rcode"); if (!string.IsNullOrEmpty(strRcode)) rcode = Enum.Parse(strRcode, true); - string qname = request.GetQuery("qname", null); + string qname = request.GetQueryOrForm("qname", null); DnsResourceRecordType? qtype = null; - string strQtype = request.Query["qtype"]; + string strQtype = request.QueryOrForm("qtype"); if (!string.IsNullOrEmpty(strQtype)) qtype = Enum.Parse(strQtype, true); DnsClass? qclass = null; - string strQclass = request.Query["qclass"]; + string strQclass = request.QueryOrForm("qclass"); if (!string.IsNullOrEmpty(strQclass)) qclass = Enum.Parse(strQclass, true); From 63accfcd07e05a0d9015f8d3c3fb82961208faba Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:07:21 +0530 Subject: [PATCH 092/191] WebServiceOtherZonesApi: code refactoring changes. --- DnsServerCore/WebServiceOtherZonesApi.cs | 90 ++++++++++-------------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/DnsServerCore/WebServiceOtherZonesApi.cs b/DnsServerCore/WebServiceOtherZonesApi.cs index 4b2f4e71..46e918d0 100644 --- a/DnsServerCore/WebServiceOtherZonesApi.cs +++ b/DnsServerCore/WebServiceOtherZonesApi.cs @@ -58,7 +58,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService._dnsServer.CacheZoneManager.Flush(); + _dnsWebService.DnsServer.CacheZoneManager.Flush(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Cache was flushed."); } @@ -72,9 +72,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string domain = request.GetQuery("domain", ""); + string domain = request.GetQueryOrForm("domain", ""); - string direction = request.Query["direction"]; + string direction = request.QueryOrForm("direction"); if (direction is not null) direction = direction.ToLower(); @@ -86,8 +86,8 @@ namespace DnsServerCore subZones.Clear(); records.Clear(); - _dnsWebService._dnsServer.CacheZoneManager.ListSubDomains(domain, subZones); - _dnsWebService._dnsServer.CacheZoneManager.ListAllRecords(domain, records); + _dnsWebService.DnsServer.CacheZoneManager.ListSubDomains(domain, subZones); + _dnsWebService.DnsServer.CacheZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; @@ -143,9 +143,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string domain = context.Request.GetQuery("domain"); + string domain = context.Request.GetQueryOrForm("domain"); - if (_dnsWebService._dnsServer.CacheZoneManager.DeleteZone(domain)) + if (_dnsWebService.DnsServer.CacheZoneManager.DeleteZone(domain)) _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Cached zone was deleted: " + domain); } @@ -162,9 +162,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string domain = request.GetQuery("domain", ""); + string domain = request.GetQueryOrForm("domain", ""); - string direction = request.Query["direction"]; + string direction = request.QueryOrForm("direction"); if (direction is not null) direction = direction.ToLower(); @@ -176,8 +176,8 @@ namespace DnsServerCore subZones.Clear(); records.Clear(); - _dnsWebService._dnsServer.AllowedZoneManager.ListSubDomains(domain, subZones); - _dnsWebService._dnsServer.AllowedZoneManager.ListAllRecords(domain, records); + _dnsWebService.DnsServer.AllowedZoneManager.ListSubDomains(domain, subZones); + _dnsWebService.DnsServer.AllowedZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; @@ -235,26 +235,20 @@ namespace DnsServerCore HttpRequest request = context.Request; - if (!request.HasFormContentType) - throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); - - string allowedZones = request.Form["allowedZones"]; - if (string.IsNullOrEmpty(allowedZones)) - throw new DnsWebServiceException("Form parameter 'allowedZones' missing."); - + string allowedZones = request.GetQueryOrForm("allowedZones"); string[] allowedZonesList = allowedZones.Split(','); bool added = false; foreach (string allowedZone in allowedZonesList) { - if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(allowedZone)) + if (_dnsWebService.DnsServer.AllowedZoneManager.AllowZone(allowedZone)) added = true; } if (added) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Total " + allowedZonesList.Length + " zones were imported into allowed zone successfully."); - _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); } } @@ -265,7 +259,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.AllowedZoneManager.ListZones(); + IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.AllowedZoneManager.ListZones(); HttpResponse response = context.Response; @@ -286,12 +280,12 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string domain = context.Request.GetQuery("domain"); + string domain = context.Request.GetQueryOrForm("domain"); - if (_dnsWebService._dnsServer.AllowedZoneManager.DeleteZone(domain)) + if (_dnsWebService.DnsServer.AllowedZoneManager.DeleteZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Allowed zone was deleted: " + domain); - _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); } } @@ -302,10 +296,10 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService._dnsServer.AllowedZoneManager.Flush(); + _dnsWebService.DnsServer.AllowedZoneManager.Flush(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Allowed zone was flushed successfully."); - _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); } public void AllowZone(HttpContext context) @@ -315,15 +309,15 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string domain = context.Request.GetQuery("domain"); + string domain = context.Request.GetQueryOrForm("domain"); if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); - if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(domain)) + if (_dnsWebService.DnsServer.AllowedZoneManager.AllowZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Zone was allowed: " + domain); - _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.AllowedZoneManager.SaveZoneFile(); } } @@ -340,9 +334,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string domain = request.GetQuery("domain", ""); + string domain = request.GetQueryOrForm("domain", ""); - string direction = request.Query["direction"]; + string direction = request.QueryOrForm("direction"); if (direction is not null) direction = direction.ToLower(); @@ -354,8 +348,8 @@ namespace DnsServerCore subZones.Clear(); records.Clear(); - _dnsWebService._dnsServer.BlockedZoneManager.ListSubDomains(domain, subZones); - _dnsWebService._dnsServer.BlockedZoneManager.ListAllRecords(domain, records); + _dnsWebService.DnsServer.BlockedZoneManager.ListSubDomains(domain, subZones); + _dnsWebService.DnsServer.BlockedZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; @@ -413,26 +407,20 @@ namespace DnsServerCore HttpRequest request = context.Request; - if (!request.HasFormContentType) - throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); - - string blockedZones = request.Form["blockedZones"]; - if (string.IsNullOrEmpty(blockedZones)) - throw new DnsWebServiceException("Form parameter 'blockedZones' missing."); - + string blockedZones = request.GetQueryOrForm("blockedZones"); string[] blockedZonesList = blockedZones.Split(','); bool added = false; foreach (string blockedZone in blockedZonesList) { - if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(blockedZone)) + if (_dnsWebService.DnsServer.BlockedZoneManager.BlockZone(blockedZone)) added = true; } if (added) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Total " + blockedZonesList.Length + " zones were imported into blocked zone successfully."); - _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); } } @@ -443,7 +431,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.BlockedZoneManager.ListZones(); + IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.BlockedZoneManager.ListZones(); HttpResponse response = context.Response; @@ -464,12 +452,12 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string domain = context.Request.GetQuery("domain"); + string domain = context.Request.GetQueryOrForm("domain"); - if (_dnsWebService._dnsServer.BlockedZoneManager.DeleteZone(domain)) + if (_dnsWebService.DnsServer.BlockedZoneManager.DeleteZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocked zone was deleted: " + domain); - _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); } } @@ -480,10 +468,10 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService._dnsServer.BlockedZoneManager.Flush(); + _dnsWebService.DnsServer.BlockedZoneManager.Flush(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocked zone was flushed successfully."); - _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); } public void BlockZone(HttpContext context) @@ -493,15 +481,15 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string domain = context.Request.GetQuery("domain"); + string domain = context.Request.GetQueryOrForm("domain"); if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); - if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(domain)) + if (_dnsWebService.DnsServer.BlockedZoneManager.BlockZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Domain was added to blocked zone: " + domain); - _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); + _dnsWebService.DnsServer.BlockedZoneManager.SaveZoneFile(); } } From 10672172d32e2c86d7252a43fcba0d02a967c958 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:11:56 +0530 Subject: [PATCH 093/191] WebServiceSettingsApi: updated API for new settings options. Code refactoring changes. --- DnsServerCore/WebServiceSettingsApi.cs | 634 +++++++++++++++---------- 1 file changed, 370 insertions(+), 264 deletions(-) diff --git a/DnsServerCore/WebServiceSettingsApi.cs b/DnsServerCore/WebServiceSettingsApi.cs index c018ff0e..11580da8 100644 --- a/DnsServerCore/WebServiceSettingsApi.cs +++ b/DnsServerCore/WebServiceSettingsApi.cs @@ -94,7 +94,7 @@ namespace DnsServerCore { Task.Run(async delegate () { - if (await _dnsWebService._dnsServer.BlockListZoneManager.UpdateBlockListsAsync()) + if (await _dnsWebService.DnsServer.BlockListZoneManager.UpdateBlockListsAsync()) { //block lists were updated //save last updated on time @@ -114,7 +114,7 @@ namespace DnsServerCore { if (DateTime.UtcNow > _blockListLastUpdatedOn.AddHours(_blockListUpdateIntervalHours)) { - if (await _dnsWebService._dnsServer.BlockListZoneManager.UpdateBlockListsAsync()) + if (await _dnsWebService.DnsServer.BlockListZoneManager.UpdateBlockListsAsync()) { //block lists were updated //save last updated on time @@ -156,14 +156,14 @@ namespace DnsServerCore { if (restartDnsService) { - _ = Task.Run(delegate () + _ = Task.Run(async delegate () { _dnsWebService._log.Write("Attempting to restart DNS service."); try { - _dnsWebService._dnsServer.Stop(); - _dnsWebService._dnsServer.Start(); + await _dnsWebService.DnsServer.StopAsync(); + await _dnsWebService.DnsServer.StartAsync(); _dnsWebService._log.Write("DNS service was restarted successfully."); } @@ -186,7 +186,7 @@ namespace DnsServerCore try { await _dnsWebService.StopWebServiceAsync(); - await _dnsWebService.StartWebServiceAsync(); + await _dnsWebService.TryStartWebServiceAsync(); _dnsWebService._log.Write("Web service was restarted successfully."); } @@ -225,12 +225,12 @@ namespace DnsServerCore { //general jsonWriter.WriteString("version", _dnsWebService.GetServerVersion()); - jsonWriter.WriteString("dnsServerDomain", _dnsWebService._dnsServer.ServerDomain); + jsonWriter.WriteString("dnsServerDomain", _dnsWebService.DnsServer.ServerDomain); jsonWriter.WritePropertyName("dnsServerLocalEndPoints"); jsonWriter.WriteStartArray(); - foreach (IPEndPoint localEP in _dnsWebService._dnsServer.LocalEndPoints) + foreach (IPEndPoint localEP in _dnsWebService.DnsServer.LocalEndPoints) jsonWriter.WriteStringValue(localEP.ToString()); jsonWriter.WriteEndArray(); @@ -238,25 +238,28 @@ namespace DnsServerCore jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService._zonesApi.DefaultRecordTtl); jsonWriter.WriteBoolean("dnsAppsEnableAutomaticUpdate", _dnsWebService._appsApi.EnableAutomaticUpdate); - jsonWriter.WriteBoolean("preferIPv6", _dnsWebService._dnsServer.PreferIPv6); + jsonWriter.WriteBoolean("preferIPv6", _dnsWebService.DnsServer.PreferIPv6); - jsonWriter.WriteNumber("udpPayloadSize", _dnsWebService._dnsServer.UdpPayloadSize); + jsonWriter.WriteNumber("udpPayloadSize", _dnsWebService.DnsServer.UdpPayloadSize); - jsonWriter.WriteBoolean("dnssecValidation", _dnsWebService._dnsServer.DnssecValidation); + jsonWriter.WriteBoolean("dnssecValidation", _dnsWebService.DnsServer.DnssecValidation); - jsonWriter.WriteBoolean("eDnsClientSubnet", _dnsWebService._dnsServer.EDnsClientSubnet); - jsonWriter.WriteNumber("eDnsClientSubnetIPv4PrefixLength", _dnsWebService._dnsServer.EDnsClientSubnetIPv4PrefixLength); - jsonWriter.WriteNumber("eDnsClientSubnetIPv6PrefixLength", _dnsWebService._dnsServer.EDnsClientSubnetIPv6PrefixLength); + jsonWriter.WriteBoolean("eDnsClientSubnet", _dnsWebService.DnsServer.EDnsClientSubnet); + jsonWriter.WriteNumber("eDnsClientSubnetIPv4PrefixLength", _dnsWebService.DnsServer.EDnsClientSubnetIPv4PrefixLength); + jsonWriter.WriteNumber("eDnsClientSubnetIPv6PrefixLength", _dnsWebService.DnsServer.EDnsClientSubnetIPv6PrefixLength); - jsonWriter.WriteNumber("qpmLimitRequests", _dnsWebService._dnsServer.QpmLimitRequests); - jsonWriter.WriteNumber("qpmLimitErrors", _dnsWebService._dnsServer.QpmLimitErrors); - jsonWriter.WriteNumber("qpmLimitSampleMinutes", _dnsWebService._dnsServer.QpmLimitSampleMinutes); - jsonWriter.WriteNumber("qpmLimitIPv4PrefixLength", _dnsWebService._dnsServer.QpmLimitIPv4PrefixLength); - jsonWriter.WriteNumber("qpmLimitIPv6PrefixLength", _dnsWebService._dnsServer.QpmLimitIPv6PrefixLength); + jsonWriter.WriteNumber("qpmLimitRequests", _dnsWebService.DnsServer.QpmLimitRequests); + jsonWriter.WriteNumber("qpmLimitErrors", _dnsWebService.DnsServer.QpmLimitErrors); + jsonWriter.WriteNumber("qpmLimitSampleMinutes", _dnsWebService.DnsServer.QpmLimitSampleMinutes); + jsonWriter.WriteNumber("qpmLimitIPv4PrefixLength", _dnsWebService.DnsServer.QpmLimitIPv4PrefixLength); + jsonWriter.WriteNumber("qpmLimitIPv6PrefixLength", _dnsWebService.DnsServer.QpmLimitIPv6PrefixLength); - jsonWriter.WriteNumber("clientTimeout", _dnsWebService._dnsServer.ClientTimeout); - jsonWriter.WriteNumber("tcpSendTimeout", _dnsWebService._dnsServer.TcpSendTimeout); - jsonWriter.WriteNumber("tcpReceiveTimeout", _dnsWebService._dnsServer.TcpReceiveTimeout); + jsonWriter.WriteNumber("clientTimeout", _dnsWebService.DnsServer.ClientTimeout); + jsonWriter.WriteNumber("tcpSendTimeout", _dnsWebService.DnsServer.TcpSendTimeout); + jsonWriter.WriteNumber("tcpReceiveTimeout", _dnsWebService.DnsServer.TcpReceiveTimeout); + jsonWriter.WriteNumber("quicIdleTimeout", _dnsWebService.DnsServer.QuicIdleTimeout); + jsonWriter.WriteNumber("quicMaxInboundStreams", _dnsWebService.DnsServer.QuicMaxInboundStreams); + jsonWriter.WriteNumber("listenBacklog", _dnsWebService.DnsServer.ListenBacklog); //web service jsonWriter.WritePropertyName("webServiceLocalAddresses"); @@ -281,9 +284,15 @@ namespace DnsServerCore jsonWriter.WriteString("webServiceTlsCertificatePassword", "************"); //optional protocols - jsonWriter.WriteBoolean("enableDnsOverHttp", _dnsWebService._dnsServer.EnableDnsOverHttp); - jsonWriter.WriteBoolean("enableDnsOverTls", _dnsWebService._dnsServer.EnableDnsOverTls); - jsonWriter.WriteBoolean("enableDnsOverHttps", _dnsWebService._dnsServer.EnableDnsOverHttps); + jsonWriter.WriteBoolean("enableDnsOverHttp", _dnsWebService.DnsServer.EnableDnsOverHttp); + jsonWriter.WriteBoolean("enableDnsOverTls", _dnsWebService.DnsServer.EnableDnsOverTls); + jsonWriter.WriteBoolean("enableDnsOverHttps", _dnsWebService.DnsServer.EnableDnsOverHttps); + jsonWriter.WriteBoolean("enableDnsOverHttpPort80", _dnsWebService.DnsServer.EnableDnsOverHttpPort80); + jsonWriter.WriteBoolean("enableDnsOverQuic", _dnsWebService.DnsServer.EnableDnsOverQuic); + jsonWriter.WriteNumber("dnsOverHttpPort", _dnsWebService.DnsServer.DnsOverHttpPort); + jsonWriter.WriteNumber("dnsOverTlsPort", _dnsWebService.DnsServer.DnsOverTlsPort); + jsonWriter.WriteNumber("dnsOverHttpsPort", _dnsWebService.DnsServer.DnsOverHttpsPort); + jsonWriter.WriteNumber("dnsOverQuicPort", _dnsWebService.DnsServer.DnsOverQuicPort); jsonWriter.WriteString("dnsTlsCertificatePath", _dnsWebService._dnsTlsCertificatePath); jsonWriter.WriteString("dnsTlsCertificatePassword", "************"); @@ -292,9 +301,9 @@ namespace DnsServerCore { jsonWriter.WriteStartArray(); - if (_dnsWebService._dnsServer.TsigKeys is not null) + if (_dnsWebService.DnsServer.TsigKeys is not null) { - foreach (KeyValuePair tsigKey in _dnsWebService._dnsServer.TsigKeys) + foreach (KeyValuePair tsigKey in _dnsWebService.DnsServer.TsigKeys) { jsonWriter.WriteStartObject(); @@ -310,15 +319,15 @@ namespace DnsServerCore } //recursion - jsonWriter.WriteString("recursion", _dnsWebService._dnsServer.Recursion.ToString()); + jsonWriter.WriteString("recursion", _dnsWebService.DnsServer.Recursion.ToString()); jsonWriter.WritePropertyName("recursionDeniedNetworks"); { jsonWriter.WriteStartArray(); - if (_dnsWebService._dnsServer.RecursionDeniedNetworks is not null) + if (_dnsWebService.DnsServer.RecursionDeniedNetworks is not null) { - foreach (NetworkAddress networkAddress in _dnsWebService._dnsServer.RecursionDeniedNetworks) + foreach (NetworkAddress networkAddress in _dnsWebService.DnsServer.RecursionDeniedNetworks) jsonWriter.WriteStringValue(networkAddress.ToString()); } @@ -329,61 +338,62 @@ namespace DnsServerCore { jsonWriter.WriteStartArray(); - if (_dnsWebService._dnsServer.RecursionAllowedNetworks is not null) + if (_dnsWebService.DnsServer.RecursionAllowedNetworks is not null) { - foreach (NetworkAddress networkAddress in _dnsWebService._dnsServer.RecursionAllowedNetworks) + foreach (NetworkAddress networkAddress in _dnsWebService.DnsServer.RecursionAllowedNetworks) jsonWriter.WriteStringValue(networkAddress.ToString()); } jsonWriter.WriteEndArray(); } - jsonWriter.WriteBoolean("randomizeName", _dnsWebService._dnsServer.RandomizeName); - jsonWriter.WriteBoolean("qnameMinimization", _dnsWebService._dnsServer.QnameMinimization); - jsonWriter.WriteBoolean("nsRevalidation", _dnsWebService._dnsServer.NsRevalidation); + jsonWriter.WriteBoolean("randomizeName", _dnsWebService.DnsServer.RandomizeName); + jsonWriter.WriteBoolean("qnameMinimization", _dnsWebService.DnsServer.QnameMinimization); + jsonWriter.WriteBoolean("nsRevalidation", _dnsWebService.DnsServer.NsRevalidation); - jsonWriter.WriteNumber("resolverRetries", _dnsWebService._dnsServer.ResolverRetries); - jsonWriter.WriteNumber("resolverTimeout", _dnsWebService._dnsServer.ResolverTimeout); - jsonWriter.WriteNumber("resolverMaxStackCount", _dnsWebService._dnsServer.ResolverMaxStackCount); + jsonWriter.WriteNumber("resolverRetries", _dnsWebService.DnsServer.ResolverRetries); + jsonWriter.WriteNumber("resolverTimeout", _dnsWebService.DnsServer.ResolverTimeout); + jsonWriter.WriteNumber("resolverMaxStackCount", _dnsWebService.DnsServer.ResolverMaxStackCount); //cache - jsonWriter.WriteBoolean("serveStale", _dnsWebService._dnsServer.ServeStale); - jsonWriter.WriteNumber("serveStaleTtl", _dnsWebService._dnsServer.CacheZoneManager.ServeStaleTtl); + jsonWriter.WriteBoolean("saveCache", _dnsWebService._saveCache); + jsonWriter.WriteBoolean("serveStale", _dnsWebService.DnsServer.ServeStale); + jsonWriter.WriteNumber("serveStaleTtl", _dnsWebService.DnsServer.CacheZoneManager.ServeStaleTtl); - jsonWriter.WriteNumber("cacheMaximumEntries", _dnsWebService._dnsServer.CacheZoneManager.MaximumEntries); - jsonWriter.WriteNumber("cacheMinimumRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.MinimumRecordTtl); - jsonWriter.WriteNumber("cacheMaximumRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.MaximumRecordTtl); - jsonWriter.WriteNumber("cacheNegativeRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.NegativeRecordTtl); - jsonWriter.WriteNumber("cacheFailureRecordTtl", _dnsWebService._dnsServer.CacheZoneManager.FailureRecordTtl); + jsonWriter.WriteNumber("cacheMaximumEntries", _dnsWebService.DnsServer.CacheZoneManager.MaximumEntries); + jsonWriter.WriteNumber("cacheMinimumRecordTtl", _dnsWebService.DnsServer.CacheZoneManager.MinimumRecordTtl); + jsonWriter.WriteNumber("cacheMaximumRecordTtl", _dnsWebService.DnsServer.CacheZoneManager.MaximumRecordTtl); + jsonWriter.WriteNumber("cacheNegativeRecordTtl", _dnsWebService.DnsServer.CacheZoneManager.NegativeRecordTtl); + jsonWriter.WriteNumber("cacheFailureRecordTtl", _dnsWebService.DnsServer.CacheZoneManager.FailureRecordTtl); - jsonWriter.WriteNumber("cachePrefetchEligibility", _dnsWebService._dnsServer.CachePrefetchEligibility); - jsonWriter.WriteNumber("cachePrefetchTrigger", _dnsWebService._dnsServer.CachePrefetchTrigger); - jsonWriter.WriteNumber("cachePrefetchSampleIntervalInMinutes", _dnsWebService._dnsServer.CachePrefetchSampleIntervalInMinutes); - jsonWriter.WriteNumber("cachePrefetchSampleEligibilityHitsPerHour", _dnsWebService._dnsServer.CachePrefetchSampleEligibilityHitsPerHour); + jsonWriter.WriteNumber("cachePrefetchEligibility", _dnsWebService.DnsServer.CachePrefetchEligibility); + jsonWriter.WriteNumber("cachePrefetchTrigger", _dnsWebService.DnsServer.CachePrefetchTrigger); + jsonWriter.WriteNumber("cachePrefetchSampleIntervalInMinutes", _dnsWebService.DnsServer.CachePrefetchSampleIntervalInMinutes); + jsonWriter.WriteNumber("cachePrefetchSampleEligibilityHitsPerHour", _dnsWebService.DnsServer.CachePrefetchSampleEligibilityHitsPerHour); //blocking - jsonWriter.WriteBoolean("enableBlocking", _dnsWebService._dnsServer.EnableBlocking); - jsonWriter.WriteBoolean("allowTxtBlockingReport", _dnsWebService._dnsServer.AllowTxtBlockingReport); + jsonWriter.WriteBoolean("enableBlocking", _dnsWebService.DnsServer.EnableBlocking); + jsonWriter.WriteBoolean("allowTxtBlockingReport", _dnsWebService.DnsServer.AllowTxtBlockingReport); - if (!_dnsWebService._dnsServer.EnableBlocking && (DateTime.UtcNow < _temporaryDisableBlockingTill)) + if (!_dnsWebService.DnsServer.EnableBlocking && (DateTime.UtcNow < _temporaryDisableBlockingTill)) jsonWriter.WriteString("temporaryDisableBlockingTill", _temporaryDisableBlockingTill); - jsonWriter.WriteString("blockingType", _dnsWebService._dnsServer.BlockingType.ToString()); + jsonWriter.WriteString("blockingType", _dnsWebService.DnsServer.BlockingType.ToString()); jsonWriter.WritePropertyName("customBlockingAddresses"); jsonWriter.WriteStartArray(); - foreach (DnsARecordData record in _dnsWebService._dnsServer.CustomBlockingARecords) + foreach (DnsARecordData record in _dnsWebService.DnsServer.CustomBlockingARecords) jsonWriter.WriteStringValue(record.Address.ToString()); - foreach (DnsAAAARecordData record in _dnsWebService._dnsServer.CustomBlockingAAAARecords) + foreach (DnsAAAARecordData record in _dnsWebService.DnsServer.CustomBlockingAAAARecords) jsonWriter.WriteStringValue(record.Address.ToString()); jsonWriter.WriteEndArray(); jsonWriter.WritePropertyName("blockListUrls"); - if ((_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count == 0) && (_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count == 0)) + if ((_dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Count == 0) && (_dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Count == 0)) { jsonWriter.WriteNullValue(); } @@ -391,10 +401,10 @@ namespace DnsServerCore { jsonWriter.WriteStartArray(); - foreach (Uri allowListUrl in _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls) + foreach (Uri allowListUrl in _dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls) jsonWriter.WriteStringValue("!" + allowListUrl.AbsoluteUri); - foreach (Uri blockListUrl in _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls) + foreach (Uri blockListUrl in _dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls) jsonWriter.WriteStringValue(blockListUrl.AbsoluteUri); jsonWriter.WriteEndArray(); @@ -411,7 +421,7 @@ namespace DnsServerCore //proxy & forwarders jsonWriter.WritePropertyName("proxy"); - if (_dnsWebService._dnsServer.Proxy == null) + if (_dnsWebService.DnsServer.Proxy == null) { jsonWriter.WriteNullValue(); } @@ -419,7 +429,7 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - NetProxy proxy = _dnsWebService._dnsServer.Proxy; + NetProxy proxy = _dnsWebService.DnsServer.Proxy; jsonWriter.WriteString("type", proxy.Type.ToString()); jsonWriter.WriteString("address", proxy.Address); @@ -447,17 +457,17 @@ namespace DnsServerCore DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp; - if (_dnsWebService._dnsServer.Forwarders == null) + if (_dnsWebService.DnsServer.Forwarders == null) { jsonWriter.WriteNullValue(); } else { - forwarderProtocol = _dnsWebService._dnsServer.Forwarders[0].Protocol; + forwarderProtocol = _dnsWebService.DnsServer.Forwarders[0].Protocol; jsonWriter.WriteStartArray(); - foreach (NameServerAddress forwarder in _dnsWebService._dnsServer.Forwarders) + foreach (NameServerAddress forwarder in _dnsWebService.DnsServer.Forwarders) jsonWriter.WriteStringValue(forwarder.OriginalAddress); jsonWriter.WriteEndArray(); @@ -465,17 +475,17 @@ namespace DnsServerCore jsonWriter.WriteString("forwarderProtocol", forwarderProtocol.ToString()); - jsonWriter.WriteNumber("forwarderRetries", _dnsWebService._dnsServer.ForwarderRetries); - jsonWriter.WriteNumber("forwarderTimeout", _dnsWebService._dnsServer.ForwarderTimeout); - jsonWriter.WriteNumber("forwarderConcurrency", _dnsWebService._dnsServer.ForwarderConcurrency); + jsonWriter.WriteNumber("forwarderRetries", _dnsWebService.DnsServer.ForwarderRetries); + jsonWriter.WriteNumber("forwarderTimeout", _dnsWebService.DnsServer.ForwarderTimeout); + jsonWriter.WriteNumber("forwarderConcurrency", _dnsWebService.DnsServer.ForwarderConcurrency); //logging jsonWriter.WriteBoolean("enableLogging", _dnsWebService._log.EnableLogging); - jsonWriter.WriteBoolean("logQueries", _dnsWebService._dnsServer.QueryLogManager != null); + jsonWriter.WriteBoolean("logQueries", _dnsWebService.DnsServer.QueryLogManager != null); jsonWriter.WriteBoolean("useLocalTime", _dnsWebService._log.UseLocalTime); jsonWriter.WriteString("logFolder", _dnsWebService._log.LogFolder); jsonWriter.WriteNumber("maxLogFileDays", _dnsWebService._log.MaxLogFileDays); - jsonWriter.WriteNumber("maxStatFileDays", _dnsWebService._dnsServer.StatsManager.MaxStatFileDays); + jsonWriter.WriteNumber("maxStatFileDays", _dnsWebService.DnsServer.StatsManager.MaxStatFileDays); } #endregion @@ -509,16 +519,16 @@ namespace DnsServerCore HttpRequest request = context.Request; //general - if (request.TryGetQuery("dnsServerDomain", out string dnsServerDomain)) + if (request.TryGetQueryOrForm("dnsServerDomain", out string dnsServerDomain)) { - if (!_dnsWebService._dnsServer.ServerDomain.Equals(dnsServerDomain, StringComparison.OrdinalIgnoreCase)) + if (!_dnsWebService.DnsServer.ServerDomain.Equals(dnsServerDomain, StringComparison.OrdinalIgnoreCase)) { - _dnsWebService._dnsServer.ServerDomain = dnsServerDomain; + _dnsWebService.DnsServer.ServerDomain = dnsServerDomain; serverDomainChanged = true; } } - string dnsServerLocalEndPoints = request.Query["dnsServerLocalEndPoints"]; + string dnsServerLocalEndPoints = request.QueryOrForm("dnsServerLocalEndPoints"); if (dnsServerLocalEndPoints is not null) { if (dnsServerLocalEndPoints.Length == 0) @@ -527,13 +537,19 @@ namespace DnsServerCore IPEndPoint[] localEndPoints = dnsServerLocalEndPoints.Split(IPEndPoint.Parse, ','); if (localEndPoints.Length > 0) { - if (_dnsWebService._dnsServer.LocalEndPoints.Count != localEndPoints.Length) + foreach (IPEndPoint localEndPoint in localEndPoints) + { + if (localEndPoint.Port == 0) + localEndPoint.Port = 53; + } + + if (_dnsWebService.DnsServer.LocalEndPoints.Count != localEndPoints.Length) { restartDnsService = true; } else { - foreach (IPEndPoint currentLocalEP in _dnsWebService._dnsServer.LocalEndPoints) + foreach (IPEndPoint currentLocalEP in _dnsWebService.DnsServer.LocalEndPoints) { if (!localEndPoints.Contains(currentLocalEP)) { @@ -543,60 +559,69 @@ namespace DnsServerCore } } - _dnsWebService._dnsServer.LocalEndPoints = localEndPoints; + _dnsWebService.DnsServer.LocalEndPoints = localEndPoints; } } - if (request.TryGetQuery("defaultRecordTtl", uint.Parse, out uint defaultRecordTtl)) + if (request.TryGetQueryOrForm("defaultRecordTtl", uint.Parse, out uint defaultRecordTtl)) _dnsWebService._zonesApi.DefaultRecordTtl = defaultRecordTtl; - if (request.TryGetQuery("dnsAppsEnableAutomaticUpdate", bool.Parse, out bool dnsAppsEnableAutomaticUpdate)) + if (request.TryGetQueryOrForm("dnsAppsEnableAutomaticUpdate", bool.Parse, out bool dnsAppsEnableAutomaticUpdate)) _dnsWebService._appsApi.EnableAutomaticUpdate = dnsAppsEnableAutomaticUpdate; - if (request.TryGetQuery("preferIPv6", bool.Parse, out bool preferIPv6)) - _dnsWebService._dnsServer.PreferIPv6 = preferIPv6; + if (request.TryGetQueryOrForm("preferIPv6", bool.Parse, out bool preferIPv6)) + _dnsWebService.DnsServer.PreferIPv6 = preferIPv6; - if (request.TryGetQuery("udpPayloadSize", ushort.Parse, out ushort udpPayloadSize)) - _dnsWebService._dnsServer.UdpPayloadSize = udpPayloadSize; + if (request.TryGetQueryOrForm("udpPayloadSize", ushort.Parse, out ushort udpPayloadSize)) + _dnsWebService.DnsServer.UdpPayloadSize = udpPayloadSize; - if (request.TryGetQuery("dnssecValidation", bool.Parse, out bool dnssecValidation)) - _dnsWebService._dnsServer.DnssecValidation = dnssecValidation; + if (request.TryGetQueryOrForm("dnssecValidation", bool.Parse, out bool dnssecValidation)) + _dnsWebService.DnsServer.DnssecValidation = dnssecValidation; - if (request.TryGetQuery("eDnsClientSubnet", bool.Parse, out bool eDnsClientSubnet)) - _dnsWebService._dnsServer.EDnsClientSubnet = eDnsClientSubnet; + if (request.TryGetQueryOrForm("eDnsClientSubnet", bool.Parse, out bool eDnsClientSubnet)) + _dnsWebService.DnsServer.EDnsClientSubnet = eDnsClientSubnet; - if (request.TryGetQuery("eDnsClientSubnetIPv4PrefixLength", byte.Parse, out byte eDnsClientSubnetIPv4PrefixLength)) - _dnsWebService._dnsServer.EDnsClientSubnetIPv4PrefixLength = eDnsClientSubnetIPv4PrefixLength; + if (request.TryGetQueryOrForm("eDnsClientSubnetIPv4PrefixLength", byte.Parse, out byte eDnsClientSubnetIPv4PrefixLength)) + _dnsWebService.DnsServer.EDnsClientSubnetIPv4PrefixLength = eDnsClientSubnetIPv4PrefixLength; - if (request.TryGetQuery("eDnsClientSubnetIPv6PrefixLength", byte.Parse, out byte eDnsClientSubnetIPv6PrefixLength)) - _dnsWebService._dnsServer.EDnsClientSubnetIPv6PrefixLength = eDnsClientSubnetIPv6PrefixLength; + if (request.TryGetQueryOrForm("eDnsClientSubnetIPv6PrefixLength", byte.Parse, out byte eDnsClientSubnetIPv6PrefixLength)) + _dnsWebService.DnsServer.EDnsClientSubnetIPv6PrefixLength = eDnsClientSubnetIPv6PrefixLength; - if (request.TryGetQuery("qpmLimitRequests", int.Parse, out int qpmLimitRequests)) - _dnsWebService._dnsServer.QpmLimitRequests = qpmLimitRequests; + if (request.TryGetQueryOrForm("qpmLimitRequests", int.Parse, out int qpmLimitRequests)) + _dnsWebService.DnsServer.QpmLimitRequests = qpmLimitRequests; - if (request.TryGetQuery("qpmLimitErrors", int.Parse, out int qpmLimitErrors)) - _dnsWebService._dnsServer.QpmLimitErrors = qpmLimitErrors; + if (request.TryGetQueryOrForm("qpmLimitErrors", int.Parse, out int qpmLimitErrors)) + _dnsWebService.DnsServer.QpmLimitErrors = qpmLimitErrors; - if (request.TryGetQuery("qpmLimitSampleMinutes", int.Parse, out int qpmLimitSampleMinutes)) - _dnsWebService._dnsServer.QpmLimitSampleMinutes = qpmLimitSampleMinutes; + if (request.TryGetQueryOrForm("qpmLimitSampleMinutes", int.Parse, out int qpmLimitSampleMinutes)) + _dnsWebService.DnsServer.QpmLimitSampleMinutes = qpmLimitSampleMinutes; - if (request.TryGetQuery("qpmLimitIPv4PrefixLength", int.Parse, out int qpmLimitIPv4PrefixLength)) - _dnsWebService._dnsServer.QpmLimitIPv4PrefixLength = qpmLimitIPv4PrefixLength; + if (request.TryGetQueryOrForm("qpmLimitIPv4PrefixLength", int.Parse, out int qpmLimitIPv4PrefixLength)) + _dnsWebService.DnsServer.QpmLimitIPv4PrefixLength = qpmLimitIPv4PrefixLength; - if (request.TryGetQuery("qpmLimitIPv6PrefixLength", int.Parse, out int qpmLimitIPv6PrefixLength)) - _dnsWebService._dnsServer.QpmLimitIPv6PrefixLength = qpmLimitIPv6PrefixLength; + if (request.TryGetQueryOrForm("qpmLimitIPv6PrefixLength", int.Parse, out int qpmLimitIPv6PrefixLength)) + _dnsWebService.DnsServer.QpmLimitIPv6PrefixLength = qpmLimitIPv6PrefixLength; - if (request.TryGetQuery("clientTimeout", int.Parse, out int clientTimeout)) - _dnsWebService._dnsServer.ClientTimeout = clientTimeout; + if (request.TryGetQueryOrForm("clientTimeout", int.Parse, out int clientTimeout)) + _dnsWebService.DnsServer.ClientTimeout = clientTimeout; - if (request.TryGetQuery("tcpSendTimeout", int.Parse, out int tcpSendTimeout)) - _dnsWebService._dnsServer.TcpSendTimeout = tcpSendTimeout; + if (request.TryGetQueryOrForm("tcpSendTimeout", int.Parse, out int tcpSendTimeout)) + _dnsWebService.DnsServer.TcpSendTimeout = tcpSendTimeout; - if (request.TryGetQuery("tcpReceiveTimeout", int.Parse, out int tcpReceiveTimeout)) - _dnsWebService._dnsServer.TcpReceiveTimeout = tcpReceiveTimeout; + if (request.TryGetQueryOrForm("tcpReceiveTimeout", int.Parse, out int tcpReceiveTimeout)) + _dnsWebService.DnsServer.TcpReceiveTimeout = tcpReceiveTimeout; + + if (request.TryGetQueryOrForm("quicIdleTimeout", int.Parse, out int quicIdleTimeout)) + _dnsWebService.DnsServer.QuicIdleTimeout = quicIdleTimeout; + + if (request.TryGetQueryOrForm("quicMaxInboundStreams", int.Parse, out int quicMaxInboundStreams)) + _dnsWebService.DnsServer.QuicMaxInboundStreams = quicMaxInboundStreams; + + if (request.TryGetQueryOrForm("listenBacklog", int.Parse, out int listenBacklog)) + _dnsWebService.DnsServer.ListenBacklog = listenBacklog; //web service - string webServiceLocalAddresses = request.Query["webServiceLocalAddresses"]; + string webServiceLocalAddresses = request.QueryOrForm("webServiceLocalAddresses"); if (webServiceLocalAddresses is not null) { if (webServiceLocalAddresses.Length == 0) @@ -621,11 +646,11 @@ namespace DnsServerCore } } - _dnsWebService._webServiceLocalAddresses = localAddresses; + _dnsWebService._webServiceLocalAddresses = DnsServer.GetValidKestralLocalAddresses(localAddresses); } } - if (request.TryGetQuery("webServiceHttpPort", int.Parse, out int webServiceHttpPort)) + if (request.TryGetQueryOrForm("webServiceHttpPort", int.Parse, out int webServiceHttpPort)) { if (_dnsWebService._webServiceHttpPort != webServiceHttpPort) { @@ -634,7 +659,7 @@ namespace DnsServerCore } } - if (request.TryGetQuery("webServiceEnableTls", bool.Parse, out bool webServiceEnableTls)) + if (request.TryGetQueryOrForm("webServiceEnableTls", bool.Parse, out bool webServiceEnableTls)) { if (_dnsWebService._webServiceEnableTls != webServiceEnableTls) { @@ -643,7 +668,7 @@ namespace DnsServerCore } } - if (request.TryGetQuery("webServiceHttpToTlsRedirect", bool.Parse, out bool webServiceHttpToTlsRedirect)) + if (request.TryGetQueryOrForm("webServiceHttpToTlsRedirect", bool.Parse, out bool webServiceHttpToTlsRedirect)) { if (_dnsWebService._webServiceHttpToTlsRedirect != webServiceHttpToTlsRedirect) { @@ -652,10 +677,10 @@ namespace DnsServerCore } } - if (request.TryGetQuery("webServiceUseSelfSignedTlsCertificate", bool.Parse, out bool webServiceUseSelfSignedTlsCertificate)) + if (request.TryGetQueryOrForm("webServiceUseSelfSignedTlsCertificate", bool.Parse, out bool webServiceUseSelfSignedTlsCertificate)) _dnsWebService._webServiceUseSelfSignedTlsCertificate = webServiceUseSelfSignedTlsCertificate; - if (request.TryGetQuery("webServiceTlsPort", int.Parse, out int webServiceTlsPort)) + if (request.TryGetQueryOrForm("webServiceTlsPort", int.Parse, out int webServiceTlsPort)) { if (_dnsWebService._webServiceTlsPort != webServiceTlsPort) { @@ -664,7 +689,7 @@ namespace DnsServerCore } } - string webServiceTlsCertificatePath = request.Query["webServiceTlsCertificatePath"]; + string webServiceTlsCertificatePath = request.QueryOrForm("webServiceTlsCertificatePath"); if (webServiceTlsCertificatePath is not null) { if (webServiceTlsCertificatePath.Length == 0) @@ -674,7 +699,7 @@ namespace DnsServerCore } else { - string webServiceTlsCertificatePassword = request.Query["webServiceTlsCertificatePassword"]; + string webServiceTlsCertificatePassword = request.QueryOrForm("webServiceTlsCertificatePassword"); if ((webServiceTlsCertificatePassword is null) || (webServiceTlsCertificatePassword == "************")) webServiceTlsCertificatePassword = _dnsWebService._webServiceTlsCertificatePassword; @@ -692,44 +717,105 @@ namespace DnsServerCore } //optional protocols - if (request.TryGetQuery("enableDnsOverHttp", bool.Parse, out bool enableDnsOverHttp)) + if (request.TryGetQueryOrForm("enableDnsOverHttp", bool.Parse, out bool enableDnsOverHttp)) { - if (_dnsWebService._dnsServer.EnableDnsOverHttp != enableDnsOverHttp) + if (_dnsWebService.DnsServer.EnableDnsOverHttp != enableDnsOverHttp) { - _dnsWebService._dnsServer.EnableDnsOverHttp = enableDnsOverHttp; + _dnsWebService.DnsServer.EnableDnsOverHttp = enableDnsOverHttp; restartDnsService = true; } } - if (request.TryGetQuery("enableDnsOverTls", bool.Parse, out bool enableDnsOverTls)) + if (request.TryGetQueryOrForm("enableDnsOverTls", bool.Parse, out bool enableDnsOverTls)) { - if (_dnsWebService._dnsServer.EnableDnsOverTls != enableDnsOverTls) + if (_dnsWebService.DnsServer.EnableDnsOverTls != enableDnsOverTls) { - _dnsWebService._dnsServer.EnableDnsOverTls = enableDnsOverTls; + _dnsWebService.DnsServer.EnableDnsOverTls = enableDnsOverTls; restartDnsService = true; } } - if (request.TryGetQuery("enableDnsOverHttps", bool.Parse, out bool enableDnsOverHttps)) + if (request.TryGetQueryOrForm("enableDnsOverHttps", bool.Parse, out bool enableDnsOverHttps)) { - if (_dnsWebService._dnsServer.EnableDnsOverHttps != enableDnsOverHttps) + if (_dnsWebService.DnsServer.EnableDnsOverHttps != enableDnsOverHttps) { - _dnsWebService._dnsServer.EnableDnsOverHttps = enableDnsOverHttps; + _dnsWebService.DnsServer.EnableDnsOverHttps = enableDnsOverHttps; restartDnsService = true; } } - string dnsTlsCertificatePath = request.Query["dnsTlsCertificatePath"]; + if (request.TryGetQueryOrForm("enableDnsOverHttpPort80", bool.Parse, out bool enableDnsOverHttpPort80)) + { + if (_dnsWebService.DnsServer.EnableDnsOverHttpPort80 != enableDnsOverHttpPort80) + { + _dnsWebService.DnsServer.EnableDnsOverHttpPort80 = enableDnsOverHttpPort80; + restartDnsService = true; + } + } + + if (request.TryGetQueryOrForm("enableDnsOverQuic", bool.Parse, out bool enableDnsOverQuic)) + { + if (_dnsWebService.DnsServer.EnableDnsOverQuic != enableDnsOverQuic) + { + if (enableDnsOverQuic) + DnsWebService.ValidateQuicSupport(); + + _dnsWebService.DnsServer.EnableDnsOverQuic = enableDnsOverQuic; + restartDnsService = true; + } + } + + if (request.TryGetQueryOrForm("dnsOverHttpPort", int.Parse, out int dnsOverHttpPort)) + { + if (_dnsWebService.DnsServer.DnsOverHttpPort != dnsOverHttpPort) + { + _dnsWebService.DnsServer.DnsOverHttpPort = dnsOverHttpPort; + restartDnsService = true; + } + } + + if (request.TryGetQueryOrForm("dnsOverTlsPort", int.Parse, out int dnsOverTlsPort)) + { + if (_dnsWebService.DnsServer.DnsOverTlsPort != dnsOverTlsPort) + { + _dnsWebService.DnsServer.DnsOverTlsPort = dnsOverTlsPort; + restartDnsService = true; + } + } + + if (request.TryGetQueryOrForm("dnsOverHttpsPort", int.Parse, out int dnsOverHttpsPort)) + { + if (_dnsWebService.DnsServer.DnsOverHttpsPort != dnsOverHttpsPort) + { + _dnsWebService.DnsServer.DnsOverHttpsPort = dnsOverHttpsPort; + restartDnsService = true; + } + } + + if (request.TryGetQueryOrForm("dnsOverQuicPort", int.Parse, out int dnsOverQuicPort)) + { + if (_dnsWebService.DnsServer.DnsOverQuicPort != dnsOverQuicPort) + { + _dnsWebService.DnsServer.DnsOverQuicPort = dnsOverQuicPort; + restartDnsService = true; + } + } + + string dnsTlsCertificatePath = request.QueryOrForm("dnsTlsCertificatePath"); if (dnsTlsCertificatePath is not null) { if (dnsTlsCertificatePath.Length == 0) { + if (!string.IsNullOrEmpty(_dnsWebService._dnsTlsCertificatePath) && (_dnsWebService.DnsServer.EnableDnsOverTls || _dnsWebService.DnsServer.EnableDnsOverHttps || _dnsWebService.DnsServer.EnableDnsOverQuic)) + restartDnsService = true; + + _dnsWebService.DnsServer.Certificate = null; _dnsWebService._dnsTlsCertificatePath = null; _dnsWebService._dnsTlsCertificatePassword = ""; } else { - string strDnsTlsCertificatePassword = request.Query["dnsTlsCertificatePassword"]; + string strDnsTlsCertificatePassword = request.QueryOrForm("dnsTlsCertificatePassword"); if ((strDnsTlsCertificatePassword is null) || (strDnsTlsCertificatePassword == "************")) strDnsTlsCertificatePassword = _dnsWebService._dnsTlsCertificatePassword; @@ -738,6 +824,9 @@ namespace DnsServerCore { _dnsWebService.LoadDnsTlsCertificate(dnsTlsCertificatePath, strDnsTlsCertificatePassword); + if (string.IsNullOrEmpty(_dnsWebService._dnsTlsCertificatePath) && (_dnsWebService.DnsServer.EnableDnsOverTls || _dnsWebService.DnsServer.EnableDnsOverHttps || _dnsWebService.DnsServer.EnableDnsOverQuic)) + restartDnsService = true; + _dnsWebService._dnsTlsCertificatePath = dnsTlsCertificatePath; _dnsWebService._dnsTlsCertificatePassword = strDnsTlsCertificatePassword; @@ -747,12 +836,12 @@ namespace DnsServerCore } //tsig - string strTsigKeys = request.Query["tsigKeys"]; + string strTsigKeys = request.QueryOrForm("tsigKeys"); if (strTsigKeys is not null) { if ((strTsigKeys.Length == 0) || strTsigKeys.Equals("false", StringComparison.OrdinalIgnoreCase)) { - _dnsWebService._dnsServer.TsigKeys = null; + _dnsWebService.DnsServer.TsigKeys = null; } else { @@ -778,108 +867,116 @@ namespace DnsServerCore } } - _dnsWebService._dnsServer.TsigKeys = tsigKeys; + _dnsWebService.DnsServer.TsigKeys = tsigKeys; } } //recursion - if (request.TryGetQuery("recursion", out DnsServerRecursion recursion)) - _dnsWebService._dnsServer.Recursion = recursion; + if (request.TryGetQueryOrForm("recursion", out DnsServerRecursion recursion)) + _dnsWebService.DnsServer.Recursion = recursion; - string recursionDeniedNetworks = request.Query["recursionDeniedNetworks"]; + string recursionDeniedNetworks = request.QueryOrForm("recursionDeniedNetworks"); if (recursionDeniedNetworks is not null) { if ((recursionDeniedNetworks.Length == 0) || recursionDeniedNetworks.Equals("false", StringComparison.OrdinalIgnoreCase)) - _dnsWebService._dnsServer.RecursionDeniedNetworks = null; + _dnsWebService.DnsServer.RecursionDeniedNetworks = null; else - _dnsWebService._dnsServer.RecursionDeniedNetworks = recursionDeniedNetworks.Split(NetworkAddress.Parse, ','); + _dnsWebService.DnsServer.RecursionDeniedNetworks = recursionDeniedNetworks.Split(NetworkAddress.Parse, ','); } - string recursionAllowedNetworks = request.Query["recursionAllowedNetworks"]; + string recursionAllowedNetworks = request.QueryOrForm("recursionAllowedNetworks"); if (recursionAllowedNetworks is not null) { if ((recursionAllowedNetworks.Length == 0) || recursionAllowedNetworks.Equals("false", StringComparison.OrdinalIgnoreCase)) - _dnsWebService._dnsServer.RecursionAllowedNetworks = null; + _dnsWebService.DnsServer.RecursionAllowedNetworks = null; else - _dnsWebService._dnsServer.RecursionAllowedNetworks = recursionAllowedNetworks.Split(NetworkAddress.Parse, ','); + _dnsWebService.DnsServer.RecursionAllowedNetworks = recursionAllowedNetworks.Split(NetworkAddress.Parse, ','); } - if (request.TryGetQuery("randomizeName", bool.Parse, out bool randomizeName)) - _dnsWebService._dnsServer.RandomizeName = randomizeName; + if (request.TryGetQueryOrForm("randomizeName", bool.Parse, out bool randomizeName)) + _dnsWebService.DnsServer.RandomizeName = randomizeName; - if (request.TryGetQuery("qnameMinimization", bool.Parse, out bool qnameMinimization)) - _dnsWebService._dnsServer.QnameMinimization = qnameMinimization; + if (request.TryGetQueryOrForm("qnameMinimization", bool.Parse, out bool qnameMinimization)) + _dnsWebService.DnsServer.QnameMinimization = qnameMinimization; - if (request.TryGetQuery("nsRevalidation", bool.Parse, out bool nsRevalidation)) - _dnsWebService._dnsServer.NsRevalidation = nsRevalidation; + if (request.TryGetQueryOrForm("nsRevalidation", bool.Parse, out bool nsRevalidation)) + _dnsWebService.DnsServer.NsRevalidation = nsRevalidation; - if (request.TryGetQuery("resolverRetries", int.Parse, out int resolverRetries)) - _dnsWebService._dnsServer.ResolverRetries = resolverRetries; + if (request.TryGetQueryOrForm("resolverRetries", int.Parse, out int resolverRetries)) + _dnsWebService.DnsServer.ResolverRetries = resolverRetries; - if (request.TryGetQuery("resolverTimeout", int.Parse, out int resolverTimeout)) - _dnsWebService._dnsServer.ResolverTimeout = resolverTimeout; + if (request.TryGetQueryOrForm("resolverTimeout", int.Parse, out int resolverTimeout)) + _dnsWebService.DnsServer.ResolverTimeout = resolverTimeout; - if (request.TryGetQuery("resolverMaxStackCount", int.Parse, out int resolverMaxStackCount)) - _dnsWebService._dnsServer.ResolverMaxStackCount = resolverMaxStackCount; + if (request.TryGetQueryOrForm("resolverMaxStackCount", int.Parse, out int resolverMaxStackCount)) + _dnsWebService.DnsServer.ResolverMaxStackCount = resolverMaxStackCount; //cache - if (request.TryGetQuery("serveStale", bool.Parse, out bool serveStale)) - _dnsWebService._dnsServer.ServeStale = serveStale; + if (request.TryGetQueryOrForm("saveCache", bool.Parse, out bool saveCache)) + { + if (!saveCache) + _dnsWebService.DnsServer.CacheZoneManager.DeleteCacheZoneFile(); - if (request.TryGetQuery("serveStaleTtl", uint.Parse, out uint serveStaleTtl)) - _dnsWebService._dnsServer.CacheZoneManager.ServeStaleTtl = serveStaleTtl; + _dnsWebService._saveCache = saveCache; + } - if (request.TryGetQuery("cacheMaximumEntries", long.Parse, out long cacheMaximumEntries)) - _dnsWebService._dnsServer.CacheZoneManager.MaximumEntries = cacheMaximumEntries; + if (request.TryGetQueryOrForm("serveStale", bool.Parse, out bool serveStale)) + _dnsWebService.DnsServer.ServeStale = serveStale; - if (request.TryGetQuery("cacheMinimumRecordTtl", uint.Parse, out uint cacheMinimumRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.MinimumRecordTtl = cacheMinimumRecordTtl; + if (request.TryGetQueryOrForm("serveStaleTtl", uint.Parse, out uint serveStaleTtl)) + _dnsWebService.DnsServer.CacheZoneManager.ServeStaleTtl = serveStaleTtl; - if (request.TryGetQuery("cacheMaximumRecordTtl", uint.Parse, out uint cacheMaximumRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.MaximumRecordTtl = cacheMaximumRecordTtl; + if (request.TryGetQueryOrForm("cacheMaximumEntries", long.Parse, out long cacheMaximumEntries)) + _dnsWebService.DnsServer.CacheZoneManager.MaximumEntries = cacheMaximumEntries; - if (request.TryGetQuery("cacheNegativeRecordTtl", uint.Parse, out uint cacheNegativeRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.NegativeRecordTtl = cacheNegativeRecordTtl; + if (request.TryGetQueryOrForm("cacheMinimumRecordTtl", uint.Parse, out uint cacheMinimumRecordTtl)) + _dnsWebService.DnsServer.CacheZoneManager.MinimumRecordTtl = cacheMinimumRecordTtl; - if (request.TryGetQuery("cacheFailureRecordTtl", uint.Parse, out uint cacheFailureRecordTtl)) - _dnsWebService._dnsServer.CacheZoneManager.FailureRecordTtl = cacheFailureRecordTtl; + if (request.TryGetQueryOrForm("cacheMaximumRecordTtl", uint.Parse, out uint cacheMaximumRecordTtl)) + _dnsWebService.DnsServer.CacheZoneManager.MaximumRecordTtl = cacheMaximumRecordTtl; - if (request.TryGetQuery("cachePrefetchEligibility", int.Parse, out int cachePrefetchEligibility)) - _dnsWebService._dnsServer.CachePrefetchEligibility = cachePrefetchEligibility; + if (request.TryGetQueryOrForm("cacheNegativeRecordTtl", uint.Parse, out uint cacheNegativeRecordTtl)) + _dnsWebService.DnsServer.CacheZoneManager.NegativeRecordTtl = cacheNegativeRecordTtl; - if (request.TryGetQuery("cachePrefetchTrigger", int.Parse, out int cachePrefetchTrigger)) - _dnsWebService._dnsServer.CachePrefetchTrigger = cachePrefetchTrigger; + if (request.TryGetQueryOrForm("cacheFailureRecordTtl", uint.Parse, out uint cacheFailureRecordTtl)) + _dnsWebService.DnsServer.CacheZoneManager.FailureRecordTtl = cacheFailureRecordTtl; - if (request.TryGetQuery("cachePrefetchSampleIntervalInMinutes", int.Parse, out int cachePrefetchSampleIntervalInMinutes)) - _dnsWebService._dnsServer.CachePrefetchSampleIntervalInMinutes = cachePrefetchSampleIntervalInMinutes; + if (request.TryGetQueryOrForm("cachePrefetchEligibility", int.Parse, out int cachePrefetchEligibility)) + _dnsWebService.DnsServer.CachePrefetchEligibility = cachePrefetchEligibility; - if (request.TryGetQuery("cachePrefetchSampleEligibilityHitsPerHour", int.Parse, out int cachePrefetchSampleEligibilityHitsPerHour)) - _dnsWebService._dnsServer.CachePrefetchSampleEligibilityHitsPerHour = cachePrefetchSampleEligibilityHitsPerHour; + if (request.TryGetQueryOrForm("cachePrefetchTrigger", int.Parse, out int cachePrefetchTrigger)) + _dnsWebService.DnsServer.CachePrefetchTrigger = cachePrefetchTrigger; + + if (request.TryGetQueryOrForm("cachePrefetchSampleIntervalInMinutes", int.Parse, out int cachePrefetchSampleIntervalInMinutes)) + _dnsWebService.DnsServer.CachePrefetchSampleIntervalInMinutes = cachePrefetchSampleIntervalInMinutes; + + if (request.TryGetQueryOrForm("cachePrefetchSampleEligibilityHitsPerHour", int.Parse, out int cachePrefetchSampleEligibilityHitsPerHour)) + _dnsWebService.DnsServer.CachePrefetchSampleEligibilityHitsPerHour = cachePrefetchSampleEligibilityHitsPerHour; //blocking - if (request.TryGetQuery("enableBlocking", bool.Parse, out bool enableBlocking)) + if (request.TryGetQueryOrForm("enableBlocking", bool.Parse, out bool enableBlocking)) { - _dnsWebService._dnsServer.EnableBlocking = enableBlocking; - if (_dnsWebService._dnsServer.EnableBlocking) + _dnsWebService.DnsServer.EnableBlocking = enableBlocking; + if (_dnsWebService.DnsServer.EnableBlocking) { if (_temporaryDisableBlockingTimer is not null) _temporaryDisableBlockingTimer.Dispose(); } } - if (request.TryGetQuery("allowTxtBlockingReport", bool.Parse, out bool allowTxtBlockingReport)) - _dnsWebService._dnsServer.AllowTxtBlockingReport = allowTxtBlockingReport; + if (request.TryGetQueryOrForm("allowTxtBlockingReport", bool.Parse, out bool allowTxtBlockingReport)) + _dnsWebService.DnsServer.AllowTxtBlockingReport = allowTxtBlockingReport; - if (request.TryGetQuery("blockingType", out DnsServerBlockingType blockingType)) - _dnsWebService._dnsServer.BlockingType = blockingType; + if (request.TryGetQueryOrForm("blockingType", out DnsServerBlockingType blockingType)) + _dnsWebService.DnsServer.BlockingType = blockingType; - string customBlockingAddresses = request.Query["customBlockingAddresses"]; + string customBlockingAddresses = request.QueryOrForm("customBlockingAddresses"); if (customBlockingAddresses is not null) { if ((customBlockingAddresses.Length == 0) || customBlockingAddresses.Equals("false", StringComparison.OrdinalIgnoreCase)) { - _dnsWebService._dnsServer.CustomBlockingARecords = null; - _dnsWebService._dnsServer.CustomBlockingAAAARecords = null; + _dnsWebService.DnsServer.CustomBlockingARecords = null; + _dnsWebService.DnsServer.CustomBlockingAAAARecords = null; } else { @@ -905,19 +1002,19 @@ namespace DnsServerCore } } - _dnsWebService._dnsServer.CustomBlockingARecords = dnsARecords; - _dnsWebService._dnsServer.CustomBlockingAAAARecords = dnsAAAARecords; + _dnsWebService.DnsServer.CustomBlockingARecords = dnsARecords; + _dnsWebService.DnsServer.CustomBlockingAAAARecords = dnsAAAARecords; } } - string blockListUrls = request.Query["blockListUrls"]; + string blockListUrls = request.QueryOrForm("blockListUrls"); if (blockListUrls is not null) { if ((blockListUrls.Length == 0) || blockListUrls.Equals("false", StringComparison.OrdinalIgnoreCase)) { - _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Clear(); - _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Clear(); - _dnsWebService._dnsServer.BlockListZoneManager.Flush(); + _dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Clear(); + _dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Clear(); + _dnsWebService.DnsServer.BlockListZoneManager.Flush(); } else { @@ -938,7 +1035,7 @@ namespace DnsServerCore if (!blockListUrlsUpdated) { - if (blockListUrlList.Length != (_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count)) + if (blockListUrlList.Length != (_dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Count)) { blockListUrlsUpdated = true; } @@ -950,7 +1047,7 @@ namespace DnsServerCore { string strAllowListUrl = strBlockListUrl.Substring(1); - if (!_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Contains(new Uri(strAllowListUrl))) + if (!_dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Contains(new Uri(strAllowListUrl))) { blockListUrlsUpdated = true; break; @@ -958,7 +1055,7 @@ namespace DnsServerCore } else { - if (!_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Contains(new Uri(strBlockListUrl))) + if (!_dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Contains(new Uri(strBlockListUrl))) { blockListUrlsUpdated = true; break; @@ -970,8 +1067,8 @@ namespace DnsServerCore if (blockListUrlsUpdated) { - _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Clear(); - _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Clear(); + _dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Clear(); + _dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Clear(); foreach (string strBlockListUrl in blockListUrlList) { @@ -979,22 +1076,22 @@ namespace DnsServerCore { Uri allowListUrl = new Uri(strBlockListUrl.Substring(1)); - if (!_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Contains(allowListUrl)) - _dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Add(allowListUrl); + if (!_dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Contains(allowListUrl)) + _dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Add(allowListUrl); } else { Uri blockListUrl = new Uri(strBlockListUrl); - if (!_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Contains(blockListUrl)) - _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Add(blockListUrl); + if (!_dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Contains(blockListUrl)) + _dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Add(blockListUrl); } } } } } - if (request.TryGetQuery("blockListUpdateIntervalHours", int.Parse, out int blockListUpdateIntervalHours)) + if (request.TryGetQueryOrForm("blockListUpdateIntervalHours", int.Parse, out int blockListUpdateIntervalHours)) { if ((blockListUpdateIntervalHours < 0) || (blockListUpdateIntervalHours > 168)) throw new DnsWebServiceException("Parameter `blockListUpdateIntervalHours` must be between 1 hour and 168 hours (7 days) or 0 to disable automatic update."); @@ -1003,40 +1100,49 @@ namespace DnsServerCore } //proxy & forwarders - if (request.TryGetQuery("proxyType", out NetProxyType proxyType)) + if (request.TryGetQueryOrForm("proxyType", out NetProxyType proxyType)) { if (proxyType == NetProxyType.None) { - _dnsWebService._dnsServer.Proxy = null; + _dnsWebService.DnsServer.Proxy = null; } else { NetworkCredential credential = null; - if (request.TryGetQuery("proxyUsername", out string proxyUsername)) - credential = new NetworkCredential(proxyUsername, request.Query["proxyPassword"]); + if (request.TryGetQueryOrForm("proxyUsername", out string proxyUsername)) + credential = new NetworkCredential(proxyUsername, request.QueryOrForm("proxyPassword")); - _dnsWebService._dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.Query["proxyAddress"], int.Parse(request.Query["proxyPort"]), credential); + _dnsWebService.DnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.QueryOrForm("proxyAddress"), int.Parse(request.QueryOrForm("proxyPort")), credential); - if (request.TryGetQuery("proxyBypass", out string proxyBypass)) - _dnsWebService._dnsServer.Proxy.BypassList = proxyBypass.Split(delegate (string value) { return new NetProxyBypassItem(value); }, ','); + if (request.TryGetQueryOrForm("proxyBypass", out string proxyBypass)) + _dnsWebService.DnsServer.Proxy.BypassList = proxyBypass.Split(delegate (string value) { return new NetProxyBypassItem(value); }, ','); } } - string strForwarders = request.Query["forwarders"]; + string strForwarders = request.QueryOrForm("forwarders"); if (strForwarders is not null) { if ((strForwarders.Length == 0) || strForwarders.Equals("false", StringComparison.OrdinalIgnoreCase)) { - _dnsWebService._dnsServer.Forwarders = null; + _dnsWebService.DnsServer.Forwarders = null; } else { - DnsTransportProtocol forwarderProtocol = request.GetQuery("forwarderProtocol", DnsTransportProtocol.Udp); - if (forwarderProtocol == DnsTransportProtocol.HttpsJson) - forwarderProtocol = DnsTransportProtocol.Https; + DnsTransportProtocol forwarderProtocol = request.GetQueryOrForm("forwarderProtocol", DnsTransportProtocol.Udp); - _dnsWebService._dnsServer.Forwarders = strForwarders.Split(delegate (string value) + switch (forwarderProtocol) + { + case DnsTransportProtocol.HttpsJson: + forwarderProtocol = DnsTransportProtocol.Https; + break; + + case DnsTransportProtocol.Quic: + DnsWebService.ValidateQuicSupport(); + break; + } + + _dnsWebService.DnsServer.Forwarders = strForwarders.Split(delegate (string value) { NameServerAddress forwarder = NameServerAddress.Parse(value); @@ -1048,36 +1154,36 @@ namespace DnsServerCore } } - if (request.TryGetQuery("forwarderRetries", int.Parse, out int forwarderRetries)) - _dnsWebService._dnsServer.ForwarderRetries = forwarderRetries; + if (request.TryGetQueryOrForm("forwarderRetries", int.Parse, out int forwarderRetries)) + _dnsWebService.DnsServer.ForwarderRetries = forwarderRetries; - if (request.TryGetQuery("forwarderTimeout", int.Parse, out int forwarderTimeout)) - _dnsWebService._dnsServer.ForwarderTimeout = forwarderTimeout; + if (request.TryGetQueryOrForm("forwarderTimeout", int.Parse, out int forwarderTimeout)) + _dnsWebService.DnsServer.ForwarderTimeout = forwarderTimeout; - if (request.TryGetQuery("forwarderConcurrency", int.Parse, out int forwarderConcurrency)) - _dnsWebService._dnsServer.ForwarderConcurrency = forwarderConcurrency; + if (request.TryGetQueryOrForm("forwarderConcurrency", int.Parse, out int forwarderConcurrency)) + _dnsWebService.DnsServer.ForwarderConcurrency = forwarderConcurrency; //logging - if (request.TryGetQuery("enableLogging", bool.Parse, out bool enableLogging)) + if (request.TryGetQueryOrForm("enableLogging", bool.Parse, out bool enableLogging)) _dnsWebService._log.EnableLogging = enableLogging; - if (request.TryGetQuery("logQueries", bool.Parse, out bool logQueries)) - _dnsWebService._dnsServer.QueryLogManager = logQueries ? _dnsWebService._log : null; + if (request.TryGetQueryOrForm("logQueries", bool.Parse, out bool logQueries)) + _dnsWebService.DnsServer.QueryLogManager = logQueries ? _dnsWebService._log : null; - if (request.TryGetQuery("useLocalTime", bool.Parse, out bool useLocalTime)) + if (request.TryGetQueryOrForm("useLocalTime", bool.Parse, out bool useLocalTime)) _dnsWebService._log.UseLocalTime = useLocalTime; - if (request.TryGetQuery("logFolder", out string logFolder)) + if (request.TryGetQueryOrForm("logFolder", out string logFolder)) _dnsWebService._log.LogFolder = logFolder; - if (request.TryGetQuery("maxLogFileDays", int.Parse, out int maxLogFileDays)) + if (request.TryGetQueryOrForm("maxLogFileDays", int.Parse, out int maxLogFileDays)) _dnsWebService._log.MaxLogFileDays = maxLogFileDays; - if (request.TryGetQuery("maxStatFileDays", int.Parse, out int maxStatFileDays)) - _dnsWebService._dnsServer.StatsManager.MaxStatFileDays = maxStatFileDays; + if (request.TryGetQueryOrForm("maxStatFileDays", int.Parse, out int maxStatFileDays)) + _dnsWebService.DnsServer.StatsManager.MaxStatFileDays = maxStatFileDays; //TLS actions - if ((_dnsWebService._webServiceTlsCertificatePath == null) && (_dnsWebService._dnsTlsCertificatePath == null)) + if ((_dnsWebService._webServiceTlsCertificatePath is null) && (_dnsWebService._dnsTlsCertificatePath is null)) _dnsWebService.StopTlsCertificateUpdateTimer(); _dnsWebService.SelfSignedCertCheck(serverDomainChanged, true); @@ -1090,7 +1196,7 @@ namespace DnsServerCore } //blocklist timers - if ((_blockListUpdateIntervalHours > 0) && ((_dnsWebService._dnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count) > 0)) + if ((_blockListUpdateIntervalHours > 0) && ((_dnsWebService.DnsServer.BlockListZoneManager.AllowListUrls.Count + _dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Count) > 0)) { if (blockListUrlsUpdated || (_blockListUpdateTimer is null)) ForceUpdateBlockLists(); @@ -1132,9 +1238,9 @@ namespace DnsServerCore { jsonWriter.WriteStartArray(); - if (_dnsWebService._dnsServer.TsigKeys is not null) + if (_dnsWebService.DnsServer.TsigKeys is not null) { - foreach (KeyValuePair tsigKey in _dnsWebService._dnsServer.TsigKeys) + foreach (KeyValuePair tsigKey in _dnsWebService.DnsServer.TsigKeys) jsonWriter.WriteStringValue(tsigKey.Key); } @@ -1151,17 +1257,17 @@ namespace DnsServerCore HttpRequest request = context.Request; - bool blockLists = request.GetQuery("blockLists", bool.Parse, false); - bool logs = request.GetQuery("logs", bool.Parse, false); - bool scopes = request.GetQuery("scopes", bool.Parse, false); - bool apps = request.GetQuery("apps", bool.Parse, false); - bool stats = request.GetQuery("stats", bool.Parse, false); - bool zones = request.GetQuery("zones", bool.Parse, false); - bool allowedZones = request.GetQuery("allowedZones", bool.Parse, false); - bool blockedZones = request.GetQuery("blockedZones", bool.Parse, false); - bool dnsSettings = request.GetQuery("dnsSettings", bool.Parse, false); - bool authConfig = request.GetQuery("authConfig", bool.Parse, false); - bool logSettings = request.GetQuery("logSettings", bool.Parse, false); + bool blockLists = request.GetQueryOrForm("blockLists", bool.Parse, false); + bool logs = request.GetQueryOrForm("logs", bool.Parse, false); + bool scopes = request.GetQueryOrForm("scopes", bool.Parse, false); + bool apps = request.GetQueryOrForm("apps", bool.Parse, false); + bool stats = request.GetQueryOrForm("stats", bool.Parse, false); + bool zones = request.GetQueryOrForm("zones", bool.Parse, false); + bool allowedZones = request.GetQueryOrForm("allowedZones", bool.Parse, false); + bool blockedZones = request.GetQueryOrForm("blockedZones", bool.Parse, false); + bool dnsSettings = request.GetQueryOrForm("dnsSettings", bool.Parse, false); + bool authConfig = request.GetQueryOrForm("authConfig", bool.Parse, false); + bool logSettings = request.GetQueryOrForm("logSettings", bool.Parse, false); string tmpFile = Path.GetTempFileName(); try @@ -1332,20 +1438,20 @@ namespace DnsServerCore HttpRequest request = context.Request; - bool blockLists = request.GetQuery("blockLists", bool.Parse, false); - bool logs = request.GetQuery("logs", bool.Parse, false); - bool scopes = request.GetQuery("scopes", bool.Parse, false); - bool apps = request.GetQuery("apps", bool.Parse, false); - bool stats = request.GetQuery("stats", bool.Parse, false); - bool zones = request.GetQuery("zones", bool.Parse, false); - bool allowedZones = request.GetQuery("allowedZones", bool.Parse, false); - bool blockedZones = request.GetQuery("blockedZones", bool.Parse, false); - bool dnsSettings = request.GetQuery("dnsSettings", bool.Parse, false); - bool authConfig = request.GetQuery("authConfig", bool.Parse, false); - bool logSettings = request.GetQuery("logSettings", bool.Parse, false); - bool deleteExistingFiles = request.GetQuery("deleteExistingFiles", bool.Parse, false); + bool blockLists = request.GetQueryOrForm("blockLists", bool.Parse, false); + bool logs = request.GetQueryOrForm("logs", bool.Parse, false); + bool scopes = request.GetQueryOrForm("scopes", bool.Parse, false); + bool apps = request.GetQueryOrForm("apps", bool.Parse, false); + bool stats = request.GetQueryOrForm("stats", bool.Parse, false); + bool zones = request.GetQueryOrForm("zones", bool.Parse, false); + bool allowedZones = request.GetQueryOrForm("allowedZones", bool.Parse, false); + bool blockedZones = request.GetQueryOrForm("blockedZones", bool.Parse, false); + bool dnsSettings = request.GetQueryOrForm("dnsSettings", bool.Parse, false); + bool authConfig = request.GetQueryOrForm("authConfig", bool.Parse, false); + bool logSettings = request.GetQueryOrForm("logSettings", bool.Parse, false); + bool deleteExistingFiles = request.GetQueryOrForm("deleteExistingFiles", bool.Parse, false); - if (request.Form.Files.Count == 0) + if (!request.HasFormContentType || (request.Form.Files.Count == 0)) throw new DnsWebServiceException("DNS backup zip file is missing."); //write to temp file @@ -1446,13 +1552,13 @@ namespace DnsServerCore //reload settings and block list zone _dnsWebService.LoadConfigFile(); - if ((_blockListUpdateIntervalHours > 0) && (_dnsWebService._dnsServer.BlockListZoneManager.BlockListUrls.Count > 0)) + if ((_blockListUpdateIntervalHours > 0) && (_dnsWebService.DnsServer.BlockListZoneManager.BlockListUrls.Count > 0)) { ThreadPool.QueueUserWorkItem(delegate (object state) { try { - _dnsWebService._dnsServer.BlockListZoneManager.LoadBlockLists(); + _dnsWebService.DnsServer.BlockListZoneManager.LoadBlockLists(); StartBlockListUpdateTimer(); } catch (Exception ex) @@ -1470,7 +1576,7 @@ namespace DnsServerCore if (apps) { //unload apps - _dnsWebService._dnsServer.DnsApplicationManager.UnloadAllApplications(); + _dnsWebService.DnsServer.DnsApplicationManager.UnloadAllApplications(); if (deleteExistingFiles) { @@ -1502,7 +1608,7 @@ namespace DnsServerCore } //reload apps - _dnsWebService._dnsServer.DnsApplicationManager.LoadAllApplications(); + _dnsWebService.DnsServer.DnsApplicationManager.LoadAllApplications(); } if (zones) @@ -1525,7 +1631,7 @@ namespace DnsServerCore } //reload zones - _dnsWebService._dnsServer.AuthZoneManager.LoadAllZoneFiles(); + _dnsWebService.DnsServer.AuthZoneManager.LoadAllZoneFiles(); _dnsWebService.InspectAndFixZonePermissions(); } @@ -1544,7 +1650,7 @@ namespace DnsServerCore } //reload - _dnsWebService._dnsServer.AllowedZoneManager.LoadAllowedZoneFile(); + _dnsWebService.DnsServer.AllowedZoneManager.LoadAllowedZoneFile(); } if (blockedZones) @@ -1562,13 +1668,13 @@ namespace DnsServerCore } //reload - _dnsWebService._dnsServer.BlockedZoneManager.LoadBlockedZoneFile(); + _dnsWebService.DnsServer.BlockedZoneManager.LoadBlockedZoneFile(); } if (scopes) { //stop dhcp server - _dnsWebService._dhcpServer.Stop(); + _dnsWebService.DhcpServer.Stop(); try { @@ -1592,7 +1698,7 @@ namespace DnsServerCore finally { //start dhcp server - _dnsWebService._dhcpServer.Start(); + _dnsWebService.DhcpServer.Start(); } } @@ -1622,7 +1728,7 @@ namespace DnsServerCore } //reload stats - _dnsWebService._dnsServer.StatsManager.ReloadStats(); + _dnsWebService.DnsServer.StatsManager.ReloadStats(); } _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Settings backup zip file was restored."); @@ -1666,7 +1772,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Settings, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - int minutes = context.Request.GetQuery("minutes", int.Parse); + int minutes = context.Request.GetQueryOrForm("minutes", int.Parse); Timer temporaryDisableBlockingTimer = _temporaryDisableBlockingTimer; if (temporaryDisableBlockingTimer is not null) @@ -1676,7 +1782,7 @@ namespace DnsServerCore { try { - _dnsWebService._dnsServer.EnableBlocking = true; + _dnsWebService.DnsServer.EnableBlocking = true; _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocking was enabled after " + minutes + " minute(s) being temporarily disabled."); } catch (Exception ex) @@ -1689,7 +1795,7 @@ namespace DnsServerCore if (ReferenceEquals(originalTimer, temporaryDisableBlockingTimer)) { newTemporaryDisableBlockingTimer.Change(minutes * 60 * 1000, Timeout.Infinite); - _dnsWebService._dnsServer.EnableBlocking = false; + _dnsWebService.DnsServer.EnableBlocking = false; _temporaryDisableBlockingTill = DateTime.UtcNow.AddMinutes(minutes); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocking was temporarily disabled for " + minutes + " minute(s)."); From 3fa1c373fc5e8f093e7327a10dd04adc46ce49b0 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:16:46 +0530 Subject: [PATCH 094/191] WebServiceZonesApi: Code refactoring changes. --- DnsServerCore/WebServiceZonesApi.cs | 1023 ++++++++++++++------------- 1 file changed, 541 insertions(+), 482 deletions(-) diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index f25be4df..5d4aeb9d 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -96,31 +96,31 @@ namespace DnsServerCore { jsonWriter.WriteStartObject(); - if (authoritativeZoneRecords) - jsonWriter.WriteBoolean("disabled", record.IsDisabled()); - jsonWriter.WriteString("name", record.Name); - jsonWriter.WriteString("type", record.Type.ToString()); - jsonWriter.WritePropertyName("ttl"); - if (authoritativeZoneRecords) - jsonWriter.WriteNumberValue(record.TTL); - else - jsonWriter.WriteStringValue(record.TTL + " (" + WebUtilities.GetFormattedTime((int)record.TTL) + ")"); - if (authoritativeZoneRecords) { - string comments = record.GetComments(); + AuthRecordInfo authRecordInfo = record.GetAuthRecordInfo(); + + jsonWriter.WriteNumber("ttl", record.TTL); + jsonWriter.WriteBoolean("disabled", authRecordInfo.Disabled); + + string comments = authRecordInfo.Comments; if (!string.IsNullOrEmpty(comments)) jsonWriter.WriteString("comments", comments); } + else + { + if (record.IsStale) + jsonWriter.WriteString("ttl", "0 (0 sec)"); + else + jsonWriter.WriteString("ttl", record.TTL + " (" + WebUtilities.GetFormattedTime((int)record.TTL) + ")"); + } jsonWriter.WritePropertyName("rData"); jsonWriter.WriteStartObject(); - DnsResourceRecordInfo recordInfo = record.GetRecordInfo(); - switch (record.Type) { case DnsResourceRecordType.A: @@ -191,8 +191,10 @@ namespace DnsServerCore if (authoritativeZoneRecords) { - IReadOnlyList primaryNameServers = record.GetPrimaryNameServers(); - if (primaryNameServers.Count > 0) + AuthRecordInfo authRecordInfo = record.GetAuthRecordInfo(); + + IReadOnlyList primaryNameServers = authRecordInfo.PrimaryNameServers; + if (primaryNameServers is not null) { string primaryAddresses = null; @@ -207,11 +209,11 @@ namespace DnsServerCore jsonWriter.WriteString("primaryAddresses", primaryAddresses); } - if (recordInfo.ZoneTransferProtocol != DnsTransportProtocol.Udp) - jsonWriter.WriteString("zoneTransferProtocol", recordInfo.ZoneTransferProtocol.ToString()); + if (authRecordInfo.ZoneTransferProtocol != DnsTransportProtocol.Udp) + jsonWriter.WriteString("zoneTransferProtocol", authRecordInfo.ZoneTransferProtocol.ToString()); - if (!string.IsNullOrEmpty(recordInfo.TsigKeyName)) - jsonWriter.WriteString("tsigKeyName", recordInfo.TsigKeyName); + if (!string.IsNullOrEmpty(authRecordInfo.TsigKeyName)) + jsonWriter.WriteString("tsigKeyName", authRecordInfo.TsigKeyName); } } break; @@ -587,54 +589,81 @@ namespace DnsServerCore jsonWriter.WriteEndObject(); - IReadOnlyList glueRecords = recordInfo.GlueRecords; - if (glueRecords is not null) - { - string glue = null; - - foreach (DnsResourceRecord glueRecord in glueRecords) - { - if (glue == null) - glue = glueRecord.RDATA.ToString(); - else - glue = glue + ", " + glueRecord.RDATA.ToString(); - } - - jsonWriter.WriteString("glueRecords", glue); - } - - IReadOnlyList rrsigRecords = recordInfo.RRSIGRecords; - IReadOnlyList nsecRecords = recordInfo.NSECRecords; - - if ((rrsigRecords is not null) || (nsecRecords is not null)) - { - jsonWriter.WritePropertyName("dnssecRecords"); - jsonWriter.WriteStartArray(); - - if (rrsigRecords is not null) - { - foreach (DnsResourceRecord rrsigRecord in rrsigRecords) - jsonWriter.WriteStringValue(rrsigRecord.ToString()); - } - - if (nsecRecords is not null) - { - foreach (DnsResourceRecord nsecRecord in nsecRecords) - jsonWriter.WriteStringValue(nsecRecord.ToString()); - } - - jsonWriter.WriteEndArray(); - } - jsonWriter.WriteString("dnssecStatus", record.DnssecStatus.ToString()); - NetworkAddress eDnsClientSubnet = recordInfo.EDnsClientSubnet; - if (eDnsClientSubnet is not null) + if (authoritativeZoneRecords) { - jsonWriter.WriteString("eDnsClientSubnet", eDnsClientSubnet.ToString()); - } + AuthRecordInfo authRecordInfo = record.GetAuthRecordInfo(); - jsonWriter.WriteString("lastUsedOn", recordInfo.LastUsedOn); + IReadOnlyList glueRecords = authRecordInfo.GlueRecords; + if (glueRecords is not null) + { + string glue = null; + + foreach (DnsResourceRecord glueRecord in glueRecords) + { + if (glue == null) + glue = glueRecord.RDATA.ToString(); + else + glue = glue + ", " + glueRecord.RDATA.ToString(); + } + + jsonWriter.WriteString("glueRecords", glue); + } + + jsonWriter.WriteString("lastUsedOn", authRecordInfo.LastUsedOn); + } + else + { + CacheRecordInfo cacheRecordInfo = record.GetCacheRecordInfo(); + + IReadOnlyList glueRecords = cacheRecordInfo.GlueRecords; + if (glueRecords is not null) + { + string glue = null; + + foreach (DnsResourceRecord glueRecord in glueRecords) + { + if (glue == null) + glue = glueRecord.RDATA.ToString(); + else + glue = glue + ", " + glueRecord.RDATA.ToString(); + } + + jsonWriter.WriteString("glueRecords", glue); + } + + IReadOnlyList rrsigRecords = cacheRecordInfo.RRSIGRecords; + IReadOnlyList nsecRecords = cacheRecordInfo.NSECRecords; + + if ((rrsigRecords is not null) || (nsecRecords is not null)) + { + jsonWriter.WritePropertyName("dnssecRecords"); + jsonWriter.WriteStartArray(); + + if (rrsigRecords is not null) + { + foreach (DnsResourceRecord rrsigRecord in rrsigRecords) + jsonWriter.WriteStringValue(rrsigRecord.ToString()); + } + + if (nsecRecords is not null) + { + foreach (DnsResourceRecord nsecRecord in nsecRecords) + jsonWriter.WriteStringValue(nsecRecord.ToString()); + } + + jsonWriter.WriteEndArray(); + } + + NetworkAddress eDnsClientSubnet = cacheRecordInfo.EDnsClientSubnet; + if (eDnsClientSubnet is not null) + { + jsonWriter.WriteString("eDnsClientSubnet", eDnsClientSubnet.ToString()); + } + + jsonWriter.WriteString("lastUsedOn", cacheRecordInfo.LastUsedOn); + } jsonWriter.WriteEndObject(); } @@ -688,7 +717,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - List zones = _dnsWebService._dnsServer.AuthZoneManager.ListZones(); + List zones = _dnsWebService.DnsServer.AuthZoneManager.ListZones(); zones.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); @@ -716,7 +745,7 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQueryAlt("zone", "domain"); + string zoneName = request.GetQueryOrFormAlt("zone", "domain"); if (zoneName.Contains('*')) throw new DnsWebServiceException("Domain name for a zone cannot contain wildcard character."); @@ -735,14 +764,14 @@ namespace DnsServerCore zoneName = zoneName.Substring(0, zoneName.Length - 1); } - AuthZoneType type = request.GetQuery("type", AuthZoneType.Primary); + AuthZoneType type = request.GetQueryOrForm("type", AuthZoneType.Primary); AuthZoneInfo zoneInfo; switch (type) { case AuthZoneType.Primary: { - zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(zoneName, _dnsWebService._dnsServer.ServerDomain, false); + zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(zoneName, _dnsWebService.DnsServer.ServerDomain, false); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); @@ -753,17 +782,20 @@ namespace DnsServerCore _dnsWebService._authManager.SaveConfigFile(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Authoritative primary zone was created: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; case AuthZoneType.Secondary: { - string primaryNameServerAddresses = request.GetQuery("primaryNameServerAddresses", null); - DnsTransportProtocol zoneTransferProtocol = request.GetQuery("zoneTransferProtocol", DnsTransportProtocol.Tcp); - string tsigKeyName = request.GetQuery("tsigKeyName", null); + string primaryNameServerAddresses = request.GetQueryOrForm("primaryNameServerAddresses", null); + DnsTransportProtocol zoneTransferProtocol = request.GetQueryOrForm("zoneTransferProtocol", DnsTransportProtocol.Tcp); + string tsigKeyName = request.GetQueryOrForm("tsigKeyName", null); - zoneInfo = await _dnsWebService._dnsServer.AuthZoneManager.CreateSecondaryZoneAsync(zoneName, primaryNameServerAddresses, zoneTransferProtocol, tsigKeyName); + if (zoneTransferProtocol == DnsTransportProtocol.Quic) + DnsWebService.ValidateQuicSupport(); + + zoneInfo = await _dnsWebService.DnsServer.AuthZoneManager.CreateSecondaryZoneAsync(zoneName, primaryNameServerAddresses, zoneTransferProtocol, tsigKeyName); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); @@ -774,15 +806,15 @@ namespace DnsServerCore _dnsWebService._authManager.SaveConfigFile(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Authoritative secondary zone was created: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; case AuthZoneType.Stub: { - string primaryNameServerAddresses = request.GetQuery("primaryNameServerAddresses", null); + string primaryNameServerAddresses = request.GetQueryOrForm("primaryNameServerAddresses", null); - zoneInfo = await _dnsWebService._dnsServer.AuthZoneManager.CreateStubZoneAsync(zoneName, primaryNameServerAddresses); + zoneInfo = await _dnsWebService.DnsServer.AuthZoneManager.CreateStubZoneAsync(zoneName, primaryNameServerAddresses); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); @@ -793,16 +825,16 @@ namespace DnsServerCore _dnsWebService._authManager.SaveConfigFile(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Stub zone was created: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; case AuthZoneType.Forwarder: { - DnsTransportProtocol forwarderProtocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); - string forwarder = request.GetQuery("forwarder"); - bool dnssecValidation = request.GetQuery("dnssecValidation", bool.Parse, false); - NetProxyType proxyType = request.GetQuery("proxyType", NetProxyType.None); + DnsTransportProtocol forwarderProtocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + string forwarder = request.GetQueryOrForm("forwarder"); + bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false); + NetProxyType proxyType = request.GetQueryOrForm("proxyType", NetProxyType.None); string proxyAddress = null; ushort proxyPort = 0; @@ -811,13 +843,24 @@ namespace DnsServerCore if (proxyType != NetProxyType.None) { - proxyAddress = request.GetQuery("proxyAddress"); - proxyPort = request.GetQuery("proxyPort", ushort.Parse); - proxyUsername = request.Query["proxyUsername"]; - proxyPassword = request.Query["proxyPassword"]; + proxyAddress = request.GetQueryOrForm("proxyAddress"); + proxyPort = request.GetQueryOrForm("proxyPort", ushort.Parse); + proxyUsername = request.QueryOrForm("proxyUsername"); + proxyPassword = request.QueryOrForm("proxyPassword"); } - zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreateForwarderZone(zoneName, forwarderProtocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, null); + switch (forwarderProtocol) + { + case DnsTransportProtocol.HttpsJson: + forwarderProtocol = DnsTransportProtocol.Https; + break; + + case DnsTransportProtocol.Quic: + DnsWebService.ValidateQuicSupport(); + break; + } + + zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreateForwarderZone(zoneName, forwarderProtocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, null); if (zoneInfo is null) throw new DnsWebServiceException("Zone already exists: " + zoneName); @@ -828,7 +871,7 @@ namespace DnsServerCore _dnsWebService._authManager.SaveConfigFile(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Forwarder zone was created: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } break; @@ -837,7 +880,7 @@ namespace DnsServerCore } //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones - _dnsWebService._dnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); + _dnsWebService.DnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("domain", string.IsNullOrEmpty(zoneInfo.Name) ? "." : zoneInfo.Name); @@ -852,17 +895,17 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string algorithm = request.GetQuery("algorithm"); - uint dnsKeyTtl = request.GetQuery("dnsKeyTtl", uint.Parse, 24 * 60 * 60); - ushort zskRolloverDays = request.GetQuery("zskRolloverDays", ushort.Parse, 90); + string algorithm = request.GetQueryOrForm("algorithm"); + uint dnsKeyTtl = request.GetQueryOrForm("dnsKeyTtl", uint.Parse, 24 * 60 * 60); + ushort zskRolloverDays = request.GetQueryOrForm("zskRolloverDays", ushort.Parse, 90); bool useNSEC3 = false; - string strNxProof = request.Query["nxProof"]; + string strNxProof = request.QueryOrForm("nxProof"); if (!string.IsNullOrEmpty(strNxProof)) { switch (strNxProof.ToUpper()) @@ -885,31 +928,31 @@ namespace DnsServerCore if (useNSEC3) { - iterations = request.GetQuery("iterations", ushort.Parse, 0); - saltLength = request.GetQuery("saltLength", byte.Parse, 0); + iterations = request.GetQueryOrForm("iterations", ushort.Parse, 0); + saltLength = request.GetQueryOrForm("saltLength", byte.Parse, 0); } switch (algorithm.ToUpper()) { case "RSA": - string hashAlgorithm = request.GetQuery("hashAlgorithm"); - int kskKeySize = request.GetQuery("kskKeySize", int.Parse); - int zskKeySize = request.GetQuery("zskKeySize", int.Parse); + string hashAlgorithm = request.GetQueryOrForm("hashAlgorithm"); + int kskKeySize = request.GetQueryOrForm("kskKeySize", int.Parse); + int zskKeySize = request.GetQueryOrForm("zskKeySize", int.Parse); if (useNSEC3) - _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC3(zoneName, hashAlgorithm, kskKeySize, zskKeySize, iterations, saltLength, dnsKeyTtl, zskRolloverDays); + _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC3(zoneName, hashAlgorithm, kskKeySize, zskKeySize, iterations, saltLength, dnsKeyTtl, zskRolloverDays); else - _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC(zoneName, hashAlgorithm, kskKeySize, zskKeySize, dnsKeyTtl, zskRolloverDays); + _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC(zoneName, hashAlgorithm, kskKeySize, zskKeySize, dnsKeyTtl, zskRolloverDays); break; case "ECDSA": - string curve = request.GetQuery("curve"); + string curve = request.GetQueryOrForm("curve"); if (useNSEC3) - _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC3(zoneName, curve, iterations, saltLength, dnsKeyTtl, zskRolloverDays); + _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC3(zoneName, curve, iterations, saltLength, dnsKeyTtl, zskRolloverDays); else - _dnsWebService._dnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC(zoneName, curve, dnsKeyTtl, zskRolloverDays); + _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC(zoneName, curve, dnsKeyTtl, zskRolloverDays); break; @@ -919,7 +962,7 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was signed successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UnsignPrimaryZone(HttpContext context) @@ -929,16 +972,16 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService._dnsServer.AuthZoneManager.UnsignPrimaryZone(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.UnsignPrimaryZone(zoneName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was unsigned successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void GetPrimaryZoneDnssecProperties(HttpContext context) @@ -948,9 +991,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No such zone was found: " + zoneName); @@ -1044,16 +1087,16 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService._dnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC(zoneName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was converted to NSEC successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void ConvertPrimaryZoneToNSEC3(HttpContext context) @@ -1065,19 +1108,19 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort iterations = request.GetQuery("iterations", ushort.Parse, 0); - byte saltLength = request.GetQuery("saltLength", byte.Parse, 0); + ushort iterations = request.GetQueryOrForm("iterations", ushort.Parse, 0); + byte saltLength = request.GetQueryOrForm("saltLength", byte.Parse, 0); - _dnsWebService._dnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC3(zoneName, iterations, saltLength); + _dnsWebService.DnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC3(zoneName, iterations, saltLength); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone was converted to NSEC3 successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UpdatePrimaryZoneNSEC3Parameters(HttpContext context) @@ -1089,19 +1132,19 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort iterations = request.GetQuery("iterations", ushort.Parse, 0); - byte saltLength = request.GetQuery("saltLength", byte.Parse, 0); + ushort iterations = request.GetQueryOrForm("iterations", ushort.Parse, 0); + byte saltLength = request.GetQueryOrForm("saltLength", byte.Parse, 0); - _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneNSEC3Parameters(zoneName, iterations, saltLength); + _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneNSEC3Parameters(zoneName, iterations, saltLength); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone NSEC3 parameters were updated successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UpdatePrimaryZoneDnssecDnsKeyTtl(HttpContext context) @@ -1113,18 +1156,18 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - uint dnsKeyTtl = request.GetQuery("ttl", uint.Parse); + uint dnsKeyTtl = request.GetQueryOrForm("ttl", uint.Parse); - _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneDnsKeyTtl(zoneName, dnsKeyTtl); + _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneDnsKeyTtl(zoneName, dnsKeyTtl); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone DNSKEY TTL was updated successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void GenerateAndAddPrimaryZoneDnssecPrivateKey(HttpContext context) @@ -1136,28 +1179,28 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - DnssecPrivateKeyType keyType = request.GetQuery("keyType"); - ushort rolloverDays = request.GetQuery("rolloverDays", ushort.Parse, (ushort)(keyType == DnssecPrivateKeyType.ZoneSigningKey ? 90 : 0)); - string algorithm = request.GetQuery("algorithm"); + DnssecPrivateKeyType keyType = request.GetQueryOrForm("keyType"); + ushort rolloverDays = request.GetQueryOrForm("rolloverDays", ushort.Parse, (ushort)(keyType == DnssecPrivateKeyType.ZoneSigningKey ? 90 : 0)); + string algorithm = request.GetQueryOrForm("algorithm"); switch (algorithm.ToUpper()) { case "RSA": - string hashAlgorithm = request.GetQuery("hashAlgorithm"); - int keySize = request.GetQuery("keySize", int.Parse); + string hashAlgorithm = request.GetQueryOrForm("hashAlgorithm"); + int keySize = request.GetQueryOrForm("keySize", int.Parse); - _dnsWebService._dnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecRsaPrivateKey(zoneName, keyType, hashAlgorithm, keySize, rolloverDays); + _dnsWebService.DnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecRsaPrivateKey(zoneName, keyType, hashAlgorithm, keySize, rolloverDays); break; case "ECDSA": - string curve = request.GetQuery("curve"); + string curve = request.GetQueryOrForm("curve"); - _dnsWebService._dnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecEcdsaPrivateKey(zoneName, keyType, curve, rolloverDays); + _dnsWebService.DnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecEcdsaPrivateKey(zoneName, keyType, curve, rolloverDays); break; default: @@ -1166,7 +1209,7 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNSSEC private key was generated and added to the primary zone successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void UpdatePrimaryZoneDnssecPrivateKey(HttpContext context) @@ -1178,19 +1221,19 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort keyTag = request.GetQuery("keyTag", ushort.Parse); - ushort rolloverDays = request.GetQuery("rolloverDays", ushort.Parse); + ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse); + ushort rolloverDays = request.GetQueryOrForm("rolloverDays", ushort.Parse); - _dnsWebService._dnsServer.AuthZoneManager.UpdatePrimaryZoneDnssecPrivateKey(zoneName, keyTag, rolloverDays); + _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneDnssecPrivateKey(zoneName, keyTag, rolloverDays); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Primary zone DNSSEC private key config was updated successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void DeletePrimaryZoneDnssecPrivateKey(HttpContext context) @@ -1202,18 +1245,18 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort keyTag = request.GetQuery("keyTag", ushort.Parse); + ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse); - _dnsWebService._dnsServer.AuthZoneManager.DeletePrimaryZoneDnssecPrivateKey(zoneName, keyTag); + _dnsWebService.DnsServer.AuthZoneManager.DeletePrimaryZoneDnssecPrivateKey(zoneName, keyTag); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] DNSSEC private key was deleted from primary zone successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(HttpContext context) @@ -1223,16 +1266,16 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQuery("zone").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - _dnsWebService._dnsServer.AuthZoneManager.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(zoneName); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] All DNSSEC private keys from the primary zone were published successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void RolloverPrimaryZoneDnsKey(HttpContext context) @@ -1244,18 +1287,18 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort keyTag = request.GetQuery("keyTag", ushort.Parse); + ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse); - _dnsWebService._dnsServer.AuthZoneManager.RolloverPrimaryZoneDnsKey(zoneName, keyTag); + _dnsWebService.DnsServer.AuthZoneManager.RolloverPrimaryZoneDnsKey(zoneName, keyTag); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was rolled over successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void RetirePrimaryZoneDnsKey(HttpContext context) @@ -1267,18 +1310,18 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQuery("zone").TrimEnd('.'); + string zoneName = request.GetQueryOrForm("zone").TrimEnd('.'); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - ushort keyTag = request.GetQuery("keyTag", ushort.Parse); + ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse); - _dnsWebService._dnsServer.AuthZoneManager.RetirePrimaryZoneDnsKey(zoneName, keyTag); + _dnsWebService.DnsServer.AuthZoneManager.RetirePrimaryZoneDnsKey(zoneName, keyTag); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was retired successfully: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneName); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneName); } public void DeleteZone(HttpContext context) @@ -1288,9 +1331,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No such zone was found: " + zoneName); @@ -1300,14 +1343,14 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - if (!_dnsWebService._dnsServer.AuthZoneManager.DeleteZone(zoneInfo.Name)) + if (!_dnsWebService.DnsServer.AuthZoneManager.DeleteZone(zoneInfo.Name)) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneInfo.Name); _dnsWebService._authManager.RemoveAllPermissions(PermissionSection.Zones, zoneInfo.Name); _dnsWebService._authManager.SaveConfigFile(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was deleted: " + zoneName); - _dnsWebService._dnsServer.AuthZoneManager.DeleteZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.DeleteZoneFile(zoneInfo.Name); } public void EnableZone(HttpContext context) @@ -1317,9 +1360,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1333,10 +1376,10 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was enabled: " + zoneInfo.Name); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones - _dnsWebService._dnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); + _dnsWebService.DnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name); } public void DisableZone(HttpContext context) @@ -1346,9 +1389,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1362,7 +1405,7 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone was disabled: " + zoneInfo.Name); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } public void GetZoneOptions(HttpContext context) @@ -1374,10 +1417,10 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQueryAlt("zone", "domain").TrimEnd('.'); - bool includeAvailableTsigKeyNames = request.GetQuery("includeAvailableTsigKeyNames", bool.Parse, false); + string zoneName = request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.'); + bool includeAvailableTsigKeyNames = request.GetQueryOrForm("includeAvailableTsigKeyNames", bool.Parse, false); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No such zone was found: " + zoneName); @@ -1513,9 +1556,9 @@ namespace DnsServerCore { jsonWriter.WriteStartArray(); - if (_dnsWebService._dnsServer.TsigKeys is not null) + if (_dnsWebService.DnsServer.TsigKeys is not null) { - foreach (KeyValuePair tsigKey in _dnsWebService._dnsServer.TsigKeys) + foreach (KeyValuePair tsigKey in _dnsWebService.DnsServer.TsigKeys) jsonWriter.WriteStringValue(tsigKey.Key); } @@ -1533,9 +1576,9 @@ namespace DnsServerCore HttpRequest request = context.Request; - string zoneName = request.GetQueryAlt("zone", "domain").TrimEnd('.'); + string zoneName = request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1545,17 +1588,17 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - if (request.TryGetQuery("disabled", bool.Parse, out bool disabled)) + if (request.TryGetQueryOrForm("disabled", bool.Parse, out bool disabled)) zoneInfo.Disabled = disabled; switch (zoneInfo.Type) { case AuthZoneType.Primary: case AuthZoneType.Secondary: - if (request.TryGetQuery("zoneTransfer", out AuthZoneTransfer zoneTransfer)) + if (request.TryGetQueryOrForm("zoneTransfer", out AuthZoneTransfer zoneTransfer)) zoneInfo.ZoneTransfer = zoneTransfer; - string strZoneTransferNameServers = request.Query["zoneTransferNameServers"]; + string strZoneTransferNameServers = request.QueryOrForm("zoneTransferNameServers"); if (strZoneTransferNameServers is not null) { if ((strZoneTransferNameServers.Length == 0) || strZoneTransferNameServers.Equals("false", StringComparison.OrdinalIgnoreCase)) @@ -1564,7 +1607,7 @@ namespace DnsServerCore zoneInfo.ZoneTransferNameServers = strZoneTransferNameServers.Split(IPAddress.Parse, ','); } - string strZoneTransferTsigKeyNames = request.Query["zoneTransferTsigKeyNames"]; + string strZoneTransferTsigKeyNames = request.QueryOrForm("zoneTransferTsigKeyNames"); if (strZoneTransferTsigKeyNames is not null) { if ((strZoneTransferTsigKeyNames.Length == 0) || strZoneTransferTsigKeyNames.Equals("false", StringComparison.OrdinalIgnoreCase)) @@ -1583,10 +1626,10 @@ namespace DnsServerCore } } - if (request.TryGetQuery("notify", out AuthZoneNotify notify)) + if (request.TryGetQueryOrForm("notify", out AuthZoneNotify notify)) zoneInfo.Notify = notify; - string strNotifyNameServers = request.Query["notifyNameServers"]; + string strNotifyNameServers = request.QueryOrForm("notifyNameServers"); if (strNotifyNameServers is not null) { if ((strNotifyNameServers.Length == 0) || strNotifyNameServers.Equals("false", StringComparison.OrdinalIgnoreCase)) @@ -1600,10 +1643,10 @@ namespace DnsServerCore switch (zoneInfo.Type) { case AuthZoneType.Primary: - if (request.TryGetQuery("update", out AuthZoneUpdate update)) + if (request.TryGetQueryOrForm("update", out AuthZoneUpdate update)) zoneInfo.Update = update; - string strUpdateIpAddresses = request.Query["updateIpAddresses"]; + string strUpdateIpAddresses = request.QueryOrForm("updateIpAddresses"); if (strUpdateIpAddresses is not null) { if ((strUpdateIpAddresses.Length == 0) || strUpdateIpAddresses.Equals("false", StringComparison.OrdinalIgnoreCase)) @@ -1612,7 +1655,7 @@ namespace DnsServerCore zoneInfo.UpdateIpAddresses = strUpdateIpAddresses.Split(IPAddress.Parse, ','); } - string strUpdateSecurityPolicies = request.Query["updateSecurityPolicies"]; + string strUpdateSecurityPolicies = request.QueryOrForm("updateSecurityPolicies"); if (strUpdateSecurityPolicies is not null) { if ((strUpdateSecurityPolicies.Length == 0) || strUpdateSecurityPolicies.Equals("false", StringComparison.OrdinalIgnoreCase)) @@ -1657,7 +1700,7 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] " + zoneInfo.Type.ToString() + " zone options were updated successfully: " + zoneInfo.Name); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } public void ResyncZone(HttpContext context) @@ -1667,9 +1710,9 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string zoneName = context.Request.GetQueryAlt("zone", "domain").TrimEnd('.'); + string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); @@ -1695,13 +1738,13 @@ namespace DnsServerCore { HttpRequest request = context.Request; - string domain = request.GetQuery("domain").TrimEnd('.'); + string domain = request.GetQueryOrForm("domain").TrimEnd('.'); - string zoneName = request.Query["zone"]; + string zoneName = request.QueryOrForm("zone"); if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -1713,10 +1756,10 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - DnsResourceRecordType type = request.GetQuery("type"); - uint ttl = request.GetQuery("ttl", uint.Parse, _defaultRecordTtl); - bool overwrite = request.GetQuery("overwrite", bool.Parse, false); - string comments = request.Query["comments"]; + DnsResourceRecordType type = request.GetQueryOrForm("type"); + uint ttl = request.GetQueryOrForm("ttl", uint.Parse, _defaultRecordTtl); + bool overwrite = request.GetQueryOrForm("overwrite", bool.Parse, false); + string comments = request.QueryOrForm("comments"); DnsResourceRecord newRecord; @@ -1725,7 +1768,7 @@ namespace DnsServerCore case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: { - string strIPAddress = request.GetQueryAlt("ipAddress", "value"); + string strIPAddress = request.GetQueryOrFormAlt("ipAddress", "value"); IPAddress ipAddress; if (strIPAddress.Equals("request-ip-address")) @@ -1733,21 +1776,21 @@ namespace DnsServerCore else ipAddress = IPAddress.Parse(strIPAddress); - bool ptr = request.GetQuery("ptr", bool.Parse, false); + bool ptr = request.GetQueryOrForm("ptr", bool.Parse, false); if (ptr) { string ptrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); + AuthZoneInfo reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); if (reverseZoneInfo is null) { - bool createPtrZone = request.GetQuery("createPtrZone", bool.Parse, false); + bool createPtrZone = request.GetQueryOrForm("createPtrZone", bool.Parse, false); if (!createPtrZone) throw new DnsServerException("No reverse zone available to add PTR record."); string ptrZone = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 24 : 64); - reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService._dnsServer.ServerDomain, false); + reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService.DnsServer.ServerDomain, false); if (reverseZoneInfo == null) throw new DnsServerException("Failed to create reverse zone to add PTR record: " + ptrZone); @@ -1764,8 +1807,8 @@ namespace DnsServerCore if (reverseZoneInfo.Type != AuthZoneType.Primary) throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is not a primary zone."); - _dnsWebService._dnsServer.AuthZoneManager.SetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); } if (type == DnsResourceRecordType.A) @@ -1774,32 +1817,32 @@ namespace DnsServerCore newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsAAAARecordData(ipAddress)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.NS: { - string nameServer = request.GetQueryAlt("nameServer", "value").TrimEnd('.'); - string glueAddresses = request.GetQuery("glue", null); + string nameServer = request.GetQueryOrFormAlt("nameServer", "value").TrimEnd('.'); + string glueAddresses = request.GetQueryOrForm("glue", null); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNSRecordData(nameServer)); - if (glueAddresses != null) + if (!string.IsNullOrEmpty(glueAddresses)) newRecord.SetGlueRecords(glueAddresses); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -1807,87 +1850,87 @@ namespace DnsServerCore { if (!overwrite) { - IReadOnlyList existingRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); + IReadOnlyList existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); if (existingRecords.Count > 0) throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } - string cname = request.GetQueryAlt("cname", "value").TrimEnd('.'); + string cname = request.GetQueryOrFormAlt("cname", "value").TrimEnd('.'); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.PTR: { - string ptrName = request.GetQueryAlt("ptrName", "value").TrimEnd('.'); + string ptrName = request.GetQueryOrFormAlt("ptrName", "value").TrimEnd('.'); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsPTRRecordData(ptrName)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.MX: { - ushort preference = request.GetQuery("preference", ushort.Parse); - string exchange = request.GetQueryAlt("exchange", "value").TrimEnd('.'); + ushort preference = request.GetQueryOrForm("preference", ushort.Parse); + string exchange = request.GetQueryOrFormAlt("exchange", "value").TrimEnd('.'); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsMXRecordData(preference, exchange)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.TXT: { - string text = request.GetQueryAlt("text", "value"); + string text = request.GetQueryOrFormAlt("text", "value"); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTXTRecordData(text)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.SRV: { - ushort priority = request.GetQuery("priority", ushort.Parse); - ushort weight = request.GetQuery("weight", ushort.Parse); - ushort port = request.GetQuery("port", ushort.Parse); - string target = request.GetQueryAlt("target", "value").TrimEnd('.'); + ushort priority = request.GetQueryOrForm("priority", ushort.Parse); + ushort weight = request.GetQueryOrForm("weight", ushort.Parse); + ushort port = request.GetQueryOrForm("port", ushort.Parse); + string target = request.GetQueryOrFormAlt("target", "value").TrimEnd('.'); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSRVRecordData(priority, weight, port, target)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; @@ -1895,117 +1938,117 @@ namespace DnsServerCore { if (!overwrite) { - IReadOnlyList existingRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); + IReadOnlyList existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); if (existingRecords.Count > 0) throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } - string dname = request.GetQueryAlt("dname", "value").TrimEnd('.'); + string dname = request.GetQueryOrFormAlt("dname", "value").TrimEnd('.'); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.DS: { - ushort keyTag = request.GetQuery("keyTag", ushort.Parse); - DnssecAlgorithm algorithm = Enum.Parse(request.GetQuery("algorithm").Replace('-', '_'), true); - DnssecDigestType digestType = Enum.Parse(request.GetQuery("digestType").Replace('-', '_'), true); - byte[] digest = request.GetQueryAlt("digest", "value", Convert.FromHexString); + ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse); + DnssecAlgorithm algorithm = Enum.Parse(request.GetQueryOrForm("algorithm").Replace('-', '_'), true); + DnssecDigestType digestType = Enum.Parse(request.GetQueryOrForm("digestType").Replace('-', '_'), true); + byte[] digest = request.GetQueryOrFormAlt("digest", "value", Convert.FromHexString); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDSRecordData(keyTag, algorithm, digestType, digest)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.SSHFP: { - DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQuery("sshfpAlgorithm"); - DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQuery("sshfpFingerprintType"); - byte[] sshfpFingerprint = request.GetQuery("sshfpFingerprint", Convert.FromHexString); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrForm("sshfpAlgorithm"); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrForm("sshfpFingerprintType"); + byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.TLSA: { - DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQuery("tlsaCertificateUsage").Replace('-', '_'), true); - DnsTLSASelector tlsaSelector = request.GetQuery("tlsaSelector"); - DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQuery("tlsaMatchingType").Replace('-', '_'), true); - string tlsaCertificateAssociationData = request.GetQuery("tlsaCertificateAssociationData"); + DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true); + DnsTLSASelector tlsaSelector = request.GetQueryOrForm("tlsaSelector"); + DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true); + string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData"); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.CAA: { - byte flags = request.GetQuery("flags", byte.Parse); - string tag = request.GetQuery("tag"); - string value = request.GetQuery("value"); + byte flags = request.GetQueryOrForm("flags", byte.Parse); + string tag = request.GetQueryOrForm("tag"); + string value = request.GetQueryOrForm("value"); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCAARecordData(flags, tag, value)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.ANAME: { - string aname = request.GetQueryAlt("aname", "value").TrimEnd('.'); + string aname = request.GetQueryOrFormAlt("aname", "value").TrimEnd('.'); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsANAMERecordData(aname)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); - string forwarder = request.GetQueryAlt("forwarder", "value"); - bool dnssecValidation = request.GetQuery("dnssecValidation", bool.Parse, false); + DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + string forwarder = request.GetQueryOrFormAlt("forwarder", "value"); + bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false); NetProxyType proxyType = NetProxyType.None; string proxyAddress = null; @@ -2015,37 +2058,37 @@ namespace DnsServerCore if (!forwarder.Equals("this-server")) { - proxyType = request.GetQuery("proxyType", NetProxyType.None); + proxyType = request.GetQueryOrForm("proxyType", NetProxyType.None); if (proxyType != NetProxyType.None) { - proxyAddress = request.GetQuery("proxyAddress"); - proxyPort = request.GetQuery("proxyPort", ushort.Parse); - proxyUsername = request.Query["proxyUsername"]; - proxyPassword = request.Query["proxyPassword"]; + proxyAddress = request.GetQueryOrForm("proxyAddress"); + proxyPort = request.GetQueryOrForm("proxyPort", ushort.Parse); + proxyUsername = request.QueryOrForm("proxyUsername"); + proxyPassword = request.QueryOrForm("proxyPassword"); } } newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecordData(protocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; if (overwrite) - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); else - _dnsWebService._dnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord); } break; case DnsResourceRecordType.APP: { - string appName = request.GetQueryAlt("appName", "value"); - string classPath = request.GetQuery("classPath"); - string recordData = request.GetQuery("recordData", ""); + string appName = request.GetQueryOrFormAlt("appName", "value"); + string classPath = request.GetQueryOrForm("classPath"); + string recordData = request.GetQueryOrForm("recordData", ""); if (!overwrite) { - IReadOnlyList existingRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); + IReadOnlyList existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type); if (existingRecords.Count > 0) throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing records."); } @@ -2053,9 +2096,9 @@ namespace DnsServerCore newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsApplicationRecordData(appName, classPath, recordData)); if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord); } break; @@ -2065,7 +2108,7 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] New record was added to authoritative zone {record: " + newRecord.ToString() + "}"); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); @@ -2078,9 +2121,9 @@ namespace DnsServerCore public void GetRecords(HttpContext context) { - string domain = context.Request.GetQuery("domain").TrimEnd('.'); + string domain = context.Request.GetQueryOrForm("domain").TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(domain); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(domain); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -2095,7 +2138,7 @@ namespace DnsServerCore WriteZoneInfoAsJson(zoneInfo, jsonWriter); List records = new List(); - _dnsWebService._dnsServer.AuthZoneManager.ListAllRecords(domain, records); + _dnsWebService.DnsServer.AuthZoneManager.ListAllRecords(domain, records); WriteRecordsAsJson(records, jsonWriter, true, zoneInfo); } @@ -2104,13 +2147,13 @@ namespace DnsServerCore { HttpRequest request = context.Request; - string domain = request.GetQuery("domain").TrimEnd('.'); + string domain = request.GetQueryOrForm("domain").TrimEnd('.'); - string zoneName = request.Query["zone"]; + string zoneName = request.QueryOrForm("zone"); if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -2122,24 +2165,24 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - DnsResourceRecordType type = request.GetQuery("type"); + DnsResourceRecordType type = request.GetQueryOrForm("type"); switch (type) { case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: { - IPAddress ipAddress = IPAddress.Parse(request.GetQueryAlt("ipAddress", "value")); + IPAddress ipAddress = IPAddress.Parse(request.GetQueryOrFormAlt("ipAddress", "value")); if (type == DnsResourceRecordType.A) - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsARecordData(ipAddress)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsARecordData(ipAddress)); else - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsAAAARecordData(ipAddress)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsAAAARecordData(ipAddress)); string ptrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo reverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); + AuthZoneInfo reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain); if ((reverseZoneInfo != null) && !reverseZoneInfo.Internal && (reverseZoneInfo.Type == AuthZoneType.Primary)) { - IReadOnlyList ptrRecords = _dnsWebService._dnsServer.AuthZoneManager.GetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR); + IReadOnlyList ptrRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR); if (ptrRecords.Count > 0) { foreach (DnsResourceRecord ptrRecord in ptrRecords) @@ -2147,8 +2190,8 @@ namespace DnsServerCore if ((ptrRecord.RDATA as DnsPTRRecordData).Domain.Equals(domain, StringComparison.OrdinalIgnoreCase)) { //delete PTR record and save reverse zone - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ptrRecord.RDATA); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ptrRecord.RDATA); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name); break; } } @@ -2159,117 +2202,117 @@ namespace DnsServerCore case DnsResourceRecordType.NS: { - string nameServer = request.GetQueryAlt("nameServer", "value").TrimEnd('.'); + string nameServer = request.GetQueryOrFormAlt("nameServer", "value").TrimEnd('.'); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsNSRecordData(nameServer)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsNSRecordData(nameServer)); } break; case DnsResourceRecordType.CNAME: - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); break; case DnsResourceRecordType.PTR: { - string ptrName = request.GetQueryAlt("ptrName", "value").TrimEnd('.'); + string ptrName = request.GetQueryOrFormAlt("ptrName", "value").TrimEnd('.'); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsPTRRecordData(ptrName)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsPTRRecordData(ptrName)); } break; case DnsResourceRecordType.MX: { - ushort preference = request.GetQuery("preference", ushort.Parse); - string exchange = request.GetQueryAlt("exchange", "value").TrimEnd('.'); + ushort preference = request.GetQueryOrForm("preference", ushort.Parse); + string exchange = request.GetQueryOrFormAlt("exchange", "value").TrimEnd('.'); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsMXRecordData(preference, exchange)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsMXRecordData(preference, exchange)); } break; case DnsResourceRecordType.TXT: { - string text = request.GetQueryAlt("text", "value"); + string text = request.GetQueryOrFormAlt("text", "value"); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTXTRecordData(text)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTXTRecordData(text)); } break; case DnsResourceRecordType.SRV: { - ushort priority = request.GetQuery("priority", ushort.Parse); - ushort weight = request.GetQuery("weight", ushort.Parse); - ushort port = request.GetQuery("port", ushort.Parse); - string target = request.GetQueryAlt("target", "value").TrimEnd('.'); + ushort priority = request.GetQueryOrForm("priority", ushort.Parse); + ushort weight = request.GetQueryOrForm("weight", ushort.Parse); + ushort port = request.GetQueryOrForm("port", ushort.Parse); + string target = request.GetQueryOrFormAlt("target", "value").TrimEnd('.'); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSRVRecordData(priority, weight, port, target)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSRVRecordData(priority, weight, port, target)); } break; case DnsResourceRecordType.DNAME: - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); break; case DnsResourceRecordType.DS: { - ushort keyTag = request.GetQuery("keyTag", ushort.Parse); - DnssecAlgorithm algorithm = Enum.Parse(request.GetQuery("algorithm").Replace('-', '_'), true); - DnssecDigestType digestType = Enum.Parse(request.GetQuery("digestType").Replace('-', '_'), true); - byte[] digest = Convert.FromHexString(request.GetQueryAlt("digest", "value")); + ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse); + DnssecAlgorithm algorithm = Enum.Parse(request.GetQueryOrForm("algorithm").Replace('-', '_'), true); + DnssecDigestType digestType = Enum.Parse(request.GetQueryOrForm("digestType").Replace('-', '_'), true); + byte[] digest = Convert.FromHexString(request.GetQueryOrFormAlt("digest", "value")); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsDSRecordData(keyTag, algorithm, digestType, digest)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsDSRecordData(keyTag, algorithm, digestType, digest)); } break; case DnsResourceRecordType.SSHFP: { - DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQuery("sshfpAlgorithm"); - DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQuery("sshfpFingerprintType"); - byte[] sshfpFingerprint = request.GetQuery("sshfpFingerprint", Convert.FromHexString); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrForm("sshfpAlgorithm"); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrForm("sshfpFingerprintType"); + byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); } break; case DnsResourceRecordType.TLSA: { - DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQuery("tlsaCertificateUsage").Replace('-', '_'), true); - DnsTLSASelector tlsaSelector = request.GetQuery("tlsaSelector"); - DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQuery("tlsaMatchingType").Replace('-', '_'), true); - string tlsaCertificateAssociationData = request.GetQuery("tlsaCertificateAssociationData"); + DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true); + DnsTLSASelector tlsaSelector = request.GetQueryOrForm("tlsaSelector"); + DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true); + string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData"); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData)); } break; case DnsResourceRecordType.CAA: { - byte flags = request.GetQuery("flags", byte.Parse); - string tag = request.GetQuery("tag"); - string value = request.GetQuery("value"); + byte flags = request.GetQueryOrForm("flags", byte.Parse); + string tag = request.GetQueryOrForm("tag"); + string value = request.GetQueryOrForm("value"); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsCAARecordData(flags, tag, value)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsCAARecordData(flags, tag, value)); } break; case DnsResourceRecordType.ANAME: { - string aname = request.GetQueryAlt("aname", "value").TrimEnd('.'); + string aname = request.GetQueryOrFormAlt("aname", "value").TrimEnd('.'); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsANAMERecordData(aname)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsANAMERecordData(aname)); } break; case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); - string forwarder = request.GetQueryAlt("forwarder", "value"); + DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + string forwarder = request.GetQueryOrFormAlt("forwarder", "value"); - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsForwarderRecordData(protocol, forwarder)); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsForwarderRecordData(protocol, forwarder)); } break; case DnsResourceRecordType.APP: - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type); break; default: @@ -2278,20 +2321,20 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Record was deleted from authoritative zone {domain: " + domain + "; type: " + type + ";}"); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); } public void UpdateRecord(HttpContext context) { HttpRequest request = context.Request; - string domain = request.GetQuery("domain").TrimEnd('.'); + string domain = request.GetQueryOrForm("domain").TrimEnd('.'); - string zoneName = request.Query["zone"]; + string zoneName = request.QueryOrForm("zone"); if (zoneName is not null) zoneName = zoneName.TrimEnd('.'); - AuthZoneInfo zoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -2303,11 +2346,11 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - string newDomain = request.GetQuery("newDomain", domain).TrimEnd('.'); - uint ttl = request.GetQuery("ttl", uint.Parse, _defaultRecordTtl); - bool disable = request.GetQuery("disable", bool.Parse, false); - string comments = request.Query["comments"]; - DnsResourceRecordType type = request.GetQuery("type"); + string newDomain = request.GetQueryOrForm("newDomain", domain).TrimEnd('.'); + uint ttl = request.GetQueryOrForm("ttl", uint.Parse, _defaultRecordTtl); + bool disable = request.GetQueryOrForm("disable", bool.Parse, false); + string comments = request.QueryOrForm("comments"); + DnsResourceRecordType type = request.GetQueryOrForm("type"); DnsResourceRecord oldRecord = null; DnsResourceRecord newRecord; @@ -2317,24 +2360,24 @@ namespace DnsServerCore case DnsResourceRecordType.A: case DnsResourceRecordType.AAAA: { - IPAddress ipAddress = IPAddress.Parse(request.GetQueryAlt("ipAddress", "value")); - IPAddress newIpAddress = IPAddress.Parse(request.GetQueryAlt("newIpAddress", "newValue", ipAddress.ToString())); + IPAddress ipAddress = IPAddress.Parse(request.GetQueryOrFormAlt("ipAddress", "value")); + IPAddress newIpAddress = IPAddress.Parse(request.GetQueryOrFormAlt("newIpAddress", "newValue", ipAddress.ToString())); - bool ptr = request.GetQuery("ptr", bool.Parse, false); + bool ptr = request.GetQueryOrForm("ptr", bool.Parse, false); if (ptr) { string newPtrDomain = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo newReverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(newPtrDomain); + AuthZoneInfo newReverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(newPtrDomain); if (newReverseZoneInfo is null) { - bool createPtrZone = request.GetQuery("createPtrZone", bool.Parse, false); + bool createPtrZone = request.GetQueryOrForm("createPtrZone", bool.Parse, false); if (!createPtrZone) throw new DnsServerException("No reverse zone available to add PTR record."); string ptrZone = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 24 : 64); - newReverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService._dnsServer.ServerDomain, false); + newReverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone, _dnsWebService.DnsServer.ServerDomain, false); if (newReverseZoneInfo is null) throw new DnsServerException("Failed to create reverse zone to add PTR record: " + ptrZone); @@ -2353,17 +2396,17 @@ namespace DnsServerCore string oldPtrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128); - AuthZoneInfo oldReverseZoneInfo = _dnsWebService._dnsServer.AuthZoneManager.FindAuthZoneInfo(oldPtrDomain); + AuthZoneInfo oldReverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(oldPtrDomain); if ((oldReverseZoneInfo != null) && !oldReverseZoneInfo.Internal && (oldReverseZoneInfo.Type == AuthZoneType.Primary)) { //delete old PTR record if any and save old reverse zone - _dnsWebService._dnsServer.AuthZoneManager.DeleteRecords(oldReverseZoneInfo.Name, oldPtrDomain, DnsResourceRecordType.PTR); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(oldReverseZoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(oldReverseZoneInfo.Name, oldPtrDomain, DnsResourceRecordType.PTR); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(oldReverseZoneInfo.Name); } //add new PTR record and save reverse zone - _dnsWebService._dnsServer.AuthZoneManager.SetRecords(newReverseZoneInfo.Name, newPtrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(newReverseZoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SetRecords(newReverseZoneInfo.Name, newPtrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecordData[] { new DnsPTRRecordData(domain) }); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(newReverseZoneInfo.Name); } if (type == DnsResourceRecordType.A) @@ -2378,62 +2421,62 @@ namespace DnsServerCore } if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.NS: { - string nameServer = request.GetQueryAlt("nameServer", "value").TrimEnd('.'); - string newNameServer = request.GetQueryAlt("newNameServer", "newValue", nameServer).TrimEnd('.'); + string nameServer = request.GetQueryOrFormAlt("nameServer", "value").TrimEnd('.'); + string newNameServer = request.GetQueryOrFormAlt("newNameServer", "newValue", nameServer).TrimEnd('.'); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsNSRecordData(nameServer)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsNSRecordData(newNameServer)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - if (request.TryGetQuery("glue", out string glueAddresses)) + if (request.TryGetQueryOrForm("glue", out string glueAddresses)) newRecord.SetGlueRecords(glueAddresses); - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.CNAME: { - string cname = request.GetQueryAlt("cname", "value").TrimEnd('.'); + string cname = request.GetQueryOrFormAlt("cname", "value").TrimEnd('.'); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCNAMERecordData(cname)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.SOA: { - string primaryNameServer = request.GetQuery("primaryNameServer").TrimEnd('.'); - string responsiblePerson = request.GetQuery("responsiblePerson").TrimEnd('.'); - uint serial = request.GetQuery("serial", uint.Parse); - uint refresh = request.GetQuery("refresh", uint.Parse); - uint retry = request.GetQuery("retry", uint.Parse); - uint expire = request.GetQuery("expire", uint.Parse); - uint minimum = request.GetQuery("minimum", uint.Parse); + string primaryNameServer = request.GetQueryOrForm("primaryNameServer").TrimEnd('.'); + string responsiblePerson = request.GetQueryOrForm("responsiblePerson").TrimEnd('.'); + uint serial = request.GetQueryOrForm("serial", uint.Parse); + uint refresh = request.GetQueryOrForm("refresh", uint.Parse); + uint retry = request.GetQueryOrForm("retry", uint.Parse); + uint expire = request.GetQueryOrForm("expire", uint.Parse); + uint minimum = request.GetQueryOrForm("minimum", uint.Parse); DnsResourceRecord newSOARecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSOARecordData(primaryNameServer, responsiblePerson, serial, refresh, retry, expire, minimum)); @@ -2441,27 +2484,32 @@ namespace DnsServerCore { case AuthZoneType.Secondary: case AuthZoneType.Stub: - if (request.TryGetQuery("primaryAddresses", out string primaryAddresses)) - newSOARecord.SetPrimaryNameServers(primaryAddresses); + if (request.TryGetQueryOrForm("primaryAddresses", out string primaryAddresses)) + newSOARecord.GetAuthRecordInfo().PrimaryNameServers = primaryAddresses.Split(NameServerAddress.Parse, ','); break; } if (zoneInfo.Type == AuthZoneType.Secondary) { - DnsResourceRecordInfo recordInfo = newSOARecord.GetRecordInfo(); + AuthRecordInfo recordInfo = newSOARecord.GetAuthRecordInfo(); + + if (request.TryGetQueryOrForm("zoneTransferProtocol", out DnsTransportProtocol zoneTransferProtocol)) + { + if (zoneTransferProtocol == DnsTransportProtocol.Quic) + DnsWebService.ValidateQuicSupport(); - if (request.TryGetQuery("zoneTransferProtocol", out DnsTransportProtocol zoneTransferProtocol)) recordInfo.ZoneTransferProtocol = zoneTransferProtocol; + } - if (request.TryGetQuery("tsigKeyName", out string tsigKeyName)) + if (request.TryGetQueryOrForm("tsigKeyName", out string tsigKeyName)) recordInfo.TsigKeyName = tsigKeyName; } if (!string.IsNullOrEmpty(comments)) - newSOARecord.SetComments(comments); + newSOARecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newSOARecord); + _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newSOARecord); newRecord = zoneInfo.GetApexRecords(DnsResourceRecordType.SOA)[0]; } @@ -2469,234 +2517,234 @@ namespace DnsServerCore case DnsResourceRecordType.PTR: { - string ptrName = request.GetQueryAlt("ptrName", "value").TrimEnd('.'); - string newPtrName = request.GetQueryAlt("newPtrName", "newValue", ptrName).TrimEnd('.'); + string ptrName = request.GetQueryOrFormAlt("ptrName", "value").TrimEnd('.'); + string newPtrName = request.GetQueryOrFormAlt("newPtrName", "newValue", ptrName).TrimEnd('.'); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsPTRRecordData(ptrName)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsPTRRecordData(newPtrName)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.MX: { - ushort preference = request.GetQuery("preference", ushort.Parse); - ushort newPreference = request.GetQuery("newPreference", ushort.Parse, preference); + ushort preference = request.GetQueryOrForm("preference", ushort.Parse); + ushort newPreference = request.GetQueryOrForm("newPreference", ushort.Parse, preference); - string exchange = request.GetQueryAlt("exchange", "value").TrimEnd('.'); - string newExchange = request.GetQueryAlt("newExchange", "newValue", exchange).TrimEnd('.'); + string exchange = request.GetQueryOrFormAlt("exchange", "value").TrimEnd('.'); + string newExchange = request.GetQueryOrFormAlt("newExchange", "newValue", exchange).TrimEnd('.'); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsMXRecordData(preference, exchange)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsMXRecordData(newPreference, newExchange)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.TXT: { - string text = request.GetQueryAlt("text", "value"); - string newText = request.GetQueryAlt("newText", "newValue", text); + string text = request.GetQueryOrFormAlt("text", "value"); + string newText = request.GetQueryOrFormAlt("newText", "newValue", text); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTXTRecordData(text)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTXTRecordData(newText)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.SRV: { - ushort priority = request.GetQuery("priority", ushort.Parse); - ushort newPriority = request.GetQuery("newPriority", ushort.Parse, priority); + ushort priority = request.GetQueryOrForm("priority", ushort.Parse); + ushort newPriority = request.GetQueryOrForm("newPriority", ushort.Parse, priority); - ushort weight = request.GetQuery("weight", ushort.Parse); - ushort newWeight = request.GetQuery("newWeight", ushort.Parse, weight); + ushort weight = request.GetQueryOrForm("weight", ushort.Parse); + ushort newWeight = request.GetQueryOrForm("newWeight", ushort.Parse, weight); - ushort port = request.GetQuery("port", ushort.Parse); - ushort newPort = request.GetQuery("newPort", ushort.Parse, port); + ushort port = request.GetQueryOrForm("port", ushort.Parse); + ushort newPort = request.GetQueryOrForm("newPort", ushort.Parse, port); - string target = request.GetQueryAlt("target", "value").TrimEnd('.'); - string newTarget = request.GetQueryAlt("newTarget", "newValue", target).TrimEnd('.'); + string target = request.GetQueryOrFormAlt("target", "value").TrimEnd('.'); + string newTarget = request.GetQueryOrFormAlt("newTarget", "newValue", target).TrimEnd('.'); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSRVRecordData(priority, weight, port, target)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSRVRecordData(newPriority, newWeight, newPort, newTarget)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.DNAME: { - string dname = request.GetQueryAlt("dname", "value").TrimEnd('.'); + string dname = request.GetQueryOrFormAlt("dname", "value").TrimEnd('.'); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDNAMERecordData(dname)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.DS: { - ushort keyTag = request.GetQuery("keyTag", ushort.Parse); - ushort newKeyTag = request.GetQuery("newKeyTag", ushort.Parse, keyTag); + ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse); + ushort newKeyTag = request.GetQueryOrForm("newKeyTag", ushort.Parse, keyTag); - DnssecAlgorithm algorithm = Enum.Parse(request.GetQuery("algorithm").Replace('-', '_'), true); - DnssecAlgorithm newAlgorithm = Enum.Parse(request.GetQuery("newAlgorithm", algorithm.ToString()).Replace('-', '_'), true); + DnssecAlgorithm algorithm = Enum.Parse(request.GetQueryOrForm("algorithm").Replace('-', '_'), true); + DnssecAlgorithm newAlgorithm = Enum.Parse(request.GetQueryOrForm("newAlgorithm", algorithm.ToString()).Replace('-', '_'), true); - DnssecDigestType digestType = Enum.Parse(request.GetQuery("digestType").Replace('-', '_'), true); - DnssecDigestType newDigestType = Enum.Parse(request.GetQuery("newDigestType", digestType.ToString()).Replace('-', '_'), true); + DnssecDigestType digestType = Enum.Parse(request.GetQueryOrForm("digestType").Replace('-', '_'), true); + DnssecDigestType newDigestType = Enum.Parse(request.GetQueryOrForm("newDigestType", digestType.ToString()).Replace('-', '_'), true); - byte[] digest = request.GetQueryAlt("digest", "value", Convert.FromHexString); - byte[] newDigest = request.GetQueryAlt("newDigest", "newValue", Convert.FromHexString, digest); + byte[] digest = request.GetQueryOrFormAlt("digest", "value", Convert.FromHexString); + byte[] newDigest = request.GetQueryOrFormAlt("newDigest", "newValue", Convert.FromHexString, digest); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDSRecordData(keyTag, algorithm, digestType, digest)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDSRecordData(newKeyTag, newAlgorithm, newDigestType, newDigest)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.SSHFP: { - DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQuery("sshfpAlgorithm"); - DnsSSHFPAlgorithm newSshfpAlgorithm = request.GetQuery("newSshfpAlgorithm", sshfpAlgorithm); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrForm("sshfpAlgorithm"); + DnsSSHFPAlgorithm newSshfpAlgorithm = request.GetQueryOrForm("newSshfpAlgorithm", sshfpAlgorithm); - DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQuery("sshfpFingerprintType"); - DnsSSHFPFingerprintType newSshfpFingerprintType = request.GetQuery("newSshfpFingerprintType", sshfpFingerprintType); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrForm("sshfpFingerprintType"); + DnsSSHFPFingerprintType newSshfpFingerprintType = request.GetQueryOrForm("newSshfpFingerprintType", sshfpFingerprintType); - byte[] sshfpFingerprint = request.GetQuery("sshfpFingerprint", Convert.FromHexString); - byte[] newSshfpFingerprint = request.GetQuery("newSshfpFingerprint", Convert.FromHexString, sshfpFingerprint); + byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString); + byte[] newSshfpFingerprint = request.GetQueryOrForm("newSshfpFingerprint", Convert.FromHexString, sshfpFingerprint); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(newSshfpAlgorithm, newSshfpFingerprintType, newSshfpFingerprint)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.TLSA: { - DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQuery("tlsaCertificateUsage").Replace('-', '_'), true); - DnsTLSACertificateUsage newTlsaCertificateUsage = Enum.Parse(request.GetQuery("newTlsaCertificateUsage", tlsaCertificateUsage.ToString()).Replace('-', '_'), true); + DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true); + DnsTLSACertificateUsage newTlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("newTlsaCertificateUsage", tlsaCertificateUsage.ToString()).Replace('-', '_'), true); - DnsTLSASelector tlsaSelector = request.GetQuery("tlsaSelector"); - DnsTLSASelector newTlsaSelector = request.GetQuery("newTlsaSelector", tlsaSelector); + DnsTLSASelector tlsaSelector = request.GetQueryOrForm("tlsaSelector"); + DnsTLSASelector newTlsaSelector = request.GetQueryOrForm("newTlsaSelector", tlsaSelector); - DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQuery("tlsaMatchingType").Replace('-', '_'), true); - DnsTLSAMatchingType newTlsaMatchingType = Enum.Parse(request.GetQuery("newTlsaMatchingType", tlsaMatchingType.ToString()).Replace('-', '_'), true); + DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true); + DnsTLSAMatchingType newTlsaMatchingType = Enum.Parse(request.GetQueryOrForm("newTlsaMatchingType", tlsaMatchingType.ToString()).Replace('-', '_'), true); - string tlsaCertificateAssociationData = request.GetQuery("tlsaCertificateAssociationData"); - string newTlsaCertificateAssociationData = request.GetQuery("newTlsaCertificateAssociationData", tlsaCertificateAssociationData); + string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData"); + string newTlsaCertificateAssociationData = request.GetQueryOrForm("newTlsaCertificateAssociationData", tlsaCertificateAssociationData); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTLSARecordData(newTlsaCertificateUsage, newTlsaSelector, newTlsaMatchingType, newTlsaCertificateAssociationData)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.CAA: { - byte flags = request.GetQuery("flags", byte.Parse); - byte newFlags = request.GetQuery("newFlags", byte.Parse, flags); + byte flags = request.GetQueryOrForm("flags", byte.Parse); + byte newFlags = request.GetQueryOrForm("newFlags", byte.Parse, flags); - string tag = request.GetQuery("tag"); - string newTag = request.GetQuery("newTag", tag); + string tag = request.GetQueryOrForm("tag"); + string newTag = request.GetQueryOrForm("newTag", tag); - string value = request.GetQuery("value"); - string newValue = request.GetQuery("newValue", value); + string value = request.GetQueryOrForm("value"); + string newValue = request.GetQueryOrForm("newValue", value); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCAARecordData(flags, tag, value)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCAARecordData(newFlags, newTag, newValue)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.ANAME: { - string aname = request.GetQueryAlt("aname", "value").TrimEnd('.'); - string newAName = request.GetQueryAlt("newAName", "newValue", aname).TrimEnd('.'); + string aname = request.GetQueryOrFormAlt("aname", "value").TrimEnd('.'); + string newAName = request.GetQueryOrFormAlt("newAName", "newValue", aname).TrimEnd('.'); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsANAMERecordData(aname)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsANAMERecordData(newAName)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = request.GetQuery("protocol", DnsTransportProtocol.Udp); - DnsTransportProtocol newProtocol = request.GetQuery("newProtocol", protocol); + DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + DnsTransportProtocol newProtocol = request.GetQueryOrForm("newProtocol", protocol); - string forwarder = request.GetQueryAlt("forwarder", "value"); - string newForwarder = request.GetQueryAlt("newForwarder", "newValue", forwarder); + string forwarder = request.GetQueryOrFormAlt("forwarder", "value"); + string newForwarder = request.GetQueryOrFormAlt("newForwarder", "newValue", forwarder); - bool dnssecValidation = request.GetQuery("dnssecValidation", bool.Parse, false); + bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false); NetProxyType proxyType = NetProxyType.None; string proxyAddress = null; @@ -2706,45 +2754,56 @@ namespace DnsServerCore if (!newForwarder.Equals("this-server")) { - proxyType = request.GetQuery("proxyType", NetProxyType.None); + proxyType = request.GetQueryOrForm("proxyType", NetProxyType.None); if (proxyType != NetProxyType.None) { - proxyAddress = request.GetQuery("proxyAddress"); - proxyPort = request.GetQuery("proxyPort", ushort.Parse); - proxyUsername = request.Query["proxyUsername"]; - proxyPassword = request.Query["proxyPassword"]; + proxyAddress = request.GetQueryOrForm("proxyAddress"); + proxyPort = request.GetQueryOrForm("proxyPort", ushort.Parse); + proxyUsername = request.QueryOrForm("proxyUsername"); + proxyPassword = request.QueryOrForm("proxyPassword"); } } + switch (newProtocol) + { + case DnsTransportProtocol.HttpsJson: + newProtocol = DnsTransportProtocol.Https; + break; + + case DnsTransportProtocol.Quic: + DnsWebService.ValidateQuicSupport(); + break; + } + oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecordData(protocol, forwarder)); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecordData(newProtocol, newForwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; case DnsResourceRecordType.APP: { - string appName = request.GetQueryAlt("appName", "value"); - string classPath = request.GetQuery("classPath"); - string recordData = request.GetQuery("recordData", ""); + string appName = request.GetQueryOrFormAlt("appName", "value"); + string classPath = request.GetQueryOrForm("classPath"); + string recordData = request.GetQueryOrForm("recordData", ""); oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsApplicationRecordData(appName, classPath, recordData)); newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsApplicationRecordData(appName, classPath, recordData)); if (disable) - newRecord.Disable(); + newRecord.GetAuthRecordInfo().Disabled = true; if (!string.IsNullOrEmpty(comments)) - newRecord.SetComments(comments); + newRecord.GetAuthRecordInfo().Comments = comments; - _dnsWebService._dnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); + _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord); } break; @@ -2754,7 +2813,7 @@ namespace DnsServerCore _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Record was updated for authoritative zone {" + (oldRecord is null ? "" : "oldRecord: " + oldRecord.ToString() + "; ") + "newRecord: " + newRecord.ToString() + "}"); - _dnsWebService._dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); + _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); From 92c786da3f72872ae6e802a5425788d30a43b355 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:22:44 +0530 Subject: [PATCH 095/191] webapp: updated html to use html5 date input. Updated sortable table headers to be clickable. Added support for DNS-over-QUIC and XFR-over-QUIC. Updated settings section for new options. Updated DNSSEC properties to use menu instead of buttons for key items. --- DnsServerCore/www/index.html | 338 +++++++++++++++++++++++++---------- 1 file changed, 244 insertions(+), 94 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index b09fd8ae..68705b7d 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -15,12 +15,7 @@ - - - - - @@ -145,8 +140,8 @@ @@ -349,11 +344,11 @@ - - - - - + + + + + @@ -405,10 +400,10 @@
    ZoneTypeDNSSECStatusExpiryZoneTypeDNSSECStatusExpiry
    - - - - + + + + @@ -550,7 +545,7 @@
    NameTypeTTLDataNameTypeTTLData
    - + @@ -614,11 +609,29 @@
  • OpenDNS FamilyShield {208.67.220.123}
  • OpenDNS FamilyShield {[2620:119:35::123]}
  • OpenDNS FamilyShield {[2620:119:53::123]}
  • -
  • OpenDNS TLS {familyshield.opendns.com (208.67.222.123:853)}
  • -
  • OpenDNS TLS {familyshield.opendns.com (208.67.220.123:853)}
  • -
  • OpenDNS TLS {familyshield.opendns.com ([2620:119:35::123]:853)}
  • -
  • OpenDNS TLS {familyshield.opendns.com ([2620:119:53::123]:853)}
  • +
  • OpenDNS FamilyShield TLS {familyshield.opendns.com (208.67.222.123:853)}
  • +
  • OpenDNS FamilyShield TLS {familyshield.opendns.com (208.67.220.123:853)}
  • +
  • OpenDNS FamilyShield TLS {familyshield.opendns.com ([2620:119:35::123]:853)}
  • +
  • OpenDNS FamilyShield TLS {familyshield.opendns.com ([2620:119:53::123]:853)}
  • OpenDNS FamilyShield HTTPS {https://doh.familyshield.opendns.com/dns-query}
  • +
  • AdGuard {94.140.14.14}
  • +
  • AdGuard {94.140.15.15}
  • +
  • AdGuard {[2a10:50c0::ad1:ff]}
  • +
  • AdGuard {[2a10:50c0::ad2:ff]}
  • +
  • AdGuard TLS {dns.adguard-dns.com (94.140.14.14:853)}
  • +
  • AdGuard TLS {dns.adguard-dns.com ([2a10:50c0::ad1:ff]:853)}
  • +
  • AdGuard HTTPS {https://dns.adguard-dns.com/dns-query}
  • +
  • AdGuard QUIC {dns.adguard-dns.com (94.140.14.14:853)}
  • +
  • AdGuard QUIC {dns.adguard-dns.com ([2a10:50c0::ad1:ff]:853)}
  • +
  • AdGuard Family Protection {94.140.14.15}
  • +
  • AdGuard Family Protection {94.140.15.16}
  • +
  • AdGuard Family Protection {[2a10:50c0::bad1:ff]}
  • +
  • AdGuard Family Protection {[2a10:50c0::bad2:ff]}
  • +
  • AdGuard Family Protection TLS {dns.adguard-dns.com (94.140.14.15:853)}
  • +
  • AdGuard Family Protection TLS {dns.adguard-dns.com ([2a10:50c0::bad1:ff]:853)}
  • +
  • AdGuard Family Protection HTTPS {https://dns.adguard-dns.com/dns-query}
  • +
  • AdGuard Family Protection QUIC {dns.adguard-dns.com (94.140.14.15:853)}
  • +
  • AdGuard Family Protection QUIC {dns.adguard-dns.com ([2a10:50c0::bad1:ff]:853)}
  • Level3 {4.2.2.1}
  • Level3 {4.2.2.2}
  • Ultra {156.154.70.1}
  • @@ -683,6 +696,7 @@ + @@ -930,6 +944,33 @@
    The amount of time a TCP socket must wait for data before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports.
    + +
    + +
    + + milliseconds (valid range 1000-90000; default 60000) +
    +
    The time interval after which an idle QUIC connection will be closed. This option applies only to QUIC transport protocol.
    +
    + +
    + +
    + + (valid range 1-1000; default 100) +
    +
    The max number of inbound bidirectional streams that can be accepted per QUIC connection. This option applies only to QUIC transport protocol.
    +
    + +
    + +
    + + (default 100) +
    +
    The maximum number of pending connections. This option applies to TCP, TLS, and QUIC transport protocols.
    +
    @@ -940,13 +981,14 @@
    -
    Local addresses are the network interface IP addresses you want the web service to listen for requests. The default values work for most scenarios so, do not change these defaults unless you have a requirement for the web service to listen on specific networks.
    +
    Local addresses are the network interface IP addresses you want the web service to listen for requests. ANY addresses (0.0.0.0 & [::]) cannot be used together with unicast IP addresses. The default values work for most scenarios so, do not change these defaults unless you have a requirement for the web service to listen on specific networks.
    - + + (default 5380)
    Specify the TCP port number for this web console over HTTP protocol.
    @@ -977,7 +1019,8 @@
    - + + (default 53443)
    Specify the TCP port number for this web console over TLS protocol.
    @@ -1014,27 +1057,77 @@
    Enable this option to accept DNS-over-HTTP requests. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks.
    Enable this option to accept DNS-over-TLS requests.
    Enable this option to accept DNS-over-HTTPS requests.
    + +
    + +
    +
    Enable this option to allow automatic TLS certificate renewal with HTTP challenge (webroot) for DNS-over-HTTPS service. This service will not accept DNS-over-HTTP requests from public IP addresses.
    + +
    + +
    +
    Enable this option to accept DNS-over-QUIC requests.
    +
    + +
    + + (default 8053) +
    +
    Specify the TCP port number for DNS-over-HTTP protocol.
    +
    + +
    + +
    + + (default 853) +
    +
    Specify the TCP port number for DNS-over-TLS protocol.
    +
    + +
    + +
    + + (default 443) +
    +
    Specify the TCP port number for DNS-over-HTTPS protocol.
    +
    + +
    + +
    + + (default 853) +
    +
    Specify the UDP port number for DNS-over-QUIC protocol.
    +
    +
    @@ -1052,9 +1145,9 @@
    -

    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 and DNS-over-HTTPS protocols will be enabled only when a TLS certificate is configured.

    +

    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 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.

    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"
    @@ -1193,6 +1286,22 @@
    +
    +
    + +
    +
    + +
    +
    Enable this option to save DNS cache on disk when the DNS server stops. The saved cache will be loaded next time the DNS server starts.
    +
    +
    + +
    Note! The DNS server will attempt to save cache to disk when it stops which may take time depending on the cache size. This may cause the server to take a lot of time to stop which may lead to the OS to kill the process causing incomplete cache to be stored on disk.
    +
    +
    @@ -1561,6 +1670,26 @@ + + + + + + + + + + + + + + + + + + + +
    Enter forwarder DNS Server IP addresses or URLs one below another in above text field or use the Quick Select list to select desired forwarder.
    @@ -1594,6 +1723,12 @@ DNS-over-HTTPS
    +
    + +
    Select a protocol that this DNS server must use to query the forwarders specified above.
    @@ -1727,13 +1862,13 @@
    Installed AppsInstalled Apps
    - - - - - - - + + + + + + + @@ -1759,10 +1894,10 @@
    ScopeMAC AddressIP AddressHost NameLease ObtainedLease ExpiresScopeMAC AddressIP AddressHost NameLease ObtainedLease Expires
    - - - - + + + + @@ -2159,11 +2294,11 @@
    NameScope Range/Subnet MaskNetwork/BroadcastInterfaceNameScope Range/Subnet MaskNetwork/BroadcastInterface
    - - - - - + + + + + @@ -2189,11 +2324,11 @@
    UsernameSessionLast SeenRemote AddressUser AgentUsernameSessionLast SeenRemote AddressUser Agent
    - - - - - + + + + + @@ -2219,8 +2354,8 @@
    UsernameDisplay NameStatusPrevious LoginRecent LoginUsernameDisplay NameStatusRecent LoginPrevious Login
    - - + + @@ -2240,7 +2375,7 @@
    NameDescriptionNameDescription
    - + @@ -2335,27 +2470,17 @@
    -
    - - - - -
    +
    -
    - - - - -
    +
    - +
    @@ -2366,6 +2491,7 @@ +
    @@ -2400,12 +2526,12 @@
    - +
    - +
    @@ -2499,7 +2625,7 @@

    Technitium DNS Server

    Version

    - Copyright (C) 2022 Shreyas Zare (shreyas@technitium.com)
    + Copyright (C) 2023 Shreyas Zare (shreyas@technitium.com)
    This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions.

    Source code available under GNU General Public License v3.0 on  GitHub

    @@ -2583,7 +2709,7 @@
    SectionSection User Permissions Group Permissions
    - + @@ -2600,10 +2726,10 @@
    GroupGroup
    - - - - + + + + @@ -2878,6 +3004,12 @@ ns1.example.com ([2001:db8::]) XFR-over-TLS +
    + +
    @@ -2917,6 +3049,12 @@ ns1.example.com ([2001:db8::]) DNS-over-HTTPS +
    + +
    @@ -3183,6 +3321,12 @@ ns1.example.com ([2001:db8::]) XFR-over-TLS +
    + +
    @@ -3408,6 +3552,12 @@ MII... DNS-over-HTTPS +
    + +
    @@ -3983,13 +4133,13 @@ MII...
    SessionLast SeenRemote AddressUser AgentSessionLast SeenRemote AddressUser Agent
    - - - - - - - + + + + + + + @@ -4239,7 +4389,7 @@ MII...
    Key TagKey TypeAlgorithmStateState ChangedRolloverKey TagKey TypeAlgorithmStateState ChangedRollover (days)
    - + @@ -4776,10 +4926,10 @@ MII...
    Store AppsStore Apps
    - - - - + + + + @@ -4904,10 +5054,10 @@ MII...
    SessionLast SeenRemote AddressUser AgentSessionLast SeenRemote AddressUser Agent
    - - - - + + + + @@ -4926,10 +5076,10 @@ MII...
    UsernameViewModifyDeleteUsernameViewModifyDelete
    - - - - + + + + From 05516323cbf5360a979de9949e50820475c07d83 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:23:05 +0530 Subject: [PATCH 096/191] main.css: updated css for sortable table headers. --- DnsServerCore/www/css/main.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/DnsServerCore/www/css/main.css b/DnsServerCore/www/css/main.css index 0a1a7dd6..ddcfc970 100644 --- a/DnsServerCore/www/css/main.css +++ b/DnsServerCore/www/css/main.css @@ -16,6 +16,15 @@ a { color: #6699ff; } +th a { + color: black; +} + + th a:hover { + color: black; + text-decoration: none; + } + #header { background-color: #6699ff; height: 32px; From 9953023233a90d2e1c6cd8a10d869e9840f8415f Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:23:53 +0530 Subject: [PATCH 097/191] auth.js: minor ui changes. --- DnsServerCore/www/js/auth.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DnsServerCore/www/js/auth.js b/DnsServerCore/www/js/auth.js index b77c9b45..9320c567 100644 --- a/DnsServerCore/www/js/auth.js +++ b/DnsServerCore/www/js/auth.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 @@ -804,8 +804,8 @@ function getAdminUsersRowHtml(id, user) { var tableHtmlRows = "" + "" + "" - + "" - + ""; + tableHtmlRows += ""; + tableHtmlRows += ""; tableHtmlRows += ""; tableHtmlRows += ""; tableHtmlRows += ""; @@ -379,12 +403,54 @@ function refreshZones(checkDisplay) { tableHtmlRows += ""; } + var paginationHtml = ""; + + if (responseJSON.response.pageNumber > 1) { + paginationHtml += "
  • «
  • "; + paginationHtml += "
  • "; + } + + var pageStart = responseJSON.response.pageNumber - 5; + if (pageStart < 1) + pageStart = 1; + + var pageEnd = pageStart + 9; + if (pageEnd > responseJSON.response.totalPages) { + var endDiff = pageEnd - responseJSON.response.totalPages; + pageEnd = responseJSON.response.totalPages; + + pageStart -= endDiff; + if (pageStart < 1) + pageStart = 1; + } + + for (var i = pageStart; i <= pageEnd; i++) { + if (i == responseJSON.response.pageNumber) + paginationHtml += "
  • " + i + "
  • "; + else + paginationHtml += "
  • " + i + "
  • "; + } + + if (responseJSON.response.pageNumber < responseJSON.response.totalPages) { + paginationHtml += "
  • "; + paginationHtml += "
  • »
  • "; + } + + var statusHtml; + + if (responseJSON.response.zones.length > 0) + statusHtml = firstRowNumber + "-" + lastRowNumber + " (" + responseJSON.response.zones.length + ") of " + responseJSON.response.totalZones + " zones (page " + responseJSON.response.pageNumber + " of " + responseJSON.response.totalPages + ")"; + else + statusHtml = "0 zones"; + + $("#txtZonesPageNumber").val(responseJSON.response.pageNumber); $("#tableZonesBody").html(tableHtmlRows); - if (zones.length > 0) - $("#tableZonesFooter").html(""); - else - $("#tableZonesFooter").html(""); + $("#tableZonesTopStatus").html(statusHtml); + $("#tableZonesTopPagination").html(paginationHtml); + + $("#tableZonesFooterStatus").html(statusHtml); + $("#tableZonesFooterPagination").html(paginationHtml); divViewZonesLoader.hide(); divViewZones.show(); @@ -545,14 +611,7 @@ function deleteZoneMenu(objMenuItem) { HTTPRequest({ url: "/api/zones/delete?token=" + sessionData.token + "&zone=" + zone, success: function (responseJSON) { - $("#trZone" + id).remove(); - - var totalZones = $('#tableZones >tbody >tr').length; - - if (totalZones > 0) - $("#tableZonesFooter").html(""); - else - $("#tableZonesFooter").html(""); + refreshZones(); showAlert("success", "Zone Deleted!", "Zone '" + zone + "' was deleted successfully."); }, @@ -1236,6 +1295,15 @@ function toggleHideDnssecRecords(hideDnssecRecords) { } function showEditZone(zone) { + if (zone == null) { + zone = $("#txtZonesEdit").val(); + if (zone === "") { + showAlert("warning", "Missing!", "Please enter a zone name to start editing."); + $("#txtZonesEdit").focus(); + return; + } + } + var divViewZonesLoader = $("#divViewZonesLoader"); var divViewZones = $("#divViewZones"); var divEditZone = $("#divEditZone"); @@ -1247,6 +1315,8 @@ function showEditZone(zone) { HTTPRequest({ url: "/api/zones/records/get?token=" + sessionData.token + "&domain=" + zone + "&zone=" + zone + "&listZone=true", success: function (responseJSON) { + zone = responseJSON.response.zone.name; + var zoneType; if (responseJSON.response.zone.internal) zoneType = "Internal"; From c17b9b95310224b9f05b32bde396e32d0c5b675c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:37:12 +0530 Subject: [PATCH 152/191] updated apidocs. --- APIDOCS.md | 99 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 36 deletions(-) diff --git a/APIDOCS.md b/APIDOCS.md index 40e5c00b..575542f2 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -1544,7 +1544,7 @@ These API calls allow managing all hosted zones on the DNS server. List all authoritative zones hosted on this DNS server. The list contains only the zones that the user has View permissions for. These API calls requires permission for both the Zones section as well as the individual permission for each zone. URL:\ -`http://localhost:5380/api/zones/list?token=x` +`http://localhost:5380/api/zones/list?token=x&pageNumber=1&zonesPerPage=10` OBSOLETE PATH:\ `/api/zone/list`\ @@ -1556,11 +1556,16 @@ Zone: View WHERE: - `token`: The session token generated by the `login` or the `createToken` call. +- `pageNumber` (optional): When this parameter is specified, the API will return paginated results based on the page number and zones per pages options. When not specified, the API will return a list of all zones. +- `zonesPerPage` (optional): The number of zones per page to be returned. This option is only used when `pageNumber` options is specified. The default value is `10` when not specified. RESPONSE: ``` { "response": { + "pageNumber": 1, + "totalPages": 2, + "totalZones": 12, "zones": [ { "name": "", @@ -1613,6 +1618,30 @@ RESPONSE: "internal": true, "dnssecStatus": "Unsigned", "disabled": false + }, + { + "name": "test0.com", + "type": "Primary", + "internal": false, + "dnssecStatus": "Unsigned", + "notifyFailed": false, + "disabled": false + }, + { + "name": "test1.com", + "type": "Primary", + "internal": false, + "dnssecStatus": "Unsigned", + "notifyFailed": false, + "disabled": false + }, + { + "name": "test2.com", + "type": "Primary", + "internal": false, + "dnssecStatus": "Unsigned", + "notifyFailed": false, + "disabled": false } ] }, @@ -4122,7 +4151,6 @@ RESPONSE: "enableDnsOverHttp": true, "enableDnsOverTls": true, "enableDnsOverHttps": true, - "enableDnsOverHttpPort80": true, "enableDnsOverQuic": false, "dnsOverHttpPort": 8053, "dnsOverTlsPort": 853, @@ -4194,58 +4222,57 @@ WHERE: - `dnsServerLocalEndPoints` (optional): Local end points are the network interface IP addresses and ports you want the DNS Server to listen for requests. - `defaultRecordTtl` (optional): The default TTL value to use if not specified when adding or updating records in a Zone. - `dnsAppsEnableAutomaticUpdate` (optional): Set to `true` to allow DNS server to automatically update the DNS Apps from the DNS App Store. The DNS Server will check for updates every 24 hrs when this option is enabled. -- `preferIPv6` (optional): DNS Server will use IPv6 for querying whenever possible with this option enabled. Default value is `false`. -- `udpPayloadSize` (optional): The maximum EDNS UDP payload size that can be used to avoid IP fragmentation. Valid range is 512-4096 bytes. Default value is `1232`. +- `preferIPv6` (optional): DNS Server will use IPv6 for querying whenever possible with this option enabled. Initial value is `false`. +- `udpPayloadSize` (optional): The maximum EDNS UDP payload size that can be used to avoid IP fragmentation. Valid range is 512-4096 bytes. Initial value is `1232`. - `dnssecValidation` (optional): Set this to `true` to enable DNSSEC validation. DNS Server will validate all responses from name servers or forwarders when this option is enabled. - `eDnsClientSubnet` (optional): Set this to `true` to enable EDNS Client Subnet. DNS Server will use the public IP address of the request with a prefix length, or the existing Client Subnet option from the request while resolving requests. -- `eDnsClientSubnetIPv4PrefixLength` (optional): The EDNS Client Subnet IPv4 prefix length to define the client subnet. Default value is `24`. -- `eDnsClientSubnetIPv6PrefixLength` (optional): The EDNS Client Subnet IPv6 prefix length to define the client subnet. Default value is `56`. +- `eDnsClientSubnetIPv4PrefixLength` (optional): The EDNS Client Subnet IPv4 prefix length to define the client subnet. Initial value is `24`. +- `eDnsClientSubnetIPv6PrefixLength` (optional): The EDNS Client Subnet IPv6 prefix length to define the client subnet. Initial value is `56`. - `qpmLimitRequests` (optional): Sets the Queries Per Minute (QPM) limit on total number of requests that is enforces per client subnet. Set value to `0` to disable the feature. - `qpmLimitErrors` (optional): Sets the Queries Per Minute (QPM) limit on total number of requests which generates an error response that is enforces per client subnet. Set value to `0` to disable the feature. Response with an RCODE of FormatError, ServerFailure, or Refused is considered as an error response. -- `qpmLimitSampleMinutes` (optional): Sets the client query stats sample size in minutes for QPM limit feature. Default value is `5`. -- `qpmLimitIPv4PrefixLength` (optional): Sets the client subnet IPv4 prefix length used to define the subnet. Default value is `24`. -- `qpmLimitIPv6PrefixLength` (optional): Sets the client subnet IPv6 prefix length used to define the subnet. Default value is `56`. -- `clientTimeout` (optional): The amount of time the DNS server must wait in milliseconds before responding with a ServerFailure response to a client request when no answer is available. Valid range is `1000`-`10000`. Default value is `4000`. -- `tcpSendTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for an ACK before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. Valid range is `1000`-`90000`. Default value is `10000`. -- `tcpReceiveTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for data before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. Valid range is `1000`-`90000`. Default value is `10000`. -- `quicIdleTimeout` (optional): The time interval in milliseconds after which an idle QUIC connection will be closed. This option applies only to QUIC transport protocol. Valid range is `1000`-`90000`. Default value is `60000`. -- `quicMaxInboundStreams` (optional): The max number of inbound bidirectional streams that can be accepted per QUIC connection. This option applies only to QUIC transport protocol. Valid range is `1`-`1000`. Default value is `100`. -- `listenBacklog` (optional): The maximum number of pending connections. This option applies to TCP, TLS, and QUIC transport protocols. Default value is `100`. +- `qpmLimitSampleMinutes` (optional): Sets the client query stats sample size in minutes for QPM limit feature. Initial value is `5`. +- `qpmLimitIPv4PrefixLength` (optional): Sets the client subnet IPv4 prefix length used to define the subnet. Initial value is `24`. +- `qpmLimitIPv6PrefixLength` (optional): Sets the client subnet IPv6 prefix length used to define the subnet. Initial value is `56`. +- `clientTimeout` (optional): The amount of time the DNS server must wait in milliseconds before responding with a ServerFailure response to a client request when no answer is available. Valid range is `1000`-`10000`. Initial value is `4000`. +- `tcpSendTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for an ACK before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. Valid range is `1000`-`90000`. Initial value is `10000`. +- `tcpReceiveTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for data before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. Valid range is `1000`-`90000`. Initial value is `10000`. +- `quicIdleTimeout` (optional): The time interval in milliseconds after which an idle QUIC connection will be closed. This option applies only to QUIC transport protocol. Valid range is `1000`-`90000`. Initial value is `60000`. +- `quicMaxInboundStreams` (optional): The max number of inbound bidirectional streams that can be accepted per QUIC connection. This option applies only to QUIC transport protocol. Valid range is `1`-`1000`. Initial value is `100`. +- `listenBacklog` (optional): The maximum number of pending connections. This option applies to TCP, TLS, and QUIC transport protocols. Initial value is `100`. - `webServiceLocalAddresses` (optional): Local addresses are the network interface IP addresses you want the web service to listen for requests. -- `webServiceHttpPort` (optional): Specify the TCP port number for the web console and this API web service. Default value is `5380`. +- `webServiceHttpPort` (optional): Specify the TCP port number for the web console and this API web service. Initial value is `5380`. - `webServiceEnableTls` (optional): Set this to `true` to start the HTTPS service to access web service. - `webServiceTlsPort` (optional): Specified the TCP port number for the web console for HTTPS access. - `webServiceUseSelfSignedTlsCertificate` (optional): Set `true` for the web service to use an automatically generated self signed certificate when TLS certificate path is not specified. - `webServiceTlsCertificatePath` (optional): Specify a PKCS #12 certificate (.pfx) file path on the server. The certificate must contain private key. This certificate is used by the web console for HTTPS access. - `webServiceTlsCertificatePassword` (optional): Enter the certificate (.pfx) password, if any. -- `enableDnsOverHttp` (optional): Enable this option to accept DNS-over-HTTP requests. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks. +- `enableDnsOverHttp` (optional): Enable this option to accept DNS-over-HTTP requests. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks. Enabling this option also allows automatic TLS certificate renewal with HTTP challenge (webroot) for DNS-over-HTTPS service. - `enableDnsOverTls` (optional): Enable this option to accept DNS-over-TLS requests. - `enableDnsOverHttps` (optional): Enable this option to accept DNS-over-HTTPS requests. -- `enableDnsOverHttpPort80` (optional): Enable this option to allow automatic TLS certificate renewal with HTTP challenge (webroot) for DNS-over-HTTPS service. This service will not accept DNS-over-HTTP requests from public IP addresses. - `enableDnsOverQuic` (optional): Enable this option to accept DNS-over-QUIC requests. -- `dnsOverHttpPort` (optional): The TCP port number for DNS-over-HTTP protocol. Default value is `8053`. -- `dnsOverTlsPort` (optional): The TCP port number for DNS-over-TLS protocol. Default value is `853`. -- `dnsOverHttpsPort` (optional): The TCP port number for DNS-over-HTTPS protocol. Default value is `443`. -- `dnsOverQuicPort` (optional): The UDP port number for DNS-over-QUIC protocol. Default value is `853`. +- `dnsOverHttpPort` (optional): The TCP port number for DNS-over-HTTP protocol. Initial value is `80`. +- `dnsOverTlsPort` (optional): The TCP port number for DNS-over-TLS protocol. Initial value is `853`. +- `dnsOverHttpsPort` (optional): The TCP port number for DNS-over-HTTPS protocol. Initial value is `443`. +- `dnsOverQuicPort` (optional): The UDP port number for DNS-over-QUIC protocol. Initial value is `853`. - `dnsTlsCertificatePath` (optional): Specify a PKCS #12 certificate (.pfx) file path on the server. The certificate must contain private key. This certificate is used by the DNS-over-TLS and DNS-over-HTTPS optional protocols. - `dnsTlsCertificatePassword` (optional): Enter the certificate (.pfx) password, if any. - `tsigKeys` (optional): A pipe `|` separated multi row list of TSIG key name, shared secret, and algorithm. Set this parameter to `false` to remove all existing keys. Supported algorithms are [`hmac-md5.sig-alg.reg.int`, `hmac-sha1`, `hmac-sha256`, `hmac-sha256-128`, `hmac-sha384`, `hmac-sha384-192`, `hmac-sha512`, `hmac-sha512-256`]. - `recursion` (optional): Sets the recursion policy for the DNS server. Valid values are [`Deny`, `Allow`, `AllowOnlyForPrivateNetworks`, `UseSpecifiedNetworks`]. - `recursionDeniedNetworks` (optional): A comma separated list of network addresses in CIDR format that must be denied recursion. Set this parameter to `false` to remove existing values. These values are only used when `recursion` is set to `UseSpecifiedNetworks`. - `recursionAllowedNetworks` (optional): A comma separated list of network addresses in CIDR format that must be allowed recursion. Set this parameter to `false` to remove existing values. These values are only used when `recursion` is set to `UseSpecifiedNetworks`. -- `randomizeName` (optional): Enables QNAME randomization [draft-vixie-dnsext-dns0x20-00](https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00) when using UDP as the transport protocol. Default value is `true`. -- `qnameMinimization` (optional): Enables QNAME minimization [draft-ietf-dnsop-rfc7816bis-04](https://tools.ietf.org/html/draft-ietf-dnsop-rfc7816bis-04) when doing recursive resolution. Default value is `true`. -- `nsRevalidation` (optional): Enables [draft-ietf-dnsop-ns-revalidation](https://datatracker.ietf.org/doc/draft-ietf-dnsop-ns-revalidation/) for recursive resolution. Default value is `true`. +- `randomizeName` (optional): Enables QNAME randomization [draft-vixie-dnsext-dns0x20-00](https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00) when using UDP as the transport protocol. Initial value is `true`. +- `qnameMinimization` (optional): Enables QNAME minimization [draft-ietf-dnsop-rfc7816bis-04](https://tools.ietf.org/html/draft-ietf-dnsop-rfc7816bis-04) when doing recursive resolution. Initial value is `true`. +- `nsRevalidation` (optional): Enables [draft-ietf-dnsop-ns-revalidation](https://datatracker.ietf.org/doc/draft-ietf-dnsop-ns-revalidation/) for recursive resolution. Initial value is `true`. - `resolverRetries` (optional): The number of retries that the recursive resolver must do. - `resolverTimeout` (optional): The timeout value in milliseconds for the recursive resolver. - `resolverMaxStackCount` (optional): The max stack count that the recursive resolver must use. - `saveCache` (optional): Enable this option to save DNS cache on disk when the DNS server stops. The saved cache will be loaded next time the DNS server starts. -- `serveStale` (optional): Enable the serve stale feature to improve resiliency by using expired or stale records in cache when the DNS server is unable to reach the upstream or authoritative name servers. Default value is `true`. -- `serveStaleTtl` (optional): The TTL value in seconds which should be used for cached records that are expired. When the serve stale TTL too expires for a stale record, it gets removed from the cache. Recommended value is between 1-3 days and maximum supported value is 7 days. Default value is `259200`. -- `cacheMinimumRecordTtl` (optional): The minimum TTL value that a record can have in cache. Set a value to make sure that the records with TTL value than it stays in cache for a minimum duration. Default value is `10`. -- `cacheMaximumRecordTtl` (optional): The maximum TTL value that a record can have in cache. Set a lower value to allow the records to expire early. Default value is `86400`. -- `cacheNegativeRecordTtl` (optional): The negative TTL value to use when there is no SOA MINIMUM value available. Default value is `300`. -- `cacheFailureRecordTtl` (optional): The failure TTL value to used for caching failure responses. This allows storing failure record in cache and prevent frequent recursive resolution to name servers that are responding with `ServerFailure`. Default value is `60`. +- `serveStale` (optional): Enable the serve stale feature to improve resiliency by using expired or stale records in cache when the DNS server is unable to reach the upstream or authoritative name servers. Initial value is `true`. +- `serveStaleTtl` (optional): The TTL value in seconds which should be used for cached records that are expired. When the serve stale TTL too expires for a stale record, it gets removed from the cache. Recommended value is between 1-3 days and maximum supported value is 7 days. Initial value is `259200`. +- `cacheMinimumRecordTtl` (optional): The minimum TTL value that a record can have in cache. Set a value to make sure that the records with TTL value than it stays in cache for a minimum duration. Initial value is `10`. +- `cacheMaximumRecordTtl` (optional): The maximum TTL value that a record can have in cache. Set a lower value to allow the records to expire early. Initial value is `86400`. +- `cacheNegativeRecordTtl` (optional): The negative TTL value to use when there is no SOA MINIMUM value available. Initial value is `300`. +- `cacheFailureRecordTtl` (optional): The failure TTL value to used for caching failure responses. This allows storing failure record in cache and prevent frequent recursive resolution to name servers that are responding with `ServerFailure`. Initial value is `60`. - `cachePrefetchEligibility` (optional): The minimum initial TTL value of a record needed to be eligible for prefetching. - `cachePrefetchTrigger` (optional): A record with TTL value less than trigger value will initiate prefetch operation immediately for itself. Set `0` to disable prefetching & auto prefetching. - `cachePrefetchSampleIntervalInMinutes` (optional): The interval to sample eligible domain names from last hour stats for auto prefetch. @@ -4255,7 +4282,7 @@ WHERE: - `blockingType` (optional): Sets how the DNS server should respond to a blocked domain request. Valid values are [`AnyAddress`, `NxDomain`, `CustomAddress`] where `AnyAddress` is default which response with `0.0.0.0` and `::` IP addresses for blocked domains. Using `NxDomain` will respond with `NX Domain` response. `CustomAddress` will return the specified custom blocking addresses. - `customBlockingAddresses` (optional): Set the custom blocking addresses to be used for blocked domain response. These addresses are returned only when `blockingType` is set to `CustomAddress`. - `blockListUrls` (optional): A comma separated list of block list URLs that this server must automatically download and use with the block lists zone. DNS Server will use the data returned by the block list URLs to update the block list zone automatically every 24 hours. The expected file format is standard hosts file format or plain text file containing list of domains to block. Set this parameter to `false` to remove existing values. -- `blockListUpdateIntervalHours` (optional): The interval in hours to automatically download and update the block lists. Default value is `24`. +- `blockListUpdateIntervalHours` (optional): The interval in hours to automatically download and update the block lists. Initial value is `24`. - `proxyType` (optional): The type of proxy protocol to be used. Valid values are [`None`, `Http`, `Socks5`]. - `proxyAddress` (optional): The proxy server hostname or IP address. - `proxyPort` (optional): The proxy server port. @@ -4267,10 +4294,10 @@ WHERE: - `forwarderRetries` (optional): The number of retries that the forwarder DNS client must do. - `forwarderTimeout` (optional): The timeout value in milliseconds for the forwarder DNS client. - `forwarderConcurrency` (optional): The number of concurrent requests that the forwarder DNS client should do. -- `enableLogging` (optional): Enable this option to log error and audit logs into the log file. Default value is `true`. -- `logQueries` (optional): Enable this option to log every query received by this DNS Server and the corresponding response answers into the log file. Default value is `false`. -- `useLocalTime` (optional): Enable this option to use local time instead of UTC for logging. Default value is `false`. -- `logFolder` (optional): The folder path on the server where the log files should be saved. The path can be relative to the DNS server config folder. Default value is `logs`. +- `enableLogging` (optional): Enable this option to log error and audit logs into the log file. Initial value is `true`. +- `logQueries` (optional): Enable this option to log every query received by this DNS Server and the corresponding response answers into the log file. Initial value is `false`. +- `useLocalTime` (optional): Enable this option to use local time instead of UTC for logging. Initial value is `false`. +- `logFolder` (optional): The folder path on the server where the log files should be saved. The path can be relative to the DNS server config folder. Initial value is `logs`. - `maxLogFileDays` (optional): Max number of days to keep the log files. Log files older than the specified number of days will be deleted automatically. Recommended value is `365`. Set `0` to disable auto delete. - `maxStatFileDays` (optional): Max number of days to keep the dashboard stats. Stat files older than the specified number of days will be deleted automatically. Recommended value is `365`. Set `0` to disable auto delete. From c29ba412d7ebae1a56fa03e835318f7eeabbcafc Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:24:19 +0530 Subject: [PATCH 153/191] AdvancedBlocking: updated ProcessRequestAsync() to use the new DirectQueryAsync() method and setting the missing response type flag. Fixed bug in ReadAdblockListFile() that added exception domain names to blocked instead of allowed list. Other minor changes. --- Apps/AdvancedBlockingApp/App.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Apps/AdvancedBlockingApp/App.cs b/Apps/AdvancedBlockingApp/App.cs index f3e0d382..a15781cb 100644 --- a/Apps/AdvancedBlockingApp/App.cs +++ b/Apps/AdvancedBlockingApp/App.cs @@ -446,8 +446,11 @@ namespace AdvancedBlocking { if (allowed) { - DnsDatagram internalResponse = await _dnsServer.DirectQueryAsync(question); - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, internalResponse.AuthoritativeAnswer, internalResponse.Truncation, request.RecursionDesired, internalResponse.RecursionAvailable, internalResponse.AuthenticData, internalResponse.CheckingDisabled, internalResponse.RCODE, request.Question, internalResponse.Answer, internalResponse.Authority, internalResponse.Additional) { Tag = internalResponse.Tag }; + DnsDatagram internalResponse = await _dnsServer.DirectQueryAsync(request); + if (internalResponse.Tag is null) + internalResponse.Tag = DnsServerResponseType.Recursive; + + return internalResponse; } return null; @@ -1222,6 +1225,7 @@ namespace AdvancedBlocking { //parse hosts file and populate block zone StreamReader sR = new StreamReader(fS, true); + char[] trimSeperator = new char[] { ' ', '\t' }; string line; while (true) @@ -1230,7 +1234,7 @@ namespace AdvancedBlocking if (line == null) break; //eof - line = line.TrimStart(' ', '\t'); + line = line.TrimStart(trimSeperator); if (line.Length == 0) continue; //skip empty line @@ -1320,6 +1324,7 @@ namespace AdvancedBlocking { //parse hosts file and populate block zone StreamReader sR = new StreamReader(fS, true); + char[] trimSeperator = new char[] { ' ', '\t' }; string line; while (true) @@ -1328,7 +1333,7 @@ namespace AdvancedBlocking if (line == null) break; //eof - line = line.TrimStart(' ', '\t'); + line = line.TrimStart(trimSeperator); if (line.Length == 0) continue; //skip empty line @@ -1364,7 +1369,7 @@ namespace AdvancedBlocking string options = line.Substring(i + 1); if (((options.Length == 0) || (options.StartsWith("$") && (options.Contains("doc") || options.Contains("all")))) && DnsClient.IsDomainNameValid(domain)) - blockedDomains.Enqueue(domain); + allowedDomains.Enqueue(domain); } else { From a727969c751634e88d9e421aa50d0abd9f486465 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:25:27 +0530 Subject: [PATCH 154/191] AdvancedBlockingApp: updated default config to enable NX blocking method since it works better in combination with Extended DNS Errors. --- Apps/AdvancedBlockingApp/dnsApp.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/AdvancedBlockingApp/dnsApp.config b/Apps/AdvancedBlockingApp/dnsApp.config index 38d2c922..410be64e 100644 --- a/Apps/AdvancedBlockingApp/dnsApp.config +++ b/Apps/AdvancedBlockingApp/dnsApp.config @@ -10,7 +10,7 @@ "name": "everyone", "enableBlocking": true, "allowTxtBlockingReport": true, - "blockAsNxDomain": false, + "blockAsNxDomain": true, "blockingAddresses": [ "0.0.0.0", "::" @@ -35,7 +35,7 @@ "name": "kids", "enableBlocking": true, "allowTxtBlockingReport": true, - "blockAsNxDomain": false, + "blockAsNxDomain": true, "blockingAddresses": [ "0.0.0.0", "::" From 7e89f3a50724b8f6326b2dec59532ce7834f7487 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:25:53 +0530 Subject: [PATCH 155/191] Dns64: minor changes. --- Apps/Dns64App/App.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/Dns64App/App.cs b/Apps/Dns64App/App.cs index cda85da5..8d2b0dae 100644 --- a/Apps/Dns64App/App.cs +++ b/Apps/Dns64App/App.cs @@ -148,7 +148,7 @@ namespace Dns64 if (!synthesizeAAAA) return new DnsDatagram(response.Identifier, true, response.OPCODE, response.AuthoritativeAnswer, response.Truncation, response.RecursionDesired, response.RecursionAvailable, response.AuthenticData, response.CheckingDisabled, response.RCODE, response.Question, newAnswer, response.Authority, response.Additional) { Tag = response.Tag }; - DnsDatagram newResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(question.Name, DnsResourceRecordType.A, question.Class), 2000); + DnsDatagram newResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(question.Name, DnsResourceRecordType.A, DnsClass.IN), 2000); uint soaTtl; { From b496f835c34a96317156aa17944e046ff5ff2d46 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:26:42 +0530 Subject: [PATCH 156/191] DnsBlockList: setting correct value for RA flag. --- Apps/DnsBlockListApp/App.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Apps/DnsBlockListApp/App.cs b/Apps/DnsBlockListApp/App.cs index 956aeaf6..d1d13e55 100644 --- a/Apps/DnsBlockListApp/App.cs +++ b/Apps/DnsBlockListApp/App.cs @@ -242,11 +242,11 @@ namespace DnsBlockList switch (question.Type) { case DnsResourceRecordType.A: - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.A, question.Class, appRecordTtl, new DnsARecordData(responseA)) }); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.A, question.Class, appRecordTtl, new DnsARecordData(responseA)) }); case DnsResourceRecordType.TXT: if (!string.IsNullOrEmpty(responseTXT)) - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.TXT, question.Class, appRecordTtl, new DnsTXTRecordData(responseTXT)) }); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.TXT, question.Class, appRecordTtl, new DnsTXTRecordData(responseTXT)) }); break; } @@ -254,7 +254,7 @@ namespace DnsBlockList //NODATA response DnsDatagram soaResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(zoneName, DnsResourceRecordType.SOA, DnsClass.IN)); - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, soaResponse.Answer); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, soaResponse.Answer); } } From c84ce72dec198ed9bd0659bcf870b512d52cebd3 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:27:22 +0530 Subject: [PATCH 157/191] Failover: setting correct RA flag value. --- Apps/FailoverApp/Address.cs | 4 ++-- Apps/FailoverApp/CNAME.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Apps/FailoverApp/Address.cs b/Apps/FailoverApp/Address.cs index cf60fd9e..38d873cb 100644 --- a/Apps/FailoverApp/Address.cs +++ b/Apps/FailoverApp/Address.cs @@ -218,7 +218,7 @@ namespace Failover if (answers.Count > 1) answers.Shuffle(); - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers)); } case DnsResourceRecordType.TXT: @@ -257,7 +257,7 @@ namespace Failover if (jsonAppRecordData.TryGetProperty("secondary", out JsonElement jsonSecondary)) GetStatusAnswers(jsonSecondary, FailoverType.Secondary, question, 30, healthCheck, healthCheckUrl, answers); - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers)); } default: diff --git a/Apps/FailoverApp/CNAME.cs b/Apps/FailoverApp/CNAME.cs index 785b7e43..c00dff30 100644 --- a/Apps/FailoverApp/CNAME.cs +++ b/Apps/FailoverApp/CNAME.cs @@ -195,7 +195,7 @@ namespace Failover } } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers)); } #endregion From bead5d88cf0defc4b9fd25fe9255f0eed7844eee Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:28:38 +0530 Subject: [PATCH 158/191] GeoCountry: setting correct RA flag value. --- Apps/GeoCountryApp/Address.cs | 4 ++-- Apps/GeoCountryApp/CNAME.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Apps/GeoCountryApp/Address.cs b/Apps/GeoCountryApp/Address.cs index 6c5d9c3a..c1990b95 100644 --- a/Apps/GeoCountryApp/Address.cs +++ b/Apps/GeoCountryApp/Address.cs @@ -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 @@ -160,7 +160,7 @@ namespace GeoCountry options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } default: diff --git a/Apps/GeoCountryApp/CNAME.cs b/Apps/GeoCountryApp/CNAME.cs index 46440915..4c2cc371 100644 --- a/Apps/GeoCountryApp/CNAME.cs +++ b/Apps/GeoCountryApp/CNAME.cs @@ -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 @@ -133,7 +133,7 @@ namespace GeoCountry options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } #endregion From a19a80bede65db326ad72721593ffef67ce577dd Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:30:55 +0530 Subject: [PATCH 159/191] GeoContinent: setting correct RA flag value. --- Apps/GeoContinentApp/Address.cs | 4 ++-- Apps/GeoContinentApp/CNAME.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Apps/GeoContinentApp/Address.cs b/Apps/GeoContinentApp/Address.cs index 8cf4f2bd..38ed82d2 100644 --- a/Apps/GeoContinentApp/Address.cs +++ b/Apps/GeoContinentApp/Address.cs @@ -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 @@ -160,7 +160,7 @@ namespace GeoContinent options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } default: diff --git a/Apps/GeoContinentApp/CNAME.cs b/Apps/GeoContinentApp/CNAME.cs index da471dcb..b0dbfb6a 100644 --- a/Apps/GeoContinentApp/CNAME.cs +++ b/Apps/GeoContinentApp/CNAME.cs @@ -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 @@ -133,7 +133,7 @@ namespace GeoContinent options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } #endregion From 2bf17df6bf747dba99d58f62a88f223410fd15b6 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:31:41 +0530 Subject: [PATCH 160/191] GeoDistance: setting correct RA flag value. --- Apps/GeoDistanceApp/Address.cs | 4 ++-- Apps/GeoDistanceApp/CNAME.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Apps/GeoDistanceApp/Address.cs b/Apps/GeoDistanceApp/Address.cs index 93793773..be6ebaca 100644 --- a/Apps/GeoDistanceApp/Address.cs +++ b/Apps/GeoDistanceApp/Address.cs @@ -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 @@ -192,7 +192,7 @@ namespace GeoDistance options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } default: diff --git a/Apps/GeoDistanceApp/CNAME.cs b/Apps/GeoDistanceApp/CNAME.cs index ceaeb612..70b78013 100644 --- a/Apps/GeoDistanceApp/CNAME.cs +++ b/Apps/GeoDistanceApp/CNAME.cs @@ -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 @@ -165,7 +165,7 @@ namespace GeoDistance options = EDnsClientSubnetOptionData.GetEDnsClientSubnetOption(requestECS.SourcePrefixLength, 0, requestECS.Address); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options)); } #endregion From 50c5999e272757678e81101e5977d54b36a8101c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:32:18 +0530 Subject: [PATCH 161/191] NoData: setting correct RA flag value. --- Apps/NoDataApp/App.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/NoDataApp/App.cs b/Apps/NoDataApp/App.cs index 0f9e294d..7c907473 100644 --- a/Apps/NoDataApp/App.cs +++ b/Apps/NoDataApp/App.cs @@ -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 @@ -59,7 +59,7 @@ namespace NoData { DnsResourceRecordType blockedType = Enum.Parse(jsonBlockedType.GetString(), true); if ((blockedType == question.Type) || (blockedType == DnsResourceRecordType.ANY)) - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question)); } } From 9daaed04dc06a349b855f51d40e99b3cccbbd703 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:32:54 +0530 Subject: [PATCH 162/191] NxDomain: setting correct RA flag value. --- Apps/NxDomainApp/App.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Apps/NxDomainApp/App.cs b/Apps/NxDomainApp/App.cs index 2b6af49f..86d8f64b 100644 --- a/Apps/NxDomainApp/App.cs +++ b/Apps/NxDomainApp/App.cs @@ -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 @@ -117,7 +117,7 @@ namespace NxDomain //return meta data DnsResourceRecord[] answer = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData("source=nx-domain-app; domain=" + blockedDomain)) }; - return Task.FromResult(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answer) { Tag = DnsServerResponseType.Blocked }); + return Task.FromResult(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answer) { Tag = DnsServerResponseType.Blocked }); } else { @@ -127,7 +127,7 @@ namespace NxDomain IReadOnlyList authority = new DnsResourceRecord[] { new DnsResourceRecord(parentDomain, DnsResourceRecordType.SOA, question.Class, 60, _soaRecord) }; - return Task.FromResult(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NxDomain, request.Question, null, authority) { Tag = DnsServerResponseType.Blocked }); + return Task.FromResult(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NxDomain, request.Question, null, authority) { Tag = DnsServerResponseType.Blocked }); } } From adee4265b22f5df694027593b35e0298a5fa3ca9 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:33:30 +0530 Subject: [PATCH 163/191] QueryLogsSqlite: minor refactoring changes. --- Apps/QueryLogsSqliteApp/App.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Apps/QueryLogsSqliteApp/App.cs b/Apps/QueryLogsSqliteApp/App.cs index bb55fdc0..dab8ddcd 100644 --- a/Apps/QueryLogsSqliteApp/App.cs +++ b/Apps/QueryLogsSqliteApp/App.cs @@ -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 @@ -394,9 +394,7 @@ CREATE TABLE IF NOT EXISTS dns_logs public Task QueryLogsAsync(long pageNumber, int entriesPerPage, bool descendingOrder, DateTime? start, DateTime? end, IPAddress clientIpAddress, DnsTransportProtocol? protocol, DnsServerResponseType? responseType, DnsResponseCode? rcode, string qname, DnsResourceRecordType? qtype, DnsClass? qclass) { - if (pageNumber < 0) - pageNumber = long.MaxValue; - else if (pageNumber == 0) + if (pageNumber == 0) pageNumber = 1; if (qname is not null) @@ -487,7 +485,7 @@ CREATE TABLE IF NOT EXISTS dns_logs long totalPages = (totalEntries / entriesPerPage) + (totalEntries % entriesPerPage > 0 ? 1 : 0); - if (pageNumber > totalPages) + if ((pageNumber > totalPages) || (pageNumber < 0)) pageNumber = totalPages; long endRowNum; From a27e38ee48ac7c9122e1ac48ea0cfbdc7b29d3a4 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:34:09 +0530 Subject: [PATCH 164/191] SplitHorizon: setting correct RA flag value. --- Apps/SplitHorizonApp/SimpleAddress.cs | 4 ++-- Apps/SplitHorizonApp/SimpleCNAME.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Apps/SplitHorizonApp/SimpleAddress.cs b/Apps/SplitHorizonApp/SimpleAddress.cs index c0257459..11c84f44 100644 --- a/Apps/SplitHorizonApp/SimpleAddress.cs +++ b/Apps/SplitHorizonApp/SimpleAddress.cs @@ -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 @@ -222,7 +222,7 @@ namespace SplitHorizon if (answers.Count > 1) answers.Shuffle(); - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers)); } default: diff --git a/Apps/SplitHorizonApp/SimpleCNAME.cs b/Apps/SplitHorizonApp/SimpleCNAME.cs index 0ce8cb6e..46d1d4fe 100644 --- a/Apps/SplitHorizonApp/SimpleCNAME.cs +++ b/Apps/SplitHorizonApp/SimpleCNAME.cs @@ -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 @@ -113,7 +113,7 @@ namespace SplitHorizon else answers = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.CNAME, DnsClass.IN, appRecordTtl, new DnsCNAMERecordData(cname)) }; - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers)); } #endregion From d6c0c3979922e81e4d92bbb2419720fd2457e715 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:34:58 +0530 Subject: [PATCH 165/191] WhatIsMyDns: setting correct RA flag value. --- Apps/WhatIsMyDnsApp/App.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/WhatIsMyDnsApp/App.cs b/Apps/WhatIsMyDnsApp/App.cs index ba4f9b23..3b0c02aa 100644 --- a/Apps/WhatIsMyDnsApp/App.cs +++ b/Apps/WhatIsMyDnsApp/App.cs @@ -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 @@ -73,7 +73,7 @@ namespace WhatIsMyDns return Task.FromResult(null); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { answer })); + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { answer })); } #endregion From bc63754a55ecf33f0aa2373bdd9dd18a7a394c5a Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:35:31 +0530 Subject: [PATCH 166/191] WildIp: setting correct RA flag value. --- Apps/WildIpApp/App.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/WildIpApp/App.cs b/Apps/WildIpApp/App.cs index 2c637fd4..900c8c1d 100644 --- a/Apps/WildIpApp/App.cs +++ b/Apps/WildIpApp/App.cs @@ -104,10 +104,10 @@ namespace WildIp //NODATA reponse DnsDatagram soaResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(zoneName, DnsResourceRecordType.SOA, DnsClass.IN)); - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, soaResponse.Answer); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, soaResponse.Answer); } - return new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { answer }); + return new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { answer }); } #endregion From 7da491c4b3eecdf9c54c5706e049057025d661f7 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:37:23 +0530 Subject: [PATCH 167/191] DnsServerInternal: implemented new DirectQueryAsync() method. --- DnsServerCore/Dns/Applications/DnsServerInternal.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/DnsServerCore/Dns/Applications/DnsServerInternal.cs b/DnsServerCore/Dns/Applications/DnsServerInternal.cs index e00783a8..836f3f66 100644 --- a/DnsServerCore/Dns/Applications/DnsServerInternal.cs +++ b/DnsServerCore/Dns/Applications/DnsServerInternal.cs @@ -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 @@ -53,6 +53,11 @@ namespace DnsServerCore.Dns.Applications return _dnsServer.DirectQueryAsync(question, timeout, true); } + public Task DirectQueryAsync(DnsDatagram request, int timeout = 4000) + { + return _dnsServer.DirectQueryAsync(request, timeout, true); + } + public void WriteLog(string message) { LogManager log = _dnsServer.LogManager; From 43bc42d00065d657ebd30ab30c43cdb95d8be007 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:37:50 +0530 Subject: [PATCH 168/191] minor changes --- DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs | 2 +- DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs index 9e9656fb..34eff79d 100644 --- a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs @@ -178,7 +178,7 @@ namespace DnsServerCore.Dns.ZoneManagers public DnsDatagram Query(DnsDatagram request) { - return _zoneManager.Query(request, true); + return _zoneManager.Query(request); } #endregion diff --git a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs index 8214001e..3f6f4695 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs @@ -196,7 +196,7 @@ namespace DnsServerCore.Dns.ZoneManagers public DnsDatagram Query(DnsDatagram request) { - return _zoneManager.Query(request, true); + return _zoneManager.Query(request); } #endregion From 6338ee25b931db30689895b057e7b9fc875f30e6 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:39:08 +0530 Subject: [PATCH 169/191] AuthZoneManager: setting correct RA flag. Code refactoring done. --- .../Dns/ZoneManagers/AuthZoneManager.cs | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs index c444975f..33c0f47b 100644 --- a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs @@ -369,7 +369,7 @@ namespace DnsServerCore.Dns.ZoneManagers } } - private DnsDatagram GetReferralResponse(DnsDatagram request, bool dnssecOk, AuthZone delegationZone, ApexZone apexZone, bool isRecursionAllowed) + private DnsDatagram GetReferralResponse(DnsDatagram request, bool dnssecOk, AuthZone delegationZone, ApexZone apexZone) { IReadOnlyList authority; @@ -424,17 +424,17 @@ namespace DnsServerCore.Dns.ZoneManagers IReadOnlyList additional = GetAdditionalRecords(authority, dnssecOk); - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, authority, additional); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, authority, additional); } - private DnsDatagram GetForwarderResponse(DnsDatagram request, AuthZone zone, AuthZone closestZone, ApexZone forwarderZone, bool isRecursionAllowed) + private DnsDatagram GetForwarderResponse(DnsDatagram request, AuthZone zone, AuthZone closestZone, ApexZone forwarderZone) { IReadOnlyList authority = null; if (zone is not null) { if (zone.ContainsNameServerRecords()) - return GetReferralResponse(request, false, zone, forwarderZone, isRecursionAllowed); + return GetReferralResponse(request, false, zone, forwarderZone); authority = zone.QueryRecords(DnsResourceRecordType.FWD, false); } @@ -442,7 +442,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (((authority is null) || (authority.Count == 0)) && (closestZone is not null)) { if (closestZone.ContainsNameServerRecords()) - return GetReferralResponse(request, false, closestZone, forwarderZone, isRecursionAllowed); + return GetReferralResponse(request, false, closestZone, forwarderZone); authority = closestZone.QueryRecords(DnsResourceRecordType.FWD, false); } @@ -450,12 +450,12 @@ namespace DnsServerCore.Dns.ZoneManagers if ((authority is null) || (authority.Count == 0)) { if (forwarderZone.ContainsNameServerRecords()) - return GetReferralResponse(request, false, forwarderZone, forwarderZone, isRecursionAllowed); + return GetReferralResponse(request, false, forwarderZone, forwarderZone); authority = forwarderZone.QueryRecords(DnsResourceRecordType.FWD, false); } - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, authority); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, null, authority); } internal void Flush() @@ -1802,15 +1802,13 @@ namespace DnsServerCore.Dns.ZoneManagers _zoneIndexLock.EnterReadLock(); try { - if (pageNumber < 0) - pageNumber = int.MaxValue; - else if (pageNumber == 0) + if (pageNumber == 0) pageNumber = 1; int totalZones = _zoneIndex.Count; int totalPages = (totalZones / zonesPerPage) + (totalZones % zonesPerPage > 0 ? 1 : 0); - if (pageNumber > totalPages) + if ((pageNumber > totalPages) || (pageNumber < 0)) pageNumber = totalPages; int start = (pageNumber - 1) * zonesPerPage; @@ -1841,14 +1839,14 @@ namespace DnsServerCore.Dns.ZoneManagers { bool dnssecOk = request.DnssecOk && (apexZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned); - return GetReferralResponse(request, dnssecOk, delegation, apexZone, true); + return GetReferralResponse(request, dnssecOk, delegation, apexZone); } //no delegation found return null; } - public DnsDatagram Query(DnsDatagram request, bool isRecursionAllowed) + public DnsDatagram Query(DnsDatagram request) { DnsQuestionRecord question = request.Question[0]; @@ -1863,10 +1861,10 @@ namespace DnsServerCore.Dns.ZoneManagers { //zone not found if ((delegation is not null) && delegation.IsActive && (delegation.Name.Length > apexZone.Name.Length)) - return GetReferralResponse(request, dnssecOk, delegation, apexZone, isRecursionAllowed); + return GetReferralResponse(request, dnssecOk, delegation, apexZone); if (apexZone is StubZone) - return GetReferralResponse(request, false, apexZone, apexZone, isRecursionAllowed); + return GetReferralResponse(request, false, apexZone, apexZone); DnsResponseCode rCode = DnsResponseCode.NoError; IReadOnlyList answer = null; @@ -1902,7 +1900,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (authority.Count == 0) { if (apexZone is ForwarderZone) - return GetForwarderResponse(request, null, closest, apexZone, isRecursionAllowed); //no DNAME or APP record available so process FWD response + return GetForwarderResponse(request, null, closest, apexZone); //no DNAME or APP record available so process FWD response if (!hasSubDomains) rCode = DnsResponseCode.NxDomain; @@ -1933,7 +1931,7 @@ namespace DnsServerCore.Dns.ZoneManagers } } - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, rCode, request.Question, answer, authority); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, rCode, request.Question, answer, authority); } else { @@ -1951,7 +1949,7 @@ namespace DnsServerCore.Dns.ZoneManagers else if (zone.Equals(delegation)) { //zone is delegation - return GetReferralResponse(request, dnssecOk, delegation, apexZone, isRecursionAllowed); + return GetReferralResponse(request, dnssecOk, delegation, apexZone); } IReadOnlyList authority = null; @@ -1981,10 +1979,10 @@ namespace DnsServerCore.Dns.ZoneManagers { //check for delegation, stub & forwarder if ((delegation is not null) && delegation.IsActive && (delegation.Name.Length > apexZone.Name.Length)) - return GetReferralResponse(request, dnssecOk, delegation, apexZone, isRecursionAllowed); + return GetReferralResponse(request, dnssecOk, delegation, apexZone); if (apexZone is StubZone) - return GetReferralResponse(request, false, apexZone, apexZone, isRecursionAllowed); + return GetReferralResponse(request, false, apexZone, apexZone); } authority = zone.QueryRecords(DnsResourceRecordType.APP, false); @@ -1999,7 +1997,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (authority.Count == 0) { if (apexZone is ForwarderZone) - return GetForwarderResponse(request, zone, closest, apexZone, isRecursionAllowed); //no APP record available so process FWD response + return GetForwarderResponse(request, zone, closest, apexZone); //no APP record available so process FWD response authority = apexZone.QueryRecords(DnsResourceRecordType.SOA, dnssecOk); @@ -2091,7 +2089,7 @@ namespace DnsServerCore.Dns.ZoneManagers } } - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, authority, additional); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answers, authority, additional); } } From 431b16c1f4dccac45d61da6ef8477bf84dc557bc Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:40:11 +0530 Subject: [PATCH 170/191] BlockListZoneManager: Updated code to support Adblock plus list file format. --- .../Dns/ZoneManagers/BlockListZoneManager.cs | 139 ++++++++++++------ 1 file changed, 92 insertions(+), 47 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs index ac715ade..0dc0bcfb 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs @@ -109,15 +109,13 @@ namespace DnsServerCore.Dns.ZoneManagers return word; } - private Queue ReadListFile(Uri listUrl, bool isAllowList) + private Queue ReadListFile(Uri listUrl, bool isAllowList, Dictionary allowedDomains) { Queue domains = new Queue(); try { - LogManager log = _dnsServer.LogManager; - if (log != null) - log.Write("DNS Server is reading " + (isAllowList ? "allow" : "block") + " list from: " + listUrl.AbsoluteUri); + _dnsServer.LogManager?.Write("DNS Server is reading " + (isAllowList ? "allow" : "block") + " list from: " + listUrl.AbsoluteUri); using (FileStream fS = new FileStream(GetBlockListFilePath(listUrl), FileMode.Open, FileAccess.Read)) { @@ -128,11 +126,14 @@ namespace DnsServerCore.Dns.ZoneManagers string firstWord; string secondWord; string hostname; + string domain; + string options; + int i; while (true) { line = sR.ReadLine(); - if (line == null) + if (line is null) break; //eof line = line.TrimStart(trimSeperator); @@ -140,62 +141,106 @@ namespace DnsServerCore.Dns.ZoneManagers if (line.Length == 0) continue; //skip empty line - if (line.StartsWith("#")) + if (line.StartsWith("#") || line.StartsWith("!")) continue; //skip comment line - firstWord = PopWord(ref line); - - if (line.Length == 0) + if (line.StartsWith("||")) { - hostname = firstWord; + //adblock format + i = line.IndexOf('^'); + if (i > -1) + { + 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); + } + else + { + domain = line.Substring(2); + + if (DnsClient.IsDomainNameValid(domain)) + domains.Enqueue(domain); + } + } + else if (line.StartsWith("@@||")) + { + //adblock format + if (!isAllowList) + { + i = line.IndexOf('^'); + if (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 (DnsClient.IsDomainNameValid(domain)) + allowedDomains.TryAdd(domain, null); + } + } } else { - secondWord = PopWord(ref line); + //hosts file format + firstWord = PopWord(ref line); - if (secondWord.Length == 0) + if (line.Length == 0) + { hostname = firstWord; + } else - hostname = secondWord; + { + secondWord = PopWord(ref line); + + if (secondWord.Length == 0) + hostname = firstWord; + else + hostname = secondWord; + } + + hostname = hostname.Trim('.').ToLower(); + + switch (hostname) + { + case "": + case "localhost": + case "localhost.localdomain": + case "local": + case "broadcasthost": + case "ip6-localhost": + case "ip6-loopback": + case "ip6-localnet": + case "ip6-mcastprefix": + case "ip6-allnodes": + case "ip6-allrouters": + case "ip6-allhosts": + continue; //skip these hostnames + } + + if (!DnsClient.IsDomainNameValid(hostname)) + continue; + + if (IPAddress.TryParse(hostname, out _)) + continue; //skip line when hostname is IP address + + domains.Enqueue(hostname); } - - hostname = hostname.Trim('.').ToLower(); - - switch (hostname) - { - case "": - case "localhost": - case "localhost.localdomain": - case "local": - case "broadcasthost": - case "ip6-localhost": - case "ip6-loopback": - case "ip6-localnet": - case "ip6-mcastprefix": - case "ip6-allnodes": - case "ip6-allrouters": - case "ip6-allhosts": - continue; //skip these hostnames - } - - if (!DnsClient.IsDomainNameValid(hostname)) - continue; - - if (IPAddress.TryParse(hostname, out _)) - continue; //skip line when hostname is IP address - - domains.Enqueue(hostname); } } - if (log != null) - log.Write("DNS Server read " + (isAllowList ? "allow" : "block") + " list file (" + domains.Count + " domains) from: " + listUrl.AbsoluteUri); + _dnsServer.LogManager?.Write("DNS Server read " + (isAllowList ? "allow" : "block") + " list file (" + domains.Count + " domains) from: " + listUrl.AbsoluteUri); } catch (Exception ex) { - LogManager log = _dnsServer.LogManager; - if (log != null) - log.Write("DNS Server failed to read " + (isAllowList ? "allow" : "block") + " list from: " + listUrl.AbsoluteUri + "\r\n" + ex.ToString()); + _dnsServer.LogManager?.Write("DNS Server failed to read " + (isAllowList ? "allow" : "block") + " list from: " + listUrl.AbsoluteUri + "\r\n" + ex.ToString()); } return domains; @@ -247,7 +292,7 @@ namespace DnsServerCore.Dns.ZoneManagers foreach (Uri allowListUrl in _allowListUrls) { - Queue queue = ReadListFile(allowListUrl, true); + Queue queue = ReadListFile(allowListUrl, true, null); while (queue.Count > 0) { @@ -265,7 +310,7 @@ namespace DnsServerCore.Dns.ZoneManagers { if (!blockListQueues.ContainsKey(blockListUrl)) { - Queue blockListQueue = ReadListFile(blockListUrl, false); + Queue blockListQueue = ReadListFile(blockListUrl, false, allowedDomains); totalDomains += blockListQueue.Count; blockListQueues.Add(blockListUrl, blockListQueue); } From 2e2fd4326364c0f9c0d9895fba22a407eedf8422 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:41:19 +0530 Subject: [PATCH 171/191] AuthZoneInfo: updated implementation to use values from apex zone reference when it is available. --- DnsServerCore/Dns/Zones/AuthZoneInfo.cs | 221 ++++++++++++++++++------ 1 file changed, 171 insertions(+), 50 deletions(-) diff --git a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs index 0f03a3d1..05de3920 100644 --- a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs +++ b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs @@ -61,9 +61,6 @@ namespace DnsServerCore.Dns.Zones readonly IReadOnlyDictionary>> _updateSecurityPolicies; readonly IReadOnlyCollection _dnssecPrivateKeys; - readonly bool _notifyFailed; //not serialized - readonly bool _syncFailed; //not serialized - #endregion #region constructor @@ -334,8 +331,6 @@ namespace DnsServerCore.Dns.Zones _zoneTransferTsigKeyNames = primaryZone.ZoneTransferTsigKeyNames; _updateSecurityPolicies = primaryZone.UpdateSecurityPolicies; _dnssecPrivateKeys = primaryZone.DnssecPrivateKeys; - - _notifyFailed = primaryZone.NotifyFailed; } else if (_apexZone is SecondaryZone secondaryZone) { @@ -346,16 +341,11 @@ namespace DnsServerCore.Dns.Zones _expiry = secondaryZone.Expiry; _zoneTransferTsigKeyNames = secondaryZone.ZoneTransferTsigKeyNames; - - _notifyFailed = secondaryZone.NotifyFailed; - _syncFailed = secondaryZone.SyncFailed; } else if (_apexZone is StubZone stubZone) { _type = AuthZoneType.Stub; _expiry = stubZone.Expiry; - - _syncFailed = stubZone.SyncFailed; } else if (_apexZone is ForwarderZone) { @@ -666,7 +656,13 @@ namespace DnsServerCore.Dns.Zones public bool Disabled { - get { return _disabled; } + get + { + if (_apexZone is null) + return _disabled; + + return _apexZone.Disabled; + } set { if (_apexZone is null) @@ -678,7 +674,13 @@ namespace DnsServerCore.Dns.Zones public AuthZoneTransfer ZoneTransfer { - get { return _zoneTransfer; } + get + { + if (_apexZone is null) + return _zoneTransfer; + + return _apexZone.ZoneTransfer; + } set { if (_apexZone is null) @@ -690,7 +692,13 @@ namespace DnsServerCore.Dns.Zones public IReadOnlyCollection ZoneTransferNameServers { - get { return _zoneTransferNameServers; } + get + { + if (_apexZone is null) + return _zoneTransferNameServers; + + return _apexZone.ZoneTransferNameServers; + } set { if (_apexZone is null) @@ -702,7 +710,13 @@ namespace DnsServerCore.Dns.Zones public AuthZoneNotify Notify { - get { return _notify; } + get + { + if (_apexZone is null) + return _notify; + + return _apexZone.Notify; + } set { if (_apexZone is null) @@ -714,7 +728,13 @@ namespace DnsServerCore.Dns.Zones public IReadOnlyCollection NotifyNameServers { - get { return _notifyNameServers; } + get + { + if (_apexZone is null) + return _notifyNameServers; + + return _apexZone.NotifyNameServers; + } set { if (_apexZone is null) @@ -726,7 +746,13 @@ namespace DnsServerCore.Dns.Zones public AuthZoneUpdate Update { - get { return _update; } + get + { + if (_apexZone is null) + return _update; + + return _apexZone.Update; + } set { if (_apexZone is null) @@ -738,7 +764,13 @@ namespace DnsServerCore.Dns.Zones public IReadOnlyCollection UpdateIpAddresses { - get { return _updateIpAddresses; } + get + { + if (_apexZone is null) + return _updateIpAddresses; + + return _apexZone.UpdateIpAddresses; + } set { if (_apexZone is null) @@ -749,53 +781,46 @@ namespace DnsServerCore.Dns.Zones } public DateTime Expiry - { get { return _expiry; } } - - public bool IsExpired { get { if (_apexZone is null) - throw new InvalidOperationException(); + return _expiry; switch (_type) { case AuthZoneType.Secondary: - return (_apexZone as SecondaryZone).IsExpired; + return (_apexZone as SecondaryZone).Expiry; case AuthZoneType.Stub: - return (_apexZone as StubZone).IsExpired; + return (_apexZone as StubZone).Expiry; default: - return false; - } - } - } - - public bool Internal - { - get - { - if (_apexZone is null) - throw new InvalidOperationException(); - - switch (_type) - { - case AuthZoneType.Primary: - return (_apexZone as PrimaryZone).Internal; - - default: - return false; + throw new InvalidOperationException(); } } } public IReadOnlyList ZoneHistory - { get { return _zoneHistory; } } + { + get + { + if (_apexZone is null) + return _zoneHistory; + + return _apexZone.GetZoneHistory(); + } + } public IReadOnlyDictionary ZoneTransferTsigKeyNames { - get { return _zoneTransferTsigKeyNames; } + get + { + if (_apexZone is null) + return _zoneTransferTsigKeyNames; + + return _apexZone.ZoneTransferTsigKeyNames; + } set { if (_apexZone is null) @@ -816,7 +841,13 @@ namespace DnsServerCore.Dns.Zones public IReadOnlyDictionary>> UpdateSecurityPolicies { - get { return _updateSecurityPolicies; } + get + { + if (_apexZone is null) + return _updateSecurityPolicies; + + return _apexZone.UpdateSecurityPolicies; + } set { if (_apexZone is null) @@ -834,6 +865,24 @@ namespace DnsServerCore.Dns.Zones } } + public IReadOnlyCollection DnssecPrivateKeys + { + get + { + if (_apexZone is null) + return _dnssecPrivateKeys; + + switch (_type) + { + case AuthZoneType.Primary: + return (_apexZone as PrimaryZone).DnssecPrivateKeys; + + default: + throw new InvalidOperationException(); + } + } + } + public AuthZoneDnssecStatus DnssecStatus { get @@ -858,19 +907,91 @@ namespace DnsServerCore.Dns.Zones return (_apexZone as PrimaryZone).GetDnsKeyTtl(); default: - throw new NotSupportedException(); + throw new InvalidOperationException(); } } } - public IReadOnlyCollection DnssecPrivateKeys - { get { return _dnssecPrivateKeys; } } + public bool Internal + { + get + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Primary: + return (_apexZone as PrimaryZone).Internal; + + default: + return false; + } + } + } + + public bool IsExpired + { + get + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Secondary: + return (_apexZone as SecondaryZone).IsExpired; + + case AuthZoneType.Stub: + return (_apexZone as StubZone).IsExpired; + + default: + return false; + } + } + } public bool NotifyFailed - { get { return _notifyFailed; } } + { + get + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Primary: + return (_apexZone as PrimaryZone).NotifyFailed; + + case AuthZoneType.Secondary: + return (_apexZone as SecondaryZone).NotifyFailed; + + default: + throw new InvalidOperationException(); + } + } + } public bool SyncFailed - { get { return _syncFailed; } } + { + get + { + if (_apexZone is null) + throw new InvalidOperationException(); + + switch (_type) + { + case AuthZoneType.Secondary: + return (_apexZone as SecondaryZone).SyncFailed; + + case AuthZoneType.Stub: + return (_apexZone as StubZone).SyncFailed; + + default: + throw new InvalidOperationException(); + } + } + } #endregion } From 12c63f0907ea84461a8a87a20da02d7ea67340b4 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:41:56 +0530 Subject: [PATCH 172/191] ResolverDnsCache: refactoring changes. --- DnsServerCore/Dns/ResolverDnsCache.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/Dns/ResolverDnsCache.cs b/DnsServerCore/Dns/ResolverDnsCache.cs index dae91c6a..6605e488 100644 --- a/DnsServerCore/Dns/ResolverDnsCache.cs +++ b/DnsServerCore/Dns/ResolverDnsCache.cs @@ -140,7 +140,7 @@ namespace DnsServerCore.Dns { try { - authResponse = requestHandler.ProcessRequestAsync(request, new IPEndPoint(IPAddress.Any, 0), DnsTransportProtocol.Tcp, false).Sync(); + authResponse = requestHandler.ProcessRequestAsync(request, new IPEndPoint(IPAddress.Any, 0), DnsTransportProtocol.Tcp, true).Sync(); if (authResponse is not null) { if ((authResponse.RCODE != DnsResponseCode.NoError) || (authResponse.Answer.Count > 0) || (authResponse.Authority.Count == 0) || authResponse.IsFirstAuthoritySOA()) @@ -157,7 +157,7 @@ namespace DnsServerCore.Dns if (authResponse is null) { - authResponse = _authZoneManager.Query(request, true); + authResponse = _authZoneManager.Query(request); if (authResponse is not null) { if ((authResponse.RCODE != DnsResponseCode.NoError) || (authResponse.Answer.Count > 0) || (authResponse.Authority.Count == 0) || authResponse.IsFirstAuthoritySOA()) From 089634f1f32517ab2ad01f89e5d3e8592ab70744 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:43:37 +0530 Subject: [PATCH 173/191] DnsServer: setting default blocking type to NX domain. Implemented independent query task scheduler to handle incoming requests. Implemented new DirectQueryAsync() method. --- DnsServerCore/Dns/DnsServer.cs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 0133c080..d71f67f9 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -174,7 +174,7 @@ namespace DnsServerCore.Dns bool _enableBlocking = true; bool _allowTxtBlockingReport = true; - DnsServerBlockingType _blockingType = DnsServerBlockingType.AnyAddress; + DnsServerBlockingType _blockingType = DnsServerBlockingType.NxDomain; IReadOnlyCollection _customBlockingARecords = Array.Empty(); IReadOnlyCollection _customBlockingAAAARecords = Array.Empty(); @@ -207,6 +207,8 @@ namespace DnsServerCore.Dns IReadOnlyDictionary _qpmLimitClientSubnetStats; IReadOnlyDictionary _qpmLimitErrorClientSubnetStats; + readonly IndependentTaskScheduler _queryTaskScheduler = new IndependentTaskScheduler(); + readonly IndependentTaskScheduler _resolverTaskScheduler = new IndependentTaskScheduler(ThreadPriority.AboveNormal); readonly ConcurrentDictionary> _resolverTasks = new ConcurrentDictionary>(); @@ -1863,7 +1865,7 @@ namespace DnsServerCore.Dns if (response is null) { - response = _authZoneManager.Query(request, isRecursionAllowed); + response = _authZoneManager.Query(request); if (response is null) return null; @@ -2057,7 +2059,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, isRecursionAllowed); + newResponse = _authZoneManager.Query(newRequest); if (newResponse is null) { //not found in auth zone @@ -2214,7 +2216,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, isRecursionAllowed); + DnsDatagram newResponse = _authZoneManager.Query(newRequest); if (newResponse is null) { //not found in auth zone; do recursion @@ -3437,7 +3439,7 @@ 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 }), true); + DnsDatagram response = _authZoneManager.Query(new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, false, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { eligibleQuerySample })); if (response is null) { //zone not hosted; do refresh @@ -4067,7 +4069,7 @@ namespace DnsServerCore.Dns _ = Task.Factory.StartNew(delegate () { return ReadUdpRequestAsync(udpListener); - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); + }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _queryTaskScheduler); } } @@ -4078,7 +4080,7 @@ namespace DnsServerCore.Dns _ = Task.Factory.StartNew(delegate () { return AcceptConnectionAsync(tcpListener, DnsTransportProtocol.Tcp); - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); + }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _queryTaskScheduler); } } @@ -4089,7 +4091,7 @@ namespace DnsServerCore.Dns _ = Task.Factory.StartNew(delegate () { return AcceptConnectionAsync(tlsListener, DnsTransportProtocol.Tls); - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); + }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _queryTaskScheduler); } } @@ -4100,7 +4102,7 @@ namespace DnsServerCore.Dns _ = Task.Factory.StartNew(delegate () { return AcceptQuicConnectionAsync(quicListener); - }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Current); + }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _queryTaskScheduler); } } @@ -4186,7 +4188,12 @@ namespace DnsServerCore.Dns public Task DirectQueryAsync(DnsQuestionRecord question, int timeout = 4000, bool skipDnsAppAuthoritativeRequestHandlers = false) { - return ProcessQueryAsync(new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { question }), IPENDPOINT_ANY_0, DnsTransportProtocol.Tcp, true, skipDnsAppAuthoritativeRequestHandlers, null).WithTimeout(timeout); + return DirectQueryAsync(new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { question }), timeout, skipDnsAppAuthoritativeRequestHandlers); + } + + public Task DirectQueryAsync(DnsDatagram request, int timeout = 4000, bool skipDnsAppAuthoritativeRequestHandlers = false) + { + return ProcessQueryAsync(request, IPENDPOINT_ANY_0, DnsTransportProtocol.Tcp, true, skipDnsAppAuthoritativeRequestHandlers, null).WithTimeout(timeout); } Task IDnsClient.ResolveAsync(DnsQuestionRecord question, CancellationToken cancellationToken) From 7e6b04441d69e5e9ba864be71675d8379df9869c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:44:30 +0530 Subject: [PATCH 174/191] DnsWebService: updated web server max request limit. --- DnsServerCore/DnsWebService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index f6a3ec97..98079fef 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -270,6 +270,7 @@ namespace DnsServerCore } serverOptions.AddServerHeader = false; + serverOptions.Limits.MaxRequestBodySize = null; }); builder.Logging.ClearProviders(); From 2ec37d1297dcc2f42a49378567a67f69b490ec3a Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:44:57 +0530 Subject: [PATCH 175/191] WebServiceZonesApi: minor refactoring changes. --- DnsServerCore/WebServiceZonesApi.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index 1f717c88..22306c33 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -398,16 +398,20 @@ namespace DnsServerCore { if ((zoneInfo is not null) && (zoneInfo.Type == AuthZoneType.Primary)) { - foreach (DnssecPrivateKey dnssecPrivateKey in zoneInfo.DnssecPrivateKeys) + IReadOnlyCollection dnssecPrivateKeys = zoneInfo.DnssecPrivateKeys; + if (dnssecPrivateKeys is not null) { - if (dnssecPrivateKey.KeyTag == rdata.ComputedKeyTag) + foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys) { - jsonWriter.WriteString("dnsKeyState", dnssecPrivateKey.State.ToString()); + if (dnssecPrivateKey.KeyTag == rdata.ComputedKeyTag) + { + jsonWriter.WriteString("dnsKeyState", dnssecPrivateKey.State.ToString()); - if ((dnssecPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (dnssecPrivateKey.State == DnssecPrivateKeyState.Published)) - jsonWriter.WriteString("dnsKeyStateReadyBy", (zoneInfo.ApexZone as PrimaryZone).GetDnsKeyStateReadyBy(dnssecPrivateKey)); + if ((dnssecPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (dnssecPrivateKey.State == DnssecPrivateKeyState.Published)) + jsonWriter.WriteString("dnsKeyStateReadyBy", (zoneInfo.ApexZone as PrimaryZone).GetDnsKeyStateReadyBy(dnssecPrivateKey)); - break; + break; + } } } } From e783b6b171e36c704e666f4a7aa48cb96f04ae10 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:45:55 +0530 Subject: [PATCH 176/191] webapp: updated html to support pagination for zone records view. Other minor changes done. --- DnsServerCore/www/index.html | 85 ++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 14 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 0e3bf589..596c5c0d 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -350,7 +350,7 @@
    - +
    @@ -424,7 +424,7 @@
    GroupViewModifyDeleteGroupViewModifyDelete
    " + htmlEncode(user.username) + "" + htmlEncode(user.displayName) + "" + status + "" + - htmlEncode(moment(user.previousSessionLoggedOn).local().format("YYYY-MM-DD HH:mm:ss")) + " from " + htmlEncode(user.previousSessionRemoteAddress) + "" + - htmlEncode(moment(user.recentSessionLoggedOn).local().format("YYYY-MM-DD HH:mm:ss")) + " from " + htmlEncode(user.recentSessionRemoteAddress); + htmlEncode(moment(user.recentSessionLoggedOn).local().format("YYYY-MM-DD HH:mm:ss")) + " from " + htmlEncode(user.recentSessionRemoteAddress) + "" + + htmlEncode(moment(user.previousSessionLoggedOn).local().format("YYYY-MM-DD HH:mm:ss")) + " from " + htmlEncode(user.previousSessionRemoteAddress); tableHtmlRows += "
      "; tableHtmlRows += "
    • View Details
    • "; From 0c715b9f5e712c358da9024d31abe6befa3b4a9c Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:24:27 +0530 Subject: [PATCH 098/191] logs.js: removed old datetime picker code. --- DnsServerCore/www/js/logs.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/DnsServerCore/www/js/logs.js b/DnsServerCore/www/js/logs.js index 7bb87663..de6b365e 100644 --- a/DnsServerCore/www/js/logs.js +++ b/DnsServerCore/www/js/logs.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 @@ -18,9 +18,6 @@ along with this program. If not, see . */ $(function () { - $('#dtpQueryLogStart').datetimepicker({ format: "YYYY-MM-DD HH:mm:ss" }); - $('#dtpQueryLogEnd').datetimepicker({ format: "YYYY-MM-DD HH:mm:ss" }); - $("#optQueryLogsAppName").change(function () { if (appsList == null) return; From 453816dc0502b95a512a70c9175c5f2bff2567fa Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:27:03 +0530 Subject: [PATCH 099/191] main.js: updated code for QUIC support. Implemented new settings options. Removed old datetime picker code. Code refactoring changes. --- DnsServerCore/www/js/main.js | 782 ++++++++++++++++++++++------------- 1 file changed, 504 insertions(+), 278 deletions(-) diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index f2c8c082..5d8b3949 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.js @@ -236,7 +236,9 @@ $(function () { var itemText = $(this).text(); $(this).closest('.dropdown').find('input').val(itemText); - if ((itemText.indexOf("TLS") !== -1) || (itemText.indexOf(":853") !== -1)) + if (itemText.indexOf("QUIC") !== -1) + $("#optDnsClientProtocol").val("QUIC"); + else if ((itemText.indexOf("TLS") !== -1) || (itemText.indexOf(":853") !== -1)) $("#optDnsClientProtocol").val("TLS"); else if ((itemText.indexOf("HTTPS") !== -1) || (itemText.indexOf("http://") !== -1) || (itemText.indexOf("https://") !== -1)) $("#optDnsClientProtocol").val("HTTPS"); @@ -302,20 +304,40 @@ $(function () { $("#txtWebServiceTlsCertificatePassword").prop("disabled", !webServiceEnableTls); }); + $("#chkEnableDnsOverHttp").click(function () { + var enableDnsOverHttp = $("#chkEnableDnsOverHttp").prop("checked"); + + $("#txtDnsOverHttpPort").prop("disabled", !enableDnsOverHttp); + }); + $("#chkEnableDnsOverTls").click(function () { var enableDnsOverTls = $("#chkEnableDnsOverTls").prop("checked"); var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop("checked"); + var enableDnsOverQuic = $("#chkEnableDnsOverQuic").prop("checked"); - $("#txtDnsTlsCertificatePath").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps); - $("#txtDnsTlsCertificatePassword").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps); + $("#txtDnsOverTlsPort").prop("disabled", !enableDnsOverTls); + $("#txtDnsTlsCertificatePath").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); + $("#txtDnsTlsCertificatePassword").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); }); $("#chkEnableDnsOverHttps").click(function () { var enableDnsOverTls = $("#chkEnableDnsOverTls").prop("checked"); var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop("checked"); + var enableDnsOverQuic = $("#chkEnableDnsOverQuic").prop("checked"); - $("#txtDnsTlsCertificatePath").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps); - $("#txtDnsTlsCertificatePassword").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps); + $("#txtDnsOverHttpsPort").prop("disabled", !enableDnsOverHttps); + $("#txtDnsTlsCertificatePath").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); + $("#txtDnsTlsCertificatePassword").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); + }); + + $("#chkEnableDnsOverQuic").click(function () { + var enableDnsOverTls = $("#chkEnableDnsOverTls").prop("checked"); + var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop("checked"); + var enableDnsOverQuic = $("#chkEnableDnsOverQuic").prop("checked"); + + $("#txtDnsOverQuicPort").prop("disabled", !enableDnsOverQuic); + $("#txtDnsTlsCertificatePath").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); + $("#txtDnsTlsCertificatePassword").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); }); $("#chkEnableLogging").click(function () { @@ -614,6 +636,98 @@ $(function () { break; + case "adguard-udp": + $("#txtForwarders").val("94.140.14.14\r\n94.140.15.15"); + $("#rdForwarderProtocolUdp").prop("checked", true); + break; + + case "adguard-udp-ipv6": + $("#txtForwarders").val("[2a10:50c0::ad1:ff]\r\n[2a10:50c0::ad2:ff]"); + $("#rdForwarderProtocolUdp").prop("checked", true); + break; + + case "adguard-tcp": + $("#txtForwarders").val("94.140.14.14\r\n94.140.15.15"); + $("#rdForwarderProtocolTcp").prop("checked", true); + break; + + case "adguard-tcp-ipv6": + $("#txtForwarders").val("[2a10:50c0::ad1:ff]\r\n[2a10:50c0::ad2:ff]"); + $("#rdForwarderProtocolTcp").prop("checked", true); + break; + + case "adguard-tls": + $("#txtForwarders").val("dns.adguard-dns.com (94.140.14.14:853)\r\ndns.adguard-dns.com (94.140.15.15:853)"); + $("#rdForwarderProtocolTls").prop("checked", true); + break; + + case "adguard-tls-ipv6": + $("#txtForwarders").val("dns.adguard-dns.com ([2a10:50c0::ad1:ff]:853)\r\ndns.adguard-dns.com ([2a10:50c0::ad2:ff]:853)"); + $("#rdForwarderProtocolTls").prop("checked", true); + break; + + case "adguard-https": + $("#txtForwarders").val("https://dns.adguard-dns.com/dns-query"); + $("#rdForwarderProtocolHttps").prop("checked", true); + break; + + case "adguard-quic": + $("#txtForwarders").val("dns.adguard-dns.com (94.140.14.14:853)\r\ndns.adguard-dns.com (94.140.15.15:853)"); + $("#rdForwarderProtocolQuic").prop("checked", true); + break; + + case "adguard-quic-ipv6": + $("#txtForwarders").val("dns.adguard-dns.com ([2a10:50c0::ad1:ff]:853)\r\ndns.adguard-dns.com ([2a10:50c0::ad2:ff]:853)"); + $("#rdForwarderProtocolQuic").prop("checked", true); + break; + + + case "adguard-f-udp": + $("#txtForwarders").val("94.140.14.15\r\n94.140.15.16"); + $("#rdForwarderProtocolUdp").prop("checked", true); + break; + + case "adguard-f-udp-ipv6": + $("#txtForwarders").val("[2a10:50c0::bad1:ff]\r\n[2a10:50c0::bad2:ff]"); + $("#rdForwarderProtocolUdp").prop("checked", true); + break; + + case "adguard-f-tcp": + $("#txtForwarders").val("94.140.14.15\r\n94.140.15.16"); + $("#rdForwarderProtocolTcp").prop("checked", true); + break; + + case "adguard-f-tcp-ipv6": + $("#txtForwarders").val("[2a10:50c0::bad1:ff]\r\n[2a10:50c0::bad2:ff]"); + $("#rdForwarderProtocolTcp").prop("checked", true); + break; + + case "adguard-f-tls": + $("#txtForwarders").val("family.adguard-dns.com (94.140.14.15:853)\r\nfamily.adguard-dns.com (94.140.15.16:853)"); + $("#rdForwarderProtocolTls").prop("checked", true); + break; + + case "adguard-f-tls-ipv6": + $("#txtForwarders").val("family.adguard-dns.com ([2a10:50c0::bad1:ff]:853)\r\nfamily.adguard-dns.com ([2a10:50c0::bad2:ff]:853)"); + $("#rdForwarderProtocolTls").prop("checked", true); + break; + + case "adguard-f-https": + $("#txtForwarders").val("https://family.adguard-dns.com/dns-query"); + $("#rdForwarderProtocolHttps").prop("checked", true); + break; + + case "adguard-f-quic": + $("#txtForwarders").val("family.adguard-dns.com (94.140.14.15:853)\r\nfamily.adguard-dns.com (94.140.15.16:853)"); + $("#rdForwarderProtocolQuic").prop("checked", true); + break; + + case "adguard-f-quic-ipv6": + $("#txtForwarders").val("family.adguard-dns.com ([2a10:50c0::bad1:ff]:853)\r\nfamily.adguard-dns.com ([2a10:50c0::bad2:ff]:853)"); + $("#rdForwarderProtocolQuic").prop("checked", true); + break; + + case "none": $("#txtForwarders").val(""); $("#rdForwarderProtocolUdp").prop("checked", true); @@ -621,12 +735,6 @@ $(function () { } }); - $("#dpCustomDayWiseStart").datepicker(); - $("#dpCustomDayWiseStart").datepicker("option", "dateFormat", "yy-m-d"); - - $("#dpCustomDayWiseEnd").datepicker(); - $("#dpCustomDayWiseEnd").datepicker("option", "dateFormat", "yy-m-d"); - $("input[type=radio][name=rdStatType]").change(function () { var type = $('input[name=rdStatType]:checked').val(); if (type === "custom") { @@ -654,8 +762,6 @@ $(function () { $("#btnCustomDayWise").click(function () { refreshDashboard(); }); - - $("#lblDoHHost").text(window.location.hostname + ":8053"); }); function checkForUpdate() { @@ -737,12 +843,13 @@ function loadDnsSettings() { $("#lblAboutVersion").text(responseJSON.response.version); checkForReverseProxy(responseJSON); + //general $("#txtDnsServerDomain").val(responseJSON.response.dnsServerDomain); $("#lblDnsServerDomain").text(" - " + responseJSON.response.dnsServerDomain); var dnsServerLocalEndPoints = responseJSON.response.dnsServerLocalEndPoints; if (dnsServerLocalEndPoints == null) { - $("#txtDnsServerLocalEndPoints").val("0.0.0.0:53\r\n[::]:53"); + $("#txtDnsServerLocalEndPoints").val(""); } else { var value = ""; @@ -753,9 +860,35 @@ function loadDnsSettings() { $("#txtDnsServerLocalEndPoints").val(value); } + $("#txtDefaultRecordTtl").val(responseJSON.response.defaultRecordTtl); + $("#txtAddEditRecordTtl").attr("placeholder", responseJSON.response.defaultRecordTtl); + $("#chkDnsAppsEnableAutomaticUpdate").prop("checked", responseJSON.response.dnsAppsEnableAutomaticUpdate); + + $("#chkPreferIPv6").prop("checked", responseJSON.response.preferIPv6); + $("#txtEdnsUdpPayloadSize").val(responseJSON.response.udpPayloadSize); + $("#chkDnssecValidation").prop("checked", responseJSON.response.dnssecValidation); + + $("#chkEDnsClientSubnet").prop("checked", responseJSON.response.eDnsClientSubnet); + $("#txtEDnsClientSubnetIPv4PrefixLength").val(responseJSON.response.eDnsClientSubnetIPv4PrefixLength); + $("#txtEDnsClientSubnetIPv6PrefixLength").val(responseJSON.response.eDnsClientSubnetIPv6PrefixLength); + + $("#txtQpmLimitRequests").val(responseJSON.response.qpmLimitRequests); + $("#txtQpmLimitErrors").val(responseJSON.response.qpmLimitErrors); + $("#txtQpmLimitSampleMinutes").val(responseJSON.response.qpmLimitSampleMinutes); + $("#txtQpmLimitIPv4PrefixLength").val(responseJSON.response.qpmLimitIPv4PrefixLength); + $("#txtQpmLimitIPv6PrefixLength").val(responseJSON.response.qpmLimitIPv6PrefixLength); + + $("#txtClientTimeout").val(responseJSON.response.clientTimeout); + $("#txtTcpSendTimeout").val(responseJSON.response.tcpSendTimeout); + $("#txtTcpReceiveTimeout").val(responseJSON.response.tcpReceiveTimeout); + $("#txtQuicIdleTimeout").val(responseJSON.response.quicIdleTimeout); + $("#txtQuicMaxInboundStreams").val(responseJSON.response.quicMaxInboundStreams); + $("#txtListenBacklog").val(responseJSON.response.listenBacklog); + + //web service var webServiceLocalAddresses = responseJSON.response.webServiceLocalAddresses; if (webServiceLocalAddresses == null) { - $("#txtWebServiceLocalAddresses").val("0.0.0.0\r\n[::]"); + $("#txtWebServiceLocalAddresses").val(""); } else { var value = ""; @@ -785,12 +918,25 @@ function loadDnsSettings() { else $("#txtWebServiceTlsCertificatePassword").val(responseJSON.response.webServiceTlsCertificatePassword); + //optional protocols $("#chkEnableDnsOverHttp").prop("checked", responseJSON.response.enableDnsOverHttp); $("#chkEnableDnsOverTls").prop("checked", responseJSON.response.enableDnsOverTls); $("#chkEnableDnsOverHttps").prop("checked", responseJSON.response.enableDnsOverHttps); + $("#chkEnableDnsOverHttpPort80").prop("checked", responseJSON.response.enableDnsOverHttpPort80); + $("#chkEnableDnsOverQuic").prop("checked", responseJSON.response.enableDnsOverQuic); - $("#txtDnsTlsCertificatePath").prop("disabled", !responseJSON.response.enableDnsOverTls && !responseJSON.response.enableDnsOverHttps); - $("#txtDnsTlsCertificatePassword").prop("disabled", !responseJSON.response.enableDnsOverTls && !responseJSON.response.enableDnsOverHttps); + $("#txtDnsOverHttpPort").prop("disabled", !responseJSON.response.enableDnsOverHttp); + $("#txtDnsOverTlsPort").prop("disabled", !responseJSON.response.enableDnsOverTls); + $("#txtDnsOverHttpsPort").prop("disabled", !responseJSON.response.enableDnsOverHttps); + $("#txtDnsOverQuicPort").prop("disabled", !responseJSON.response.enableDnsOverQuic); + + $("#txtDnsOverHttpPort").val(responseJSON.response.dnsOverHttpPort); + $("#txtDnsOverTlsPort").val(responseJSON.response.dnsOverTlsPort); + $("#txtDnsOverHttpsPort").val(responseJSON.response.dnsOverHttpsPort); + $("#txtDnsOverQuicPort").val(responseJSON.response.dnsOverQuicPort); + + $("#txtDnsTlsCertificatePath").prop("disabled", !responseJSON.response.enableDnsOverTls && !responseJSON.response.enableDnsOverHttps && !responseJSON.response.enableDnsOverQuic); + $("#txtDnsTlsCertificatePassword").prop("disabled", !responseJSON.response.enableDnsOverTls && !responseJSON.response.enableDnsOverHttps && !responseJSON.response.enableDnsOverQuic); $("#txtDnsTlsCertificatePath").val(responseJSON.response.dnsTlsCertificatePath); @@ -799,6 +945,11 @@ function loadDnsSettings() { else $("#txtDnsTlsCertificatePassword").val(responseJSON.response.dnsTlsCertificatePassword); + $("#lblDoHHost").text(window.location.hostname + ":" + responseJSON.response.dnsOverHttpPort); + $("#lblDoTHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverTlsPort); + $("#lblDoQHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverQuicPort); + + //tsig $("#tableTsigKeys").html(""); if (responseJSON.response.tsigKeys != null) { @@ -807,40 +958,7 @@ function loadDnsSettings() { } } - $("#txtDefaultRecordTtl").val(responseJSON.response.defaultRecordTtl); - $("#txtAddEditRecordTtl").attr("placeholder", responseJSON.response.defaultRecordTtl); - $("#chkDnsAppsEnableAutomaticUpdate").prop("checked", responseJSON.response.dnsAppsEnableAutomaticUpdate); - - $("#chkPreferIPv6").prop("checked", responseJSON.response.preferIPv6); - $("#txtEdnsUdpPayloadSize").val(responseJSON.response.udpPayloadSize); - $("#chkDnssecValidation").prop("checked", responseJSON.response.dnssecValidation); - - $("#chkEDnsClientSubnet").prop("checked", responseJSON.response.eDnsClientSubnet); - $("#txtEDnsClientSubnetIPv4PrefixLength").val(responseJSON.response.eDnsClientSubnetIPv4PrefixLength); - $("#txtEDnsClientSubnetIPv6PrefixLength").val(responseJSON.response.eDnsClientSubnetIPv6PrefixLength); - - $("#txtResolverRetries").val(responseJSON.response.resolverRetries); - $("#txtResolverTimeout").val(responseJSON.response.resolverTimeout); - $("#txtResolverMaxStackCount").val(responseJSON.response.resolverMaxStackCount); - - $("#txtForwarderRetries").val(responseJSON.response.forwarderRetries); - $("#txtForwarderTimeout").val(responseJSON.response.forwarderTimeout); - $("#txtForwarderConcurrency").val(responseJSON.response.forwarderConcurrency); - - $("#txtClientTimeout").val(responseJSON.response.clientTimeout); - $("#txtTcpSendTimeout").val(responseJSON.response.tcpSendTimeout); - $("#txtTcpReceiveTimeout").val(responseJSON.response.tcpReceiveTimeout); - - $("#chkEnableLogging").prop("checked", responseJSON.response.enableLogging); - $("#chkLogQueries").prop("disabled", !responseJSON.response.enableLogging); - $("#chkUseLocalTime").prop("disabled", !responseJSON.response.enableLogging); - $("#txtLogFolderPath").prop("disabled", !responseJSON.response.enableLogging); - $("#chkLogQueries").prop("checked", responseJSON.response.logQueries); - $("#chkUseLocalTime").prop("checked", responseJSON.response.useLocalTime); - $("#txtLogFolderPath").val(responseJSON.response.logFolder); - $("#txtMaxLogFileDays").val(responseJSON.response.maxLogFileDays); - $("#txtMaxStatFileDays").val(responseJSON.response.maxStatFileDays); - + //recursion $("#txtRecursionDeniedNetworks").prop("disabled", true); $("#txtRecursionAllowedNetworks").prop("disabled", true); @@ -887,11 +1005,12 @@ function loadDnsSettings() { $("#chkQnameMinimization").prop("checked", responseJSON.response.qnameMinimization); $("#chkNsRevalidation").prop("checked", responseJSON.response.nsRevalidation); - $("#txtQpmLimitRequests").val(responseJSON.response.qpmLimitRequests); - $("#txtQpmLimitErrors").val(responseJSON.response.qpmLimitErrors); - $("#txtQpmLimitSampleMinutes").val(responseJSON.response.qpmLimitSampleMinutes); - $("#txtQpmLimitIPv4PrefixLength").val(responseJSON.response.qpmLimitIPv4PrefixLength); - $("#txtQpmLimitIPv6PrefixLength").val(responseJSON.response.qpmLimitIPv6PrefixLength); + $("#txtResolverRetries").val(responseJSON.response.resolverRetries); + $("#txtResolverTimeout").val(responseJSON.response.resolverTimeout); + $("#txtResolverMaxStackCount").val(responseJSON.response.resolverMaxStackCount); + + //cache + $("#chkSaveCache").prop("checked", responseJSON.response.saveCache); $("#chkServeStale").prop("checked", responseJSON.response.serveStale); $("#txtServeStaleTtl").prop("disabled", !responseJSON.response.serveStale); @@ -908,6 +1027,84 @@ function loadDnsSettings() { $("#txtCachePrefetchSampleIntervalInMinutes").val(responseJSON.response.cachePrefetchSampleIntervalInMinutes); $("#txtCachePrefetchSampleEligibilityHitsPerHour").val(responseJSON.response.cachePrefetchSampleEligibilityHitsPerHour); + //blocking + $("#chkEnableBlocking").prop("checked", responseJSON.response.enableBlocking); + $("#chkAllowTxtBlockingReport").prop("checked", responseJSON.response.allowTxtBlockingReport); + + if (responseJSON.response.temporaryDisableBlockingTill == null) + $("#lblTemporaryDisableBlockingTill").text("Not Set"); + else + $("#lblTemporaryDisableBlockingTill").text(moment(responseJSON.response.temporaryDisableBlockingTill).local().format("YYYY-MM-DD HH:mm:ss")); + + $("#txtTemporaryDisableBlockingMinutes").val(""); + + $("#txtCustomBlockingAddresses").prop("disabled", true); + + switch (responseJSON.response.blockingType) { + case "NxDomain": + $("#rdBlockingTypeNxDomain").prop("checked", true); + break; + + case "CustomAddress": + $("#rdBlockingTypeCustomAddress").prop("checked", true); + $("#txtCustomBlockingAddresses").prop("disabled", false); + break; + + case "AnyAddress": + default: + $("#rdBlockingTypeAnyAddress").prop("checked", true); + break; + } + + { + var value = ""; + + for (var i = 0; i < responseJSON.response.customBlockingAddresses.length; i++) + value += responseJSON.response.customBlockingAddresses[i] + "\r\n"; + + $("#txtCustomBlockingAddresses").val(value); + } + + var blockListUrls = responseJSON.response.blockListUrls; + if (blockListUrls == null) { + $("#txtBlockListUrls").val(""); + $("#btnUpdateBlockListsNow").prop("disabled", true); + } + else { + var value = ""; + + for (var i = 0; i < blockListUrls.length; i++) + value += blockListUrls[i] + "\r\n"; + + $("#txtBlockListUrls").val(value); + $("#btnUpdateBlockListsNow").prop("disabled", false); + } + + $("#optQuickBlockList").val("blank"); + + //fix custom block list url in case port changes + { + var optCustomLocalBlockList = $("#optCustomLocalBlockList"); + + optCustomLocalBlockList.attr("value", "http://localhost:" + responseJSON.response.webServiceHttpPort + "/blocklist.txt"); + optCustomLocalBlockList.text("Custom Local Block List (http://localhost:" + responseJSON.response.webServiceHttpPort + "/blocklist.txt)"); + } + + $("#txtBlockListUpdateIntervalHours").val(responseJSON.response.blockListUpdateIntervalHours); + + if (responseJSON.response.blockListNextUpdatedOn == null) { + $("#lblBlockListNextUpdatedOn").text("Not Scheduled"); + } + else { + var blockListNextUpdatedOn = moment(responseJSON.response.blockListNextUpdatedOn); + + if (moment().utc().isBefore(blockListNextUpdatedOn)) + $("#lblBlockListNextUpdatedOn").text(blockListNextUpdatedOn.local().format("YYYY-MM-DD HH:mm:ss")); + else + $("#lblBlockListNextUpdatedOn").text("Updating Now"); + } + + //proxy & forwarders var proxy = responseJSON.response.proxy; if (proxy === null) { $("#rdProxyTypeNone").prop("checked", true); @@ -988,86 +1185,30 @@ function loadDnsSettings() { $("#rdForwarderProtocolHttps").prop("checked", true); break; + case "quic": + $("#rdForwarderProtocolQuic").prop("checked", true); + break; + default: $("#rdForwarderProtocolUdp").prop("checked", true); break; } - $("#chkEnableBlocking").prop("checked", responseJSON.response.enableBlocking); - $("#chkAllowTxtBlockingReport").prop("checked", responseJSON.response.allowTxtBlockingReport); + $("#txtForwarderRetries").val(responseJSON.response.forwarderRetries); + $("#txtForwarderTimeout").val(responseJSON.response.forwarderTimeout); + $("#txtForwarderConcurrency").val(responseJSON.response.forwarderConcurrency); - if (responseJSON.response.temporaryDisableBlockingTill == null) - $("#lblTemporaryDisableBlockingTill").text("Not Set"); - else - $("#lblTemporaryDisableBlockingTill").text(moment(responseJSON.response.temporaryDisableBlockingTill).local().format("YYYY-MM-DD HH:mm:ss")); + //logging + $("#chkEnableLogging").prop("checked", responseJSON.response.enableLogging); + $("#chkLogQueries").prop("disabled", !responseJSON.response.enableLogging); + $("#chkUseLocalTime").prop("disabled", !responseJSON.response.enableLogging); + $("#txtLogFolderPath").prop("disabled", !responseJSON.response.enableLogging); - $("#txtTemporaryDisableBlockingMinutes").val(""); - - $("#txtCustomBlockingAddresses").prop("disabled", true); - - switch (responseJSON.response.blockingType) { - case "NxDomain": - $("#rdBlockingTypeNxDomain").prop("checked", true); - break; - - case "CustomAddress": - $("#rdBlockingTypeCustomAddress").prop("checked", true); - $("#txtCustomBlockingAddresses").prop("disabled", false); - break; - - case "AnyAddress": - default: - $("#rdBlockingTypeAnyAddress").prop("checked", true); - break; - } - - { - var value = ""; - - for (var i = 0; i < responseJSON.response.customBlockingAddresses.length; i++) - value += responseJSON.response.customBlockingAddresses[i] + "\r\n"; - - $("#txtCustomBlockingAddresses").val(value); - } - - var blockListUrls = responseJSON.response.blockListUrls; - if (blockListUrls == null) { - $("#txtBlockListUrls").val(""); - $("#btnUpdateBlockListsNow").prop("disabled", true); - } - else { - var value = ""; - - for (var i = 0; i < blockListUrls.length; i++) - value += blockListUrls[i] + "\r\n"; - - $("#txtBlockListUrls").val(value); - $("#btnUpdateBlockListsNow").prop("disabled", false); - } - - $("#optQuickBlockList").val("blank"); - - //fix custom block list url in case port changes - { - var optCustomLocalBlockList = $("#optCustomLocalBlockList"); - - optCustomLocalBlockList.attr("value", "http://localhost:" + responseJSON.response.webServiceHttpPort + "/blocklist.txt"); - optCustomLocalBlockList.text("Custom Local Block List (http://localhost:" + responseJSON.response.webServiceHttpPort + "/blocklist.txt)"); - } - - $("#txtBlockListUpdateIntervalHours").val(responseJSON.response.blockListUpdateIntervalHours); - - if (responseJSON.response.blockListNextUpdatedOn == null) { - $("#lblBlockListNextUpdatedOn").text("Not Scheduled"); - } - else { - var blockListNextUpdatedOn = moment(responseJSON.response.blockListNextUpdatedOn); - - if (moment().utc().isBefore(blockListNextUpdatedOn)) - $("#lblBlockListNextUpdatedOn").text(blockListNextUpdatedOn.local().format("YYYY-MM-DD HH:mm:ss")); - else - $("#lblBlockListNextUpdatedOn").text("Updating Now"); - } + $("#chkLogQueries").prop("checked", responseJSON.response.logQueries); + $("#chkUseLocalTime").prop("checked", responseJSON.response.useLocalTime); + $("#txtLogFolderPath").val(responseJSON.response.logFolder); + $("#txtMaxLogFileDays").val(responseJSON.response.maxLogFileDays); + $("#txtMaxStatFileDays").val(responseJSON.response.maxStatFileDays); divDnsSettingsLoader.hide(); divDnsSettings.show(); @@ -1080,6 +1221,7 @@ function loadDnsSettings() { } function saveDnsSettings() { + //general var dnsServerDomain = $("#txtDnsServerDomain").val(); if ((dnsServerDomain === null) || (dnsServerDomain === "")) { @@ -1095,38 +1237,6 @@ function saveDnsSettings() { else $("#txtDnsServerLocalEndPoints").val(dnsServerLocalEndPoints.replace(/,/g, "\n")); - var webServiceLocalAddresses = cleanTextList($("#txtWebServiceLocalAddresses").val()); - - if ((webServiceLocalAddresses.length === 0) || (webServiceLocalAddresses === ",")) - webServiceLocalAddresses = "0.0.0.0,[::]"; - else - $("#txtWebServiceLocalAddresses").val(webServiceLocalAddresses.replace(/,/g, "\n")); - - var webServiceHttpPort = $("#txtWebServiceHttpPort").val(); - - if ((webServiceHttpPort === null) || (webServiceHttpPort === "")) - webServiceHttpPort = 5380; - - var webServiceEnableTls = $("#chkWebServiceEnableTls").prop("checked"); - var webServiceHttpToTlsRedirect = $("#chkWebServiceHttpToTlsRedirect").prop("checked"); - var webServiceUseSelfSignedTlsCertificate = $("#chkWebServiceUseSelfSignedTlsCertificate").prop("checked"); - var webServiceTlsPort = $("#txtWebServiceTlsPort").val(); - var webServiceTlsCertificatePath = $("#txtWebServiceTlsCertificatePath").val(); - var webServiceTlsCertificatePassword = $("#txtWebServiceTlsCertificatePassword").val(); - - var enableDnsOverHttp = $("#chkEnableDnsOverHttp").prop('checked'); - var enableDnsOverTls = $("#chkEnableDnsOverTls").prop('checked'); - var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop('checked'); - var dnsTlsCertificatePath = $("#txtDnsTlsCertificatePath").val(); - var dnsTlsCertificatePassword = $("#txtDnsTlsCertificatePassword").val(); - - var tsigKeys = serializeTableData($("#tableTsigKeys"), 3); - if (tsigKeys === false) - return; - - if (tsigKeys.length === 0) - tsigKeys = false; - var defaultRecordTtl = $("#txtDefaultRecordTtl").val(); var dnsAppsEnableAutomaticUpdate = $("#chkDnsAppsEnableAutomaticUpdate").prop('checked'); var preferIPv6 = $("#chkPreferIPv6").prop('checked'); @@ -1149,96 +1259,6 @@ function saveDnsSettings() { return; } - var resolverRetries = $("#txtResolverRetries").val(); - if ((resolverRetries == null) || (resolverRetries === "")) { - showAlert("warning", "Missing!", "Please enter a value for Resolver Retries."); - $("#txtResolverRetries").focus(); - return; - } - - var resolverTimeout = $("#txtResolverTimeout").val(); - if ((resolverTimeout == null) || (resolverTimeout === "")) { - showAlert("warning", "Missing!", "Please enter a value for Resolver Timeout."); - $("#txtResolverTimeout").focus(); - return; - } - - var resolverMaxStackCount = $("#txtResolverMaxStackCount").val(); - if ((resolverMaxStackCount == null) || (resolverMaxStackCount === "")) { - showAlert("warning", "Missing!", "Please enter a value for Resolver Max Stack Count."); - $("#txtResolverMaxStackCount").focus(); - return; - } - - var forwarderRetries = $("#txtForwarderRetries").val(); - if ((forwarderRetries == null) || (forwarderRetries === "")) { - showAlert("warning", "Missing!", "Please enter a value for Forwarder Retries."); - $("#txtForwarderRetries").focus(); - return; - } - - var forwarderTimeout = $("#txtForwarderTimeout").val(); - if ((forwarderTimeout == null) || (forwarderTimeout === "")) { - showAlert("warning", "Missing!", "Please enter a value for Forwarder Timeout."); - $("#txtForwarderTimeout").focus(); - return; - } - - var forwarderConcurrency = $("#txtForwarderConcurrency").val(); - if ((forwarderConcurrency == null) || (forwarderConcurrency === "")) { - showAlert("warning", "Missing!", "Please enter a value for Forwarder Concurrency."); - $("#txtForwarderConcurrency").focus(); - return; - } - - var clientTimeout = $("#txtClientTimeout").val(); - if ((clientTimeout == null) || (clientTimeout === "")) { - showAlert("warning", "Missing!", "Please enter a value for Client Timeout."); - $("#txtClientTimeout").focus(); - return; - } - - var tcpSendTimeout = $("#txtTcpSendTimeout").val(); - if ((tcpSendTimeout == null) || (tcpSendTimeout === "")) { - showAlert("warning", "Missing!", "Please enter a value for TCP Send Timeout."); - $("#txtTcpSendTimeout").focus(); - return; - } - - var tcpReceiveTimeout = $("#txtTcpReceiveTimeout").val(); - if ((tcpReceiveTimeout == null) || (tcpReceiveTimeout === "")) { - showAlert("warning", "Missing!", "Please enter a value for TCP Receive Timeout."); - $("#txtTcpReceiveTimeout").focus(); - return; - } - - var enableLogging = $("#chkEnableLogging").prop('checked'); - var logQueries = $("#chkLogQueries").prop('checked'); - var useLocalTime = $("#chkUseLocalTime").prop('checked'); - var logFolder = $("#txtLogFolderPath").val(); - var maxLogFileDays = $("#txtMaxLogFileDays").val(); - var maxStatFileDays = $("#txtMaxStatFileDays").val(); - - var recursion = $("input[name=rdRecursion]:checked").val(); - - var recursionDeniedNetworks = cleanTextList($("#txtRecursionDeniedNetworks").val()); - - if ((recursionDeniedNetworks.length === 0) || (recursionDeniedNetworks === ",")) - recursionDeniedNetworks = false; - else - $("#txtRecursionDeniedNetworks").val(recursionDeniedNetworks.replace(/,/g, "\n")); - - var recursionAllowedNetworks = cleanTextList($("#txtRecursionAllowedNetworks").val()); - - if ((recursionAllowedNetworks.length === 0) || (recursionAllowedNetworks === ",")) - recursionAllowedNetworks = false; - else - $("#txtRecursionAllowedNetworks").val(recursionAllowedNetworks.replace(/,/g, "\n")); - - var randomizeName = $("#chkRandomizeName").prop('checked'); - var qnameMinimization = $("#chkQnameMinimization").prop('checked'); - var nsRevalidation = $("#chkNsRevalidation").prop('checked'); - var qpmLimitRequests = $("#txtQpmLimitRequests").val(); if ((qpmLimitRequests == null) || (qpmLimitRequests === "")) { showAlert("warning", "Missing!", "Please enter Queries Per Minute (QPM) request limit value."); @@ -1274,6 +1294,159 @@ function saveDnsSettings() { return; } + var clientTimeout = $("#txtClientTimeout").val(); + if ((clientTimeout == null) || (clientTimeout === "")) { + showAlert("warning", "Missing!", "Please enter a value for Client Timeout."); + $("#txtClientTimeout").focus(); + return; + } + + var tcpSendTimeout = $("#txtTcpSendTimeout").val(); + if ((tcpSendTimeout == null) || (tcpSendTimeout === "")) { + showAlert("warning", "Missing!", "Please enter a value for TCP Send Timeout."); + $("#txtTcpSendTimeout").focus(); + return; + } + + var tcpReceiveTimeout = $("#txtTcpReceiveTimeout").val(); + if ((tcpReceiveTimeout == null) || (tcpReceiveTimeout === "")) { + showAlert("warning", "Missing!", "Please enter a value for TCP Receive Timeout."); + $("#txtTcpReceiveTimeout").focus(); + return; + } + + var quicIdleTimeout = $("#txtQuicIdleTimeout").val(); + if ((quicIdleTimeout == null) || (quicIdleTimeout === "")) { + showAlert("warning", "Missing!", "Please enter a value for QUIC Idle Timeout."); + $("#txtQuicIdleTimeout").focus(); + return; + } + + var quicMaxInboundStreams = $("#txtQuicMaxInboundStreams").val(); + if ((quicMaxInboundStreams == null) || (quicMaxInboundStreams === "")) { + showAlert("warning", "Missing!", "Please enter a value for QUIC Max Inbound Streams."); + $("#txtQuicMaxInboundStreams").focus(); + return; + } + + var listenBacklog = $("#txtListenBacklog").val(); + if ((listenBacklog == null) || (listenBacklog === "")) { + showAlert("warning", "Missing!", "Please enter a value for Listen Backlog."); + $("#txtListenBacklog").focus(); + return; + } + + //web service + var webServiceLocalAddresses = cleanTextList($("#txtWebServiceLocalAddresses").val()); + + if ((webServiceLocalAddresses.length === 0) || (webServiceLocalAddresses === ",")) + webServiceLocalAddresses = "0.0.0.0,[::]"; + else + $("#txtWebServiceLocalAddresses").val(webServiceLocalAddresses.replace(/,/g, "\n")); + + var webServiceHttpPort = $("#txtWebServiceHttpPort").val(); + + if ((webServiceHttpPort === null) || (webServiceHttpPort === "")) + webServiceHttpPort = 5380; + + var webServiceEnableTls = $("#chkWebServiceEnableTls").prop("checked"); + var webServiceHttpToTlsRedirect = $("#chkWebServiceHttpToTlsRedirect").prop("checked"); + var webServiceUseSelfSignedTlsCertificate = $("#chkWebServiceUseSelfSignedTlsCertificate").prop("checked"); + var webServiceTlsPort = $("#txtWebServiceTlsPort").val(); + var webServiceTlsCertificatePath = $("#txtWebServiceTlsCertificatePath").val(); + var webServiceTlsCertificatePassword = $("#txtWebServiceTlsCertificatePassword").val(); + + //optional protocols + var enableDnsOverHttp = $("#chkEnableDnsOverHttp").prop("checked"); + var enableDnsOverTls = $("#chkEnableDnsOverTls").prop("checked"); + var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop("checked"); + var enableDnsOverHttpPort80 = $("#chkEnableDnsOverHttpPort80").prop("checked"); + var enableDnsOverQuic = $("#chkEnableDnsOverQuic").prop("checked"); + + var dnsOverHttpPort = $("#txtDnsOverHttpPort").val(); + if ((dnsOverHttpPort == null) || (dnsOverHttpPort === "")) { + showAlert("warning", "Missing!", "Please enter a value for DNS-over-HTTP Port."); + $("#txtDnsOverHttpPort").focus(); + return; + } + + var dnsOverTlsPort = $("#txtDnsOverTlsPort").val(); + if ((dnsOverTlsPort == null) || (dnsOverTlsPort === "")) { + showAlert("warning", "Missing!", "Please enter a value for DNS-over-TLS Port."); + $("#txtDnsOverTlsPort").focus(); + return; + } + + var dnsOverHttpsPort = $("#txtDnsOverHttpsPort").val(); + if ((dnsOverHttpsPort == null) || (dnsOverHttpsPort === "")) { + showAlert("warning", "Missing!", "Please enter a value for DNS-over-HTTPS Port."); + $("#txtDnsOverHttpsPort").focus(); + return; + } + + var dnsOverQuicPort = $("#txtDnsOverQuicPort").val(); + if ((dnsOverQuicPort == null) || (dnsOverQuicPort === "")) { + showAlert("warning", "Missing!", "Please enter a value for DNS-over-QUIC Port."); + $("#txtDnsOverQuicPort").focus(); + return; + } + + var dnsTlsCertificatePath = $("#txtDnsTlsCertificatePath").val(); + var dnsTlsCertificatePassword = $("#txtDnsTlsCertificatePassword").val(); + + //tsig + var tsigKeys = serializeTableData($("#tableTsigKeys"), 3); + if (tsigKeys === false) + return; + + if (tsigKeys.length === 0) + tsigKeys = false; + + //recursion + var recursion = $("input[name=rdRecursion]:checked").val(); + + var recursionDeniedNetworks = cleanTextList($("#txtRecursionDeniedNetworks").val()); + + if ((recursionDeniedNetworks.length === 0) || (recursionDeniedNetworks === ",")) + recursionDeniedNetworks = false; + else + $("#txtRecursionDeniedNetworks").val(recursionDeniedNetworks.replace(/,/g, "\n")); + + var recursionAllowedNetworks = cleanTextList($("#txtRecursionAllowedNetworks").val()); + + if ((recursionAllowedNetworks.length === 0) || (recursionAllowedNetworks === ",")) + recursionAllowedNetworks = false; + else + $("#txtRecursionAllowedNetworks").val(recursionAllowedNetworks.replace(/,/g, "\n")); + + var randomizeName = $("#chkRandomizeName").prop('checked'); + var qnameMinimization = $("#chkQnameMinimization").prop('checked'); + var nsRevalidation = $("#chkNsRevalidation").prop('checked'); + + var resolverRetries = $("#txtResolverRetries").val(); + if ((resolverRetries == null) || (resolverRetries === "")) { + showAlert("warning", "Missing!", "Please enter a value for Resolver Retries."); + $("#txtResolverRetries").focus(); + return; + } + + var resolverTimeout = $("#txtResolverTimeout").val(); + if ((resolverTimeout == null) || (resolverTimeout === "")) { + showAlert("warning", "Missing!", "Please enter a value for Resolver Timeout."); + $("#txtResolverTimeout").focus(); + return; + } + + var resolverMaxStackCount = $("#txtResolverMaxStackCount").val(); + if ((resolverMaxStackCount == null) || (resolverMaxStackCount === "")) { + showAlert("warning", "Missing!", "Please enter a value for Resolver Max Stack Count."); + $("#txtResolverMaxStackCount").focus(); + return; + } + + //cache + var saveCache = $("#chkSaveCache").prop("checked"); + var serveStale = $("#chkServeStale").prop("checked"); var serveStaleTtl = $("#txtServeStaleTtl").val(); @@ -1340,6 +1513,28 @@ function saveDnsSettings() { return; } + //blocking + var enableBlocking = $("#chkEnableBlocking").prop("checked"); + var allowTxtBlockingReport = $("#chkAllowTxtBlockingReport").prop("checked"); + + var blockingType = $("input[name=rdBlockingType]:checked").val(); + + var customBlockingAddresses = cleanTextList($("#txtCustomBlockingAddresses").val()); + if ((customBlockingAddresses.length === 0) || customBlockingAddresses === ",") + customBlockingAddresses = false; + else + $("#txtCustomBlockingAddresses").val(customBlockingAddresses.replace(/,/g, "\n") + "\n"); + + var blockListUrls = cleanTextList($("#txtBlockListUrls").val()); + + if ((blockListUrls.length === 0) || (blockListUrls === ",")) + blockListUrls = false; + else + $("#txtBlockListUrls").val(blockListUrls.replace(/,/g, "\n") + "\n"); + + var blockListUpdateIntervalHours = $("#txtBlockListUpdateIntervalHours").val(); + + //proxy & forwarders var proxy; var proxyType = $('input[name=rdProxyType]:checked').val().toLowerCase(); if (proxyType === "none") { @@ -1381,43 +1576,55 @@ function saveDnsSettings() { var forwarderProtocol = $('input[name=rdForwarderProtocol]:checked').val(); - var enableBlocking = $("#chkEnableBlocking").prop("checked"); - var allowTxtBlockingReport = $("#chkAllowTxtBlockingReport").prop("checked"); + var forwarderRetries = $("#txtForwarderRetries").val(); + if ((forwarderRetries == null) || (forwarderRetries === "")) { + showAlert("warning", "Missing!", "Please enter a value for Forwarder Retries."); + $("#txtForwarderRetries").focus(); + return; + } - var blockingType = $("input[name=rdBlockingType]:checked").val(); + var forwarderTimeout = $("#txtForwarderTimeout").val(); + if ((forwarderTimeout == null) || (forwarderTimeout === "")) { + showAlert("warning", "Missing!", "Please enter a value for Forwarder Timeout."); + $("#txtForwarderTimeout").focus(); + return; + } - var customBlockingAddresses = cleanTextList($("#txtCustomBlockingAddresses").val()); - if ((customBlockingAddresses.length === 0) || customBlockingAddresses === ",") - customBlockingAddresses = false; - else - $("#txtCustomBlockingAddresses").val(customBlockingAddresses.replace(/,/g, "\n") + "\n"); + var forwarderConcurrency = $("#txtForwarderConcurrency").val(); + if ((forwarderConcurrency == null) || (forwarderConcurrency === "")) { + showAlert("warning", "Missing!", "Please enter a value for Forwarder Concurrency."); + $("#txtForwarderConcurrency").focus(); + return; + } - var blockListUrls = cleanTextList($("#txtBlockListUrls").val()); - - if ((blockListUrls.length === 0) || (blockListUrls === ",")) - blockListUrls = false; - else - $("#txtBlockListUrls").val(blockListUrls.replace(/,/g, "\n") + "\n"); - - var blockListUpdateIntervalHours = $("#txtBlockListUpdateIntervalHours").val(); + //logging + var enableLogging = $("#chkEnableLogging").prop('checked'); + var logQueries = $("#chkLogQueries").prop('checked'); + var useLocalTime = $("#chkUseLocalTime").prop('checked'); + var logFolder = $("#txtLogFolderPath").val(); + var maxLogFileDays = $("#txtMaxLogFileDays").val(); + var maxStatFileDays = $("#txtMaxStatFileDays").val(); + //send request var btn = $("#btnSaveDnsSettings").button('loading'); HTTPRequest({ - url: "/api/settings/set?token=" + sessionData.token + "&dnsServerDomain=" + dnsServerDomain + "&dnsServerLocalEndPoints=" + encodeURIComponent(dnsServerLocalEndPoints) - + "&webServiceLocalAddresses=" + encodeURIComponent(webServiceLocalAddresses) + "&webServiceHttpPort=" + webServiceHttpPort + "&webServiceEnableTls=" + webServiceEnableTls + "&webServiceHttpToTlsRedirect=" + webServiceHttpToTlsRedirect + "&webServiceUseSelfSignedTlsCertificate=" + webServiceUseSelfSignedTlsCertificate + "&webServiceTlsPort=" + webServiceTlsPort + "&webServiceTlsCertificatePath=" + encodeURIComponent(webServiceTlsCertificatePath) + "&webServiceTlsCertificatePassword=" + encodeURIComponent(webServiceTlsCertificatePassword) - + "&enableDnsOverHttp=" + enableDnsOverHttp + "&enableDnsOverTls=" + enableDnsOverTls + "&enableDnsOverHttps=" + enableDnsOverHttps + "&dnsTlsCertificatePath=" + encodeURIComponent(dnsTlsCertificatePath) + "&dnsTlsCertificatePassword=" + encodeURIComponent(dnsTlsCertificatePassword) - + "&tsigKeys=" + encodeURIComponent(tsigKeys) + url: "/api/settings/set", + method: "POST", + data: "token=" + sessionData.token + "&dnsServerDomain=" + dnsServerDomain + "&dnsServerLocalEndPoints=" + encodeURIComponent(dnsServerLocalEndPoints) + "&defaultRecordTtl=" + defaultRecordTtl + "&dnsAppsEnableAutomaticUpdate=" + dnsAppsEnableAutomaticUpdate + "&preferIPv6=" + preferIPv6 + "&udpPayloadSize=" + udpPayloadSize + "&dnssecValidation=" + dnssecValidation + "&eDnsClientSubnet=" + eDnsClientSubnet + "&eDnsClientSubnetIPv4PrefixLength=" + eDnsClientSubnetIPv4PrefixLength + "&eDnsClientSubnetIPv6PrefixLength=" + eDnsClientSubnetIPv6PrefixLength - + "&resolverRetries=" + resolverRetries + "&resolverTimeout=" + resolverTimeout + "&resolverMaxStackCount=" + resolverMaxStackCount - + "&forwarderRetries=" + forwarderRetries + "&forwarderTimeout=" + forwarderTimeout + "&forwarderConcurrency=" + forwarderConcurrency - + "&clientTimeout=" + clientTimeout + "&tcpSendTimeout=" + tcpSendTimeout + "&tcpReceiveTimeout=" + tcpReceiveTimeout - + "&enableLogging=" + enableLogging + "&logQueries=" + logQueries + "&useLocalTime=" + useLocalTime + "&logFolder=" + encodeURIComponent(logFolder) + "&maxLogFileDays=" + maxLogFileDays + "&maxStatFileDays=" + maxStatFileDays - + "&recursion=" + recursion + "&recursionDeniedNetworks=" + encodeURIComponent(recursionDeniedNetworks) + "&recursionAllowedNetworks=" + encodeURIComponent(recursionAllowedNetworks) + "&randomizeName=" + randomizeName + "&qnameMinimization=" + qnameMinimization + "&nsRevalidation=" + nsRevalidation + "&qpmLimitRequests=" + qpmLimitRequests + "&qpmLimitErrors=" + qpmLimitErrors + "&qpmLimitSampleMinutes=" + qpmLimitSampleMinutes + "&qpmLimitIPv4PrefixLength=" + qpmLimitIPv4PrefixLength + "&qpmLimitIPv6PrefixLength=" + qpmLimitIPv6PrefixLength - + "&serveStale=" + serveStale + "&serveStaleTtl=" + serveStaleTtl + "&cacheMaximumEntries=" + cacheMaximumEntries + "&cacheMinimumRecordTtl=" + cacheMinimumRecordTtl + "&cacheMaximumRecordTtl=" + cacheMaximumRecordTtl + "&cacheNegativeRecordTtl=" + cacheNegativeRecordTtl + "&cacheFailureRecordTtl=" + cacheFailureRecordTtl + "&cachePrefetchEligibility=" + cachePrefetchEligibility + "&cachePrefetchTrigger=" + cachePrefetchTrigger + "&cachePrefetchSampleIntervalInMinutes=" + cachePrefetchSampleIntervalInMinutes + "&cachePrefetchSampleEligibilityHitsPerHour=" + cachePrefetchSampleEligibilityHitsPerHour - + proxy + "&forwarders=" + encodeURIComponent(forwarders) + "&forwarderProtocol=" + forwarderProtocol + "&enableBlocking=" + enableBlocking + "&allowTxtBlockingReport=" + allowTxtBlockingReport + "&blockingType=" + blockingType + "&customBlockingAddresses=" + encodeURIComponent(customBlockingAddresses) + "&blockListUrls=" + encodeURIComponent(blockListUrls) + "&blockListUpdateIntervalHours=" + blockListUpdateIntervalHours, + + "&clientTimeout=" + clientTimeout + "&tcpSendTimeout=" + tcpSendTimeout + "&tcpReceiveTimeout=" + tcpReceiveTimeout + "&quicIdleTimeout=" + quicIdleTimeout + "&quicMaxInboundStreams=" + quicMaxInboundStreams + "&listenBacklog=" + listenBacklog + + "&webServiceLocalAddresses=" + encodeURIComponent(webServiceLocalAddresses) + "&webServiceHttpPort=" + webServiceHttpPort + "&webServiceEnableTls=" + webServiceEnableTls + "&webServiceHttpToTlsRedirect=" + webServiceHttpToTlsRedirect + "&webServiceUseSelfSignedTlsCertificate=" + webServiceUseSelfSignedTlsCertificate + "&webServiceTlsPort=" + webServiceTlsPort + "&webServiceTlsCertificatePath=" + encodeURIComponent(webServiceTlsCertificatePath) + "&webServiceTlsCertificatePassword=" + encodeURIComponent(webServiceTlsCertificatePassword) + + "&enableDnsOverHttp=" + enableDnsOverHttp + "&enableDnsOverTls=" + enableDnsOverTls + "&enableDnsOverHttps=" + enableDnsOverHttps + "&enableDnsOverHttpPort80=" + enableDnsOverHttpPort80 + "&enableDnsOverQuic=" + enableDnsOverQuic + "&dnsOverHttpPort=" + dnsOverHttpPort + "&dnsOverTlsPort=" + dnsOverTlsPort + "&dnsOverHttpsPort=" + dnsOverHttpsPort + "&dnsOverQuicPort=" + dnsOverQuicPort + "&dnsTlsCertificatePath=" + encodeURIComponent(dnsTlsCertificatePath) + "&dnsTlsCertificatePassword=" + encodeURIComponent(dnsTlsCertificatePassword) + + "&tsigKeys=" + encodeURIComponent(tsigKeys) + + "&recursion=" + recursion + "&recursionDeniedNetworks=" + encodeURIComponent(recursionDeniedNetworks) + "&recursionAllowedNetworks=" + encodeURIComponent(recursionAllowedNetworks) + "&randomizeName=" + randomizeName + "&qnameMinimization=" + qnameMinimization + "&nsRevalidation=" + nsRevalidation + "&resolverRetries=" + resolverRetries + "&resolverTimeout=" + resolverTimeout + "&resolverMaxStackCount=" + resolverMaxStackCount + + "&saveCache=" + saveCache + "&serveStale=" + serveStale + "&serveStaleTtl=" + serveStaleTtl + "&cacheMaximumEntries=" + cacheMaximumEntries + "&cacheMinimumRecordTtl=" + cacheMinimumRecordTtl + "&cacheMaximumRecordTtl=" + cacheMaximumRecordTtl + "&cacheNegativeRecordTtl=" + cacheNegativeRecordTtl + "&cacheFailureRecordTtl=" + cacheFailureRecordTtl + "&cachePrefetchEligibility=" + cachePrefetchEligibility + "&cachePrefetchTrigger=" + cachePrefetchTrigger + "&cachePrefetchSampleIntervalInMinutes=" + cachePrefetchSampleIntervalInMinutes + "&cachePrefetchSampleEligibilityHitsPerHour=" + cachePrefetchSampleEligibilityHitsPerHour + + "&enableBlocking=" + enableBlocking + "&allowTxtBlockingReport=" + allowTxtBlockingReport + "&blockingType=" + blockingType + "&customBlockingAddresses=" + encodeURIComponent(customBlockingAddresses) + "&blockListUrls=" + encodeURIComponent(blockListUrls) + "&blockListUpdateIntervalHours=" + blockListUpdateIntervalHours + + proxy + "&forwarders=" + encodeURIComponent(forwarders) + "&forwarderProtocol=" + forwarderProtocol + "&forwarderRetries=" + forwarderRetries + "&forwarderTimeout=" + forwarderTimeout + "&forwarderConcurrency=" + forwarderConcurrency + + "&enableLogging=" + enableLogging + "&logQueries=" + logQueries + "&useLocalTime=" + useLocalTime + "&logFolder=" + encodeURIComponent(logFolder) + "&maxLogFileDays=" + maxLogFileDays + "&maxStatFileDays=" + maxStatFileDays, + processData: false, success: function (responseJSON) { document.title = responseJSON.response.dnsServerDomain + " - " + "Technitium DNS Server v" + responseJSON.response.version; $("#lblDnsServerDomain").text(" - " + responseJSON.response.dnsServerDomain); @@ -1425,6 +1632,20 @@ function saveDnsSettings() { $("#txtAddEditRecordTtl").attr("placeholder", responseJSON.response.defaultRecordTtl); + //reload local addresses + var webServiceLocalAddresses = responseJSON.response.webServiceLocalAddresses; + if (webServiceLocalAddresses == null) { + $("#txtWebServiceLocalAddresses").val(""); + } + else { + var value = ""; + + for (var i = 0; i < webServiceLocalAddresses.length; i++) + value += webServiceLocalAddresses[i] + "\r\n"; + + $("#txtWebServiceLocalAddresses").val(value); + } + //reset tls state $("#chkWebServiceEnableTls").prop("checked", responseJSON.response.webServiceEnableTls); $("#chkWebServiceHttpToTlsRedirect").prop("disabled", !responseJSON.response.webServiceEnableTls); @@ -1433,6 +1654,11 @@ function saveDnsSettings() { $("#txtWebServiceTlsCertificatePath").prop("disabled", !responseJSON.response.webServiceEnableTls); $("#txtWebServiceTlsCertificatePassword").prop("disabled", !responseJSON.response.webServiceEnableTls); + //optional protocols + $("#lblDoHHost").text(window.location.hostname + ":" + responseJSON.response.dnsOverHttpPort); + $("#lblDoTHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverTlsPort); + $("#lblDoQHost").text("tls-certificate-domain:" + responseJSON.response.dnsOverQuicPort); + //reload tsig keys $("#tableTsigKeys").html(""); From a460ee529f45eb8734f150431d48282dd0423e30 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:28:54 +0530 Subject: [PATCH 100/191] zone.js: updated code to support QUIC. Updated DNSSEC properties to show "ready by" datetime and key item menu code changes. --- DnsServerCore/www/js/zone.js | 66 ++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/DnsServerCore/www/js/zone.js b/DnsServerCore/www/js/zone.js index fc783dad..f14b9f20 100644 --- a/DnsServerCore/www/js/zone.js +++ b/DnsServerCore/www/js/zone.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 @@ -64,6 +64,7 @@ $(function () { break; case "Tls": + case "Quic": $("#txtAddZoneForwarder").attr("placeholder", "dns.quad9.net (9.9.9.9:853)") break; @@ -2763,6 +2764,7 @@ function updateAddEditFormForwarderPlaceholder() { break; case "Tls": + case "Quic": $("#txtAddEditRecordDataForwarder").attr("placeholder", "dns.quad9.net (9.9.9.9:853)") break; @@ -2899,6 +2901,10 @@ function showEditRecordModal(objBtn) { $("#rdEditRecordDataSoaZoneTransferProtocolTls").prop("checked", true); break; + case "quic": + $("#rdEditRecordDataSoaZoneTransferProtocolQuic").prop("checked", true); + break; + case "tcp": default: $("#rdEditRecordDataSoaZoneTransferProtocolTcp").prop("checked", true); @@ -3952,8 +3958,12 @@ function refreshDnssecProperties(divDnssecPropertiesLoader) { + "
    " + responseJSON.response.dnssecPrivateKeys[i].keyType + "" + responseJSON.response.dnssecPrivateKeys[i].algorithm + "" + responseJSON.response.dnssecPrivateKeys[i].state + "" + moment(responseJSON.response.dnssecPrivateKeys[i].stateChangedOn).local().format("YYYY-MM-DD HH:mm") + ""; + + "" + moment(responseJSON.response.dnssecPrivateKeys[i].stateChangedOn).local().format("YYYY-MM-DD HH:mm"); + + if (responseJSON.response.dnssecPrivateKeys[i].stateReadyBy != null) + tableHtmlRows += "
    (ready by: " + moment(responseJSON.response.dnssecPrivateKeys[i].stateReadyBy).local().format("YYYY-MM-DD HH:mm") + ")"; + + tableHtmlRows += "
    "; if (responseJSON.response.dnssecPrivateKeys[i].keyType === "ZoneSigningKey") { switch (responseJSON.response.dnssecPrivateKeys[i].state) { @@ -3984,15 +3994,19 @@ function refreshDnssecProperties(divDnssecPropertiesLoader) { switch (responseJSON.response.dnssecPrivateKeys[i].state) { case "Generated": - tableHtmlRows += ""; + tableHtmlRows += "
      "; + tableHtmlRows += "
    • Delete
    • "; + tableHtmlRows += "
    "; foundGeneratedKey = true; break; case "Ready": case "Active": if (!responseJSON.response.dnssecPrivateKeys[i].isRetiring) { - tableHtmlRows += ""; - tableHtmlRows += ""; + tableHtmlRows += "
      "; + tableHtmlRows += "
    • Rollover
    • "; + tableHtmlRows += "
    • Retire
    • "; + tableHtmlRows += "
    "; } break; } @@ -4074,16 +4088,17 @@ function updateDnssecPrivateKey(keyTag, objBtn) { }); } -function deleteDnssecPrivateKey(keyTag, objBtn) { - if (!confirm("Are you sure to permanently delete the private key?")) +function deleteDnssecPrivateKey(keyTag, id) { + if (!confirm("Are you sure to permanently delete the private key (" + keyTag + ")?")) return; - var btn = $(objBtn); - var id = btn.attr("data-id"); var divDnssecPropertiesAlert = $("#divDnssecPropertiesAlert"); var zone = $("#lblDnssecPropertiesZoneName").attr("data-zone"); - btn.button('loading'); + var btn = $("#btnDnssecPropertiesDnsKeyRowOption" + id); + var originalBtnHtml = btn.html(); + btn.prop("disabled", true); + btn.html(""); HTTPRequest({ url: "/api/zones/dnssec/properties/deletePrivateKey?token=" + sessionData.token + "&zone=" + zone + "&keyTag=" + keyTag, @@ -4092,7 +4107,8 @@ function deleteDnssecPrivateKey(keyTag, objBtn) { showAlert("success", "Private Key Deleted!", "The DNSSEC private key was deleted successfully.", divDnssecPropertiesAlert); }, error: function () { - btn.button('reset'); + btn.prop("disabled", false); + btn.html(originalBtnHtml); }, invalidToken: function () { $("#modalDnssecProperties").modal("hide"); @@ -4102,15 +4118,17 @@ function deleteDnssecPrivateKey(keyTag, objBtn) { }); } -function rolloverDnssecDnsKey(keyTag, objBtn) { - if (!confirm("Are you sure you want to rollover the DNS Key?")) +function rolloverDnssecDnsKey(keyTag, id) { + if (!confirm("Are you sure you want to rollover the DNS Key (" + keyTag + ")?")) return; - var btn = $(objBtn); var divDnssecPropertiesAlert = $("#divDnssecPropertiesAlert"); var zone = $("#lblDnssecPropertiesZoneName").attr("data-zone"); - btn.button('loading'); + var btn = $("#btnDnssecPropertiesDnsKeyRowOption" + id); + var originalBtnHtml = btn.html(); + btn.prop("disabled", true); + btn.html(""); HTTPRequest({ url: "/api/zones/dnssec/properties/rolloverDnsKey?token=" + sessionData.token + "&zone=" + zone + "&keyTag=" + keyTag, @@ -4119,7 +4137,8 @@ function rolloverDnssecDnsKey(keyTag, objBtn) { showAlert("success", "Rollover Done!", "The DNS Key was rolled over successfully.", divDnssecPropertiesAlert); }, error: function () { - btn.button('reset'); + btn.prop("disabled", false); + btn.html(originalBtnHtml); }, invalidToken: function () { $("#modalDnssecProperties").modal("hide"); @@ -4129,15 +4148,17 @@ function rolloverDnssecDnsKey(keyTag, objBtn) { }); } -function retireDnssecDnsKey(keyTag, objBtn) { - if (!confirm("Are you sure you want to retire the DNS Key?")) +function retireDnssecDnsKey(keyTag, id) { + if (!confirm("Are you sure you want to retire the DNS Key (" + keyTag + ")?")) return; - var btn = $(objBtn); var divDnssecPropertiesAlert = $("#divDnssecPropertiesAlert"); var zone = $("#lblDnssecPropertiesZoneName").attr("data-zone"); - btn.button('loading'); + var btn = $("#btnDnssecPropertiesDnsKeyRowOption" + id); + var originalBtnHtml = btn.html(); + btn.prop("disabled", true); + btn.html(""); HTTPRequest({ url: "/api/zones/dnssec/properties/retireDnsKey?token=" + sessionData.token + "&zone=" + zone + "&keyTag=" + keyTag, @@ -4146,7 +4167,8 @@ function retireDnssecDnsKey(keyTag, objBtn) { showAlert("success", "DNS Key Retired!", "The DNS Key was retired successfully.", divDnssecPropertiesAlert); }, error: function () { - btn.button('reset'); + btn.prop("disabled", false); + btn.html(originalBtnHtml); }, invalidToken: function () { $("#modalDnssecProperties").modal("hide"); From 4c41414aa1511c4423a0186b68ca907809363e01 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:29:22 +0530 Subject: [PATCH 101/191] minor changes --- DnsServerSystemTrayApp/frmAbout.resx | 41 +++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/DnsServerSystemTrayApp/frmAbout.resx b/DnsServerSystemTrayApp/frmAbout.resx index c1e97335..b509627c 100644 --- a/DnsServerSystemTrayApp/frmAbout.resx +++ b/DnsServerSystemTrayApp/frmAbout.resx @@ -57,10 +57,49 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + True + + + True + + + True + + + True + - Copyright (C) 2022 Shreyas Zare (shreyas@technitium.com) + Copyright (C) 2023 Shreyas Zare (shreyas@technitium.com) This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Click link below for details: + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + From ff52ec3653ad51489393675fd4e456920eb34dde Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 15:37:26 +0530 Subject: [PATCH 102/191] updated apidocs --- APIDOCS.md | 199 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 111 insertions(+), 88 deletions(-) diff --git a/APIDOCS.md b/APIDOCS.md index 74028eaa..c889f06c 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -4,6 +4,10 @@ Technitium DNS Server provides a HTTP API which is used by the web console to pe The URL in the documentation uses `localhost` and port `5380`. You should use the hostname/IP address and port that is specific to your DNS server instance. +## API Request + +Unless it is explicitly specified, all HTTP API requests can use both `GET` or `POST` methods. When using `POST` method to pass the API parameters as form data, the `Content-Type` header must be set to `application/x-www-form-urlencoded`. When the HTTP API call is used to upload files, the call must use `POST` method and the `Content-Type` header must be set to `multipart/form-data`. + ## API Response Format The HTTP API returns a JSON formatted response for all requests. The JSON object returned contains `status` property which indicate if the request was successful. @@ -63,7 +67,7 @@ None WHERE: - `user`: The username for the user account. The built-in administrator username on the DNS server is `admin`. - `pass`: The password for the user account. The default password for `admin` user is `admin`. -- `includeInfo`: Includes basic info relevant for the user in response. +- `includeInfo` (optional): Includes basic info relevant for the user in response. WARNING: It is highly recommended to change the password on first use to avoid security related issues. @@ -147,7 +151,7 @@ WHERE: Allows creating a non-expiring API token that can be used with automation scripts to make API calls. The token allows access to API calls with the same privileges as that of the user account. Thus its recommended to create a separate user account with limited permissions as required by the specific task that the token will be used for. The token cannot be used to change the user's password, or update the user profile details. URL:\ -`http://localhost:5380/api/user/createToken?user=admin&pass=admin&tokenName=MyToken1&includeInfo=true` +`http://localhost:5380/api/user/createToken?user=admin&pass=admin&tokenName=MyToken1` PERMISSIONS:\ None @@ -1635,9 +1639,9 @@ WHERE: - `zone`: The domain name for creating the new zone. The value can be valid domain name, an IP address, or an network address in CIDR format. When value is IP address or network address, a reverse zone is created. - `type`: The type of zone to be created. Valid values are [`Primary`, `Secondary`, `Stub`, `Forwarder`]. - `primaryNameServerAddresses` (optional): List of comma separated IP addresses of the primary name server. This optional parameter is used only with Secondary and Stub zones. If this parameter is not used, the DNS server will try to recursively resolve the primary name server addresses automatically. -- `zoneTransferProtocol` (optional): The zone transfer protocol to be used by secondary zones. Valid values are [`Tcp`, `Tls`]. +- `zoneTransferProtocol` (optional): The zone transfer protocol to be used by secondary zones. Valid values are [`Tcp`, `Tls`, `Quic`]. - `tsigKeyName` (optional): The TSIG key name to be used by secondary zones. -- `protocol` (optional): The DNS transport protocol to be used by the conditional forwarder zone. This optional parameter is used with Conditional Forwarder zones. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. Default `Udp` protocol is used when this parameter is missing. +- `protocol` (optional): The DNS transport protocol to be used by the conditional forwarder zone. This optional parameter is used with Conditional Forwarder zones. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. Default `Udp` protocol is used when this parameter is missing. - `forwarder` (optional): The address of the DNS server to be used as a forwarder. This optional parameter is required to be used with Conditional Forwarder zones. A special value `this-server` can be used as a forwarder which when used will forward all the requests internally to this DNS server such that you can override the zone with records and rest of the zone gets resolved via This Server. - `dnssecValidation` (optional): Set this boolean value to indicate if DNSSEC validation must be done. This optional parameter is required to be used with Conditional Forwarder zones. - `proxyType` (optional): The type of proxy that must be used for conditional forwarding. This optional parameter is required to be used with Conditional Forwarder zones. Valid values are [`None`, `Http`, `Socks5`]. Default value `None` is used when this parameter is missing. @@ -2399,7 +2403,7 @@ WHERE: - `tag` (optional): This parameter is required for adding the `CAA` record. - `value` (optional): This parameter is required for adding the `CAA` record. - `aname` (optional): The ANAME domain name. This option is required for adding `ANAME` record. -- `protocol` (optional): This parameter is required for adding the `FWD` record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. +- `protocol` (optional): This parameter is required for adding the `FWD` record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. - `forwarder` (optional): The forwarder address. A special value of `this-server` can be used to directly forward requests internally to the DNS server. This parameter is required for adding the `FWD` record. - `dnssecValidation` (optional): Set this boolean value to indicate if DNSSEC validation must be done. This optional parameter is to be used with FWD records. Default value is `false`. - `proxyType` (optional): The type of proxy that must be used for conditional forwarding. This optional parameter is to be used with FWD records. Valid values are [`None`, `Http`, `Socks5`]. Default value `None` is used when this parameter is missing. @@ -3014,7 +3018,7 @@ WHERE: - `expire` (optional): This is the expire parameter in the SOA record. This parameter is required when updating the SOA record. - `minimum` (optional): This is the minimum parameter in the SOA record. This parameter is required when updating the SOA record. - `primaryAddresses` (optional): This is a comma separated list of IP addresses of the primary name server. This parameter is to be used with secondary and stub zones where the primary name server address is not directly resolvable. -- `zoneTransferProtocol` (optional): The zone transfer protocol to be used by the secondary zone. Valid values are [`Tcp`, `Tls`]. This parameter is used with `SOA` record. +- `zoneTransferProtocol` (optional): The zone transfer protocol to be used by the secondary zone. Valid values are [`Tcp`, `Tls`, `Quic`]. This parameter is used with `SOA` record. - `tsigKeyName` (optional): The TSIG key name to be used by the secondary zone. This parameter is used with `SOA` record. - `ptrName`(optional): The current PTR domain name. This option is required for updating `PTR` record. - `newPtrName`(optional): The new PTR domain name. This option is required for updating `PTR` record. @@ -3063,8 +3067,8 @@ WHERE: - `newValue` (optional): The new value in CAA record. This parameter is required when updating the `CAA` record. - `aname` (optional): The current ANAME domain name. This parameter is required when updating the `ANAME` record. - `newAName` (optional): The new ANAME domain name. This parameter is required when updating the `ANAME` record. -- `protocol` (optional): This is the current protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. -- `newProtocol` (optional): This is the new protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. +- `protocol` (optional): This is the current protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. +- `newProtocol` (optional): This is the new protocol value in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. This parameter is optional and default value `Udp` will be used when updating the `FWD` record. - `forwarder` (optional): The current forwarder address. This parameter is required when updating the `FWD` record. - `newForwarder` (optional): The new forwarder address. This parameter is required when updating the `FWD` record. - `dnssecValidation` (optional): Set this boolean value to indicate if DNSSEC validation must be done. This optional parameter is to be used with FWD records. Default value is `false`. @@ -3155,7 +3159,7 @@ WHERE: - `tag` (optional): This is the tag parameter in the CAA record. This parameter is required when deleting the `CAA` record. - `value` (optional): This parameter is required when deleting the `CAA` record. - `aname` (optional): This parameter is required when deleting the `ANAME` record. -- `protocol` (optional): This is the protocol parameter in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. This parameter is optional and default value `Udp` will be used when deleting the `FWD` record. +- `protocol` (optional): This is the protocol parameter in the FWD record. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. This parameter is optional and default value `Udp` will be used when deleting the `FWD` record. - `forwarder` (optional): This parameter is required when deleting the `FWD` record. RESPONSE: @@ -3998,7 +4002,7 @@ WHERE: - `server`: The name server to query using the DNS client. - `domain`: The domain name to query. - `type`: The type of the query. -- `protocol` (optional): The DNS transport protocol to be used to query. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. The default value of `Udp` is used when the parameter is missing. +- `protocol` (optional): The DNS transport protocol to be used to query. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. The default value of `Udp` is used when the parameter is missing. - `dnssec` (optional): Set to `true` to enable DNSSEC validation. - `import` (optional): This parameter when set to `true` indicates that the response of the DNS query should be imported in the an authoritative zone on this DNS server. Default value is `false` when this parameter is missing. If a zone does not exists, a primary zone for the `domain` name is created and the records from the response are set into the zone. Import can be done only for primary and forwarder type of zones. When `type` is set to AXFR, then the import feature will work as if a zone transfer was requested and the complete zone will be updated as per the zone transfer response. Note that any existing record type for the given `type` will be overwritten when syncing the records. It is recommended to use `recursive-resolver` or the actual name server address for the `server` parameter when importing records. You must have Zones Modify permission to create a zone or Zone Modify permission to import records into an existing zone. @@ -4079,29 +4083,12 @@ RESPONSE: ``` { "response": { - "version": "10.0", + "version": "11.0", "dnsServerDomain": "server1", "dnsServerLocalEndPoints": [ "0.0.0.0:53", "[::]:53" ], - "webServiceLocalAddresses": [ - "0.0.0.0", - "[::]" - ], - "webServiceHttpPort": 5380, - "webServiceEnableTls": false, - "webServiceHttpToTlsRedirect": false, - "webServiceTlsPort": 53443, - "webServiceUseSelfSignedTlsCertificate": false, - "webServiceTlsCertificatePath": "", - "webServiceTlsCertificatePassword": "************", - "enableDnsOverHttp": false, - "enableDnsOverTls": false, - "enableDnsOverHttps": false, - "dnsTlsCertificatePath": null, - "dnsTlsCertificatePassword": "************", - "tsigKeys": [], "defaultRecordTtl": 3600, "dnsAppsEnableAutomaticUpdate": true, "preferIPv6": false, @@ -4110,32 +4097,49 @@ RESPONSE: "eDnsClientSubnet": false, "eDnsClientSubnetIPv4PrefixLength": 24, "eDnsClientSubnetIPv6PrefixLength": 56, - "resolverRetries": 2, - "resolverTimeout": 2000, - "resolverMaxStackCount": 16, - "forwarderRetries": 3, - "forwarderTimeout": 2000, - "forwarderConcurrency": 2, + "qpmLimitRequests": 0, + "qpmLimitErrors": 0, + "qpmLimitSampleMinutes": 5, + "qpmLimitIPv4PrefixLength": 24, + "qpmLimitIPv6PrefixLength": 56, "clientTimeout": 4000, "tcpSendTimeout": 10000, "tcpReceiveTimeout": 10000, - "enableLogging": true, - "logQueries": false, - "useLocalTime": false, - "logFolder": "logs", - "maxLogFileDays": 0, - "maxStatFileDays": 0, + "quicIdleTimeout": 60000, + "quicMaxInboundStreams": 100, + "listenBacklog": 100, + "webServiceLocalAddresses": [ + "[::]" + ], + "webServiceHttpPort": 5380, + "webServiceEnableTls": false, + "webServiceHttpToTlsRedirect": false, + "webServiceUseSelfSignedTlsCertificate": false, + "webServiceTlsPort": 53443, + "webServiceTlsCertificatePath": null, + "webServiceTlsCertificatePassword": "************", + "enableDnsOverHttp": true, + "enableDnsOverTls": true, + "enableDnsOverHttps": true, + "enableDnsOverHttpPort80": true, + "enableDnsOverQuic": false, + "dnsOverHttpPort": 8053, + "dnsOverTlsPort": 853, + "dnsOverHttpsPort": 443, + "dnsOverQuicPort": 853, + "dnsTlsCertificatePath": "z:\\ns2.technitium.com.pfx", + "dnsTlsCertificatePassword": "************", + "tsigKeys": [], "recursion": "AllowOnlyForPrivateNetworks", "recursionDeniedNetworks": [], "recursionAllowedNetworks": [], "randomizeName": true, "qnameMinimization": true, "nsRevalidation": true, - "qpmLimitRequests": 0, - "qpmLimitErrors": 0, - "qpmLimitSampleMinutes": 5, - "qpmLimitIPv4PrefixLength": 24, - "qpmLimitIPv6PrefixLength": 56, + "resolverRetries": 2, + "resolverTimeout": 2000, + "resolverMaxStackCount": 16, + "saveCache": false, "serveStale": true, "serveStaleTtl": 259200, "cacheMaximumEntries": 10000, @@ -4147,15 +4151,24 @@ RESPONSE: "cachePrefetchTrigger": 9, "cachePrefetchSampleIntervalInMinutes": 5, "cachePrefetchSampleEligibilityHitsPerHour": 30, - "proxy": null, - "forwarders": null, - "forwarderProtocol": "Udp", "enableBlocking": true, "allowTxtBlockingReport": true, "blockingType": "AnyAddress", "customBlockingAddresses": [], "blockListUrls": null, - "blockListUpdateIntervalHours": 24 + "blockListUpdateIntervalHours": 24, + "proxy": null, + "forwarders": null, + "forwarderProtocol": "Udp", + "forwarderRetries": 3, + "forwarderTimeout": 2000, + "forwarderConcurrency": 2, + "enableLogging": true, + "logQueries": false, + "useLocalTime": false, + "logFolder": "logs", + "maxLogFileDays": 0, + "maxStatFileDays": 0 }, "status": "ok" } @@ -4178,6 +4191,25 @@ WHERE: - `token`: The session token generated by the `login` or the `createToken` call. - `dnsServerDomain` (optional): The primary domain name used by this DNS Server to identify itself. - `dnsServerLocalEndPoints` (optional): Local end points are the network interface IP addresses and ports you want the DNS Server to listen for requests. +- `defaultRecordTtl` (optional): The default TTL value to use if not specified when adding or updating records in a Zone. +- `dnsAppsEnableAutomaticUpdate` (optional): Set to `true` to allow DNS server to automatically update the DNS Apps from the DNS App Store. The DNS Server will check for updates every 24 hrs when this option is enabled. +- `preferIPv6` (optional): DNS Server will use IPv6 for querying whenever possible with this option enabled. Default value is `false`. +- `udpPayloadSize` (optional): The maximum EDNS UDP payload size that can be used to avoid IP fragmentation. Valid range is 512-4096 bytes. Default value is `1232`. +- `dnssecValidation` (optional): Set this to `true` to enable DNSSEC validation. DNS Server will validate all responses from name servers or forwarders when this option is enabled. +- `eDnsClientSubnet` (optional): Set this to `true` to enable EDNS Client Subnet. DNS Server will use the public IP address of the request with a prefix length, or the existing Client Subnet option from the request while resolving requests. +- `eDnsClientSubnetIPv4PrefixLength` (optional): The EDNS Client Subnet IPv4 prefix length to define the client subnet. Default value is `24`. +- `eDnsClientSubnetIPv6PrefixLength` (optional): The EDNS Client Subnet IPv6 prefix length to define the client subnet. Default value is `56`. +- `qpmLimitRequests` (optional): Sets the Queries Per Minute (QPM) limit on total number of requests that is enforces per client subnet. Set value to `0` to disable the feature. +- `qpmLimitErrors` (optional): Sets the Queries Per Minute (QPM) limit on total number of requests which generates an error response that is enforces per client subnet. Set value to `0` to disable the feature. Response with an RCODE of FormatError, ServerFailure, or Refused is considered as an error response. +- `qpmLimitSampleMinutes` (optional): Sets the client query stats sample size in minutes for QPM limit feature. Default value is `5`. +- `qpmLimitIPv4PrefixLength` (optional): Sets the client subnet IPv4 prefix length used to define the subnet. Default value is `24`. +- `qpmLimitIPv6PrefixLength` (optional): Sets the client subnet IPv6 prefix length used to define the subnet. Default value is `56`. +- `clientTimeout` (optional): The amount of time the DNS server must wait in milliseconds before responding with a ServerFailure response to a client request when no answer is available. Valid range is `1000`-`10000`. Default value is `4000`. +- `tcpSendTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for an ACK before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. Valid range is `1000`-`90000`. Default value is `10000`. +- `tcpReceiveTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for data before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. Valid range is `1000`-`90000`. Default value is `10000`. +- `quicIdleTimeout` (optional): The time interval in milliseconds after which an idle QUIC connection will be closed. This option applies only to QUIC transport protocol. Valid range is `1000`-`90000`. Default value is `60000`. +- `quicMaxInboundStreams` (optional): The max number of inbound bidirectional streams that can be accepted per QUIC connection. This option applies only to QUIC transport protocol. Valid range is `1`-`1000`. Default value is `100`. +- `listenBacklog` (optional): The maximum number of pending connections. This option applies to TCP, TLS, and QUIC transport protocols. Default value is `100`. - `webServiceLocalAddresses` (optional): Local addresses are the network interface IP addresses you want the web service to listen for requests. - `webServiceHttpPort` (optional): Specify the TCP port number for the web console and this API web service. Default value is `5380`. - `webServiceEnableTls` (optional): Set this to `true` to start the HTTPS service to access web service. @@ -4188,43 +4220,25 @@ WHERE: - `enableDnsOverHttp` (optional): Enable this option to accept DNS-over-HTTP requests. It must be used with a TLS terminating reverse proxy like nginx and will work only on private networks. - `enableDnsOverTls` (optional): Enable this option to accept DNS-over-TLS requests. - `enableDnsOverHttps` (optional): Enable this option to accept DNS-over-HTTPS requests. +- `enableDnsOverHttpPort80` (optional): Enable this option to allow automatic TLS certificate renewal with HTTP challenge (webroot) for DNS-over-HTTPS service. This service will not accept DNS-over-HTTP requests from public IP addresses. +- `enableDnsOverQuic` (optional): Enable this option to accept DNS-over-QUIC requests. +- `dnsOverHttpPort` (optional): The TCP port number for DNS-over-HTTP protocol. Default value is `8053`. +- `dnsOverTlsPort` (optional): The TCP port number for DNS-over-TLS protocol. Default value is `853`. +- `dnsOverHttpsPort` (optional): The TCP port number for DNS-over-HTTPS protocol. Default value is `443`. +- `dnsOverQuicPort` (optional): The UDP port number for DNS-over-QUIC protocol. Default value is `853`. - `dnsTlsCertificatePath` (optional): Specify a PKCS #12 certificate (.pfx) file path on the server. The certificate must contain private key. This certificate is used by the DNS-over-TLS and DNS-over-HTTPS optional protocols. - `dnsTlsCertificatePassword` (optional): Enter the certificate (.pfx) password, if any. - `tsigKeys` (optional): A pipe `|` separated multi row list of TSIG key name, shared secret, and algorithm. Set this parameter to `false` to remove all existing keys. Supported algorithms are [`hmac-md5.sig-alg.reg.int`, `hmac-sha1`, `hmac-sha256`, `hmac-sha256-128`, `hmac-sha384`, `hmac-sha384-192`, `hmac-sha512`, `hmac-sha512-256`]. -- `defaultRecordTtl` (optional): The default TTL value to use if not specified when adding or updating records in a Zone. -- `dnsAppsEnableAutomaticUpdate` (optional): Set to `true` to allow DNS server to automatically update the DNS Apps from the DNS App Store. The DNS Server will check for updates every 24 hrs when this option is enabled. -- `preferIPv6` (optional): DNS Server will use IPv6 for querying whenever possible with this option enabled. Default value is `false`. -- `udpPayloadSize` (optional): The maximum EDNS UDP payload size that can be used to avoid IP fragmentation. Valid range is 512-4096 bytes. Default value is `1232`. -- `dnssecValidation` (optional): Set this to `true` to enable DNSSEC validation. DNS Server will validate all responses from name servers or forwarders when this option is enabled. -- `eDnsClientSubnet` (optional): Set this to `true` to enable EDNS Client Subnet. DNS Server will use the public IP address of the request with a prefix length, or the existing Client Subnet option from the request while resolving requests. -- `eDnsClientSubnetIPv4PrefixLength` (optional): The EDNS Client Subnet IPv4 prefix length to define the client subnet. Default value is `24`. -- `eDnsClientSubnetIPv6PrefixLength` (optional): The EDNS Client Subnet IPv6 prefix length to define the client subnet. Default value is `56`. -- `resolverRetries` (optional): The number of retries that the recursive resolver must do. -- `resolverTimeout` (optional): The timeout value in milliseconds for the recursive resolver. -- `resolverMaxStackCount` (optional): The max stack count that the recursive resolver must use. -- `forwarderRetries` (optional): The number of retries that the forwarder DNS client must do. -- `forwarderTimeout` (optional): The timeout value in milliseconds for the forwarder DNS client. -- `forwarderConcurrency` (optional): The number of concurrent requests that the forwarder DNS client should do. -- `clientTimeout` (optional): The amount of time the DNS server must wait in milliseconds before responding with a ServerFailure response to a client request when no answer is available. -- `tcpSendTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for an ACK before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. -- `tcpReceiveTimeout` (optional): The amount of time in milliseconds a TCP socket must wait for data before closing the connection. This option will apply for DNS requests being received by the DNS Server over TCP, TLS, or HTTPS transports. -- `enableLogging` (optional): Enable this option to log error and audit logs into the log file. Default value is `true`. -- `logQueries` (optional): Enable this option to log every query received by this DNS Server and the corresponding response answers into the log file. Default value is `false`. -- `useLocalTime` (optional): Enable this option to use local time instead of UTC for logging. Default value is `false`. -- `logFolder` (optional): The folder path on the server where the log files should be saved. The path can be relative to the DNS server config folder. Default value is `logs`. -- `maxLogFileDays` (optional): Max number of days to keep the log files. Log files older than the specified number of days will be deleted automatically. Recommended value is `365`. Set `0` to disable auto delete. -- `maxStatFileDays` (optional): Max number of days to keep the dashboard stats. Stat files older than the specified number of days will be deleted automatically. Recommended value is `365`. Set `0` to disable auto delete. - `recursion` (optional): Sets the recursion policy for the DNS server. Valid values are [`Deny`, `Allow`, `AllowOnlyForPrivateNetworks`, `UseSpecifiedNetworks`]. - `recursionDeniedNetworks` (optional): A comma separated list of network addresses in CIDR format that must be denied recursion. Set this parameter to `false` to remove existing values. These values are only used when `recursion` is set to `UseSpecifiedNetworks`. - `recursionAllowedNetworks` (optional): A comma separated list of network addresses in CIDR format that must be allowed recursion. Set this parameter to `false` to remove existing values. These values are only used when `recursion` is set to `UseSpecifiedNetworks`. - `randomizeName` (optional): Enables QNAME randomization [draft-vixie-dnsext-dns0x20-00](https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00) when using UDP as the transport protocol. Default value is `true`. - `qnameMinimization` (optional): Enables QNAME minimization [draft-ietf-dnsop-rfc7816bis-04](https://tools.ietf.org/html/draft-ietf-dnsop-rfc7816bis-04) when doing recursive resolution. Default value is `true`. - `nsRevalidation` (optional): Enables [draft-ietf-dnsop-ns-revalidation](https://datatracker.ietf.org/doc/draft-ietf-dnsop-ns-revalidation/) for recursive resolution. Default value is `true`. -- `qpmLimitRequests` (optional): Sets the Queries Per Minute (QPM) limit on total number of requests that is enforces per client subnet. Set value to `0` to disable the feature. -- `qpmLimitErrors` (optional): Sets the Queries Per Minute (QPM) limit on total number of requests which generates an error response that is enforces per client subnet. Set value to `0` to disable the feature. Response with an RCODE of FormatError, ServerFailure, or Refused is considered as an error response. -- `qpmLimitSampleMinutes` (optional): Sets the client query stats sample size in minutes for QPM limit feature. Default value is `5`. -- `qpmLimitIPv4PrefixLength` (optional): Sets the client subnet IPv4 prefix length used to define the subnet. Default value is `24`. -- `qpmLimitIPv6PrefixLength` (optional): Sets the client subnet IPv6 prefix length used to define the subnet. Default value is `56`. +- `resolverRetries` (optional): The number of retries that the recursive resolver must do. +- `resolverTimeout` (optional): The timeout value in milliseconds for the recursive resolver. +- `resolverMaxStackCount` (optional): The max stack count that the recursive resolver must use. +- `saveCache` (optional): Enable this option to save DNS cache on disk when the DNS server stops. The saved cache will be loaded next time the DNS server starts. - `serveStale` (optional): Enable the serve stale feature to improve resiliency by using expired or stale records in cache when the DNS server is unable to reach the upstream or authoritative name servers. Default value is `true`. - `serveStaleTtl` (optional): The TTL value in seconds which should be used for cached records that are expired. When the serve stale TTL too expires for a stale record, it gets removed from the cache. Recommended value is between 1-3 days and maximum supported value is 7 days. Default value is `259200`. - `temporaryDisableBlockingTill` (read only): An ISO 8601 String with the Date and Time when the Temporary Blocking will end. @@ -4236,14 +4250,6 @@ WHERE: - `cachePrefetchTrigger` (optional): A record with TTL value less than trigger value will initiate prefetch operation immediately for itself. Set `0` to disable prefetching & auto prefetching. - `cachePrefetchSampleIntervalInMinutes` (optional): The interval to sample eligible domain names from last hour stats for auto prefetch. - `cachePrefetchSampleEligibilityHitsPerHour` (optional): Minimum required hits per hour for a domain name to be eligible for auto prefetch. -- `proxyType` (optional): The type of proxy protocol to be used. Valid values are [`None`, `Http`, `Socks5`]. -- `proxyAddress` (optional): The proxy server hostname or IP address. -- `proxyPort` (optional): The proxy server port. -- `proxyUsername` (optional): The proxy server username. -- `proxyPassword` (optional): The proxy server password. -- `proxyBypass` (optional): A comma separated bypass list consisting of IP addresses, network addresses in CIDR format, or host/domain names to never use proxy for. -- `forwarders` (optional): A comma separated list of forwarders to be used by this DNS server. Set this parameter to `false` string to remove existing forwarders so that the DNS server does recursive resolution by itself. -- `forwarderProtocol` (optional): The forwarder DNS transport protocol to be used. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. - `enableBlocking` (optional): Sets the DNS server to block domain names using Blocked Zone and Block List Zone. - `allowTxtBlockingReport` (optional): Specifies if the DNS Server should respond with TXT records containing a blocked domain report for TXT type requests. - `blockingType` (optional): Sets how the DNS server should respond to a blocked domain request. Valid values are [`AnyAddress`, `NxDomain`, `CustomAddress`] where `AnyAddress` is default which response with `0.0.0.0` and `::` IP addresses for blocked domains. Using `NxDomain` will respond with `NX Domain` response. `CustomAddress` will return the specified custom blocking addresses. @@ -4251,6 +4257,23 @@ WHERE: - `customBlockingAddresses` (optional): Set the custom blocking addresses to be used for blocked domain response. These addresses are returned only when `blockingType` is set to `CustomAddress`. - `blockListUrls` (optional): A comma separated list of block list URLs that this server must automatically download and use with the block lists zone. DNS Server will use the data returned by the block list URLs to update the block list zone automatically every 24 hours. The expected file format is standard hosts file format or plain text file containing list of domains to block. Set this parameter to `false` to remove existing values. - `blockListUpdateIntervalHours` (optional): The interval in hours to automatically download and update the block lists. Default value is `24`. +- `proxyType` (optional): The type of proxy protocol to be used. Valid values are [`None`, `Http`, `Socks5`]. +- `proxyAddress` (optional): The proxy server hostname or IP address. +- `proxyPort` (optional): The proxy server port. +- `proxyUsername` (optional): The proxy server username. +- `proxyPassword` (optional): The proxy server password. +- `proxyBypass` (optional): A comma separated bypass list consisting of IP addresses, network addresses in CIDR format, or host/domain names to never use proxy for. +- `forwarders` (optional): A comma separated list of forwarders to be used by this DNS server. Set this parameter to `false` string to remove existing forwarders so that the DNS server does recursive resolution by itself. +- `forwarderProtocol` (optional): The forwarder DNS transport protocol to be used. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. +- `forwarderRetries` (optional): The number of retries that the forwarder DNS client must do. +- `forwarderTimeout` (optional): The timeout value in milliseconds for the forwarder DNS client. +- `forwarderConcurrency` (optional): The number of concurrent requests that the forwarder DNS client should do. +- `enableLogging` (optional): Enable this option to log error and audit logs into the log file. Default value is `true`. +- `logQueries` (optional): Enable this option to log every query received by this DNS Server and the corresponding response answers into the log file. Default value is `false`. +- `useLocalTime` (optional): Enable this option to use local time instead of UTC for logging. Default value is `false`. +- `logFolder` (optional): The folder path on the server where the log files should be saved. The path can be relative to the DNS server config folder. Default value is `logs`. +- `maxLogFileDays` (optional): Max number of days to keep the log files. Log files older than the specified number of days will be deleted automatically. Recommended value is `365`. Set `0` to disable auto delete. +- `maxStatFileDays` (optional): Max number of days to keep the dashboard stats. Stat files older than the specified number of days will be deleted automatically. Recommended value is `365`. Set `0` to disable auto delete. RESPONSE: This call returns the newly updated settings in the same format as that of the `getDnsSettings` call. @@ -4736,7 +4759,7 @@ RESPONSE: Adds a reserved lease entry to the specified scope. URL:\ -`http://localhost:5380/api/dhcp/scopes/addReservedLease?token=x` +`http://localhost:5380/api/dhcp/scopes/addReservedLease?token=x&name=Default&hardwareAddress=00:00:00:00:00:00` PERMISSIONS:\ DhcpServer: Modify @@ -4762,7 +4785,7 @@ RESPONSE: Removed a reserved lease entry from the specified scope. URL:\ -`http://localhost:5380/api/dhcp/scopes/removeReservedLease?token=x` +`http://localhost:5380/api/dhcp/scopes/removeReservedLease?token=x&name=Default&hardwareAddress=00:00:00:00:00:00` PERMISSIONS:\ DhcpServer: Modify @@ -5848,7 +5871,7 @@ WHERE: - `start` (optional): The start date time in ISO 8601 format to filter the logs. - `end` (optional): The end date time in ISO 8601 format to filter the logs. - `clientIpAddress` (optional): The client IP address to filter the logs. -- `protocol` (optional): The DNS transport protocol to filter the logs. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`]. +- `protocol` (optional): The DNS transport protocol to filter the logs. Valid values are [`Udp`, `Tcp`, `Tls`, `Https`, `Quic`]. - `responseType` (optional): The DNS server response type to filter the logs. Valid values are [`Authoritative`, `Recursive`, `Cached`, `Blocked`]. - `rcode` (optional): The DNS response code to filter the logs. - `qname` (optional): The query name (QNAME) in the request question section to filter the logs. From 2b7c10861d6379a9e45ebd6e71ba7633b6cbd5ae Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 17:22:05 +0530 Subject: [PATCH 103/191] SecondaryZone: updated CreateAsync() to parse primary name server and convert protocol to zone transfer protocol. Updated RefreshZoneAsync() to explicitly change initial probe name servers to udp. Code refactoring done. --- DnsServerCore/Dns/Zones/SecondaryZone.cs | 79 ++++++++++++++---------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/DnsServerCore/Dns/Zones/SecondaryZone.cs b/DnsServerCore/Dns/Zones/SecondaryZone.cs index 6e70fb9c..f015a6cc 100644 --- a/DnsServerCore/Dns/Zones/SecondaryZone.cs +++ b/DnsServerCore/Dns/Zones/SecondaryZone.cs @@ -100,14 +100,25 @@ namespace DnsServerCore.Dns.Zones DnsQuestionRecord soaQuestion = new DnsQuestionRecord(name, DnsResourceRecordType.SOA, DnsClass.IN); DnsDatagram soaResponse; + NameServerAddress[] primaryNameServers = null; - if (primaryNameServerAddresses == null) + if (string.IsNullOrEmpty(primaryNameServerAddresses)) { soaResponse = await secondaryZone._dnsServer.DirectQueryAsync(soaQuestion); } else { - DnsClient dnsClient = new DnsClient(primaryNameServerAddresses); + primaryNameServers = primaryNameServerAddresses.Split(delegate (string address) + { + NameServerAddress nameServer = NameServerAddress.Parse(address); + + if (nameServer.Protocol != zoneTransferProtocol) + nameServer = nameServer.ChangeProtocol(zoneTransferProtocol); + + return nameServer; + }, ','); + + DnsClient dnsClient = new DnsClient(primaryNameServers); foreach (NameServerAddress nameServerAddress in dnsClient.Servers) { @@ -138,9 +149,7 @@ namespace DnsServerCore.Dns.Zones AuthRecordInfo authRecordInfo = soaRR[0].GetAuthRecordInfo(); - if (!string.IsNullOrEmpty(primaryNameServerAddresses)) - authRecordInfo.PrimaryNameServers = primaryNameServerAddresses.Split(NameServerAddress.Parse, ','); - + authRecordInfo.PrimaryNameServers = primaryNameServers; authRecordInfo.ZoneTransferProtocol = zoneTransferProtocol; authRecordInfo.TsigKeyName = tsigKeyName; @@ -291,7 +300,18 @@ namespace DnsServerCore.Dns.Zones if (!_resync) { - DnsClient client = new DnsClient(primaryNameServers); + //check for update; use UDP transport + List udpNameServers = new List(primaryNameServers.Count); + + foreach (NameServerAddress primaryNameServer in primaryNameServers) + { + if (primaryNameServer.Protocol == DnsTransportProtocol.Udp) + udpNameServers.Add(primaryNameServer); + else + udpNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Udp)); + } + + DnsClient client = new DnsClient(udpNameServers); client.Proxy = _dnsServer.Proxy; client.PreferIPv6 = _dnsServer.PreferIPv6; @@ -339,47 +359,38 @@ namespace DnsServerCore.Dns.Zones } } - //update available; do zone transfer with TLS or TCP transport + //update available; do zone transfer with TLS, QUIC, or TCP transport + List updatedNameServers = new List(primaryNameServers.Count); switch (zoneTransferProtocol) { case DnsTransportProtocol.Tls: case DnsTransportProtocol.Quic: + //change name server protocol to TLS/QUIC + foreach (NameServerAddress primaryNameServer in primaryNameServers) { - //change name server protocol to TLS/QUIC - List updatedNameServers = new List(primaryNameServers.Count); - - foreach (NameServerAddress primaryNameServer in primaryNameServers) - { - if (primaryNameServer.Protocol == zoneTransferProtocol) - updatedNameServers.Add(primaryNameServer); - else - updatedNameServers.Add(primaryNameServer.ChangeProtocol(zoneTransferProtocol)); - } - - primaryNameServers = updatedNameServers; - break; + if (primaryNameServer.Protocol == zoneTransferProtocol) + updatedNameServers.Add(primaryNameServer); + else + updatedNameServers.Add(primaryNameServer.ChangeProtocol(zoneTransferProtocol)); } + break; + default: + //change name server protocol to TCP + foreach (NameServerAddress primaryNameServer in primaryNameServers) { - //change name server protocol to TCP - List updatedNameServers = new List(primaryNameServers.Count); - - foreach (NameServerAddress primaryNameServer in primaryNameServers) - { - if (primaryNameServer.Protocol == DnsTransportProtocol.Tcp) - updatedNameServers.Add(primaryNameServer); - else - updatedNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tcp)); - } - - primaryNameServers = updatedNameServers; - break; + if (primaryNameServer.Protocol == DnsTransportProtocol.Tcp) + updatedNameServers.Add(primaryNameServer); + else + updatedNameServers.Add(primaryNameServer.ChangeProtocol(DnsTransportProtocol.Tcp)); } + + break; } - DnsClient xfrClient = new DnsClient(primaryNameServers); + DnsClient xfrClient = new DnsClient(updatedNameServers); xfrClient.Proxy = _dnsServer.Proxy; xfrClient.PreferIPv6 = _dnsServer.PreferIPv6; From 88b4b6c4ea9d48a21f051e753ce718c7f625ed30 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 17:23:38 +0530 Subject: [PATCH 104/191] StubZone: Updated CreateAsync() to parse and convert primary name servers to udp transport. Code refactoring done. --- DnsServerCore/Dns/Zones/StubZone.cs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/DnsServerCore/Dns/Zones/StubZone.cs b/DnsServerCore/Dns/Zones/StubZone.cs index 90329837..5e21f0e1 100644 --- a/DnsServerCore/Dns/Zones/StubZone.cs +++ b/DnsServerCore/Dns/Zones/StubZone.cs @@ -82,14 +82,25 @@ namespace DnsServerCore.Dns.Zones DnsQuestionRecord soaQuestion = new DnsQuestionRecord(name, DnsResourceRecordType.SOA, DnsClass.IN); DnsDatagram soaResponse; + NameServerAddress[] primaryNameServers = null; - if (primaryNameServerAddresses == null) + if (string.IsNullOrEmpty(primaryNameServerAddresses)) { soaResponse = await stubZone._dnsServer.DirectQueryAsync(soaQuestion); } else { - DnsClient dnsClient = new DnsClient(primaryNameServerAddresses); + primaryNameServers = primaryNameServerAddresses.Split(delegate (string address) + { + NameServerAddress nameServer = NameServerAddress.Parse(address); + + if (nameServer.Protocol != DnsTransportProtocol.Udp) + nameServer = nameServer.ChangeProtocol(DnsTransportProtocol.Udp); + + return nameServer; + }, ','); + + DnsClient dnsClient = new DnsClient(primaryNameServers); foreach (NameServerAddress nameServerAddress in dnsClient.Servers) { @@ -113,8 +124,8 @@ namespace DnsServerCore.Dns.Zones DnsSOARecordData soa = new DnsSOARecordData(receivedSoa.PrimaryNameServer, receivedSoa.ResponsiblePerson, 0u, receivedSoa.Refresh, receivedSoa.Retry, receivedSoa.Expire, receivedSoa.Minimum); DnsResourceRecord[] soaRR = new DnsResourceRecord[] { new DnsResourceRecord(stubZone._name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Refresh, soa) }; - if (!string.IsNullOrEmpty(primaryNameServerAddresses)) - soaRR[0].GetAuthRecordInfo().PrimaryNameServers = primaryNameServerAddresses.Split(NameServerAddress.Parse, ','); + if (primaryNameServers is not null) + soaRR[0].GetAuthRecordInfo().PrimaryNameServers = primaryNameServers; stubZone._entries[DnsResourceRecordType.SOA] = soaRR; @@ -292,8 +303,7 @@ namespace DnsServerCore.Dns.Zones foreach (NameServerAddress nameServer in nameServers) tcpNameServers.Add(nameServer.ChangeProtocol(DnsTransportProtocol.Tcp)); - nameServers = tcpNameServers; - client = new DnsClient(nameServers); + client = new DnsClient(tcpNameServers); client.Proxy = _dnsServer.Proxy; client.PreferIPv6 = _dnsServer.PreferIPv6; From 6a216e881f63dbfd55ab1b5a00e57291cce1cafa Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 17:24:42 +0530 Subject: [PATCH 105/191] WebServiceZonesApi: updated UpdateRecord() to parse SOA primary name servers and convert them to needed transport protocols for secondary and stub zones. --- DnsServerCore/WebServiceZonesApi.cs | 56 ++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index 5d4aeb9d..dc7cfada 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -2483,27 +2483,51 @@ namespace DnsServerCore switch (zoneInfo.Type) { case AuthZoneType.Secondary: - case AuthZoneType.Stub: - if (request.TryGetQueryOrForm("primaryAddresses", out string primaryAddresses)) - newSOARecord.GetAuthRecordInfo().PrimaryNameServers = primaryAddresses.Split(NameServerAddress.Parse, ','); + { + AuthRecordInfo recordInfo = newSOARecord.GetAuthRecordInfo(); + if (request.TryGetQueryOrForm("zoneTransferProtocol", out DnsTransportProtocol zoneTransferProtocol)) + { + if (zoneTransferProtocol == DnsTransportProtocol.Quic) + DnsWebService.ValidateQuicSupport(); + + recordInfo.ZoneTransferProtocol = zoneTransferProtocol; + } + + if (request.TryGetQueryOrForm("primaryAddresses", out string primaryAddresses)) + { + recordInfo.PrimaryNameServers = primaryAddresses.Split(delegate (string address) + { + NameServerAddress nameServer = NameServerAddress.Parse(address); + + if (nameServer.Protocol != zoneTransferProtocol) + nameServer = nameServer.ChangeProtocol(zoneTransferProtocol); + + return nameServer; + }, ','); + } + + if (request.TryGetQueryOrForm("tsigKeyName", out string tsigKeyName)) + recordInfo.TsigKeyName = tsigKeyName; + } break; - } - if (zoneInfo.Type == AuthZoneType.Secondary) - { - AuthRecordInfo recordInfo = newSOARecord.GetAuthRecordInfo(); + case AuthZoneType.Stub: + { + if (request.TryGetQueryOrForm("primaryAddresses", out string primaryAddresses)) + { + newSOARecord.GetAuthRecordInfo().PrimaryNameServers = primaryAddresses.Split(delegate (string address) + { + NameServerAddress nameServer = NameServerAddress.Parse(address); - if (request.TryGetQueryOrForm("zoneTransferProtocol", out DnsTransportProtocol zoneTransferProtocol)) - { - if (zoneTransferProtocol == DnsTransportProtocol.Quic) - DnsWebService.ValidateQuicSupport(); + if (nameServer.Protocol != DnsTransportProtocol.Udp) + nameServer = nameServer.ChangeProtocol(DnsTransportProtocol.Udp); - recordInfo.ZoneTransferProtocol = zoneTransferProtocol; - } - - if (request.TryGetQueryOrForm("tsigKeyName", out string tsigKeyName)) - recordInfo.TsigKeyName = tsigKeyName; + return nameServer; + }, ','); + } + } + break; } if (!string.IsNullOrEmpty(comments)) From e25d5c01b22e6bcefcd4fad05d1f7e37d1fb27cb Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 14 Jan 2023 17:37:18 +0530 Subject: [PATCH 106/191] CacheZoneManager: added log messages for dns cache operations. --- DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs index 75470fc1..cc8b345b 100644 --- a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs @@ -958,6 +958,8 @@ namespace DnsServerCore.Dns.ZoneManagers if (!File.Exists(cacheZoneFile)) return; + + _dnsServer.LogManager?.Write("Loading DNS Cache from disk..."); using (FileStream fS = new FileStream(cacheZoneFile, FileMode.Open, FileAccess.Read)) { @@ -999,6 +1001,8 @@ namespace DnsServerCore.Dns.ZoneManagers public void SaveCacheZoneFile() { + _dnsServer.LogManager?.Write("Saving DNS Cache to disk..."); + string cacheZoneFile = Path.Combine(_dnsServer.ConfigFolder, "cache.bin"); using (FileStream fS = new FileStream(cacheZoneFile, FileMode.Create, FileAccess.Write)) From 0e420e596608e20ec6aab466ffbaabd0275d017f Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 15 Jan 2023 18:32:59 +0530 Subject: [PATCH 107/191] webapp: updated html for minor changes. --- DnsServerCore/www/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index 68705b7d..b193170e 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -1299,7 +1299,7 @@ -
    Note! The DNS server will attempt to save cache to disk when it stops which may take time depending on the cache size. This may cause the server to take a lot of time to stop which may lead to the OS to kill the process causing incomplete cache to be stored on disk.
    +
    Note! The DNS server will attempt to save cache to disk when it stops which may take time depending on the cache size. If the DNS server takes a lot of time to stop then it may lead to the OS killing the DNS server process causing an incomplete cache to be stored on disk.
    @@ -1541,7 +1541,7 @@
    Click the 'Update Now' button to reset the next update schedule and force download and update of the block lists.
    -
    DNS Server will use the data returned by the block list URLs to update the block list zone automatically. The expected file format is standard hosts file format or plain text file containing list of domains to block.
    +
    DNS Server will use the data returned by the block list URLs to update the block list zone automatically. The expected file format is standard hosts file format, plain text file containing list of domains to block, or wildcard block list file format.
    From 78e4cd225373cf8a13c2ba1a7e52042426f49c51 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 15 Jan 2023 18:35:35 +0530 Subject: [PATCH 108/191] CacheZoneManager: updated LoadCacheZoneFile() to avoid loading empty cache zones. --- DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs index cc8b345b..5d4391e5 100644 --- a/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/CacheZoneManager.cs @@ -958,7 +958,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (!File.Exists(cacheZoneFile)) return; - + _dnsServer.LogManager?.Write("Loading DNS Cache from disk..."); using (FileStream fS = new FileStream(cacheZoneFile, FileMode.Open, FileAccess.Read)) @@ -976,12 +976,16 @@ namespace DnsServerCore.Dns.ZoneManagers try { + bool serveStale = _dnsServer.ServeStale; + while (bR.BaseStream.Position < bR.BaseStream.Length) { - CacheZone zone = CacheZone.ReadFrom(bR); - - if (_root.TryAdd(zone.Name, zone)) - addedEntries += zone.TotalEntries; + CacheZone zone = CacheZone.ReadFrom(bR, serveStale); + if (!zone.IsEmpty) + { + if (_root.TryAdd(zone.Name, zone)) + addedEntries += zone.TotalEntries; + } } } finally From d2a1ba6de04520f414703c1b9a4f448ddb8c0d3b Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 15 Jan 2023 18:36:40 +0530 Subject: [PATCH 109/191] CacheZone: updated ReadFrom() and ReadEntriesFrom() to avoid loading stale records and empty RR sets. --- DnsServerCore/Dns/Zones/CacheZone.cs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/DnsServerCore/Dns/Zones/CacheZone.cs b/DnsServerCore/Dns/Zones/CacheZone.cs index 01fdabc2..417836f0 100644 --- a/DnsServerCore/Dns/Zones/CacheZone.cs +++ b/DnsServerCore/Dns/Zones/CacheZone.cs @@ -51,14 +51,14 @@ namespace DnsServerCore.Dns.Zones #region static - public static CacheZone ReadFrom(BinaryReader bR) + public static CacheZone ReadFrom(BinaryReader bR, bool serveStale) { byte version = bR.ReadByte(); switch (version) { case 1: string name = bR.ReadString(); - ConcurrentDictionary> entries = ReadEntriesFrom(bR); + ConcurrentDictionary> entries = ReadEntriesFrom(bR, serveStale); CacheZone cacheZone = new CacheZone(name, entries); @@ -67,15 +67,19 @@ namespace DnsServerCore.Dns.Zones int ecsCount = bR.ReadInt32(); if (ecsCount > 0) { - cacheZone._ecsEntries = new ConcurrentDictionary>>(1, ecsCount); + ConcurrentDictionary>> ecsEntries = new ConcurrentDictionary>>(1, ecsCount); for (int i = 0; i < ecsCount; i++) { NetworkAddress key = NetworkAddress.ReadFrom(bR); - ConcurrentDictionary> ecsEntries = ReadEntriesFrom(bR); + ConcurrentDictionary> ecsEntry = ReadEntriesFrom(bR, serveStale); - cacheZone._ecsEntries.TryAdd(key, ecsEntries); + if (!ecsEntry.IsEmpty) + ecsEntries.TryAdd(key, ecsEntry); } + + if (!ecsEntries.IsEmpty) + cacheZone._ecsEntries = ecsEntries; } } @@ -136,7 +140,7 @@ namespace DnsServerCore.Dns.Zones return records; } - private static ConcurrentDictionary> ReadEntriesFrom(BinaryReader bR) + private static ConcurrentDictionary> ReadEntriesFrom(BinaryReader bR, bool serveStale) { int count = bR.ReadInt32(); ConcurrentDictionary> entries = new ConcurrentDictionary>(1, count); @@ -155,7 +159,8 @@ namespace DnsServerCore.Dns.Zones }); } - entries.TryAdd(key, records); + if (!DnsResourceRecord.IsRRSetExpired(records, serveStale)) + entries.TryAdd(key, records); } return entries; @@ -314,7 +319,7 @@ namespace DnsServerCore.Dns.Zones } } - if (ecsEntry.Value.Count == 0) + if (ecsEntry.Value.IsEmpty) _ecsEntries.TryRemove(ecsEntry.Key, out _); } } @@ -348,7 +353,7 @@ namespace DnsServerCore.Dns.Zones } } - if (ecsEntry.Value.Count == 0) + if (ecsEntry.Value.IsEmpty) _ecsEntries.TryRemove(ecsEntry.Key, out _); } } From 4765eb92d361e0e971d6871ec8821dc9535eab56 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 13:50:41 +0530 Subject: [PATCH 110/191] AdvancedBlockingApp: code refactoring changes done. --- Apps/AdvancedBlockingApp/App.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Apps/AdvancedBlockingApp/App.cs b/Apps/AdvancedBlockingApp/App.cs index 46dd4396..196736fa 100644 --- a/Apps/AdvancedBlockingApp/App.cs +++ b/Apps/AdvancedBlockingApp/App.cs @@ -1004,6 +1004,8 @@ namespace AdvancedBlocking { #region variables + readonly static char[] _popWordSeperator = new char[] { ' ', '\t' }; + IReadOnlyDictionary _listZone = new Dictionary(0); #endregion @@ -1023,9 +1025,9 @@ namespace AdvancedBlocking if (line.Length == 0) return line; - line = line.TrimStart(' ', '\t'); + line = line.TrimStart(_popWordSeperator); - int i = line.IndexOfAny(new char[] { ' ', '\t' }); + int i = line.IndexOfAny(_popWordSeperator); string word; if (i < 0) @@ -1054,6 +1056,7 @@ namespace AdvancedBlocking { //parse hosts file and populate block zone StreamReader sR = new StreamReader(fS, true); + char[] trimSeperator = new char[] { ' ', '\t', '*', '.' }; string line; string firstWord; string secondWord; @@ -1065,7 +1068,7 @@ namespace AdvancedBlocking if (line == null) break; //eof - line = line.TrimStart(' ', '\t', '*', '.'); + line = line.TrimStart(trimSeperator); if (line.Length == 0) continue; //skip empty line From e049616880e22a7f40f7df67451571e09b430b5b Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 13:52:16 +0530 Subject: [PATCH 111/191] AdvancedForwardingApp: added new app for bulk conditional forwarding support. --- .../AdvancedForwardingApp.csproj | 45 + Apps/AdvancedForwardingApp/App.cs | 808 ++++++++++++++++++ .../adguard-upstreams.txt | 10 + Apps/AdvancedForwardingApp/dnsApp.config | 77 ++ 4 files changed, 940 insertions(+) create mode 100644 Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj create mode 100644 Apps/AdvancedForwardingApp/App.cs create mode 100644 Apps/AdvancedForwardingApp/adguard-upstreams.txt create mode 100644 Apps/AdvancedForwardingApp/dnsApp.config diff --git a/Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj b/Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj new file mode 100644 index 00000000..c923bc47 --- /dev/null +++ b/Apps/AdvancedForwardingApp/AdvancedForwardingApp.csproj @@ -0,0 +1,45 @@ + + + + net7.0 + false + 1.0 + Technitium + Technitium DNS Server + Shreyas Zare + AdvancedForwardingApp + AdvancedForwarding + https://technitium.com/dns/ + https://github.com/TechnitiumSoftware/DnsServer + Provides advanced, bulk conditional forwarding options. Supports creating groups based on client's IP address or subnet to enable different conditional forwarding configuration for each group. Supports AdGuard Upstreams config files.\n\nNote: This app works independent of the DNS server's built-in Conditional Forwarder Zones feature. + false + Library + + + + + false + + + + + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll + false + + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll + false + + + + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/Apps/AdvancedForwardingApp/App.cs b/Apps/AdvancedForwardingApp/App.cs new file mode 100644 index 00000000..267fc0e4 --- /dev/null +++ b/Apps/AdvancedForwardingApp/App.cs @@ -0,0 +1,808 @@ +/* +Technitium DNS Server +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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using DnsServerCore.ApplicationCommon; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using TechnitiumLibrary; +using TechnitiumLibrary.Net; +using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.ResourceRecords; +using TechnitiumLibrary.Net.Proxy; + +namespace AdvancedForwarding +{ + public class App : IDnsApplication, IDnsAuthoritativeRequestHandler + { + #region variables + + IDnsServer _dnsServer; + + bool _enableForwarding; + Dictionary _configProxyServers; + Dictionary _configForwarders; + IReadOnlyDictionary _networkGroupMap; + IReadOnlyDictionary _groups; + + #endregion + + #region IDisposable + + public void Dispose() + { + if (_groups is not null) + { + foreach (KeyValuePair group in _groups) + group.Value.Dispose(); + } + } + + #endregion + + #region private + + private static IReadOnlyList GetUpdatedForwarderRecords(IReadOnlyList forwarderRecords, bool dnssecValidation, ConfigProxyServer configProxyServer) + { + List newForwarderRecords = new List(forwarderRecords.Count); + + foreach (DnsForwarderRecordData forwarderRecord in forwarderRecords) + newForwarderRecords.Add(GetForwarderRecord(forwarderRecord.Protocol, forwarderRecord.Forwarder, dnssecValidation, configProxyServer)); + + return newForwarderRecords; + } + + private static DnsForwarderRecordData GetForwarderRecord(NameServerAddress forwarder, bool dnssecValidation, ConfigProxyServer configProxyServer) + { + return GetForwarderRecord(forwarder.Protocol, forwarder.ToString(), dnssecValidation, configProxyServer); + } + + private static DnsForwarderRecordData GetForwarderRecord(DnsTransportProtocol protocol, string forwarder, bool dnssecValidation, ConfigProxyServer configProxyServer) + { + DnsForwarderRecordData forwarderRecord; + + if (configProxyServer is null) + forwarderRecord = new DnsForwarderRecordData(protocol, forwarder, dnssecValidation, NetProxyType.None, null, 0, null, null); + else + forwarderRecord = new DnsForwarderRecordData(protocol, forwarder, dnssecValidation, configProxyServer.Type, configProxyServer.ProxyAddress, configProxyServer.ProxyPort, configProxyServer.ProxyUsername, configProxyServer.ProxyPassword); + + return forwarderRecord; + } + + private Tuple ReadGroup(JsonElement jsonGroup) + { + Group group; + string name = jsonGroup.GetProperty("name").GetString(); + + if ((_groups is not null) && _groups.TryGetValue(name, out group)) + group.ReloadConfig(_configProxyServers, _configForwarders, jsonGroup); + else + group = new Group(_dnsServer, _configProxyServers, _configForwarders, jsonGroup); + + return new Tuple(group.Name, group); + } + + #endregion + + #region public + + public Task InitializeAsync(IDnsServer dnsServer, string config) + { + _dnsServer = dnsServer; + + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; + + _enableForwarding = jsonConfig.GetPropertyValue("enableForwarding", true); + + if (jsonConfig.TryReadArrayAsMap("proxyServers", delegate (JsonElement jsonProxy) + { + ConfigProxyServer proxyServer = new ConfigProxyServer(jsonProxy); + return new Tuple(proxyServer.Name, proxyServer); + }, out Dictionary configProxyServers)) + _configProxyServers = configProxyServers; + else + _configProxyServers = null; + + if (jsonConfig.TryReadArrayAsMap("forwarders", delegate (JsonElement jsonForwarder) + { + ConfigForwarder forwarder = new ConfigForwarder(jsonForwarder, _configProxyServers); + return new Tuple(forwarder.Name, forwarder); + }, out Dictionary configForwarders)) + _configForwarders = configForwarders; + else + _configForwarders = null; + + _networkGroupMap = jsonConfig.ReadObjectAsMap("networkGroupMap", delegate (string network, JsonElement jsonGroup) + { + if (!NetworkAddress.TryParse(network, out NetworkAddress networkAddress)) + throw new FormatException("Network group map contains an invalid network address: " + network); + + return new Tuple(networkAddress, jsonGroup.GetString()); + }); + + if (jsonConfig.TryReadArrayAsMap("groups", ReadGroup, out Dictionary groups)) + { + if (_groups is not null) + { + foreach (KeyValuePair group in _groups) + { + if (!groups.ContainsKey(group.Key)) + group.Value.Dispose(); + } + } + + _groups = groups; + } + else + { + throw new FormatException("Groups array was not defined."); + } + + return Task.CompletedTask; + } + + public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed) + { + if (!_enableForwarding) + return Task.FromResult(null); + + IPAddress remoteIP = remoteEP.Address; + NetworkAddress network = null; + string groupName = null; + + foreach (KeyValuePair entry in _networkGroupMap) + { + if (entry.Key.Contains(remoteIP) && ((network is null) || (entry.Key.PrefixLength > network.PrefixLength))) + { + network = entry.Key; + groupName = entry.Value; + } + } + + if ((groupName is null) || !_groups.TryGetValue(groupName, out Group group) || !group.EnableForwarding) + return Task.FromResult(null); + + DnsQuestionRecord question = request.Question[0]; + string qname = question.Name; + + if (!group.TryGetForwarderRecords(qname, out IReadOnlyList forwarderRecords)) + return Task.FromResult(null); + + DnsResourceRecord[] authority = new DnsResourceRecord[forwarderRecords.Count]; + + for (int i = 0; i < forwarderRecords.Count; i++) + authority[i] = new DnsResourceRecord(qname, DnsResourceRecordType.FWD, DnsClass.IN, 0, forwarderRecords[i]); + + return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, authority)); + } + + #endregion + + #region properties + + public string Description + { get { return "Performs bulk conditional forwarding for configured domain names and AdGuard Upstream config files."; } } + + #endregion + + class Group : IDisposable + { + #region variables + + readonly IDnsServer _dnsServer; + Dictionary _configProxyServers; + Dictionary _configForwarders; + + readonly string _name; + bool _enableForwarding; + IReadOnlyList _forwardings; + IReadOnlyDictionary _adguardUpstreams; + + #endregion + + #region constructor + + public Group(IDnsServer dnsServer, Dictionary configProxyServers, Dictionary configForwarders, JsonElement jsonGroup) + { + _dnsServer = dnsServer; + + _name = jsonGroup.GetProperty("name").GetString(); + + ReloadConfig(configProxyServers, configForwarders, jsonGroup); + } + + #endregion + + #region IDisposable + + public void Dispose() + { + if (_adguardUpstreams is not null) + { + foreach (KeyValuePair adguardUpstream in _adguardUpstreams) + adguardUpstream.Value.Dispose(); + + _adguardUpstreams = null; + } + } + + #endregion + + #region private + + private Tuple ReadAdGuardUpstream(JsonElement jsonAdguardUpstream) + { + AdGuardUpstream adGuardUpstream; + string name = jsonAdguardUpstream.GetProperty("configFile").GetString(); + + if ((_adguardUpstreams is not null) && _adguardUpstreams.TryGetValue(name, out adGuardUpstream)) + adGuardUpstream.ReloadConfig(_configProxyServers, jsonAdguardUpstream); + else + adGuardUpstream = new AdGuardUpstream(_dnsServer, _configProxyServers, jsonAdguardUpstream); + + return new Tuple(adGuardUpstream.Name, adGuardUpstream); + } + + #endregion + + #region public + + public void ReloadConfig(Dictionary configProxyServers, Dictionary configForwarders, JsonElement jsonGroup) + { + _configProxyServers = configProxyServers; + _configForwarders = configForwarders; + + _enableForwarding = jsonGroup.GetPropertyValue("enableForwarding", true); + + if (jsonGroup.TryReadArray("forwardings", delegate (JsonElement jsonForwarding) { return new Forwarding(jsonForwarding, _configForwarders); }, out Forwarding[] forwardings)) + _forwardings = forwardings; + else + _forwardings = null; + + if (jsonGroup.TryReadArrayAsMap("adguardUpstreams", ReadAdGuardUpstream, out Dictionary adguardUpstreams)) + { + if (_adguardUpstreams is not null) + { + foreach (KeyValuePair adguardUpstream in _adguardUpstreams) + { + if (!adguardUpstreams.ContainsKey(adguardUpstream.Key)) + adguardUpstream.Value.Dispose(); + } + } + + _adguardUpstreams = adguardUpstreams; + } + else + { + if (_adguardUpstreams is not null) + { + foreach (KeyValuePair adguardUpstream in _adguardUpstreams) + adguardUpstream.Value.Dispose(); + } + + _adguardUpstreams = null; + } + } + + public bool TryGetForwarderRecords(string domain, out IReadOnlyList forwarderRecords) + { + domain = domain.ToLower(); + + if ((_forwardings is not null) && (_forwardings.Count > 0) && Forwarding.TryGetForwarderRecords(domain, _forwardings, out forwarderRecords)) + return true; + + if (_adguardUpstreams is not null) + { + foreach (KeyValuePair adguardUpstream in _adguardUpstreams) + { + if (adguardUpstream.Value.TryGetForwarderRecords(domain, out forwarderRecords)) + return true; + } + } + + forwarderRecords = null; + return false; + } + + #endregion + + #region properties + + public string Name + { get { return _name; } } + + public bool EnableForwarding + { get { return _enableForwarding; } } + + #endregion + } + + class Forwarding + { + #region variables + + IReadOnlyList _forwarderRecords; + readonly IReadOnlyDictionary _domainMap; + + #endregion + + #region constructor + + public Forwarding(JsonElement jsonForwarding, Dictionary configForwarders) + { + JsonElement jsonForwarders = jsonForwarding.GetProperty("forwarders"); + List forwarderRecords = new List(); + + foreach (JsonElement jsonForwarder in jsonForwarders.EnumerateArray()) + { + string forwarderName = jsonForwarder.GetString(); + + if ((configForwarders is null) || !configForwarders.TryGetValue(forwarderName, out ConfigForwarder configForwarder)) + throw new FormatException("Forwarder was not defined: " + forwarderName); + + forwarderRecords.AddRange(configForwarder.ForwarderRecords); + } + + _forwarderRecords = forwarderRecords; + + _domainMap = jsonForwarding.ReadArrayAsMap("domains", delegate (JsonElement jsonDomain) + { + return new Tuple(jsonDomain.GetString().ToLower(), null); + }); + } + + public Forwarding(IReadOnlyList domains, NameServerAddress forwarder, bool dnssecValidation, ConfigProxyServer proxy) + : this(new DnsForwarderRecordData[] { GetForwarderRecord(forwarder, dnssecValidation, proxy) }, domains) + { } + + public Forwarding(IReadOnlyList forwarderRecords, IReadOnlyList domains) + { + _forwarderRecords = forwarderRecords; + + Dictionary domainMap = new Dictionary(domains.Count); + + foreach (string domain in domains) + { + if (DnsClient.IsDomainNameValid(domain)) + domainMap.TryAdd(domain.ToLower(), null); + } + + _domainMap = domainMap; + } + + #endregion + + #region static + + public static bool TryGetForwarderRecords(string domain, IReadOnlyList forwardings, out IReadOnlyList forwarderRecords) + { + if (forwardings.Count == 1) + { + if (forwardings[0].TryGetForwarderRecords(domain, out forwarderRecords, out _)) + return true; + } + else + { + Dictionary> fwdMap = new Dictionary>(forwardings.Count); + + foreach (Forwarding forwarding in forwardings) + { + if (forwarding.TryGetForwarderRecords(domain, out IReadOnlyList fwdRecords, out string matchedDomain)) + { + if (fwdMap.TryGetValue(matchedDomain, out List fwdRecordsList)) + { + fwdRecordsList.AddRange(fwdRecords); + } + else + { + fwdRecordsList = new List(fwdRecords); + fwdMap.Add(matchedDomain, fwdRecordsList); + } + } + } + + if (fwdMap.Count > 0) + { + forwarderRecords = null; + string lastMatchedDomain = null; + + foreach (KeyValuePair> fwdEntry in fwdMap) + { + if ((lastMatchedDomain is null) || (fwdEntry.Key.Length > lastMatchedDomain.Length) || ((fwdEntry.Key.Length == lastMatchedDomain.Length) && lastMatchedDomain.StartsWith("*."))) + { + lastMatchedDomain = fwdEntry.Key; + forwarderRecords = fwdEntry.Value; + } + } + + return true; + } + } + + forwarderRecords = null; + return false; + } + + #endregion + + #region private + + private static string GetParentZone(string domain) + { + int i = domain.IndexOf('.'); + if (i > -1) + return domain.Substring(i + 1); + + //dont return root zone + return null; + } + + private bool IsDomainBlocked(string domain, out string matchedDomain) + { + string parent; + + do + { + if (_domainMap.TryGetValue(domain, out _)) + { + matchedDomain = domain; + return true; + } + + parent = GetParentZone(domain); + if (parent is null) + break; + + domain = "*." + parent; + + if (_domainMap.TryGetValue(domain, out _)) + { + matchedDomain = domain; + return true; + } + + domain = parent; + } + while (true); + + matchedDomain = null; + return false; + } + + private bool TryGetForwarderRecords(string domain, out IReadOnlyList forwarderRecords, out string matchedDomain) + { + if (IsDomainBlocked(domain, out matchedDomain)) + { + forwarderRecords = _forwarderRecords; + return true; + } + + forwarderRecords = null; + return false; + } + + #endregion + + #region public + + public void UpdateForwarderRecords(bool dnssecValidation, ConfigProxyServer proxy) + { + _forwarderRecords = GetUpdatedForwarderRecords(_forwarderRecords, dnssecValidation, proxy); + } + + #endregion + } + + class AdGuardUpstream : IDisposable + { + #region variables + + readonly IDnsServer _dnsServer; + + readonly string _name; + ConfigProxyServer _configProxyServer; + bool _dnssecValidation; + + IReadOnlyList _defaultForwarderRecords; + IReadOnlyList _forwardings; + + readonly string _configFile; + DateTime _configFileLastModified; + + Timer _autoReloadTimer; + const int AUTO_RELOAD_TIMER_INTERVAL = 60000; + + #endregion + + #region constructor + + public AdGuardUpstream(IDnsServer dnsServer, Dictionary configProxyServers, JsonElement jsonAdguardUpstream) + { + _dnsServer = dnsServer; + + _name = jsonAdguardUpstream.GetProperty("configFile").GetString(); + + _configFile = _name; + + if (!Path.IsPathRooted(_configFile)) + _configFile = Path.Combine(_dnsServer.ApplicationFolder, _configFile); + + _autoReloadTimer = new Timer(delegate (object state) + { + try + { + DateTime configFileLastModified = File.GetLastWriteTimeUtc(_configFile); + if (configFileLastModified > _configFileLastModified) + ReloadUpstreamsFile(); + } + catch (Exception ex) + { + _dnsServer.WriteLog(ex); + } + finally + { + _autoReloadTimer?.Change(AUTO_RELOAD_TIMER_INTERVAL, Timeout.Infinite); + } + }); + + ReloadConfig(configProxyServers, jsonAdguardUpstream); + } + + #endregion + + #region IDisposable + + public void Dispose() + { + if (_autoReloadTimer is not null) + { + _autoReloadTimer.Dispose(); + _autoReloadTimer = null; + } + } + + #endregion + + #region private + + private void ReloadUpstreamsFile() + { + try + { + _dnsServer.WriteLog("The app is reading AdGuard Upstreams config file: " + _configFile); + + List defaultForwarderRecords = new List(); + List forwardings = new List(); + + using (FileStream fS = new FileStream(_configFile, FileMode.Open, FileAccess.Read)) + { + StreamReader sR = new StreamReader(fS, true); + string line; + + while (true) + { + line = sR.ReadLine(); + if (line is null) + break; //eof + + line = line.TrimStart(); + + if (line.Length == 0) + continue; //skip empty line + + if (line.StartsWith("#")) + continue; //skip comment line + + if (line.StartsWith("[")) + { + int i = line.LastIndexOf(']'); + if (i < 0) + throw new FormatException("Invalid AdGuard Upstreams config file format: missing ']' bracket."); + + string[] domains = line.Substring(1, i - 1).Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + string forwarder = line.Substring(i + 1); + + if (forwarder == "#") + { + if (defaultForwarderRecords.Count == 0) + throw new FormatException("Invalid AdGuard Upstreams config file format: missing default upstream servers."); + + forwardings.Add(new Forwarding(defaultForwarderRecords, domains)); + } + else + { + forwardings.Add(new Forwarding(domains, NameServerAddress.Parse(forwarder), _dnssecValidation, _configProxyServer)); + } + } + else + { + defaultForwarderRecords.Add(GetForwarderRecord(NameServerAddress.Parse(line), _dnssecValidation, _configProxyServer)); + } + } + + _configFileLastModified = File.GetLastWriteTimeUtc(fS.SafeFileHandle); + } + + _defaultForwarderRecords = defaultForwarderRecords; + _forwardings = forwardings; + + _dnsServer.WriteLog("The app has successfully loaded AdGuard Upstreams config file: " + _configFile); + } + catch (Exception ex) + { + _dnsServer.WriteLog("The app failed to read AdGuard Upstreams config file: " + _configFile + "\r\n" + ex.ToString()); + } + } + + #endregion + + #region public + + public void ReloadConfig(Dictionary configProxyServers, JsonElement jsonAdguardUpstream) + { + string proxyName = jsonAdguardUpstream.GetPropertyValue("proxy", null); + _dnssecValidation = jsonAdguardUpstream.GetPropertyValue("dnssecValidation", true); + + ConfigProxyServer configProxyServer = null; + + if (!string.IsNullOrEmpty(proxyName) && ((configProxyServers is null) || !configProxyServers.TryGetValue(proxyName, out configProxyServer))) + throw new FormatException("Proxy server was not defined: " + proxyName); + + _configProxyServer = configProxyServer; + + DateTime configFileLastModified = File.GetLastWriteTimeUtc(_configFile); + if (configFileLastModified > _configFileLastModified) + { + //reload complete config file + _autoReloadTimer.Change(0, Timeout.Infinite); + } + else + { + //update only forwarder records + _defaultForwarderRecords = GetUpdatedForwarderRecords(_defaultForwarderRecords, _dnssecValidation, _configProxyServer); + + foreach (Forwarding forwarding in _forwardings) + forwarding.UpdateForwarderRecords(_dnssecValidation, _configProxyServer); + } + } + + public bool TryGetForwarderRecords(string domain, out IReadOnlyList forwarderRecords) + { + if ((_forwardings.Count > 0) && Forwarding.TryGetForwarderRecords(domain, _forwardings, out forwarderRecords)) + return true; + + if (_defaultForwarderRecords.Count > 0) + { + forwarderRecords = _defaultForwarderRecords; + return true; + } + + forwarderRecords = null; + return false; + } + + #endregion + + #region property + + public string Name + { get { return _name; } } + + #endregion + } + + class ConfigProxyServer + { + #region variables + + readonly string _name; + readonly NetProxyType _type; + readonly string _proxyAddress; + readonly ushort _proxyPort; + readonly string _proxyUsername; + readonly string _proxyPassword; + + #endregion + + #region constructor + + public ConfigProxyServer(JsonElement jsonProxy) + { + _name = jsonProxy.GetProperty("name").GetString(); + _type = jsonProxy.GetPropertyEnumValue("type", NetProxyType.Http); + _proxyAddress = jsonProxy.GetProperty("proxyAddress").GetString(); + _proxyPort = jsonProxy.GetProperty("proxyPort").GetUInt16(); + _proxyUsername = jsonProxy.GetPropertyValue("proxyUsername", null); + _proxyPassword = jsonProxy.GetPropertyValue("proxyPassword", null); + } + + #endregion + + #region properties + + public string Name + { get { return _name; } } + + public NetProxyType Type + { get { return _type; } } + + public string ProxyAddress + { get { return _proxyAddress; } } + + public ushort ProxyPort + { get { return _proxyPort; } } + + public string ProxyUsername + { get { return _proxyUsername; } } + + public string ProxyPassword + { get { return _proxyPassword; } } + + #endregion + } + + class ConfigForwarder + { + #region variables + + readonly string _name; + readonly IReadOnlyList _forwarderRecords; + + #endregion + + #region constructor + + public ConfigForwarder(JsonElement jsonForwarder, Dictionary configProxyServers) + { + _name = jsonForwarder.GetProperty("name").GetString(); + + string proxyName = jsonForwarder.GetPropertyValue("proxy", null); + bool dnssecValidation = jsonForwarder.GetPropertyValue("dnssecValidation", true); + DnsTransportProtocol forwarderProtocol = jsonForwarder.GetPropertyEnumValue("forwarderProtocol", DnsTransportProtocol.Udp); + + ConfigProxyServer configProxyServer = null; + + if (!string.IsNullOrEmpty(proxyName) && ((configProxyServers is null) || !configProxyServers.TryGetValue(proxyName, out configProxyServer))) + throw new FormatException("Proxy server was not defined: " + proxyName); + + _forwarderRecords = jsonForwarder.ReadArray("forwarderAddresses", delegate (string address) + { + return GetForwarderRecord(forwarderProtocol, address, dnssecValidation, configProxyServer); + }); + } + + #endregion + + #region properties + + public string Name + { get { return _name; } } + + public IReadOnlyList ForwarderRecords + { get { return _forwarderRecords; } } + + #endregion + } + } +} diff --git a/Apps/AdvancedForwardingApp/adguard-upstreams.txt b/Apps/AdvancedForwardingApp/adguard-upstreams.txt new file mode 100644 index 00000000..77674a51 --- /dev/null +++ b/Apps/AdvancedForwardingApp/adguard-upstreams.txt @@ -0,0 +1,10 @@ +# AdGuard Upstreams +# File Format Reference: https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams +# +# Example: +# 8.8.8.8 +# udp://9.9.9.9 +# [/host.com/example.com/]tls://1.1.1.1 +# [/maps.host.com/]# +# [/home/]192.168.10.2 +# [/test.com/]https://dns.quad9.net/dns-query (9.9.9.9) diff --git a/Apps/AdvancedForwardingApp/dnsApp.config b/Apps/AdvancedForwardingApp/dnsApp.config new file mode 100644 index 00000000..96ca8daf --- /dev/null +++ b/Apps/AdvancedForwardingApp/dnsApp.config @@ -0,0 +1,77 @@ +{ + "enableForwarding": true, + "proxyServers": [ + { + "name": "local-proxy", + "type": "socks5", + "proxyAddress": "localhost", + "proxyPort": 1080, + "proxyUsername": null, + "proxyPassword": null + } + ], + "forwarders": [ + { + "name": "quad9-doh", + "proxy": null, + "dnssecValidation": true, + "forwarderProtocol": "Https", + "forwarderAddresses": [ + "https://dns.quad9.net/dns-query (9.9.9.9)" + ] + }, + { + "name": "cloudflare-google", + "proxy": null, + "dnssecValidation": true, + "forwarderProtocol": "Tls", + "forwarderAddresses": [ + "1.1.1.1", + "8.8.8.8" + ] + }, + { + "name": "quad9-tls-proxied", + "proxy": "local-proxy", + "dnssecValidation": true, + "forwarderProtocol": "Tls", + "forwarderAddresses": [ + "9.9.9.9" + ] + } + ], + "networkGroupMap": { + "0.0.0.0/0": "everyone" + }, + "groups": [ + { + "name": "everyone", + "enableForwarding": true, + "forwardings": [ + { + "forwarders": [ + "quad9-doh" + ], + "domains": [ + "example.com" + ] + }, + { + "forwarders": [ + "cloudflare-google" + ], + "domains": [ + "example.net" + ] + } + ], + "adguardUpstreams": [ + { + "proxy": null, + "dnssecValidation": true, + "configFile": "adguard-upstreams.txt" + } + ] + } + ] +} From c05f8be48ea8ab68873260d2b37daf9352b4afc9 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 13:53:29 +0530 Subject: [PATCH 112/191] BlockPageApp: updated ProcessConnectionAsync() to set a timeout when authenticating SSL connection. --- Apps/BlockPageApp/App.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Apps/BlockPageApp/App.cs b/Apps/BlockPageApp/App.cs index 5d2099d4..1b9a912d 100644 --- a/Apps/BlockPageApp/App.cs +++ b/Apps/BlockPageApp/App.cs @@ -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 @@ -296,13 +296,17 @@ namespace BlockPage if (usingHttps) { SslStream httpsStream = new SslStream(stream); - await httpsStream.AuthenticateAsServerAsync(_webServerTlsCertificate); + await httpsStream.AuthenticateAsServerAsync(_webServerTlsCertificate).WithTimeout(TCP_RECV_TIMEOUT); stream = httpsStream; } await ProcessHttpRequestAsync(stream, remoteEP, usingHttps); } + catch (TimeoutException) + { + //ignore timeout exception on TLS auth + } catch (IOException) { //ignore IO exceptions @@ -313,8 +317,7 @@ namespace BlockPage } finally { - if (socket is not null) - socket.Dispose(); + socket.Dispose(); } } From 84ba6bd5bcbcfd04f64c61b2a5da7ec0daaaab86 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 13:54:06 +0530 Subject: [PATCH 113/191] Dns64App: code refactoring changes. --- Apps/Dns64App/App.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/Dns64App/App.cs b/Apps/Dns64App/App.cs index 043ed0cb..cda85da5 100644 --- a/Apps/Dns64App/App.cs +++ b/Apps/Dns64App/App.cs @@ -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 @@ -216,7 +216,7 @@ namespace Dns64 if ((groupName is null) || !_groups.TryGetValue(groupName, out Group group) || !group.EnableDns64) return Task.FromResult(null); - IPAddress ipv6Address = IPAddressExtension.ParseReverseDomain(question.Name); + IPAddress ipv6Address = IPAddressExtensions.ParseReverseDomain(question.Name); if (ipv6Address.AddressFamily != AddressFamily.InterNetworkV6) return Task.FromResult(null); From b1d04329794d28559be44dd50261bfef6711445d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:10:39 +0530 Subject: [PATCH 114/191] DnsBlockListApp: added new app to allow running DNSBL. --- Apps/DnsBlockListApp/App.cs | 813 ++++++++++++++++++++ Apps/DnsBlockListApp/DnsBlockListApp.csproj | 48 ++ Apps/DnsBlockListApp/dnsApp.config | 20 + Apps/DnsBlockListApp/domain-blocklist.txt | 10 + Apps/DnsBlockListApp/ip-blocklist.txt | 13 + 5 files changed, 904 insertions(+) create mode 100644 Apps/DnsBlockListApp/App.cs create mode 100644 Apps/DnsBlockListApp/DnsBlockListApp.csproj create mode 100644 Apps/DnsBlockListApp/dnsApp.config create mode 100644 Apps/DnsBlockListApp/domain-blocklist.txt create mode 100644 Apps/DnsBlockListApp/ip-blocklist.txt diff --git a/Apps/DnsBlockListApp/App.cs b/Apps/DnsBlockListApp/App.cs new file mode 100644 index 00000000..956aeaf6 --- /dev/null +++ b/Apps/DnsBlockListApp/App.cs @@ -0,0 +1,813 @@ +/* +Technitium DNS Server +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 +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +*/ + +using DnsServerCore.ApplicationCommon; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using TechnitiumLibrary; +using TechnitiumLibrary.Net; +using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.ResourceRecords; + +namespace DnsBlockList +{ + //DNS Blacklists and Whitelists + //https://www.rfc-editor.org/rfc/rfc5782 + + public class App : IDnsApplication, IDnsAppRecordRequestHandler + { + #region variables + + IDnsServer _dnsServer; + + IReadOnlyDictionary _dnsBlockLists; + + #endregion + + #region IDisposable + + public void Dispose() + { + if (_dnsBlockLists is not null) + { + foreach (KeyValuePair dnsBlockList in _dnsBlockLists) + dnsBlockList.Value.Dispose(); + + _dnsBlockLists = null; + } + } + + #endregion + + #region private + + private static bool TryParseDnsblDomain(string qName, string appRecordName, out IPAddress address, out string domain) + { + qName = qName.Substring(0, qName.Length - appRecordName.Length - 1); + + string[] parts = qName.Split('.'); + string lastPart = parts[parts.Length - 1]; + + if (byte.TryParse(lastPart, out _) || byte.TryParse(lastPart, NumberStyles.HexNumber, null, out _)) + { + switch (parts.Length) + { + case 4: + { + byte[] buffer = new byte[4]; + + for (int i = 0, j = parts.Length - 1; (i < 4) && (j > -1); i++, j--) + buffer[i] = byte.Parse(parts[j]); + + address = new IPAddress(buffer); + domain = null; + return true; + } + + case 32: + { + byte[] buffer = new byte[16]; + + for (int i = 0, j = parts.Length - 1; (i < 16) && (j > 0); i++, j -= 2) + buffer[i] = (byte)(byte.Parse(parts[j], NumberStyles.HexNumber) << 4 | byte.Parse(parts[j - 1], NumberStyles.HexNumber)); + + address = new IPAddress(buffer); + domain = null; + return true; + } + + default: + address = null; + domain = null; + return false; + } + } + else + { + address = null; + domain = lastPart; + + for (int i = parts.Length - 2; i > -1; i--) + domain = parts[i] + "." + domain; + + return true; + } + } + + private Tuple ReadBlockList(JsonElement jsonBlockList) + { + BlockList blockList; + string name = jsonBlockList.GetProperty("name").GetString(); + BlockListType type = jsonBlockList.GetPropertyEnumValue("type", BlockListType.Ip); + + if ((_dnsBlockLists is not null) && _dnsBlockLists.TryGetValue(name, out BlockList existingBlockList) && (existingBlockList.Type == type)) + { + existingBlockList.ReloadConfig(jsonBlockList); + blockList = existingBlockList; + } + else + { + switch (type) + { + case BlockListType.Ip: + blockList = new IpBlockList(_dnsServer, jsonBlockList); + break; + + case BlockListType.Domain: + blockList = new DomainBlockList(_dnsServer, jsonBlockList); + break; + + default: + throw new NotSupportedException("DNSBL block list type is not supported: " + type.ToString()); + } + } + + return new Tuple(blockList.Name, blockList); + } + + #endregion + + #region public + + public Task InitializeAsync(IDnsServer dnsServer, string config) + { + _dnsServer = dnsServer; + + using JsonDocument jsonDocument = JsonDocument.Parse(config); + JsonElement jsonConfig = jsonDocument.RootElement; + + if (jsonConfig.TryReadArrayAsMap("dnsBlockLists", ReadBlockList, out Dictionary dnsBlockLists)) + { + if (_dnsBlockLists is not null) + { + foreach (KeyValuePair dnsBlockList in _dnsBlockLists) + { + if (!dnsBlockLists.ContainsKey(dnsBlockList.Key)) + dnsBlockList.Value.Dispose(); + } + } + + _dnsBlockLists = dnsBlockLists; + } + else + { + if (_dnsBlockLists is not null) + { + foreach (KeyValuePair dnsBlockList in _dnsBlockLists) + dnsBlockList.Value.Dispose(); + } + + _dnsBlockLists = null; + } + + return Task.CompletedTask; + } + + public async Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) + { + DnsQuestionRecord question = request.Question[0]; + string qname = question.Name; + + if (qname.Length == appRecordName.Length) + return null; + + if ((_dnsBlockLists is null) || !TryParseDnsblDomain(qname, appRecordName, out IPAddress address, out string domain)) + return null; + + using JsonDocument jsonDocument = JsonDocument.Parse(appRecordData); + JsonElement jsonAppRecordData = jsonDocument.RootElement; + + if (jsonAppRecordData.TryReadArray("dnsBlockLists", out string[] dnsBlockLists)) + { + bool isBlocked = false; + IPAddress responseA = null; + string responseTXT = null; + + if (address is not null) + { + foreach (string dnsBlockList in dnsBlockLists) + { + if (_dnsBlockLists.TryGetValue(dnsBlockList, out BlockList blockList) && blockList.Enabled && (blockList.Type == BlockListType.Ip) && blockList.IsBlocked(address, out responseA, out responseTXT)) + { + isBlocked = true; + + if (!string.IsNullOrEmpty(responseTXT)) + responseTXT = responseTXT.Replace("{ip}", address.ToString()); + + break; + } + } + } + else if (domain is not null) + { + foreach (string dnsBlockList in dnsBlockLists) + { + if (_dnsBlockLists.TryGetValue(dnsBlockList, out BlockList blockList) && blockList.Enabled && (blockList.Type == BlockListType.Domain) && blockList.IsBlocked(domain, out string foundDomain, out responseA, out responseTXT)) + { + isBlocked = true; + + if (!string.IsNullOrEmpty(responseTXT)) + responseTXT = responseTXT.Replace("{domain}", foundDomain); + + break; + } + } + } + + if (isBlocked) + { + switch (question.Type) + { + case DnsResourceRecordType.A: + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.A, question.Class, appRecordTtl, new DnsARecordData(responseA)) }); + + case DnsResourceRecordType.TXT: + if (!string.IsNullOrEmpty(responseTXT)) + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { new DnsResourceRecord(qname, DnsResourceRecordType.TXT, question.Class, appRecordTtl, new DnsTXTRecordData(responseTXT)) }); + + break; + } + + //NODATA response + DnsDatagram soaResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(zoneName, DnsResourceRecordType.SOA, DnsClass.IN)); + + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, soaResponse.Answer); + } + } + + return null; + } + + #endregion + + #region properties + + public string Description + { get { return "Returns A or TXT records based on the DNS Block Lists (DNSBL) configured in the APP record data. Returns NXDOMAIN response when an IP address or domain name is not blocked in any of the configured blocklists."; } } + + public string ApplicationRecordDataTemplate + { + get + { + return @"{ + ""dnsBlockLists"": [ + ""ipblocklist1"", + ""domainblocklist1"" + ] +}"; + } + } + + #endregion + + enum BlockListType + { + Ip = 1, + Domain = 2 + } + + abstract class BlockList : IDisposable + { + #region variables + + protected static readonly char[] _popWordSeperator = new char[] { ' ', '\t', '|' }; + + protected readonly IDnsServer _dnsServer; + readonly BlockListType _type; + + readonly string _name; + bool _enabled; + protected IPAddress _responseA; + protected string _responseTXT; + protected string _blockListFile; + + protected DateTime _blockListFileLastModified; + + Timer _autoReloadTimer; + const int AUTO_RELOAD_TIMER_INTERVAL = 60000; + + #endregion + + #region constructor + + protected BlockList(IDnsServer dnsServer, BlockListType type, JsonElement jsonBlockList) + { + _dnsServer = dnsServer; + _type = type; + + _name = jsonBlockList.GetProperty("name").GetString(); + + _autoReloadTimer = new Timer(delegate (object state) + { + try + { + DateTime blockListFileLastModified = File.GetLastWriteTimeUtc(_blockListFile); + if (blockListFileLastModified > _blockListFileLastModified) + ReloadBlockListFile(); + } + catch (Exception ex) + { + _dnsServer.WriteLog(ex); + } + finally + { + _autoReloadTimer?.Change(AUTO_RELOAD_TIMER_INTERVAL, Timeout.Infinite); + } + }); + + ReloadConfig(jsonBlockList); + } + + #endregion + + #region IDisposable + + public void Dispose() + { + if (_autoReloadTimer is not null) + { + _autoReloadTimer.Dispose(); + _autoReloadTimer = null; + } + } + + #endregion + + #region protected + + protected abstract void ReloadBlockListFile(); + + protected static string PopWord(ref string line) + { + if (line.Length == 0) + return line; + + line = line.TrimStart(_popWordSeperator); + + int i = line.IndexOfAny(_popWordSeperator); + string word; + + if (i < 0) + { + word = line; + line = ""; + } + else + { + word = line.Substring(0, i); + line = line.Substring(i + 1); + } + + return word; + } + + #endregion + + #region public + + public void ReloadConfig(JsonElement jsonBlockList) + { + _enabled = jsonBlockList.GetPropertyValue("enabled", true); + _responseA = IPAddress.Parse(jsonBlockList.GetPropertyValue("responseA", "127.0.0.2")); + + if (jsonBlockList.TryGetProperty("responseTXT", out JsonElement jsonResponseTXT)) + _responseTXT = jsonResponseTXT.GetString(); + else + _responseTXT = null; + + string blockListFile = jsonBlockList.GetProperty("blockListFile").GetString(); + + if (!Path.IsPathRooted(blockListFile)) + blockListFile = Path.Combine(_dnsServer.ApplicationFolder, blockListFile); + + if (!blockListFile.Equals(_blockListFile)) + { + _blockListFile = blockListFile; + _blockListFileLastModified = default; + } + + _autoReloadTimer.Change(0, Timeout.Infinite); + } + + public virtual bool IsBlocked(IPAddress address, out IPAddress responseA, out string responseTXT) + { + throw new InvalidOperationException(); + } + + public virtual bool IsBlocked(string domain, out string foundDomain, out IPAddress responseA, out string responseTXT) + { + throw new InvalidOperationException(); + } + + #endregion + + #region properties + + public BlockListType Type + { get { return _type; } } + + public string Name + { get { return _name; } } + + public bool Enabled + { get { return _enabled; } } + + public IPAddress ResponseA + { get { return _responseA; } } + + public string ResponseTXT + { get { return _responseTXT; } } + + public string BlockListFile + { get { return _blockListFile; } } + + #endregion + } + + class BlockEntry + { + #region variables + + readonly T _key; + readonly IPAddress _responseA; + readonly string _responseTXT; + + #endregion + + #region constructor + + public BlockEntry(T key, string responseA, string responseTXT) + { + _key = key; + + if (IPAddress.TryParse(responseA, out IPAddress addr)) + _responseA = addr; + + if (!string.IsNullOrEmpty(responseTXT)) + _responseTXT = responseTXT; + } + + #endregion + + #region properties + + public T Key + { get { return _key; } } + + public IPAddress ResponseA + { get { return _responseA; } } + + public string ResponseTXT + { get { return _responseTXT; } } + + #endregion + } + + class IpBlockList : BlockList + { + #region variables + + Dictionary> _ipv4Map; + Dictionary> _ipv6Map; + NetworkMap> _ipv4NetworkMap; + NetworkMap> _ipv6NetworkMap; + + #endregion + + #region constructor + + public IpBlockList(IDnsServer dnsServer, JsonElement jsonBlockList) + : base(dnsServer, BlockListType.Ip, jsonBlockList) + { } + + #endregion + + #region protected + + protected override void ReloadBlockListFile() + { + try + { + _dnsServer.WriteLog("The app is reading IP block list file: " + _blockListFile); + + //parse ip block list file + Queue> ipv4Addresses = new Queue>(); + Queue> ipv6Addresses = new Queue>(); + Queue> ipv4Networks = new Queue>(); + Queue> ipv6Networks = new Queue>(); + + ipv4Addresses.Enqueue(new BlockEntry(IPAddress.Parse("127.0.0.2"), "127.0.0.2", "rfc5782 test entry")); + ipv6Addresses.Enqueue(new BlockEntry(IPAddress.Parse("::FFFF:7F00:2"), "127.0.0.2", "rfc5782 test entry")); + + using (FileStream fS = new FileStream(_blockListFile, FileMode.Open, FileAccess.Read)) + { + StreamReader sR = new StreamReader(fS, true); + string line; + string network; + string responseA; + string responseTXT; + + while (true) + { + line = sR.ReadLine(); + if (line is null) + break; //eof + + line = line.TrimStart(_popWordSeperator); + + if (line.Length == 0) + continue; //skip empty line + + if (line.StartsWith("#")) + continue; //skip comment line + + network = PopWord(ref line); + responseA = PopWord(ref line); + responseTXT = line; + + if (NetworkAddress.TryParse(network, out NetworkAddress networkAddress)) + { + switch (networkAddress.AddressFamily) + { + case AddressFamily.InterNetwork: + if (networkAddress.PrefixLength == 32) + ipv4Addresses.Enqueue(new BlockEntry(networkAddress.Address, responseA, responseTXT)); + else + ipv4Networks.Enqueue(new BlockEntry(networkAddress, responseA, responseTXT)); + + break; + + case AddressFamily.InterNetworkV6: + if (networkAddress.PrefixLength == 128) + ipv6Addresses.Enqueue(new BlockEntry(networkAddress.Address, responseA, responseTXT)); + else + ipv6Networks.Enqueue(new BlockEntry(networkAddress, responseA, responseTXT)); + + break; + } + } + } + + _blockListFileLastModified = File.GetLastWriteTimeUtc(fS.SafeFileHandle); + } + + //load ip lookup list + Dictionary> ipv4AddressMap = new Dictionary>(ipv4Addresses.Count); + + while (ipv4Addresses.Count > 0) + { + BlockEntry entry = ipv4Addresses.Dequeue(); + ipv4AddressMap.TryAdd(entry.Key, entry); + } + + Dictionary> ipv6AddressMap = new Dictionary>(ipv6Addresses.Count); + + while (ipv6Addresses.Count > 0) + { + BlockEntry entry = ipv6Addresses.Dequeue(); + ipv6AddressMap.TryAdd(entry.Key, entry); + } + + NetworkMap> ipv4NetworkMap = new NetworkMap>(ipv4Networks.Count); + + while (ipv4Networks.Count > 0) + { + BlockEntry entry = ipv4Networks.Dequeue(); + ipv4NetworkMap.Add(entry.Key, entry); + } + + NetworkMap> ipv6NetworkMap = new NetworkMap>(ipv6Networks.Count); + + while (ipv6Networks.Count > 0) + { + BlockEntry entry = ipv6Networks.Dequeue(); + ipv6NetworkMap.Add(entry.Key, entry); + } + + //update + _ipv4Map = ipv4AddressMap; + _ipv6Map = ipv6AddressMap; + _ipv4NetworkMap = ipv4NetworkMap; + _ipv6NetworkMap = ipv6NetworkMap; + + _dnsServer.WriteLog("The app has successfully loaded IP block list file: " + _blockListFile); + } + catch (Exception ex) + { + _dnsServer.WriteLog("The app failed to read IP block list file: " + _blockListFile + "\r\n" + ex.ToString()); + } + } + + #endregion + + #region public + + public override bool IsBlocked(IPAddress address, out IPAddress responseA, out string responseTXT) + { + switch (address.AddressFamily) + { + case AddressFamily.InterNetwork: + { + if (_ipv4Map.TryGetValue(address, out BlockEntry ipEntry)) + { + responseA = ipEntry.ResponseA is null ? _responseA : ipEntry.ResponseA; + responseTXT = ipEntry.ResponseTXT is null ? _responseTXT : ipEntry.ResponseTXT; + return true; + } + + if (_ipv4NetworkMap.TryGetValue(address, out BlockEntry networkEntry)) + { + responseA = networkEntry.ResponseA is null ? _responseA : networkEntry.ResponseA; + responseTXT = networkEntry.ResponseTXT is null ? _responseTXT : networkEntry.ResponseTXT; + return true; + } + } + break; + + case AddressFamily.InterNetworkV6: + { + if (_ipv6Map.TryGetValue(address, out BlockEntry ipEntry)) + { + responseA = ipEntry.ResponseA is null ? _responseA : ipEntry.ResponseA; + responseTXT = ipEntry.ResponseTXT is null ? _responseTXT : ipEntry.ResponseTXT; + return true; + } + + if (_ipv6NetworkMap.TryGetValue(address, out BlockEntry networkEntry)) + { + responseA = networkEntry.ResponseA is null ? _responseA : networkEntry.ResponseA; + responseTXT = networkEntry.ResponseTXT is null ? _responseTXT : networkEntry.ResponseTXT; + return true; + } + } + break; + } + + responseA = null; + responseTXT = null; + return false; + } + + #endregion + } + + class DomainBlockList : BlockList + { + #region variables + + Dictionary> _domainMap; + + #endregion + + #region constructor + + public DomainBlockList(IDnsServer dnsServer, JsonElement jsonIpBlockList) + : base(dnsServer, BlockListType.Domain, jsonIpBlockList) + { } + + #endregion + + #region protected + + protected override void ReloadBlockListFile() + { + try + { + _dnsServer.WriteLog("The app is reading domain block list file: " + _blockListFile); + + //parse ip block list file + Queue> domains = new Queue>(); + + domains.Enqueue(new BlockEntry("test", "127.0.0.2", "rfc5782 test entry")); + + using (FileStream fS = new FileStream(_blockListFile, FileMode.Open, FileAccess.Read)) + { + StreamReader sR = new StreamReader(fS, true); + char[] trimSeperator = new char[] { ' ', '\t', ':', '|', ',' }; + string line; + string domain; + string responseA; + string responseTXT; + + while (true) + { + line = sR.ReadLine(); + if (line is null) + break; //eof + + line = line.TrimStart(trimSeperator); + + if (line.Length == 0) + continue; //skip empty line + + if (line.StartsWith("#")) + continue; //skip comment line + + domain = PopWord(ref line); + responseA = PopWord(ref line); + responseTXT = line; + + if (DnsClient.IsDomainNameValid(domain)) + domains.Enqueue(new BlockEntry(domain.ToLower(), responseA, responseTXT)); + } + + _blockListFileLastModified = File.GetLastWriteTimeUtc(fS.SafeFileHandle); + } + + //load ip lookup list + Dictionary> domainMap = new Dictionary>(domains.Count); + + while (domains.Count > 0) + { + BlockEntry entry = domains.Dequeue(); + domainMap.TryAdd(entry.Key, entry); + } + + //update + _domainMap = domainMap; + + _dnsServer.WriteLog("The app has successfully loaded domain block list file: " + _blockListFile); + } + catch (Exception ex) + { + _dnsServer.WriteLog("The app failed to read domain block list file: " + _blockListFile + "\r\n" + ex.ToString()); + } + } + + #endregion + + #region private + + private static string GetParentZone(string domain) + { + int i = domain.IndexOf('.'); + if (i > -1) + return domain.Substring(i + 1); + + //dont return root zone + return null; + } + + private bool IsDomainBlocked(string domain, out BlockEntry domainEntry) + { + do + { + if (_domainMap.TryGetValue(domain, out domainEntry)) + { + return true; + } + + domain = GetParentZone(domain); + } + while (domain is not null); + + return false; + } + + #endregion + + #region public + + public override bool IsBlocked(string domain, out string foundDomain, out IPAddress responseA, out string responseTXT) + { + if (IsDomainBlocked(domain.ToLower(), out BlockEntry domainEntry)) + { + foundDomain = domainEntry.Key; + responseA = domainEntry.ResponseA is null ? _responseA : domainEntry.ResponseA; + responseTXT = domainEntry.ResponseTXT is null ? _responseTXT : domainEntry.ResponseTXT; + return true; + } + + foundDomain = null; + responseA = null; + responseTXT = null; + return false; + } + + #endregion + } + } +} diff --git a/Apps/DnsBlockListApp/DnsBlockListApp.csproj b/Apps/DnsBlockListApp/DnsBlockListApp.csproj new file mode 100644 index 00000000..02c9578a --- /dev/null +++ b/Apps/DnsBlockListApp/DnsBlockListApp.csproj @@ -0,0 +1,48 @@ + + + + net7.0 + false + 1.0 + Technitium + Technitium DNS Server + Shreyas Zare + DnsBlockListApp + DnsBlockList + https://technitium.com/dns/ + https://github.com/TechnitiumSoftware/DnsServer + Allows creating APP records in primary and forwarder zones that can return A or TXT records based on the DNS Block Lists (DNSBL) configured. The implementation is based on RFC 5782. + false + Library + + + + + false + + + + + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll + false + + + ..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll + false + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/Apps/DnsBlockListApp/dnsApp.config b/Apps/DnsBlockListApp/dnsApp.config new file mode 100644 index 00000000..0a58cb61 --- /dev/null +++ b/Apps/DnsBlockListApp/dnsApp.config @@ -0,0 +1,20 @@ +{ + "dnsBlockLists": [ + { + "name": "ipblocklist1", + "type": "ip", + "enabled": true, + "responseA": "127.0.0.2", + "responseTXT": "https://example.com/dnsbl?ip={ip}", + "blockListFile": "ip-blocklist.txt" + }, + { + "name": "domainblocklist1", + "type": "domain", + "enabled": true, + "responseA": "127.0.0.2", + "responseTXT": "https://example.com/dnsbl?domain={domain}", + "blockListFile": "domain-blocklist.txt" + } + ] +} \ No newline at end of file diff --git a/Apps/DnsBlockListApp/domain-blocklist.txt b/Apps/DnsBlockListApp/domain-blocklist.txt new file mode 100644 index 00000000..f7fc3007 --- /dev/null +++ b/Apps/DnsBlockListApp/domain-blocklist.txt @@ -0,0 +1,10 @@ +# DNSBL domain block list +# Format: domain A-response TXT-response +# Seperator: , , or char +# +# A-response & TXT-response are optional but A-response must exists when TXT-response is specified +# +# Examples: +# example.com +# example.net 127.0.0.4 +# malware.com 127.0.0.4 malware see: https://example.com/dnsbl?domain={domain} diff --git a/Apps/DnsBlockListApp/ip-blocklist.txt b/Apps/DnsBlockListApp/ip-blocklist.txt new file mode 100644 index 00000000..6da722d1 --- /dev/null +++ b/Apps/DnsBlockListApp/ip-blocklist.txt @@ -0,0 +1,13 @@ +# DNSBL IP block list +# Format: ip/network A-response TXT-response +# Seperator: , , or char +# +# A-response & TXT-response are optional but A-response must exists when TXT-response is specified. +# Supports both IPv4 and IPv6 addresses. +# +# Examples: +# 192.168.1.1 +# 192.168.0.0/24 +# 192.168.2.1 127.0.0.3 +# 10.8.1.0/24 127.0.0.3 malware see: https://example.com/dnsbl?ip={ip} +# 2001:db8::/64 From d099080ec42682410b4d449ca07daa407ad701bc Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:11:49 +0530 Subject: [PATCH 115/191] FailoverApp: minor code refactoring changes done. --- Apps/FailoverApp/HealthService.cs | 13 ++++++++++--- Apps/FailoverApp/dnsApp.config | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Apps/FailoverApp/HealthService.cs b/Apps/FailoverApp/HealthService.cs index 67b26511..99536d0d 100644 --- a/Apps/FailoverApp/HealthService.cs +++ b/Apps/FailoverApp/HealthService.cs @@ -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 @@ -333,9 +333,16 @@ namespace Failover foreach (JsonElement jsonNetwork in jsonUnderMaintenance.EnumerateArray()) { string network = jsonNetwork.GetProperty("network").GetString(); - bool enable = jsonNetwork.GetProperty("enable").GetBoolean(); + bool enabled; - _underMaintenance.TryAdd(NetworkAddress.Parse(network), enable); + if (jsonNetwork.TryGetProperty("enabled", out JsonElement jsonEnabled)) + enabled = jsonEnabled.GetBoolean(); + else if (jsonNetwork.TryGetProperty("enable", out JsonElement jsonEnable)) + enabled = jsonEnable.GetBoolean(); + else + enabled = true; + + _underMaintenance.TryAdd(NetworkAddress.Parse(network), enabled); } } } diff --git a/Apps/FailoverApp/dnsApp.config b/Apps/FailoverApp/dnsApp.config index f4954e9b..ced9d001 100644 --- a/Apps/FailoverApp/dnsApp.config +++ b/Apps/FailoverApp/dnsApp.config @@ -89,11 +89,11 @@ "underMaintenance": [ { "network": "192.168.10.2/32", - "enable": false + "enabled": false }, { "network": "10.1.1.0/24", - "enable": false + "enabled": false } ] } \ No newline at end of file From 9c1a5e60efa9d7b042d774cd7d39f60fa3cc1ba2 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:12:35 +0530 Subject: [PATCH 116/191] SplitHorizonApp: code refactoring changes. --- Apps/SplitHorizonApp/AddressTranslation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Apps/SplitHorizonApp/AddressTranslation.cs b/Apps/SplitHorizonApp/AddressTranslation.cs index ca7d81a1..8bcc9715 100644 --- a/Apps/SplitHorizonApp/AddressTranslation.cs +++ b/Apps/SplitHorizonApp/AddressTranslation.cs @@ -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 @@ -291,7 +291,7 @@ namespace SplitHorizon if ((groupName is null) || !_groups.TryGetValue(groupName, out Group group) || !group.Enabled || !group.TranslateReverseLookups) return Task.FromResult(null); - IPAddress ptrIpAddress = IPAddressExtension.ParseReverseDomain(question.Name); + IPAddress ptrIpAddress = IPAddressExtensions.ParseReverseDomain(question.Name); if (!group.InternalToExternalTranslation.TryGetValue(ptrIpAddress, out IPAddress externalIp)) return Task.FromResult(null); From 7f2e2c27209c77fbf683ba176b6113e30d74c31d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:22:12 +0530 Subject: [PATCH 117/191] WildIpApp: updated app to respond with NODATA when no address was parsed to avoid NXDOMAIN response by the dns server. --- Apps/WildIpApp/App.cs | 44 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/Apps/WildIpApp/App.cs b/Apps/WildIpApp/App.cs index 274a22bc..2c637fd4 100644 --- a/Apps/WildIpApp/App.cs +++ b/Apps/WildIpApp/App.cs @@ -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 @@ -28,6 +28,12 @@ namespace WildIp { public class App : IDnsApplication, IDnsAppRecordRequestHandler { + #region variables + + IDnsServer _dnsServer; + + #endregion + #region IDisposable public void Dispose() @@ -41,18 +47,19 @@ namespace WildIp public Task InitializeAsync(IDnsServer dnsServer, string config) { - //do nothing + _dnsServer = dnsServer; + return Task.CompletedTask; } - public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) + public async Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData) { string qname = request.Question[0].Name; if (qname.Length == appRecordName.Length) - return Task.FromResult(null); + return null; - DnsResourceRecord answer; + DnsResourceRecord answer = null; switch (request.Question[0].Type) { @@ -69,12 +76,8 @@ namespace WildIp rawIp[i++] = x; } - if (i < 4) - return Task.FromResult(null); - - IPAddress address = new IPAddress(rawIp); - - answer = new DnsResourceRecord(request.Question[0].Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(address)); + if (i == 4) + answer = new DnsResourceRecord(request.Question[0].Name, DnsResourceRecordType.A, DnsClass.IN, appRecordTtl, new DnsARecordData(new IPAddress(rawIp))); } break; @@ -90,18 +93,21 @@ namespace WildIp break; } - if (address is null) - return Task.FromResult(null); - - answer = new DnsResourceRecord(request.Question[0].Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address)); + if (address is not null) + answer = new DnsResourceRecord(request.Question[0].Name, DnsResourceRecordType.AAAA, DnsClass.IN, appRecordTtl, new DnsAAAARecordData(address)); } break; - - default: - return Task.FromResult(null); } - return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { answer })); + if (answer is null) + { + //NODATA reponse + DnsDatagram soaResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(zoneName, DnsResourceRecordType.SOA, DnsClass.IN)); + + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, soaResponse.Answer); + } + + return new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, new DnsResourceRecord[] { answer }); } #endregion From 50cf6fdf2ef4c537db1bd512b3c9ebf562707295 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:26:18 +0530 Subject: [PATCH 118/191] code refactoring changes. --- DnsServerCore/Auth/User.cs | 8 ++--- DnsServerCore/Auth/UserSession.cs | 2 +- DnsServerCore/Dhcp/Lease.cs | 4 +-- .../Options/ClasslessStaticRouteOption.cs | 4 +-- DnsServerCore/Dhcp/Scope.cs | 30 +++++++++---------- DnsServerCore/Dns/StatsManager.cs | 10 +++---- DnsServerCore/Dns/Zones/AuthZoneInfo.cs | 6 ++-- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/DnsServerCore/Auth/User.cs b/DnsServerCore/Auth/User.cs index 32b6fd60..1a8b37b1 100644 --- a/DnsServerCore/Auth/User.cs +++ b/DnsServerCore/Auth/User.cs @@ -92,9 +92,9 @@ namespace DnsServerCore.Auth _sessionTimeoutSeconds = bR.ReadInt32(); _previousSessionLoggedOn = bR.ReadDateTime(); - _previousSessionRemoteAddress = IPAddressExtension.ReadFrom(bR); + _previousSessionRemoteAddress = IPAddressExtensions.ReadFrom(bR); _recentSessionLoggedOn = bR.ReadDateTime(); - _recentSessionRemoteAddress = IPAddressExtension.ReadFrom(bR); + _recentSessionRemoteAddress = IPAddressExtensions.ReadFrom(bR); { int count = bR.ReadByte(); @@ -223,9 +223,9 @@ namespace DnsServerCore.Auth bW.Write(_sessionTimeoutSeconds); bW.Write(_previousSessionLoggedOn); - IPAddressExtension.WriteTo(_previousSessionRemoteAddress, bW); + IPAddressExtensions.WriteTo(_previousSessionRemoteAddress, bW); bW.Write(_recentSessionLoggedOn); - IPAddressExtension.WriteTo(_recentSessionRemoteAddress, bW); + IPAddressExtensions.WriteTo(_recentSessionRemoteAddress, bW); bW.Write(Convert.ToByte(_memberOfGroups.Count)); diff --git a/DnsServerCore/Auth/UserSession.cs b/DnsServerCore/Auth/UserSession.cs index 8aefa269..12f19b12 100644 --- a/DnsServerCore/Auth/UserSession.cs +++ b/DnsServerCore/Auth/UserSession.cs @@ -88,7 +88,7 @@ namespace DnsServerCore.Auth _user = authManager.GetUser(bR.ReadShortString()); _lastSeen = bR.ReadDateTime(); - _lastSeenRemoteAddress = IPAddressExtension.ReadFrom(bR); + _lastSeenRemoteAddress = IPAddressExtensions.ReadFrom(bR); _lastSeenUserAgent = bR.ReadShortString(); if (_lastSeenUserAgent.Length == 0) diff --git a/DnsServerCore/Dhcp/Lease.cs b/DnsServerCore/Dhcp/Lease.cs index 0635844e..89737bfc 100644 --- a/DnsServerCore/Dhcp/Lease.cs +++ b/DnsServerCore/Dhcp/Lease.cs @@ -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 @@ -88,7 +88,7 @@ namespace DnsServerCore.Dhcp _hostName = null; _hardwareAddress = bR.ReadBuffer(); - _address = IPAddressExtension.ReadFrom(bR); + _address = IPAddressExtensions.ReadFrom(bR); if (version >= 2) { diff --git a/DnsServerCore/Dhcp/Options/ClasslessStaticRouteOption.cs b/DnsServerCore/Dhcp/Options/ClasslessStaticRouteOption.cs index e59fe1cf..50dc25b5 100644 --- a/DnsServerCore/Dhcp/Options/ClasslessStaticRouteOption.cs +++ b/DnsServerCore/Dhcp/Options/ClasslessStaticRouteOption.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2021 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 @@ -109,7 +109,7 @@ namespace DnsServerCore.Dhcp.Options s.ReadBytes(destinationBuffer, 0, Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(subnetMaskWidth) / 8))); _destination = new IPAddress(destinationBuffer); - _subnetMask = IPAddressExtension.GetSubnetMask(subnetMaskWidth); + _subnetMask = IPAddressExtensions.GetSubnetMask(subnetMaskWidth); _router = new IPAddress(s.ReadBytes(4)); } diff --git a/DnsServerCore/Dhcp/Scope.cs b/DnsServerCore/Dhcp/Scope.cs index 9ff638a7..b33db552 100644 --- a/DnsServerCore/Dhcp/Scope.cs +++ b/DnsServerCore/Dhcp/Scope.cs @@ -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 @@ -136,7 +136,7 @@ namespace DnsServerCore.Dhcp _name = bR.ReadShortString(); _enabled = bR.ReadBoolean(); - ChangeNetwork(IPAddressExtension.ReadFrom(bR), IPAddressExtension.ReadFrom(bR), IPAddressExtension.ReadFrom(bR)); + ChangeNetwork(IPAddressExtensions.ReadFrom(bR), IPAddressExtensions.ReadFrom(bR), IPAddressExtensions.ReadFrom(bR)); _leaseTimeDays = bR.ReadUInt16(); _leaseTimeHours = bR.ReadByte(); @@ -175,7 +175,7 @@ namespace DnsServerCore.Dhcp if (version >= 2) { - _serverAddress = IPAddressExtension.ReadFrom(bR); + _serverAddress = IPAddressExtensions.ReadFrom(bR); if (_serverAddress.Equals(IPAddress.Any)) _serverAddress = null; } @@ -191,7 +191,7 @@ namespace DnsServerCore.Dhcp _bootFileName = null; } - _routerAddress = IPAddressExtension.ReadFrom(bR); + _routerAddress = IPAddressExtensions.ReadFrom(bR); if (_routerAddress.Equals(IPAddress.Any)) _routerAddress = null; @@ -209,7 +209,7 @@ namespace DnsServerCore.Dhcp IPAddress[] dnsServers = new IPAddress[count]; for (int i = 0; i < count; i++) - dnsServers[i] = IPAddressExtension.ReadFrom(bR); + dnsServers[i] = IPAddressExtensions.ReadFrom(bR); _dnsServers = dnsServers; } @@ -223,7 +223,7 @@ namespace DnsServerCore.Dhcp IPAddress[] winsServers = new IPAddress[count]; for (int i = 0; i < count; i++) - winsServers[i] = IPAddressExtension.ReadFrom(bR); + winsServers[i] = IPAddressExtensions.ReadFrom(bR); _winsServers = winsServers; } @@ -236,7 +236,7 @@ namespace DnsServerCore.Dhcp IPAddress[] ntpServers = new IPAddress[count]; for (int i = 0; i < count; i++) - ntpServers[i] = IPAddressExtension.ReadFrom(bR); + ntpServers[i] = IPAddressExtensions.ReadFrom(bR); _ntpServers = ntpServers; } @@ -296,7 +296,7 @@ namespace DnsServerCore.Dhcp IPAddress[] capwapAcIpAddresses = new IPAddress[count]; for (int i = 0; i < count; i++) - capwapAcIpAddresses[i] = IPAddressExtension.ReadFrom(bR); + capwapAcIpAddresses[i] = IPAddressExtensions.ReadFrom(bR); _capwapAcIpAddresses = capwapAcIpAddresses; } @@ -310,7 +310,7 @@ namespace DnsServerCore.Dhcp IPAddress[] tftpServerAddreses = new IPAddress[count]; for (int i = 0; i < count; i++) - tftpServerAddreses[i] = IPAddressExtension.ReadFrom(bR); + tftpServerAddreses[i] = IPAddressExtensions.ReadFrom(bR); _tftpServerAddreses = tftpServerAddreses; } @@ -343,7 +343,7 @@ namespace DnsServerCore.Dhcp Exclusion[] exclusions = new Exclusion[count]; for (int i = 0; i < count; i++) - exclusions[i] = new Exclusion(IPAddressExtension.ReadFrom(bR), IPAddressExtension.ReadFrom(bR)); + exclusions[i] = new Exclusion(IPAddressExtensions.ReadFrom(bR), IPAddressExtensions.ReadFrom(bR)); _exclusions = exclusions; } @@ -992,12 +992,12 @@ namespace DnsServerCore.Dhcp return null; } - offerAddress = IPAddressExtension.ConvertNumberToIp(_startingAddress.ConvertIpToNumber() - 1u); + offerAddress = IPAddressExtensions.ConvertNumberToIp(_startingAddress.ConvertIpToNumber() - 1u); offerAddressWasResetFromEnd = true; continue; } - offerAddress = IPAddressExtension.ConvertNumberToIp(nextOfferAddressNumber); + offerAddress = IPAddressExtensions.ConvertNumberToIp(nextOfferAddressNumber); AddressStatus addressStatus = await IsAddressAvailableAsync(offerAddress); if (addressStatus.IsAddressAvailable) @@ -1372,13 +1372,13 @@ namespace DnsServerCore.Dhcp if (broadcastAddressNumber == endingAddressNumber) throw new ArgumentException("Ending address cannot be same as the broadcast address."); - _networkAddress = IPAddressExtension.ConvertNumberToIp(networkAddressNumber); - _broadcastAddress = IPAddressExtension.ConvertNumberToIp(broadcastAddressNumber); + _networkAddress = IPAddressExtensions.ConvertNumberToIp(networkAddressNumber); + _broadcastAddress = IPAddressExtensions.ConvertNumberToIp(broadcastAddressNumber); _lastAddressOfferedLock.Wait(); try { - _lastAddressOffered = IPAddressExtension.ConvertNumberToIp(startingAddressNumber - 1u); + _lastAddressOffered = IPAddressExtensions.ConvertNumberToIp(startingAddressNumber - 1u); } finally { diff --git a/DnsServerCore/Dns/StatsManager.cs b/DnsServerCore/Dns/StatsManager.cs index 148b4753..d5a308a5 100644 --- a/DnsServerCore/Dns/StatsManager.cs +++ b/DnsServerCore/Dns/StatsManager.cs @@ -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 @@ -1388,7 +1388,7 @@ namespace DnsServerCore.Dns _clientIpAddresses = new ConcurrentDictionary(1, count); for (int i = 0; i < count; i++) - _clientIpAddresses.TryAdd(IPAddressExtension.ReadFrom(bR), new Counter(bR.ReadInt32())); + _clientIpAddresses.TryAdd(IPAddressExtensions.ReadFrom(bR), new Counter(bR.ReadInt32())); if (version < 6) _totalClients = count; @@ -1413,7 +1413,7 @@ namespace DnsServerCore.Dns _errorIpAddresses = new ConcurrentDictionary(1, count); for (int i = 0; i < count; i++) - _errorIpAddresses.TryAdd(IPAddressExtension.ReadFrom(bR), new Counter(bR.ReadInt32())); + _errorIpAddresses.TryAdd(IPAddressExtensions.ReadFrom(bR), new Counter(bR.ReadInt32())); } else { @@ -1465,7 +1465,7 @@ namespace DnsServerCore.Dns _clientIpAddresses = new ConcurrentDictionary(1, count); for (int i = 0; i < count; i++) - _clientIpAddresses.TryAdd(IPAddressExtension.ReadFrom(bR), new Counter(bR.ReadInt64())); + _clientIpAddresses.TryAdd(IPAddressExtensions.ReadFrom(bR), new Counter(bR.ReadInt64())); } { @@ -1481,7 +1481,7 @@ namespace DnsServerCore.Dns _errorIpAddresses = new ConcurrentDictionary(1, count); for (int i = 0; i < count; i++) - _errorIpAddresses.TryAdd(IPAddressExtension.ReadFrom(bR), new Counter(bR.ReadInt64())); + _errorIpAddresses.TryAdd(IPAddressExtensions.ReadFrom(bR), new Counter(bR.ReadInt64())); } break; diff --git a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs index 6d0b6bd4..18432d9f 100644 --- a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs +++ b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs @@ -117,7 +117,7 @@ namespace DnsServerCore.Dns.Zones IPAddress[] nameServers = new IPAddress[count]; for (int i = 0; i < count; i++) - nameServers[i] = IPAddressExtension.ReadFrom(bR); + nameServers[i] = IPAddressExtensions.ReadFrom(bR); _zoneTransferNameServers = nameServers; } @@ -132,7 +132,7 @@ namespace DnsServerCore.Dns.Zones IPAddress[] nameServers = new IPAddress[count]; for (int i = 0; i < count; i++) - nameServers[i] = IPAddressExtension.ReadFrom(bR); + nameServers[i] = IPAddressExtensions.ReadFrom(bR); _notifyNameServers = nameServers; } @@ -148,7 +148,7 @@ namespace DnsServerCore.Dns.Zones IPAddress[] ipAddresses = new IPAddress[count]; for (int i = 0; i < count; i++) - ipAddresses[i] = IPAddressExtension.ReadFrom(bR); + ipAddresses[i] = IPAddressExtensions.ReadFrom(bR); _updateIpAddresses = ipAddresses; } From ba48a63eb1607c69f9490e580168a70c4b2b099e Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:28:16 +0530 Subject: [PATCH 119/191] AuthZoneManager: split ListAllRecords() into ListAllZoneRecords() and ListAllRecords() for different usages. Code refactoring done. --- .../Dns/ZoneManagers/AuthZoneManager.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs index f55d5c23..a504b7e5 100644 --- a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs @@ -94,7 +94,7 @@ namespace DnsServerCore.Dns.ZoneManagers //update authoritative zone SOA and NS records try { - List zones = ListZones(); + List zones = GetAllZones(); foreach (AuthZoneInfo zone in zones) { @@ -978,12 +978,20 @@ namespace DnsServerCore.Dns.ZoneManagers return _root.TryGet(zoneName, domain, out _); } - public void ListAllRecords(string zoneName, List records) + public void ListAllZoneRecords(string zoneName, List records) { foreach (AuthZone zone in _root.GetZoneWithSubDomainZones(zoneName)) zone.ListAllRecords(records); } + public void ListAllRecords(string zoneName, string domain, List records) + { + ValidateZoneNameFor(zoneName, domain); + + if (_root.TryGet(zoneName, domain, out AuthZone authZone)) + authZone.ListAllRecords(records); + } + public IReadOnlyList GetRecords(string zoneName, string domain, DnsResourceRecordType type) { ValidateZoneNameFor(zoneName, domain); @@ -1018,7 +1026,7 @@ namespace DnsServerCore.Dns.ZoneManagers DnsResourceRecord soaRecord = soaRecords[0]; List records = new List(); - ListAllRecords(zoneName, records); + ListAllZoneRecords(zoneName, records); List xfrRecords = new List(records.Count + 1); @@ -1191,7 +1199,7 @@ namespace DnsServerCore.Dns.ZoneManagers //sync records List currentRecords = new List(); - ListAllRecords(zoneName, currentRecords); + ListAllZoneRecords(zoneName, currentRecords); Dictionary>> currentRecordsGroupedByDomain = DnsResourceRecord.GroupRecords(currentRecords); Dictionary>> latestRecordsGroupedByDomain = DnsResourceRecord.GroupRecords(latestRecords); @@ -1690,7 +1698,7 @@ namespace DnsServerCore.Dns.ZoneManagers } } - public List ListZones() + public List GetAllZones() { List zones = new List(); @@ -2201,7 +2209,7 @@ namespace DnsServerCore.Dns.ZoneManagers //write all zone records List records = new List(); - ListAllRecords(zoneName, records); + ListAllZoneRecords(zoneName, records); bW.Write(records.Count); From cb5cd38ef8275728c76a10e98ac19510e490c994 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:29:02 +0530 Subject: [PATCH 120/191] code refactoring changes. --- DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs | 6 +++--- DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs index 03672e05..bef3147c 100644 --- a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs @@ -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 @@ -139,12 +139,12 @@ namespace DnsServerCore.Dns.ZoneManagers public List ListZones() { - return _zoneManager.ListZones(); + return _zoneManager.GetAllZones(); } public void ListAllRecords(string domain, List records) { - _zoneManager.ListAllRecords(domain, records); + _zoneManager.ListAllRecords(domain, domain, records); } public void ListSubDomains(string domain, List subDomains) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs index 14a39b01..0f410f7f 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs @@ -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 @@ -157,12 +157,12 @@ namespace DnsServerCore.Dns.ZoneManagers public List ListZones() { - return _zoneManager.ListZones(); + return _zoneManager.GetAllZones(); } public void ListAllRecords(string domain, List records) { - _zoneManager.ListAllRecords(domain, records); + _zoneManager.ListAllRecords(domain, domain, records); } public void ListSubDomains(string domain, List subDomains) From 975bc5d584185e44d6eee2b5e38f137d1f35d66d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:29:37 +0530 Subject: [PATCH 121/191] BlockListZoneManager: refactored code for optimization. --- DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs index bc09a64f..022e8e4d 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs @@ -35,6 +35,8 @@ namespace DnsServerCore.Dns.ZoneManagers { #region variables + readonly static char[] _popWordSeperator = new char[] { ' ', '\t' }; + readonly DnsServer _dnsServer; readonly string _localCacheFolder; @@ -87,9 +89,9 @@ namespace DnsServerCore.Dns.ZoneManagers if (line.Length == 0) return line; - line = line.TrimStart(' ', '\t'); + line = line.TrimStart(_popWordSeperator); - int i = line.IndexOfAny(new char[] { ' ', '\t' }); + int i = line.IndexOfAny(_popWordSeperator); string word; if (i < 0) @@ -120,6 +122,7 @@ namespace DnsServerCore.Dns.ZoneManagers { //parse hosts file and populate block zone StreamReader sR = new StreamReader(fS, true); + char[] trimSeperator = new char[] { ' ', '\t', '*', '.' }; string line; string firstWord; string secondWord; @@ -131,7 +134,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (line == null) break; //eof - line = line.TrimStart(' ', '\t', '*', '.'); + line = line.TrimStart(trimSeperator); if (line.Length == 0) continue; //skip empty line From 73cbff24a02c885e2fd7dfddebf79ca7818be7f9 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:32:28 +0530 Subject: [PATCH 122/191] code refactoring changes. --- DnsServerCore/DnsWebService.cs | 16 ++++++++-------- DnsServerCore/Extensions.cs | 6 +++--- DnsServerCore/WebServiceApi.cs | 4 ++-- DnsServerCore/WebServiceAuthApi.cs | 4 ++-- DnsServerCore/WebServiceDashboardApi.cs | 2 +- DnsServerCore/WebServiceOtherZonesApi.cs | 4 ++-- DnsServerCore/WebServiceSettingsApi.cs | 8 ++++---- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index ff20f45c..d80fa24b 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -948,7 +948,7 @@ namespace DnsServerCore } //add missing admin permissions - List zones = _dnsServer.AuthZoneManager.ListZones(); + List zones = _dnsServer.AuthZoneManager.GetAllZones(); Group admins = _authManager.GetGroup(Group.ADMINISTRATORS); Group dnsAdmins = _authManager.GetGroup(Group.DNS_ADMINISTRATORS); @@ -1009,7 +1009,7 @@ namespace DnsServerCore IPAddress[] localAddresses = new IPAddress[count]; for (int i = 0; i < count; i++) - localAddresses[i] = IPAddressExtension.ReadFrom(bR); + localAddresses[i] = IPAddressExtensions.ReadFrom(bR); _webServiceLocalAddresses = localAddresses; } @@ -1054,7 +1054,7 @@ namespace DnsServerCore IPEndPoint[] localEndPoints = new IPEndPoint[count]; for (int i = 0; i < count; i++) - localEndPoints[i] = (IPEndPoint)EndPointExtension.ReadFrom(bR); + localEndPoints[i] = (IPEndPoint)EndPointExtensions.ReadFrom(bR); _dnsServer.LocalEndPoints = localEndPoints; } @@ -1239,7 +1239,7 @@ namespace DnsServerCore for (int i = 0; i < count; i++) { - IPAddress customAddress = IPAddressExtension.ReadFrom(bR); + IPAddress customAddress = IPAddressExtensions.ReadFrom(bR); switch (customAddress.AddressFamily) { @@ -1351,7 +1351,7 @@ namespace DnsServerCore IPAddress[] localAddresses = new IPAddress[count]; for (int i = 0; i < count; i++) - localAddresses[i] = IPAddressExtension.ReadFrom(bR); + localAddresses[i] = IPAddressExtensions.ReadFrom(bR); _webServiceLocalAddresses = localAddresses; } @@ -1655,7 +1655,7 @@ namespace DnsServerCore for (int i = 0; i < count; i++) { - IPAddress customAddress = IPAddressExtension.ReadFrom(bR); + IPAddress customAddress = IPAddressExtensions.ReadFrom(bR); switch (customAddress.AddressFamily) { @@ -1715,7 +1715,7 @@ namespace DnsServerCore IPEndPoint[] localEndPoints = new IPEndPoint[count]; for (int i = 0; i < count; i++) - localEndPoints[i] = (IPEndPoint)EndPointExtension.ReadFrom(bR); + localEndPoints[i] = (IPEndPoint)EndPointExtensions.ReadFrom(bR); _dnsServer.LocalEndPoints = localEndPoints; } @@ -1728,7 +1728,7 @@ namespace DnsServerCore IPEndPoint[] localEndPoints = new IPEndPoint[count]; for (int i = 0; i < count; i++) - localEndPoints[i] = new IPEndPoint(IPAddressExtension.ReadFrom(bR), 53); + localEndPoints[i] = new IPEndPoint(IPAddressExtensions.ReadFrom(bR), 53); _dnsServer.LocalEndPoints = localEndPoints; } diff --git a/DnsServerCore/Extensions.cs b/DnsServerCore/Extensions.cs index 9bd1b403..630bbfef 100644 --- a/DnsServerCore/Extensions.cs +++ b/DnsServerCore/Extensions.cs @@ -120,7 +120,7 @@ namespace DnsServerCore return parse(value); } - public static T GetQueryOrForm(this HttpRequest request, string parameter) where T : struct + public static T GetQueryOrFormEnum(this HttpRequest request, string parameter) where T : struct { string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) @@ -138,7 +138,7 @@ namespace DnsServerCore return parse(value); } - public static T GetQueryOrForm(this HttpRequest request, string parameter, T defaultValue) where T : struct + public static T GetQueryOrFormEnum(this HttpRequest request, string parameter, T defaultValue) where T : struct { string value = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(value)) @@ -169,7 +169,7 @@ namespace DnsServerCore return true; } - public static bool TryGetQueryOrForm(this HttpRequest request, string parameter, out T value) where T : struct + public static bool TryGetQueryOrFormEnum(this HttpRequest request, string parameter, out T value) where T : struct { string strValue = request.QueryOrForm(parameter); if (string.IsNullOrEmpty(strValue)) diff --git a/DnsServerCore/WebServiceApi.cs b/DnsServerCore/WebServiceApi.cs index 2ba8eea9..7c940cc1 100644 --- a/DnsServerCore/WebServiceApi.cs +++ b/DnsServerCore/WebServiceApi.cs @@ -161,8 +161,8 @@ namespace DnsServerCore string server = request.GetQueryOrForm("server"); string domain = request.GetQueryOrForm("domain").Trim(new char[] { '\t', ' ', '.' }); - DnsResourceRecordType type = request.GetQueryOrForm("type"); - DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + DnsResourceRecordType type = request.GetQueryOrFormEnum("type"); + DnsTransportProtocol protocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp); bool dnssecValidation = request.GetQueryOrForm("dnssec", bool.Parse, false); bool importResponse = request.GetQueryOrForm("import", bool.Parse, false); NetProxy proxy = _dnsWebService.DnsServer.Proxy; diff --git a/DnsServerCore/WebServiceAuthApi.cs b/DnsServerCore/WebServiceAuthApi.cs index 89638001..acc0088f 100644 --- a/DnsServerCore/WebServiceAuthApi.cs +++ b/DnsServerCore/WebServiceAuthApi.cs @@ -829,7 +829,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - section = request.GetQueryOrForm("section"); + section = request.GetQueryOrFormEnum("section"); break; case PermissionSection.Zones: @@ -877,7 +877,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - section = request.GetQueryOrForm("section"); + section = request.GetQueryOrFormEnum("section"); break; case PermissionSection.Zones: diff --git a/DnsServerCore/WebServiceDashboardApi.cs b/DnsServerCore/WebServiceDashboardApi.cs index c54443b2..f15ab21d 100644 --- a/DnsServerCore/WebServiceDashboardApi.cs +++ b/DnsServerCore/WebServiceDashboardApi.cs @@ -497,7 +497,7 @@ namespace DnsServerCore HttpRequest request = context.Request; string strType = request.GetQueryOrForm("type", "lastHour"); - TopStatsType statsType = request.GetQueryOrForm("statsType"); + TopStatsType statsType = request.GetQueryOrFormEnum("statsType"); int limit = request.GetQueryOrForm("limit", int.Parse, 1000); List> topStatsData; diff --git a/DnsServerCore/WebServiceOtherZonesApi.cs b/DnsServerCore/WebServiceOtherZonesApi.cs index 46e918d0..40de4077 100644 --- a/DnsServerCore/WebServiceOtherZonesApi.cs +++ b/DnsServerCore/WebServiceOtherZonesApi.cs @@ -223,7 +223,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); - WebServiceZonesApi.WriteRecordsAsJson(new List(records), jsonWriter, false); + WebServiceZonesApi.WriteRecordsAsJson(records, jsonWriter, true); } public void ImportAllowedZones(HttpContext context) @@ -395,7 +395,7 @@ namespace DnsServerCore jsonWriter.WriteEndArray(); - WebServiceZonesApi.WriteRecordsAsJson(new List(records), jsonWriter, false); + WebServiceZonesApi.WriteRecordsAsJson(records, jsonWriter, true); } public void ImportBlockedZones(HttpContext context) diff --git a/DnsServerCore/WebServiceSettingsApi.cs b/DnsServerCore/WebServiceSettingsApi.cs index 11580da8..6e1ab973 100644 --- a/DnsServerCore/WebServiceSettingsApi.cs +++ b/DnsServerCore/WebServiceSettingsApi.cs @@ -872,7 +872,7 @@ namespace DnsServerCore } //recursion - if (request.TryGetQueryOrForm("recursion", out DnsServerRecursion recursion)) + if (request.TryGetQueryOrFormEnum("recursion", out DnsServerRecursion recursion)) _dnsWebService.DnsServer.Recursion = recursion; string recursionDeniedNetworks = request.QueryOrForm("recursionDeniedNetworks"); @@ -967,7 +967,7 @@ namespace DnsServerCore if (request.TryGetQueryOrForm("allowTxtBlockingReport", bool.Parse, out bool allowTxtBlockingReport)) _dnsWebService.DnsServer.AllowTxtBlockingReport = allowTxtBlockingReport; - if (request.TryGetQueryOrForm("blockingType", out DnsServerBlockingType blockingType)) + if (request.TryGetQueryOrFormEnum("blockingType", out DnsServerBlockingType blockingType)) _dnsWebService.DnsServer.BlockingType = blockingType; string customBlockingAddresses = request.QueryOrForm("customBlockingAddresses"); @@ -1100,7 +1100,7 @@ namespace DnsServerCore } //proxy & forwarders - if (request.TryGetQueryOrForm("proxyType", out NetProxyType proxyType)) + if (request.TryGetQueryOrFormEnum("proxyType", out NetProxyType proxyType)) { if (proxyType == NetProxyType.None) { @@ -1129,7 +1129,7 @@ namespace DnsServerCore } else { - DnsTransportProtocol forwarderProtocol = request.GetQueryOrForm("forwarderProtocol", DnsTransportProtocol.Udp); + DnsTransportProtocol forwarderProtocol = request.GetQueryOrFormEnum("forwarderProtocol", DnsTransportProtocol.Udp); switch (forwarderProtocol) { From 33714b2ac259cd623fb86e5399ad3452a205964d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:35:08 +0530 Subject: [PATCH 123/191] WebServiceZonesApi: updated GetRecords() api to allow listing all zone records and also list records for the specified domain. Code refactoring done. --- DnsServerCore/WebServiceZonesApi.cs | 86 ++++++++++++++++------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index dc7cfada..e31ec481 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -395,7 +395,7 @@ namespace DnsServerCore if (authoritativeZoneRecords) { - if (zoneInfo.Type == AuthZoneType.Primary) + if ((zoneInfo is not null) && (zoneInfo.Type == AuthZoneType.Primary)) { foreach (DnssecPrivateKey dnssecPrivateKey in zoneInfo.DnssecPrivateKeys) { @@ -717,7 +717,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - List zones = _dnsWebService.DnsServer.AuthZoneManager.ListZones(); + List zones = _dnsWebService.DnsServer.AuthZoneManager.GetAllZones(); zones.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); @@ -764,7 +764,7 @@ namespace DnsServerCore zoneName = zoneName.Substring(0, zoneName.Length - 1); } - AuthZoneType type = request.GetQueryOrForm("type", AuthZoneType.Primary); + AuthZoneType type = request.GetQueryOrFormEnum("type", AuthZoneType.Primary); AuthZoneInfo zoneInfo; switch (type) @@ -789,7 +789,7 @@ namespace DnsServerCore case AuthZoneType.Secondary: { string primaryNameServerAddresses = request.GetQueryOrForm("primaryNameServerAddresses", null); - DnsTransportProtocol zoneTransferProtocol = request.GetQueryOrForm("zoneTransferProtocol", DnsTransportProtocol.Tcp); + DnsTransportProtocol zoneTransferProtocol = request.GetQueryOrFormEnum("zoneTransferProtocol", DnsTransportProtocol.Tcp); string tsigKeyName = request.GetQueryOrForm("tsigKeyName", null); if (zoneTransferProtocol == DnsTransportProtocol.Quic) @@ -831,10 +831,10 @@ namespace DnsServerCore case AuthZoneType.Forwarder: { - DnsTransportProtocol forwarderProtocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + DnsTransportProtocol forwarderProtocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp); string forwarder = request.GetQueryOrForm("forwarder"); bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false); - NetProxyType proxyType = request.GetQueryOrForm("proxyType", NetProxyType.None); + NetProxyType proxyType = request.GetQueryOrFormEnum("proxyType", NetProxyType.None); string proxyAddress = null; ushort proxyPort = 0; @@ -1184,7 +1184,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - DnssecPrivateKeyType keyType = request.GetQueryOrForm("keyType"); + DnssecPrivateKeyType keyType = request.GetQueryOrFormEnum("keyType"); ushort rolloverDays = request.GetQueryOrForm("rolloverDays", ushort.Parse, (ushort)(keyType == DnssecPrivateKeyType.ZoneSigningKey ? 90 : 0)); string algorithm = request.GetQueryOrForm("algorithm"); @@ -1595,7 +1595,7 @@ namespace DnsServerCore { case AuthZoneType.Primary: case AuthZoneType.Secondary: - if (request.TryGetQueryOrForm("zoneTransfer", out AuthZoneTransfer zoneTransfer)) + if (request.TryGetQueryOrFormEnum("zoneTransfer", out AuthZoneTransfer zoneTransfer)) zoneInfo.ZoneTransfer = zoneTransfer; string strZoneTransferNameServers = request.QueryOrForm("zoneTransferNameServers"); @@ -1626,7 +1626,7 @@ namespace DnsServerCore } } - if (request.TryGetQueryOrForm("notify", out AuthZoneNotify notify)) + if (request.TryGetQueryOrFormEnum("notify", out AuthZoneNotify notify)) zoneInfo.Notify = notify; string strNotifyNameServers = request.QueryOrForm("notifyNameServers"); @@ -1643,7 +1643,7 @@ namespace DnsServerCore switch (zoneInfo.Type) { case AuthZoneType.Primary: - if (request.TryGetQueryOrForm("update", out AuthZoneUpdate update)) + if (request.TryGetQueryOrFormEnum("update", out AuthZoneUpdate update)) zoneInfo.Update = update; string strUpdateIpAddresses = request.QueryOrForm("updateIpAddresses"); @@ -1756,7 +1756,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); - DnsResourceRecordType type = request.GetQueryOrForm("type"); + DnsResourceRecordType type = request.GetQueryOrFormEnum("type"); uint ttl = request.GetQueryOrForm("ttl", uint.Parse, _defaultRecordTtl); bool overwrite = request.GetQueryOrForm("overwrite", bool.Parse, false); string comments = request.QueryOrForm("comments"); @@ -1975,8 +1975,8 @@ namespace DnsServerCore case DnsResourceRecordType.SSHFP: { - DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrForm("sshfpAlgorithm"); - DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrForm("sshfpFingerprintType"); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrFormEnum("sshfpAlgorithm"); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrFormEnum("sshfpFingerprintType"); byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString); newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); @@ -1994,7 +1994,7 @@ namespace DnsServerCore case DnsResourceRecordType.TLSA: { DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true); - DnsTLSASelector tlsaSelector = request.GetQueryOrForm("tlsaSelector"); + DnsTLSASelector tlsaSelector = request.GetQueryOrFormEnum("tlsaSelector"); DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true); string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData"); @@ -2046,7 +2046,7 @@ namespace DnsServerCore case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + DnsTransportProtocol protocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp); string forwarder = request.GetQueryOrFormAlt("forwarder", "value"); bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false); @@ -2058,7 +2058,7 @@ namespace DnsServerCore if (!forwarder.Equals("this-server")) { - proxyType = request.GetQueryOrForm("proxyType", NetProxyType.None); + proxyType = request.GetQueryOrFormEnum("proxyType", NetProxyType.None); if (proxyType != NetProxyType.None) { proxyAddress = request.GetQueryOrForm("proxyAddress"); @@ -2121,9 +2121,15 @@ namespace DnsServerCore public void GetRecords(HttpContext context) { - string domain = context.Request.GetQueryOrForm("domain").TrimEnd('.'); + HttpRequest request = context.Request; - AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(domain); + string domain = request.GetQueryOrForm("domain").TrimEnd('.'); + + string zoneName = request.QueryOrForm("zone"); + if (zoneName is not null) + zoneName = zoneName.TrimEnd('.'); + + AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); @@ -2132,14 +2138,20 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); + bool listZone = request.GetQueryOrForm("listZone", bool.Parse, false); + + List records = new List(); + + if (listZone) + _dnsWebService.DnsServer.AuthZoneManager.ListAllZoneRecords(zoneInfo.Name, records); + else + _dnsWebService.DnsServer.AuthZoneManager.ListAllRecords(zoneInfo.Name, domain, records); + Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("zone"); WriteZoneInfoAsJson(zoneInfo, jsonWriter); - List records = new List(); - _dnsWebService.DnsServer.AuthZoneManager.ListAllRecords(domain, records); - WriteRecordsAsJson(records, jsonWriter, true, zoneInfo); } @@ -2165,7 +2177,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); - DnsResourceRecordType type = request.GetQueryOrForm("type"); + DnsResourceRecordType type = request.GetQueryOrFormEnum("type"); switch (type) { case DnsResourceRecordType.A: @@ -2265,8 +2277,8 @@ namespace DnsServerCore case DnsResourceRecordType.SSHFP: { - DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrForm("sshfpAlgorithm"); - DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrForm("sshfpFingerprintType"); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrFormEnum("sshfpAlgorithm"); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrFormEnum("sshfpFingerprintType"); byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString); _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint)); @@ -2276,7 +2288,7 @@ namespace DnsServerCore case DnsResourceRecordType.TLSA: { DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true); - DnsTLSASelector tlsaSelector = request.GetQueryOrForm("tlsaSelector"); + DnsTLSASelector tlsaSelector = request.GetQueryOrFormEnum("tlsaSelector"); DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true); string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData"); @@ -2304,7 +2316,7 @@ namespace DnsServerCore case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); + DnsTransportProtocol protocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp); string forwarder = request.GetQueryOrFormAlt("forwarder", "value"); _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsForwarderRecordData(protocol, forwarder)); @@ -2350,7 +2362,7 @@ namespace DnsServerCore uint ttl = request.GetQueryOrForm("ttl", uint.Parse, _defaultRecordTtl); bool disable = request.GetQueryOrForm("disable", bool.Parse, false); string comments = request.QueryOrForm("comments"); - DnsResourceRecordType type = request.GetQueryOrForm("type"); + DnsResourceRecordType type = request.GetQueryOrFormEnum("type"); DnsResourceRecord oldRecord = null; DnsResourceRecord newRecord; @@ -2486,7 +2498,7 @@ namespace DnsServerCore { AuthRecordInfo recordInfo = newSOARecord.GetAuthRecordInfo(); - if (request.TryGetQueryOrForm("zoneTransferProtocol", out DnsTransportProtocol zoneTransferProtocol)) + if (request.TryGetQueryOrFormEnum("zoneTransferProtocol", out DnsTransportProtocol zoneTransferProtocol)) { if (zoneTransferProtocol == DnsTransportProtocol.Quic) DnsWebService.ValidateQuicSupport(); @@ -2669,11 +2681,11 @@ namespace DnsServerCore case DnsResourceRecordType.SSHFP: { - DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrForm("sshfpAlgorithm"); - DnsSSHFPAlgorithm newSshfpAlgorithm = request.GetQueryOrForm("newSshfpAlgorithm", sshfpAlgorithm); + DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrFormEnum("sshfpAlgorithm"); + DnsSSHFPAlgorithm newSshfpAlgorithm = request.GetQueryOrFormEnum("newSshfpAlgorithm", sshfpAlgorithm); - DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrForm("sshfpFingerprintType"); - DnsSSHFPFingerprintType newSshfpFingerprintType = request.GetQueryOrForm("newSshfpFingerprintType", sshfpFingerprintType); + DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrFormEnum("sshfpFingerprintType"); + DnsSSHFPFingerprintType newSshfpFingerprintType = request.GetQueryOrFormEnum("newSshfpFingerprintType", sshfpFingerprintType); byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString); byte[] newSshfpFingerprint = request.GetQueryOrForm("newSshfpFingerprint", Convert.FromHexString, sshfpFingerprint); @@ -2696,8 +2708,8 @@ namespace DnsServerCore DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true); DnsTLSACertificateUsage newTlsaCertificateUsage = Enum.Parse(request.GetQueryOrForm("newTlsaCertificateUsage", tlsaCertificateUsage.ToString()).Replace('-', '_'), true); - DnsTLSASelector tlsaSelector = request.GetQueryOrForm("tlsaSelector"); - DnsTLSASelector newTlsaSelector = request.GetQueryOrForm("newTlsaSelector", tlsaSelector); + DnsTLSASelector tlsaSelector = request.GetQueryOrFormEnum("tlsaSelector"); + DnsTLSASelector newTlsaSelector = request.GetQueryOrFormEnum("newTlsaSelector", tlsaSelector); DnsTLSAMatchingType tlsaMatchingType = Enum.Parse(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true); DnsTLSAMatchingType newTlsaMatchingType = Enum.Parse(request.GetQueryOrForm("newTlsaMatchingType", tlsaMatchingType.ToString()).Replace('-', '_'), true); @@ -2762,8 +2774,8 @@ namespace DnsServerCore case DnsResourceRecordType.FWD: { - DnsTransportProtocol protocol = request.GetQueryOrForm("protocol", DnsTransportProtocol.Udp); - DnsTransportProtocol newProtocol = request.GetQueryOrForm("newProtocol", protocol); + DnsTransportProtocol protocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp); + DnsTransportProtocol newProtocol = request.GetQueryOrFormEnum("newProtocol", protocol); string forwarder = request.GetQueryOrFormAlt("forwarder", "value"); string newForwarder = request.GetQueryOrFormAlt("newForwarder", "newValue", forwarder); @@ -2778,7 +2790,7 @@ namespace DnsServerCore if (!newForwarder.Equals("this-server")) { - proxyType = request.GetQueryOrForm("proxyType", NetProxyType.None); + proxyType = request.GetQueryOrFormEnum("proxyType", NetProxyType.None); if (proxyType != NetProxyType.None) { proxyAddress = request.GetQueryOrForm("proxyAddress"); From 31aa04c1c5b4805ec97aaefefe0ae95b178b9bb5 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:37:15 +0530 Subject: [PATCH 124/191] DnsServer: Updated ProcessConnectionAsync() to add timeout condition for AuthenticateAsServerAsync() call. Updated ProcessAPPAsync() to decide on correct RCODE to be used for response. --- DnsServerCore/Dns/DnsServer.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 40415fdc..e8b356ba 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -515,7 +515,7 @@ namespace DnsServerCore.Dns case DnsTransportProtocol.Tls: SslStream tlsStream = new SslStream(new NetworkStream(socket)); - await tlsStream.AuthenticateAsServerAsync(_certificate); + await tlsStream.AuthenticateAsServerAsync(_certificate).WithTimeout(_tcpReceiveTimeout); await ReadStreamRequestAsync(tlsStream, remoteEP, protocol); break; @@ -524,6 +524,10 @@ namespace DnsServerCore.Dns throw new InvalidOperationException(); } } + catch (TimeoutException) + { + //ignore timeout exception on TLS auth + } catch (IOException) { //ignore IO exceptions @@ -1945,11 +1949,14 @@ namespace DnsServerCore.Dns DnsDatagram appResponse = await appRecordRequestHandler.ProcessRequestAsync(request, remoteEP, protocol, isRecursionAllowed, zoneInfo.Name, appResourceRecord.Name, appResourceRecord.TTL, appRecord.Data); if (appResponse is null) { + DnsResponseCode rcode; IReadOnlyList authority = null; if (zoneInfo.Type == AuthZoneType.Forwarder) { //return FWD response + rcode = DnsResponseCode.NoError; + if (!zoneInfo.Name.Equals(appResourceRecord.Name, StringComparison.OrdinalIgnoreCase)) { AuthZone authZone = _authZoneManager.GetAuthZone(zoneInfo.Name, appResourceRecord.Name); @@ -1962,11 +1969,16 @@ namespace DnsServerCore.Dns } else { - //return NO DATA response + //return NODATA/NXDOMAIN response + if (request.Question[0].Name.Length > appResourceRecord.Name.Length) + rcode = DnsResponseCode.NxDomain; + else + rcode = DnsResponseCode.NoError; + authority = zoneInfo.GetApexRecords(DnsResourceRecordType.SOA); } - return new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, null, authority) { Tag = DnsServerResponseType.Authoritative }; + return new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, rcode, request.Question, null, authority) { Tag = DnsServerResponseType.Authoritative }; } else { From b74d6f4f148574fa2fe11e8bb958840ce2f4b938 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:37:57 +0530 Subject: [PATCH 125/191] webapp: minor html changes. --- DnsServerCore/www/index.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index b193170e..b2b2d2f8 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -2650,9 +2650,9 @@

    Donate

    -

    Make a contribution to Technitium by becoming a Patron and help making new software, updates, and features possible.

    +

    Make a contribution to Technitium and help making new software, updates, and features possible.

    - Become A Patron Now! + Donate Now!

    @@ -3713,7 +3713,7 @@ MII...
    @@ -4043,7 +4043,7 @@ MII...
    - (valid range 0-32, recommended 0) + bytes (valid range 0-32, recommended 0)
    The number of bytes of random salt to generate to be used with the NSEC3 hash computation. It is recommended to not use salt by setting the length to 0 [RFC 9276]. @@ -4055,7 +4055,7 @@ MII...
    - (default 3600) + seconds (default 3600)
    The TTL value to be used for DNSKEY records. A lower value will allow quicker addition or rollover to a new DNS Key at the cost of increased frequency of DNSKEY queries by resolvers. @@ -4276,7 +4276,7 @@ MII...
    - (valid range 0-32, recommended 0) + bytes (valid range 0-32, recommended 0)
    The number of bytes of random salt to generate to be used with the NSEC3 hash computation. It is recommended to not use salt by setting the length to 0 [RFC 9276]. @@ -4297,7 +4297,7 @@ MII...
    - (default 3600) + seconds (default 3600)
    From 1b537279eeddfd23a4367a0c22d3869c01b92a0d Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:38:46 +0530 Subject: [PATCH 126/191] zone.js: updated showEditZone() to use new get records api call changes. --- DnsServerCore/www/js/zone.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DnsServerCore/www/js/zone.js b/DnsServerCore/www/js/zone.js index f14b9f20..c74d5f26 100644 --- a/DnsServerCore/www/js/zone.js +++ b/DnsServerCore/www/js/zone.js @@ -1245,7 +1245,7 @@ function showEditZone(zone) { divViewZonesLoader.show(); HTTPRequest({ - url: "/api/zones/records/get?token=" + sessionData.token + "&domain=" + zone, + url: "/api/zones/records/get?token=" + sessionData.token + "&domain=" + zone + "&zone=" + zone + "&listZone=true", success: function (responseJSON) { var zoneType; if (responseJSON.response.zone.internal) From 0ade11e1cf73a1d722f7346316cd01ac9918f746 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:39:44 +0530 Subject: [PATCH 127/191] updated apidocs. --- APIDOCS.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/APIDOCS.md b/APIDOCS.md index c889f06c..40e5c00b 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -1996,7 +1996,7 @@ WHERE: - `zskKeySize` (optional): The size of the Zone Signing Key (ZSK) in bits to be used when using `RSA` algorithm. This optional parameter is required when using `RSA` algorithm. - `curve` (optional): The name of the curve to be used when using `ECDSA` algorithm. Valid values are [`P256`, `P384`]. This optional parameter is required when using `ECDSA` algorithm. - `dnsKeyTtl` (optional): The TTL value to be used for DNSKEY records. Default value is `86400` when not specified. -- `zskRolloverDays` (optional): The frequency in days that the DNS server must automatically rollover the Zone Signing Keys (ZSK) in the zone. Valid range is 0-365 days where 0 disables rollover. Default value is `90` days. +- `zskRolloverDays` (optional): The frequency in days that the DNS server must automatically rollover the Zone Signing Keys (ZSK) in the zone. Valid range is 0-365 days where 0 disables rollover. Default value is `90` when not specified. - `nxProof` (optional): The type of proof of non-existence that must be used for signing the zone. Valid values are [`NSEC`, `NSEC3`]. Default value is `NSEC` when not specified. - `iterations` (optional): The number of iterations to use for hashing in NSEC3. This optional parameter is only applicable when using `NSEC3` as the `nxProof`. Default value is `0` when not specified. - `saltLength` (optional): The length of salt in bytes to use for hashing in NSEC3. This optional parameter is only applicable when using `NSEC3` as the `nxProof`. Default value is `0` when not specified. @@ -2447,7 +2447,7 @@ RESPONSE: Gets all records for a given authoritative zone. URL:\ -`http://localhost:5380/api/zones/records/get?token=x&domain=example.com&zone=example.com` +`http://localhost:5380/api/zones/records/get?token=x&domain=example.com&zone=example.com&listZone=true` OBSOLETE PATH:\ `/api/zone/getRecords`\ @@ -2461,6 +2461,7 @@ WHERE: - `token`: The session token generated by the `login` or the `createToken` call. - `domain`: The domain name of the zone to get records. - `zone` (optional): The name of the authoritative zone into which the `domain` exists. When unspecified, the closest authoritative zone will be used. +- `listZone` (optional): When set to `true` will list all records in the zone else will list records only for the given domain name. Default value is `false` when not specified. RESPONSE: ``` @@ -4241,7 +4242,6 @@ WHERE: - `saveCache` (optional): Enable this option to save DNS cache on disk when the DNS server stops. The saved cache will be loaded next time the DNS server starts. - `serveStale` (optional): Enable the serve stale feature to improve resiliency by using expired or stale records in cache when the DNS server is unable to reach the upstream or authoritative name servers. Default value is `true`. - `serveStaleTtl` (optional): The TTL value in seconds which should be used for cached records that are expired. When the serve stale TTL too expires for a stale record, it gets removed from the cache. Recommended value is between 1-3 days and maximum supported value is 7 days. Default value is `259200`. -- `temporaryDisableBlockingTill` (read only): An ISO 8601 String with the Date and Time when the Temporary Blocking will end. - `cacheMinimumRecordTtl` (optional): The minimum TTL value that a record can have in cache. Set a value to make sure that the records with TTL value than it stays in cache for a minimum duration. Default value is `10`. - `cacheMaximumRecordTtl` (optional): The maximum TTL value that a record can have in cache. Set a lower value to allow the records to expire early. Default value is `86400`. - `cacheNegativeRecordTtl` (optional): The negative TTL value to use when there is no SOA MINIMUM value available. Default value is `300`. @@ -4253,7 +4253,6 @@ WHERE: - `enableBlocking` (optional): Sets the DNS server to block domain names using Blocked Zone and Block List Zone. - `allowTxtBlockingReport` (optional): Specifies if the DNS Server should respond with TXT records containing a blocked domain report for TXT type requests. - `blockingType` (optional): Sets how the DNS server should respond to a blocked domain request. Valid values are [`AnyAddress`, `NxDomain`, `CustomAddress`] where `AnyAddress` is default which response with `0.0.0.0` and `::` IP addresses for blocked domains. Using `NxDomain` will respond with `NX Domain` response. `CustomAddress` will return the specified custom blocking addresses. -- `blockListNextUpdatedOn` (read only): An ISO 8601 String with the Date and Time when the blocklist will next be updated. - `customBlockingAddresses` (optional): Set the custom blocking addresses to be used for blocked domain response. These addresses are returned only when `blockingType` is set to `CustomAddress`. - `blockListUrls` (optional): A comma separated list of block list URLs that this server must automatically download and use with the block lists zone. DNS Server will use the data returned by the block list URLs to update the block list zone automatically every 24 hours. The expected file format is standard hosts file format or plain text file containing list of domains to block. Set this parameter to `false` to remove existing values. - `blockListUpdateIntervalHours` (optional): The interval in hours to automatically download and update the block lists. Default value is `24`. From 100ba49b97369abb0c518eb101105f36f835fc99 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:41:01 +0530 Subject: [PATCH 128/191] updated readme --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e398c8c7..2fdb4274 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,12 @@ Be it a home network or an organization's network, having a locally running DNS - Installs in just a minute and works out-of-the-box with zero configuration. - Block ads & malware using one or more block list URLs. - High performance DNS server based on async IO that can serve millions of requests per minute even on a commodity desktop PC hardware (load tested on Intel i7-8700 CPU with more than 100,000 request/second over Gigabit Ethernet). -- Self host [DNS-over-TLS](https://en.wikipedia.org/wiki/DNS_over_TLS) and [DNS-over-HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) DNS service on your network. -- Use public DNS resolvers like Cloudflare, Google & Quad9 with [DNS-over-TLS](https://en.wikipedia.org/wiki/DNS_over_TLS) and [DNS-over-HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) protocols as forwarders. +- Self host [DNS-over-TLS](https://www.rfc-editor.org/rfc/rfc7858.html), [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.html), and [DNS-over-QUIC](https://www.ietf.org/rfc/rfc9250.html) DNS service on your network. +- Use public DNS resolvers like Cloudflare, Google, Quad9, & AdGuard with [DNS-over-TLS](https://www.rfc-editor.org/rfc/rfc7858.html), [DNS-over-HTTPS](https://www.rfc-editor.org/rfc/rfc8484.html), or [DNS-over-QUIC](https://www.ietf.org/rfc/rfc9250.html) protocols as forwarders. - Advanced caching with features like serve stale, prefetching and auto prefetching. - Supports working as an authoritative as well as a recursive DNS server. -- DNSSEC validation support with RSA & ECDSA algorithms for recursive resolver, forwarders, and conditional forwarders. -- DNSSEC support for all supported DNS transport protocols including encrypted DNS protocols (DoT, DoH, & DoH JSON). +- DNSSEC validation support with RSA & ECDSA algorithms for recursive resolver, forwarders, and conditional forwarders with NSEC and NSEC3 support. +- DNSSEC support for all supported DNS transport protocols including encrypted DNS protocols. - DANE TLSA [RFC 6698](https://datatracker.ietf.org/doc/html/rfc6698) record type support. This includes support for automatically generating the hash values using certificates in PEM format. - SSHFP [RFC 4255](https://www.rfc-editor.org/rfc/rfc4255.html) record type support. - CNAME cloaking feature to block domain names that resolve to CNAME which are blocked. @@ -49,7 +49,10 @@ Be it a home network or an organization's network, having a locally running DNS - Primary, Secondary, Stub, and Conditional Forwarder zone support. - Static stub zone support implemented in Conditional Forwarder zone to force a domain name to resolve via given name servers using NS records. - DNSSEC signed zones support with RSA & ECDSA algorithms. +- DNSSEC support for both NSEC and NSEC3. +- Zone transfer with AXFR and IXFR [RFC 1995](https://www.rfc-editor.org/rfc/rfc1995.html) support. - Zone transfer over TLS (XFR-over-TLS) [RFC 9103](https://www.rfc-editor.org/rfc/rfc9103.html) support. +- Zone transfer over QUIC (XFR-over-QUIC) [RFC 9250](https://www.ietf.org/rfc/rfc9250.html) support. - Dynamic DNS Updates [RFC 2136](https://www.rfc-editor.org/rfc/rfc2136) support with security policy. - Secret key transaction authentication (TSIG) [RFC 8945](https://datatracker.ietf.org/doc/html/rfc8945) support for zone transfers. - EDNS(0) [RFC6891](https://datatracker.ietf.org/doc/html/rfc6891) support. @@ -94,9 +97,9 @@ For support, send an email to support@technitium.com. For any issues, feedback, Join [/r/technitium](https://www.reddit.com/r/technitium/) on Reddit. # Donate -Make contribution to Technitium by becoming a Patron and help making new software, updates, and features possible. +Make contribution to Technitium and help making new software, updates, and features possible. -[Become a Patron now!](https://www.patreon.com/technitium) +[Donate Now!](https://www.patreon.com/technitium) # Blog Posts - [Technitium Blog: Technitium DNS Server v10 Released!](https://blog.technitium.com/2022/11/technitium-dns-server-v10-released.html) (Nov 2022) From 4ec000e51c825dfcc8ec573ea47d62b76abab6ad Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 16:49:41 +0530 Subject: [PATCH 129/191] code refactoring changes. --- DnsServerSystemTrayApp/DnsProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerSystemTrayApp/DnsProvider.cs b/DnsServerSystemTrayApp/DnsProvider.cs index 72fa6d6b..870108c4 100644 --- a/DnsServerSystemTrayApp/DnsProvider.cs +++ b/DnsServerSystemTrayApp/DnsProvider.cs @@ -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 @@ -52,7 +52,7 @@ namespace DnsServerSystemTrayApp int count = bR.ReadInt32(); for (int i = 0; i < count; i++) - this.Addresses.Add(IPAddressExtension.ReadFrom(bR)); + this.Addresses.Add(IPAddressExtensions.ReadFrom(bR)); } #endregion From ebc6e5f1f37314403b8058130384619171adaf44 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 17:21:20 +0530 Subject: [PATCH 130/191] DnsServer: merged doh web apps. --- DnsServerCore/Dns/DnsServer.cs | 110 +++++---------------------------- 1 file changed, 17 insertions(+), 93 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index e8b356ba..0ed6933d 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -109,7 +109,6 @@ namespace DnsServerCore.Dns readonly List _tlsListeners = new List(); readonly List _quicListeners = new List(); - WebApplication _dohPrivateWebService; WebApplication _dohWebService; readonly AuthZoneManager _authZoneManager; @@ -3678,90 +3677,6 @@ namespace DnsServerCore.Dns #region doh web service - private async Task StartDoHPrivateAsync() - { - WebApplicationBuilder builder = WebApplication.CreateBuilder(); - - builder.Environment.ContentRootFileProvider = new PhysicalFileProvider(Path.GetDirectoryName(_dohwwwFolder)) - { - UseActivePolling = true, - UsePollingFileWatcher = true - }; - - builder.Environment.WebRootFileProvider = new PhysicalFileProvider(_dohwwwFolder) - { - UseActivePolling = true, - UsePollingFileWatcher = true - }; - - IReadOnlyList localAddresses = GetValidKestralLocalAddresses(_localEndPoints.Convert(delegate (IPEndPoint ep) { return ep.Address; })); - - builder.WebHost.ConfigureKestrel(delegate (WebHostBuilderContext context, KestrelServerOptions serverOptions) - { - foreach (IPAddress localAddress in localAddresses) - serverOptions.Listen(localAddress, _dnsOverHttpPort); - - serverOptions.AddServerHeader = false; - serverOptions.Limits.RequestHeadersTimeout = TimeSpan.FromMilliseconds(_tcpReceiveTimeout); - serverOptions.Limits.KeepAliveTimeout = TimeSpan.FromMilliseconds(_tcpReceiveTimeout); - serverOptions.Limits.MaxRequestHeadersTotalSize = 4096; - serverOptions.Limits.MaxRequestLineSize = serverOptions.Limits.MaxRequestHeadersTotalSize; - serverOptions.Limits.MaxRequestBufferSize = serverOptions.Limits.MaxRequestLineSize; - serverOptions.Limits.MaxRequestBodySize = 64 * 1024; - serverOptions.Limits.MaxResponseBufferSize = 4096; - }); - - builder.Logging.ClearProviders(); - - _dohPrivateWebService = builder.Build(); - - _dohPrivateWebService.UseDefaultFiles(); - _dohPrivateWebService.UseStaticFiles(new StaticFileOptions() - { - OnPrepareResponse = delegate (StaticFileResponseContext ctx) - { - ctx.Context.Response.Headers.Add("X-Robots-Tag", "noindex, nofollow"); - ctx.Context.Response.Headers.Add("Cache-Control", "private, max-age=300"); - } - }); - - _dohPrivateWebService.UseRouting(); - _dohPrivateWebService.MapGet("/dns-query", ProcessDoHRequestAsync); - _dohPrivateWebService.MapPost("/dns-query", ProcessDoHRequestAsync); - - try - { - await _dohPrivateWebService.StartAsync(); - - if (_log is not null) - { - foreach (IPAddress localAddress in localAddresses) - _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server was bound successfully."); - } - } - catch (Exception ex) - { - await StopDoHPrivateAsync(); - - if (_log is not null) - { - foreach (IPAddress localAddress in localAddresses) - _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server failed to bind."); - - _log?.Write(ex); - } - } - } - - private async Task StopDoHPrivateAsync() - { - if (_dohPrivateWebService is not null) - { - await _dohPrivateWebService.DisposeAsync(); - _dohPrivateWebService = null; - } - } - private async Task StartDoHAsync() { WebApplicationBuilder builder = WebApplication.CreateBuilder(); @@ -3782,6 +3697,13 @@ namespace DnsServerCore.Dns builder.WebHost.ConfigureKestrel(delegate (WebHostBuilderContext context, KestrelServerOptions serverOptions) { + //bind to http port + if (_enableDnsOverHttp) + { + foreach (IPAddress localAddress in localAddresses) + serverOptions.Listen(localAddress, _dnsOverHttpPort); + } + //bind to http port 80 for certbot webroot support if (_enableDnsOverHttpPort80) { @@ -3790,7 +3712,7 @@ namespace DnsServerCore.Dns } //bind to https port - if (_certificate is not null) + if (_enableDnsOverHttps && (_certificate is not null)) { serverOptions.ConfigureHttpsDefaults(delegate (HttpsConnectionAdapterOptions configureOptions) { @@ -3846,10 +3768,13 @@ namespace DnsServerCore.Dns { foreach (IPAddress localAddress in localAddresses) { + if (_enableDnsOverHttp) + _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server was bound successfully."); + if (_enableDnsOverHttpPort80) _log?.Write(new IPEndPoint(localAddress, 80), "Http", "DNS Server was bound successfully."); - if (_certificate is not null) + if (_enableDnsOverHttps && (_certificate is not null)) _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpsPort), "Https", "DNS Server was bound successfully."); } } @@ -3862,10 +3787,13 @@ namespace DnsServerCore.Dns { foreach (IPAddress localAddress in localAddresses) { + if (_enableDnsOverHttp) + _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server failed to bind."); + if (_enableDnsOverHttpPort80) _log?.Write(new IPEndPoint(localAddress, 80), "Http", "DNS Server failed to bind."); - if (_certificate is not null) + if (_enableDnsOverHttps && (_certificate is not null)) _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpsPort), "Https", "DNS Server failed to bind."); } @@ -4157,10 +4085,7 @@ namespace DnsServerCore.Dns } } - if (_enableDnsOverHttp) - await StartDoHPrivateAsync(); - - if (_enableDnsOverHttps) + if (_enableDnsOverHttp || _enableDnsOverHttpPort80 || (_enableDnsOverHttps && (_certificate is not null))) await StartDoHAsync(); _cachePrefetchSamplingTimer = new Timer(CachePrefetchSamplingTimerCallback, null, Timeout.Infinite, Timeout.Infinite); @@ -4235,7 +4160,6 @@ namespace DnsServerCore.Dns _tlsListeners.Clear(); _quicListeners.Clear(); - await StopDoHPrivateAsync(); await StopDoHAsync(); _state = ServiceState.Stopped; From 9c6acf65802e22358a1a8ce6d89dc4b5b1849ca6 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 17:29:02 +0530 Subject: [PATCH 131/191] main.js: minor ui changes. --- DnsServerCore/www/js/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index 5d8b3949..53f601b9 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.js @@ -325,6 +325,7 @@ $(function () { var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop("checked"); var enableDnsOverQuic = $("#chkEnableDnsOverQuic").prop("checked"); + $("#chkEnableDnsOverHttpPort80").prop("checked", enableDnsOverHttps); $("#txtDnsOverHttpsPort").prop("disabled", !enableDnsOverHttps); $("#txtDnsTlsCertificatePath").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); $("#txtDnsTlsCertificatePassword").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); From 1d2823f7c19a821e8d6cba74791ba2f13a74e322 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 17:32:37 +0530 Subject: [PATCH 132/191] solution file update --- DnsServer.sln | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/DnsServer.sln b/DnsServer.sln index 787db03d..57805a81 100644 --- a/DnsServer.sln +++ b/DnsServer.sln @@ -43,6 +43,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NoDataApp", "Apps\NoDataApp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dns64App", "Apps\Dns64App\Dns64App.csproj", "{3514C4B4-78C1-46A1-82D5-4E676DD114FA}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DnsBlockListApp", "Apps\DnsBlockListApp\DnsBlockListApp.csproj", "{9F2EC41F-6A9E-47C4-B47B-75190D5B6903}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedForwardingApp", "Apps\AdvancedForwardingApp\AdvancedForwardingApp.csproj", "{42DD2C37-4082-4E33-9AB0-04A97290D5B7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -125,6 +129,14 @@ Global {3514C4B4-78C1-46A1-82D5-4E676DD114FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {3514C4B4-78C1-46A1-82D5-4E676DD114FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {3514C4B4-78C1-46A1-82D5-4E676DD114FA}.Release|Any CPU.Build.0 = Release|Any CPU + {9F2EC41F-6A9E-47C4-B47B-75190D5B6903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F2EC41F-6A9E-47C4-B47B-75190D5B6903}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F2EC41F-6A9E-47C4-B47B-75190D5B6903}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F2EC41F-6A9E-47C4-B47B-75190D5B6903}.Release|Any CPU.Build.0 = Release|Any CPU + {42DD2C37-4082-4E33-9AB0-04A97290D5B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42DD2C37-4082-4E33-9AB0-04A97290D5B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42DD2C37-4082-4E33-9AB0-04A97290D5B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42DD2C37-4082-4E33-9AB0-04A97290D5B7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -144,6 +156,8 @@ Global {8B6BEB00-0AC2-4680-A848-31AD8A0FCD82} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2} {BE08D981-DDB0-4314-A571-D68EDF0F3971} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2} {3514C4B4-78C1-46A1-82D5-4E676DD114FA} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2} + {9F2EC41F-6A9E-47C4-B47B-75190D5B6903} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2} + {42DD2C37-4082-4E33-9AB0-04A97290D5B7} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6747BB6D-2826-4356-A213-805FBCCF9201} From 2fb02674cabad31fe144aef3b344c12cadb707f8 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 5 Feb 2023 17:34:06 +0530 Subject: [PATCH 133/191] IDnsAppRecordRequestHandler: updated api docs. --- .../IDnsAppRecordRequestHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore.ApplicationCommon/IDnsAppRecordRequestHandler.cs b/DnsServerCore.ApplicationCommon/IDnsAppRecordRequestHandler.cs index 94cc93d6..b8f045e4 100644 --- a/DnsServerCore.ApplicationCommon/IDnsAppRecordRequestHandler.cs +++ b/DnsServerCore.ApplicationCommon/IDnsAppRecordRequestHandler.cs @@ -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 @@ -39,7 +39,7 @@ namespace DnsServerCore.ApplicationCommon /// The domain name of the APP record. /// The TTL value set in the APP record. /// The record data in the APP record as required for processing the request. - /// The DNS response for the DNS request or null to send no answer response with an SOA authority. + /// The DNS response for the DNS request or null to send NODATA response when QNAME matches APP record name or else NXDOMAIN response with an SOA authority. Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed, string zoneName, string appRecordName, uint appRecordTtl, string appRecordData); /// From 0c9aab4adb34b14568c01efbc9e7c73d0112a0e5 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 12:01:47 +0530 Subject: [PATCH 134/191] AdvancedBlockingApp: updated implementation to disable cname cloaking when a domain is allowed. Added support for extended dns error for blocking report. --- Apps/AdvancedBlockingApp/App.cs | 66 +++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/Apps/AdvancedBlockingApp/App.cs b/Apps/AdvancedBlockingApp/App.cs index 196736fa..f3e0d382 100644 --- a/Apps/AdvancedBlockingApp/App.cs +++ b/Apps/AdvancedBlockingApp/App.cs @@ -33,6 +33,7 @@ using System.Threading.Tasks; using TechnitiumLibrary; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.EDnsOptions; using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace AdvancedBlocking @@ -418,10 +419,10 @@ namespace AdvancedBlocking return Task.CompletedTask; } - public Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed) + public async Task ProcessRequestAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, bool isRecursionAllowed) { if (!_enableBlocking) - return Task.FromResult(null); + return null; IPAddress remoteIP = remoteEP.Address; NetworkAddress network = null; @@ -437,37 +438,63 @@ namespace AdvancedBlocking } if ((groupName is null) || !_groups.TryGetValue(groupName, out Group group) || !group.EnableBlocking) - return Task.FromResult(null); + return null; DnsQuestionRecord question = request.Question[0]; - if (!group.IsZoneBlocked(question.Name, out string blockedDomain, out string blockedRegex, out Uri blockListUrl)) - return Task.FromResult(null); - - if (group.AllowTxtBlockingReport && (question.Type == DnsResourceRecordType.TXT)) + if (!group.IsZoneBlocked(question.Name, out bool allowed, out string blockedDomain, out string blockedRegex, out Uri blockListUrl)) { - //return meta data - DnsResourceRecord[] answer; + if (allowed) + { + DnsDatagram internalResponse = await _dnsServer.DirectQueryAsync(question); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, internalResponse.AuthoritativeAnswer, internalResponse.Truncation, request.RecursionDesired, internalResponse.RecursionAvailable, internalResponse.AuthenticData, internalResponse.CheckingDisabled, internalResponse.RCODE, request.Question, internalResponse.Answer, internalResponse.Authority, internalResponse.Additional) { Tag = internalResponse.Tag }; + } + + return null; + } + + string GetBlockingReport() + { + string blockingReport = "source=advanced-blocking-app; group=" + group.Name; if (blockedRegex is null) { if (blockListUrl is not null) - answer = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData("source=advanced-blocking-app; group=" + group.Name + "; blockListUrl=" + blockListUrl.AbsoluteUri + "; domain=" + blockedDomain)) }; + blockingReport += "; blockListUrl=" + blockListUrl.AbsoluteUri + "; domain=" + blockedDomain; else - answer = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData("source=advanced-blocking-app; group=" + group.Name + "; domain=" + blockedDomain)) }; + blockingReport += "; domain=" + blockedDomain; } else { if (blockListUrl is not null) - answer = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData("source=advanced-blocking-app; group=" + group.Name + "; regexBlockListUrl=" + blockListUrl.AbsoluteUri + "; regex=" + blockedRegex)) }; + blockingReport += "; regexBlockListUrl=" + blockListUrl.AbsoluteUri + "; regex=" + blockedRegex; else - answer = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData("source=advanced-blocking-app; group=" + group.Name + "; regex=" + blockedRegex)) }; + blockingReport += "; regex=" + blockedRegex; } - return Task.FromResult(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answer) { Tag = DnsServerResponseType.Blocked }); + return blockingReport; + } + + if (group.AllowTxtBlockingReport && (question.Type == DnsResourceRecordType.TXT)) + { + //return meta data + string blockingReport = GetBlockingReport(); + + DnsResourceRecord[] answer = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData(blockingReport)) }; + + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answer) { Tag = DnsServerResponseType.Blocked }; } else { + EDnsOption[] options = null; + + if (group.AllowTxtBlockingReport && (request.EDNS is not null)) + { + string blockingReport = GetBlockingReport(); + + options = new EDnsOption[] { new EDnsOption(EDnsOptionCode.EXTENDED_DNS_ERROR, new EDnsExtendedDnsErrorOptionData(EDnsExtendedDnsErrorCode.Blocked, blockingReport)) }; + } + DnsResponseCode rcode; IReadOnlyList answer = null; IReadOnlyList authority = null; @@ -540,7 +567,7 @@ namespace AdvancedBlocking } } - return Task.FromResult(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, rcode, request.Question, answer, authority) { Tag = DnsServerResponseType.Blocked }); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, rcode, request.Question, answer, authority, null, request.EDNS is null ? ushort.MinValue : _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options) { Tag = DnsServerResponseType.Blocked }; } } @@ -727,7 +754,7 @@ namespace AdvancedBlocking } } - public bool IsZoneBlocked(string domain, out string blockedDomain, out string blockedRegex, out Uri listUrl) + public bool IsZoneBlocked(string domain, out bool allowed, out string blockedDomain, out string blockedRegex, out Uri listUrl) { domain = domain.ToLower(); @@ -735,6 +762,7 @@ namespace AdvancedBlocking if (IsZoneFound(_allowed, domain, out _) || IsZoneFound(_allowListZones, domain, out _, out _) || IsMatchFound(_allowedRegex, domain, out _) || IsMatchFound(_regexAllowListZones, domain, out _, out _) || IsZoneAllowed(_adBlockListZones, domain, out _, out _)) { //found zone allowed + allowed = true; blockedDomain = null; blockedRegex = null; listUrl = null; @@ -745,6 +773,7 @@ namespace AdvancedBlocking if (IsZoneFound(_blocked, domain, out string foundZone1)) { //found zone blocked + allowed = false; blockedDomain = foundZone1; blockedRegex = null; listUrl = null; @@ -755,6 +784,7 @@ namespace AdvancedBlocking if (IsZoneFound(_blockListZones, domain, out string foundZone2, out Uri blockListUrl1)) { //found zone blocked + allowed = false; blockedDomain = foundZone2; blockedRegex = null; listUrl = blockListUrl1; @@ -765,6 +795,7 @@ namespace AdvancedBlocking if (IsMatchFound(_blockedRegex, domain, out string blockedPattern1)) { //found pattern blocked + allowed = false; blockedDomain = null; blockedRegex = blockedPattern1; listUrl = null; @@ -775,6 +806,7 @@ namespace AdvancedBlocking if (IsMatchFound(_regexBlockListZones, domain, out string blockedPattern2, out Uri blockListUrl2)) { //found pattern blocked + allowed = false; blockedDomain = null; blockedRegex = blockedPattern2; listUrl = blockListUrl2; @@ -785,12 +817,14 @@ namespace AdvancedBlocking if (App.IsZoneBlocked(_adBlockListZones, domain, out string foundZone3, out Uri blockListUrl3)) { //found zone blocked + allowed = false; blockedDomain = foundZone3; blockedRegex = null; listUrl = blockListUrl3; return true; } + allowed = false; blockedDomain = null; blockedRegex = null; listUrl = null; From 29d35fb0222f8a3ad972ba20cb5ca815b6a368e7 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 12:51:19 +0530 Subject: [PATCH 135/191] AuthZoneInfo: implemented Equals() and GetHashCode() methods. --- DnsServerCore/Dns/Zones/AuthZoneInfo.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs index 18432d9f..0f03a3d1 100644 --- a/DnsServerCore/Dns/Zones/AuthZoneInfo.cs +++ b/DnsServerCore/Dns/Zones/AuthZoneInfo.cs @@ -630,6 +630,22 @@ namespace DnsServerCore.Dns.Zones return _name.CompareTo(other._name); } + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) + return true; + + if (obj is not AuthZoneInfo other) + return false; + + return _name.Equals(other._name, StringComparison.OrdinalIgnoreCase); + } + + public override int GetHashCode() + { + return _name.GetHashCode(); + } + public override string ToString() { return _name; From 06282fc8c06192cc660ef4c92c88646bddaa4485 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 12:56:09 +0530 Subject: [PATCH 136/191] AuthZoneManager: Implemented zone index to allow paginated access to zones list. --- .../Dns/ZoneManagers/AuthZoneManager.cs | 463 ++++++++++++------ 1 file changed, 305 insertions(+), 158 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs index a504b7e5..c444975f 100644 --- a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs @@ -45,7 +45,8 @@ namespace DnsServerCore.Dns.ZoneManagers readonly AuthZoneTree _root = new AuthZoneTree(); - int _totalZones; + readonly List _zoneIndex = new List(10); + readonly ReaderWriterLockSlim _zoneIndexLock = new ReaderWriterLockSlim(); #endregion @@ -94,7 +95,7 @@ namespace DnsServerCore.Dns.ZoneManagers //update authoritative zone SOA and NS records try { - List zones = GetAllZones(); + IReadOnlyList zones = GetAllZones(); foreach (AuthZoneInfo zone in zones) { @@ -179,10 +180,7 @@ namespace DnsServerCore.Dns.ZoneManagers } if (_root.TryAdd(zone)) - { - _totalZones++; return zone; - } throw new DnsServerException("Zone already exists: " + zoneInfo.Name); } @@ -462,7 +460,16 @@ namespace DnsServerCore.Dns.ZoneManagers internal void Flush() { - _root.Clear(); + _zoneIndexLock.EnterWriteLock(); + try + { + _root.Clear(); + _zoneIndex.Clear(); + } + finally + { + _zoneIndexLock.ExitWriteLock(); + } } private static IReadOnlyList CondenseIncrementalZoneTransferRecords(string zoneName, DnsResourceRecord currentSoaRecord, IReadOnlyList xfrRecords) @@ -652,7 +659,7 @@ namespace DnsServerCore.Dns.ZoneManagers public void LoadAllZoneFiles() { - _root.Clear(); + Flush(); string zonesFolder = Path.Combine(_dnsServer.ConfigFolder, "zones"); if (!Directory.Exists(zonesFolder)) @@ -666,7 +673,7 @@ namespace DnsServerCore.Dns.ZoneManagers File.Move(oldZoneFile, Path.Combine(zonesFolder, Path.GetFileName(oldZoneFile))); } - //remove old internal zones + //remove old internal zones files { string[] oldZoneFiles = new string[] { "localhost.zone", "1.0.0.127.in-addr.arpa.zone", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.zone" }; @@ -722,27 +729,38 @@ namespace DnsServerCore.Dns.ZoneManagers } //load zone files - string[] zoneFiles = Directory.GetFiles(zonesFolder, "*.zone"); - - foreach (string zoneFile in zoneFiles) + _zoneIndexLock.EnterWriteLock(); + try { - try - { - using (FileStream fS = new FileStream(zoneFile, FileMode.Open, FileAccess.Read)) - { - LoadZoneFrom(fS); - } + string[] zoneFiles = Directory.GetFiles(zonesFolder, "*.zone"); - LogManager log = _dnsServer.LogManager; - if (log != null) - log.Write("DNS Server successfully loaded zone file: " + zoneFile); - } - catch (Exception ex) + foreach (string zoneFile in zoneFiles) { - LogManager log = _dnsServer.LogManager; - if (log != null) - log.Write("DNS Server failed to load zone file: " + zoneFile + "\r\n" + ex.ToString()); + try + { + using (FileStream fS = new FileStream(zoneFile, FileMode.Open, FileAccess.Read)) + { + AuthZoneInfo zoneInfo = LoadZoneFrom(fS); + _zoneIndex.Add(zoneInfo); + } + + LogManager log = _dnsServer.LogManager; + if (log != null) + log.Write("DNS Server successfully loaded zone file: " + zoneFile); + } + catch (Exception ex) + { + LogManager log = _dnsServer.LogManager; + if (log != null) + log.Write("DNS Server failed to load zone file: " + zoneFile + "\r\n" + ex.ToString()); + } } + + _zoneIndex.Sort(); + } + finally + { + _zoneIndexLock.ExitWriteLock(); } } @@ -750,10 +768,21 @@ namespace DnsServerCore.Dns.ZoneManagers { PrimaryZone apexZone = new PrimaryZone(_dnsServer, zoneName, soaRecord, ns); - if (_root.TryAdd(apexZone)) + _zoneIndexLock.EnterWriteLock(); + try { - _totalZones++; - return new AuthZoneInfo(apexZone); + if (_root.TryAdd(apexZone)) + { + AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone); + _zoneIndex.Add(zoneInfo); + _zoneIndex.Sort(); + + return zoneInfo; + } + } + finally + { + _zoneIndexLock.ExitWriteLock(); } return null; @@ -763,10 +792,21 @@ namespace DnsServerCore.Dns.ZoneManagers { PrimaryZone apexZone = new PrimaryZone(_dnsServer, zoneName, primaryNameServer, @internal); - if (_root.TryAdd(apexZone)) + _zoneIndexLock.EnterWriteLock(); + try { - _totalZones++; - return new AuthZoneInfo(apexZone); + if (_root.TryAdd(apexZone)) + { + AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone); + _zoneIndex.Add(zoneInfo); + _zoneIndex.Sort(); + + return zoneInfo; + } + } + finally + { + _zoneIndexLock.ExitWriteLock(); } return null; @@ -776,11 +816,23 @@ namespace DnsServerCore.Dns.ZoneManagers { SecondaryZone apexZone = await SecondaryZone.CreateAsync(_dnsServer, zoneName, primaryNameServerAddresses, zoneTransferProtocol, tsigKeyName); - if (_root.TryAdd(apexZone)) + _zoneIndexLock.EnterWriteLock(); + try { - apexZone.TriggerRefresh(0); - _totalZones++; - return new AuthZoneInfo(apexZone); + if (_root.TryAdd(apexZone)) + { + apexZone.TriggerRefresh(0); + + AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone); + _zoneIndex.Add(zoneInfo); + _zoneIndex.Sort(); + + return zoneInfo; + } + } + finally + { + _zoneIndexLock.ExitWriteLock(); } return null; @@ -790,11 +842,23 @@ namespace DnsServerCore.Dns.ZoneManagers { StubZone apexZone = await StubZone.CreateAsync(_dnsServer, zoneName, primaryNameServerAddresses); - if (_root.TryAdd(apexZone)) + _zoneIndexLock.EnterWriteLock(); + try { - apexZone.TriggerRefresh(0); - _totalZones++; - return new AuthZoneInfo(apexZone); + if (_root.TryAdd(apexZone)) + { + apexZone.TriggerRefresh(0); + + AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone); + _zoneIndex.Add(zoneInfo); + _zoneIndex.Sort(); + + return zoneInfo; + } + } + finally + { + _zoneIndexLock.ExitWriteLock(); } return null; @@ -804,10 +868,21 @@ namespace DnsServerCore.Dns.ZoneManagers { ForwarderZone apexZone = new ForwarderZone(zoneName, forwarderProtocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, fwdRecordComments); - if (_root.TryAdd(apexZone)) + _zoneIndexLock.EnterWriteLock(); + try { - _totalZones++; - return new AuthZoneInfo(apexZone); + if (_root.TryAdd(apexZone)) + { + AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone); + _zoneIndex.Add(zoneInfo); + _zoneIndex.Sort(); + + return zoneInfo; + } + } + finally + { + _zoneIndexLock.ExitWriteLock(); } return null; @@ -943,12 +1018,23 @@ namespace DnsServerCore.Dns.ZoneManagers public bool DeleteZone(string zoneName) { - if (_root.TryRemove(zoneName, out ApexZone apexZone)) + _zoneIndexLock.EnterWriteLock(); + try { - apexZone.Dispose(); + if (_root.TryRemove(zoneName, out ApexZone apexZone)) + { + apexZone.Dispose(); - _totalZones--; - return true; + AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone); + if (!_zoneIndex.Remove(zoneInfo)) + throw new InvalidOperationException("Zone deleted from tree but failed to remove from zone index."); + + return true; + } + } + finally + { + _zoneIndexLock.ExitWriteLock(); } return false; @@ -1698,31 +1784,49 @@ namespace DnsServerCore.Dns.ZoneManagers } } - public List GetAllZones() + public IReadOnlyList GetAllZones() { - List zones = new List(); - - foreach (AuthZoneNode zoneNode in _root) + _zoneIndexLock.EnterReadLock(); + try { - ApexZone apexZone = zoneNode.ApexZone; - if (apexZone is null) - continue; - - AuthZoneInfo zoneInfo = new AuthZoneInfo(apexZone); - switch (zoneInfo.Type) - { - case AuthZoneType.Primary: - case AuthZoneType.Secondary: - case AuthZoneType.Stub: - case AuthZoneType.Forwarder: - zones.Add(zoneInfo); - break; - } + return new List(_zoneIndex); } + finally + { + _zoneIndexLock.ExitReadLock(); + } + } - _totalZones = zones.Count; + public ZonesPage GetZonesPage(int pageNumber, int zonesPerPage) + { + _zoneIndexLock.EnterReadLock(); + try + { + if (pageNumber < 0) + pageNumber = int.MaxValue; + else if (pageNumber == 0) + pageNumber = 1; - return zones; + int totalZones = _zoneIndex.Count; + int totalPages = (totalZones / zonesPerPage) + (totalZones % zonesPerPage > 0 ? 1 : 0); + + if (pageNumber > totalPages) + pageNumber = totalPages; + + int start = (pageNumber - 1) * zonesPerPage; + int end = Math.Min(start + zonesPerPage, totalZones); + + List zones = new List(end - start); + + for (int i = start; i < end; i++) + zones.Add(_zoneIndex[i]); + + return new ZonesPage(pageNumber, totalPages, totalZones, zones); + } + finally + { + _zoneIndexLock.ExitReadLock(); + } } public void ListSubDomains(string domain, List subDomains) @@ -2018,7 +2122,7 @@ namespace DnsServerCore.Dns.ZoneManagers } } - public void LoadZoneFrom(Stream s) + public AuthZoneInfo LoadZoneFrom(Stream s) { BinaryReader bR = new BinaryReader(s); @@ -2030,108 +2134,110 @@ namespace DnsServerCore.Dns.ZoneManagers case 2: { DnsResourceRecord[] records = new DnsResourceRecord[bR.ReadInt32()]; - if (records.Length > 0) + if (records.Length == 0) + throw new InvalidDataException("Zone does not contain SOA record."); + + DnsResourceRecord soaRecord = null; + + for (int i = 0; i < records.Length; i++) { - DnsResourceRecord soaRecord = null; + records[i] = new DnsResourceRecord(s); - for (int i = 0; i < records.Length; i++) - { - records[i] = new DnsResourceRecord(s); - - if (records[i].Type == DnsResourceRecordType.SOA) - soaRecord = records[i]; - } - - if (soaRecord == null) - throw new InvalidDataException("Zone does not contain SOA record."); - - //make zone info - AuthZoneType zoneType; - if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecordData).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) - zoneType = AuthZoneType.Primary; - else - zoneType = AuthZoneType.Stub; - - AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, false); - - //create zone - ApexZone apexZone = CreateEmptyZone(zoneInfo); - - try - { - //load records - LoadRecords(apexZone, records); - } - catch - { - DeleteZone(zoneInfo.Name); - throw; - } - - //init zone - switch (zoneInfo.Type) - { - case AuthZoneType.Primary: - (apexZone as PrimaryZone).TriggerNotify(); - break; - } + if (records[i].Type == DnsResourceRecordType.SOA) + soaRecord = records[i]; } + + if (soaRecord == null) + throw new InvalidDataException("Zone does not contain SOA record."); + + //make zone info + AuthZoneType zoneType; + if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecordData).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) + zoneType = AuthZoneType.Primary; + else + zoneType = AuthZoneType.Stub; + + AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, false); + + //create zone + ApexZone apexZone = CreateEmptyZone(zoneInfo); + + try + { + //load records + LoadRecords(apexZone, records); + } + catch + { + DeleteZone(zoneInfo.Name); + throw; + } + + //init zone + switch (zoneInfo.Type) + { + case AuthZoneType.Primary: + (apexZone as PrimaryZone).TriggerNotify(); + break; + } + + return new AuthZoneInfo(apexZone); } - break; case 3: { bool zoneDisabled = bR.ReadBoolean(); DnsResourceRecord[] records = new DnsResourceRecord[bR.ReadInt32()]; - if (records.Length > 0) + if (records.Length == 0) + throw new InvalidDataException("Zone does not contain SOA record."); + + DnsResourceRecord soaRecord = null; + + for (int i = 0; i < records.Length; i++) { - DnsResourceRecord soaRecord = null; + records[i] = new DnsResourceRecord(s); + records[i].Tag = new AuthRecordInfo(bR, records[i].Type == DnsResourceRecordType.SOA); - for (int i = 0; i < records.Length; i++) - { - records[i] = new DnsResourceRecord(s); - records[i].Tag = new AuthRecordInfo(bR, records[i].Type == DnsResourceRecordType.SOA); - - if (records[i].Type == DnsResourceRecordType.SOA) - soaRecord = records[i]; - } - - if (soaRecord == null) - throw new InvalidDataException("Zone does not contain SOA record."); - - //make zone info - AuthZoneType zoneType; - if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecordData).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) - zoneType = AuthZoneType.Primary; - else - zoneType = AuthZoneType.Stub; - - AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, zoneDisabled); - - //create zone - ApexZone apexZone = CreateEmptyZone(zoneInfo); - - try - { - //load records - LoadRecords(apexZone, records); - } - catch - { - DeleteZone(zoneInfo.Name); - throw; - } - - //init zone - switch (zoneInfo.Type) - { - case AuthZoneType.Primary: - (apexZone as PrimaryZone).TriggerNotify(); - break; - } + if (records[i].Type == DnsResourceRecordType.SOA) + soaRecord = records[i]; } + + if (soaRecord == null) + throw new InvalidDataException("Zone does not contain SOA record."); + + //make zone info + AuthZoneType zoneType; + if (_dnsServer.ServerDomain.Equals((soaRecord.RDATA as DnsSOARecordData).PrimaryNameServer, StringComparison.OrdinalIgnoreCase)) + zoneType = AuthZoneType.Primary; + else + zoneType = AuthZoneType.Stub; + + AuthZoneInfo zoneInfo = new AuthZoneInfo(records[0].Name, zoneType, zoneDisabled); + + //create zone + ApexZone apexZone = CreateEmptyZone(zoneInfo); + + try + { + //load records + LoadRecords(apexZone, records); + } + catch + { + DeleteZone(zoneInfo.Name); + throw; + } + + //init zone + switch (zoneInfo.Type) + { + case AuthZoneType.Primary: + (apexZone as PrimaryZone).TriggerNotify(); + break; + } + + return new AuthZoneInfo(apexZone); } - break; case 4: { @@ -2181,8 +2287,9 @@ namespace DnsServerCore.Dns.ZoneManagers break; } } + + return new AuthZoneInfo(apexZone); } - break; default: throw new InvalidDataException("DNS Zone file version not supported."); @@ -2269,8 +2376,48 @@ namespace DnsServerCore.Dns.ZoneManagers } public int TotalZones - { get { return _totalZones; } } + { get { return _zoneIndex.Count; } } #endregion + + public class ZonesPage + { + #region variables + + readonly long _pageNumber; + readonly long _totalPages; + readonly long _totalZones; + readonly IReadOnlyList _zones; + + #endregion + + #region constructor + + public ZonesPage(long pageNumber, long totalPages, long totalZones, IReadOnlyList zones) + { + _pageNumber = pageNumber; + _totalPages = totalPages; + _totalZones = totalZones; + _zones = zones; + } + + #endregion + + #region properties + + public long PageNumber + { get { return _pageNumber; } } + + public long TotalPages + { get { return _totalPages; } } + + public long TotalZones + { get { return _totalZones; } } + + public IReadOnlyList Zones + { get { return _zones; } } + + #endregion + } } } From f71c7008b524ee899edbd7ab8b295f4006b536c5 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 12:57:41 +0530 Subject: [PATCH 137/191] code refactoring changes. --- DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs | 4 ++-- DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs index bef3147c..9e9656fb 100644 --- a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs @@ -137,7 +137,7 @@ namespace DnsServerCore.Dns.ZoneManagers _zoneManager.Flush(); } - public List ListZones() + public IReadOnlyList GetAllZones() { return _zoneManager.GetAllZones(); } @@ -154,7 +154,7 @@ namespace DnsServerCore.Dns.ZoneManagers public void SaveZoneFile() { - List allowedZones = _dnsServer.AllowedZoneManager.ListZones(); + IReadOnlyList allowedZones = _dnsServer.AllowedZoneManager.GetAllZones(); string allowedZoneFile = Path.Combine(_dnsServer.ConfigFolder, "allowed.config"); diff --git a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs index 0f410f7f..8214001e 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs @@ -155,7 +155,7 @@ namespace DnsServerCore.Dns.ZoneManagers _zoneManager.Flush(); } - public List ListZones() + public IReadOnlyList GetAllZones() { return _zoneManager.GetAllZones(); } @@ -172,7 +172,7 @@ namespace DnsServerCore.Dns.ZoneManagers public void SaveZoneFile() { - List blockedZones = _dnsServer.BlockedZoneManager.ListZones(); + IReadOnlyList blockedZones = _dnsServer.BlockedZoneManager.GetAllZones(); string blockedZoneFile = Path.Combine(_dnsServer.ConfigFolder, "blocked.config"); From 3dab7b5f4bb36fe42fb90790cdefc5c2b43b4da0 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 12:59:07 +0530 Subject: [PATCH 138/191] BlockListZoneManager: implemented extended error report for blocked domain report. --- .../Dns/ZoneManagers/BlockListZoneManager.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs index 022e8e4d..ac715ade 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs @@ -27,6 +27,7 @@ using System.Text; using System.Threading.Tasks; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns; +using TechnitiumLibrary.Net.Dns.EDnsOptions; using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore.Dns.ZoneManagers @@ -422,10 +423,20 @@ namespace DnsServerCore.Dns.ZoneManagers for (int i = 0; i < answer.Length; i++) answer[i] = new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData("source=block-list-zone; blockListUrl=" + blockLists[i].AbsoluteUri + "; domain=" + blockedDomain)); - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answer); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answer); } else { + EDnsOption[] options = null; + + if (_dnsServer.AllowTxtBlockingReport && (request.EDNS is not null)) + { + options = new EDnsOption[blockLists.Count]; + + for (int i = 0; i < options.Length; i++) + options[i] = new EDnsOption(EDnsOptionCode.EXTENDED_DNS_ERROR, new EDnsExtendedDnsErrorOptionData(EDnsExtendedDnsErrorCode.Blocked, "source=block-list-zone; blockListUrl=" + blockLists[i].AbsoluteUri + "; domain=" + blockedDomain)); + } + IReadOnlyCollection aRecords; IReadOnlyCollection aaaaRecords; @@ -446,7 +457,7 @@ namespace DnsServerCore.Dns.ZoneManagers if (parentDomain is null) parentDomain = string.Empty; - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NxDomain, request.Question, null, new DnsResourceRecord[] { new DnsResourceRecord(parentDomain, DnsResourceRecordType.SOA, question.Class, 60, _soaRecord) }); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NxDomain, request.Question, null, new DnsResourceRecord[] { new DnsResourceRecord(parentDomain, DnsResourceRecordType.SOA, question.Class, 60, _soaRecord) }, null, request.EDNS is null ? ushort.MinValue : _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options); default: throw new InvalidOperationException(); @@ -496,7 +507,7 @@ namespace DnsServerCore.Dns.ZoneManagers break; } - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answer, authority); + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answer, authority, null, request.EDNS is null ? ushort.MinValue : _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options); } } From f0b611fa9011bbf75df4806905323e8625dfe483 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:00:14 +0530 Subject: [PATCH 139/191] ResolverDnsCache: added option to skip calling app authoritative request handlers. --- DnsServerCore/Dns/ResolverDnsCache.cs | 33 +++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/DnsServerCore/Dns/ResolverDnsCache.cs b/DnsServerCore/Dns/ResolverDnsCache.cs index f57ade5e..dae91c6a 100644 --- a/DnsServerCore/Dns/ResolverDnsCache.cs +++ b/DnsServerCore/Dns/ResolverDnsCache.cs @@ -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 @@ -36,17 +36,19 @@ namespace DnsServerCore.Dns readonly AuthZoneManager _authZoneManager; readonly CacheZoneManager _cacheZoneManager; readonly LogManager _log; + readonly bool _skipDnsAppAuthoritativeRequestHandlers; #endregion #region constructor - public ResolverDnsCache(DnsApplicationManager dnsApplicationManager, AuthZoneManager authZoneManager, CacheZoneManager cacheZoneManager, LogManager log) + public ResolverDnsCache(DnsApplicationManager dnsApplicationManager, AuthZoneManager authZoneManager, CacheZoneManager cacheZoneManager, LogManager log, bool skipDnsAppAuthoritativeRequestHandlers) { _dnsApplicationManager = dnsApplicationManager; _authZoneManager = authZoneManager; _cacheZoneManager = cacheZoneManager; _log = log; + _skipDnsAppAuthoritativeRequestHandlers = skipDnsAppAuthoritativeRequestHandlers; } #endregion @@ -55,7 +57,7 @@ namespace DnsServerCore.Dns private DnsDatagram DnsApplicationQueryClosestDelegation(DnsDatagram request) { - if ((_dnsApplicationManager.DnsAuthoritativeRequestHandlers.Count < 1) || (request.Question.Count != 1)) + if (_skipDnsAppAuthoritativeRequestHandlers || (_dnsApplicationManager.DnsAuthoritativeRequestHandlers.Count < 1) || (request.Question.Count != 1)) return null; IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 0); @@ -132,21 +134,24 @@ namespace DnsServerCore.Dns { DnsDatagram authResponse = null; - foreach (IDnsAuthoritativeRequestHandler requestHandler in _dnsApplicationManager.DnsAuthoritativeRequestHandlers) + if (!_skipDnsAppAuthoritativeRequestHandlers) { - try + foreach (IDnsAuthoritativeRequestHandler requestHandler in _dnsApplicationManager.DnsAuthoritativeRequestHandlers) { - authResponse = requestHandler.ProcessRequestAsync(request, new IPEndPoint(IPAddress.Any, 0), DnsTransportProtocol.Tcp, false).Sync(); - if (authResponse is not null) + try { - if ((authResponse.RCODE != DnsResponseCode.NoError) || (authResponse.Answer.Count > 0) || (authResponse.Authority.Count == 0) || authResponse.IsFirstAuthoritySOA()) - return authResponse; + authResponse = requestHandler.ProcessRequestAsync(request, new IPEndPoint(IPAddress.Any, 0), DnsTransportProtocol.Tcp, false).Sync(); + if (authResponse is not null) + { + if ((authResponse.RCODE != DnsResponseCode.NoError) || (authResponse.Answer.Count > 0) || (authResponse.Authority.Count == 0) || authResponse.IsFirstAuthoritySOA()) + return authResponse; + } + } + catch (Exception ex) + { + if (_log is not null) + _log.Write(ex); } - } - catch (Exception ex) - { - if (_log is not null) - _log.Write(ex); } } From a154173bcc3a007c7f9c3f7ae1d12bf182ad8fd7 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:00:46 +0530 Subject: [PATCH 140/191] ResolverPrefetchDnsCache: code refactoring changes. --- DnsServerCore/Dns/ResolverPrefetchDnsCache.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DnsServerCore/Dns/ResolverPrefetchDnsCache.cs b/DnsServerCore/Dns/ResolverPrefetchDnsCache.cs index 90c74c14..a7bb049f 100644 --- a/DnsServerCore/Dns/ResolverPrefetchDnsCache.cs +++ b/DnsServerCore/Dns/ResolverPrefetchDnsCache.cs @@ -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 @@ -33,8 +33,8 @@ namespace DnsServerCore.Dns #region constructor - public ResolverPrefetchDnsCache(DnsApplicationManager dnsApplicationManager, AuthZoneManager authZoneManager, CacheZoneManager cacheZoneManager, LogManager log, DnsQuestionRecord prefetchQuestion) - : base(dnsApplicationManager, authZoneManager, cacheZoneManager, log) + public ResolverPrefetchDnsCache(DnsApplicationManager dnsApplicationManager, AuthZoneManager authZoneManager, CacheZoneManager cacheZoneManager, LogManager log, bool skipDnsAppAuthoritativeRequestHandlers, DnsQuestionRecord prefetchQuestion) + : base(dnsApplicationManager, authZoneManager, cacheZoneManager, log, skipDnsAppAuthoritativeRequestHandlers) { _prefetchQuestion = prefetchQuestion; } From dffda22867511fd3fd6ad8aeb08091aac28549af Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:01:39 +0530 Subject: [PATCH 141/191] StatsManager: updated code to support new response types. --- DnsServerCore/Dns/StatsManager.cs | 35 ++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/DnsServerCore/Dns/StatsManager.cs b/DnsServerCore/Dns/StatsManager.cs index d5a308a5..803c3521 100644 --- a/DnsServerCore/Dns/StatsManager.cs +++ b/DnsServerCore/Dns/StatsManager.cs @@ -1537,10 +1537,21 @@ namespace DnsServerCore.Dns switch (responseCode) { case DnsResponseCode.NoError: - if ((query is not null) && (responseType != DnsServerResponseType.Blocked)) //skip blocked domains + if (query is not null) { - _queryDomains.GetOrAdd(query.Name.ToLower(), GetNewCounter).Increment(); - _queries.GetOrAdd(query, GetNewCounter).Increment(); + switch (responseType) + { + case DnsServerResponseType.Blocked: + case DnsServerResponseType.UpstreamBlocked: + case DnsServerResponseType.CacheBlocked: + //skip blocked domains + break; + + default: + _queryDomains.GetOrAdd(query.Name.ToLower(), GetNewCounter).Increment(); + _queries.GetOrAdd(query, GetNewCounter).Increment(); + break; + } } Interlocked.Increment(ref _totalNoError); @@ -1585,6 +1596,24 @@ namespace DnsServerCore.Dns Interlocked.Increment(ref _totalBlocked); break; + + case DnsServerResponseType.UpstreamBlocked: + Interlocked.Increment(ref _totalRecursive); + + if (query is not null) + _queryBlockedDomains.GetOrAdd(query.Name.ToLower(), GetNewCounter).Increment(); + + Interlocked.Increment(ref _totalBlocked); + break; + + case DnsServerResponseType.CacheBlocked: + Interlocked.Increment(ref _totalCached); + + if (query is not null) + _queryBlockedDomains.GetOrAdd(query.Name.ToLower(), GetNewCounter).Increment(); + + Interlocked.Increment(ref _totalBlocked); + break; } if (query is not null) From 8239139015529219fcaaca17ac46f729fc271df1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:06:27 +0530 Subject: [PATCH 142/191] DnsServer: removed doh-port 80 compatibility option. Updated ProcessBlockedQuery() to support extended dns error for blocked domain report. Updated ProcessRecusriveQueryAsync() to support new response types. Updated RecursiveResolveAsync() to use new ResolveDnsCache object with skip option enabled. Updated PrepareRecursiveResolveResponse() to copy dns client extended errors to get similar response as from cache. --- DnsServerCore/Dns/DnsServer.cs | 147 ++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 67 deletions(-) diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index 0ed6933d..0133c080 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -145,9 +145,8 @@ namespace DnsServerCore.Dns bool _enableDnsOverHttp; bool _enableDnsOverTls; bool _enableDnsOverHttps; - bool _enableDnsOverHttpPort80; bool _enableDnsOverQuic; - int _dnsOverHttpPort = 8053; + int _dnsOverHttpPort = 80; int _dnsOverTlsPort = 853; int _dnsOverHttpsPort = 443; int _dnsOverQuicPort = 853; @@ -258,7 +257,7 @@ namespace DnsServerCore.Dns _cacheZoneManager = new CacheZoneManager(this); _dnsApplicationManager = new DnsApplicationManager(this); - _dnsCache = new ResolverDnsCache(_dnsApplicationManager, _authZoneManager, _cacheZoneManager, _log); + _dnsCache = new ResolverDnsCache(_dnsApplicationManager, _authZoneManager, _cacheZoneManager, _log, false); //init stats _stats = new StatsManager(this); @@ -1075,7 +1074,7 @@ namespace DnsServerCore.Dns if ((question.Type == DnsResourceRecordType.ANY) && (protocol == DnsTransportProtocol.Udp)) //force TCP for ANY request return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, true, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question) { Tag = DnsServerResponseType.Authoritative }; - return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, null, _dnssecValidation, false); + return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, null, _dnssecValidation, false, skipDnsAppAuthoritativeRequestHandlers); } catch (InvalidDomainNameException) { @@ -1888,10 +1887,10 @@ namespace DnsServerCore.Dns switch (lastRR.Type) { case DnsResourceRecordType.CNAME: - return await ProcessCNAMEAsync(request, remoteEP, response, isRecursionAllowed, protocol, false); + return await ProcessCNAMEAsync(request, remoteEP, response, isRecursionAllowed, protocol, false, skipDnsAppAuthoritativeRequestHandlers); case DnsResourceRecordType.ANAME: - return await ProcessANAMEAsync(request, remoteEP, response, isRecursionAllowed, protocol); + return await ProcessANAMEAsync(request, remoteEP, response, isRecursionAllowed, protocol, skipDnsAppAuthoritativeRequestHandlers); } } } @@ -1904,7 +1903,7 @@ namespace DnsServerCore.Dns if (request.RecursionDesired && isRecursionAllowed) { //do forced recursive resolution using empty conditional forwarders; name servers will be provided via ResolverDnsCache - return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, Array.Empty(), _dnssecValidation, false); + return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, Array.Empty(), _dnssecValidation, false, skipDnsAppAuthoritativeRequestHandlers); } break; @@ -1913,12 +1912,12 @@ namespace DnsServerCore.Dns 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); + 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); + return await ProcessRecursiveQueryAsync(request, remoteEP, protocol, response.Authority, _dnssecValidation, false, skipDnsAppAuthoritativeRequestHandlers); } case DnsResourceRecordType.APP: @@ -2006,7 +2005,7 @@ namespace DnsServerCore.Dns } } - private async Task ProcessCNAMEAsync(DnsDatagram request, IPEndPoint remoteEP, DnsDatagram response, bool isRecursionAllowed, DnsTransportProtocol protocol, bool cacheRefreshOperation) + private async Task ProcessCNAMEAsync(DnsDatagram request, IPEndPoint remoteEP, DnsDatagram response, bool isRecursionAllowed, DnsTransportProtocol protocol, bool cacheRefreshOperation, bool skipDnsAppAuthoritativeRequestHandlers) { List newAnswer = new List(response.Answer.Count + 4); newAnswer.AddRange(response.Answer); @@ -2065,7 +2064,7 @@ namespace DnsServerCore.Dns if (newRequest.RecursionDesired && isRecursionAllowed) { //do recursion - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, null, _dnssecValidation, false, cacheRefreshOperation); + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, null, _dnssecValidation, false, cacheRefreshOperation, skipDnsAppAuthoritativeRequestHandlers); isAuthoritativeAnswer = false; } else @@ -2076,7 +2075,7 @@ namespace DnsServerCore.Dns } else if ((newResponse.Answer.Count > 0) && (newResponse.GetLastAnswerRecord().Type == DnsResourceRecordType.ANAME)) { - newResponse = await ProcessANAMEAsync(request, remoteEP, newResponse, isRecursionAllowed, protocol); + newResponse = await ProcessANAMEAsync(request, remoteEP, newResponse, isRecursionAllowed, protocol, skipDnsAppAuthoritativeRequestHandlers); } else if ((newResponse.Answer.Count == 0) && (newResponse.Authority.Count > 0)) { @@ -2088,7 +2087,7 @@ namespace DnsServerCore.Dns if (newRequest.RecursionDesired && isRecursionAllowed) { //do forced recursive resolution using empty conditional forwarders; name servers will be provided via ResolveDnsCache - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, Array.Empty(), _dnssecValidation, false, false); + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, Array.Empty(), _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); isAuthoritativeAnswer = false; } @@ -2098,13 +2097,13 @@ namespace DnsServerCore.Dns 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); + 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); + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, newResponse.Authority, _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); isAuthoritativeAnswer = false; } @@ -2191,7 +2190,7 @@ namespace DnsServerCore.Dns return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, isAuthoritativeAnswer, false, request.RecursionDesired, isRecursionAllowed, false, request.CheckingDisabled, rcode, request.Question, newAnswer, authority, additional) { Tag = response.Tag }; } - private async Task ProcessANAMEAsync(DnsDatagram request, IPEndPoint remoteEP, DnsDatagram response, bool isRecursionAllowed, DnsTransportProtocol protocol) + private async Task ProcessANAMEAsync(DnsDatagram request, IPEndPoint remoteEP, DnsDatagram response, bool isRecursionAllowed, DnsTransportProtocol protocol, bool skipDnsAppAuthoritativeRequestHandlers) { EDnsOption[] eDnsClientSubnetOption = null; @@ -2219,7 +2218,7 @@ namespace DnsServerCore.Dns if (newResponse is null) { //not found in auth zone; do recursion - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, null, _dnssecValidation, false, false); + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, null, _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); } else if ((newResponse.Answer.Count == 0) && (newResponse.Authority.Count > 0)) { @@ -2229,19 +2228,19 @@ namespace DnsServerCore.Dns { case DnsResourceRecordType.NS: //do forced recursive resolution using empty conditional forwarders; name servers will be provided via ResolverDnsCache - newResponse = await RecursiveResolveAsync(newRequest, remoteEP, Array.Empty(), _dnssecValidation, false, false); + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, Array.Empty(), _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); 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); + 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); + newResponse = await RecursiveResolveAsync(newRequest, remoteEP, newResponse.Authority, _dnssecValidation, false, false, skipDnsAppAuthoritativeRequestHandlers); } break; @@ -2392,23 +2391,35 @@ namespace DnsServerCore.Dns //domain is blocked in blocked zone DnsQuestionRecord question = request.Question[0]; + string GetBlockedDomain() + { + DnsResourceRecord firstAuthority = response.FindFirstAuthorityRecord(); + if ((firstAuthority is not null) && (firstAuthority.Type == DnsResourceRecordType.SOA)) + return firstAuthority.Name; + else + return question.Name; + } + if (_allowTxtBlockingReport && (question.Type == DnsResourceRecordType.TXT)) { //return meta data - string blockedDomain; - - DnsResourceRecord firstAuthority = response.FindFirstAuthorityRecord(); - if ((firstAuthority is not null) && (firstAuthority.Type == DnsResourceRecordType.SOA)) - blockedDomain = firstAuthority.Name; - else - blockedDomain = question.Name; + string blockedDomain = GetBlockedDomain(); IReadOnlyList answer = new DnsResourceRecord[] { new DnsResourceRecord(question.Name, DnsResourceRecordType.TXT, question.Class, 60, new DnsTXTRecordData("source=blocked-zone; domain=" + blockedDomain)) }; - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answer) { Tag = DnsServerResponseType.Blocked }; + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answer) { Tag = DnsServerResponseType.Blocked }; } else { + string blockedDomain = null; + EDnsOption[] options = null; + + if (_allowTxtBlockingReport && (request.EDNS is not null)) + { + blockedDomain = GetBlockedDomain(); + options = new EDnsOption[] { new EDnsOption(EDnsOptionCode.EXTENDED_DNS_ERROR, new EDnsExtendedDnsErrorOptionData(EDnsExtendedDnsErrorCode.Blocked, "source=blocked-zone; domain=" + blockedDomain)) }; + } + IReadOnlyCollection aRecords; IReadOnlyCollection aaaaRecords; @@ -2425,19 +2436,14 @@ namespace DnsServerCore.Dns break; case DnsServerBlockingType.NxDomain: - string blockedDomain; - - DnsResourceRecord firstAuthority = response.FindFirstAuthorityRecord(); - if ((firstAuthority is not null) && (firstAuthority.Type == DnsResourceRecordType.SOA)) - blockedDomain = firstAuthority.Name; - else - blockedDomain = question.Name; + if (blockedDomain is null) + blockedDomain = GetBlockedDomain(); string parentDomain = AuthZoneManager.GetParentZone(blockedDomain); if (parentDomain is null) parentDomain = string.Empty; - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NxDomain, request.Question, null, new DnsResourceRecord[] { new DnsResourceRecord(parentDomain, DnsResourceRecordType.SOA, question.Class, 60, _blockedZoneManager.DnsSOARecord) }) { Tag = DnsServerResponseType.Blocked }; + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NxDomain, request.Question, null, new DnsResourceRecord[] { new DnsResourceRecord(parentDomain, DnsResourceRecordType.SOA, question.Class, 60, _blockedZoneManager.DnsSOARecord) }, null, request.EDNS is null ? ushort.MinValue : _udpPayloadSize, EDnsHeaderFlags.None, options) { Tag = DnsServerResponseType.Blocked }; default: throw new InvalidOperationException(); @@ -2476,12 +2482,12 @@ namespace DnsServerCore.Dns break; } - return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answer, authority) { Tag = DnsServerResponseType.Blocked }; + return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, answer, authority, null, request.EDNS is null ? ushort.MinValue : _udpPayloadSize, EDnsHeaderFlags.None, options) { Tag = DnsServerResponseType.Blocked }; } } } - private async Task ProcessRecursiveQueryAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, IReadOnlyList conditionalForwarders, bool dnssecValidation, bool cacheRefreshOperation) + private async Task ProcessRecursiveQueryAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, IReadOnlyList conditionalForwarders, bool dnssecValidation, bool cacheRefreshOperation, bool skipDnsAppAuthoritativeRequestHandlers) { bool inAllowedZone; @@ -2507,7 +2513,7 @@ namespace DnsServerCore.Dns } } - DnsDatagram response = await RecursiveResolveAsync(request, remoteEP, conditionalForwarders, dnssecValidation, false, cacheRefreshOperation); + DnsDatagram response = await RecursiveResolveAsync(request, remoteEP, conditionalForwarders, dnssecValidation, false, cacheRefreshOperation, skipDnsAppAuthoritativeRequestHandlers); if (response.Answer.Count > 0) { @@ -2515,7 +2521,7 @@ namespace DnsServerCore.Dns DnsResourceRecord lastRR = response.GetLastAnswerRecord(); if ((lastRR.Type != questionType) && (lastRR.Type == DnsResourceRecordType.CNAME) && (questionType != DnsResourceRecordType.ANY)) - response = await ProcessCNAMEAsync(request, remoteEP, response, true, protocol, cacheRefreshOperation); + response = await ProcessCNAMEAsync(request, remoteEP, response, true, protocol, cacheRefreshOperation, skipDnsAppAuthoritativeRequestHandlers); if (!inAllowedZone) { @@ -2555,10 +2561,21 @@ namespace DnsServerCore.Dns } } + if (response.Tag is null) + { + if (response.IsBlockedResponse()) + response.Tag = DnsServerResponseType.UpstreamBlocked; + } + else if ((DnsServerResponseType)response.Tag == DnsServerResponseType.Cached) + { + if (response.IsBlockedResponse()) + response.Tag = DnsServerResponseType.CacheBlocked; + } + return response; } - private async Task RecursiveResolveAsync(DnsDatagram request, IPEndPoint remoteEP, IReadOnlyList conditionalForwarders, bool dnssecValidation, bool cachePrefetchOperation, bool cacheRefreshOperation) + private async Task RecursiveResolveAsync(DnsDatagram request, IPEndPoint remoteEP, IReadOnlyList conditionalForwarders, bool dnssecValidation, bool cachePrefetchOperation, bool cacheRefreshOperation, bool skipDnsAppAuthoritativeRequestHandlers) { DnsQuestionRecord question = request.Question[0]; NetworkAddress eDnsClientSubnet = null; @@ -2654,7 +2671,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(question, eDnsClientSubnet, conditionalForwarders, dnssecValidation, cachePrefetchOperation, cacheRefreshOperation, resolverTaskCompletionSource); + return RecursiveResolveAsync(question, eDnsClientSubnet, conditionalForwarders, dnssecValidation, cachePrefetchOperation, cacheRefreshOperation, skipDnsAppAuthoritativeRequestHandlers, resolverTaskCompletionSource); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _resolverTaskScheduler); } @@ -2710,7 +2727,7 @@ namespace DnsServerCore.Dns return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.ServerFailure, request.Question, null, null, null, _udpPayloadSize, request.DnssecOk ? EDnsHeaderFlags.DNSSEC_OK : EDnsHeaderFlags.None, options); } - private async Task RecursiveResolveAsync(DnsQuestionRecord question, NetworkAddress eDnsClientSubnet, IReadOnlyList conditionalForwarders, bool dnssecValidation, bool cachePrefetchOperation, bool cacheRefreshOperation, TaskCompletionSource taskCompletionSource) + private async Task RecursiveResolveAsync(DnsQuestionRecord question, NetworkAddress eDnsClientSubnet, IReadOnlyList conditionalForwarders, bool dnssecValidation, bool cachePrefetchOperation, bool cacheRefreshOperation, bool skipDnsAppAuthoritativeRequestHandlers, TaskCompletionSource taskCompletionSource) { try { @@ -2718,7 +2735,9 @@ namespace DnsServerCore.Dns IDnsCache dnsCache; if (cachePrefetchOperation || cacheRefreshOperation) - dnsCache = new ResolverPrefetchDnsCache(_dnsApplicationManager, _authZoneManager, _cacheZoneManager, _log, question); + dnsCache = new ResolverPrefetchDnsCache(_dnsApplicationManager, _authZoneManager, _cacheZoneManager, _log, skipDnsAppAuthoritativeRequestHandlers, question); + else if (skipDnsAppAuthoritativeRequestHandlers) + dnsCache = new ResolverDnsCache(_dnsApplicationManager, _authZoneManager, _cacheZoneManager, _log, true); else dnsCache = _dnsCache; @@ -3152,7 +3171,7 @@ namespace DnsServerCore.Dns //additional section checks if (additional.Count > 0) { - if ((request.EDNS is not null) && (response.EDNS is not null) && (response.EDNS.Options.Count > 0)) + if ((request.EDNS is not null) && (response.EDNS is not null) && ((response.EDNS.Options.Count > 0) || (response.DnsClientExtendedErrors.Count > 0))) { //copy options as new OPT and keep other records List newAdditional = new List(additional.Count); @@ -3211,6 +3230,19 @@ namespace DnsServerCore.Dns options = response.EDNS.Options; } + if (response.DnsClientExtendedErrors.Count > 0) + { + //add dns client extended errors + List newOptions = new List(options.Count + response.DnsClientExtendedErrors.Count); + + newOptions.AddRange(options); + + foreach (EDnsExtendedDnsErrorOptionData ee in response.DnsClientExtendedErrors) + newOptions.Add(new EDnsOption(EDnsOptionCode.EXTENDED_DNS_ERROR, ee)); + + options = newOptions; + } + newAdditional.Add(DnsDatagramEdns.GetOPTFor(_udpPayloadSize, response.RCODE, 0, request.DnssecOk ? EDnsHeaderFlags.DNSSEC_OK : EDnsHeaderFlags.None, options)); additional = newAdditional; @@ -3284,7 +3316,7 @@ namespace DnsServerCore.Dns { try { - await RecursiveResolveAsync(request, remoteEP, conditionalForwarders, _dnssecValidation, true, false); + await RecursiveResolveAsync(request, remoteEP, conditionalForwarders, _dnssecValidation, true, false, false); } catch (Exception ex) { @@ -3298,7 +3330,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, IPENDPOINT_ANY_0, DnsTransportProtocol.Udp, sample.ConditionalForwarders, _dnssecValidation, true); + DnsDatagram response = await ProcessRecursiveQueryAsync(request, IPENDPOINT_ANY_0, DnsTransportProtocol.Udp, sample.ConditionalForwarders, _dnssecValidation, true, false); bool addBackToSampleList = false; DateTime utcNow = DateTime.UtcNow; @@ -3704,13 +3736,6 @@ namespace DnsServerCore.Dns serverOptions.Listen(localAddress, _dnsOverHttpPort); } - //bind to http port 80 for certbot webroot support - if (_enableDnsOverHttpPort80) - { - foreach (IPAddress localAddress in localAddresses) - serverOptions.Listen(localAddress, 80); - } - //bind to https port if (_enableDnsOverHttps && (_certificate is not null)) { @@ -3771,9 +3796,6 @@ namespace DnsServerCore.Dns if (_enableDnsOverHttp) _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server was bound successfully."); - if (_enableDnsOverHttpPort80) - _log?.Write(new IPEndPoint(localAddress, 80), "Http", "DNS Server was bound successfully."); - if (_enableDnsOverHttps && (_certificate is not null)) _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpsPort), "Https", "DNS Server was bound successfully."); } @@ -3790,9 +3812,6 @@ namespace DnsServerCore.Dns if (_enableDnsOverHttp) _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpPort), "Http", "DNS Server failed to bind."); - if (_enableDnsOverHttpPort80) - _log?.Write(new IPEndPoint(localAddress, 80), "Http", "DNS Server failed to bind."); - if (_enableDnsOverHttps && (_certificate is not null)) _log?.Write(new IPEndPoint(localAddress, _dnsOverHttpsPort), "Https", "DNS Server failed to bind."); } @@ -4085,7 +4104,7 @@ namespace DnsServerCore.Dns } } - if (_enableDnsOverHttp || _enableDnsOverHttpPort80 || (_enableDnsOverHttps && (_certificate is not null))) + if (_enableDnsOverHttp || (_enableDnsOverHttps && (_certificate is not null))) await StartDoHAsync(); _cachePrefetchSamplingTimer = new Timer(CachePrefetchSamplingTimerCallback, null, Timeout.Infinite, Timeout.Infinite); @@ -4480,12 +4499,6 @@ namespace DnsServerCore.Dns set { _enableDnsOverHttps = value; } } - public bool EnableDnsOverHttpPort80 - { - get { return _enableDnsOverHttpPort80; } - set { _enableDnsOverHttpPort80 = value; } - } - public bool EnableDnsOverQuic { get { return _enableDnsOverQuic; } From 05c4d96b657c1d0fb144c3cfc9be561ec75f58d1 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:15:13 +0530 Subject: [PATCH 143/191] DnsWebService: updated config to remove doh-port80 compatibility option. --- DnsServerCore/DnsWebService.cs | 36 ++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index d80fa24b..f6a3ec97 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -948,7 +948,7 @@ namespace DnsServerCore } //add missing admin permissions - List zones = _dnsServer.AuthZoneManager.GetAllZones(); + IReadOnlyList zones = _dnsServer.AuthZoneManager.GetAllZones(); Group admins = _authManager.GetGroup(Group.ADMINISTRATORS); Group dnsAdmins = _authManager.GetGroup(Group.DNS_ADMINISTRATORS); @@ -976,7 +976,7 @@ namespace DnsServerCore int version = bR.ReadByte(); - if ((version >= 28) && (version <= 30)) + if ((version >= 28) && (version <= 31)) { ReadConfigFrom(bR, version); } @@ -1108,9 +1108,18 @@ namespace DnsServerCore _dnsServer.EnableDnsOverTls = bR.ReadBoolean(); _dnsServer.EnableDnsOverHttps = bR.ReadBoolean(); - if (version >= 30) + if (version >= 31) { - _dnsServer.EnableDnsOverHttpPort80 = bR.ReadBoolean(); + _dnsServer.EnableDnsOverQuic = bR.ReadBoolean(); + + _dnsServer.DnsOverHttpPort = bR.ReadInt32(); + _dnsServer.DnsOverTlsPort = bR.ReadInt32(); + _dnsServer.DnsOverHttpsPort = bR.ReadInt32(); + _dnsServer.DnsOverQuicPort = bR.ReadInt32(); + } + else if (version >= 30) + { + _ = bR.ReadBoolean(); //removed EnableDnsOverHttpPort80 value _dnsServer.EnableDnsOverQuic = bR.ReadBoolean(); _dnsServer.DnsOverHttpPort = bR.ReadInt32(); @@ -1120,10 +1129,22 @@ namespace DnsServerCore } else { - _dnsServer.EnableDnsOverHttpPort80 = _dnsServer.EnableDnsOverHttps; _dnsServer.EnableDnsOverQuic = false; - _dnsServer.DnsOverHttpPort = 8053; + if (_dnsServer.EnableDnsOverHttps) + { + _dnsServer.EnableDnsOverHttp = true; + _dnsServer.DnsOverHttpPort = 80; + } + else if (_dnsServer.EnableDnsOverHttp) + { + _dnsServer.DnsOverHttpPort = 8053; + } + else + { + _dnsServer.DnsOverHttpPort = 80; + } + _dnsServer.DnsOverTlsPort = 853; _dnsServer.DnsOverHttpsPort = 443; _dnsServer.DnsOverQuicPort = 853; @@ -1898,7 +1919,7 @@ namespace DnsServerCore private void WriteConfigTo(BinaryWriter bW) { bW.Write(Encoding.ASCII.GetBytes("DS")); //format - bW.Write((byte)30); //version + bW.Write((byte)31); //version //web service { @@ -1967,7 +1988,6 @@ namespace DnsServerCore bW.Write(_dnsServer.EnableDnsOverHttp); bW.Write(_dnsServer.EnableDnsOverTls); bW.Write(_dnsServer.EnableDnsOverHttps); - bW.Write(_dnsServer.EnableDnsOverHttpPort80); bW.Write(_dnsServer.EnableDnsOverQuic); bW.Write(_dnsServer.DnsOverHttpPort); From bd613409cf152f7ce9d744af85d59e99fbdbde7e Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:16:00 +0530 Subject: [PATCH 144/191] WebServiceOtherZonesApi: code refactoring changes done. --- DnsServerCore/WebServiceOtherZonesApi.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/WebServiceOtherZonesApi.cs b/DnsServerCore/WebServiceOtherZonesApi.cs index 40de4077..7ab8b785 100644 --- a/DnsServerCore/WebServiceOtherZonesApi.cs +++ b/DnsServerCore/WebServiceOtherZonesApi.cs @@ -259,7 +259,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.AllowedZoneManager.ListZones(); + IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.AllowedZoneManager.GetAllZones(); HttpResponse response = context.Response; @@ -431,7 +431,7 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.BlockedZoneManager.ListZones(); + IReadOnlyList zoneInfoList = _dnsWebService.DnsServer.BlockedZoneManager.GetAllZones(); HttpResponse response = context.Response; From 3592e75f63b97b465e29708db00a1a924eaac80b Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:18:33 +0530 Subject: [PATCH 145/191] WebServiceSettingsApi: removed doh-port80 from api. --- DnsServerCore/WebServiceSettingsApi.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/DnsServerCore/WebServiceSettingsApi.cs b/DnsServerCore/WebServiceSettingsApi.cs index 6e1ab973..22ff70fb 100644 --- a/DnsServerCore/WebServiceSettingsApi.cs +++ b/DnsServerCore/WebServiceSettingsApi.cs @@ -287,7 +287,6 @@ namespace DnsServerCore jsonWriter.WriteBoolean("enableDnsOverHttp", _dnsWebService.DnsServer.EnableDnsOverHttp); jsonWriter.WriteBoolean("enableDnsOverTls", _dnsWebService.DnsServer.EnableDnsOverTls); jsonWriter.WriteBoolean("enableDnsOverHttps", _dnsWebService.DnsServer.EnableDnsOverHttps); - jsonWriter.WriteBoolean("enableDnsOverHttpPort80", _dnsWebService.DnsServer.EnableDnsOverHttpPort80); jsonWriter.WriteBoolean("enableDnsOverQuic", _dnsWebService.DnsServer.EnableDnsOverQuic); jsonWriter.WriteNumber("dnsOverHttpPort", _dnsWebService.DnsServer.DnsOverHttpPort); jsonWriter.WriteNumber("dnsOverTlsPort", _dnsWebService.DnsServer.DnsOverTlsPort); @@ -744,15 +743,6 @@ namespace DnsServerCore } } - if (request.TryGetQueryOrForm("enableDnsOverHttpPort80", bool.Parse, out bool enableDnsOverHttpPort80)) - { - if (_dnsWebService.DnsServer.EnableDnsOverHttpPort80 != enableDnsOverHttpPort80) - { - _dnsWebService.DnsServer.EnableDnsOverHttpPort80 = enableDnsOverHttpPort80; - restartDnsService = true; - } - } - if (request.TryGetQueryOrForm("enableDnsOverQuic", bool.Parse, out bool enableDnsOverQuic)) { if (_dnsWebService.DnsServer.EnableDnsOverQuic != enableDnsOverQuic) From 0a7ee462f511ca5c3545638dfb3686b04cda0dbd Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:19:41 +0530 Subject: [PATCH 146/191] WebServiceZonesApi: updated ListZones() to support pagination options. Other minor changes done. --- DnsServerCore/WebServiceZonesApi.cs | 46 +++++++++++++++++++---------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/DnsServerCore/WebServiceZonesApi.cs b/DnsServerCore/WebServiceZonesApi.cs index e31ec481..1f717c88 100644 --- a/DnsServerCore/WebServiceZonesApi.cs +++ b/DnsServerCore/WebServiceZonesApi.cs @@ -21,6 +21,7 @@ using DnsServerCore.Auth; using DnsServerCore.Dns; using DnsServerCore.Dns.Dnssec; using DnsServerCore.Dns.ResourceRecords; +using DnsServerCore.Dns.ZoneManagers; using DnsServerCore.Dns.Zones; using Microsoft.AspNetCore.Http; using System; @@ -717,10 +718,25 @@ namespace DnsServerCore if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); - List zones = _dnsWebService.DnsServer.AuthZoneManager.GetAllZones(); - zones.Sort(); - + HttpRequest request = context.Request; Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); + IReadOnlyList zones; + + if (request.TryGetQueryOrForm("pageNumber", int.Parse, out int pageNumber)) + { + int zonesPerPage = request.GetQueryOrForm("zonesPerPage", int.Parse, 10); + + AuthZoneManager.ZonesPage page = _dnsWebService.DnsServer.AuthZoneManager.GetZonesPage(pageNumber, zonesPerPage); + zones = page.Zones; + + jsonWriter.WriteNumber("pageNumber", page.PageNumber); + jsonWriter.WriteNumber("totalPages", page.TotalPages); + jsonWriter.WriteNumber("totalZones", page.TotalZones); + } + else + { + zones = _dnsWebService.DnsServer.AuthZoneManager.GetAllZones(); + } jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); @@ -995,7 +1011,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No such zone was found: " + zoneName); + throw new DnsWebServiceException("No such authoritative zone was found: " + zoneName); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -1335,7 +1351,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No such zone was found: " + zoneName); + throw new DnsWebServiceException("No such authoritative zone was found: " + zoneName); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -1344,7 +1360,7 @@ namespace DnsServerCore throw new DnsWebServiceException("Access was denied."); if (!_dnsWebService.DnsServer.AuthZoneManager.DeleteZone(zoneInfo.Name)) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneInfo.Name); + throw new DnsWebServiceException("Failed to delete the zone: " + zoneInfo.Name); _dnsWebService._authManager.RemoveAllPermissions(PermissionSection.Zones, zoneInfo.Name); _dnsWebService._authManager.SaveConfigFile(); @@ -1364,7 +1380,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); + throw new DnsWebServiceException("No such authoritative zone was found: " + zoneName); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -1393,7 +1409,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); + throw new DnsWebServiceException("No such authoritative zone was found: " + zoneName); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -1422,7 +1438,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No such zone was found: " + zoneName); + throw new DnsWebServiceException("No such authoritative zone was found: " + zoneName); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -1580,7 +1596,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); + throw new DnsWebServiceException("No such authoritative zone was found: " + zoneName); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -1714,7 +1730,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + zoneName); + throw new DnsWebServiceException("No such authoritative zone was found: " + zoneName); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -1746,7 +1762,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); + throw new DnsWebServiceException("No such authoritative zone was found: " + domain); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -2131,7 +2147,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); + throw new DnsWebServiceException("No such authoritative zone was found: " + domain); UserSession session = context.GetCurrentSession(); @@ -2167,7 +2183,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); + throw new DnsWebServiceException("No such authoritative zone was found: " + domain); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); @@ -2348,7 +2364,7 @@ namespace DnsServerCore AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName); if (zoneInfo is null) - throw new DnsWebServiceException("No authoritative zone was not found for domain: " + domain); + throw new DnsWebServiceException("No such authoritative zone was found: " + domain); if (zoneInfo.Internal) throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone."); From a3b83a43b5bd295d3c3e596209adc42b5a42fa95 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:20:24 +0530 Subject: [PATCH 147/191] IDnsQueryLogger: added UpstreamBlocked and CacheBlocked as new response types. --- DnsServerCore.ApplicationCommon/IDnsQueryLogger.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/DnsServerCore.ApplicationCommon/IDnsQueryLogger.cs b/DnsServerCore.ApplicationCommon/IDnsQueryLogger.cs index 40ba6a59..dfc5145d 100644 --- a/DnsServerCore.ApplicationCommon/IDnsQueryLogger.cs +++ b/DnsServerCore.ApplicationCommon/IDnsQueryLogger.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2021 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 @@ -31,7 +31,9 @@ namespace DnsServerCore.ApplicationCommon Authoritative = 1, Recursive = 2, Cached = 3, - Blocked = 4 + Blocked = 4, + UpstreamBlocked = 5, + CacheBlocked = 6 } /// From d7b03d9c0ce4ad727806e476e93f1181f3a07fb6 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:27:32 +0530 Subject: [PATCH 148/191] webapp: updated html to implement zone pagination view. Removed doh-port80 html. --- DnsServerCore/www/index.html | 91 +++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/DnsServerCore/www/index.html b/DnsServerCore/www/index.html index b2b2d2f8..0e3bf589 100644 --- a/DnsServerCore/www/index.html +++ b/DnsServerCore/www/index.html @@ -331,19 +331,64 @@
    -
    +
    -
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    + + +
    + +
    +
    +
    + +
    +
    + 0 zones +
    +
    + +
    +
    +
    + + @@ -352,17 +397,34 @@ - - - - + + + + +
    # Zone Type DNSSEC
    Total Records: 0
    +
    +
    + 0 zones +
    +
    + +
    +
    +
    +
    -
    Specifies if the DNS Server should respond with TXT records containing a blocked domain report for TXT type requests.
    +
    Specifies if the DNS Server should respond with TXT records containing a blocked domain report for TXT type requests. This option also enables Extended DNS Error blocked domain report in response for requests that support EDNS.
    @@ -2503,6 +2558,8 @@ + +
    From e7919c7f77fa445745a74a941ec716e0e00023de Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:34:08 +0530 Subject: [PATCH 149/191] logs.js: storing current drop down value in local storage. --- DnsServerCore/www/js/logs.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DnsServerCore/www/js/logs.js b/DnsServerCore/www/js/logs.js index de6b365e..7f2bc23a 100644 --- a/DnsServerCore/www/js/logs.js +++ b/DnsServerCore/www/js/logs.js @@ -39,6 +39,14 @@ $(function () { $("#optQueryLogsClassPath").html(optClassPaths); $("#txtAddEditRecordDataData").val(""); }); + + $("#optQueryLogsEntriesPerPage").change(function () { + localStorage.setItem("optQueryLogsEntriesPerPage", $("#optQueryLogsEntriesPerPage").val()); + }); + + var optQueryLogsEntriesPerPage = localStorage.getItem("optQueryLogsEntriesPerPage"); + if (optQueryLogsEntriesPerPage != null) + $("#optQueryLogsEntriesPerPage").val(optQueryLogsEntriesPerPage); }); function refreshLogsTab() { From 71f9cfefeb1fcfb63c2750fa633bae1ae2504a96 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:34:59 +0530 Subject: [PATCH 150/191] main.js: removed doh-port80 support and other minor changes. --- DnsServerCore/www/js/main.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/DnsServerCore/www/js/main.js b/DnsServerCore/www/js/main.js index 53f601b9..4031a707 100644 --- a/DnsServerCore/www/js/main.js +++ b/DnsServerCore/www/js/main.js @@ -325,7 +325,6 @@ $(function () { var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop("checked"); var enableDnsOverQuic = $("#chkEnableDnsOverQuic").prop("checked"); - $("#chkEnableDnsOverHttpPort80").prop("checked", enableDnsOverHttps); $("#txtDnsOverHttpsPort").prop("disabled", !enableDnsOverHttps); $("#txtDnsTlsCertificatePath").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); $("#txtDnsTlsCertificatePassword").prop("disabled", !enableDnsOverTls && !enableDnsOverHttps && !enableDnsOverQuic); @@ -923,7 +922,6 @@ function loadDnsSettings() { $("#chkEnableDnsOverHttp").prop("checked", responseJSON.response.enableDnsOverHttp); $("#chkEnableDnsOverTls").prop("checked", responseJSON.response.enableDnsOverTls); $("#chkEnableDnsOverHttps").prop("checked", responseJSON.response.enableDnsOverHttps); - $("#chkEnableDnsOverHttpPort80").prop("checked", responseJSON.response.enableDnsOverHttpPort80); $("#chkEnableDnsOverQuic").prop("checked", responseJSON.response.enableDnsOverQuic); $("#txtDnsOverHttpPort").prop("disabled", !responseJSON.response.enableDnsOverHttp); @@ -1361,7 +1359,6 @@ function saveDnsSettings() { var enableDnsOverHttp = $("#chkEnableDnsOverHttp").prop("checked"); var enableDnsOverTls = $("#chkEnableDnsOverTls").prop("checked"); var enableDnsOverHttps = $("#chkEnableDnsOverHttps").prop("checked"); - var enableDnsOverHttpPort80 = $("#chkEnableDnsOverHttpPort80").prop("checked"); var enableDnsOverQuic = $("#chkEnableDnsOverQuic").prop("checked"); var dnsOverHttpPort = $("#txtDnsOverHttpPort").val(); @@ -1618,7 +1615,7 @@ function saveDnsSettings() { + "&qpmLimitRequests=" + qpmLimitRequests + "&qpmLimitErrors=" + qpmLimitErrors + "&qpmLimitSampleMinutes=" + qpmLimitSampleMinutes + "&qpmLimitIPv4PrefixLength=" + qpmLimitIPv4PrefixLength + "&qpmLimitIPv6PrefixLength=" + qpmLimitIPv6PrefixLength + "&clientTimeout=" + clientTimeout + "&tcpSendTimeout=" + tcpSendTimeout + "&tcpReceiveTimeout=" + tcpReceiveTimeout + "&quicIdleTimeout=" + quicIdleTimeout + "&quicMaxInboundStreams=" + quicMaxInboundStreams + "&listenBacklog=" + listenBacklog + "&webServiceLocalAddresses=" + encodeURIComponent(webServiceLocalAddresses) + "&webServiceHttpPort=" + webServiceHttpPort + "&webServiceEnableTls=" + webServiceEnableTls + "&webServiceHttpToTlsRedirect=" + webServiceHttpToTlsRedirect + "&webServiceUseSelfSignedTlsCertificate=" + webServiceUseSelfSignedTlsCertificate + "&webServiceTlsPort=" + webServiceTlsPort + "&webServiceTlsCertificatePath=" + encodeURIComponent(webServiceTlsCertificatePath) + "&webServiceTlsCertificatePassword=" + encodeURIComponent(webServiceTlsCertificatePassword) - + "&enableDnsOverHttp=" + enableDnsOverHttp + "&enableDnsOverTls=" + enableDnsOverTls + "&enableDnsOverHttps=" + enableDnsOverHttps + "&enableDnsOverHttpPort80=" + enableDnsOverHttpPort80 + "&enableDnsOverQuic=" + enableDnsOverQuic + "&dnsOverHttpPort=" + dnsOverHttpPort + "&dnsOverTlsPort=" + dnsOverTlsPort + "&dnsOverHttpsPort=" + dnsOverHttpsPort + "&dnsOverQuicPort=" + dnsOverQuicPort + "&dnsTlsCertificatePath=" + encodeURIComponent(dnsTlsCertificatePath) + "&dnsTlsCertificatePassword=" + encodeURIComponent(dnsTlsCertificatePassword) + + "&enableDnsOverHttp=" + enableDnsOverHttp + "&enableDnsOverTls=" + enableDnsOverTls + "&enableDnsOverHttps=" + enableDnsOverHttps + "&enableDnsOverQuic=" + enableDnsOverQuic + "&dnsOverHttpPort=" + dnsOverHttpPort + "&dnsOverTlsPort=" + dnsOverTlsPort + "&dnsOverHttpsPort=" + dnsOverHttpsPort + "&dnsOverQuicPort=" + dnsOverQuicPort + "&dnsTlsCertificatePath=" + encodeURIComponent(dnsTlsCertificatePath) + "&dnsTlsCertificatePassword=" + encodeURIComponent(dnsTlsCertificatePassword) + "&tsigKeys=" + encodeURIComponent(tsigKeys) + "&recursion=" + recursion + "&recursionDeniedNetworks=" + encodeURIComponent(recursionDeniedNetworks) + "&recursionAllowedNetworks=" + encodeURIComponent(recursionAllowedNetworks) + "&randomizeName=" + randomizeName + "&qnameMinimization=" + qnameMinimization + "&nsRevalidation=" + nsRevalidation + "&resolverRetries=" + resolverRetries + "&resolverTimeout=" + resolverTimeout + "&resolverMaxStackCount=" + resolverMaxStackCount + "&saveCache=" + saveCache + "&serveStale=" + serveStale + "&serveStaleTtl=" + serveStaleTtl + "&cacheMaximumEntries=" + cacheMaximumEntries + "&cacheMinimumRecordTtl=" + cacheMinimumRecordTtl + "&cacheMaximumRecordTtl=" + cacheMaximumRecordTtl + "&cacheNegativeRecordTtl=" + cacheNegativeRecordTtl + "&cacheFailureRecordTtl=" + cacheFailureRecordTtl + "&cachePrefetchEligibility=" + cachePrefetchEligibility + "&cachePrefetchTrigger=" + cachePrefetchTrigger + "&cachePrefetchSampleIntervalInMinutes=" + cachePrefetchSampleIntervalInMinutes + "&cachePrefetchSampleEligibilityHitsPerHour=" + cachePrefetchSampleEligibilityHitsPerHour @@ -2439,6 +2436,7 @@ function resetBackupSettingsModal() { $("#chkBackupAllowedZones").prop("checked", true); $("#chkBackupBlockedZones").prop("checked", true); $("#chkBackupScopes").prop("checked", true); + $("#chkBackupApps").prop("checked", true); $("#chkBackupStats").prop("checked", true); $("#chkBackupLogs").prop("checked", false); $("#chkBackupBlockLists").prop("checked", true); @@ -2482,6 +2480,7 @@ function resetRestoreSettingsModal() { $("#chkRestoreAllowedZones").prop("checked", true); $("#chkRestoreBlockedZones").prop("checked", true); $("#chkRestoreScopes").prop("checked", true); + $("#chkRestoreApps").prop("checked", true); $("#chkRestoreStats").prop("checked", true); $("#chkRestoreLogs").prop("checked", false); $("#chkRestoreBlockLists").prop("checked", true); From 409347ba4af73eff93055176f5b7ddfd16ac2142 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sun, 12 Feb 2023 13:36:11 +0530 Subject: [PATCH 151/191] zone.js: implementes zones section pagination support. --- DnsServerCore/www/js/zone.js | 104 +++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 17 deletions(-) diff --git a/DnsServerCore/www/js/zone.js b/DnsServerCore/www/js/zone.js index c74d5f26..d5136471 100644 --- a/DnsServerCore/www/js/zone.js +++ b/DnsServerCore/www/js/zone.js @@ -269,16 +269,37 @@ $(function () { break; } }); + + $("#optZonesPerPage").change(function () { + localStorage.setItem("optZonesPerPage", $("#optZonesPerPage").val()); + }); + + var optZonesPerPage = localStorage.getItem("optZonesPerPage"); + if (optZonesPerPage != null) + $("#optZonesPerPage").val(optZonesPerPage); }); -function refreshZones(checkDisplay) { +function refreshZones(checkDisplay, pageNumber) { if (checkDisplay == null) checkDisplay = false; var divViewZones = $("#divViewZones"); - if (checkDisplay && (divViewZones.css('display') === "none")) - return; + if (checkDisplay) { + if (divViewZones.css("display") === "none") + return; + + if (($("#tableZonesBody").html().length > 0) && !$("#mainPanelTabPaneZones").hasClass("active")) + return; + } + + if (pageNumber == null) { + pageNumber = $("#txtZonesPageNumber").val(); + if (pageNumber == "") + pageNumber = 1; + } + + var zonesPerPage = $("#optZonesPerPage").val(); var divViewZonesLoader = $("#divViewZonesLoader"); var divEditZone = $("#divEditZone"); @@ -288,9 +309,11 @@ function refreshZones(checkDisplay) { divViewZonesLoader.show(); HTTPRequest({ - url: "/api/zones/list?token=" + sessionData.token, + url: "/api/zones/list?token=" + sessionData.token + "&pageNumber=" + pageNumber + "&zonesPerPage=" + zonesPerPage, success: function (responseJSON) { var zones = responseJSON.response.zones; + var firstRowNumber = ((responseJSON.response.pageNumber - 1) * zonesPerPage) + 1; + var lastRowNumber = firstRowNumber + (zones.length - 1); var tableHtmlRows = ""; for (var i = 0; i < zones.length; i++) { @@ -349,7 +372,8 @@ function refreshZones(checkDisplay) { break; } - tableHtmlRows += "
    " + htmlEncode(name === "." ? "" : name) + "
    " + (firstRowNumber + i) + "" + htmlEncode(name === "." ? "" : name) + "" + type + "" + dnssecStatus + "" + status + "
    Total Zones: " + zones.length + "
    No Zones Found
    Total Zones: " + totalZones + "
    No Zones Found
    + @@ -471,8 +510,26 @@ - - + + + +
    # Name Type TTL
    Total Records: 0
    +
    +
    + 0 records +
    +
    + +
    +
    +
    +
    @@ -1106,6 +1163,7 @@

    Note! The web service port changes will be automatically applied and so you do not need to manually restart the main service. This web page will be automatically redirected to the new web console URL after saving settings. The HTTPS protocol will be enabled only when a TLS certificate is configured.

    When using a reverse proxy with the Web Service, you need to add X-Real-IP header to the proxy request with the IP address of the client to allow the Web 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.

    +

    The web service uses Kestral web server which supports both HTTP/2 and HTTP/3 protocols when TLS certificate is configured. HTTP/3 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:

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

    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.

    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:

    openssl pkcs12 -export -out "example.com.pfx" -inkey "privkey.pem" -in "cert.pem" -certfile "chain.pem"
    @@ -1291,7 +1350,7 @@ Randomize Name -
    Enables QNAME randomization when using UDP as the transport protocol to improve security.
    +
    Enables QNAME case randomization when using UDP as the transport protocol to improve security.
    @@ -1596,7 +1652,7 @@
    Click the 'Update Now' button to reset the next update schedule and force download and update of the block lists.
    -
    DNS Server will use the data returned by the block list URLs to update the block list zone automatically. The expected file format is standard hosts file format, plain text file containing list of domains to block, or wildcard block list file format.
    +
    Note! DNS Server will use the data returned by the block list URLs to update the block list zone automatically. The expected file format is standard hosts file format, plain text file containing list of domains to block, wildcard block list file format, or Adblock Plus file format.
    @@ -2642,13 +2698,14 @@
    Type Class Answer
    +
    Found: 0 logs From 0034e3e0b0ac8d5586fae1f18eb97e30a86ebb65 Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 18 Feb 2023 11:46:51 +0530 Subject: [PATCH 177/191] log.js: fixed minor issue in queryLogs() and added context menu for query logs entries. --- DnsServerCore/www/js/logs.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/DnsServerCore/www/js/logs.js b/DnsServerCore/www/js/logs.js index 7f2bc23a..e170de89 100644 --- a/DnsServerCore/www/js/logs.js +++ b/DnsServerCore/www/js/logs.js @@ -292,7 +292,10 @@ function queryLogs(pageNumber) { if (pageNumber == null) pageNumber = $("#txtQueryLogPageNumber").val(); - var entriesPerPage = $("#optQueryLogsEntriesPerPage").val(); + var entriesPerPage = Number($("#optQueryLogsEntriesPerPage").val()); + if (entriesPerPage < 1) + entriesPerPage = 10; + var descendingOrder = $("#optQueryLogsDescendingOrder").val(); var start = $("#txtQueryLogStart").val(); @@ -333,7 +336,22 @@ function queryLogs(pageNumber) { htmlEncode(responseJSON.response.entries[i].qname == "" ? "." : responseJSON.response.entries[i].qname) + "
    " + (responseJSON.response.entries[i].qtype == null ? "" : responseJSON.response.entries[i].qtype) + "" + (responseJSON.response.entries[i].qclass == null ? "" : responseJSON.response.entries[i].qclass) + "" + - htmlEncode(responseJSON.response.entries[i].answer) + "
      "; + + switch (responseJSON.response.entries[i].responseType.toLowerCase()) { + case "blocked": + case "upstreamblocked": + case "cacheblocked": + tableHtml += "
    • Allow Domain
    • "; + break; + + default: + tableHtml += "
    • Block Domain
    • "; + break; + } + + tableHtml += "
    Total Records: " + recordCount + "
    No Records Found
    " + htmlEncode(name) + "
    " + (index + 1) + "" + htmlEncode(name) + "" + record.type + "" + record.ttl + ""; - tableHtmlRow += "
    "; - tableHtmlRow += ""; - tableHtmlRow += ""; - tableHtmlRow += ""; - tableHtmlRow += "
    Total Records: " + recordCount + "
    No Records Found
    Total Records: " + recordCount + "
    No Records Found