Raspberry PI Router

I am doing this for a number of reasons. Mostly because the home router that comes with my net connection has some serious issues. So of these include problems like broken multicast between dual band wireless, randomly breaking IPv6 routing, hijacking tcp connection and redirecting them to the router page if the net connection is down and for other reasons of flexibility. This will really show just how powerful a pi can be as a router. It does seems to perform well up to around 100mbit. Though I did not look at the performance of wireless too much anything serious I have on my network is connected by a cable simply because there is too much wireless interference at 2.4Ghz to actually have any useful bandwidth.

Basic setup

For this I started off with a fresh rasbian image. The first obvious steps is to update the install and setup some various things though raspi-config like timezone information. I also have a pile of additional hardware like an extra USB Ethernet and two USB wireless adaptors.

Lockdown

Its important to lock the pi down. Since part of the router will be reachable by the internet. So to this I added my own username and locked out the pi user account by replacing the password hash for the pi user in /etc/shadow with an asterisk which will make logging into that account impossible. I also add my new username to the same groups as the pi user by editing /etc/group.

For the new username I added I also copy /etc/sudoers.d/010_pi-nopasswd to /etc/sudoers.d/010_myuser-nopasswd and change the username in the new file to match my username. This will give my new account the the ability to become root.

I can also now enable the ssh though the raspi-config utility. For my new account I can also add my ssh keys to the new account and also replace the password hash for that account in /etc/shadow. Though be aware this will also now prevent local logins to the pi. So you may want to leave this step until the end or skip it completely. Or alternatively set a password for root to be able to login locally which ssh will block remote logins for.

Basic bridge setup

Since the pi is going to be acting as a wireless access point for my house I am going to need to setup a bridge between the Ethernet port and the wireless lan. For this I add the following file to /etc/network/interfaces.d/br0 This will give the pi a static ip address and also set the mac address of the bridge interface to the same as the Ethernet card. For some reason raspbian has named my network card "enxb827ebb22a9d"

auto br0
iface br0 inet static
    address 10.172.0.254
    netmask 255.255.255.0
    bridge_ports enxb827ebb22a9d
    post-up ip link set br0 address b8:27:eb:b2:2a:9d

I can now bring the bridge interface up by installing bridge utils "apt-get install bridge-utils" and then running "ifup br0". We will add other network interfaces to this bridge later on when we are setting up the wireless access points

Since there is now a static ip address setup we can also disable dhcpcd. We do this by running "systemctl stop dhcpcd && systemctl disable dhcpcd". This is required as we want to stop dhcpcd from doing an auto config on any of our network interfaces

We also need to take the ip address off the Ethernet interface now. So we add another file in /etc/network/interfaces.d/enxb827ebb22a9d

auto enxb827ebb22a9d
iface enxb827ebb22a9d inet manual

Dropping private data

This step is options but its something that should actually be done in almost every home router but basically isn't. This will drop any data which is attempt to send to private networks. We can simply use a dummy network device to do this. We can do this by adding /etc/network/interfaces.d/dummy0

auto dummy0
iface dummy0 inet manual
    pre-up modprobe dummy
    pre-up ip link del dummy0 ; ip link add dummy0 type dummy
    post-up route add -net 192.168.0.0 netmask 255.255.0.0 dev dummy0
    post-up    route add -net 10.0.0.0 netmask 255.0.0.0 dev dummy0
    post-up    route add -net 172.16.0.0 netmask 255.240.0.0 dev dummy0
    post-down ip link del dummy0

Wireless access points

Since I want a dual band router that works in both 2.4Ghx and 5Ghz ranges. We are going to need two access points to be configured. I plan to use two different usb adaptors for 2.4Ghz and 5GHz. For this additional adaptor I have to install some extra drivers which were available from http://www.fars-robotics.net/install-wifi which is a great script to download pre built drivers for raspbian

This is where its likely that you can start to run into problems with specific wireless drivers. For example the pi3 on board wireless nic won't support 4addr mode which means it cannot be added to the bridge. So I will show an example of adding both a bridged and routed wireless interfaces. You can test a wireless card for this feature by running "iw dev wlan0 set 4addr on" it will return "command failed: Operation not supported (-95)" for a wireless nic that won't support it.

Bridged example

Add another interface in /etc/network/interfaces.d/wlx000f600763ec which will bring the interface up and set the 4addr mode on. Then add it to the br0 interface as another network card. You can test this with "ifup wlx000f600763ec"

auto wlx000f600763ec
iface wlx000f600763ec inet manual
    pre-up iw dev wlx000f600763ec set 4addr on
    pre-up ifconfig $IFACE up ; brctl addif br0 $IFACE

