|
{{ title }}
Generated: {{ generated }}
|
|
Total hosts: {{ total_hosts }}
Matching expected: {{ ok_hosts }}
With issues: {{ hosts_with_issues|length }}
|
{% if not only_issues and ok_hosts == total_hosts and total_hosts > 0 %}
All hosts matched expected ports.
{% endif %}
{% if only_issues and hosts_with_issues|length == 0 %}
No hosts with issues found. ✅
{% endif %}
{# ===== Host Sections (LIGHT theme) ===== #}
{# Reusable delta row #}
{% macro delta_row(label, ports) -%}
|
{{ label }}: {{ fmt_ports(ports) }}
|
{%- endmacro %}
{# ---------- 1) Issues first (already IP-sorted in Python) ---------- #}
{% for hr in issues %}
{% set ip_key = hr.ip %}
{% set r = hr %}
{% set host_row = host_results_by_ip.get(ip_key) %}
{% set header_title = ip_key ~ ((' (' ~ host_row.host ~ ')') if host_row and host_row.host else '') %}
|
{{ header_title }} {{ badge('ISSUES', '#ef4444') }}
|
|
{{ badge('ISSUES', '#ef4444') }}
|
{{ delta_row('Unexpected TCP open ports', r.unexpected_tcp) }}
{{ delta_row('Expected TCP ports not seen', r.missing_tcp) }}
{{ delta_row('Unexpected UDP open ports', r.unexpected_udp) }}
{{ delta_row('Expected UDP ports not seen', r.missing_udp) }}
|
Discovered Ports
|
| Protocol |
Port |
State |
Service |
Expectation |
{% if host_row and host_row.ports %}
{% set ns = namespace(visible_rows=0) %}
{% for p in host_row.ports %}
{% set proto = (p.protocol|string|lower) %}
{% set state = (p.state|string|lower) %}
{% set skip_row = (proto == 'udp' and ('closed' in state)) %}
{% set is_tcp = (proto == 'tcp') %}
{% set is_udp = (proto == 'udp') %}
{% set is_open = ('open' in state) %}
{% set is_issue = (is_open and (
(is_tcp and (p.port in (r.unexpected_tcp or []))) or
(is_udp and (p.port in (r.unexpected_udp or [])))
)) %}
{% set expectation_badge = (
badge('Issue', '#ef4444') if is_issue
else (badge('Expected', '#16a34a') if is_open else '—')
) %}
{% if not skip_row %}
{% set ns.visible_rows = ns.visible_rows + 1 %}
| {{ pill_proto(p.protocol) }} |
{{ p.port }} |
{{ pill_state(p.state) }} |
{{ p.service or '-' }} |
{{ expectation_badge | safe }} |
{% endif %}
{% endfor %}
{% if ns.visible_rows == 0 %}
|
No per-port details to display after filtering closed UDP results.
|
{% endif %}
{% else %}
|
No per-port details available for this host.
|
{% endif %}
{% endfor %}
{# ---------- 2) Expected / OK (only if not only_issues) ---------- #}
{% if not only_issues %}
{% for hr in expected %}
{% set ip_key = hr.ip %}
{% set host_row = host_results_by_ip.get(ip_key) %}
{% set header_title = ip_key ~ ((' (' ~ host_row.host ~ ')') if host_row and host_row.host else '') %}
|
{{ header_title }} {{ badge('OK', '#16a34a') }}
|
|
{{ badge('OK', '#16a34a') }} Matches expected ports.
|
{% endfor %}
{% endif %}
Report generated by mass-scan-v2 • {{ generated }}