Porting cjdns to the Ubiquiti EdgeRouter

cjdns is experimental software that aims to produce an end-to-end encrypted IPv6 network that guarantees security and privacy. A routing algorithm loosely based on Kademlia is used to establish routes to other nodes in the network. Having recently come to own an Ubiquiti EdgeRouter X, I started to wonder how easy it might be to port cjdns to the ER-X.

The operating system on the ER-X, known as EdgeOS, is actually a fork of the Vyatta virtual router system, which itself is Debian Linux-derived. The system is built around a dual-core MIPS processor with 256MB DDR3 RAM and a further 256MB of NAND flash storage. There are five Ethernet ports, including one supporting Power-over-Ethernet (PoE), all of which can be joined to a hardware-driven switch. Certainly more than capable of stepping up to the job.

The first step of the process was to build an environment which can be used to cross-compile the cjdns binary itself to the MIPS architecture of the ER-X. As it turned out, a Debian Jessie environment proved suitable for this, using the crossbuild toolchains. The build system packaged with cjdns itself already includes some cross-compilation support, so a few easy steps later, I wrote a Makefile that would build cjdns using the MIPS toolchain. Fairly easy sailing so far.

(As I later found out, building for the EdgeRouter X was significantly easier than building for the EdgeRouter Lite, due to the fact that the ER-L uses a 64-bit MIPS architecture instead of the 32-bit one used by the ER-X. The Debian embedded crossbuild toolchains don't seem to have any support for the 64-bit MIPS architecture, so in the end a contributor on GitHub dug out an altogether different toolchain from Codescape.)

However, building the cjdns executable itself was only a minor part of the battle. Vyatta-based systems, EdgeOS included, have a command-line configuration interface (known as vyatta-cfg) which allows the configuration of the router and its various components. The cjdns package had to fit into this in order to be user-friendly, otherwise the user of the software would need to manually edit the cjdns configuration files - not ideal). 

The vyatta-cfg system actually draws all of its supported configuration commands from a folder structure stored on the system itself, in which every configuration node is defined with a number of options including the types of values that should be accepted, and what to do with those values once they were added to, updated in or removed from the system configuration. Not knowing really where to start with this, I figured it would be easiest to start with an existing Vyatta package and to modify the contents. I later discovered that actually, vyatta-cfg is actually fairly-well documented

Having defined the options that should be available to configure cjdns was still not enough. After all, the vyatta-cfg system still didn't know how to generate a configuration that would be suitable for cjdns to parse. (For the record, the cjdns configuration file is a JSON file which made it somewhat easier to manipulate.)

The final part of the puzzle was to write a script that could take a variety of inputs from the vyatta-cfg system and to use it to modify the cjdns configuration file by itself, adding, changing or removing values based on the input to the Vyatta command line. I chose to write this script in Python largely for two reasons: one was because I wanted to reinforce my Python skills a little, and the other because it seems to be already fairly widely in use within Vyatta/EdgeOS. It seemed like a logical choice.

Finally, all of this was pulled together into a Debian package and the net result is a package that can be deployed to the EdgeRouter in order to provide cjdns functionality. At present the necessary functionality to set up cjdns peerings is present, both over UDP and using Ethernet beacons, and configuring the firewall is also there. There are still some features missing, such as configuring IP Tunnel and specifying Ethernet peers by MAC address, however I plan to add these soon. There is also a fairly decided lack of input validation at present, so entering bad values will probably just result in cjdns failing to start.

I have been running this package on my ER-X for nearly a month now with very few problems. Sometimes the cjdns executable crashes (after all, cjdns is still alpha software), but I have found that the easiest way to get around this in the interim is just to configure a scheduled task within the CLI that checks every minute if the application is still running, and starts it if not. Not entirely ideal, but I haven't yet had the time to write the necessary boilerplate code to "supervise" the process correctly. 

I have open-sourced this project and it is hosted on GitHub, along with documentation how to build it using a Debian Jessie system and how to configure it once installed on the EdgeRouter: