diff --git a/.ci_scripts/run-all-pcaps.sh b/.ci_scripts/run-all-pcaps.sh
index 53446e7df36d149299e2343eff067e9091cf4ff3..a8c960e34aebf8183f9e9261f6142ec2f2225e7b 100755
--- a/.ci_scripts/run-all-pcaps.sh
+++ b/.ci_scripts/run-all-pcaps.sh
@@ -5,7 +5,7 @@ EXITCODE=0
 for pcap in $GITHUB_WORKSPACE/traces/*.pcap
 do
     # Run pcap_fuzzer script on pcap file
-    python3 $GITHUB_WORKSPACE/src/pcap_fuzzer.py $pcap
+    python3 $GITHUB_WORKSPACE/pcap_fuzzer/pcap_fuzzer.py $pcap
     # If the exit code is not 0, set EXITCODE to 1
     if [[ $? -ne 0 ]]
     then
diff --git a/.gitignore b/.gitignore
index 292cb60f21bfc37533f9f4752c55418543e6abe2..9a4d2f09843c91df2d445d19733226e228f51e62 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,12 @@
+# Environment config directories
 .vscode
+
+# Python build directories
+__pycache__
+build
+dist
+*.egg-info
+
+# Temp files
 *.log
 csv
diff --git a/pcap_fuzzer/__init__.py b/pcap_fuzzer/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..866076dd814cf0c751c325139276ea1d860e8b27
--- /dev/null
+++ b/pcap_fuzzer/__init__.py
@@ -0,0 +1,6 @@
+"""
+Initialization script for package `pcap_fuzzer`.
+"""
+
+from packet import *
+from pcap_fuzzer import fuzz_pcaps
diff --git a/src/packet/ARP.py b/pcap_fuzzer/packet/ARP.py
similarity index 87%
rename from src/packet/ARP.py
rename to pcap_fuzzer/packet/ARP.py
index e03788717a5d2dd6c7dd38a7b63453f6c471e070..9bef2867ccf8e2a0b3ca570771254cbd2c50ad4a 100644
--- a/src/packet/ARP.py
+++ b/pcap_fuzzer/packet/ARP.py
@@ -1,4 +1,4 @@
-from packet.Packet import Packet
+from Packet import Packet
 
 class ARP(Packet):
 
diff --git a/src/packet/BOOTP.py b/pcap_fuzzer/packet/BOOTP.py
similarity index 99%
rename from src/packet/BOOTP.py
rename to pcap_fuzzer/packet/BOOTP.py
index a88730e0ad10af1aab596596e7ed7f037e5c0fc9..2d26baf6196611f1872c99e394935b4d8fad6a82 100644
--- a/src/packet/BOOTP.py
+++ b/pcap_fuzzer/packet/BOOTP.py
@@ -1,7 +1,7 @@
 from typing import Tuple
 import random
 import scapy.all as scapy
-from packet.Packet import Packet
+from Packet import Packet
 
 class BOOTP(Packet):
     """
diff --git a/src/packet/CoAP.py b/pcap_fuzzer/packet/CoAP.py
similarity index 99%
rename from src/packet/CoAP.py
rename to pcap_fuzzer/packet/CoAP.py
index b274a7d48fb49258196136368ea08ba1771ea5a3..67c45e07e5f0543cfc4fd8ae441fd3b68f4ce76c 100644
--- a/src/packet/CoAP.py
+++ b/pcap_fuzzer/packet/CoAP.py
@@ -1,5 +1,5 @@
 import random
-from packet.Packet import Packet
+from Packet import Packet
 
 class CoAP(Packet):
 
diff --git a/src/packet/DNS.py b/pcap_fuzzer/packet/DNS.py
similarity index 99%
rename from src/packet/DNS.py
rename to pcap_fuzzer/packet/DNS.py
index 213974041e92362f055edfa9beaf47d11459e8f9..abec9f102f3c188ec5057484d81b675c1d43a30a 100644
--- a/src/packet/DNS.py
+++ b/pcap_fuzzer/packet/DNS.py
@@ -1,6 +1,6 @@
 import random
 from scapy.layers import dns
-from packet.Packet import Packet
+from Packet import Packet
 
 class DNS(Packet):
 
diff --git a/src/packet/HTTP_Request.py b/pcap_fuzzer/packet/HTTP_Request.py
similarity index 91%
rename from src/packet/HTTP_Request.py
rename to pcap_fuzzer/packet/HTTP_Request.py
index 6d5665f9e556d5dcd9d9fb11aefd0192d1d4c583..cb63ffd14828270f287c2328660f3e0fe1a6ac24 100644
--- a/src/packet/HTTP_Request.py
+++ b/pcap_fuzzer/packet/HTTP_Request.py
@@ -1,4 +1,4 @@
-from packet.Packet import Packet
+from Packet import Packet
 
 class HTTP_Request(Packet):
 
diff --git a/src/packet/ICMP.py b/pcap_fuzzer/packet/ICMP.py
similarity index 91%
rename from src/packet/ICMP.py
rename to pcap_fuzzer/packet/ICMP.py
index 8d4879f431ef839c788710215e77d4d6dfedd877..0554a20f22fd85faec789d39a9419ce236374c04 100644
--- a/src/packet/ICMP.py
+++ b/pcap_fuzzer/packet/ICMP.py
@@ -1,4 +1,4 @@
-from packet.Packet import Packet
+from Packet import Packet
 
 class ICMP(Packet):
 
diff --git a/src/packet/IGMP.py b/pcap_fuzzer/packet/IGMP.py
similarity index 91%
rename from src/packet/IGMP.py
rename to pcap_fuzzer/packet/IGMP.py
index 0afe978b15aec089f83c07d324a148f7fff6d57a..1d203e0cb18bde75016c45dc74f7bb35c62ae3f2 100644
--- a/src/packet/IGMP.py
+++ b/pcap_fuzzer/packet/IGMP.py
@@ -1,4 +1,4 @@
-from packet.Packet import Packet
+from Packet import Packet
 
 class IGMP(Packet):
     """
diff --git a/src/packet/IGMPv3mr.py b/pcap_fuzzer/packet/IGMPv3mr.py
similarity index 97%
rename from src/packet/IGMPv3mr.py
rename to pcap_fuzzer/packet/IGMPv3mr.py
index 482a6654bb961963a0dec28e49ce06a9be8f34dc..1a38c83d5f6bfd726608b8209381b874a558165b 100644
--- a/src/packet/IGMPv3mr.py
+++ b/pcap_fuzzer/packet/IGMPv3mr.py
@@ -1,4 +1,4 @@
-from packet.Packet import Packet
+from Packet import Packet
 
 class IGMPv3mr(Packet):
     """
diff --git a/src/packet/IPv4.py b/pcap_fuzzer/packet/IPv4.py
similarity index 82%
rename from src/packet/IPv4.py
rename to pcap_fuzzer/packet/IPv4.py
index 06363358d8910b145ceadd43db67af3a528b4c9f..7bddcfa770b74d120559fe1b47f988e1777a5d44 100644
--- a/src/packet/IPv4.py
+++ b/pcap_fuzzer/packet/IPv4.py
@@ -1,4 +1,4 @@
-from packet.Packet import Packet
+from Packet import Packet
 
 class IPv4(Packet):
 
diff --git a/src/packet/IPv6.py b/pcap_fuzzer/packet/IPv6.py
similarity index 82%
rename from src/packet/IPv6.py
rename to pcap_fuzzer/packet/IPv6.py
index 0d8703a0a9c7580793f6fe64ed0ab368db3e0cc0..00eda71f56604a84671d0e92c58b5fb87efc2430 100644
--- a/src/packet/IPv6.py
+++ b/pcap_fuzzer/packet/IPv6.py
@@ -1,4 +1,4 @@
-from packet.Packet import Packet
+from Packet import Packet
 
 class IPv6(Packet):
 
diff --git a/src/packet/Packet.py b/pcap_fuzzer/packet/Packet.py
similarity index 100%
rename from src/packet/Packet.py
rename to pcap_fuzzer/packet/Packet.py
diff --git a/src/packet/TCP.py b/pcap_fuzzer/packet/TCP.py
similarity index 84%
rename from src/packet/TCP.py
rename to pcap_fuzzer/packet/TCP.py
index 0a19fedd2adca47287364956ee506013584e8ede..325b4dfe4413c0d0e6c3bd524fc09ad6ef4da70a 100644
--- a/src/packet/TCP.py
+++ b/pcap_fuzzer/packet/TCP.py
@@ -1,4 +1,4 @@
-from packet.Transport import Transport
+from Transport import Transport
 
 class TCP(Transport):
 
diff --git a/src/packet/Transport.py b/pcap_fuzzer/packet/Transport.py
similarity index 98%
rename from src/packet/Transport.py
rename to pcap_fuzzer/packet/Transport.py
index d6e147376a6a018156fd5c90cf1da081a17c6d8d..a0e203d5845c487412e6d8fc481e351b6196e85a 100644
--- a/src/packet/Transport.py
+++ b/pcap_fuzzer/packet/Transport.py
@@ -1,5 +1,5 @@
 import random
-from packet.Packet import Packet
+from Packet import Packet
 
 class Transport(Packet):
     """
diff --git a/src/packet/UDP.py b/pcap_fuzzer/packet/UDP.py
similarity index 90%
rename from src/packet/UDP.py
rename to pcap_fuzzer/packet/UDP.py
index c2e586b34812c2fbb1bb58618ecb66e3835016f1..b0a324e7277c299937ba0f6b42e001aa11ef7386 100644
--- a/src/packet/UDP.py
+++ b/pcap_fuzzer/packet/UDP.py
@@ -1,4 +1,4 @@
-from packet.Transport import Transport
+from Transport import Transport
 
 class UDP(Transport):
 
diff --git a/pcap_fuzzer/packet/__init__.py b/pcap_fuzzer/packet/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4db1f6eb50b33d8f61c9c1c74695415384e1513b
--- /dev/null
+++ b/pcap_fuzzer/packet/__init__.py
@@ -0,0 +1,3 @@
+"""
+Initialization script for subpackage `packet`.
+"""
diff --git a/src/packet/mDNS.py b/pcap_fuzzer/packet/mDNS.py
similarity index 97%
rename from src/packet/mDNS.py
rename to pcap_fuzzer/packet/mDNS.py
index 55abe5159f2c67fe1440544a7d81239f8eece34b..60e32b1a1cac4537f1930bc9ab8288ba6490b9da 100644
--- a/src/packet/mDNS.py
+++ b/pcap_fuzzer/packet/mDNS.py
@@ -1,6 +1,6 @@
 import random
 import scapy.all as scapy
-from packet.DNS import DNS
+from DNS import DNS
 
 class mDNS(DNS):
 
diff --git a/src/pcap_fuzzer.py b/pcap_fuzzer/pcap_fuzzer.py
similarity index 100%
rename from src/pcap_fuzzer.py
rename to pcap_fuzzer/pcap_fuzzer.py
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bce13a8a1409e055bfb81c2e13b82ccc2b9a44a
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,24 @@
+from setuptools import setup, find_packages
+
+setup(
+    name='pcap_fuzzer',
+    version='0.1.0',
+    author='François De Keersmaeker',
+    author_email='francois.dekeersmaeker@uclouvain.be',
+    description='Randomly edit packet fields in a PCAP file.',
+    long_description=open('README.md').read(),
+    long_description_content_type='text/markdown',
+    url='https://github.com/smart-home-network-security/pcap-fuzzer',
+    license='GPLv3+',
+    packages=find_packages(),
+    classifiers=[
+        'Programming Language :: Python :: 3',
+        'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+        'Operating System :: OS Independent',
+    ],
+    python_requires='>=3.7',
+    install_requires=[
+        'scapy',
+    ],
+    #test_suite='tests',
+)
diff --git a/src/.gitignore b/src/.gitignore
deleted file mode 100644
index bee8a64b79a99590d5303307144172cfe824fbf7..0000000000000000000000000000000000000000
--- a/src/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-__pycache__
diff --git a/traces/.gitignore b/traces/.gitignore
index 2057419cdcbaeef061113f494c884b2f28e803ed..d69b96843318f69b39f06e91817ddea9605fe3d6 100644
--- a/traces/.gitignore
+++ b/traces/.gitignore
@@ -1,2 +1,3 @@
+# Edited PCAP files
 edited
-*.edit.pcap
\ No newline at end of file
+*.edit.pcap