How to Build your Own Wireless Router

By Renaud Cerrato

I’ve spent the last decade buying cheap networking hardware and upgrading them to DD-WRT in order to get back $500+ worth of “features” that have been expunged from the Linux kernel on which the stock firmwares were based on.

Despite unstable builds, unfixed bugs and the controversy about it, DD-WRT was still a better choice than stock firmwares. But nowadays, decent hardware is cheaper than ever and Linux is the new fad among the DIY community (I’m looking at you, Mr Raspberry), so why not making your own, tailor-made, wireless router once and for all?

Among the important pieces of hardware you’ll have to pick, you must first choose your platform: x86 or ARM? I’m not going to explain the key differences in details since that information is available, but long story short: the former have better performance while the latter is all about being cost and power effective. Whereas Raspberry Pi boards (or alike) are extremely cheap and probably have more horsepower than most wireless routers you’ll find on commercial off-the-shelf products, keep in mind that x86-based platforms are widespreads and benefits of well-standardized form factors and extension ports.

Of course, the most important piece of hardware is the wireless chipset: both 802.11n (2.4Ghz) and 802.11ac (5Ghz) are de-facto standards today, but choosing a wireless device for Linux might be a daunting task, even more if AP mode must be supported. Long story short again: Atheros chipsets are the way to go for a painless road. Both ath9k and ath10k drivers are well maintained, and you’ll easily find those chipsets in USB and/or mini-PCIe shape depending on your available ports.

While a single NIC interface is the minimum requirement, RAM and storage may be freely chosen according to your needs.

Making some personal trade-off on price and power-consumption, I chose an x86-based platform to benefit of a modular, upgradable (and relatively beefy) setup.

If you’re not going to pick an ARM platform, be sure to go fanless.

The case is spacious, and have pre-cut holes for the AC/DC plug. The motherboard, RAM and the Pico-PSU installation went smoothly:

Hardware Porn

The trickiest part has been the mini-PCIe WiFi card since the board only supports half-sized cards: here come the mPCIe Extender to the rescue. I used a 20cm FFC cable (included) to connect both sides of the adapter and fixed the mini-PCIe side to the chassis using some double sided tape.

mini-PCIe Extender

Luckily, the case comes with 3 pre-cut holes for the antennas. Here’s the final result:

The next part will show you how to setup your network interfaces and enable a minimal 802.11n access-point.


Page 2

This post is the second part of the serie. The first part covered the hardware, that part will show you how to setup your network interfaces and enable a minimal 802.11n access-point.

No surprise, Linux is the de-facto choice. Depending on the hardware you previously picked, it may be an optimized distribution like Raspbian (for Raspberry Pi) or any other Linux distro you’re comfortable with. Since I’m an Ubuntu user for years, I chose Ubuntu Server 18.04 LTS for a butter smooth experience and long term support.

The remaining parts of the serie will assume you’re running a Debian-derived Linux distribution.

Assuming the installation went right and you’re given access to a shell, let’s first identify the interfaces names:

$ ip -br a | awk '{print $1}'
lo
enp1s0
enp2s0
wlp5s0

The motherboard have 2 built-in NIC named enp1s0 and enp2s0. The wireless card is showing as wlp5s0, and support AP mode as expected:

$ iw list
...
Supported interface modes:
* managed
* AP
* AP/VLAN
* monitor
* mesh point

We are now able to draw what we want to achieve: the first NIC will serve as the WAN port, while the remaining one will be bridged to the wireless interface:

If you’re running Ubuntu 18.04, let’s immediately get rid of netplan to get back /etc/network/interfaces support:

$ sudo apt-get install ifupdown bridge-utils
$ sudo systemctl stop networkd-dispatcher
$ sudo systemctl disable networkd-dispatcher
$ sudo systemctl mask networkd-dispatcher
$ sudo apt-get purge nplan netplan.io

We’ll pick dnsmasq as DHCP/DNS server:

$ sudo apt-get install dnsmasq

Since we’ll be running and configuring the dnsmasq process through the post-up hook, don’t forget to disable the daemon on startup:

$ sudo sed -i "s/^ENABLED=1$/ENABLED=0/g" /etc/default/dnsmasq

Let’s write a preliminary network interfaces configuration matching the diagram, including a minimal dnsmasq setup:

$ cat /etc/network/interfaces
# Loopback
auto lo
iface lo inet loopback
# WAN interface
auto enp1s0
iface enp1s0 inet dhcp
# Bridge (LAN)
auto br0
iface br0 inet static
address 192.168.1.1
network 192.168.1.0
netmask 255.255.255.0
broadcast 192.168.1.255
bridge_ports enp2s0
post-up /usr/sbin/dnsmasq \
--pid-file=/var/run/dnsmasq.$IFACE.pid \
--dhcp-leasefile=/var/lib/misc/dnsmasq.$IFACE.leases \
--conf-file=/dev/null \
--interface=$IFACE --except-interface=lo \
--bind-interfaces \
--dhcp-range=192.168.1.10,192.168.1.150,24h
pre-down cat /var/run/dnsmasq.$IFACE.pid | xargs kill
/etc/network/interfaces documentation is available on the man page.

