Wireless Router DIY
- Transfer
- Tutorial
- Selection of components
- Network Interface Launch
- Install an 802.11ac access point (5 GHz)
- Configuring a virtual SSID using hostapd
For the last ten years, I have bought cheap network equipment and put DD-WRT on it in order to return “functions” at the cost of more than $ 500 removed from the Linux kernel, on which the stock firmware is based.
Despite unstable assemblies, uncorrected errors and disputes , DD-WRT is still preferable to stock firmware. But now worthy components are cheaper than ever, and the DIY community has moved to Linux without exception (I'm looking at you, Mr. Raspberry), so why not put together your own wireless router once and for all?
Selection of components
First you need to decide on the platform: x86 or ARM ? I will not discuss in detail the key differences , but in short: the former has better performance, and the latter is cheaper and more energy efficient. Raspberry Pi boards (and analogues) are extremely cheap and probably more powerful than most wireless commercial routers, but x86 platforms are widespread and have an advantage due to standardized form factors and expansion ports.
Of course, the most important detail is the chipset. Today, the de facto standards are 802.11n (2.4 GHz) and 802.11ac (5 GHz), but finding drivers for Linux is also a problem., especially with support for AP mode (access point). In short, if you do not want problems, choose Atheros chipsets . The ath9k and ath10k drivers are well supported, you can easily find them with USB and / or mini-PCIe interfaces.
At least one network interface controller (NIC) is the minimum necessary, and choose RAM and storage to your liking.
List of materials
Having sacrificed price and power consumption, I chose the x86 platform for a modular, relatively powerful configuration available for upgrade.
If you do not need ARM, then the fan is not required.
- Gigabyte GA-J1900N-D3V (J1900 quad-core 2 GHz Celeron, two NICs)
- Airetos AEX-QCA9880-NX (dual-band 802.11ac, MIMO)
- 4 GB RAM (DDR3-LP, 1333 MHz, 1.35 V)
- MPCIe extension
- MX500 mini-ITX housing
- Three 6dBi RP-SMA dual-band antennas + RP-SMA cable
- Picopsu-90
- Spare HDD 2.5 ”
The case is spacious, with two prepared holes for the AC / DC plug. The installation of the motherboard, RAM and Pico-PSU went smoothly:
Iron porn
The installation of mini-PCIe WiFi was the most difficult because the board only supports half-size cards: here the mPCIe extender came to the rescue. I took a 20 cm FFC cable (included) to connect both sides of the adapter and secured the mini-PCIe to the chassis using double-sided tape.
Mini-PCIe Expander
Fortunately, the chassis comes with three pre-cut antenna holes. Here is the final result:
Software
It is clear that we put Linux. Depending on the hardware, this could be an optimized distribution like Raspbian (for Raspberry Pi) or any other Linux distribution that you like. Since I have been using Ubuntu for many years, I chose Ubuntu Server 18.04 LTS , with which I am accustomed to work and who have long-term support.
The rest of this article assumes that you are using a Debian based distribution.
If the installation went well and you entered the console, we define the interface names:
$ ip -br a | awk '{print $1}'
lo
enp1s0
enp2s0
wlp5s0
There are two embedded NICs on the motherboard: this
enp1s0
and enp2s0
. The wireless card is displayed as wlp5s0
and supports AP mode, as expected:$ iw list
...
Supported interface modes:
* managed
* AP
* AP/VLAN
* monitor
* mesh point
Now we can outline what we need: we put the first NIC as a WAN port, and the second is connected to the wireless interface:
Network
If you have Ubuntu 18.04, then immediately get rid of
netplan
, to return to the support of / etc / network / interfaces:$ 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
As a DHCP / DNS server, choose dnsmasq :
$ sudo apt-get install dnsmasq
Since we will start and configure the process
dnsmasq
via a hook post-up
, do not forget to disable the daemon at boot:$ sudo sed -i "s/^ENABLED=1$/ENABLED=0/g" /etc/default/dnsmasq
We will write a preliminary configuration of network interfaces in accordance with the diagram, including the minimum setting
dnsmasq
:$ 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
Documentation
/etc/network/interfaces
hereAs you can see in the section
post-up
, dnsmasq starts as soon as the bridge rises. Its configuration is performed only by command line arguments ( --conf-file=/dev/null
), and the process will stop when the interface is disabled. The
bridge_ports
interface is not specifically specified in the field wlp5s0
because it hostapd
will automatically add it to the bridge (brctl may refuse to do this before hostapd is started to change the interface mode). See the documentation for
dnsmasq
. You can now restart the network (
sudo service networking restart
) or simply reboot to verify that the network configuration settings are correct. Please note: although we can currently receive DHCP from
enp2s0
, but we will not haveno wireless connection (more on this later), no internet access (see below).Routing
At this stage, you need to route packets between the LAN (
enp2s0
) and WAN ( enp1s0
) interfaces and enable network address translation . Enable 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 last command ensures that the configuration is maintained until the next reboot.
Network address translation is another matter; you usually have to figure out (or rather fight) with
iptables
. Fortunately, the stone age is long over, and the guys from FireHol put a lot of effort, adding the necessary level of abstraction:$ sudo apt-get install firehol
FireHOL is a state-of-the-art protected firewall language, its configuration is easily understood and accessible. You no longer need to write statements
iptables
: the configuration file itself is translated into statements iptables
and is applied as it should. No daemon in the background. The inclusion of network address translation for local network interfaces with the addition of minimum firewall rules is done simply:
$ 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 is written by people for people, the documentation is here .
You can check the settings by manually running
firehol
( sudo firehol start
) and connecting the laptop to the LAN port: now you can get online if the WAN port is connected. Before rebooting, do not forget to edit
/etc/default/firehol
to allow the launch of FireHol at startup:$ sudo sed -i -E "s/^START_FIREHOL=.+$/START_FIREHOL=YES/g" /etc/default/firehol
I will not go into the details of the entire syntax
firehol
, the configuration file explains itself, I recommend to consult the documentation in the case of more complex settings. If you are really interested in what you firehol
did with iptables
, just type sudo firehol status
in the command line.Wireless access point
Obviously, we will manage the access point using hostapd :
$ sudo apt-get install hostapd
Below you will find the minimum and almost no explanation for the 802.11 n / 2.4 Ghz / 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
For documentation,
hostpad.conf
see c/usr/share/doc/hostapd/examples/hostapd.conf
. The described configuration can be tested manually:
$ sudo hostapd /etc/hostapd/hostapd-simple.conf
If everything goes well, a wireless connection will appear . If you are satisfied with the result, do not forget to change the configuration in order to launch
hostapd
as soon as the interface rises (as shown below). Here is 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
Install an 802.11ac access point (5 GHz)
Passive scan
According to the Airetos AEX-QCA9880-NX documentation , the chipset supports 802.11ac, so that we can leave the crowded 2.4 GHz channels to the heavenly 5 GHz.
Let's see which frequencies are supported:
$ iw list
...
Frequencies:
* 2412 MHz [1] (20.0 dBm)
* 2417 MHz [2] (20.0 dBm)
* 2422 MHz [3] (20.0 dBm)
* 2427 MHz [4] (20.0 dBm)
* 2432 MHz [5] (20.0 dBm)
* 2437 MHz [6] (20.0 dBm)
* 2442 MHz [7] (20.0 dBm)
* 2447 MHz [8] (20.0 dBm)
* 2452 MHz [9] (20.0 dBm)
* 2457 MHz [10] (20.0 dBm)
* 2462 MHz [11] (20.0 dBm)
* 2467 MHz [12] (disabled)
* 2472 MHz [13] (disabled)
* 2484 MHz [14] (disabled)
...
Frequencies:
* 5180 MHz [36] (17.0 dBm) (no IR)
* 5200 MHz [40] (17.0 dBm) (no IR)
* 5220 MHz [44] (17.0 dBm) (no IR)
* 5240 MHz [48] (17.0 dBm) (no IR)
* 5260 MHz [52] (23.0 dBm) (no IR, radar detection)
* 5280 MHz [56] (23.0 dBm) (no IR, radar detection)
* 5300 MHz [60] (23.0 dBm) (no IR, radar detection)
* 5320 MHz [64] (23.0 dBm) (no IR, radar detection)
* 5500 MHz [100] (23.0 dBm) (no IR, radar detection)
* 5520 MHz [104] (23.0 dBm) (no IR, radar detection)
* 5540 MHz [108] (23.0 dBm) (no IR, radar detection)
* 5560 MHz [112] (23.0 dBm) (no IR, radar detection)
* 5580 MHz [116] (23.0 dBm) (no IR, radar detection)
* 5600 MHz [120] (23.0 dBm) (no IR, radar detection)
* 5620 MHz [124] (23.0 dBm) (no IR, radar detection)
* 5640 MHz [128] (23.0 dBm) (no IR, radar detection)
* 5660 MHz [132] (23.0 dBm) (no IR, radar detection)
* 5680 MHz [136] (23.0 dBm) (no IR, radar detection)
* 5700 MHz [140] (23.0 dBm) (no IR, radar detection)
* 5720 MHz [144] (23.0 dBm) (no IR, radar detection)
* 5745 MHz [149] (30.0 dBm) (no IR)
* 5765 MHz [153] (30.0 dBm) (no IR)
* 5785 MHz [157] (30.0 dBm) (no IR)
* 5805 MHz [161] (30.0 dBm) (no IR)
* 5825 MHz [165] (30.0 dBm) (no IR)
...
In the above list, we see that the chipset supports channels 1-14 (2.4 GHz) and channels 36-165 (5 GHz), but did you notice the flag
no IR
? The flag
no IR
means no-initiating-radiation (i.e. passive scanning ). This means that this mode is prohibited in the case when the device first initiates radiation (including beacons ). In other words, you cannot launch an access point on these channels !Regulatory requirements
The above situation is explained by the Linux regulatory requirements that govern the use of the radio frequency spectrum depending on the country .
But wait!
I live in the United States, and the link says that I have the right to initiate radiation on channels 36-48, so what's the matter? Let's see which regulation domain is currently used:
$ iw reg get
country 00: DFS-UNSET
(2402 - 2472 @ 40), (N/A, 20), (N/A)
(2457 - 2482 @ 40), (N/A, 20), (N/A), NO-IR
(2474 - 2494 @ 20), (N/A, 20), (N/A), NO-OFDM, NO-IR
(5170 - 5250 @ 80), (N/A, 20), (N/A), NO-IR
(5250 - 5330 @ 80), (N/A, 20), (0 ms), DFS, NO-IR
(5490 - 5730 @ 160), (N/A, 20), (0 ms), DFS, NO-IR
(5735 - 5835 @ 80), (N/A, 20), (N/A), NO-IR
(57240 - 63720 @ 2160), (N/A, 0), (N/A)
The output shows that the world domain is now active (or not established), that is, the minimum values allowed in each country .
Unfortunately, manually installing the domain
sudo iw reg set
will fail, because the domain is sewn into the EEPROM:$ dmesg | grep EEPROM
[ 12.123068] ath: EEPROM regdomain: 0x6c
Patch!
Fortunately, regulatory requirements are handled at the driver level, so they can be easily changed: we find the patch in the Open-WRT source code .
First of all, do not forget to connect the source code repository from
/etc/apt/sources.list
:$ cat /etc/apt/sources.list
...
deb-src http://us.archive.ubuntu.com/ubuntu/ bionic main restricted
...
Then prepare the environment by installing the necessary dependencies:
$ sudo apt-get install build-essential fakeroot
$ sudo apt-get build-dep linux
Download your kernel sources:
$ apt-get source linux
Since the original Open-WRT patch cannot be applied “as is” to the Ubuntu core tree due to subtle differences in the build system, I had to fix it:
$ VERSION=$(uname -r)
$ cd linux-${VERSION%%-*}
$ wget -O - https://gist.github.com/renaudcerrato/02de8b2e8dc013bc71326defd2ef062c/raw/a2db325e520e6442c8c12f7599d64ac1b7596a3e/402-ath_regd_optional.patch | patch -p1 -b
Everything is ready for assembly:
$ fakeroot debian/rules clean
$ fakeroot debian/rules binary-generic
If there are no problems, then now you can install the fixed kernel over the previous one:
$ cd ..
$ sudo dpkg -i linux*.deb
Reboot, and voila:
$ sudo iw reg set US
$ iw list
...
Frequencies:
* 5180 MHz [36] (17.0 dBm)
* 5200 MHz [40] (17.0 dBm)
* 5220 MHz [44] (17.0 dBm)
* 5240 MHz [48] (17.0 dBm)
* 5260 MHz [52] (23.0 dBm) (radar detection)
* 5280 MHz [56] (23.0 dBm) (radar detection)
* 5300 MHz [60] (23.0 dBm) (radar detection)
* 5320 MHz [64] (23.0 dBm) (radar detection)
* 5500 MHz [100] (23.0 dBm) (radar detection)
* 5520 MHz [104] (23.0 dBm) (radar detection)
* 5540 MHz [108] (23.0 dBm) (radar detection)
* 5560 MHz [112] (23.0 dBm) (radar detection)
* 5580 MHz [116] (23.0 dBm) (radar detection)
* 5600 MHz [120] (23.0 dBm) (radar detection)
* 5620 MHz [124] (23.0 dBm) (radar detection)
* 5640 MHz [128] (23.0 dBm) (radar detection)
* 5660 MHz [132] (23.0 dBm) (radar detection)
* 5680 MHz [136] (23.0 dBm) (radar detection)
* 5700 MHz [140] (23.0 dBm) (radar detection)
* 5720 MHz [144] (23.0 dBm) (radar detection)
* 5745 MHz [149] (30.0 dBm)
* 5765 MHz [153] (30.0 dBm)
* 5785 MHz [157] (30.0 dBm)
* 5805 MHz [161] (30.0 dBm)
* 5825 MHz [165] (30.0 dBm)
...
In order to avoid automatic updating, you may need to fix the version of the Linux kernel .
Configuration
The new configuration file
hostapd
will be quite simple: hw_mode=a
includes 5 GHz bands, and ieee80211ac=1
includes 802.11ac (VHT). Option ieee80211d=1
indicating country_code=US
defines the regulatory domain, under which we operate. To maximize the use of bandwidth,
ht_capab
and vht_capab
should reflect the capabilities of the equipment:$ iw list
...
Band 1:
Capabilities: 0x19e3
RX LDPC
HT20/HT40
Static SM Power Save
RX HT20 SGI
RX HT40 SGI
TX STBC
RX STBC 1-stream
Max AMSDU length: 7935 bytes
DSSS/CCK HT40
...
Band 2:
VHT Capabilities (0x338001b2):
Max MPDU length: 11454
Supported Channel Width: neither 160 nor 80+80
RX LDPC
short GI (80 MHz)
TX STBC
RX antenna pattern consistency
TX antenna pattern consistency
Given this, here is the final one
hostapd.conf
:$ cat /etc/hostapd/hostapd.conf
#### Interface configuration ####
interface=wlp5s0
bridge=br0
driver=nl80211
##### IEEE 802.11 related configuration #####
ssid=iCanHearYouHavingSex
hw_mode=a
channel=0
auth_algs=1
wmm_enabled=1
country_code=US
ieee80211d=1
ieee80211h=0
##### IEEE 802.11n related configuration #####
ieee80211n=1
ht_capab=[HT40+][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CK-40][LDPC][MAX-AMSDU-7935]
##### IEEE 802.11ac related configuration #####
ieee80211ac=1
vht_capab=[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP7][TX-ANTENNA-PATTERN][RX-ANTENNA-PATTERN]
vht_oper_chwidth=1
##### WPA/IEEE 802.11i configuration #####
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=YouCantGuess
For documentation,
hostpad.conf
see c/usr/share/doc/hostapd/examples/hostapd.conf
. At this stage, the wireless router is fully operational, and if you need a more complex setup, you can now dive into the configuration files.
Configuring a virtual SSID using hostapd
Regardless of whether you want to configure a guest access point or a dedicated wireless network for your VPN, at some point you will have to configure a virtual SSID.
Diagram
Based on the current configuration , here is an updated diagram of what we want to get. Assuming that it
wlp5s0
is a physical wireless interface, the virtual SSID will work on the virtual interface wlan0
using its own subnet 192.168.2.0/24
:Training
First, verify that your wireless device supports multiple SSIDs:
$ iw list
...
valid interface combinations:
* #{ AP, mesh point } <= 8,
total <= 8, #channels <= 1, STA/AP BI must match
...
As you can see, the chipset supports up to eight access points on one channel. This means that you can configure up to seven virtual SSIDs, and they will all work on the same channel.
Network interface
According to the documentation in hostapd.conf, there is a strict connection between the MAC address of the physical interface and the BSSID of the virtual interfaces:
hostapd will generate a BSSID mask based on the BSSIDs that are configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is not the case, the MAC address of the radio must be changed before starting hostapd. If a BSSID is configured for every secondary BSS, this limitation is not applied at hostapd and other masks may be used if the driver supports them (e.g., swap the locally administered bit)
BSSIDs are assigned in order to each BSS, unless an explicit BSSID is specified using the 'bssid' parameter.
If an explicit BSSID is specified, it must be chosen such that it:
— results in a valid MASK that covers it and the dev_addr
— is not the same as the MAC address of the radio
— is not the same as any other explicitly specified BSSID
To meet these requirements and allow the
hostapd
virtual interface (s) to automatically assign the BSSID, update the MAC address of the physical wireless interface to zero the four least significant bits. That's enough for 15 virtual BSSIDs - much more than necessary. First we define the current MAC address:
$ ip addr show wlp5s0 | grep link | awk '{print $2}'
44:c3:06:00:03:eb
If you clear the last four bits and set the U / L bit, you’ll end up with a MAC address
46:c3:06:00:03:e0
. Now we will update the configuration in order to set the correct MAC address right before the interface is loaded, and also announce the virtual wireless interface in accordance with our diagram:
$ cat /etc/network/interfaces
...
# Physical Wireless
auto wlp5s0
iface wlp5s0 inet manual
pre-up ip link set dev wlp5s0 address 46:c3:06:00:03:e0
# Virtual Wireless
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.2.1
network 192.168.2.0
netmask 255.255.255.0
broadcast 192.168.2.255
post-up /usr/sbin/dnsmasq \
--pid-file=/var/run/dnsmasq-wlan0.pid \
--conf-file=/dev/null \
--interface=wlan0 --except-interface=lo \
--bind-interfaces \
--dhcp-range=192.168.2.10,192.168.2.150,24h
post-down cat /var/run/dnsmasq-wlan0.pid | xargs kill
...
Fine. I use
dnsmasq
as a DHCP server - feel free to replace with something you like. Please note that virtual interface is required for correct operation allow-hotplug
.Access point configuration
Now the simplest thing is to add a virtual SSID to the current configuration
hostapd
. Just add it to the end of the existing file hostapd.conf
:$ cat /etc/hostapd/hostapd.conf
...
### Virtual SSID(s) ###
bss=wlan0
ssid=MyVirtualSSID
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=you_cant_guess
In the example above, I used WPA2 encryption, but most of the radio interface options are available (for example,
channel
). You can add more virtual SSIDs by simply adding lines in the configuration file, according to the declared and properly configured virtual interfaces. Now we reboot and we see our new SSID along with the new wireless interface (note the MAC address):
$ ip addr show wlan0 | grep link | awk '{print $2}'
46:c3:06:00:03:e1
That's it guys!