OpenBSD Routing with PF

Last summer, I inhereited the bulk of the sysadmin duties at WUVT, the campus radio station, and have been in the process of improving their infrastructure. One project I've been working on is migrating our current router (pfsense, which I would not recommend) to an OpenBSD box. OpenBSD tends to work very well for pretty much any router application that's not consumer-grade or ISP-grade because hardware tends to be comparatively cheaper, incredibly secure, and much more extensible. The main downside tends to be lack of support contracts, but OpenBSD tends to be incredibly well-documented compared to Linux.

My favorite feature in OpenBSD (and other BSDs) is probably PF (the packet filter) which controls routing/NATing and the firewall. On Linux, this would involve using iptables instead, which is a major pain as you have to use its confusing shell interface rather than a simple config file. PF also eliminates the complex "chain" style that iptables uses, and allows you to update rules on the fly by simply rewriting the config file. Additionally, it supports anchors, which are essentially functions you can call on a ruleset.

Quality-of-service support is also built-in, which is a nice way to prevent a single user or service (bittorrent, for example) from hogging the entire pipe. Essentially, you can set different priority queues which are selected by the service, port, or interface using a connection. I haven't tested this in OpenBSD, but it works great for dealing with the congestion management practices of horrible ISPs.

Re: Dorm automation

I just recently saw Ben's post  on Dorm Automation ideas and felt I should share something similar I've done. Last year, I lived in Barringer Hall, a horrible dorm lacking both air conditioning and a thermostat for the radiator. We had fans in the windows, but it became a huge pain for me to get out of bed to turn them on and off whenever I wanted to change the temperature. Using an Arduino, ethernet shield, WRT54G, and spare components, I set out to create an unnecessarily complex system for controlling my fan wirelessly and satisfying my laziness. As it turns out, this was extremely easy to do by hacking together a bunch of sample code, simple circuits, bash scripts.

I installed OpenWrt on my router, which is a custom firmware designed to add lots of enterprise features on consumer hardware; it runs the Linux kernel, but not the full GNU userspace due to a lack of flash memory. It was already running a HTTP server, so I was able to just write a simple HTML page that included frames of external pages on the Arduino. On the Ardunio, I modified an example web server and had it also interface with a LM34 temperature sensor to display its output value, which was fairly easy to do. Hardware was equally simple, as I only needed a NPN transistor to amplify the signal from a digital ouptut pin and operate a solid state relay which controlled a 120VAC extension cord. I ended up putting it in a large enclosure to discourage questions from curious fire marshalls. While the whole setup was one big kludge, it worked well and I was the envy of my fellow engineering hallmates.

Unfortunately, I don't think I saved my final code, so I can't share it. I had planned to replace this whole setup with a more robust python daemon, but soon moved to an apartment with a real thermostat and disassembled it. In the future, I plan on replacing this with either something python based on a laptop that controlls a parallel port or a Cerebot board I have left over from 2534. My eventual goal is to have something more complex than Zack Anderson's setup.


Lately, I've been playing with Kerberos, which is an interesting protocol designed to solve a number of problems with mutual authentication. In larger networks, it's very convenient to have a central authentication database so users can use their same credentials across many machines. This would ordinarily be a simple problem to resolve; however, workstations and other services can't be trusted. Since one rogue workstation can compromise everyone's credentials, you need a system to verify both the authentication server and the client, which is where Kerberos comes in. Kerberos uses a "ticket-granting-ticket" system in which users authenticate with a password to a centralized server, which gives them a token that can be used to prove their identity to any "Kerberized" service. This is extremely convenient for single-signon applications in which it's a pain to have to enter a password for each service; additionally, users can manage a single password for all applications ins a Kerberos realm without any security risks.

One thing I've found useful is Kerberized SSH access, which lots of large institutions (e..g. university departments) happen to offer. Ordinarily, you have to install a SSH key on all machines you'd like to use or remember a password for all of those; under best-practices use, users have encrypted keys that require a password at each use. Kerberos can maintain a more secure environment while generally being more convenient, since tokens last for 24 hours and can't easily be stolen like SSH keys. Also, if a key needs to be revoked, Kerberos can destroy all tokens at once, which is beneficial if you forget which servers your key is on.

