From 244809e128c183aaadf4b6295bcf054757b41f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20De=20Keersmaeker?= <francois.dekeersmaeker@uclouvain.be> Date: Thu, 19 Dec 2024 15:44:55 +0100 Subject: [PATCH] Unit tests for entire package --- pcap_anonymize/__init__.py | 2 +- pcap_anonymize/__main__.py | 11 +++-- pcap_anonymize/pcap_anonymize.py | 26 ++++++++++- test/test_traces.py | 73 +++++++++++++++++++++++++++++++ test/traces/.gitignore | 2 + test/traces/dhcp.pcap | Bin 0 -> 3172 bytes test/traces/http.pcap | Bin 0 -> 8247 bytes test/traces/tplink.pcap | Bin 0 -> 106 bytes 8 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 test/test_traces.py create mode 100644 test/traces/.gitignore create mode 100644 test/traces/dhcp.pcap create mode 100644 test/traces/http.pcap create mode 100644 test/traces/tplink.pcap diff --git a/pcap_anonymize/__init__.py b/pcap_anonymize/__init__.py index 31f5153..e070d14 100644 --- a/pcap_anonymize/__init__.py +++ b/pcap_anonymize/__init__.py @@ -1 +1 @@ -from .pcap_anonymize import anonymize_pcap +from .pcap_anonymize import anonymize_pcap, anonymize_pcaps_in_dir diff --git a/pcap_anonymize/__main__.py b/pcap_anonymize/__main__.py index 9b740f6..3c49610 100644 --- a/pcap_anonymize/__main__.py +++ b/pcap_anonymize/__main__.py @@ -1,16 +1,19 @@ -import os import argparse -from .pcap_anonymize import anonymize_pcap +from .pcap_anonymize import anonymize_pcap, anonymize_pcaps_in_dir ### MAIN FUNCTION ### def main() -> None: parser = argparse.ArgumentParser(description="Anonymize a PCAP traffic capture.") - parser.add_argument("input", type=str, help="Path to the input PCAP file.") + parser.add_argument("-i", "--input", type=str, help="Path to the input PCAP file.") parser.add_argument("-o", "--output", type=str, help="Path to the output PCAP file.") + parser.add_argument("-d", "--dir", type=str, help="Path to the directory containing the input PCAP files.") args = parser.parse_args() - anonymize_pcap(args.input, args.output) + if args.dir: + anonymize_pcaps_in_dir(args.dir) + else: + anonymize_pcap(args.input, args.output) ### ENTRY POINT ### diff --git a/pcap_anonymize/pcap_anonymize.py b/pcap_anonymize/pcap_anonymize.py index 81c78cc..571fdf4 100644 --- a/pcap_anonymize/pcap_anonymize.py +++ b/pcap_anonymize/pcap_anonymize.py @@ -3,6 +3,7 @@ Anonymize all packets in a PCAP file. """ import os +import glob from pathlib import Path from scapy.all import Packet, sniff, wrpcap # Packet layers @@ -69,13 +70,34 @@ def anonymize_pcap(input: os.PathLike, output: os.PathLike = None) -> None: Args: input: path to the input PCAP file output: path to the output PCAP file. - If None, create a new file having the same name as the input file with the suffix '.anonymized.pcap'. + If None, create a new file having the same name as the input file with the suffix '.anon.pcap'. """ + global packets + if output is None: - output = str(Path(input).with_suffix('.anonymized.pcap')) + output = str(Path(input).with_suffix(".anon.pcap")) # Read and anonymize packets from the input file sniff(offline=input, prn=anonymize_packet, store=False) # Write anonymized packets to the output file wrpcap(output, packets) + + # Reset global packets list + packets = [] + + +def anonymize_pcaps_in_dir(dir: os.PathLike) -> None: + """ + Anonymize all PCAP files in a directory. + + Args: + dir: path to the directory containing the PCAP files + """ + for pcap_file in glob.glob(os.path.join(dir, "*.pcap")): + + # Skip traces already anonymized + if pcap_file.endswith(".anon.pcap"): + continue + + anonymize_pcap(pcap_file, None) diff --git a/test/test_traces.py b/test/test_traces.py new file mode 100644 index 0000000..0af8929 --- /dev/null +++ b/test/test_traces.py @@ -0,0 +1,73 @@ +""" +Test the package with PCAP traces. +""" + +import os +import glob +from pathlib import Path +from pcap_anonymize import anonymize_pcap, anonymize_pcaps_in_dir + + +### TEST CONSTANTS ### + +dir_self = os.path.dirname(os.path.abspath(__file__)) +dir_traces = os.path.join(dir_self, "traces") + + +### TEST FUNCTIONS ### + +def test_anonymize_pcap_http(tmp_path: Path) -> None: + """ + Test the package with a PCAP trace containing HTTP packets. + + Args: + tmp_path (pathlib.Path): temporary directory to store the output traces + """ + input = os.path.join(dir_traces, "http.pcap") + output = os.path.join(tmp_path, "http.anon.pcap") + anonymize_pcap(input, output) + assert os.path.exists(input) + assert os.path.exists(output) + + +def test_anonymize_pcap_dhcp(tmp_path: Path) -> None: + """ + Test the package with a PCAP trace containing DHCP packets. + + Args: + tmp_path (pathlib.Path): temporary directory to store the output traces + """ + input = os.path.join(dir_traces, "dhcp.pcap") + output = os.path.join(tmp_path, "dhcp.anon.pcap") + anonymize_pcap(input, output) + assert os.path.exists(input) + assert os.path.exists(output) + + +def test_anonymize_pcap_tplink(tmp_path: Path) -> None: + """ + Test the package with a PCAP trace containing + TP-Link Smart Home protocol packets. + + Args: + tmp_path (pathlib.Path): temporary directory to store the output traces + """ + input = os.path.join(dir_traces, "tplink.pcap") + output = os.path.join(tmp_path, "tplink.anon.pcap") + anonymize_pcap(input, output) + assert os.path.exists(input) + assert os.path.exists(output) + + +def test_anonymize_pcaps_in_dir() -> None: + """ + Test the package with a directory containing PCAP traces. + """ + input_traces = glob.glob(os.path.join(dir_traces, "*.pcap")) + anonymize_pcaps_in_dir(dir_traces) + output_traces = glob.glob(os.path.join(dir_traces, "*.anon.pcap")) + assert len(output_traces) == len(input_traces) + + # Clean up + for output_trace in output_traces: + os.remove(output_trace) diff --git a/test/traces/.gitignore b/test/traces/.gitignore new file mode 100644 index 0000000..cac23be --- /dev/null +++ b/test/traces/.gitignore @@ -0,0 +1,2 @@ +# Anonymized PCAP files +*.anon.pcap diff --git a/test/traces/dhcp.pcap b/test/traces/dhcp.pcap new file mode 100644 index 0000000000000000000000000000000000000000..4ed3d9b4d63dd4dd23a473d19b3f1719f9b195b4 GIT binary patch literal 3172 zcmca|c+)~A1{MYw`2U}Qff2}&(n(1_EX%^+$HV}}|G^;O`2Md8nmHI;8JHY^iWnRO zE7pN%kR*c(gENy(gD@i_8-qLVgHDh*I)La$7ah9%<fh<cQ$|Kxc1DQLcvwAx4Gj%! z_)AkVk_!|J^epu(bqk78&Dj{4*?9P6fPp&-fFS@%UAq-WQy2ckFq*pXhYv1UQ0lT$ zWnqW{7Gxj{$(skl)GhjZfMwSKMjuu_P}%kV*MSv`j6mGZ;LPB{Xi-(pgjRNe<Undb zHVx0Ri^+@y<UwO#4Y1;X6_5-`um+NoS1_`G%5)i!?0;sk8a6P=&zzH(2QBCRgF<@0 z2I={DlHtg!C721;5=Ni^Ziht3XpI4>CCqh3Qx~ps4k8YzB}P*h{!qe{1(jVs`gm&z ZesC@E6I4KgawepfC?A2f1S>_g1OPC^1q%QG literal 0 HcmV?d00001 diff --git a/test/traces/http.pcap b/test/traces/http.pcap new file mode 100644 index 0000000000000000000000000000000000000000..98a6d762add2eb51490554e5f63185ef9b471df0 GIT binary patch literal 8247 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 VL|iv8jIVb&HJ_<hD<^G-`yXvVTpa)a literal 0 HcmV?d00001 diff --git a/test/traces/tplink.pcap b/test/traces/tplink.pcap new file mode 100644 index 0000000000000000000000000000000000000000..aeed1c0e7971a4c2a639a1e4d98d06694c712b2e GIT binary patch literal 106 zcmca|c+)~A1{MYw`2U}Qff2}&(n(3LKE}-81Z0D7!14WG7c|#wuHN_1jDx|Ifx$%U yxdVd(Tle$>D;V>DxP9(Cb^fk^8GH|yb{98DFs$+24m638gNr%s+-r{JQb7P{7a=<U literal 0 HcmV?d00001 -- GitLab