Back in 2020 I stumbled on Bandwhich, a “Terminal bandwidth utilization tool”, written in Rust.
More recently, I was looking for a tool to identify which processes on a box were using bandwidth, and how much. I remembered Bandwhich and took another look. I wanted an easy way to install Bandwhich on a variety of machines, running a variety of Linux distributions across different architectures.
So I built a snap of bandwhich.
I thought I’d write up what I did in case anyone else wants to build a snap of a rust application.
The upstream bandwidth developers are currently having a bit of a reorg, after the lead developer no longer has the … bandwidth … to maintain the application. If you’re a rust developer, and have some time, perhaps you may be able to contribute.
If you just want to use bandwhich, then install the snap of bandwhich and run
sudo bandwhich, no need to continue reading.
If you’re interested in how the snap was made, read on.
I’m using my home machine running Ubuntu 23.04 to build the snap and test it out. I’ll be using
lxd. Maybe one day I’ll use Incus, but that’s not today.
$ sudo snap install snapcraft --classic $ sudo snap install lxd
This is mostly just ‘press enter repeatedly’ until it’s done. The only deviation from this was saying ’none’ when asked about ipv6 bridging.
$ sudo lxd init
Reboot or logout/in so joining the
lxd group is done. Or run
newgrp lxd if you don’t want to reboot right now.
I got a prompt answer which was basically ‘uninstall docker’. I don’t recall why I had docker installed, and was happy to remove it. Never liked docker :D.
I like to create a new folder to build in, and name the path to be the same as my github username.
$ mkdir ~/Source/popey/bandwhich-snap/snap
snapcraft.yaml is used by the
snapcraft command to build and package the application. By default it lives in that
The initial bones of a
snapcraft.yaml are pretty straightforward:
name: bandwhich # The snap name as seen in the store base: core18 # We build in an Ubuntu 18.04 environment summary: Terminal bandwidth utilization tool description: This is a CLI utility for displaying current network utilization by process, connection and remote IP/hostname grade: stable confinement: strict # Will be strictly confined
There’s only one part required here, for the
bandwhich application itself. I’ve commented it a bit. It’s very simple.
adopt-info: bandwhich # Get version info from the bandwhich part parts: bandwhich: # Only one part needed plugin: rust # snapcraft knows how to build rust applications rust-revision: "1.70.0" # bandwhich needs at least this version of rust source: https://github.com/imsnif/bandwhich.git # Where the upstream source lives build-packages: # Requirements to compile bandwhich - build-essential - cargo override-pull: | # After we pull the source, set the package version snapcraftctl pull snapcraftctl set-version $(git describe --tags --abbrev=0)
This is how snap exposes the binary inside the snap to the world outside, on the host platform, and defines the resources it needs access to. The documentation for this can be found here.
network- enables network access
network-bind- operate as a network service
network-status- access the NetworkingStatus service
network-control- change low-level network settings
The first three are automatically connected by policy, when the snap is installed. However
network-control is not. More on that further down.
apps: bandwhich: # The binary name as it's seen by the host command: bandwhich # The binary name as it's known inside the snap plugs: # Interfaces connected to allow access - network - network-bind - network-control - network-status
This builds the snap on the local machine.
$ snapcraft --use-lxd
This spins up a LXD container, then builds the snap inside it. Here’s the bottom of the output from that command.
⋮ Compiling pnet_transport v0.34.0 Compiling trust-dns-resolver v0.23.0 Finished release [optimized] target(s) in 44.12s Installing /root/parts/bandwhich/install/bin/bandwhich Installed package `bandwhich v0.21.0 (/root/parts/bandwhich/build)` (executable `bandwhich`) info: This is the version for the rustup toolchain manager, not the rustc compiler. info: The currently active `rustc` version is `rustc 1.70.0 (90c541806 2023-05-31)` Staging bandwhich + snapcraftctl stage Priming bandwhich + snapcraftctl prime Snapping | Snapped bandwhich_v0.21.0.067b798_amd64.snap
Test local build
Once the snap builds, we can test it.
--dangerous tag is needed because the origin of the snap is unknown to
$ sudo snap install bandwhich_v0.21.0.067b798_amd64.snap --dangerous bandwhich v0.21.0.067b798 installed
I mentioned that some of the interfaces are auto-connected, but
network-control isn’t. As a result, the application fails to start.
$ sudo bandwhich Error: lo, wlp1s0, lxdbr0, zt44xdmaty: Insufficient permissions to listen on network interface(s). You can work around this issue like this: * Try running `bandwhich` with `sudo` * Build a `setcap(8)` wrapper for `bandwhich` with the following rules: `cap_sys_ptrace,cap_dac_read_search,cap_net_raw,cap_net_admin+ep`
If we connect the interface, it works.
$ sudo snap connect bandwhich:network-control
I created a repo and pushed my yaml to it.
In the snapcraft store build page, I hooked up that repo, then the builds started flowing.
Testing the store builds was simply a matter of running this on my machines.
$ sudo snap install bandwhich --edge
On my developer workstation I switched from the local build to the store one in a similar fashion.
$ sudo snap refresh bandwhich --edge --amend
While it’s possible for users to manually connect that interface, it may be preferable to have it auto-connected, like the other interfaces.
There was a short discussion, and the approval was completed in the store around ten days later.
Once the store team approved the request for autoconnection, I then released the app to the stable channel.
Now you can visit the bandwhich store page or just
snap install bandwhich if you have
There’s currently six users of the Bandwhich snap - probably mostly me! Maybe this blog might change that!