Why we built it
Consumer routers are the least trustworthy computer most people own. They run a
vendor’s fork of an old kernel, a tangle of shell scripts around dnsmasq, and a
web interface that stops receiving security updates about eighteen months after
you buy it. When one misbehaves, there is usually no way to find out why.
corerouter is the opposite proposition: a router where every routing function is our own code, the whole stack is small enough to reason about, and a bad change undoes itself.
What it does
Flash an SD card, plug the board into your modem, and you have a working router — addressing, name resolution, a NATed route to the internet, a firewall, wired and wireless clients on one network, and a dashboard showing what is actually happening.
Underneath, it is deliberately unlike its competitors:
- Our own implementations, not wrappers. Address assignment, the caching resolver, the firewall, multi-WAN failover with automatic failback, and traffic shaping are all first-party code. That means one language, one set of conventions, and no surprises hiding in glue between five projects that were never designed to work together.
- Small enough to audit. Seven static binaries, no container runtime on the device, nothing compiled on the device, and roughly fifteen megabytes of memory for the entire stack. A footprint this size is one a single engineer can hold in their head.
- A config plane that cannot lock you out. Every setting is typed, so a configuration value cannot inject into a firewall ruleset. Applying a change validates it against every service, commits atomically, waits for the system to settle, and rolls back if it does not. A change can also be made self-reverting: confirm within the window or the router puts itself back the way it was. Anyone who has locked themselves out of a remote device knows exactly what that is worth.
What this demonstrates
corerouter is the clearest single artefact of what this practice does: it spans firmware and board bring-up, kernel-adjacent networking, systems programming in a memory-safe language, and the build and release engineering to turn all of it into an image you can flash. Those are usually four different teams. Here they are one codebase.
The build itself is part of the point — it cross-compiles and assembles a bootable image without ever executing target code, so it runs on an ordinary development machine with no emulator, and the test suites run against a real kernel in isolated network namespaces rather than against mocks.
Where it actually stands
The image has been assembled and verified by reading the finished artefact back — firmware, kernel, device tree, init, services and the identifiers the bootloader resolves against. It has not yet been booted on physical hardware, and that distinction matters: an earlier build carried every correct file and still could not have booted, because a rebuild changed an identifier the boot path depended on. It was caught by verification and is now asserted at build time — but only a real boot proves a real boot.
Wireless access-point bring-up is the least validated area. Address assignment on the internet-facing side currently uses the base system’s client rather than our own, and IPv6, port forwarding, VLANs and VPN are not implemented.
That list is here on purpose. If we are going to claim that we write down what we have and have not proven, the claim has to survive contact with our own work.
Talk to us about
Custom network appliances, embedded Linux platforms, control-plane and data-plane software, or replacing an ageing vendor stack with something you own and can actually audit.