📜 ⬆️ ⬇️

Wireless Router DIY


  1. Selection of components
  2. Starting Network Interfaces
  3. Install an 802.11ac access point (5 GHz)
  4. 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 am 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 thing is the chipset. Today, the de facto standards are 802.11n (2.4 GHz) and 802.11ac (5 GHz), but choosing drivers for Linux is another task , especially with support for the 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.


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 most difficult was the installation of mini-PCIe WiFi, because the board only supports half-size cards: 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 extender

Fortunately, the case comes with three pre-cut holes for the antennas. 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 distribution based on Debian.

If the installation went fine 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: these are 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 will install the first NIC as a WAN port, and the second will be connected to the wireless interface:



Network


If you have Ubuntu 18.04, then we will 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 dnsmasq process via the post-up hook, do not forget to disable the daemon at boot time:

 $ 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 dnsmasq setting:

 $ 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 here

As you can see from the post-up section, dnsmasq starts as soon as the bridge rises. Its configuration is performed only with 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 wlp5s0 , because hostapd will add it to the bridge automatically (brctl may refuse to do this before hostapd is running to change the interface mode).

See dnsmasq documentation .

Now you can restart the network ( sudo service networking restart ) or simply reboot to verify that the network configuration settings are correct.

Please note: although at the moment we can get DHCP from enp2s0 , we will not have either a wireless connection (more on this later) or internet access (see below).

Routing


At this stage, you need to route packets between the LAN ( enp2s0 ) and WAN interfaces ( enp1s0 ) 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 deal with (or rather, fight) 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 iptables statements: the configuration file itself is translated into iptables statements 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 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 boot:

 $ sudo sed -i -E "s/^START_FIREHOL=.+$/START_FIREHOL=YES/g" /etc/default/firehol 

I will not go into the details of the whole firehol syntax, the configuration file explains itself, I recommend to consult the documentation in the case of more complex settings. If you really wonder what firehol did with iptables , just type sudo firehol status on 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 

hostpad.conf documentation hostpad.conf see /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 start 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 no IR flag indicates 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 US, 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 setting the sudo iw reg set domain 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 hostapd configuration hostapd will be pretty simple: hw_mode=a includes 5 GHz bands, and ieee80211ac=1 includes 802.11ac (VHT). The option ieee80211d=1 indicating country_code=US specifies the regulatory domain under which we operate.

To maximize 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 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 

hostpad.conf documentation hostpad.conf see /usr/share/doc/hostapd/examples/hostapd.conf .

At this stage, the wireless router is fully operational, and if more complicated configuration is needed, then you can now dive into 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 wlp5s0 is a physical wireless interface, the virtual SSID will work on the wlan0 virtual interface using its own 192.168.2.0/24 subnet:



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 all of them will 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 . The address of the radio must be changed before the hostapd. If you are using the BSSID, you can use it (eg, swap the locally administered bit)

BSSIDs are 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
- the address of the radio is not the same.
- BSSID

To meet these requirements and allow hostapd automatically assign the BSSID of the virtual interface (s), we’ll update the MAC address of the physical wireless interface to zero the four least significant bits. That's enough for 15 virtual BSSIDs - a lot 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 get the 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 it with something you like. Please note that for the virtual interface to work correctly, allow-hotplug is required.

Access Point Configuration


Now the simplest thing: add a virtual SSID to the current hostapd configuration. Just add this to the end of the existing hostapd.conf file:

 $ 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 applied 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!

Source: https://habr.com/ru/post/437634/