Friday, October 28, 2016

Configuring Raspberry Pi as a router

I'm setting up a little test network for IoT devices, one isolated a bit from my home network. This is a perfect job for a computer like the Raspberry Pi (or similar computers, such as the Odroid-C2, which is what I'm actually using here). I thought I'd blog the setup details in case anybody else wanted to setup their own isolated home network.

Choice of hardware

The Raspberry Pi B v3 is a fine choice, but there are many alternatives. I'm using the Odroid C2 instead. It's nearly the same, but the chief difference for my purposes is that the Ethernet adapter is native. On the RPi, the Ethernet adapter is actually connected via USB. Network utilities don't like USB Ethernet as much.

The choice of hardware dictates the operating system. Download the latest version of Ubuntu for the Odroid C2. They keep moving around where to get it, but you can google "odroid c2 downloads" to find it. My version is Ubuntu MATE 16.04 LTS.

Your home network

Your home network likely uses the addresses This is also the range that most of the devices I'm testing will use as their initial defaults. Therefore, I've changed my network to something strange that won't share the address range, like 10.20.30.x.

sudo bash

On the Internet, help text always prefixes sudo in front of every line. This is tedious. I just open up a root bash prompt instead. All the examples below assume that.

Reconfigure the hostname

The first step for me is always reconfiguring the hostname. I've got a bunch of small systems and VMs, and if I don't remember to reset the hostname, I go crazy. You do this by editing the files  /etc/hostname and the file /ets/hosts.

vi /etc/hostname
vi /etc/hosts

I'm naming this device odroidrouter.

Reconfigure networking

All these small computers seem to be using some form of Debian, which usually uses the ifupdown method of configuring the network. It's in flux and always changing, but my current configuration looks like the following.

vi /etc/network/interfaces

auto usbnet0
allow-hotplug usbnet0
iface usbnet0 inet static

iface usbnet0 inet6 auto

auto eth0
allow-hotplug eth0
iface eth0 inet static

I've got two Ethernet interfaces, the built-in one (eth0) and the additional one I get from plugging in a USB dongle (usbnet0).

The WAN interface, the one point to the Internet, is usbnet0

The local interface, the one on the isolated network, is eth0. That's because I'm going to be running network tools like tcpdump on that interface, so I want the "real" Ethernet to be in that direction.

Turn on routing

You need to turn on the routing bit. The best way to do it is in the sysctl.conf file.

vi /etc/sysctl.conf

There's usually a commented-out line with the parameter we want, just uncomment-it-out. Otherwise, add the line:


Note that there are many other ways of doing this. For example, routing could be off until you plug in the Ethernet cable, using the ifupdown configuration files. In that case, you'll need a line that does something like

echo 1 > /proc/sys/net/ipv4/ip_forward

You'll also want to run that command if you want to immediately test things out, without having to reboot.

Turn on NATting

Reconfigure that iptables firewall with the following to turn on NAT.

iptables -t nat -A POSTROUTING -o usbnet0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o usbnet0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i usbnet0 -o eth0 -j ACCEPT

But these configuration change aren't persistent. To make them persistent, you need to install iptables-persistent.

apt-get install iptables-persistent

It'll ask you while installing if you want to make the changes persistent. Do that. Otherwise, later you'll need to do this:

iptables-save > /etc/iptables/rules.v4

Turn on DHCP server

Some of the devices on our isolated network come with static IP addresses, like Some use DHCP, so we'll need to install a DHCP server.

apt-get install isc-dhcp-server

You'll then need to edit the configuration file. The defaults are fine, but you need to tell it which address ranges you need to give out:

