Raspberry Pi vlan Routing

gs108t

(Update: this is probably not a 100% safe setup and the PI’s 10 Mb/s network interface limitation makes this solution somewhat limited. But it was a fun exercise ;-))

I wanted to expand my home network beyond Apple Airport’s three LAN ports, into three separate networks: a Internet-of-Things network, where my TellstickNet could live; a demilitarized zone where I could put a web server without worrying too much; and a local area network where my files would be safe. To get this I thought I needed a firewall with three network interfaces plus switches for the three networks.

I happened to mention my plans to my colleague and network expert Tobias Genberg. He said something like this:

“You have a Raspberry Pi, right?”

“Yes…”

It turned out my plan was needlessly complicated and expensive. What I could do instead was to get a “smart switch”, a switch capable of running virtual networks, and then use my Raspberry Pi as a firewall slash router. I decided to proceed with this solution.

I knew this was going to be a challenge, because I had to learn a lot – how to configure the switch; how to setup networking on the Pi with virtual interfaces, vlans, dhcp, and dns; learn to understand how iptables works. And of course, I did not know what I did not know when I started. I put a lot of hours into this project, and while my friends and family suffered, I learned a few things about networking and Linux.

Switch configuration

There are a lot of switches out there. I fell for the Netgear GS108T v2 – a capable and yet affordable piece of switch. It is made out of metal and is quite heavy for its small size. A solid impression.

A Virtual LAN (VLAN) is a group of devices on one or more LANs that are configured so that they can communicate as if they were attached to the same wire, when in fact they are located on a number of different LAN segments. Because VLANs are based on logical instead of physical connections.

On this switch, vlan numbers can be any number between 1-4093, except vlan 1-3 which are reserved. I came up with a naming scheme that includes the port numbers, so WAN on port 1 becomes 11 and LAN on port 2 and 3 becomes 23. Easy to remember.

  • 11 WAN – the Internet connection
  • 23 LAN
  • 45 IOT – Internet of Things
  • 66 DMZ

WAN cable goes into port 1 and Pi router connects to port 8.

A vlans on the GS108T have untagged and tagged ports. Devices connected to an untagged ports will not notice that they are indeed on a vlan and will have the same experience as when connecting to a “normal” network. The tagged port however is where the vlan magic happens. The tagged port 8 will enable the router to distinguish between several logical networks on the same physical port.

vlan membership

The table below illustrates how ports on each vlan are configured.

1 2 3 4 5 6 7 8
vlan 11 U T
vlan 23 U U T
vlan 45 U U T
vlan 66 U T

Each port are assigned a default vlan.

pvid configuration

Ingress Filtering enabled on all ports except router port 8 (picture is not showing this). To my understanding, when enabled, ethernet frames from other vlans are discarded, which seems like a good thing. When disabled, all frames are forwarded, essential for the vlan routing to work.

Router Prerequisites

I decided to run the Pi on Raspian using NOOBS to install it. A small but very important detail: ip forwarding must be enabled for all this to work (I learned this the hard way)!

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

Uncomment the line below in /etc/sysctl.conf to enable packet forwarding for IPv4.

net.ipv4.ip_forward=1

vlan

Raspian does not come with vlan out of the box, so the vlan package has to be installed:

apt-get install vlan

The 8021q kernel module has to be loaded

echo 8021q >> /etc/modules

If everything works …

lsmod | grep 8021q

… should output something like this:

8021q                  18046  0 
garp                    6335  1 8021q

DHCP

We need to install a dhcp server, I choose to run isc-dhcp-server.

apt-get install isc-dhcp-server

There’s a few tools that are very useful when debugging network issues.

apt-get install tcpdump

Vconfig

Adding vlans to the router is done with the vconfig command. There are different naming conventions for vlans. I choose to use the interface.vlan-number convention, e.g eth0.11, which I think is the default one. But to be sure, just run:

vconfig set_name_type DEV_PLUS_VID_NO_PAD

Adding the vlans:

vconfig add eth0 11
vconfig add eth0 23
vconfig add eth0 45
vconfig add eth0 66

Interface Definitions

auto lo

iface lo inet loopback

