OpenWRT and VLANs

2007-12-30

I can't even count the number of times I thought to myself "Wouldn't it be great if OpenBSD ran on the Linksys WRT boxes?" I still haven't managed to find the time to learn how to port OpenBSD, but I have found an alternate solution.

The OpenWRT project has finally released a stable build of Kamikaze which consists of a major rewrite and architecture shift from the previous White Russian build. The most noticeable change with Kamikaze is that userspace configuration is no longer stored in NVRAM, which solves a whole slew of issues that could arise if you accidentally wiped the wrong mtd device or something (not that anybody would ever do that...) All of the configuration is now stored in a sensible /etc/config folder with a common format for all of the options and separate files for different bits of functionality. The most useful of which being /etc/config/network, which has some pretty nifty ways of creating new pseudo-interfaces and bridges. This type of setup also makes it a lot easier to play around with the hardware switch configuration which, among other things, supports VLAN trunking.

The default switch configuration looks something like this:

config switch eth0
    option vlan0    "0 1 2 3 5*"
    option vlan1    "4 5"

Each VLAN option line specifies a new VLAN to be created, with the specified ID. The string following the VLAN ID lists all of the ports that will be attached to this VLAN. Ports 0-3 are the four normally switched "LAN" ports, port 4 is the "WAN" and port 5 is connected to the CPU on board. You can create as many VLANs as you want, theoretically you can have as many as 4096 different VLANs.

You can manually set each port in a VLAN as tagged or untagged, by specifying 't' or 'u' right after the port number. By default, all ports are untagged except for the CPU port. The asterisk '*' at the end of a VLAN option sets the default VLAN.

Now that we've got that figured out, we can start to build some neat things. In my setup, I wanted a tagged port that would be connected to my OpenBSD box. One port would be used for the uplink, one for my internet connection, and the remaining three ports for LAN traffic. I also wanted to have all wireless traffic encapsulated in an isolated VLAN. The Linksys box plays no role at all in the routing or handling of the traffic. Everything is sent to the OpenBSD box for routing and filtering. My final configuration looks like this...

config switch eth0
    option vlan0    "0 4t"
    option vlan1    "1 2 3 4t 5"
    option vlan2    "4t 5"

config interface loopback
    option ifname   "lo"
    option proto    static
    option ipaddr   127.0.0.1
    option netmask  255.0.0.0

config interface lan
    option type     bridge
    option ifname   "eth0.1"
    option proto    static
    option ipaddr   10.50.1.254
    option netmask  255.255.255.0

config interface wireless
    option type     bridge
    option ifname   "eth0.2"
    option proto    static
    option ipaddr 10.50.2.254
    option netmask 255.255.255.0

In a perfect world, I could have left the CPU port out of the VLAN config completely and not created the eth0.1 bridge, but I wanted to retain SSH access to the WRT just in case things went wrong or I needed to change something. Port 4 becomes the uplink port, with every frame being tagged on the way out. Port 0 is connected to my cable modem, and Ports 1-3 are used for LAN. VLAN 2 exists for the purpose of encapsulating the wireless traffic, which must be routed through the CPU.

On the other side of the uplink, where the grass is greener and PF is usable, we create three VLAN interfaces, all using the same physical interface for tagged packets (in this case, rl0).

ifconfig vlan0 create
ifconfig vlan0 vlan 0 vlandev rl0 up
dhclient vlan0

Those three commands are all that are needed to tag packets and request a DHCP address from my cable modem. A quick tcpdump on vlan0 shows ridiculous amounts of ARP broadcast traffic, verifying that everything is working properly.

ifconfig vlan1 create
ifconfig vlan1 vlan 1 vlandev rl0 up
ifconfig vlan1 10.50.1.1 netmask 255.255.255.0 up

ifconfig vlan2 create
ifconfig vlan2 vlan 2 vlandev rl0 up
ifconfig vlan2 10.50.2.1 netmask 255.255.255.0 up

The vlan1 interface allows me to SSH to the WRT and communicate with other hosts on the three switched ports. vlan2 shows all of the traffic coming from wireless hosts. Unfortunately, with the wireless traffic routed this way, you only see legitimate traffic, none of the cool 802.11 headers that allow you to do neat things like passive scanning and whatnot. If that sort of functionality was desired, you could probably setup a layer-2 over TCP or UDP encapsulation with socat or something similar. OpenBSD's vlan(4) manpage details a setup with gif(4) that would provide that sort of functionality, assuming you could find a way to do the same on the WRT.

Now that the traffic is routed and the VLANs are setup, you can go crazy with OpenBSD's networking options, particularly PF. You could even take it a step further and setup multiple access points and allow users to roam between them, or segregate access completely. You could also make use of the new multiple SSID support for Broadcom chips in Kamikaze (forum thread) and create separate wireless networks on the access point and use the OpenBSD box as a wireless concentrator, a-la Cisco Aironet.

Hopefully this post gets you on your way to building something cool with nothing more than an old PC, a couple of NICs, and a pile of access points.

Next post - Sennheiser HD515 vs. Shure ES210