Files
DnsServer-TechnitiumSoftware/DnsServerCore/WebServiceDashboardApi.cs
2025-11-22 11:46:06 +05:30

863 lines
36 KiB
C#

/*
Technitium DNS Server
Copyright (C) 2025 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 <http://www.gnu.org/licenses/>.
*/
using DnsServerCore.Auth;
using DnsServerCore.HttpApi.Models;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using TechnitiumLibrary.Net.Dns;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
namespace DnsServerCore
{
public partial class DnsWebService
{
class WebServiceDashboardApi
{
#region variables
readonly DnsWebService _dnsWebService;
const int CLUSTER_NODE_DASHBOARD_STATS_API_TIMEOUT = 10000;
#endregion
#region constructor
public WebServiceDashboardApi(DnsWebService dnsWebService)
{
_dnsWebService = dnsWebService;
}
#endregion
#region private
private static void WriteChartDataSet(Utf8JsonWriter jsonWriter, DashboardStats.DataSet dataSet, string backgroundColor, string borderColor)
{
jsonWriter.WriteStartObject();
jsonWriter.WriteString("label", dataSet.Label);
jsonWriter.WriteString("backgroundColor", backgroundColor);
jsonWriter.WriteString("borderColor", borderColor);
jsonWriter.WriteNumber("borderWidth", 2);
jsonWriter.WriteBoolean("fill", true);
jsonWriter.WritePropertyName("data");
jsonWriter.WriteStartArray();
foreach (long value in dataSet.Data)
jsonWriter.WriteNumberValue(value);
jsonWriter.WriteEndArray();
jsonWriter.WriteEndObject();
}
private async Task ResolvePtrTopClientsAsync(DashboardStats.TopClientStats[] topClients)
{
IDictionary<string, string> dhcpClientIpMap = _dnsWebService._dhcpServer.GetAddressHostNameMap();
async Task ResolvePtrAsync(DashboardStats.TopClientStats item)
{
string ip = item.Name;
if (dhcpClientIpMap.TryGetValue(ip, out string dhcpDomain))
{
item.Domain = dhcpDomain;
return;
}
IPAddress address = IPAddress.Parse(ip);
if (IPAddress.IsLoopback(address))
{
item.Domain = "localhost";
return;
}
DnsDatagram ptrResponse = await _dnsWebService._dnsServer.DirectQueryAsync(new DnsQuestionRecord(address, DnsClass.IN), 500);
if (ptrResponse.Answer.Count > 0)
{
IReadOnlyList<string> ptrDomains = DnsClient.ParseResponsePTR(ptrResponse);
if (ptrDomains.Count > 0)
{
item.Domain = ptrDomains[0];
return;
}
}
}
List<Task> resolverTasks = new List<Task>(topClients.Length);
foreach (DashboardStats.TopClientStats item in topClients)
{
if (string.IsNullOrEmpty(item.Domain))
resolverTasks.Add(ResolvePtrAsync(item));
}
foreach (Task resolverTask in resolverTasks)
{
try
{
await resolverTask;
}
catch
{ }
}
}
#endregion
#region public
public async Task GetStats(HttpContext context)
{
User sessionUser = _dnsWebService.GetSessionUser(context);
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Dashboard, sessionUser, PermissionFlag.View))
throw new DnsWebServiceException("Access was denied.");
HttpRequest request = context.Request;
DashboardStatsType type = request.GetQueryOrFormEnum("type", DashboardStatsType.LastHour);
bool utcFormat = request.GetQueryOrForm("utc", bool.Parse, false);
bool isLanguageEnUs = true;
string acceptLanguage = request.Headers.AcceptLanguage;
if (!string.IsNullOrEmpty(acceptLanguage))
isLanguageEnUs = acceptLanguage.StartsWith("en-us", StringComparison.OrdinalIgnoreCase);
bool dontTrimQueryTypeData = request.GetQueryOrForm("dontTrimQueryTypeData", bool.Parse, false);
DateTime startDate = default;
DateTime endDate = default;
if (type == DashboardStatsType.Custom)
{
string strStartDate = request.GetQueryOrForm("start");
string strEndDate = request.GetQueryOrForm("end");
if (!DateTime.TryParse(strStartDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out startDate))
throw new DnsWebServiceException("Invalid start date format.");
if (!DateTime.TryParse(strEndDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out endDate))
throw new DnsWebServiceException("Invalid end date format.");
if (startDate > endDate)
throw new DnsWebServiceException("Start date must be less than or equal to end date.");
}
List<Task<DashboardStats>> tasks = null;
if (_dnsWebService._clusterManager.ClusterInitialized)
{
string node = request.GetQueryOrForm("node", null);
if ("cluster".Equals(node, StringComparison.OrdinalIgnoreCase))
{
IReadOnlyDictionary<int, Cluster.ClusterNode> clusterNodes = _dnsWebService._clusterManager.ClusterNodes;
tasks = new List<Task<DashboardStats>>(clusterNodes.Count);
foreach (KeyValuePair<int, Cluster.ClusterNode> clusterNode in clusterNodes)
{
if (clusterNode.Value.State == Cluster.ClusterNodeState.Self)
continue;
tasks.Add(TechnitiumLibrary.TaskExtensions.TimeoutAsync(delegate (CancellationToken cancellationToken1)
{
return clusterNode.Value.GetDashboardStatsAsync(sessionUser, type, utcFormat, acceptLanguage, true, startDate, endDate, cancellationToken1);
}, CLUSTER_NODE_DASHBOARD_STATS_API_TIMEOUT));
}
}
}
DashboardStats dashboardStats;
string labelFormat;
switch (type)
{
case DashboardStatsType.LastHour:
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetLastHourMinuteWiseStats(utcFormat);
labelFormat = "HH:mm";
break;
case DashboardStatsType.LastDay:
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetLastDayHourWiseStats(utcFormat);
if (isLanguageEnUs)
labelFormat = "MM/DD HH:00";
else
labelFormat = "DD/MM HH:00";
break;
case DashboardStatsType.LastWeek:
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetLastWeekDayWiseStats(utcFormat);
if (isLanguageEnUs)
labelFormat = "MM/DD";
else
labelFormat = "DD/MM";
break;
case DashboardStatsType.LastMonth:
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetLastMonthDayWiseStats(utcFormat);
if (isLanguageEnUs)
labelFormat = "MM/DD";
else
labelFormat = "DD/MM";
break;
case DashboardStatsType.LastYear:
labelFormat = "MM/YYYY";
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetLastYearMonthWiseStats(utcFormat);
break;
case DashboardStatsType.Custom:
TimeSpan duration = endDate - startDate;
if ((Convert.ToInt32(duration.TotalDays) + 1) > 7)
{
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetDayWiseStats(startDate, endDate, utcFormat);
if (isLanguageEnUs)
labelFormat = "MM/DD";
else
labelFormat = "DD/MM";
}
else if ((Convert.ToInt32(duration.TotalHours) + 1) > 3)
{
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetHourWiseStats(startDate, endDate, utcFormat);
if (isLanguageEnUs)
labelFormat = "MM/DD HH:00";
else
labelFormat = "DD/MM HH:00";
}
else
{
dashboardStats = _dnsWebService._dnsServer.StatsManager.GetMinuteWiseStats(startDate, endDate, utcFormat);
if (isLanguageEnUs)
labelFormat = "MM/DD HH:mm";
else
labelFormat = "DD/MM HH:mm";
}
break;
default:
throw new DnsWebServiceException("Unknown stats type requested: " + type.ToString());
}
//add extra stats
{
dashboardStats.Stats.Zones = _dnsWebService._dnsServer.AuthZoneManager.TotalZones;
dashboardStats.Stats.CachedEntries = _dnsWebService._dnsServer.CacheZoneManager.TotalEntries;
dashboardStats.Stats.AllowedZones = _dnsWebService._dnsServer.AllowedZoneManager.TotalZonesAllowed;
dashboardStats.Stats.BlockedZones = _dnsWebService._dnsServer.BlockedZoneManager.TotalZonesBlocked;
dashboardStats.Stats.AllowListZones = _dnsWebService._dnsServer.BlockListZoneManager.TotalZonesAllowed;
dashboardStats.Stats.BlockListZones = _dnsWebService._dnsServer.BlockListZoneManager.TotalZonesBlocked;
}
if (tasks is not null)
{
foreach (Task<DashboardStats> task in tasks)
{
try
{
dashboardStats.Merge(await task, 10);
}
catch (Exception ex)
{
_dnsWebService._log.Write(ex);
}
}
}
if (!dontTrimQueryTypeData)
dashboardStats.QueryTypeChartData.Trim(10); //trim query type data
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
//stats
{
jsonWriter.WritePropertyName("stats");
jsonWriter.WriteStartObject();
jsonWriter.WriteNumber("totalQueries", dashboardStats.Stats.TotalQueries);
jsonWriter.WriteNumber("totalNoError", dashboardStats.Stats.TotalNoError);
jsonWriter.WriteNumber("totalServerFailure", dashboardStats.Stats.TotalServerFailure);
jsonWriter.WriteNumber("totalNxDomain", dashboardStats.Stats.TotalNxDomain);
jsonWriter.WriteNumber("totalRefused", dashboardStats.Stats.TotalRefused);
jsonWriter.WriteNumber("totalAuthoritative", dashboardStats.Stats.TotalAuthoritative);
jsonWriter.WriteNumber("totalRecursive", dashboardStats.Stats.TotalRecursive);
jsonWriter.WriteNumber("totalCached", dashboardStats.Stats.TotalCached);
jsonWriter.WriteNumber("totalBlocked", dashboardStats.Stats.TotalBlocked);
jsonWriter.WriteNumber("totalDropped", dashboardStats.Stats.TotalDropped);
jsonWriter.WriteNumber("totalClients", dashboardStats.Stats.TotalClients);
jsonWriter.WriteNumber("zones", dashboardStats.Stats.Zones);
jsonWriter.WriteNumber("cachedEntries", dashboardStats.Stats.CachedEntries);
jsonWriter.WriteNumber("allowedZones", dashboardStats.Stats.AllowedZones);
jsonWriter.WriteNumber("blockedZones", dashboardStats.Stats.BlockedZones);
jsonWriter.WriteNumber("allowListZones", dashboardStats.Stats.AllowListZones);
jsonWriter.WriteNumber("blockListZones", dashboardStats.Stats.BlockListZones);
jsonWriter.WriteEndObject();
}
//main chart
{
jsonWriter.WritePropertyName("mainChartData");
jsonWriter.WriteStartObject();
//label format
{
jsonWriter.WriteString("labelFormat", labelFormat);
}
//label
{
jsonWriter.WritePropertyName("labels");
jsonWriter.WriteStartArray();
foreach (string label in dashboardStats.MainChartData.Labels)
jsonWriter.WriteStringValue(label);
jsonWriter.WriteEndArray();
}
//datasets
{
jsonWriter.WritePropertyName("datasets");
jsonWriter.WriteStartArray();
foreach (DashboardStats.DataSet dataSet in dashboardStats.MainChartData.DataSets)
{
string backgroundColor;
string borderColor;
switch (dataSet.Label)
{
case "Total":
backgroundColor = "rgba(102, 153, 255, 0.1)";
borderColor = "rgb(102, 153, 255)";
break;
case "No Error":
backgroundColor = "rgba(92, 184, 92, 0.1)";
borderColor = "rgb(92, 184, 92)";
break;
case "Server Failure":
backgroundColor = "rgba(217, 83, 79, 0.1)";
borderColor = "rgb(217, 83, 79)";
break;
case "NX Domain":
backgroundColor = "rgba(120, 120, 120, 0.1)";
borderColor = "rgb(120, 120, 120)";
break;
case "Refused":
backgroundColor = "rgba(91, 192, 222, 0.1)";
borderColor = "rgb(91, 192, 222)";
break;
case "Authoritative":
backgroundColor = "rgba(150, 150, 0, 0.1)";
borderColor = "rgb(150, 150, 0)";
break;
case "Recursive":
backgroundColor = "rgba(23, 162, 184, 0.1)";
borderColor = "rgb(23, 162, 184)";
break;
case "Cached":
backgroundColor = "rgba(111, 84, 153, 0.1)";
borderColor = "rgb(111, 84, 153)";
break;
case "Blocked":
backgroundColor = "rgba(255, 165, 0, 0.1)";
borderColor = "rgb(255, 165, 0)";
break;
case "Dropped":
backgroundColor = "rgba(30, 30, 30, 0.1)";
borderColor = "rgb(30, 30, 30)";
break;
case "Clients":
backgroundColor = "rgba(51, 122, 183, 0.1)";
borderColor = "rgb(51, 122, 183)";
break;
default:
throw new InvalidOperationException();
}
WriteChartDataSet(jsonWriter, dataSet, backgroundColor, borderColor);
}
jsonWriter.WriteEndArray();
}
jsonWriter.WriteEndObject();
}
//query response chart
{
jsonWriter.WritePropertyName("queryResponseChartData");
jsonWriter.WriteStartObject();
//labels
{
jsonWriter.WritePropertyName("labels");
jsonWriter.WriteStartArray();
foreach (string label in dashboardStats.QueryResponseChartData.Labels)
jsonWriter.WriteStringValue(label);
jsonWriter.WriteEndArray();
}
//datasets
{
jsonWriter.WritePropertyName("datasets");
jsonWriter.WriteStartArray();
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("data");
jsonWriter.WriteStartArray();
foreach (long value in dashboardStats.QueryResponseChartData.DataSets[0].Data)
jsonWriter.WriteNumberValue(value);
jsonWriter.WriteEndArray();
jsonWriter.WritePropertyName("backgroundColor");
jsonWriter.WriteStartArray();
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(7, 7, 7, 0.5)");
jsonWriter.WriteEndArray();
jsonWriter.WriteEndObject();
jsonWriter.WriteEndArray();
}
jsonWriter.WriteEndObject();
}
//query type chart
{
jsonWriter.WritePropertyName("queryTypeChartData");
jsonWriter.WriteStartObject();
//labels
{
jsonWriter.WritePropertyName("labels");
jsonWriter.WriteStartArray();
foreach (string label in dashboardStats.QueryTypeChartData.Labels)
jsonWriter.WriteStringValue(label);
jsonWriter.WriteEndArray();
}
//datasets
{
jsonWriter.WritePropertyName("datasets");
jsonWriter.WriteStartArray();
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("data");
jsonWriter.WriteStartArray();
foreach (long value in dashboardStats.QueryTypeChartData.DataSets[0].Data)
jsonWriter.WriteNumberValue(value);
jsonWriter.WriteEndArray();
jsonWriter.WritePropertyName("backgroundColor");
jsonWriter.WriteStartArray();
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();
jsonWriter.WriteEndArray();
}
jsonWriter.WriteEndObject();
}
//protocol type chart
{
jsonWriter.WritePropertyName("protocolTypeChartData");
jsonWriter.WriteStartObject();
//labels
{
jsonWriter.WritePropertyName("labels");
jsonWriter.WriteStartArray();
foreach (string label in dashboardStats.ProtocolTypeChartData.Labels)
jsonWriter.WriteStringValue(label);
jsonWriter.WriteEndArray();
}
//datasets
{
jsonWriter.WritePropertyName("datasets");
jsonWriter.WriteStartArray();
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("data");
jsonWriter.WriteStartArray();
foreach (long value in dashboardStats.ProtocolTypeChartData.DataSets[0].Data)
jsonWriter.WriteNumberValue(value);
jsonWriter.WriteEndArray();
jsonWriter.WritePropertyName("backgroundColor");
jsonWriter.WriteStartArray();
jsonWriter.WriteStringValue("rgba(111, 84, 153, 0.5)");
jsonWriter.WriteStringValue("rgba(150, 150, 0, 0.5)");
jsonWriter.WriteStringValue("rgba(23, 162, 184, 0.5)"); ;
jsonWriter.WriteStringValue("rgba(255, 165, 0, 0.5)");
jsonWriter.WriteStringValue("rgba(91, 192, 222, 0.5)");
jsonWriter.WriteEndArray();
jsonWriter.WriteEndObject();
jsonWriter.WriteEndArray();
}
jsonWriter.WriteEndObject();
}
//top clients
{
await ResolvePtrTopClientsAsync(dashboardStats.TopClients);
jsonWriter.WritePropertyName("topClients");
jsonWriter.WriteStartArray();
foreach (DashboardStats.TopClientStats item in dashboardStats.TopClients)
{
jsonWriter.WriteStartObject();
jsonWriter.WriteString("name", item.Name);
if (!string.IsNullOrEmpty(item.Domain))
jsonWriter.WriteString("domain", item.Domain);
jsonWriter.WriteNumber("hits", item.Hits);
IPAddress ip = IPAddress.Parse(item.Name);
jsonWriter.WriteBoolean("rateLimited", item.RateLimited || _dnsWebService._dnsServer.HasQpmLimitExceeded(ip, DnsTransportProtocol.Udp) || _dnsWebService._dnsServer.HasQpmLimitExceeded(ip, DnsTransportProtocol.Tcp));
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
//top domains
{
jsonWriter.WritePropertyName("topDomains");
jsonWriter.WriteStartArray();
foreach (DashboardStats.TopStats item in dashboardStats.TopDomains)
{
jsonWriter.WriteStartObject();
jsonWriter.WriteString("name", item.Name);
if (DnsClient.TryConvertDomainNameToUnicode(item.Name, out string idn))
jsonWriter.WriteString("nameIdn", idn);
jsonWriter.WriteNumber("hits", item.Hits);
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
//top blocked domains
{
jsonWriter.WritePropertyName("topBlockedDomains");
jsonWriter.WriteStartArray();
foreach (DashboardStats.TopStats item in dashboardStats.TopBlockedDomains)
{
jsonWriter.WriteStartObject();
jsonWriter.WriteString("name", item.Name);
if (DnsClient.TryConvertDomainNameToUnicode(item.Name, out string idn))
jsonWriter.WriteString("nameIdn", idn);
jsonWriter.WriteNumber("hits", item.Hits);
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
}
public async Task GetTopStats(HttpContext context)
{
User sessionUser = _dnsWebService.GetSessionUser(context);
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Dashboard, sessionUser, PermissionFlag.View))
throw new DnsWebServiceException("Access was denied.");
HttpRequest request = context.Request;
DashboardStatsType type = request.GetQueryOrFormEnum("type", DashboardStatsType.LastHour);
DashboardTopStatsType statsType = request.GetQueryOrFormEnum<DashboardTopStatsType>("statsType");
int limit = request.GetQueryOrForm("limit", int.Parse, 1000);
DateTime startDate = default;
DateTime endDate = default;
if (type == DashboardStatsType.Custom)
{
string strStartDate = request.GetQueryOrForm("start");
string strEndDate = request.GetQueryOrForm("end");
if (!DateTime.TryParse(strStartDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out startDate))
throw new DnsWebServiceException("Invalid start date format.");
if (!DateTime.TryParse(strEndDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out endDate))
throw new DnsWebServiceException("Invalid end date format.");
if (startDate > endDate)
throw new DnsWebServiceException("Start date must be less than or equal to end date.");
}
List<Task<DashboardStats>> tasks = null;
if (_dnsWebService._clusterManager.ClusterInitialized)
{
string node = request.GetQueryOrForm("node", null);
if ("cluster".Equals(node, StringComparison.OrdinalIgnoreCase))
{
IReadOnlyDictionary<int, Cluster.ClusterNode> clusterNodes = _dnsWebService._clusterManager.ClusterNodes;
tasks = new List<Task<DashboardStats>>(clusterNodes.Count);
foreach (KeyValuePair<int, Cluster.ClusterNode> clusterNode in clusterNodes)
{
if (clusterNode.Value.State == Cluster.ClusterNodeState.Self)
continue;
tasks.Add(TechnitiumLibrary.TaskExtensions.TimeoutAsync(delegate (CancellationToken cancellationToken1)
{
return clusterNode.Value.GetDashboardTopStatsAsync(sessionUser, statsType, limit, type, startDate, endDate, cancellationToken1);
}, CLUSTER_NODE_DASHBOARD_STATS_API_TIMEOUT));
}
}
}
DashboardStats topStatsData;
switch (type)
{
case DashboardStatsType.LastHour:
topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastHourTopStats(statsType, limit);
break;
case DashboardStatsType.LastDay:
topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastDayTopStats(statsType, limit);
break;
case DashboardStatsType.LastWeek:
topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastWeekTopStats(statsType, limit);
break;
case DashboardStatsType.LastMonth:
topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastMonthTopStats(statsType, limit);
break;
case DashboardStatsType.LastYear:
topStatsData = _dnsWebService._dnsServer.StatsManager.GetLastYearTopStats(statsType, limit);
break;
case DashboardStatsType.Custom:
TimeSpan duration = endDate - startDate;
if ((Convert.ToInt32(duration.TotalDays) + 1) > 7)
topStatsData = _dnsWebService._dnsServer.StatsManager.GetDayWiseTopStats(startDate, endDate, statsType, limit);
else if ((Convert.ToInt32(duration.TotalHours) + 1) > 3)
topStatsData = _dnsWebService._dnsServer.StatsManager.GetHourWiseTopStats(startDate, endDate, statsType, limit);
else
topStatsData = _dnsWebService._dnsServer.StatsManager.GetMinuteWiseTopStats(startDate, endDate, statsType, limit);
break;
default:
throw new DnsWebServiceException("Unknown stats type requested: " + type.ToString());
}
if (tasks is not null)
{
foreach (Task<DashboardStats> task in tasks)
{
try
{
topStatsData.Merge(await task, limit);
}
catch (Exception ex)
{
_dnsWebService._log.Write(ex);
}
}
}
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
switch (statsType)
{
case DashboardTopStatsType.TopClients:
{
bool noReverseLookup = request.GetQueryOrForm("noReverseLookup", bool.Parse, false);
bool onlyRateLimitedClients = request.GetQueryOrForm("onlyRateLimitedClients", bool.Parse, false);
if (!noReverseLookup)
await ResolvePtrTopClientsAsync(topStatsData.TopClients);
jsonWriter.WritePropertyName("topClients");
jsonWriter.WriteStartArray();
foreach (DashboardStats.TopClientStats item in topStatsData.TopClients)
{
IPAddress ip = IPAddress.Parse(item.Name);
bool rateLimited = item.RateLimited || _dnsWebService._dnsServer.HasQpmLimitExceeded(ip, DnsTransportProtocol.Udp) || _dnsWebService._dnsServer.HasQpmLimitExceeded(ip, DnsTransportProtocol.Tcp);
if (onlyRateLimitedClients && !rateLimited)
continue;
jsonWriter.WriteStartObject();
jsonWriter.WriteString("name", item.Name);
if (!string.IsNullOrEmpty(item.Domain))
jsonWriter.WriteString("domain", item.Domain);
jsonWriter.WriteNumber("hits", item.Hits);
jsonWriter.WriteBoolean("rateLimited", rateLimited);
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
break;
case DashboardTopStatsType.TopDomains:
{
jsonWriter.WritePropertyName("topDomains");
jsonWriter.WriteStartArray();
foreach (DashboardStats.TopStats item in topStatsData.TopDomains)
{
jsonWriter.WriteStartObject();
jsonWriter.WriteString("name", item.Name);
if (DnsClient.TryConvertDomainNameToUnicode(item.Name, out string idn))
jsonWriter.WriteString("nameIdn", idn);
jsonWriter.WriteNumber("hits", item.Hits);
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
break;
case DashboardTopStatsType.TopBlockedDomains:
{
jsonWriter.WritePropertyName("topBlockedDomains");
jsonWriter.WriteStartArray();
foreach (DashboardStats.TopStats item in topStatsData.TopBlockedDomains)
{
jsonWriter.WriteStartObject();
jsonWriter.WriteString("name", item.Name);
if (DnsClient.TryConvertDomainNameToUnicode(item.Name, out string idn))
jsonWriter.WriteString("nameIdn", idn);
jsonWriter.WriteNumber("hits", item.Hits);
jsonWriter.WriteEndObject();
}
jsonWriter.WriteEndArray();
}
break;
default:
throw new NotSupportedException();
}
}
#endregion
}
}
}