Routed example

For a routed mode we effectively add another network to /etc/network/interfaces.d/wlx000f003609df

auto wlx000f003609df
iface wlx000f003609df inet static
    address 10.172.1.254
    netmask 255.255.255.0

We also need to actually turn the wireless interface into a access point. Lets start by installing hostapd with "apt-get install hostapd" Then we add the following to /etc/hostapd/hostapd.conf make sure you change the ssid and passwords to suit your needs. Its also a good idea to change the country codes as well. As different countries have different restrictions on wireless frequencies.

Adding a 2.4Ghz access point (802.11g)

interface=wlx000f600763ec
ssid=Test2.4
hw_mode=g
channel=0
ieee80211d=1
country_code=GB
ieee80211n=1
macaddr_acl=0
auth_algs=1
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_passphrase=password
rsn_pairwise=CCMP

Adding a 5Ghz access point (802.11ac)

interface=wlx000f003609df
ssid=Test5
hw_mode=a
channel=0
ieee80211d=1
country_code=GB
ieee80211n=1
ieee80211ac=1
macaddr_acl=0
auth_algs=1
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_passphrase=password
rsn_pairwise=CCMP

To also turn on the hostpd.conf file that we just added we need to change /etc/default/hostapd and make it point to our configuration

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Yo can either run hostpd.conf manually or just restart it using "systemctl restart hostapd". The access points should become visible to devices and they should be able to connect

DHCP Server

Since we will be the router we also want to hand out addresses to machines on the network. We will need to setup a dhcp scope for the br0 network interface which will take care of Ethernet and the wireless interfaces that are bridged. For each wireless interface that is not bridge it will need its own dhcp scope

Install dnsmasq "apt-get install dnsmasq"

For each interface we need to support we can add the config to /etc/dnsmasq lets starts with /etc/dnsmasq/br0

interface=br0
listen-address=10.172.0.254
bind-interfaces
domain-needed
bogus-priv
dhcp-range=10.172.0.50,10.172.0.250,30d

And for a routed wireless interface

interface=wlx000f003609df
listen-address=10.172.1.254
bind-interfaces
domain-needed
bogus-priv
dhcp-range=10.172.1.50,10.172.1.250,30d

Routing

We need to add some values to turn linux into a router so we can add /etc/sysctl.d/90-router.conf

net.ipv4.ip_forward = 1

Internet connection

Finally we can start setting up an internet connection. For my use case I have a pppeo modem which connects to a VDSL line which gives about 20mbit upstream and around 70mbit downstream. Since the pi network card can only do 100mbit. I am going to add another one for the connection.

Lets add yet another network interface. So we add /etc/network/interfaces.d/enx001150e7461a Its also worth pointing out here that pppeo doesn't need to use IP addresses to communicate. So I didn't bother giving the network interface an ip address

auto enx001150e7461a
iface enx001150e7461a inet manual

Lets install the tools "apt-get install pppoe pppoeconf pppstatus"

The pppoeconf is a great tool to generate a pppoe configuration. It will probe each network interface until it finds the modem. Then prompt for various details like usernames and passwords. The only shortfall here is that it does not setup iptables rules for doing nat. It also completed missing anything to do with IPv6.

The pppoeconf is a great tool to generate a pppoe configuration. It will probe each network interface until it finds the modem. Then prompt for various details like usernames and passwords. The only shortfall here is that it does not setup iptables rules for doing nat. It also completed missing anything IPv6 related. By default it will put the settings into /etc/ppp/peers/dsl-provider. You can also bring the link up / down manually by running poff dsl-provider or pon dsl-provider.

To fix the iptables nat problem we can create a shell script that is run when the link comes up in /etc/ppp/ip-up.d/firewall this script is run with a number of parameters. We are specifically interested in the first parameter since its the ppp interface. So our script will look something like this. This also includes a number of port forwards to a web server which is also running on another pi. I have included a few port forwards here as an example as well.

#!/bin/bash

iptables -t nat -A POSTROUTING -o $1 -j MASQUERADE
iptables -t nat -A PREROUTING -i $1 -p tcp --dport 22 -j DNAT --to-destination 10.172.0.10
iptables -t nat -A PREROUTING -i $1 -p tcp --dport 80 -j DNAT --to-destination 10.172.0.10
iptables -t nat -A PREROUTING -i $1 -p tcp --dport 443 -j DNAT --to-destination 10.172.0.10

We also need to remove the rules again if the link goes down. So we have another script that does the opposite. in /etc/ppp/ip-down.d/firewall. Since I am lazy I am just going to remove all the rules. But if we had other network interfaces up at the same time we would need to do this more carefully! Another approach to this is to create a net iptables chain and then just have the ppp0 jump to it so that only one rule is added / deleted and the other chain is maintained in another script.

