From 4c6652decd00d5db956102b6ab4699b85f10b7aa Mon Sep 17 00:00:00 2001 From: Shreyas Zare Date: Sat, 29 Jun 2019 12:15:46 +0530 Subject: [PATCH] WebService: updated GetStats() api with new stats and new chart. Updated zone api to support CAA record. Refactored UpdateRecord() api call for simple usage. Fixed minor TTL related issue with dns client import record feature. Updated zone file loading from 'zones' directory. --- DnsServerCore/WebService.cs | 230 +++++++++++++++++++++++++++++++----- 1 file changed, 199 insertions(+), 31 deletions(-) diff --git a/DnsServerCore/WebService.cs b/DnsServerCore/WebService.cs index 6e4d9018..f69a5d0a 100644 --- a/DnsServerCore/WebService.cs +++ b/DnsServerCore/WebService.cs @@ -1484,13 +1484,17 @@ namespace DnsServerCore jsonWriter.WritePropertyName("datasets"); jsonWriter.WriteStartArray(); - WriteChartDataSet(jsonWriter, "Total Queries", "rgba(102, 153, 255, 0.1)", "rgb(102, 153, 255)", data["totalQueriesPerInterval"]); - WriteChartDataSet(jsonWriter, "Cache Hit", "rgba(111, 84, 153, 0.1)", "rgb(111, 84, 153)", data["totalCacheHitPerInterval"]); + WriteChartDataSet(jsonWriter, "Total", "rgba(102, 153, 255, 0.1)", "rgb(102, 153, 255)", data["totalQueriesPerInterval"]); WriteChartDataSet(jsonWriter, "No Error", "rgba(92, 184, 92, 0.1)", "rgb(92, 184, 92)", data["totalNoErrorPerInterval"]); WriteChartDataSet(jsonWriter, "Server Failure", "rgba(217, 83, 79, 0.1)", "rgb(217, 83, 79)", data["totalServerFailurePerInterval"]); WriteChartDataSet(jsonWriter, "Name Error", "rgba(7, 7, 7, 0.1)", "rgb(7, 7, 7)", data["totalNameErrorPerInterval"]); WriteChartDataSet(jsonWriter, "Refused", "rgba(91, 192, 222, 0.1)", "rgb(91, 192, 222)", data["totalRefusedPerInterval"]); + + WriteChartDataSet(jsonWriter, "Authoritative", "rgba(150, 150, 0, 0.1)", "rgb(150, 150, 0)", data["totalAuthHitPerInterval"]); + WriteChartDataSet(jsonWriter, "Recursive", "rgba(23, 162, 184, 0.1)", "rgb(23, 162, 184)", data["totalRecursionsPerInterval"]); + WriteChartDataSet(jsonWriter, "Cached", "rgba(111, 84, 153, 0.1)", "rgb(111, 84, 153)", data["totalCacheHitPerInterval"]); WriteChartDataSet(jsonWriter, "Blocked", "rgba(255, 165, 0, 0.1)", "rgb(255, 165, 0)", data["totalBlockedPerInterval"]); + WriteChartDataSet(jsonWriter, "Clients", "rgba(51, 122, 183, 0.1)", "rgb(51, 122, 183)", data["totalClientsPerInterval"]); jsonWriter.WriteEndArray(); @@ -1499,6 +1503,84 @@ namespace DnsServerCore jsonWriter.WriteEndObject(); } + //query response chart + { + jsonWriter.WritePropertyName("queryResponseChartData"); + jsonWriter.WriteStartObject(); + + List> stats = data["stats"]; + + //labels + { + jsonWriter.WritePropertyName("labels"); + jsonWriter.WriteStartArray(); + + foreach (KeyValuePair item in stats) + { + switch (item.Key) + { + case "totalAuthHit": + jsonWriter.WriteValue("Authoritative"); + break; + + case "totalRecursions": + jsonWriter.WriteValue("Recursive"); + break; + + case "totalCacheHit": + jsonWriter.WriteValue("Cached"); + break; + + case "totalBlocked": + jsonWriter.WriteValue("Blocked"); + break; + } + } + + jsonWriter.WriteEndArray(); + } + + //datasets + { + jsonWriter.WritePropertyName("datasets"); + jsonWriter.WriteStartArray(); + + jsonWriter.WriteStartObject(); + + jsonWriter.WritePropertyName("data"); + jsonWriter.WriteStartArray(); + + foreach (KeyValuePair item in stats) + { + switch (item.Key) + { + case "totalAuthHit": + case "totalRecursions": + case "totalCacheHit": + case "totalBlocked": + jsonWriter.WriteValue(item.Value); + break; + } + } + + jsonWriter.WriteEndArray(); + + 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.WriteEndArray(); + + jsonWriter.WriteEndObject(); + + jsonWriter.WriteEndArray(); + } + + jsonWriter.WriteEndObject(); + } + //query type chart { jsonWriter.WritePropertyName("queryTypeChartData"); @@ -2296,6 +2378,20 @@ namespace DnsServerCore } break; + case DnsResourceRecordType.CAA: + { + string flags = request.QueryString["flags"]; + if (string.IsNullOrEmpty(flags)) + throw new WebServiceException("Parameter 'flags' missing."); + + string tag = request.QueryString["tag"]; + if (string.IsNullOrEmpty(tag)) + throw new WebServiceException("Parameter 'tag' missing."); + + _dnsServer.AuthoritativeZoneRoot.AddRecord(domain, type, ttl, new DnsCAARecord(byte.Parse(flags), tag, value)); + } + break; + default: throw new WebServiceException("Type not supported for AddRecords()."); } @@ -2500,6 +2596,23 @@ namespace DnsServerCore } break; + case DnsResourceRecordType.CAA: + { + DnsCAARecord rdata = resourceRecord.RDATA as DnsCAARecord; + if (rdata != null) + { + jsonWriter.WritePropertyName("flags"); + jsonWriter.WriteValue(rdata.Flags); + + jsonWriter.WritePropertyName("tag"); + jsonWriter.WriteValue(rdata.Tag); + + jsonWriter.WritePropertyName("value"); + jsonWriter.WriteValue(rdata.Value); + } + } + break; + default: { jsonWriter.WritePropertyName("value"); @@ -2587,6 +2700,20 @@ namespace DnsServerCore } break; + case DnsResourceRecordType.CAA: + { + string flags = request.QueryString["flags"]; + if (string.IsNullOrEmpty(flags)) + throw new WebServiceException("Parameter 'flags' missing."); + + string tag = request.QueryString["tag"]; + if (string.IsNullOrEmpty(tag)) + throw new WebServiceException("Parameter 'tag' missing."); + + _dnsServer.AuthoritativeZoneRoot.DeleteRecord(domain, type, new DnsCAARecord(byte.Parse(flags), tag, value)); + } + break; + default: throw new WebServiceException("Type not supported for DeleteRecord()."); } @@ -2615,15 +2742,12 @@ namespace DnsServerCore if (zoneInfo.Internal) throw new WebServiceException("Access was denied to manage internal DNS Server zone."); - string oldDomain = request.QueryString["oldDomain"]; - if (string.IsNullOrEmpty(oldDomain)) - oldDomain = domain; + string newDomain = request.QueryString["newDomain"]; + if (string.IsNullOrEmpty(newDomain)) + newDomain = domain; - if (oldDomain.EndsWith(".")) - oldDomain = oldDomain.Substring(0, oldDomain.Length - 1); - - string value = request.QueryString["value"]; - string oldValue = request.QueryString["oldValue"]; + if (newDomain.EndsWith(".")) + newDomain = newDomain.Substring(0, newDomain.Length - 1); uint ttl; string strTtl = request.QueryString["ttl"]; @@ -2632,6 +2756,12 @@ namespace DnsServerCore else ttl = uint.Parse(strTtl); + string value = request.QueryString["value"]; + + string newValue = request.QueryString["newValue"]; + if (string.IsNullOrEmpty(newValue)) + newValue = value; + bool disable = false; string strDisable = request.QueryString["disable"]; if (!string.IsNullOrEmpty(strDisable)) @@ -2640,27 +2770,27 @@ namespace DnsServerCore switch (type) { case DnsResourceRecordType.A: - _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsARecord(IPAddress.Parse(oldValue))), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsARecord(IPAddress.Parse(value))) { Tag = new DnsResourceRecordInfo(disable) }); + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsARecord(IPAddress.Parse(value))), new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsARecord(IPAddress.Parse(newValue))) { Tag = new DnsResourceRecordInfo(disable) }); break; case DnsResourceRecordType.AAAA: - _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsAAAARecord(IPAddress.Parse(oldValue))), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsAAAARecord(IPAddress.Parse(value))) { Tag = new DnsResourceRecordInfo(disable) }); + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsAAAARecord(IPAddress.Parse(value))), new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsAAAARecord(IPAddress.Parse(newValue))) { Tag = new DnsResourceRecordInfo(disable) }); break; case DnsResourceRecordType.MX: string preference = request.QueryString["preference"]; if (string.IsNullOrEmpty(preference)) - throw new WebServiceException("Parameter 'preference' missing."); + preference = "1"; - _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsMXRecord(0, oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsMXRecord(ushort.Parse(preference), value)) { Tag = new DnsResourceRecordInfo(disable) }); + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsMXRecord(0, value)), new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsMXRecord(ushort.Parse(preference), newValue)) { Tag = new DnsResourceRecordInfo(disable) }); break; case DnsResourceRecordType.TXT: - _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsTXTRecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTXTRecord(value)) { Tag = new DnsResourceRecordInfo(disable) }); + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTXTRecord(value)), new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTXTRecord(newValue)) { Tag = new DnsResourceRecordInfo(disable) }); break; case DnsResourceRecordType.NS: - _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsNSRecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNSRecord(value)) { Tag = new DnsResourceRecordInfo(disable) }); + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsNSRecord(value)), new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsNSRecord(newValue)) { Tag = new DnsResourceRecordInfo(disable) }); break; case DnsResourceRecordType.SOA: @@ -2698,18 +2828,18 @@ namespace DnsServerCore break; case DnsResourceRecordType.PTR: - _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsPTRRecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsPTRRecord(value)) { Tag = new DnsResourceRecordInfo(disable) }); + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsPTRRecord(value)), new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsPTRRecord(newValue)) { Tag = new DnsResourceRecordInfo(disable) }); break; case DnsResourceRecordType.CNAME: - _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsCNAMERecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCNAMERecord(value)) { Tag = new DnsResourceRecordInfo(disable) }); + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCNAMERecord(value)), new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCNAMERecord(newValue)) { Tag = new DnsResourceRecordInfo(disable) }); break; case DnsResourceRecordType.SRV: { - string oldPort = request.QueryString["oldPort"]; - if (string.IsNullOrEmpty(oldPort)) - throw new WebServiceException("Parameter 'oldPort' missing."); + string port = request.QueryString["port"]; + if (string.IsNullOrEmpty(port)) + throw new WebServiceException("Parameter 'port' missing."); string priority = request.QueryString["priority"]; if (string.IsNullOrEmpty(priority)) @@ -2719,12 +2849,37 @@ namespace DnsServerCore if (string.IsNullOrEmpty(weight)) throw new WebServiceException("Parameter 'weight' missing."); - string port = request.QueryString["port"]; - if (string.IsNullOrEmpty(port)) - throw new WebServiceException("Parameter 'port' missing."); + string newPort = request.QueryString["newPort"]; + if (string.IsNullOrEmpty(newPort)) + newPort = port; - DnsResourceRecord oldRecord = new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsSRVRecord(0, 0, ushort.Parse(oldPort), oldValue)); - DnsResourceRecord newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSRVRecord(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), value)) { Tag = new DnsResourceRecordInfo(disable) }; + DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSRVRecord(0, 0, ushort.Parse(port), value)); + DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSRVRecord(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(newPort), newValue)) { Tag = new DnsResourceRecordInfo(disable) }; + + _dnsServer.AuthoritativeZoneRoot.UpdateRecord(oldRecord, newRecord); + } + break; + + case DnsResourceRecordType.CAA: + { + string flags = request.QueryString["flags"]; + if (string.IsNullOrEmpty(flags)) + throw new WebServiceException("Parameter 'flags' missing."); + + string tag = request.QueryString["tag"]; + if (string.IsNullOrEmpty(tag)) + throw new WebServiceException("Parameter 'tag' missing."); + + string newFlags = request.QueryString["newFlags"]; + if (string.IsNullOrEmpty(newFlags)) + newFlags = flags; + + string newTag = request.QueryString["newTag"]; + if (string.IsNullOrEmpty(newTag)) + newTag = tag; + + DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCAARecord(byte.Parse(flags), tag, value)); + DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCAARecord(byte.Parse(newFlags), newTag, newValue)) { Tag = new DnsResourceRecordInfo(disable) }; _dnsServer.AuthoritativeZoneRoot.UpdateRecord(oldRecord, newRecord); } @@ -2734,9 +2889,9 @@ namespace DnsServerCore throw new WebServiceException("Type not supported for UpdateRecords()."); } - _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Record was updated for authoritative zone {oldDomain: " + oldDomain + "; domain: " + domain + "; type: " + type + "; oldValue: " + oldValue + "; value: " + value + "; ttl: " + ttl + "; disabled: " + disable + ";}"); + _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Record was updated for authoritative zone {oldDomain: " + domain + "; domain: " + newDomain + "; type: " + type + "; oldValue: " + value + "; value: " + newValue + "; ttl: " + ttl + "; disabled: " + disable + ";}"); - SaveZoneFile(domain); + SaveZoneFile(newDomain); } private void ResolveQuery(HttpListenerRequest request, JsonTextWriter jsonWriter) @@ -2835,6 +2990,7 @@ namespace DnsServerCore { if (record.Name.Equals(domain, StringComparison.OrdinalIgnoreCase)) { + record.RemoveExpiry(); recordsToSet.Add(record); if (record.Type == DnsResourceRecordType.SOA) @@ -3462,7 +3618,19 @@ namespace DnsServerCore private void LoadZoneFiles() { - string[] zoneFiles = Directory.GetFiles(_configFolder, "*.zone"); + string zonePath = Path.Combine(_configFolder, "zones"); + if (!Directory.Exists(zonePath)) + Directory.CreateDirectory(zonePath); + + //move zone files to new folder + { + string[] oldZoneFiles = Directory.GetFiles(_configFolder, "*.zone"); + + foreach (string oldZoneFile in oldZoneFiles) + File.Move(oldZoneFile, Path.Combine(zonePath, Path.GetFileName(oldZoneFile))); + } + + string[] zoneFiles = Directory.GetFiles(zonePath, "*.zone"); if (zoneFiles.Length == 0) { @@ -3627,7 +3795,7 @@ namespace DnsServerCore //write to zone file mS.Position = 0; - using (FileStream fS = new FileStream(Path.Combine(_configFolder, authZone + ".zone"), FileMode.Create, FileAccess.Write)) + using (FileStream fS = new FileStream(Path.Combine(Path.Combine(_configFolder, "zones"), authZone + ".zone"), FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); } @@ -3640,7 +3808,7 @@ namespace DnsServerCore { domain = domain.ToLower(); - File.Delete(Path.Combine(_configFolder, domain + ".zone")); + File.Delete(Path.Combine(Path.Combine(_configFolder, "zones"), domain + ".zone")); _log.Write("Deleted zone file for domain: " + domain); }