Create a router based on ArchLinux
Introduction
This is a description on how to set up a server based on ArchLunix to route network traffic between two interfaces. As an extension I also add some common router functions such as DHCP/DNS and NAT/firewall.
For configuring a server as described here at least two network interfaces are
needed. In my setup I used a virtual machine with 3 network interfaces,
1 management interface called enp0s3
and two interfaces for routing between
two networks, they are called enp0s8
and enp0s9
.
The interface enp0s8
is connected to network1
and enp0s9
is connected to
network2
.
Configuration
Routing is enabled by turning on forwarding in the kernel
# sysctl net.ipv4.conf.all.forwarding=1
This will turn on forwaring on all interfaces and set the ip_forward
flag.
Note that it is only temporary, it will not be persistent accross a reboot. To
make forwarding persistent add a sysctl conf file:
# echo "net.ipv4.conf.all.forwarding=1" | sudo tee /etc/sysctl.d/routing.conf
Configure IP addresses with netctl
The network interfaces that will be used for routing need to have static ip addresses so let’s start with that.
On ArchLinux netctl
can be used for handling network interfaces. In
order to use netctl
the interfaces need to be down otherwise interfaces
are considered to already be managed by some other service and netctl
does not
do anything. Bring down the interfaces:
$ sudo ip link set enp0s8 down
$ sudo ip link set enp0s9 down
If dhcpcd
is running the static/extra interfaces needs to be
disabled from getting managed by dhcpcd
. This is done by adding the following
line to /etc/dhcpcd.conf
:
allowinterfaces enp0s3
This will use DHCP on the ‘management’ interface and not the other interfaces.
Example
Interface enp0s8
and enp0s9
are connected to two different networks.
Assigning ip address can be done with ip addr
but for making it persistent
I’ll do it the netctl
way.
Create a netctl profile in the file /etc/netctl/enp0s8
containing:
Interface=enp0s8
Connection=ethernet
IP=static
Address='10.0.1.1/24'
And for the next interface create the profile: /etc/netctl/enp0s9
containing:
Interface=enp0s9
Connection=ethernet
IP=static
Address='10.0.2.1/24'
Now list available netctl profiles
$ netctl list
enp0s8
enp0s9
A *
will indicate interfaces that are up and configured.
Start profiles:
$ sudo netctl start enp0s8
$ sudo netctl start enp0s9
To make this configuration persistent:
$ sudo netctl enable enp0s8
$ sudo netctl enable enp0s9
Then set up a DHCP server to assign addresses to hosts on the two networks.
DHCP server
A simple choice for running a DHCP server is dnsmasq
. Install dnsmasq
$ sudo pacman -S dnsmasq
Configure dnsmaq in /etc/dnsmasq.conf
, the file contains a lot of config
lines that are commented out and one just have to find the needed config option
and enable it with the wanted parameters.
First specify the interfaces to listen to
interface=enp0s8
interface=enp0s9
there are other options here, for example you can list interface not to listen to instead, or the address to listen on etc.
Then configure ranges on which to hand out adresses
dhcp-range=10.0.1.100,10.0.1.250,12h
dhcp-range=10.0.2.100,10.0.2.250,12h
This will hand out addresses in the range 10.0.1.100 -> 10.0.1.250
on the
10.0.1.0/24 network and 10.0.2.100 -> 10.0.2.250
on that network.
The last number on the line is the DHCP lease time.
For debugging purposes it can be nice to turn on logging in dnsmasq. This
is done by editing dnsmasq service script. Open
/usr/lib/systemd/system/dnsmasq.service
and add the --log-facility
argument:
ExecStart=/usr/bin/dnsmasq -k --enable-dbus --user=dnsmasq --pid-file --log-facility=/var/log/dnsmasq.log
DNS
dnsmasq
also serves as a DNS server. It’ll use /etc/hosts
to resolve
hostnames. Start by specifying name and ip in /etc/hosts
10.0.1.50 server1
10.0.1.51 server2
Use dhcp-host
in /etc/dnsmasq.conf
to make the dhcp server hand out the ip
above to a server that identifies itself as the host name.
dhcp-host=server1
dhcp-host=server2
A server with host name server1
on network1
will now get the ip 10.0.1.50
and other servers can access server1
by host name and will have the name
resolved to the same ip.
Start and enable dnsmasq
service:
$ sudo systemctl start dnsmasq.service
$ sudo systemctl enable dnsmasq.service
Firewall
The linux kernel firewall iptables
is used to prevent access to hosts on the
two networks. In this example hosts on network2
(the 10.0.2.0/24 network on
enp0s9
) will be behind NAT and hidden outside that network. Hosts on
network1
are still accessible individually from network2
.
Add a rule to the nat table to replace the source address for hosts on
network2
for traffic that leaves to the other network
$ sudo iptables -t nat -A POSTROUTING -o enp0s8 -j MASQUERADE
It is also possible to use SNAT
instead of MASQUERADE
here since the ip
address is static, perhaps also perferable for performace reasons.
Then add a rule to the filtering table to block traffic from network1
to
network2
, i.e. traffic entering enp0s8
and going out on enp0s9
.
$ sudo iptables -I FORWARD -i enp0s8 -o enp0s9 -j REJECT
This will also block responses to traffic going out from network2
to
network1
. That is fixed by adding a filtering rule to allow packets that are
part of an already established connection.
$ sudo iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
Make the firewall rules persistent by saving current config to a config file
$ sudo iptables-save | sudo tee /etc/iptables/iptables.rules
$ sudo iptables-save -t nat | sudo tee -a /etc/iptables/iptables.rules
Then enable the service
$ sudo systemctl enable iptables.service
Conclusions
As seen here it’s really simple to create a Linux router. Of course there is a lot more that can be done that will make things more complicated. Anyway, I had a lot of fun exploring this!