# eth0 is not used
auto eth0
iface eth0 inet static
	address 0.0.0.0
	netmask 255.255.255.255

# WAN
auto eth0.11
iface eth0.11 inet dhcp
	vlan_raw_device eth0

# LAN
auto eth0.23
iface eth0.23 inet static
	address 192.168.23.1
	netmask 255.255.255.0
	mtu 1500
	vlan_raw_device eth0

# IOT
auto eth0.45
iface eth0.45 inet static
	address 192.168.45.1
	netmask 255.255.255.0
	mtu 1500
	vlan_raw_device eth0

# DMZ
auto eth0.66
iface eth0.66 inet static
	address 192.168.66.1
	netmask 255.255.255.0
	mtu 1500
	vlan_raw_device eth0

# Extra
auto eth0.77
iface eth0.77 inet static
	address 192.168.77.1
	netmask 255.255.255.0
	mtu 1500
	vlan_raw_device eth0

iface default inet dhcp

DHCP Configuration

ddns-update-style none;
ddns-domainname "home.local";
ignore client-updates;

# option definitions common to all supported networks...
option domain-name "home.local";
option domain-name-servers 192.168.23.1, 192.168.45.1, 192.168.66.1;

default-lease-time 600;
max-lease-time 7200;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# LAN
subnet 192.168.23.0 netmask 255.255.255.0 {
  range 192.168.23.10 192.168.23.30;
  option routers 192.168.23.1;
  option broadcast-address 192.168.23.255;
  option domain-name "lan.home.local";
}

# IOT
subnet 192.168.45.0 netmask 255.255.255.0 {
  range 192.168.45.10 192.168.45.30;
  option routers 192.168.45.1;
  option broadcast-address 192.168.45.255;
  option domain-name "local";
  option domain-name-servers 8.8.8.8, 8.8.4.4;
}

# DMZ
ddns-update-style none;
ddns-domainname "home.local";
ignore client-updates;

# option definitions common to all supported networks...
option domain-name "home.local";
option domain-name-servers 192.168.23.1, 192.168.45.1, 192.168.66.1;

default-lease-time 600;
max-lease-time 7200;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# LAN
subnet 192.168.23.0 netmask 255.255.255.0 {
  range 192.168.23.10 192.168.23.30;
  option routers 192.168.23.1;
  option broadcast-address 192.168.23.255;
  option domain-name "lan.home.local";
}

# IOT
subnet 192.168.45.0 netmask 255.255.255.0 {
  range 192.168.45.10 192.168.45.30;
  option routers 192.168.45.1;
  option broadcast-address 192.168.45.255;
  option domain-name "local";
  option domain-name-servers 8.8.8.8, 8.8.4.4;
}

# DMZ
subnet 192.168.66.0 netmask 255.255.255.0 {
  range 192.168.66.10 192.168.66.30;
  option routers 192.168.66.1;
  option broadcast-address 192.168.66.255;
  option domain-name "dmz.home.local";
}

Iptables

Iptables is a tool for manipulating, filtering, redirecting, and blocking network traffic rules on Linux, which forms the foundation of the firewall functionality in this setup.

I put all the iptables rules in a script to make it all more manageable.

#!/bin/sh

WAN=eth0.11
LAN=eth0.23
IOT=eth0.45
DMZ=eth0.66

NET_RANGE=192.168.0.0/16

WAN_NET=192.168.11.0/24
LAN_NET=192.168.23.0/24
IOT_NET=192.168.45.0/24
DMZ_NET=192.168.66.0/24

# Delete existing rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

## General rules
# -P option describes the default policy for these chains
# Filters packets destined to the firewall. 
iptables -P INPUT DROP

# Filters packets to servers accessible by another NIC on the firewall. 
iptables -P FORWARD DROP

# Filters packets originating from the firewall 
iptables -P OUTPUT ACCEPT


## ICMP
# Accept icmp but limit them to 2/s on the outside
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 2/s -i $WAN -j ACCEPT
# Set no limits on other interfaces
iptables -A OUTPUT -p icmp --icmp-type echo-request ! -i $WAN  -j ACCEPT
iptables -A INPUT  -p icmp --icmp-type echo-reply ! -i $WAN  -j ACCEPT


