Linux has long had a great reputation as an OS for network management, and with good reason; it can turn an old PC in to a firewall and router for your home or office broadband connection. Lately though, a new breed of low-cost embedded network devices have become popular, with lots of features and easy web-based management. They're not as flexible as a dedicated Linux box, but they're small, silent, and cheap.
A great example is the Linksys WRT54G, which combines a router, firewall, switch and 802.11g wireless access point and costs about $130. However, this particular device has an ace up its sleeve: it actually runs Linux, and by installing an alternative firmware, you can unlock its true potential.
Linux's fantastic voyage
Many devices run Linux these days, from routers like the WRT54G through to PDAs like the Zaurus, but these humble devices are starved for resources compared to a modern PC. For instance, the only storage on the WRT54G is 4MB of flash RAM. With modern distributions taking close to 4GB for a full install, how can you possibly shrink Linux down to just 4MB?
The first step is to strip the system down to its bare components - the kernel, standard C library, a shell, and various command-line utilities. A typical Linux system uses GNU packages such as glibc and bash, but over the years these packages have grown to the point where they just won't fit on a really tiny system. Thankfully, embedded developers have put together some great alternatives.
uClibc is a standard C library designed with size in mind. It lacks glibc features like modular authentication and extensive foreign language support, but it covers everything needed for embedded applications. Similarly, Busybox is a collection of command-line utilities that's designed with size in mind. It implements over 200 separate utilities, from ls and df through to a simple vi implementation, a powerful shell, and even a basic web server.
The other way to keep your system small is to use a compressed filesystem. Most embedded systems use read-only filesystems, keeping their config data in a separate part of the flash, because it virtually eliminates the risk of a software fault corrupting the filesystem. Read-only, compressed filesystems like cramfs and the newer squashfs are designed specifically for embedded systems.
Depending on exactly what features are compiled in, Busybox and uClibc combined take under 2MB. Even after adding the kernel, wireless drivers, and other utilities needed to make a router function, the entire system compressed easily fits in to the 4MB of flash in the WRT54G.
Along with the 4MB of flash RAM, the WRT54G has 16MB of system RAM and a 200MHz MIPS CPU. It may not sound like much, but Linux has always worked wonders with small systems. I still thought it was perhaps a bit too small though, so I bought a WRT54GS, a slightly more expensive model that adds extra wireless speed when talking to a matching Linksys device. I didn't buy it for the extra speed though; rather, the WRT54GS also features 32MB of RAM and 8MB of flash.
The standard firmware is based on Linux, but it hides it behind its simple web interface. To get to the WRT54G's full potential you'll need to install an alternative firmware. Thankfully, Linksys have released the source code (www.linksys.com/support/gpl.asp) and tools needed to build the firmware, giving rise to a number of firmware projects. I've experimented with the two most popular - EWRT and OpenWRT.
Flashing 101
You can flash your firmware by uploading it via the standard web interface, but if anything goes wrong you'll be left with a funny-looking paperweight. A better option is to use a special pre-boot environment that lets you transfer a new image to the device just after turning it on. To enable it, follow these steps:
1. Make sure you have got a WAN IP address configured. You don't actually have to connect to the internet - just open the web interface, set the WAN type to "Static" and put in any valid IP address.
2. In your web browser, go to the Ping.asp page on your router. One by one, copy and paste the following commands in to the address field and run a ping:
;cp${IFS}*/*/nvram${IFS}/tmp/n
;*/n${IFS}set${IFS}boot_wait=on
;*/n${IFS}commit
3. To confirm that these commands have successfully enabled boot_wait, 'ping' this command:
;*/n${IFS}show>tmp/ping.log
This should show several pages worth of variables. Scroll down until you find boot_wait and make sure it's set to 1.
With that done, you can send a firmware image to the router using the TFTP protocol at boot. Install a TFTP client on your Linux machine and plug it directly in to the router. Regardless of what IP you've configured the LAN interface on the router to use, the pre-boot system uses 192.168.1.1, so make sure you give your PC a static IP address on the same subnet (ie: ifconfig eth0 192.168.1.2).
To do the transfer, run "tftp 192.168.1.1", which should open a tftp prompt. Enter the following commands:
binary
rexmt 1
trace
put firmware.bin
This will start the transfer, retrying every second until it gets through. With that running, unplug the router and then plug it back in. The TFTP transfer should hit the device as it's powering up. It doesn't always work first time though, so don't worry if you have to try a few times to get the flash to work.
EWRT
Probably the most popular alternative firmware for the WRT54G is EWRT (www.portless.net/menu/ewrt/). It's based heavily on the standard firmware, but it adds some handy features like traffic shaping, and an SSH daemon for remote shell access. It's also a great drop-in replacement for the standard firmware since it uses the same web interface, and keeps all of your old settings.
The EWRT website has a firmware image ready to flash on to a WRT54G, but the headers in the image needed a bit of fudging to make it work on my GS. The following command did the trick for me:
sed -e "1s,^W54G,W54S," < ewrt-0.2-beta1.bin >ewrt-gs.bin
Once installed, EWRT is pretty similar to the standard firmware, but with a bunch of extra options under the Management section of the web interface. Here you can enable various features, like traffic shaping and the SSH daemon.
Having remote shell access is neat, but a router running EWRT is still a fixed-function device. What I wanted was to run my router just like a little Linux system, with a package manager and easy installation of new software.
That's exactly what I found in OpenWRT (http://openwrt.org). It's an entirely new firmware, combining a minimal uClibc and busybox system with drivers taken from the Linksys firmware. It installs this minimal system at the start of the flash memory, and formats the rest as a read/write filesystem, giving you the ability to install only the software you need. The base system is about 2MB leaving about 2MB for your own software on a WRT54G, or 6MB on a GS.
Because it's designed as a minimal system, OpenWRT doesn't ship with the Linksys web interface, but if you're willing to do things the traditional Linux way, it has all the command-line tools you need to get things running.
You'll find snapshot builds of the OpenWRT firmware on the website, but I decided to grab the source from CVS and build it myself. To grab the OpenWRT sources, run the following commands, and hit enter when asked for a password:
cvs -d:pserver:anonymous@openwrt.org:/openwrt login
cvs -d:pserver:anonymous@openwrt.org:/openwrt co buildroot
Change in to the buildroot directory and type 'make'. The build process downloads about 200MB of software packages, including the Linksys firmware and modified kernel sources, and a complete set of GCC sources. It builds GCC as a cross-compiler - a compiler that runs on one system (my Athlon PC), but builds binaries for another (in our case, MIPS). Once that's done, it uses the cross-compiler to build the kernel, uClibc, busybox, and various other utilities.
If the build goes smoothly, you should end up with two .bin files - one for the WRT54G, and one for the GS. Flash the appropriate file and boot up your router, then telnet in to your router's LAN IP address. Once you're in, you need to set up the read/write filesystem by running the "firstboot" command, rebooting once it's finished.
The OpenWRT filesystem looks a bit odd at first, since every file is actually a symlink to the read-only filesystem mounted at /rom. This prevents any unnecessary duplication of files, but it means that before you can edit a file, you have to delete the symlink and copy the original file over from out of /rom. You can then make your changes to this fresh copy.
Finding your way around the router is no different from any other Linux machine, though it perhaps has a few more network interfaces than you're used to. The LAN interface is actually br0, a bridged interface combining the LAN ports and the wireless interface, and the WAN interface is on vlan1. Most of the network configuration is actually stored as name and value pairs in a separate area of flash, which you can access with the nvram command.
OpenWRT uses ipkg, a simple package manager that can easily download packages, much like Debian's apt. Before installing anything, update your package lists with an 'ipkg update' command. Installing packages is just as easy. The following will install dropbear, a tiny SSH client and server:
ipkg install dropbear
To be of much use to me, my router had to handle my ADSL connection. I used ipkg to install the pppoecd package and edited the PPPoE settings in nvram:
nvram set wan_ifname=ppp0
nvram set wan_proto=pppoe
nvram set pppoe_ifname=vlan1
nvram set ppp_username=user@isp.com
nvram set ppp_passwd=password
nvram set wan_mtu=1492
With the configuration done, run 'ifup wan' to bring up the connection. If all goes well, you can save your settings in to flash with 'nvram commit', and the ADSL connection will be started automatically at boot.
That covers the basics - what you do with your new router now is entirely up to you. I've installed a PPTP server for running VPNs, and even irssi, a text-based IRC client. I'm also working on a web interface of my own using a small scripting language called Lua. Stay tuned.