From b9891d830785670d9dbba43ceca3d742845fd316 Mon Sep 17 00:00:00 2001 From: Aliaksandr Nikitsin Date: Mon, 16 Dec 2024 15:17:32 +0100 Subject: [PATCH 1/5] generating dns module report using jinja --- modules/test/dns/dns.Dockerfile | 6 +- modules/test/dns/python/src/dns_module.py | 130 +++++++++--------- .../test/dns/resources/report_template.jinja2 | 31 +++++ 3 files changed, 103 insertions(+), 64 deletions(-) create mode 100644 modules/test/dns/resources/report_template.jinja2 diff --git a/modules/test/dns/dns.Dockerfile b/modules/test/dns/dns.Dockerfile index 461e87899..53f8f31f8 100644 --- a/modules/test/dns/dns.Dockerfile +++ b/modules/test/dns/dns.Dockerfile @@ -31,4 +31,8 @@ COPY $MODULE_DIR/conf /testrun/conf COPY $MODULE_DIR/bin /testrun/bin # Copy over all python files -COPY $MODULE_DIR/python /testrun/python \ No newline at end of file +COPY $MODULE_DIR/python /testrun/python + +# Copy Jinja template +COPY $MODULE_DIR/resources/report_template.jinja2 $REPORT_TEMPLATE_PATH/ + diff --git a/modules/test/dns/python/src/dns_module.py b/modules/test/dns/python/src/dns_module.py index fe244f0a7..42133d5c0 100644 --- a/modules/test/dns/python/src/dns_module.py +++ b/modules/test/dns/python/src/dns_module.py @@ -17,19 +17,21 @@ from test_module import TestModule import os from collections import Counter +from jinja2 import Environment, FileSystemLoader LOG_NAME = 'test_dns' -MODULE_REPORT_FILE_NAME = 'dns_report.html' +MODULE_REPORT_FILE_NAME = 'dns_report.jinja2' DNS_SERVER_CAPTURE_FILE = '/runtime/network/dns.pcap' STARTUP_CAPTURE_FILE = '/runtime/device/startup.pcap' MONITOR_CAPTURE_FILE = '/runtime/device/monitor.pcap' LOGGER = None +REPORT_TEMPLATE_FILE = 'report_template.jinja2' class DNSModule(TestModule): """DNS Test module""" - def __init__(self, + def __init__(self, # pylint: disable=R0917 module, conf_file=None, results_dir=None, @@ -48,11 +50,33 @@ def __init__(self, LOGGER = self._get_logger() def generate_module_report(self): + # Load Jinja2 template + page_max_height = 910 + header_height = 48 + summary_height = 135 + row_height = 42 + loader=FileSystemLoader(self._report_template_folder) + template = Environment(loader=loader).get_template(REPORT_TEMPLATE_FILE) + module_header='DNS Module' + # Summary table headers + summary_headers = [ + 'Requests to local DNS server', + 'Requests to external DNS servers', + 'Total DNS requests', + 'Total DNS responses', + ] + # Module data Headers + module_data_headers = [ + 'Source', + 'Destination', + 'Resolved IP', + 'Type', + 'URL', + 'Count', + ] # Extract DNS data from the pcap file dns_table_data = self.extract_dns_data() - html_content = '

DNS Module