# Defense for SYN flood attacks by limiting the acceptance of TCP segments 
# with the SYN bit set to no more than five per second
iptables -A INPUT -p tcp --syn -m limit --limit 5/s -i $WAN -j ACCEPT


# Allow loopback access
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -s 127.0.0.1/32 -j ACCEPT


## ssh
# Allow ssh on all interfaces - a good password, fail2ban, 
# and two factor authentication will hopefpull keep us safe
iptables -A INPUT -p tcp -m multiport --dports 22 -j ACCEPT


## WAN
# NAT
iptables -A POSTROUTING -t nat -o $WAN -s $NET_RANGE ! -d $NET_RANGE  -j MASQUERADE
# Drop Private Network Address On Public Interface
iptables -A INPUT -i $WAN -s $NET_RANGE -j DROP
# Prior to masquerading, the packets are routed via the filter
# table's FORWARD chain.
# Allowed outbound: New, established and related connections
# Allowed inbound : Established and related connections
iptables -A FORWARD -t filter -o $WAN -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -t filter -i $WAN -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT


## LAN
iptables -A INPUT -s $LAN_NET -i $LAN -j ACCEPT
# Block input from other networks
iptables -A INPUT ! -s $LAN_NET -i $LAN -j REJECT
iptables -A FORWARD -d $LAN_NET -j ACCEPT
iptables -A OUTPUT -s $LAN_NET -i $LAN -j ACCEPT


## IOT
# Only accept access from LAN
iptables -A INPUT -s $LAN_NET -d $IOT_NET -j ACCEPT
# Reject others
iptables -A INPUT -s $LAN_NET ! -d $IOT_NET -j REJECT
iptables -A FORWARD -d $IOT_NET -j ACCEPT
iptables -A OUTPUT -s $IOT_NET -i $IOT -j ACCEPT


## DMZ
iptables -A INPUT -s $DMZ_NET -j ACCEPT
# Block DMZ from doing outward connections
iptables -A OUTPUT -s $DMZ_NET -j REJECT

iptables-save 
 

… and then I made another script which wipes all rules. Believe me, it can be very useful. Iptables is not too hard to understand, but when you don’t, you often find yourself locked out.

#!/bin/sh

iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

iptables-save
iptables -L

Conclusions

I’ve been running this setup for a couple of weeks now without (knowingly) being hacked. If you see places for improvements, I would like to hear about them.

Thank you Tobias for helping me out 😉

Advertisements

4 thoughts on “Raspberry Pi vlan Routing

  1. that’s very interesting!
    i have a question: does the Raspberry Pi as Router will limit the traffic speed because of its lower speed 100Mb/s network adapter on a 1000Mb/s VLAN switch (e.g. GS108E), when RPi routes packages across different VLANs?

    1. Yes, I think that is the case. If we are expecting gigabit speeds the PI definitely becomes a limiting factor here. My Internet connection is just 10 Mb/s and most of the LAN traffic happens over WiFi, so in my case that’s not really an issue. Traffic between nodes inside a vlan should be unaffected. At least that’s what I’m thinking.

  2. Hi,
    I’m trying to do the same with my Banana Pi as you did with the Raspberry Pi. I wonder about two things:
    1. Did you define on what interfaces the DHCP-Server shall listen to? From where does the DHCP-Server know which address range shall be used? Or is this defined by the static network address?
    2. Your listing of the /etc/dhcp/dhcp.conf has its content twice. Copy’n’paste error?

    Thanks for sharing your work. I will use this to separate my private network from a lab network and a public open wifi (I will have to figure out if this is also applicable to use as Freifunk router).

    I hope that the Banana Pi has the power to really increase network speed as it has a Gigabit interface… Let’s see.

    1. I did this as a way of learning-by-doing iptables and vlan. Looking back at this now it’s hard for me to recall all the details – I simply don’t deal with iptables on a daily basis. I stopped using this setup mainly because the 10 Mbit/s limitation of the PI interface (great thing with that 1 Gbit/s Banana Pi!) and because I didn’t completely trust it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s