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
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
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
debian/rules, and double-checking the contents of maintainer
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 (
arm64 respectively). Some
explanations were given about part of the
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
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
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.
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
pipcalls 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.
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 (
the challenge even more interesting.
Cyril suggested creating an extra
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
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
that performs a build of each component with the appropriate options, then
make install step that targets a staging area (
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
NFStream build system can be pointed to that staging area, which is
done by adding
-Ivendor/staging/usr/include/nDPI for the
The final touch was asking
dh_python3 not to rename the C extension. By
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:
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
(this was not investigated).
The resulting source package can be built inside a clean
armhf and once for
arm64, and the resulting
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
repository, which aggregates a
few Python packages:
nskeyedunarchiver. Those packages were drafted using
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
repository, it made more sense
to have a separate
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
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
bullseye base distribution. More details can be found in commit
where the tweaked packages were merged into the
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
directory of the PPA:
|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
|python/python3-numpy_1.22.1-1+pirogue1_armhf.deb||Borrowed from Debian
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
directory of the PPA:
|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|
Let’s check what the dependency graph looks like, between all aforementioned
components (leaving aside any packages that are found in the
- in light green, the first two dependency levels are from the
- in light blue, dependency levels three and above are from the
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!