' - # Set the summary variables local_requests = sum( 1 for row in dns_table_data @@ -67,79 +91,59 @@ def generate_module_report(self): if row['Type'] == 'Response') # Add summary table - html_content += (f''' - - - - - - - - - - - - - - - - -
Requests to local DNS serverRequests to external DNS serversTotal DNS requestsTotal DNS responses
{local_requests}{external_requests}{total_requests}{total_responses}
- ''') - + summary_data = [ + local_requests, + external_requests, + total_requests, + total_responses, + ] + + module_data = [] if (total_requests + total_responses) > 0: - table_content = ''' - - - - - - - - - - - - ''' - # Count unique combinations counter = Counter((row['Source'], row['Destination'], row['ResolvedIP'], row['Type'], row['Data']) for row in dns_table_data) # Generate the HTML table with the count column for (src, dst, res_ip, typ, dat), count in counter.items(): - table_content += f''' - - - - - - - - ''' - - table_content += ''' - -
SourceDestinationResolved IPTypeURLCount
{src}{dst}{res_ip}{typ}{dat}{count}
''' - - html_content += table_content - - else: - html_content += (''' -
-
- No DNS traffic detected from the device -
''') - - LOGGER.debug('Module report:\n' + html_content) + module_data.append({ + 'src': src, + 'dst': dst, + 'res_ip': res_ip, + 'typ': typ, + 'dat': dat, + 'count': count, + }) + # Handling the possible table split + table_height = (len(module_data) + 1) * row_height + page_useful_space = page_max_height - header_height - summary_height + pages = table_height // (page_useful_space) + rows_on_page = (page_useful_space) // row_height + start = 0 + report_html = '' + for page in range(pages+1): + end = start + min(len(module_data), rows_on_page) + module_header_repr = module_header if page == 0 else None + page_html = template.render( + base_template=self._base_template_file, + module_header=module_header_repr, + summary_headers=summary_headers, + summary_data=summary_data, + module_data_headers=module_data_headers, + module_data=module_data[start:end] + ) + report_html += page_html + start = end + + LOGGER.debug('Module report:\n' + report_html) # Use os.path.join to create the complete file path report_path = os.path.join(self._results_dir, MODULE_REPORT_FILE_NAME) # Write the content to a file with open(report_path, 'w', encoding='utf-8') as file: - file.write(html_content) + file.write(report_html) LOGGER.info('Module report generated at: ' + str(report_path)) diff --git a/modules/test/dns/resources/report_template.jinja2 b/modules/test/dns/resources/report_template.jinja2 new file mode 100644 index 000000000..2d4dd99b2 --- /dev/null +++ b/modules/test/dns/resources/report_template.jinja2 @@ -0,0 +1,31 @@ +{% extends base_template %} +{% block content %} +{% if module_data %} + + + + {% for header in module_data_headers %} + + {% endfor %} + + + + {% for row in module_data %} + + + + + + + + + {% endfor %} + +
{{ header }}
{{ row['src'] }}{{ row['dst'] }}{{ row['res_ip'] }}{{ row['typ'] }}{{ row['dat'] }}{{ row['count'] }}
+{% else %} +
+
+ No DNS traffic detected from the device +
+{% endif %} +{% endblock %} \ No newline at end of file From 7190a3b48490d8a37c11fccc7d87b5e1855559b3 Mon Sep 17 00:00:00 2001 From: Aliaksandr Nikitsin Date: Wed, 18 Dec 2024 13:32:40 +0100 Subject: [PATCH 2/5] rename report file --- modules/test/dns/python/src/dns_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/test/dns/python/src/dns_module.py b/modules/test/dns/python/src/dns_module.py index 42133d5c0..47cdb82b4 100644 --- a/modules/test/dns/python/src/dns_module.py +++ b/modules/test/dns/python/src/dns_module.py @@ -20,7 +20,7 @@ from jinja2 import Environment, FileSystemLoader LOG_NAME = 'test_dns' -MODULE_REPORT_FILE_NAME = 'dns_report.jinja2' +MODULE_REPORT_FILE_NAME = 'dns_report.j2.html' DNS_SERVER_CAPTURE_FILE = '/runtime/network/dns.pcap' STARTUP_CAPTURE_FILE = '/runtime/device/startup.pcap' MONITOR_CAPTURE_FILE = '/runtime/device/monitor.pcap' From abbdcbd5cbd497019c433d5090ca36e44295e88f Mon Sep 17 00:00:00 2001 From: Volha Mardvilka Date: Thu, 19 Dec 2024 12:38:40 +0000 Subject: [PATCH 3/5] 382100926: (feat) change styles for dns module table --- .../test/dns/resources/report_template.jinja2 | 16 ++++++++-------- resources/report/test_report_styles.css | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/modules/test/dns/resources/report_template.jinja2 b/modules/test/dns/resources/report_template.jinja2 index 2d4dd99b2..2a690f610 100644 --- a/modules/test/dns/resources/report_template.jinja2 +++ b/modules/test/dns/resources/report_template.jinja2 @@ -1,7 +1,7 @@ {% extends base_template %} {% block content %} {% if module_data %} - +
{% for header in module_data_headers %} @@ -12,13 +12,13 @@ {% for row in module_data %} - - - - - - - + + + + + + + {% endfor %}
{{ row['src'] }}{{ row['dst'] }}{{ row['res_ip'] }}{{ row['typ'] }}{{ row['dat'] }}{{ row['count'] }}
{{ row['src'] }}
>
{{ row['dst'] }}
{{ row['res_ip'] }}
{{ row['typ'] }}
{{ row['dat'] }}
{{ row['count'] }}
diff --git a/resources/report/test_report_styles.css b/resources/report/test_report_styles.css index b1ed9d33c..3971bd2eb 100644 --- a/resources/report/test_report_styles.css +++ b/resources/report/test_report_styles.css @@ -222,6 +222,24 @@ word-break: break-word; } + .module-data.dns-module thead tr th, + .module-data.dns-module tbody tr td { + padding: 12px 16px; + } + + .module-data.dns-module tbody tr td { + max-width: 1px; + } + + .module-data.dns-module tbody tr td.count-row { + width: 1px; + } + + .module-data.dns-module tbody tr td div { + word-wrap: break-word; + overflow-wrap: break-word; + } + div.steps-to-resolve { background-color: #F8F9FA; margin-bottom: 30px; From 95f6aa221eea60750cd5e591a303ed925ff7c31b Mon Sep 17 00:00:00 2001 From: Aliaksandr Nikitsin Date: Thu, 19 Dec 2024 14:39:41 +0100 Subject: [PATCH 4/5] fix tag --- modules/test/dns/resources/report_template.jinja2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/test/dns/resources/report_template.jinja2 b/modules/test/dns/resources/report_template.jinja2 index 2a690f610..8e701a8e3 100644 --- a/modules/test/dns/resources/report_template.jinja2 +++ b/modules/test/dns/resources/report_template.jinja2 @@ -12,7 +12,7 @@ {% for row in module_data %} -
{{ row['src'] }}
> +
{{ row['src'] }}
{{ row['dst'] }}
{{ row['res_ip'] }}
{{ row['typ'] }}
From 7d9e197b6d1bd57b1308b411ea2c09ab2c5d7f77 Mon Sep 17 00:00:00 2001 From: Aliaksandr Nikitsin Date: Thu, 19 Dec 2024 15:10:03 +0100 Subject: [PATCH 5/5] unit tests --- .../unit/dns/reports/dns_report_local.html | 258 +++++++++++------- .../dns/reports/dns_report_local_no_dns.html | 94 +++++-- 2 files changed, 232 insertions(+), 120 deletions(-) diff --git a/testing/unit/dns/reports/dns_report_local.html b/testing/unit/dns/reports/dns_report_local.html index ce5a535fd..9c4e6c90a 100644 --- a/testing/unit/dns/reports/dns_report_local.html +++ b/testing/unit/dns/reports/dns_report_local.html @@ -1,97 +1,161 @@ -

DNS Module

- - - - - - - - - - - - - - - - -
Requests to local DNS serverRequests to external DNS serversTotal DNS requestsTotal DNS responses
7107184
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SourceDestinationResolved IPTypeURLCount
10.10.10.1410.10.10.4N/AQuerymqtt.googleapis.com64
10.10.10.410.10.10.14173.194.195.206Responsemqtt.googleapis.com38
10.10.10.410.10.10.142607:f8b0:4001:c11::ceResponsemqtt.googleapis.com32
10.10.10.1410.10.10.4N/AQuerypool.ntp.org7
10.10.10.410.10.10.14N/AResponsepool.ntp.org4
10.10.10.410.10.10.145.78.89.3Responsepool.ntp.org2
10.10.10.410.10.10.14199.68.201.234Responsepool.ntp.org2
10.10.10.410.10.10.142607:f8b0:4001:c08::ceResponsemqtt.googleapis.com6
\ No newline at end of file + +
+
+
+ {# Badge #} +

+ {% if json_data['device']['test_pack'] == 'Device Qualification' %} + + Device Qualification + {% else %} + + Pilot Assessment + {% endif %} +

+ {{ title }} +
+ + {{ device['manufacturer'] }} + {{ device['model']}} + + Testrun +
+ +
+ +

DNS Module

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Requests to local DNS serverRequests to external DNS serversTotal DNS requestsTotal DNS responses
7107184
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SourceDestinationResolved IPTypeURLCount
10.10.10.14
10.10.10.4
N/A
Query
mqtt.googleapis.com
64
10.10.10.4
10.10.10.14
173.194.195.206
Response
mqtt.googleapis.com
38
10.10.10.4
10.10.10.14
2607:f8b0:4001:c11::ce
Response
mqtt.googleapis.com
32
10.10.10.14
10.10.10.4
N/A
Query
pool.ntp.org
7
10.10.10.4
10.10.10.14
N/A
Response
pool.ntp.org
4
10.10.10.4
10.10.10.14
5.78.89.3
Response
pool.ntp.org
2
10.10.10.4
10.10.10.14
199.68.201.234
Response
pool.ntp.org
2
10.10.10.4
10.10.10.14
2607:f8b0:4001:c08::ce
Response
mqtt.googleapis.com
6
+ + +
+ + +
+
diff --git a/testing/unit/dns/reports/dns_report_local_no_dns.html b/testing/unit/dns/reports/dns_report_local_no_dns.html index f144655f5..f9dee2020 100644 --- a/testing/unit/dns/reports/dns_report_local_no_dns.html +++ b/testing/unit/dns/reports/dns_report_local_no_dns.html @@ -1,23 +1,71 @@ -

DNS Module

- - - - - - - - - - - - - - - - -
Requests to local DNS serverRequests to external DNS serversTotal DNS requestsTotal DNS responses
0000
- -
-
- No DNS traffic detected from the device -
\ No newline at end of file + +
+
+
+ {# Badge #} +

+ {% if json_data['device']['test_pack'] == 'Device Qualification' %} + + Device Qualification + {% else %} + + Pilot Assessment + {% endif %} +

+ {{ title }} +
+ + {{ device['manufacturer'] }} + {{ device['model']}} + + Testrun +
+ +
+ +

DNS Module

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Requests to local DNS serverRequests to external DNS serversTotal DNS requestsTotal DNS responses
0000
+ + +
+
+ No DNS traffic detected from the device +
+ + +
+ + +
+