diff --git a/DnsServerCore/Dns/StatsManager.cs b/DnsServerCore/Dns/StatsManager.cs index 21ba77f4..4354d97b 100644 --- a/DnsServerCore/Dns/StatsManager.cs +++ b/DnsServerCore/Dns/StatsManager.cs @@ -1142,7 +1142,7 @@ namespace DnsServerCore.Dns return totalStatCounter.GetEligibleQueries(minimumHitsPerHour); } - public IReadOnlyDictionary GetLatestClientStats(int minutes) + public void GetLatestClientStats(int minutes, out IReadOnlyDictionary clientStats, out IReadOnlyDictionary refusedClientStats) { StatCounter totalStatCounter = new StatCounter(); totalStatCounter.Lock(); @@ -1159,7 +1159,8 @@ namespace DnsServerCore.Dns totalStatCounter.Merge(statCounter); } - return totalStatCounter.GetClientStats(); + clientStats = totalStatCounter.GetClientStats(); + refusedClientStats = totalStatCounter.GetRefusedClientStats(); } #endregion @@ -1282,6 +1283,7 @@ namespace DnsServerCore.Dns readonly ConcurrentDictionary _queryBlockedDomains; readonly ConcurrentDictionary _queryTypes; readonly ConcurrentDictionary _clientIpAddresses; + readonly ConcurrentDictionary _refusedIpAddresses; readonly ConcurrentDictionary _queries; #endregion @@ -1294,6 +1296,7 @@ namespace DnsServerCore.Dns _queryBlockedDomains = new ConcurrentDictionary(); _queryTypes = new ConcurrentDictionary(); _clientIpAddresses = new ConcurrentDictionary(); + _refusedIpAddresses = new ConcurrentDictionary(); _queries = new ConcurrentDictionary(); } @@ -1309,6 +1312,7 @@ namespace DnsServerCore.Dns case 2: case 3: case 4: + case 5: _totalQueries = bR.ReadInt32(); _totalNoError = bR.ReadInt32(); _totalServerFailure = bR.ReadInt32(); @@ -1375,6 +1379,19 @@ namespace DnsServerCore.Dns _queries = new ConcurrentDictionary(1, 0); } + if (version >= 5) + { + int count = bR.ReadInt32(); + _refusedIpAddresses = new ConcurrentDictionary(1, count); + + for (int i = 0; i < count; i++) + _refusedIpAddresses.TryAdd(IPAddressExtension.Parse(bR), new Counter(bR.ReadInt32())); + } + else + { + _refusedIpAddresses = new ConcurrentDictionary(1, 0); + } + break; default: @@ -1448,6 +1465,7 @@ namespace DnsServerCore.Dns break; case StatsResponseCode.Refused: + _refusedIpAddresses.GetOrAdd(clientIpAddress, GetNewCounter).Increment(); Interlocked.Increment(ref _totalRefused); break; } @@ -1504,6 +1522,9 @@ namespace DnsServerCore.Dns foreach (KeyValuePair clientIpAddress in statCounter._clientIpAddresses) _clientIpAddresses.GetOrAdd(clientIpAddress.Key, GetNewCounter).Merge(clientIpAddress.Value); + foreach (KeyValuePair refusedIpAddress in statCounter._refusedIpAddresses) + _refusedIpAddresses.GetOrAdd(refusedIpAddress.Key, GetNewCounter).Merge(refusedIpAddress.Value); + foreach (KeyValuePair query in statCounter._queries) _queries.GetOrAdd(query.Key, GetNewCounter).Merge(query.Value); } @@ -1600,6 +1621,26 @@ namespace DnsServerCore.Dns truncated = true; } + if (_refusedIpAddresses.Count > limit) + { + List> topRefusedClients = new List>(_refusedIpAddresses); + + _refusedIpAddresses.Clear(); + + topRefusedClients.Sort(delegate (KeyValuePair item1, KeyValuePair item2) + { + return item2.Value.Count.CompareTo(item1.Value.Count); + }); + + if (topRefusedClients.Count > limit) + topRefusedClients.RemoveRange(limit, topRefusedClients.Count - limit); + + foreach (KeyValuePair item in topRefusedClients) + _refusedIpAddresses[item.Key] = item.Value; + + truncated = true; + } + if (_queries.Count > limit) { //only last hour queries data is required for cache auto prefetching @@ -1617,7 +1658,7 @@ namespace DnsServerCore.Dns throw new DnsServerException("StatCounter must be locked."); bW.Write(Encoding.ASCII.GetBytes("SC")); //format - bW.Write((byte)4); //version + bW.Write((byte)5); //version bW.Write(_totalQueries); bW.Write(_totalNoError); @@ -1674,6 +1715,15 @@ namespace DnsServerCore.Dns bW.Write(query.Value.Count); } } + + { + bW.Write(_refusedIpAddresses.Count); + foreach (KeyValuePair refusedIpAddress in _refusedIpAddresses) + { + refusedIpAddress.Key.WriteTo(bW); + bW.Write(refusedIpAddress.Value.Count); + } + } } public List> GetTopDomains(int limit) @@ -1755,6 +1805,16 @@ namespace DnsServerCore.Dns return clientStats; } + public IReadOnlyDictionary GetRefusedClientStats() + { + Dictionary refusedClientStats = new Dictionary(_refusedIpAddresses.Count); + + foreach (KeyValuePair item in _refusedIpAddresses) + refusedClientStats.Add(item.Key, item.Value.Count); + + return refusedClientStats; + } + #endregion #region properties