As you may have noticed, dnsmasq will be started as soon as the bridge is up thanks to the post-up section. Its configuration is done through command line arguments only (--conf-file=/dev/null) and the process will be shutdown when the interface go down.

The bridge_ports field is intentionally missing wlp5s0 since that interface will be added to the bridge automatically by hostapd (brctl may refuse to do this before hostapd has been started to change the interface mode).

dnsmasq documentation is available on the man page.

You can now restart your networking (sudo service networking restart) or simply reboot to check if your network configuration is properly setup.

However, please note that while you should be able to get DHCP leases from enp2s0 at this point, you won’t be able to connect wirelessly (more on this later), nor able to connect to the internet yet (see below).

At this point, we need to route packets between the LAN (enp2s0) and WAN (enp1s0) interfaces, and enable masquerading on it.

Enabling packet forwarding is easy:

$ sudo sysctl -w net.ipv4.ip_forward=1
$ echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
The latter command will ensure that the configuration will survive to the next reboot.

Enabling packet masquerading is another story, and usually requires to deal (or rather fight) with iptables. Thankfully, stone-age has long passed by, and the guys at FireHol put a lot of efforts adding the required level of abstraction to that:

$ sudo apt-get install firehol

FireHOL is a language which builds secure, stateful firewalls from easy to understand, human-readable configurations. Humans are not required to write iptables statements anymore: your configuration file will be translated to iptables statements and applied before quitting. No daemon running in the background.

Enabling masquerading for the LAN interfaces while adding minimum firewall rules using firehol is as simple as:

$ cat /etc/firehol/firehol.conf 
version 6
# Accept all client traffic on WAN
interface enp1s0 wan
client all accept
# Accept all traffic on LAN
interface br0 lan
server all accept
client all accept
# Route packets between LAN and WAN
router lan2wan inface br0 outface enp1s0
masquerade
route all accept
firehol has been made for humans by humans. Take a look at the documentation.

You can test the above setup by starting firehol manually (sudo firehol start) and by connecting a laptop to the LAN port: you should now be able to browse the internet if the WAN port is plugged.

Before rebooting, do not forget to edit /etc/default/firehol to allow FireHol to start on boot:

$ sudo sed -i -E "s/^START_FIREHOL=.+$/START_FIREHOL=YES/g" /etc/default/firehol
I won’t go into details about the whole firehol syntax, the configuration file should be almost self-explanatory and I recommend giving a look at the documentation for a more complex setup. If you’re really curious about what firehol did to your iptables, just drop sudo firehol status on the command line.

With no surprise, we’ll use hostapd to manage your access-point:

$ sudo apt-get install hostapd

You’ll find below a minimal and almost self-explanatory 802.11n/2.4Ghz/WPA2-AES configuration file:

$ cat /etc/hostapd/hostapd-simple.conf 
#### Interface configuration ####
interface=wlp5s0
bridge=br0
driver=nl80211
##### IEEE 802.11 related configuration #####
ssid=iCanHearYouHavingSex
hw_mode=g
channel=1
auth_algs=1
wmm_enabled=1
##### IEEE 802.11n related configuration #####
ieee80211n=1
##### WPA/IEEE 802.11i configuration #####
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=YouCantGuess
hostpad.conf documentation can be found inline at /usr/share/doc/hostapd/examples/hostapd.conf

The configuration above can be tested by hand:

$ sudo hostapd /etc/hostapd/hostapd-simple.conf

If everything goes well, you should now be able to connect wirelessly. If you’re satisfied with the result, do not forget to edit the interface configuration to start hostapd right after the interface goes up (as seen below).

Here’s your final /etc/network/interfaces:

$ cat /etc/network/interfaces
# Loopback
auto lo
iface lo inet loopback
# WAN interface
auto enp1s0
iface enp1s0 inet dhcp
# Bridge (LAN)
auto br0
iface br0 inet static
address 192.168.1.1
network 192.168.1.0
netmask 255.255.255.0
broadcast 192.168.1.255
bridge_ports enp2s0
post-up /usr/sbin/hostapd \
-P /var/run/hostapd.$IFACE.pid \
-B /etc/hostapd/hostapd-simple.conf

post-up /usr/sbin/dnsmasq \
--pid-file=/var/run/dnsmasq.$IFACE.pid \
--dhcp-leasefile=/var/lib/misc/dnsmasq.$IFACE.leases \
--conf-file=/dev/null \
--interface=$IFACE --except-interface=lo \
--bind-interfaces \
--dhcp-range=192.168.1.10,192.168.1.150,24h
pre-down cat /var/run/dnsmasq.$IFACE.pid | xargs kill
pre-down cat /var/run/hostapd.$IFACE.pid | xargs kill

In this part, we learned how to properly setup your network interfaces using /etc/network/interfaces, introducing dnsmasq as DHCP server. We leveraged firehol to declare your firewall and routing rules before setting-up hostapd. At this point, your router is accepting and properly routing traffic between its interfaces, delivering DHCP leases on the LAN and broadcasting some SSID on the 2.4Ghz channels.

The next part will enable 802.11ac (5Ghz).