PiRogue Tool Suite logo

Helping with PiRogue Tool Suite

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 for amd64;
  • engine_cc.cpython-39-aarch64-linux-gnu.so for arm64;
  • engine_cc.cpython-39-arm-linux-gnueabihf.so for armhf.

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!