diff --git a/src/opnsense/mvc/app/views/OPNsense/Diagnostics/traffic.volt b/src/opnsense/mvc/app/views/OPNsense/Diagnostics/traffic.volt
index 2205fa0e8..d622019c3 100644
--- a/src/opnsense/mvc/app/views/OPNsense/Diagnostics/traffic.volt
+++ b/src/opnsense/mvc/app/views/OPNsense/Diagnostics/traffic.volt
@@ -264,7 +264,15 @@ POSSIBILITY OF SUCH DAMAGE.
.data('bps_max_out', 0).data('total_in', 0).data('total_out', 0)
.data('intf', intf);
tr.append($("
| ").html(intf_label));
- tr.append($(" | ").text(item.address));
+ if (item.rname) {
+ tr.append(
+ $(" | ").append(
+ $("").text(item.rname), $("").text("("+item.address+")")
+ )
+ );
+ } else {
+ tr.append($(" | ").text(item.address));
+ }
tr.append($(" | ").text("0b"));
tr.append($(" | ").text("0b"));
tr.append($(" | ").text("0b"));
diff --git a/src/opnsense/scripts/interfaces/traffic_top.py b/src/opnsense/scripts/interfaces/traffic_top.py
index 98657a3b7..f856fd11c 100755
--- a/src/opnsense/scripts/interfaces/traffic_top.py
+++ b/src/opnsense/scripts/interfaces/traffic_top.py
@@ -27,6 +27,7 @@
"""
import argparse
+import asyncio
import decimal
import subprocess
import os
@@ -34,6 +35,8 @@ import sys
import math
import ujson
import netaddr
+import dns.resolver
+from dns.asyncresolver import Resolver
from concurrent.futures import ThreadPoolExecutor
from netaddr import IPNetwork, IPAddress, AddrFormatError
@@ -79,6 +82,31 @@ def to_bformat(value):
ndx = math.floor(math.log(value) / math.log(1000)) if value > 0 else 0
return "%s %s" % (round(value / math.pow(1000, ndx), 2), fileSizeTypes[ndx])
+class AsyncLookup:
+ def __init__(self):
+ self._results = {}
+
+ async def request_ittr(self, addresses):
+ self._results = {}
+ dnsResolver = Resolver()
+ dnsResolver.timeout = 2
+ tasks = []
+ for adres in addresses:
+ tasks.append(dnsResolver.resolve_address(adres))
+ responses = await asyncio.gather(*tasks, return_exceptions=True)
+ for response in responses:
+ if type(response) is dns.resolver.Answer:
+ addr = ".".join(reversed(response.canonical_name.to_text().replace('.in-addr.arpa.', '').split('.')))
+ for item in response.response.answer:
+ if type(item) is dns.rrset.RRset and len(item.items) > 0:
+ self._results[addr] = str(list(item.items)[0])
+
+ def collect(self, addresses):
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+ asyncio.run(self.request_ittr(addresses))
+ loop.close()
+ return self._results
if __name__ == '__main__':
result = dict()
@@ -152,7 +180,9 @@ if __name__ == '__main__':
# XXX: sort output, limit output results to max 200 (safety precaution)
top_hosts = sorted(agg_results.values(), key=lambda x: x['rate_bits'], reverse=True)[:200]
+ reverse_lookup = AsyncLookup().collect([x['address'] for x in top_hosts])
for host in top_hosts:
+ host['rname'] = reverse_lookup[host['address']] if host['address'] in reverse_lookup else ""
host['rate_in'] = to_bformat(host['rate_bits_in'])
host['rate_out'] = to_bformat(host['rate_bits_out'])
host['rate'] = to_bformat(host['rate_bits'])