Linux IPv6 Router How To
Linux IPv4/IPv6 router using shorewall and dnsmasq only, without radvd.
My old home wi-fi router is dying and instead of buying one, I decided to build one with Linux this time. This will give me more control and visibility into my network and internet traffic.
The new box I am using is Qotom-Q355G4:
- Main Port: 1 HD Video Port + 1 COM + 2 USB 2.0 + 2 USB 3.0 + 4 LAN.
- CPU: Intel Core i5-5200U SOC Processor (Broadwell, Dual Core, 3M Cache, 2.2GHz, up to 2.7GHz). Support AES-NI.
- Configuration: 8GB DDR3L RAM, 512GB mSATA SSD, WiFi, NO 2.5" SATA HDD, fanless
- Audio in/out
It is way overkill for a home router even with 100M+ download speed. However it has the extra power to do some docker testing.
|IPv6 DHCP Client||wide-dhcpv6-client|
|Firewall||shorewall & shorewall6|
|Wi-Fi Access Point||hostapd|
|DNS and DHCP Server||dnsmasq|
|NIC Port||Network Zone||IPv4||IPv6|
|1||WAN (Internet)||from ISP||from ISP|
|2 & Wi-Fi||DMZ||10.0.0.1/24||PD from ISP|
|3 & 4||LAN||192.168.0.1/24||PD from ISP|
OS Network Setup
The base OS is Ubuntu Server with unnecessary packages removed. You can check my Ubuntu Commands page on that.
To support IPv6 and as a router, following need to be set in
enp1s0 is device name of NIC 1. The last 2 lines are for accepting IPv6 info from upstream ISP.
The base interface setup is as follow in
First we have the “wan” interface
|dhcp4: true||We need to IPv4 address from upstream|
|dhcp-identifier: mac||This is needed to get proper dhcp|
|link-local: [ ]||This prevent systemd-network from starting dhcp6, explain below.|
optional: ture for other interfaces allow boot process to continue without delay if no cable is plugged in.
Then we have our two bridges
enp2s0(NIC2) by itself.
hostapd will add the wi-fi interfaces to it in later section.
lan consist of
enp4s0(NIC4) bridged together for internal network.
Plug in your internet cable to NIC 1 and enable the settings:
Internet access should be working with IPv4.
Netplan & accept_ra
net.ipv6.conf.enp1s0.accept_ra=2 is set in
sysctl.conf, netplan will remove it during network start up because
link-local: [ ] is used. That will prevent the router from receiving IPv6 info from upstream.
To make sure accept_ra is set after network interface is up, create following files:
Enable it during boot:
While dmz and lan IPv4s are configured in netplan, IPv6 use global address even for devices within your network. PD(prefix-delegation) is required for
dmz interfaces so devices behind them will work correctly.
Netplan doesn’t support PD config at the time of writing. Package
wide-dhcpv6-client is used. It is able to assign PD IPv6 addresses to other interfaces after PDs are received, almost (see
sla-len at end of this section) without any address hardcoding in the config file or external helper script.
Config file is located at
wide-dhcpv6-client during startup:
After reboot all 3 interfaces(enp1s0, dmz, lan) should have IPv4 and IPv6(scope global) addresses.
journalctl -t dhcp6c | grep 'IA_PD prefix:'. If the IA_PD prefix end in /56 instead of /64, change both line to
sla-len 8;. This config is for /64 prefix and actually not suitable for /56, which should use a single
id-assoc pdblock with two
A firewall is needed for the following:
- stop incoming traffic
- NAT for IPv4 traffic from lan/dmz to internet
- separation of lan and dmz
Shorewall and shorewall6 are used due to their ease of configuration. To install:
Following are the basic configuration.
Shorewall handle IPv4 traffic. Following are config files base on
This is NAT configuration for both lan and dmz.
Shorewall6 handles IPv6 traffic. Following are config files base on
/usr/share/doc/shorewall6/examples/three-interfaces. There is no
snat for IPv6.
More detail examples of all the config files are in the example directory.
hostapd to create a wi-fi access point.
iw is a command line wifi configuration tool. It can list capabilities of wi-fi adapter.
Wi-Fi adapter of my box is
wlp5s0. It will be added to bridge
A 2nd virtual interface
wlan0 will be created and join bridge
bssid of the physical wi-fi adapter(
wlp5s0) is its real mac address.
bssid of the virtual wi-fi adapter(
wlan0) can be any valid mac address format that don’t conflict with other devices in the network. I usually just increase the physical adapter mac by 1.
hostapd may die during boot up due to interface initialization timing. Add following in hostapd.service
Enable and restart service:
DNS & DHCP
dnsmasq is used to provide both dns and dhcp services for dmz and lan. It is able to create IPv6 dhcp range automatically base on IPv6 address of the interface.
Put the configuration file in
systemd-resolved as it is Ubuntu default dns server and delete existing
It took much longer than I thought to put all this together.
I had to switch packages a few times due to various reasons, but mostly to avoid creating custom scripts. The most notable one is dnsmasq replacing both systemd-resolved/powerDNS-recursor and radvd. dnsmasq is able to handle both functions with much cleaner way and more flexibility.
I believe currently, if not using a full router/firewall distro like OpenWRT, pfSense or ClearOS, then dnsmasq with wide-dhcpv6-client is the best combination for DIY Linux router solution. Their ability of auto IPv6 prefix handling, which allow configurations without hardcoding IPv6 prefix, is especially important for location that can’t secure their own IPV6 prefix.
mpd on Qotom-Q355G4
mpd has difficulty identifying the ALSA PCM on Qotom-Q355G4. Use following
/etc/asound.conf to solve it: