PiRogue Tool Suite
Here’s how the project is presented on its website:
PiRogue tool suite (PTS) is an open-source tool suite that provides a comprehensive mobile forensic and network traffic analysis platform targeting mobile devices both Android and iOS, internet of things devices (devices that are connected to the user mobile apps), and in general any device using Wi-Fi to connect to the Internet.
The concept is to provide a tool suite that leverages a Raspberry Pi based device, the PiRogue, to conduct a number of analyses.
The PiRogue operates as a network router, analyzing network traffic in real time. It can operate in different modes, detailed under “What a PiRogue is”:
- a kiosk mode for anyone who wants to know which servers a mobile device is communicating with;
- an on-the-field mode;
- an expert mode.
The PiRogue itself consists of:
- a regular Pi 3 or Pi 4;
- a HAT;
- a case.
The conception follows an open hardware approach, with KiCad files available in the pirogue-hat repository. The HAT makes it possible to get information on a small LCD screen, to control a fan, and to get an RTC (to keep track of time when the PiRogue is shut down). For discovery and development purposes, it’s very fine to use just a Pi 3 or Pi 4, without the HAT and the case.
Debamax’s initial involvement
PiRogue tool suite is mainly developed and maintained by Defensive Lab Agency in the person of Esther Onfroy. Some development sessions are streamed live, and Esther got in touch to see if it would be possible to talk about Debian packaging, looking at some practical use cases. This seemed very interesting, and a very nice way to learn more about this project, so Cyril jumped right in.
The entry point for this improvised workshop was the deb-packages
repository, which contains the source of a few Debian packages. The resulting binary packages are published in a Debian repository (or PPA).
The PiRogue OS is built using a fork of the official toolchain to create Raspberry Pi OS images, published in the pirogue-os
repository. The modifications are basically about configuring the package manager so that it knows about the additional repository, and about installing the pirogue-base
metapackage that pulls all required pirogue-*
packages and their dependencies.
The idea is to keep build time modifications as minimal as possible, which means that users don’t need to download and deploy PiRogue OS images: it should be possible to start from a Raspberry OS image (possibly even from a Debian image) that’s already deployed, then configure the package manager and install a few packages, to get an equivalent PiRogue OS image.
During the live session, we looked at the set of packages prepared by Esther, mostly reviewing metadata in the debian/control
files, checking build instructions in debian/rules
, and double-checking the contents of maintainer scripts (e.g. preinst
and postinst
).
Some packages were moved from Architecture: any
(meaning they have to be built for each target architecture) to Architecture: all
(meaning the exact same package can be used across all target architectures). Using Python for most things allows for such an optimization, which helps support building 32-bit and 64-bit images down the line (armhf
and arm64
respectively). Some explanations were given about part of the debhelper
suite, e.g. dh_installsystemd
which deals with systemd units, and about overrides in debian/rules
: those tools should have a sane default behavior, but sometimes developers might need to add some tweaks.
We also alluded to tools facilitating clean builds, like pbuilder
, cowbuilder
, and sbuild
. Those are particularly helpful to check that the expressed build dependencies are correct, and to shield the build process from possible system configuration tweaks that might only be present on a given developer’s system. This helps getting reproducible results when packages are built on different systems, and it’s been considered best practice in the Debian ecosystem for many years anyway.
All packages were in a very decent shape already, and this work session ended up being an opportunity to give an overview of packaging concepts with an hands-on approach.
Follow-up work
This live session really piqued Cyril’s interest, as two main improvements had been identified:
- by Esther from the get-go: NFStream;
- by Cyril: the
pip
calls in maintainer scripts.
Helping with a project that aims at defending people’s rights seemed very appealing, and was a nice return to some form of hacktivism, so Debamax dedicated some days to doing all the heavy lifting for some non-trivial packages, alongside answering any questions Esther might have about existing or forthcoming packages, and participating in general brainstorming.
Packaging NFStream
As explained in the previous section, the PiRogue OS concept is:
- publish a few packages published in a PPA;
- either add this PPA during a PiRogue OS image build, or add it to an already-deployed Raspberry OS or Debian system;
- install all
pirogue-*
packages and their dependencies.
That wasn’t possible initially, as NFStream (a flexible network data analysis framework) was being built during the image build, and deployed under /usr/local
… which invalidated the “you can deploy PiRogue on top of your system” use case. That also meant that further upgrades would be harder: those files weren’t tracked by the package manager, and we would need to think about some custom system to support upgrades.
Additionally, NFStream requires specific tags or development branches for a few of its build dependencies (libgpg-error
, libgcrypt
, libpcap
, and nDPI
), making the challenge even more interesting.
Cyril suggested creating an extra deb-nfstream
repository, where all the required components would be aggregated. A bullseye
branch was forked from the 6.3.5 upstream tag, and the aforementioned components were declared as Git submodules under the vendor/
directory.
Working inside a development chroot
environment, it became clear that each build resulted in the deployment of development files (C headers and static libraries), and that the NFStream built was using those static libraries to generate a C extension (shared library) that can be used by the Python interpreter. After that, those development files weren’t needed, so it seemed feasible to ship NFStream’s Python files and its C extension, leaving all intermediary files behind.
That’s how we ended up with a debian/rules
file that performs a build of each component with the appropriate options, then performs a make install
step that targets a staging area (vendor/staging
), via the usual DESTDIR
variable. This means we stash everything inside a designated area of the build directory, without risking polluting system paths (even if permission issues would stop us, as building is usually done as a non-privileged user). Then, the NFStream
build system can be pointed to that staging area, which is done by adding -Ivendor/staging/usr/include
and -Ivendor/staging/usr/include/nDPI
for the gcc
call.
The final touch was asking dh_python3
not to rename the C extension. By default, engine_cc.so
would be renamed to embed information about the interpreter (CPython version 3.9 on bullseye
, our base distribution) and about the architecture (the usual arch triplet) in its filename:
engine_cc.cpython-39-x86_64-linux-gnu.so
foramd64
;engine_cc.cpython-39-aarch64-linux-gnu.so
forarm64
;engine_cc.cpython-39-arm-linux-gnueabihf.so
forarmhf
.
This renaming is probably meant to support co-installability of packages from various architectures on the same system. That’s not something that would make sense for PiRogue OS, that’s why it was decided to skip the renaming altogether. Other possibilities included shipping an engine_cc.so
symlink pointing at the right filename (this was tested successfully), or adjusting the ffi.dlopen()
call (this was not investigated).
The resulting source package can be built inside a clean cowbuilder
chroot, once for armhf
and once for arm64
, and the resulting python3-nfstream
binary packages are published in the pirogue-3rd-party
section of the PPA.
Packaging more Python components
The next topic that could be vastly improved was the manual installation of several Python packages, via pip install
calls in maintainer scripts. It seemed a little hazardous to rely on the contents of the Python Package index, even more so when no versions were being specified: the set of packages installed from PyPI could change at any time.
Having proper Debian packages for all dependencies would streamline both the build process and further upgrade scenarios, meaning we would only have to care about the contents of our PPA. And incidentally, while Cyril was working on creating those packages, the PiRogue image build process starting to break during release candidate preparations! That reinforced the initial “we should try and provide proper packages for every component” feeling.
This explains how we ended up with a new deb-python
repository, which aggregates a few Python packages: adb-shell
, communityid
, geoip2
, iosbackup
, maxminddb
, mvt
, and nskeyedunarchiver
. Those packages were drafted using the py2dsp
command (found in the pypi2deb
package). This “Python source package to Debian source package converter” made it easy to prepare the debian/
directory for each module, even if it’s still based on some old debhelper
compatibility level (10 instead of 13).
A Python package required some extra care: Frida. It’s a particularly important one in the PiRogue Tool Suite ecosystem, and the upstream repository is a little trickier as it relies on several Git submodules. Instead of incorporating a specific tarball in the common deb-python
repository, it made more sense to have a separate deb-frida
repository, forked from the upstream Frida repository, with a debian/bullseye
packaging branch. Contrary to all other packages in the PiRogue Tool Suite project, which follow best practices regarding Debian packaging, that one requires specific settings when getting built in a clean environment (like cowbuilder
): it requires network access since the appropriate embedded toolchain gets downloaded during the build process.
To work around an (unfortunately undocumented) issue with the NumPy package, a dependency on a higher version was declared in the pip install
call. The specified version being only available in Debian experimental
, it was decided to fetch the packages from there, and repack them a little. It’s indeed built for several versions of the Python interpreter, while all we care about is 3.9 for our bullseye
base distribution. More details can be found in commit a1ee864c99, where the tweaked packages were merged into the PPA.
Piecing everything together
Third party components
In the interest of having as much control as possible over the set of packages being deployed on the PiRogue, and for simplicity’s sake as well, Cyril suggested merging the remaining third party packages into the PPA. This means not having to maintain extra configuration for Grafana, InfluxDB, etc.
That’s how we ended up with the following packages in the pirogue-3rd-party
directory of the PPA:
Filename | Origin |
---|---|
chronograf_1.9.1-1_arm64.deb | Merged from https://repos.influxdata.com/ |
chronograf_1.9.1-1_armhf.deb | Merged from https://repos.influxdata.com/ |
frida_15.1.17~pirogue1_arm64.deb | Built from deb-frida |
frida_15.1.17~pirogue1_armhf.deb | Built from deb-frida |
grafana_8.1.5_arm64.deb | Merged from https://grafana.com/grafana/download |
grafana_8.1.5_armhf.deb | Merged from https://grafana.com/grafana/download |
influxdb_1.8.10-1_arm64.deb | Merged from https://repos.influxdata.com/ |
influxdb_1.8.10-1_armhf.deb | Merged from https://repos.influxdata.com/ |
python3-nfstream_6.3.5~ds2_arm64.deb | Built from deb-nfstream |
python3-nfstream_6.3.5~ds2_armhf.deb | Built from deb-nfstream |
python/python3-adb-shell_0.4.2-1~pirogue1_all.deb | Built from deb-python |
python/python3-communityid_1.4-1~pirogue1_all.deb | Built from deb-python |
python/python3-geoip2_4.5.0-1~pirogue1_all.deb | Built from deb-python |
python/python3-iosbackup_0.9.923-1~pirogue1_all.deb | Built from deb-python |
python/python3-maxminddb_2.2.0-1~pirogue1_arm64.deb | Built from deb-python |
python/python3-maxminddb_2.2.0-1~pirogue1_armhf.deb | Built from deb-python |
python/python3-mvt_1.5.4-1~pirogue1_all.deb | Built from deb-python |
python/python3-nskeyedunarchiver_1.5-1~pirogue1_all.deb | Built from deb-python |
python/python3-numpy_1.22.1-1+pirogue1_arm64.deb | Borrowed from Debian experimental |
python/python3-numpy_1.22.1-1+pirogue1_armhf.deb | Borrowed from Debian experimental |
PiRogue components
While Cyril mainly worked on trying to get a reasonable set of extra packages to complement what’s found in the Debian distribution, let’s look at the set of packages proposed by PiRogue Tool Suite developers, published in the pirogue
directory of the PPA:
Filename | Purpose |
---|---|
pirogue-ap_1.0.0_all.deb | Configures Wi-Fi Access Point |
pirogue-base_1.0.1_all.deb | Depends on all other packages (metapackage) |
pirogue-cli_1.0.0-beta_all.deb | Provisions Command Line Interface tools |
pirogue-dashboard_1.0.1_all.deb | Provisions PiRogue dashboards |
pirogue-eve-collector_1.0.3_all.deb | Provisions the Suricata alarm collector |
pirogue-flow-inspector_1.0.2_all.deb | Provisions Deep Packet Inspection |
pirogue-hat_1.0.1_all.deb | Manages hardware configuration for the HAT |
pirogue-maintenance_1.0.1_all.deb | Updates Suricata rules |
pirogue-screen-st7789-240x240_1.0.2_arm64.deb | Drives the LCD on the HAT |
pirogue-screen-st7789-240x240_1.0.2_armhf.deb | Drives the LCD on the HAT |
pirogue-tools_1.0.2_all.deb | Installs additional tools like Frida or MVT |
Most of them can be found in the deb-packages
repository, while pirogue-cli
lives in its own repository.
PPA overview
Let’s check what the dependency graph looks like, between all aforementioned components (leaving aside any packages that are found in the bullseye
base distribution):
- in light green, the first two dependency levels are from the
pirogue
directory; - in light blue, dependency levels three and above are from the
pirogue-3rd-party
directory.
Conclusion
What started as an impromptu “let’s talk about Debian packaging for a few hours” live session turned into a strong (even if informal) commitment to helping PiRogue Tool Suite developers. Defending people’s rights is not a new topic for Debamax, which worked on Tails previously, and which provides some financial support to Exodus Privacy. It’s a pleasure to share some technical expertise with such an important project, and to have helped reach the 1.0.0 milestone!