#!/bin/bash
iptables -t nat -F

IPv6

So far I have completely ignored IPv6 configuration. The pppoeconf tool also completely missed it. The ISP I use providers me with a /64 ipv6 on the ppp0 interface. To enable this I just add "+ipv6" and "ipv6cp-use-ipaddr" to /etc/ppp/peers/dsl-provider and use poff / pon to get pppd to restart which will put the network address on the ppp0 interface. However my ISP also give me a IPv6 /48 address range. In order to get this to work I can just add it to /etc/network/interfaces.d/br0 as another inet6 static address.

We also still need to make it a router for IPv6 and to advertise it as such so that the other hosts on the network can auto configure. There isn't a dhcp server involved in IPv6 this way. Many OS's also don't yet support DHCPv6. We simply need to add "net.ipv6.conf.all.forwarding = 1" to /etc/sysctl.d/90-router.conf just like we did with IPv4 earlier.

We also need to install radvd with "apt-get install radvd" and create a basic config file that will make the pi advertise IPv6 routes to the lan.

interface br0
{
    AdvSendAdvert on;     

    MaxRtrAdvInterval 30;

    prefix 2a02:8010:613a::/64
    {
        AdvOnLink on;
        AdvAutonomous on;

    };

    route ::/0
    {
        AdvRoutePreference high;
        AdvRouteLifetime 300;
        RemoveRoute on;
    };
};

```text
The above is only a sample. Since I have a /48 and I am only using a /64. It means I can also add IPv6 ranges to the wireless cards that are not bridged as well.


I was having a problem here where pppeo / pppd was not setting a default route for the internet connection. So I add the following script to /etc/ppp/ipv6-up.d/defaultroute rather than get involved in debugging pppd and trying to figure out why it was not being setup correctly
```text
#!/bin/bash
ip -6 route add 0::/0 dev $1

Testing

Its useful to do a reboot to make sure the device will come up with all the parts enabled. It's also recommended to do some things like cable pull's between the pi and the network and the modem to make sure the internet connection can also recover should something go wrong. pppeoconf is pretty robust these days and will almost always recover the internet connection.

Performance

I did some speed tests with the pi. It did indeed perform well. I was able to use the full amount of network bandwidth from my isp.

The only drawback here is that the wireless -> LAN can be slightly slower that what my previous router had. However it had serious issues with 2.4ghz clients communicating with 5Ghz clients.

I do know that there is a performance problem with raspbian when using tcpdump. It the link is overloaded then tcpdump will drops lots of packets. I have not had time to look into it yet but the other symtom of it is that ksoftirqd uses 100% cpu time.

Cleanup

There are some Bluetooth services enabled on a pi3. Then won't be needed so these can be disabled.

systemctl stop hciuart.service
systemctl disable hciuart.service
systemctl stop bluetooth.service
systemctl disable bluetooth.service

Additional stuff

There is still plenty more to do after this. So other things worth looking into

  • Adding firewall rules for IPv6
  • Install ifstat "apt-get install ifstat" then run "ifstat -i ppp0" It will produce stats.
  • Have a look at a redundant USB 3g connection if the internet connection does fail.
  • If you have complex router requirements. zebra can be used to support multiple routing protocols.
  • You can add UPNP support for port forwards. Such packages like miniupnpd, miniupnpc, minidlna are probably worth looking into.
  • Accurate bandwidth monitoring to check up on your ISP monitoring if you suspect they are taking "the piss"
  • Per host bandwidth accounting - https://github.com/mistralol/ipstats
  • IDS / IPS systems.
  • Advanced routing - http://lartc.org/howto/
  • Advanced routing - Priorities / limits for specific hosts / QOS etc...
  • More Advanced routing - Bonding multiple internet connection
  • Use of a VPN for being anonymous
  • dnsmasq - Force usage of dnssec (signed dns requests)


Did You find this page useful?

Yes No



Last Modified: 03 September 2017

Releated Posts


2017-09-02 - Raspberry PI - Router Guide
2017-03-17 - Raspberry PI - Simple RTSP Server
2013-02-14 - Linux - Getting sshfs to work
2012-12-04 - Linux - sudo without a password
2012-10-13 - Rasberry Pi - Alternative method to play video without omx gstreamer element
2012-10-10 - How to run tcpdump as root
2012-04-05 - Using gdb to debug a core file
2012-01-16 - Linux - Color Coding The Bash Prompt
2012-01-14 - Linux - Automatically set the DISPLAY environment variable in SSH connection
2012-01-06 - Adding extra swap space to linux