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