This is part 3 of the router series; part 1, part 2 and part 4 are also available
In this long overdue third part of this series we will demonstrate how to setup all the software components that comprise a modern router. You might want to refer back to part 1 for the network topology we are aiming to build. Bear in mind that this guide is based on an Alpine Linux setup but most of the points mentioned can be easily transferred to any Linux distribution. I will try to highlight the Alpine-specific bits.
Contents
Conventions
Before continuing you will need to decide which ethernet ports will be facing
the internet and which the local one. In my case eth0
is facing the
internet (or the modem) and eth1
the local network. We will also use
the home.net
domain for our network and router
as the hostname of our
gateway.
Basic configuration
Installing the required software
As illustrated in the first part we will need some
software to make our linux setup functional. So go ahead and install
(apk add
) the following packages
dhcpcd
for IPv6 prefix delegationdnsmasq
for DHCP and DNS cacherp-pppoe
andppp-pppoe
for PPPoE connectioniptables
andip6tables
for firewallingshorewall
andshorewall6
for firewallingchrony
NTP serveriputils
provides theip
tool for managing interfacesopenssh-server
for remote administrationethtool
(optional) for monitoring the ethernet linksdrill
(optional) for hostname resolvinghtop
(optional) a bettertop
lm_sensors
(optional) for temperature monitoring- and your favorite
$EDITOR
!
Required kernel modules
Alpine does not load all kernel modules that are commonly found in more
heavyweight distributions so we need to ensure that the necessary modules are
loaded. Edit /etc/modules
and append the following
# For dhcp
af_packet
# For IPv6 support
ipv6
# For PPPoE
pppoe
You can obviously forego the modules that are not relevant to you. It doesn’t
make much sense to load ipv6
on an IPv4-only network.
Configure hostname and /etc/hosts
Let’s assume you have set router
as a hostname in /etc/hostname
. You will
additionally need to create a skeleton /etc/hosts
. So edit or create the file
and append
127.0.0.1 router router.home.net
::1 router ipv6-gateway ipv6-loopback
ff00::0 ipv6-localnet
ff00::0 ipv6-mcastprefix
ff00::1 ipv6-allnodes
ff00::2 ipv6-allrouters
ff00::3 ipv6-allhosts
Kernel parameters
In order to allow for packet forwarding this option will need to be enabled in
your kernel parameters. To do so put the following in /etc/sysctl.conf
# Enable IPv4 forwarding
net.ipv4.ip_forward = 1
# Enable IPv6 forwarding across all interfaces
net.ipv6.conf.all.forwarding = 2
net.ipv6.conf.default.forwarding = 2
# Allow router advertisements through all interfaces
net.ipv6.conf.all.accept_ra = 2
net.ipv6.conf.default.accept_ra = 2
This is the absolute minimum of sysctl parameters that need to be enabled for
the device to have router functionality. Most of the above should be
self-explanatory except, maybe, for the 2
in router advertisements. Simply
put router advertisements are used by the IPv6 stack to convey various
configuration aspects to IPv6 clients such as the value and lifetime of the
IPv6 prefix used through the network, MTU, hop limit, etc. They are necessary
in an IPv6 network for the clients to discover the router and autoconfigure
themselves. By default the Linux kernel disables router advertisements if
forwarding is enabled (the 1
value). However 2
will force the acceptance of
advertisement even if forwarding is enabled. There are a lot of different
sysctl
parameters
to tune to further enhance the security of the router but I elected not to go
into them at this point in order not to overcomplicate things and to allow for
fewer points of failure if the whole thing is not working as expected. Once you
have a basic network up and running you can experiment at your leisure.
Connecting to your WAN
Prepare your xDSL or Cable modem
This guide will assume that you are using PPPoE to connect to your ISP as this is the case for most residential ISPs in Europe. If you got a router from your ISP you will need to set it up in bridge mode. As this is modem/router dependent so you will have to consult the manual of your device on how to do that. After doing so the router capabilities of your equipment will be disabled as only the modem functionality will be used. For those using PPPoA things are more complicated as you will need a PPPoA-to-PPPoE client modem.
At this point network connectivity among your network devices will be lost so you will need to login to your router directly either using a monitor and keyboard or the serial port in the APU2 case.
PPP configuration
There are two relevant configuration files for rp-pppoe
. The first is your
peer file and it is configured on per ISP basis. So create a new file for
your ISP in /etc/ppp/peers
and ensure that readable only by root
# touch /etc/ppp/peers/ISP && chmod 600 /etc/ppp/peers/ISP
A basic peer file is provided below. I’ve added comments on the bits you will need to tweak.
# If you need to debug your connection remove this line
nolog
noipdefault
# make the new ppp interface the default external route
defaultroute
defaultroute-metric 300
# detach pppd when connection is established
updetach
# replace eth0 with the interface that is connected to your modem
plugin rp-pppoe.so eth0
# do not log passwords
hide-password
lcp-echo-interval 20
lcp-echo-failure 3
noauth
# as this is a xDSL connection make sure that interface is always up
persist
# this is the number of failed attempts before the PPP daemon gives up on
# connecting to your ISP. 0 means keep trying in perpetuity
maxfail 0
# replace this with the username provided by your ISP
user "user000@ISP"
# compression
bsdcomp 15
deflate 15
# IPv6; if your ISP supports it
+ipv6 ipv6cp-use-ipaddr
# this is not a typo; it is literally "ipv6", space and comma
ipv6 ,
You might notice there is no authentication information on the peer file. This
is configured in the secrets
file. Depending on whether your ISP uses PAP or
CHAP for the authentication you will need to add the following to
/etc/ppp/pap-secrets
or /etc/ppp/chap-secrets
respectively. As PAP is
inherently insecure virtually all ISPs use CHAP for authentication.
# do not forget the quotes
# client server secret IP addresses
"user000@ISP" * "passw0rd"
Interface configuration
We are now in a point that we can setup the actual network interfaces. In
Alpine this configuration lives in /etc/network/interfaces
pretty much as it
is in Debian-based distributions. There are a series of stanzas that define the
IPv4 and IPv6 behaviour of the listed interfaces. Any network cards not
mentioned will remain unconfigured (ie. down). In our case we will configure
two physical interface, the loopback and the PPP interface. Of course if your
connection to your ISP is not PPP you will need to forgo the relevant stanza.
# Loopback interface; nothing complex here
auto lo
iface lo inet loopback
address 127.0.0.1
netmask 255.0.0.0
iface eth0 inet static
address 192.168.0.2
netmask 255.255.255.0
broadcast 192.168.0.255
pre-up /sbin/ip link set eth0 up
up ifup -f ppp0=ISP
down ifdown -f ppp0=ISP
post-down /sbin/ip link set eth0 down
iface eth1 inet static
address 192.168.1.1
netmask 255.255.255.0
broadcast 192.168.1.255
iface eth1 inet6 static
address 2001:db8::1
netmask 64
Points of interest
In the configuration file above eth0
is the interface connected to the modem,
as per our convention, the same as the one mentioned in the PPP peer file.
Although, physically, it is the external interface its role will be superseded
by the ppp interface so its only purpose at the moment is to trigger the
activation of the ppp client (the up & down parts). There are three caveats
here:
- You will need to assign an address on a different subnetwork
- Once
eth0
is brought up it will trigger the creation of theppp0
interface. The argument of this function (the part after theppp0=
) must be the same as the filename of your peer file. - If you are not using PPP then this is your real external interface and
you will need to assign its address in a fashion that your ISP mandates.
If this is a direct ethernet link you will need to either assign it the
address your ISP gave you or set it to
dhcp
.
Further down eth1
is the LAN-facing interface. This defines the address and
subnet mask of our local (IPv4) network. Nothing complicated here just choose a
private subnet of your preference or if you are lucky enough to have IPs to
spare a public one.
Although IPv4 is quite straightforward, the IPv6 assignment merits a little
more thorough discussion. In the case above I have assigned a static IPv6
prefix that my ISP gave me. If your prefix is dynamic you will need to omit the
whole section (we will use DHCP later on) or add a Unique Local
Address which is an
address from the fc::/7
block. Use this
page to generate a subnet. Please note that
fc::/7
address are not routable from the open internet and are homologous to
the private IPv4 addresses but it will allow you to have your IPv6 network up
even if connectivity with the outside world is lost.
IPv6 Prefix delegation
No matter if you have a static or dynamic IPv6 address your ISP will most probably assign it to you through a process called DHCPv6 Prefix Delegation (DHCPv6-PD). DHCPv6-PD is a process through which a delegating router (the one on your ISP side) is assigning and IPv6 prefix to a requesting router (your router) in a fashion similar to how DHCP works for local networks. If you have a static IPv6 prefix you can technically hardcode it and waive the whole process but DHCPv6-PD has the added benefit of providing your router with the necessary routes as well as the default gateway automagically. As an interface can have multiple addresses DHCPv6-PD will not replace the existing IPv6 addresses from the requesting interface but add to them.
There are four different tools that can do DHCPv6-PD. Dibbler, WIDE-DHCPv6, ISC dhclient and dhcpcd. All work as expected but I have opted for dhcpcd. ISC dhclient can’t do DHCPv6-PD over PPP links, WIDE-DHCPv6 is not really maintained and between Dibbler and dhcpcd I went with the most universally accepted option (dhcpcd is literally everywhere); plus it gets very frequent updates.
To enable prefix delegation you will need an instance of dhcpcd running. In my
case I only use dhcpcd on my router for PD so I went ahead and edited the main
configuration file: /etc/dhcpcd.conf
. However if you need a DHCP client for
another reason then it’s probably better to use a separate instance of dhcpcd
for IPv6 only. I have found this option to be simpler but if you feel
adventurous go ahead and try with a simple configuration file. In any case you
will need the following absolute minimum configuration to get PD working.
duid
ipv6only
noipv6rs
denyinterfaces eth0
nohook lookup-hostname
nohook resolv.conf
nogateway
interface ppp0
ipv6rs
iaid 1
ia_pd 1/::/64 eth1/0/64
I agree that this is indeed quite cryptic. duid
generates a unique
identifier for the interface used. Then
ipv6only
and noipv6rs
force dhcpcd into IPv6-only operation and disable
router solicitations for the active interface. We then block dhcpcd from using
eth0
(the interface connected to the modem) as we will use ppp0
to get our
address. Of course, if you are not using PPP you might want to omit this. The
following three lines disable some dhcpcd-intrinsic hooks as we don’t want
dhcpcd to touch anything other than move the address from our external
interface into our network.
The most important bit is the stanza that follows. In summary this will assign
an IPv6 address to the eth1
interface (the LAN-facing) by delegating an
address from the external interface. In this case is ppp0
but it can be an
actual physical interface. For this particular interface we proceed to enable
router solicitation (ipv6rs
) and assign a unique identifier to it (the iaid
bit). The actual delegation is done in the following line. What this line does
is take whatever address (the ::
bit) that the interface with iaid 1
(ie.
ppp0
) has and assigns an address to eth1
that with a /64
netmask. The
0
bit here means that the resultant prefix has the same prefix length as
the delegation, practically assigning the whole delegated prefix to our
network. If you have multiple routers in your network then you will probably
need to increase this number to prevent allocation of addresses belonging to
a different network. By default dhcpcd will assign the ::1
suffix to your
delegated prefix to generate the address for the LAN-facing interface. So if
the delegated prefix is 2001:db8::/64
eth1
will get 2001:db8::1
assigned.
If you are not happy with that you can change the delegation to include an
additional part as in eth1/0/64/0
. The final part is the suffix you want
eth1
to have. 0
is a special value and will assign an autoconfigured value
(through SLAAC) to eth1
.
This is the end of part 3. If you are following this guide with Alpine linux
this is probably a good time to save your settings. So go ahead and lbu
commit
them. You can then proceed onto part 4 for the
firewall configuration