subnet netmask {
  option routers;
  option domain-name-servers,;
  option domain-name "";

You then want to tell the DHCP service which Interface to use when serving requests, so you don't serve them on the wrong adapter.

vi /etc/default/isc-dhcp-server

Make sure you have the following line, usually by editing the line that is already there in the defaults


If you want to turn on DHCP before rebooting, you can start the service:

service start isc-dhcp-server

It's easy to make a mistake with the configuration files, but dhcpd gives no error messages. To get them, you need to install syslog. It's a pain in the ass.


I want my isolated devices to get to the Internet, but I don't want them to be able to access my internal network. Therefore, I need to add a firewall rule that prevents them from accessing my own subnet. However, this rule needs to be done so that I can still reach the router/firewall machine from my subnet. Therefore, the rule needs to be placed on the eth0 interface, and not generically in the stack or on the usbnet0 interface. Note that I use the -I directive here, to insert the dropping rule before the forwarding rules configured above.

iptables -I FORWARD -d -i eth0 -j DROP

Logging into the test machine I can confirm that I can ping my local subnet before this firewall rule, but not after. But, I can still log into the gateway device from my local network.

Port forwarding

Now that I have my victim device safely on an isolated network, with outbound access to the Internet, I need to forward ports from the Internet to the victim machine. The ports that it is listening on are:

There are two steps here. First, I need to configure my home router to forward ports to this RPi router. The second step is to use IP tables to forward those ports to the target device.

One question is whether you use the same port number. In other words, I want to forward Telnet on port 23 from the Internet to this device. I could therefore write firewall rules that just changes the IP address. However, in case of accidents, this is unsafe. I'd rather have a brittle configuration that'll easily fail rather than allow hackers into my local network.

Therefore, on my firewall router, I've mapped port 50001 to port 23 on the target victim device.

iptables -A PREROUTING -t nat -i usbnet0 -p tcp --dport 50001 -j DNAT --to

On my home Internet gateway, I do the reverse, mapping Internet-visible Telnet port 23 to port 50001 on my RPi firwall. In other words, the two mappings I've done are:

internet:23 -> ->

Capturing packets

Now that I've I've isolated my test device, I'll want to monitor it. I'll want to monitor what traffic it sends out to the Internet when I turn it on. Then, when I expose it to the Internet to get infected, I want to monitor all the traffic going into and out of it.

Because the log files can get big, I'll wan to rotate the log files. I've chosen to rotate them every hour. I do this with the command:

tcpdump -i eth0 -G 3600 -w 'cameradome-%Y%m%d-%H.pcap'

BTW, since I need to leave this process running in the background when I log off, I run this under a screen session. I suppose I should just run this during startup, detached as a demon, but I"m too lazy.

Since this is an RPi class device, I probably don't want to log the packets to the SD card. Instead, I log them to an external USB flash drive. Thus, before executing tcpdump I did:

mkdir ~/lexar
mount /dev/sda1 lexar

Rate limiting

In my setup, the isolated devices may be used to execute DDoS attacks. I don't want that, obviously. To fix this, I can rate limit. There are various ways of traffic shaping on Linux for advanced purposes, but really, I just want something simple -- anything that will stop this from being useful in a DDoS.

There are many extensions to iptables (man iptables-extensions). One is a simple extension, called limit, that limits how often a rule will match per second (per hour, per day, etc.). The easiest way to use that extension is on the NAT rule, to prevent how many connections per second can be NATted. Change the above rule to this:

iptables  -A FORWARD -i eth0 -o usbnet0 -m state --state RELATED,ESTABLISHED -m limit --limit 10/sec -j ACCEPT

This is the same NAT rule above, but we use the -m option to tell it to use the matching extension module named "limit". Then, we use the new --limit option (works only with this module) to set a rate of 10-per-second. What that means is that after this rule triggers 10 times in a second, on the 11th, it won't.

However, the packet will still be forwarded. That's because this is the default action for iptables if no rule matches. It'll be sent with the wrong IP address, so it can never receive responses. That'll block TCP based DDoS, but not those that do simple UDP and ICMP floods. We need to do something that, by default, blocks forwarded packets if no rule matches.

One way is to set the default policy for the chain named "FORWARD":

iptables -P FORWARD DROP

This seems to block everything. I don't know why, my iptables foo isn't good enough. So instead, I just add a block rule that matches the NAT rule:

iptables -A FORWARD -i eth0 -o usbnet0 -j DROP

The -A parameter means to append this rule after all the others. If a rule matches before this, then iptables stops walking the chain, and never reaches this drop rule. When nothing matches, because of the rate limiting feature, then the packet will reach this rule and get dropped.


Unknown said...

Thank you for this. I saw your dramas on Twitter...

Did you look at static ips in dhcpcd.conf? I thought i read that somewhere and it seems to work better.

Unknown said...

Hello Guys, I want to fully recommend the efforts of shadow duty he is a guru he increased my credit score from poor credit and helped my nephew upgrade her school grade and GPA without any traces, he is geniune and reliable you will be grateful. +1 325 216 9100