78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
"""Headless CLI for IoT PreTester 4.6 Demo.
|
|
|
|
Exit codes: 0 no high/critical findings, 2 at least one, 1 runtime error.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import logging
|
|
import sys
|
|
|
|
from . import __version__
|
|
from .engine import AnalysisEngine
|
|
from .findings import Severity
|
|
from .reporting import render, FORMATS
|
|
from . import logutil
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
p = argparse.ArgumentParser(
|
|
prog="analyzer",
|
|
description="Analyze the security of a PCAP or PCAPNG network capture.",
|
|
)
|
|
p.add_argument("capture", help="Path to a .pcap or .pcapng file")
|
|
p.add_argument("-f", "--format", choices=FORMATS, default="md",
|
|
help="Output format (default: md)")
|
|
p.add_argument("-o", "--output", default=None,
|
|
help="Output file (default: standard output)")
|
|
p.add_argument("--packet-limit", type=int, default=None,
|
|
help="Maximum packets to read from a large capture")
|
|
p.add_argument("--device-ip", default=None,
|
|
help="IP address of the device under test (focuses and attributes findings)")
|
|
p.add_argument("-v", "--verbose", action="store_true", help="Debug logging on stderr")
|
|
p.add_argument("--log-file", default=None, help="Write the analysis log to this file")
|
|
p.add_argument(
|
|
"--version",
|
|
action="version",
|
|
version=f"IoT PreTester 4.6 Demo analyzer {__version__}",
|
|
)
|
|
return p
|
|
|
|
|
|
def main(argv=None) -> int:
|
|
args = build_parser().parse_args(argv)
|
|
logutil.configure_console("DEBUG" if args.verbose else "WARNING")
|
|
|
|
try:
|
|
with logutil.run_log(args.log_file):
|
|
result = AnalysisEngine().analyze_pcap(args.capture, packet_limit=args.packet_limit,
|
|
device_ip=args.device_ip)
|
|
except FileNotFoundError as exc:
|
|
print(f"Error: {exc}", file=sys.stderr)
|
|
return 1
|
|
except RuntimeError as exc:
|
|
print(f"Error: {exc}", file=sys.stderr)
|
|
return 1
|
|
except Exception as exc:
|
|
logging.getLogger("analyzer.cli").exception("Unexpected failure")
|
|
print(f"Error: {exc!r}", file=sys.stderr)
|
|
return 1
|
|
|
|
report = render(result, args.format)
|
|
|
|
if args.output:
|
|
with open(args.output, "w", encoding="utf-8") as fh:
|
|
fh.write(report)
|
|
print(f"Report written: {args.output} "
|
|
f"({result.meta.get('finding_count', 0)} Findings)", file=sys.stderr)
|
|
else:
|
|
print(report)
|
|
|
|
worst = max((f.severity.rank for f in result.findings), default=0)
|
|
return 2 if worst >= Severity.HIGH.rank else 0
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
raise SystemExit(main())
|