If you happen to have Kerberos credentials, it's generally fairly simple to setup with SSH. I only needed to include this line in my $HOME/.ssh/config:
Host *
    GSSAPIAuthentication yes
    GSSAPIDelegateCredentials yes
Getting a Kerberos token tends to only require running kinit user@REALM like such :
matt@badwolf> kinit user@ECE.VT.EDU
Password for user@ECE.VT.EDU:
matt@badwolf> klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: user@ECE.VT.EDU
Valid starting     Expires            Service principal
12/20/12 17:30:36  12/21/12 17:30:32 krbtgt/ECE.VT.EDU@ECE.VT.EDU
and then you can ssh without a password. You need to run kinit -R before your tokens expire if you don't want to have to enter a password to authenticate again. I've been meaning to daemonize this for convenience, but haven't had a need to lately. As a shameless plug, VTLUUG now offers free Kerberized shell accounts for those that come to meetings.

PXE Boot Adventures

The installfest for VTLUUG was this past weekend, and I was tasked with setting up a PXE boot server. For those unfamiliar with this, PXE (Preboot eXecution Environment) is a built-in feature on most newer motherboards that allows users to obtain a bootloader over the network for remote OS installations. The only requirements on the network side are a router capable of directing DHCP clients to a TFTP server and assigning a file path. Client machines can then download a bootloader (e.g. syslinux) image which provides a menu of kernels to choose from. Typically, only the minimum number of required files are stored on the TFTP server, so that clients can download the rest via faster protocols such as NFS or HTTP.

Setting up the server was not all that difficult, but there were a few setbacks. I started with a 64-bit Debian VM on my laptop with atftp-server and followed a basic tutorial I found online. Setup for this was fairly straightforward for the more common distributions with text installers- -you only needed to mount the netinstall ISO, copy the files to the TFTP root (/var/lib/tftp in my case) and make a bootloader entry pointing to the kernel for each OS.

Unfortunately, this did not always work. Distros like Ubuntu with fancy graphical installers could not be served entirely of of TFTP and required an NFS share for the rest of the content on the ISO. This was fairly easy to do with a "nfsroot=" string appended to the kernel line in the syslinux configuration. Eventually, I was able to get most common distributions (Ubuntu, CentOS, Fedora, Debian, etc) up and running on my VM, but Arch would not boot.

Since I needed a PXE server for another organization, I had everything up and running a few weeks in advance, and just rsynced all of my data to another Debian x64 server on campus. I figured I'd just open the TFTP port for the duration of installfest so everyone could boot remotely. The night before installfest, I found out that TFTP booting would not work at all over NATs, becaus e the UDP ports used were chosen randomly and therefore can't be forwarded in advance.

With less than 12 hours remaining, our options were limited to:
  • Setting up an iPXE server and handing out USB drives
  • Making another PXE boot server
  • Hauling a server across campus and up serveral flights of stairs
  • Learning IPsec and setting up a point-to-point VPN
  • Using the original (albeit outdated) VM on my laptop
We ended up picking a combination of these and had a rather interesting network configuration. I brought a router to assign DHCP leases and pointed the TFTP boot server to a bridged interface to my VM. We also setup an iPXE server elsewhere on campus, which was much easier to install (yet unsupported by nearly all motherboards). To solve this, I was able to set a menu entry on my PXE VM to point to the iPXE kernel, and we had a few flash drives with the iPXE bootloader to hand out. Unfortunately, the iPXE installation had intermittent connectivity issues, possibly due to DHCP timeouts on my router's dnsmasq server.

Installfest was a much larger success than in years past, probably due to our promotion at Gobblerfest and spamming of all the listservs. We ended up with 27 successful installations in a few hours, mainly composed of Fedora, Ubuntu, and Arch Linux. Less popular distros included Sabayon, OpenBSD, FreeBSD, DragonflyBSD, and Rebecca Black Linux (yes, that's a thing).