thinkpad keys on awesome WM

The last bit of configuration that my laptop required before I’d call it “usable” with the new window manager was related to the function keys. This doesn’t have anything to do with configuring the awesome window manager directly but it does address a few small configurations necessary to provide some functionality that I was used to having gnome do by default.

Linux has great support for Thinkpads in general and my x61s specifically. With basic power management packages installed and the kernel thinkpad_acpi driver loaded not only did S3 work fine but my Thinkpad function key to put my laptop to sleep worked out of the box! The only keys that didn’t work right out of the box were an easy fix.

Screen Brightness

Traveling as much as I do I find that I use the manual controls for screen brightness quite a bit. If you’re on a plane often times it’s really nice to be able to dial down the screen brightness to absolutely minimal levels to preserve your battery and your eyes. The gnome-power-manager is the gnome component that takes care of this and it’s simple enough to install. Nothing interesting here except a new found appreciation for how much Gnome does out of the box and why it’s so big.

Volume and Mute

Lastly configuring the volume buttons was a must. If you’re just interested in getting them to work, install the gnome-settings-daemon and add a command to your rc.lua file to run it. I spent a little time getting to the bottom of it and learned a little bit.

Fire up a terminal and run the xev command to see the keyboard events from each key. A regular keyboard key will generate some output like:

KeyPress event, serial 29, synthetic NO, window 0x1600001,
    root 0x105, subw 0x0, time 316658902, (470,254), root:(472,689),
    state 0x0, keycode 24 (keysym 0x71, q), same_screen YES,
    XLookupString gives 1 bytes: (71) "q"
    XmbLookupString gives 1 bytes: (71) "q"
    XFilterEvent returns: False

KeyRelease event, serial 29, synthetic NO, window 0x1600001,
    root 0x105, subw 0x0, time 316658990, (470,254), root:(472,689),
    state 0x0, keycode 24 (keysym 0x71, q), same_screen YES,
    XLookupString gives 1 bytes: (71) "q"
    XFilterEvent returns: False

Those are they key press and release events triggered by typing a ‘q’. Pressing one of the volume buttons looks a little different:

KeyPress event, serial 28, synthetic NO, window 0x1000001,
    root 0x105, subw 0x0, time 316864564, (132,42), root:(134,477),
    state 0x0, keycode 121 (keysym 0x1008ff12, XF86AudioMute), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x1000001,
    root 0x105, subw 0x0, time 316864684, (132,42), root:(134,477),
    state 0x0, keycode 121 (keysym 0x1008ff12, XF86AudioMute), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

You’ll notice that they keycode indicates the XF86AudioMute button was pressed this time instead of q but the XLookupString returns 0 bytes.

Basically the three volume buttons are is associated with virtual X keys: XF86AudioMute, XF86AudioRaiseVolume, XF86AudioLowerVolume. It’s pretty straight forward to use xbindkeys to map these to alsa commands to manually mute, raise or lower the volue. My .xbindkeys looked like this:

"amixer  set Master 2dB+"
  XF86AudioRaiseVolume

"amixer set Master 2dB-"
  XF86AudioLowerVolume

"amixer set Master toggle"
  XF86AudioMute

Some prefer to link these keys to the PCM volume control. I found that toggle (as well as mute/unmute) doesn’t work for the PCM channel. I’m honestly not sure what the PCM channel is even for so I reserve the right to change this in the future. There’s lots of howto’s out there with people implementing shell hacks to fake a mute / unmute for the PCM channel using xbindkeys if you’re interested enough to search.

So the above configuration and a quick entry in my rc.lua to kick off xbindkeys was enough to get this working. The one down side to using xbind keys: it doesn’t have a cool little volume indicator that pops up to show the volume level when you press your volume keys 🙂

managing IPsec packets with iptables

A few weeks back I upgraded my wireless router and added an racoon based IPsec VPN. When I built my first home router / wireless access point a few years ago I did so to get some experience configuring Linux systems and writing firewall rules. I’ve revisited this script a number of times as I’ve added new functionality to the access point and now I’ve added a few rules for IPsec traffic that I figured were worth mentioning here.

First off the script is a “default drop” policy. This means that any packets that don’t match a rule in the firewall ending in a jump to ACCEPT target are dropped. More specifically the default policy for the input, output and forward chains are DROP:

iptables --policy INPUT DROP
iptables --policy OUTPUT DROP
iptables --policy FORWARD DROP

This means that any traffic that doesn’t have an explicit rule that allows it to pass will be dropped. The design goal I had in mind is two write all rules that allow traffic to be as exact as possible so as to not match any unintended traffic. This is as close to mandatory access control for network traffic as I can figure.

Rules for IKE exchange

Hopefully I’ll get a chance to publish the whole script but it’s pretty long (600 lines or so) and needs some cleanup. But the rules I’ve added to allow the racoon server are pretty clean and they’re super useful so here they are:

The first stage of establishing the VPN tunnel is direct negotiation between the client and the access point (the wireless router in this case). The racoon server listens on ports 500 and 4500 and it negotiates directly with the clients racoon server on the same ports. I’m including just the raw rules here but you should wrap these up in functions to keep your scripts clean:

iptables --table filter --append INPUT 
  --in-interface extif                 
  --proto udp                          
  --destination ${PUBLIC_IP}           
  --dport 500                          
  --source  0.0.0.0/                   
  --sport 500                          
  --jump ACCEPT

iptables --table filter --append INPUT 
  --in-interface extif                 
  --proto udp                          
  --destination ${PUBLIC_IP}           
  --dport 4500                         
  --source  0.0.0.0/0                  
  --sport 4500                         
  --jump ACCEPT

iptables --table filter --append OUTPUT 
  --out-interface extif                 
  --proto udp                           
  --destination 0.0.0.0/0               
  --dport 500                           
  --source ${PUBLIC_IP}                 
  --sport 500                           
  --jump ACCEPT

iptables --table filter --append OUTPUT 
  --out-interface extif                 
  --proto udp                           
  --destination 0.0.0.0/0               
  --dport 4500                          
  --source ${PUBLIC_IP}                 
  --sport 4500                          
  --jump ACCEPT
}

Notice that I’ve limited the interface through which the IKE traffic can be accepted and transmitted as well as the IP of the server and the source and destination ports. The loosest part is that of the clients IP which we can’t know in advance. These rules are pretty standard, the interesting ones come next.

Rules for VPN traffic

So now our clients can negotiate security associations with the IKE server. This allows them to get IP addresses on the VPN network but they can’t talk to any other systems on the VPN or the other networks connected to the router (my file server etc).

VPN talking to internal network

To enable this we need FOWARD rules allowing traffic from the VPN network (10.0.2.0/24 that arrives on the interface ‘extif’) to go to the other network connected to the router (10.0.1.0/24 that arrives on the interface ‘wirif’). Typically this would look like:

iptables -A FORWARD         
  --in-interface extif      
  --source 10.0.2.0/24      
  --out-interface wirif     
  --destination 10.0.1.0/24 
  --jump ACCEPT

iptables -A FORWARD         
  --in-interface wirif      
  --source 10.0.1.0/24      
  --out-interface extif     
  --destination 10.0.2.0/24 
  --jump ACCEPT

These rules look pretty tight right? We’ve limited the the networks that can communicate and the interfaces on which the traffic should originate. We can do better though.

I’m particularly wary of the interface on the router that’s connected to the internet. The iptables rules above will allow the traffic we want to allow but it doesn’t require that the traffic from the 10.0.2.0/24 network arrive over the VPN! Theoretically an attacker that isn’t on the VPN could spoof traffic with the VPN IP and exchange packets with the protected 10.0.1.0/24 network. This is bad.

Policy Matching

So we need to add to these rules policy that will require the packets come from, and go to the VPN network through the IPsec tunnel. I’d never even heard of the iptables policy module till I was searching for the answer to this problem. Here’s what I came up with:

iptables --append FORWARD    
  --match policy             
  --dir in                   
  --pol ipsec                
  --mode tunnel              
  --tunnel-dst ${PUBLIC_IP}  
  --tunnel-src 0.0.0.0/0     
  --in-interface extif       
  --source 10.0.2.0/24       
  --out-interface wirif      
  --destination 10.0.1.0/24  
  --jump ACCEPT

iptables --append FORWARD    
  --match policy             
  --dir out                  
  --pol ipsec                
  --mode tunnel              
  --tunnel-dst 0.0.0.0/0     
  --tunnel-src ${PUBLIC_IP}  
  --in-interface wirif       
  --source 10.0.1.0/24       
  --out-interface extif      
  --destination 10.0.2.0/24  
  --jump ACCEPT

This allows the two networks to communicate, but this time it specifies that the packets must travel through the IPsec tunnel as we’d expect.

So now our VPN users can connect to the racoon server on the firewall and can talk to hosts behind the firewall. What’s left? Well my router / firewall also happens to have a dnsmasq server that offers clients DHCP leases and DNS service. The DNS service is particularly useful for those connecting to my storage server so they don’t have to memorize IP addresses.

Offering DNS services to VPN users

VPN users should be able to use the DNS service too (they don’t need DHCP since they get their IPs from racoon). The rules to allow this are very similar to the FORWARD rules above:

iptables --append INPUT     
  --match policy            
  --pol ipsec               
  --dir in                  
  --mode tunnel             
  --tunnel-dst ${PUBLIC_IP} 
  --tunnel-src 0.0.0.0/0    
  --protocol udp            
  --in-interface extif      
  --source 10.0.2.0/24      
  --source-port 1024:65535  
  --destination 10.0.1.1/24 
  --destination-port 53     
  --jump ACCEPT

iptables --append OUTPUT        
  --match policy                
  --pol ipsec                   
  --dir out                     
  --mode tunnel                 
  --tunnel-dst 0.0.0.0/0        
  --tunnel-src ${PUBLIC_IP}     
  --protocol udp                
  --source $10.0.1.1/24         
  --source-port 53              
  --out-interface extif         
  --destination 10.0.2.0/24     
  --destination-port 1024:65535 
  --jump ACCEPT

These rules are pretty self explanatory once you understand the syntax. There’s lots of info in these rules too, we identify the direction of the packets through the ipsec tunnel, the endpoints of the tunnel and the standard IP stuff: source address and port, destination and port as well as the interfaces.

That’s it. 8 rules are all that’s required to allow VPN users to connect, speak to hosts on my internal network and to talk to the DNS server. Using the policy match these rules are pretty exact … if there’s anyway I can make them better let me know in the comments.

T100 Engine Covers

In my first two years riding my motorcycle I learned a few things the hard way. Long story short I laid my Thruxton down twice, once on each side. They weren’t bad spills but I got a few cool scars out of the deal and so did my bike.

A few weeks ago I purchased new T100 (chrome!) engine covers and today I’m fixing up the last of the damage left over from my wipe-outs. The alternator cover isn’t too bad but the primary got beat up something aweful. Here’s what my covers looked like before:

Removing Old Engine Covers

The first and most obvious step is draining your oil. The primary and alternator covers are wet seals and if you break them you’re gonna leak all of your oil out on to your driveway / garage floor. I’ve planned this maintenance around an oil change anyway so I drained my oil completely and have a new oil filter ready to go.

I started on my primary cover: removed the bolts and started to pull. This thing wasn’t budging so I broke out my rubber mallet. That’s right, when all else fails hit it with a hammer … but not one that will scratch up your new chrome parts! A few good taps around the seams and the seal gave and started dripping oil all over the place. Have a pan ready and set yourself up on some cardboard to catch any stray drips.

The cover should come off easy enough but the seal is likely to break up leaving bits stuck around the edges. You’ve got to get all of this off before you can put the new cover and seal on so break out a razor and carefully scrape what’s left of the old seal off the engine. Be very careful not to get little bits of the seal on any of your engine’s internals. You do not want little bits of plastic floating around gumming up the works.

When you’re done the mounting surface on the engine should look nice and clean. Here’s what the primary side looks like (forgot to shoot the alternator side):

Alternator Cover

On the alternator side you’ll notice some wires that run out from between the engine case and the cover. These connect to the stator and power your electrical. The seals around these are a bit of a pain. You’ll have to transfer the coils to you new cover then worry about the wires.

When you reattach the alternator cover you’ll have to get your new seal in place but that probably won’t be enough. The wires have a rubber housing that you should seal up too. I opted to “borrow” some Form-A Gasket Sealant from my room mate.

This stuff is nasty. Get ready to apply it with your fingers and then spend some time scrubbing it off your hands later. You want to put enough on to fill the cracks but if you put so much on that it oozes out. It’s probably oozing out inside the case too which is not a good thing.

When you’ putting the the cover back on you’ll wish you had a few extra hands. Holding the seal, the wires and the cover in place at the same time is a pain, especially with the seal goop getting on everything. Once you juggle it all into place torque down the bolts to the spec (9Nm if I remember correctly which isn’t much).

The sprocket cover is easy in comparison. No seals no nothing. Just throw it on. Here’s what they look like, nice and shiny:

Primary Cover

The primary side doesn’t have any wires for you to worry about but it’s more of a pain. First off if you’re bike is on it’s kick stand the primary side will be tilted toward the ground which will make putting the cover back on much more difficult. Specifically there are a few metal pins that are seated in the cover and they’ll slide out much more easily if the engine is tilted downward.

Pay attention to the small cog at the lower front of the engine on this side. There’s a funny washer sitting over the pin holding it in place. This pin has a corresponding hole it will fit into on the inside of the primary cover. If you’re not careful while the cover is off this washer and pin may slip out. Be very careful of this.

Also on the primary side is the clutch leaver that you’ll have to transfer from your old cover to the new one. These are held in place by 7 or 8 hex screws that Triumph was kind enough to goop up with red locktite. This makes removing them very difficult and you’ve got to be extra careful to keep from stripping them.

I’ll admit that I stripped one but managed to get it out still. I had to take a trip to the local fastener shop in Syracuse to get a replacement. As much as the locktite is a pain when you’re removing the bolts it’s a good idea to use some when you put them in your new cover. Having one of these come loose in your engine would pretty much be the end of it.

I probably don’t have to say this but when you do transfer the clutch leaver over keep an eye on the set-up in the old cover and make sure you get everything in place right. It’s not hard but I’m sure it can be screwed up if you’re not careful. Be sure to keep track of the pin seated in the case that actuates the clutch. Mine kept dropping out of place when I was putting the cover back on.

Speaking of putting the primary cover back on, it’s a pain in the ass! If you’ve got an extra set of hands around you’re gonna need them. Here’s what it should look like when you’re done.

Oil and a Paryer

So when both covers are back on with the seals in place and torqued down, finish your oil change (change your filter etc). It’s not uncommon for the seals to leak a little bit at first until their seated. If they keep leaking after you’ve had the engine running for a bit try tightening down the bolts a little more but not too much. If this doesn’t fix your leak then something more serious went wrong (damaged seal?).

If you were looking at the pictures closely you’ll notice there weren’t any pipes on my Thruxton. I timed changing the engine covers with sending my pipes out to a local guy who runs a paint booth / powder coating shop out of his garage. More to come on that.

Xen Network Driver Domain: How

In my last post I went into the reasons why exporting the network hardware from dom0 to an unprivileged driver domain is good for security. This time the “how” is our focus. The documentation out there isn’t perfect and it could use a bit of updating so expect to see a few edits to the relevant Xen wiki page [1] in the near future.

Basic setup

How you configure your Xen system is super important. The remainder of this post assumes you’re running the latest Xen from the unstable mercurial repository (4.0.1) with the latest 2.6.32 paravirt_ops kernel [2] from Jeremy Fitzhardinge’s git tree (2.6.32.16). If you’re running older versions of either Xen or the Linux kernel this may not work so you should consider updating.

For this post I’ll have 3 virtual machines (VMs).

  1. the administrative domain (dom0) which is required to boot the system
  2. an unprivileged domain (domU) that we’ll call “nicdom” which is short for network interface card (NIC) domain. You guessed it, this will become our network driver domain.
  3. another unprivileged domain (domU or client domain) that will get its virtual network interface from nicdom

I don’t really care how you build your virtual machines. Use whatever method you’re comfortable with. Personally I’m a command line junkie so I’ll be debootstrapping mine on LVM partitions as minimal Debian squeeze/sid systems running the latest pvops kernel. Initially the configuration files used to start up these two domUs will be nearly identical:
nicdom:

kernel="/boot/vmlinuz-2.6.32.16-xen-amd64"
ramdisk="/boot/initrd.img-2.6.32.16-xen-amd64"
memory=256
name="nicdom"
disk=["phy:/dev/lvgroup/nicdom_root,xvda,w"]
root="/dev/xvda ro"
extra="console=hvc0 xencons=tty"

client domain

kernel="/boot/vmlinuz-2.6.32.16-xen-amd64"
ramdisk="/boot/initrd.img-2.6.32.16-xen-amd64"
memory=1024
name="client"
disk=[
    "phy:/dev/lvgroup/client_root,xvda,w",
    "phy:/dev/lvgroup/client_swap,xvdb,w",
]
root="/dev/xvda ro"
extra="console=hvc0 xencons=tty"

I’ve given the client a swap partition and more ram because I intend to turn it into a desktop. The nicdom (driver domain) has been kept as small as possible since it’s basically a utility that won’t have many logins. Obviously there’s more to it than just load up these config files but installing VMs is beyond the scope of this document.

PCI pass through

The first step in configuring the nicdom is passing the network card directly through to it. The xen-pciback driver is the first step in this process. It hides the PCI device from dom0 which will later allow us to bind the device to a domU through configuration when we boot it using xm

There’s two ways to configure the xen-pciback driver:

  1. kernel parameters at dom0 boot time
  2. dynamic configuration using sysfs

xen-pciback kernel parameter

The first is the easiest so we’ll start there. You need to pass the kernel some parameters to tell it which PCI device to pass to the xen-pciback driver. Your grub kernel line should look something like this:

module /vmlinuz-2.6.32.16-xen-amd64 /vmlinuz-2.6.32.16-xen-amd64 root=/dev/something ro console=tty0 xen-pciback.hide=(00:19.0) intel_iommu=on

The important part here is the xen-pciback.hide parameter that identifies the PCI device to hide. I’m using a mixed Debian squeeze/sid system so getting used to grub2 is a bit of a task. Automating the configuration through grub is outside the scope of this document so I’ll assume you have a working grub.cfg or a way to build one.

Once you boot up your dom0 you’ll notice that lspci still shows the PCI device. That’s fine because the device is still there, it’s just the kernel is ignoring it. What’s important is that when you issue an ip addr you don’t have a network device for this PCI device. On my system all I see is the loopback (lo) device, no eth0.

dynamic configuration with sysfs

If you don’t want to restart your system you can pass the network device to the xen-pciback driver dynamically. First you need to unload all drivers that access the device: modprobe -r e1000e. This is the e1000e driver in my case.

Next we tell the xen-pciback driver to hide the device by passing it the device address:

echo "0000:00:19.0" | sudo tee /sys/bus/pci/drivers/pciback/new_slot
echo "0000:00:19.0" | sudo tee /sys/bus/pci/drivers/pciback/bind

Some of you may be thinking “what’s a slot” and I’ve got no good answer. If someone reading this knows, leave me something in the comments if you’ve got the time.

passing pci device to driver domain

Now that dom0 isn’t using the PCI device we can pass it off to our nicdom. We do this by including the line:

pci=['00:19.0']

in the configuration file for the nicdom. We can pass more than one device to this domain by placing another address between the square brackets like so:

pci=['00:19.0', '03:00.0']

Also we want to tell Xen that this domain is going to be a network driver domain and we have to configure IOMMU:

netif="yes"
extra="console=hvc0 xencons=tty iommu=soft"

Honestly I’m not sure exactly what these last two configuration lines do. There are a number of mailing list posts giving a number of magic configurations that are required to get PCI passthrough to work right. These ones worked for me so YMMV. If anyone wants to explain please leave a comment.

Now when this domU boots we can lspci and we’ll see these two devices listed. Their address may be the same as in dom0 but this depends on how you’ve configured your kernel. Make sure to read the Xen wiki page for PCIPassthrough [4] as it’s quite complete.

Depending on how you’ve set up your nicdom you may already have some networking configuration in place. I’m partial to debootstrapping my installs on a LVM partition so I end up doing the network configuration by hand. I’ll dedicate a whole post to configuring the networking in the nicdom later. For now just get it working however you know how.

the driver domain

As much as we want to just jump in and make the driver domain work there’s still a few configurations that we need to run through first.

Xen split drivers

Xen split drivers exist in two halves. The backend of the driver is located in the domain that owns the physical device. Each client domain that is serviced by the backend has a frontend driver that exposes a virtual device for the client. This is typically referred to as xen split drivers [3].

The xen networking drivers exist in two halves. For our nicdom to serve its purpose we need to load the xen-netback driver along with the xen-evtchn and the xenfs. We’ve already discussed what the xen-netback driver so let’s talk about what the others are.

The xenfs driver will exposes some xen specific stuff form the kernel to user space through the /proc file system. Exactly what this “stuff” is I’m still figuring out. If you dig into the code for the xen tools (xenstored and the various xenstore-* utilities) you’ll see a number of references to files in proc. From my preliminary reading this is where a lot of the xenstore data is exposed to domUs.

The xen-evtchn is a bit more mysterious to me at the moment. The name makes me think it’s responsible for the events used for communication between backend and frontend drivers but that’s just a guess.

So long story short, we need these modules loaded in nicdom:

modprobe -i xenfs xen-evtchn xen-netback

In the client we need the xenfs, xen-evtchn and the xen-netfront modules loaded.

Xen scripts and udev rules

Just like the Xen wiki says, we need to install the udev rules and the associated networking scripts. If you’re like me you like to know exactly what’s happening though, so you may want to trigger the backend / frontend and see the events coming from udev before you just blindly copy these files over.

udev events

To do this you need both the nicdom and the client VM up and running with no networking configured (see configs above). Once their both up start udevadm monitor --kernel --udev in each VM. Then try to create the network front and backends using xm. This is done from dom0 with a command like:

xm network-attach client mac=XX:XX:XX:XX:XX:XX,backend=nicdom

I’ll let the man page for xm explain the parameters 🙂

In the nicdom you should see the udev events creating the backend vif:

KERNEL[timestamp] online   /devices/vif/-4-0 (xen-backend)
UDEV_LOG=3
ACTION=online
DEVPATH=/devices/vif-4-0
SUBSYSTEM=xen-backend
XENBUS_TYPE=vif
XENBUS_PATH=backend/vif/4/0
XENBUS_BASE_PATH=backend
script=/etc/xen/scripts/vif-nat
vif=vif4.0

There are actually quite a few events but this one is the most important mostly because of the script and vif values. script is how the udev rule configures the network interface in the driver domain and the vif tells us the new interface name.

Really we don’t care what udev events happend in the client since the kernel will just magically create an eth0 device like any other. You can configure it using /etc/network/interfaces or any other method. If you’re interested in which events are triggered in the client I recommend recreating this experiment for yourself.

Without any udev rules and scripts in place the xm network-attach command should fail after a time out period. If you’re into reading network scripts or xend log files you’ll see that xend is waiting for the nicdom to report the status of the network-attach in a xenstore variable:

DEBUG (DevController:144) Waiting for 0.
DEBUG (DevController:628) hotplugStatusCallback /local/domain/1/backend/vif/3/0/hotplug-status

installing rules, scripts and tools

Now that we’ve seen the udev events we want to install the rules for Xen that will wait for the right event and will then trigger the necessary script. From the udevadm output above we’ve seen that dom0 passes the script name through the udev event. This script name is actually configured in the xend-config.xsp file in dom0:

(vif-script vif-whatever)

You can use whatever xen networking script you want (bridge is likely the easiest).

So how to install the udev rules and the scripts? Well you could just copy them over manually (mount the nicdom partition in dom0 and literally cp them into place). This method got me in trouble though and this detail is omitted from the relevant Xen wiki page [1]. What I didn’t know is the info I just supplied above: that dom0 waits for the driver domain to report its status through the xenstore. The networking scripts that get run in nicdom report this status but they require some xenstore-* utilities that aren’t installed in a client domain by default.

Worse yet I couldn’t see any logging out put from the script indicating that it was trying to execute xenstore-write and failing because there wasn’t an executable by that name on it’s path. Once I tracked down this problem (literally two weeks of code reading and bugging people on mailing lists) it was smooth sailing. You can install these utilities by hand to keep your nicdom as minimal as possible. What I did was copy over the whole xen-unstable source tree to my home directory on nicdom with the make tools target already built. Then I just ran make -C tools install to install all of the tools.

This is a bit heavy handed since it installs xend and xenstored which we don’t need. Not a big deal IMHO at this point. That’s pretty much it. If you want your vif to be created when your client VM is created just add a vif line to its configuration:

vif=["mac=XX:XX:XX:XX:XX:XX,backend=nic"]

Conclusion

In short the Xen DriverDomain has nearly all the information you need to get a driver domain up and running. What they’re missing are the little configuation tweeks that likely change from time to time and that the xenstore-* tools need to be installed in the driver domain. This last bit really stumped me since there seems to be virtually no debug info that comes out of the networking scripts.

If anyone out there tries to follow this leave me some feedback. There’s a lot of info here and I’m sure I forgot something. I’m interested in any way I can make this better / more clear so let me know what you think.

[1] http://wiki.xen.org/xenwiki/DriverDomain
[2] http://wiki.xensource.com/xenwiki/XenParavirtOps
[3] http://wiki.xen.org/xenwiki/XenSplitDrivers
[4] http://wiki.xen.org/xenwiki/XenPCIpassthrough

Xen Network Driver Domain: Why

If you’ve been watching the xen-user, xen-devel or the xen channel on freenode you’ve probably seen me asking questions about setting up a driver domain. You also may have noticed that the Xen wiki page dedicated to the topic [1] is a bit light on details. I’ve even had a few people contact me directly through email and my blog to see if I have this working yet which I think is great. I’m glad to know there are other people interested in this besides me.

This post is the first in a series in which I’ll explains how I went about configuring Xen to bind a network device to an unprivileged domain (typically called domU) and how I configured this domU (Linux) to act as a network back end for other Linux domUs. This first post will frame the problem and tell you why you should care. My next post will dig into the details of what needs to be done to set up a network driver domain.

Why

First off why is this important? Every Xen configuration I’ve seen had all devices hosted in the administrative domain (dom0) and everything worked fine. What do we gain by removing the device from dom0 and having it hosted in a domU.

The answer to these questions is all about security. If all you care about is functionality then don’t bother configuring a driver domain. You get no new “features” and no performance improvement (that I know of). What you do get is a dom0, the most security critical domain, with a reduced attack surface.

Let’s consider an attack scenario to make this concrete: Say an exploit exists in whichever Linux network driver you use. This exploit allows a remote attacker to send a specially crafted packet to your NIC and execute arbitrary code in your kernel. This is a worst case scenario, probably not something that will happen but it is possible. If dom0 is hosting this and all other devices and their drivers your system is hosed. The attacker can manipulate all of your domUs, the data in your domUs, everything.

Now suppose you’ve bound your NIC to a domU and configure this domU to act as a network back end for other domUs. Using the same (slightly far-fetched) vulnerability as an example, have we reduced the impact of the exploit?

The driver domain makes a significant difference here. Instead of having malicious code executing in dom0, it’s in an unprivileged domain. This isn’t to say that the exploit has no effect on the system. What we have achieved though is reducing the effects of the exploit. Instead of a full system compromise we’re now faced with a single unprivileged domain compromise and a denial of service on the networking offered to the other VMs.

The attacker can take down the networking for all of your VMs but they can’t get at their disks, they can’t shut them down, and they can’t create new VMs. Sure the attacker could sit in the driver domain and snoop on you domUs traffic but this sort of snooping is possible remotely. The appropriate use of encryption solves the disclosure problem. In the worst case scenario attacker could use this exploit as a first step in a more complex attack on the other VMs by manipulating the network driver front ends and possibly triggering another exploit.

In short a driver domain can reduce the attack surface of your Xen system. It’s not a cure-all but it’s good for your overall system security. I’m pretty burned out so I’ll wrap up with the matching “How” part of this post in the next day or two. Stay tuned.

[1] http://wiki.xen.org/xenwiki/DriverDomain

Chrome Valve Cover

A few weeks ago the seal on my valve cover started leaking a bit of oil. It was very minor at first so I ignored it. Eventually it started leaking out on to my exhaust (headers) so I’d pull up to a light and notice a bit of smoke rising off my front end. That’s about the point when you can’t ignore the problem any more.

Replacing a seal is pretty easy especially a dry seal like the valve cover seal. I’ve been planning some upgrades though so I took the opportunity to blow some money. There’s some back story here though: this was my first bike and I learned to ride on it, the hard way. In my first summer I laid it down once on each side. The bike survived with minimal damage but the engine cover on the clutch side looks like someone went at it with a file. The alternator and valve covers got off easy but still got chipped up. Over time the hard coat on them started cracking noticeably.

Since I had to remove the valve cover I might as well replace it, right? Might as well get a chrome one too 🙂 I even managed to track down the chrome replacement on ebay for pretty cheep so that’s always nice. Now I really screwed this one up though: I didn’t take as many pictures as I should have. With that in mind here’s the before shots with the tank removed.

When the valve cover is off the cam shafts are exposed. It was all I could do to keep from grabbing my laptop and ordering some more aggressive replacement cams. One step at a time. First replace the seal which actually wasn’t in bad shape. It was a bit frayed at the edges but there wasn’t any serious wear that I could see.

This is the point where I got excited, threw the camera to the side, replaced the seal and threw the new cover on without taking any pictures. I’ll learn eventually. I did it by the book (well by the Haynes Manual). I put a bit of grease on the seal, fitted it into the cover and replaced the bolts at the specified torque. Here’s what it looked like after it’s all back together.

Sadly it’s still bleeding a bit of oil. Nothing as bad as it was so I’m thinking the gasket may just need to get seated. Also the grease I applied may be running out a bit. For now I’m just carrying a shop rag with me and hoping for the best.

I ordered the rest of the replacement covers in chrome from British Customs along with a bunch of other stuff. My next post largely depends on what arrives in the mail first.

Running OP for the First Time

OP is a little wonky to run the first time. Not because it doesn’t work but because it doesn’t appear to. Sounds strange right? Well the first time I fired it up (by running the run-op2 script in the root of the source tree) it loaded up the web page of one of the students working on the project. His name is Shou Tang [1].

Unfortunately OP loads most of his page, sometimes the whole thing, and then seems to get lost. Attempts to load any other page will fail. The little icon in the tab which indicates that it’s “thinking” continues to spin but nothing happens. If you fire up tcpdump and watch for http traffic you’ll see that OP is making web requests and getting responses but it doesn’t render the page at all.

Unfortunately there isn’t a whole lot of debug output. Since I’m not very familiar with the architecture yet there may be some debug that I just don’t know where to find. There is a warning that gets dumpted to the console indicating that a clientClosed signal is being ignored this warning is generated by a lot of pages, not just Shou’s page. I did get a few weird errors from X but I couldn’t seem to reproduce these reliably.

So to get OP working you need to fire it up using the run-op2 script and let it get all messed up by Shou’s page. Then pull down the Menu button that’s in the upper right side of the screen. Go into the Edit tab and select Preferences. In here change the default home page to something that won’t muck up the browser (I chose Google). Then restart the browser. This time you’ll start out on a different home page and hopefully this one won’t screw up OP.

I’m gonna hold off on speculating as to why Shou’s page messes up OP. Fixing this bug would be nice but it’s not really my focus. My next post will detail how OP starts up and hopefully some architectural details (which parts talk to each ether etc). Documenting this will be the first step towards laying out what a Type Enforcement policy (a la SELinux) for OP should look like.

[1] http://www.cs.uiuc.edu/homes/stang6/

OP browser install

Building / installing “research” software is always fun. OP was better than most as far as the building goes. There isn’t a way to install it (at least not through the build system) so we’ll leave that part out. For posterity the code I’m using is a tarball they put up on google code back in October [1]. I had hoped to use the svn tree that they advertise [2] but it’s just an empty directory, no code.

Their directions are pretty good. I started from their google code wiki page that has directions for doing the install on Ubuntu. I did the install on a Debian Squeeze system that I’m running as a VM on my laptop. OP uses the WebKit rendering engine and those of you familiar with building WebKit already know how long it’s gona take me to build this in a wimpy little VM 🙂

Packages

The first time running OPs build script it will fail. There’s a bunch of development software you’ll need that’s not part of a default Squeeze install. Save yourself some time and just apt-get install these packages:

apt-get install gcc g++ flex bison gperf qt4-qmake libqt4-dev libsqlite3-dev libphonon-dev libxext-dev x11proto-xext-dev libfontconfig1-dev

Some of these libraries like libphonon-dev and libxext-dev were discovered as dependencies through trial and error. I mean to say I ran the build script, it errored out with some cryptic error like a missing header file like SomethingPhonon.h and then I apt-cache searched for a development package with the keywords phonon and dev and found the right one. Trial and error is pretty time consuming when you’re compiling this on a very low powered machine. Some additional packages may be pulled in as dependencies but the above list should be enough to get you what you need. If you run into any problems recreating this let me know in the comments.

OP recommends that you install Qt directly from Nokia but everything built fine for me using the Qt4 shipped with Squeeze. There are webkit and libqt4-webkit packages on squeeze and I tried these first. I’m pretty sure the libqt4-webkit package is missing some headers that OP needs since the build failed looking for headers that are supplied in the Qt bindings from the WebKit source tree. Nothing’s perfect, just use the WebKit source and the Qt4 bindings that comes with it.

Building WebKit

This is the part where I start complaining about building WebKit. Not just how long it takes (that’s my laptops fault) but the crazy build system. I guess I’ve been spoiled by all the great open source packages out there that build with the standard ./configure && make && sudo make install. Webkit ships with an autobuild.sh which will bootstrap the standard gnu autotools infrastructure but it will only build the WebKit core, it won’t build the Qt bindings we need for OP.

OP goes above and beyond in that they ship a script that downloads the WebKit code from the “nightly build” that OP was developed against [3]). It applies a set of patches too.

You can build WebKit through the script supplied by OP or you can do it yourself. If you chose the latter all you need to do is:

wget http://builds.nightly.webkit.org/files/trunk/src/WebKit-r48592.tar.bz2
tar jxvf WebKit-r48592.tar.bz2
mv WebKit-r48592 web-app/WebKit
cd WebKit; cat ../webkit_patches/*r48592.diff | patch -p0; cd ../
./web-app/WebKit/WebKitTools/Scripts/build.sh --qt --release

That’s downloading the right nightly build, extracting it, renaming the directory (OP has this path hard coded in their scripts), patching it and running the build script. I did this manually because the build kept failing and I wanted to narrow down the problem. Even with all of the right libraries installed I was getting a strange error from g++ indicating that there was a bug in the compiler itself:

g++: Internal error: Killed (program cc1plus)
Please submit a full bug report.
See <file:///usr/share/doc/gcc-4.4/README.Bugs> for instructions.
make[1]: *** [obj/release/FrameLoader.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make[1]: Leaving directory `/home/myuname/opbrowser-release-2009_09_30/webapp/WebKit/WebKitBuild/Release/WebCore'
make: *** [sub-WebCore-make_default-ordered] Error 2

Google for this error real quick and usually the problem is the machine that’s doing the compile running out of RAM. There are some great mailing list posts with people compiling glibc on a system with 32MB of ram with 128MB swap space. That makes my VM look like a super computer (512MB of RAM and a 1GB swap disk). My first reaction was then to think that there was no way I was running out of RAM.

More swap!!

So how to test this? Run the build again and this time run in parallel the command free -m -s 2. This will poll your RAM and swap usage every 2 seconds printing some info to the console. Sure enough the build was using up all of my RAM and swap which is pretty ridiculous IMHO.

So just throw more ram at it right? Getting KVM to give this VM more RAM take a restart so we get on that giving it 1GB of RAM (double what it had previously) and leave the 1GB of swap alone. FAIL, free still shows us running out of both RAM and swap.

OK no messing around this time. On my host system I allocated a 5Gb KVM logical volume and passed this to the VM as an additional hard disk (another restart of the VM). I then dropped the old swap space and set this 5Gb disk as swap. This turned out to be enough. Watching free showed my swap usage going well over 2Gb … jeez that greedy. Something in this script is assuming that my system is pretty beefy.

One final problem I ran into was a significant number of undefined references turning up in the final linking. This is from the build failing so many times previously. Typically you’d hope the build system would rebuild anything that fails but that’s not the case here. In fact even if you run the build script with the --clean switch it doesn’t clean the enough to remove broken object files. I had to manually delete the WebKitBuild directory which is under the WebKit root and rebuild WebKit one last time. You’ll see this message when you’re done:

===========================================================
 WebKit is now built (2h:45m:25s). 
 To run QtLauncher with this newly-built code, use the
 "./run-launcher" script.
===========================================================

That’s right, almost 3 hours to build this beast.

Building OP

In comparison to WebKit, building OP was a breeze. The only additional libraries were a few from boost [4]. These are as follows.

apt-get install ant sun-java6-jdk libboost-dev libboost-regex-dev

Installing libboost-regex-dev will pull in a bunch of boost dev packages one of which is libboost-dev. I’ve included libboost-dev in the list above just for completeness.

I’m pretty sure the OpenJDK java packages would work but since we’re trying to minimize the possible problems we may run into I just grabbed the “non-free” sun packages. That way if I end up having to get in touch with the guys that wrote OP with a question / problem they won’t have the opportunity to say “we don’t support the OpenJDK packages, make sure you’re using the genuine Sun (Oracle?) Java”. If anyone gives this a go with the OpenJDK packages let me know how it turns out in the comments.

Once you’re done accepting the licensing agreement ::sigh:: run the build script and OP should be good to go. OP ships with a build script in its root named build.sh. Agian this makes some assumptions about your system since it passes make the -j4 flag. This is generally the option you’d pass to make if you’ve got 2 CPUs. Since my VM only has one I went through and removed it:

cat build.sh | sed 's/-j4//' > build-single.sh

Then run it and you should be good to go.

I couldn’t figure out how to actually install WebKit once it was built. OP takes this on by setting LD_LIBRARY_PATH and DYLD_LIBRARY_PATH environment variable in its launch script to contain the WebKit release library directory: web-app/WebKit/WebKitBuild/Release/lib. There is also a hard coded reference to that path in some of OPs Makefiles.

This can cause a problem if you don’t pass the WebKit build script the --release flag (like maybe you built it with --debug instead). OP won’t build right in this case. It will fail complaining about a bunch of undefined references. If you do this by mistake and you don’t want to rebuild WebKit (because it takes around 3 hours) you can just use a soft link.

So now it’s built. This post is long enough so I’ll comment on running OP next time.

[1] http://code.google.com/p/op-web-browser/downloads/list
[2] http://code.google.com/p/op-web-browser/source/checkout
[3] http://builds.nightly.webkit.org/files/trunk/src/WebKit-r48592.tar.bz2
[4] http://www.boost.org/

dnsmasq and racoon VPN

I’ve always used the standard dhcp3 server on my local networks (non-routable IPs). Never really knew of any other options and I didn’t look for any. As the few networks I manage have gotten larger I’ve wanted my DHCP server to be able to feed information into local DNS so I don’t have to maintain hosts files or remember IP addresses. I’ve heard horror stories about configuring BIND so I figured hooking up DHCP and BIND would be way too much work for my purposes.

After some digging I ran across dnsmasq [1]. It’s a DHCP server and a DNS proxy rolled into one. As it doles out DHCP leases it populates the DNS proxy with host names, just what I need. There are a good lot of howto’s out there for setting up dnsmasq so I won’t pollute the web with another one that’s likely not as good as the others. Frankly, dnsmasq can pretty much be configured with the information contained in its well documented example config file (provided as part of the Debian package).

What I will add to the inter-tubes is how I got dnsmasq to resolve names for VPN users connected to the racoon VPN that I’ve documented in a previous post [2] without interfering with other DNS configurations on the client. This requires a few modifications to the racoon server config and the client side up/down scripts. It also takes some resolvconf magic to finish the job.

Serving DNS info to VPN Clients

The configuration required to get racoon to send DNS information to clients as part of the mode_cfg is pretty straight forward.

    dns4 10.XXX.XXX.XXX;
    default_domain "vpn.example";

That’s it. The client side up script receives these config parameters in two new environment variables: INTERNAL_DNS4_LIST and DEFAULT_DOMAIN. The INTERNAL_DNS4_LIST reflects the fact that we can include the address of more than one DNS server. In this example we’ve only got one but we write our script such that it can handle the list.

In the up script we’ve got the DNS information now but what do we do with it? I’m no expert at building a resolv.conf files by hand and I really don’t want to be. We need a way to manage multiple DNS configurations at the same time such that when we need to resolve names for hosts on the VPN network they get routed to the DNS server configuration received from racoon. Other names we want resolved by whatever DNS configuration was in place when we brought up the VPN connection. The resolvconf program (yeah bad/confusing choice of names) almost does what we need.

Client Configuration with resolvconf

The man page for resolvconf is pretty straight forward but it leaves out one specific detail. By my reading of the man page I would think to call resolvconf as follows:

  echo -e "domain ${DEFAULT_DOMAIN}nnameserver ${DNS_IP}" | resolvconf -a ${INTERFACE}

Where INTERFACE would be the name of the interface we’re talking to the VPN through.

This doesn’t actually work though. After an hour of trying multiple configurations to see what I was doing wrong I thought to look at the script that the resolvconf package installed in my /etc/network/if-up.d directory. This script takes whatever DNS info was associated with the interface either statically in the interfaces file or dynamically over DHCP and feeds it into the resolvconf program. It does something funny though. The interface name used isn’t actually that of the interface. The script appends the address family to the interface name passed into resolvconf.

I tried using this convention for the VPN configuration scripts. I appended ‘.vpn’ to the interface name (very original I know) and this time the DNS info obtained over the VPN doesn’t stomp all over the existing DNS info (the configuration my laptop got from DHCP on the local network). The small addition to the racoon up script is as follows:

RESOLVCONF=$(which resolvconf)
INTERFACE=$(ip route get ${REMOTE_ADDR} 
    | grep --only-match 'dev[[:space:]][0-9a-zA-Z]*' | awk '{print $2}')
if [ -x ${RESOLVCONF} ]; then
    INPUT=""
    for DNS in ${INTERNAL_DNS4_LIST}
    do
        INPUT=${INPUT}$(echo "nameserver ${DNS}")
    done
    echo -n -e "domain ${DEFAULT_DOMAIN}n${INPUT}" 
        | resolvconf -a "${INTERFACE}.vpn" | logger -t "phaseone-up"
fi

This is a step in the right direction but it still doesn’t work exactly as we want.

The resolv.conf file generated by resolvconf after bringing up the VPN looks like this:

nameserver 192.XXX.XXX.XXX
nameserver 10.XXX.XXX.XXX
search home.example vpn.example

Here the 192.XXX.XXX.XXX DNS server was obtained by our network interface when it was brought up using DHCP. This is the DNS server on my home network. It knows the names of devices that have registered using DHCP and when searching for a hostname that’s not qualified the suffix appended is ‘home.example’. I leave off the top level suffix to prevent the proxy from forwarding bad search requests. The 10.XXX.XXX.XXX DNS server is the one that will resolve hosts on the VPN network. Again it knows the names of devices that have registered on the VPN network using DHCP and provides the search suffix of ‘vpn.example’.

Why This Doesn’t Work

Because the home DNS server is listed before the VPN DNS server it will be queried first. When asked for a host that exists on the VPN domain the query will first be sent to the DNS server on the home.example netowrk and the query will fail. The query will fall through to the next nameserver only in the case of a timeout or an error so the VPN DNS server will not be queried in this case and we can’t resolve names on the VPN network. If we switch their order manually we’ll be able to resolve names on the vpn.example network but attempts to resolve names on the home.example network will fail.

This situation is represented graphically here:

To make this more concrete, say we want to resolve the name for ‘bob’ (like if I were to run ‘ping bob’), a system on the home.example network. We’d expect the resolver to be smart enough to search through the two available DNS servers knowing their search domains. It could ask the vpn.example DNS server for ‘bob.vpn.example’ and if I didn’t find bob there it could then ask the DNS server on home.example for ‘bob.home.example’. If only the resolver functions in libc were this smart.
NOTE: we’d be in trouble if each network has a host named ‘bob’ but how to handle that situation is out of scope for this discussion.

For configurations that are relatively advanced we have to fall back on a DNS proxy like dnsmasq. Yes we’re already running dnsmasq as a DNS proxy on these two networks but the problem we’re running into is that the resolver on the client isn’t smart enough. The smarts we need are built into dnsmasq.

dnsmasq as a Client-side DNS Proxy

Installing dnsmasq on the client is painless. It’s already tied into the resolvconf system so its notified of changes to the reslover information but it preserves the behavior of the standard libc resolver described above. We can however statically configure dnsmasq to consult a particular DNS servers for a specific domain with one configuration line:

server=/domain/ip

For the network layout described we could add two lines to the dnsmasq.conf file to get the behavior we want:

server=/home.example/192.XXX.XXX.XXX
server=/vpn.example/10.XXX.XXX.XXX

Static configurations stink though (too easy) and with a little more work we can get the same effect with a short script:

#!/bin/sh                                                                       
# ip address from string to int                              
function inet_aton () {
    local count=3
    local int=0
    for num in $(echo $1 | sed -e 's/./ /g'); do
        let "int+=$num*256**$count"
        let "count-=1"
    done
    echo $int
}
pushd "/etc/resolvconf/run/interface/" > /dev/null
FILES=$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')
for file in $FILES; do
    ns=$(cat $file | sed -n -e 's/^[[:space:]]*nameserver[[:space:]]+//p')
    PARAMS+="uint32:$(inet_aton $ns) "
    domain=$(cat $file | sed -n -e 's/^[[:space:]]*domain[[:space:]]+//p')
    PARAMS+="string:$domain "
done
dbus-send --system  --dest='uk.org.thekelleys.dnsmasq' 
    /uk/org/thekelleys/dnsmasq uk.org.thekelleys.SetServers $PARAMS
popd > /dev/null

For this script to make sense it’s important to know that when the resolvconf system is passed DNS information for a particular interface it makes a file with the name of the interface in /etc/resolvconf/run/interface/. This last script is placed in the directory /etc/resolvconf/update.d/. Each script in this directory is run every time the resolvconf information is changed. In the script we extract the nameserver and domain information from each file and send it to dnsmasq through the dnsmasq dbus interface (which must be enabled in dnsmasq.conf).

That’s it. Now each time we make a connection to the VPN the racoon client scripts send the VPN DNS info into resolvconf. resolvconf then runs its update.d scripts and the new script that we’ve provided takes this DNS information and sends it through to dnsmasq through a dbus interface. That was a lot of work, but now my VPN works the way I want it to. Well worth the effort IMHO.

I’m no dbus expert but I don’t really like the dnsmasq dbus interface. All functionality for manipulating the servers is packed into one function. As you can see from the above script it’s just “SetServers”. The interface would be much more effective and much easier to use if this one function were broken up into several, like an “AddServer”, “RemoveServer” etc. The full documentation for the dnsmasq dbus interface can be found here [3]. Proposing a few patches to fix this up would be a fun summer project 🙂

Racoon IPsec VPN on Debian Lenny

I’ve been wanting to set up a “pure” IPsec VPN using racoon for a while now. Part just for fun, part because I can. I spent a weekend on it once a while back, didn’t make much progress, got sick of trying to figure out cryptic racoon debug output and then gave up (more pressing stuff, you know how it is).

Anyways I ran into a situation where I NEED a VPN now. I manage a few systems that are facing the internet so they’re constantly under attack (mostly bots trying to brute force ssh all the time). Remote administration over ssh is pretty much all I need but I’d like to be able to keep a closer eye on the hardware through the “Integrated Lights-Out” system (they’re HP Proliant servers). These I don’t want facing the internet. Similarly I don’t want the configuration interfaces for my switch facing the public either.

So what I needed was a management network that I could connect to through a VPN gateway remotely (typically known as a “roadwarrior” setup). The ALIX system I’ve been blogging about in the recent past is what I’m using as the gateway / server. This post is a quick run down of the contortions I went through to get this working and why I didn’t get it working just how I want it 😦

Requirements

  • racoon only, no L2TP
  • rsasig authentication
  • as little hard coded network configuration as possible on the client

I thought the above was pretty ambitious. Configuring racoon is pretty complicated but after pouring over the man page for racoon.conf I found the mode_cfg section which specifies the network configuration for the server to send out to authenticated clients. A little more digging turned up a few examples, particurlarly useful were the netbsd howto and the howto forge racoon roadwarrior configuration.

Both of these give a working example of using the hybrid_rsa authentication with mode_cfg. This isn’t exactly what I wanted but it solves 2 of my 3 requirements above so it’s a great start. Next was adding my own server and client certificates to the configuration and making sure that both the certificate and the remote identifier were being verified. I didn’t want to keep having to type in a password when connecting to the VPN so I moved on to getting rsasig authentication working. Naturally at this point all hell broke loose.

It took me forever to figure it out, but it looks like the ipsec-tools version that ships with Lenny (0.7.1) doesn’t play nice with rsasig authentication and mode_cfg. The client and server are able to negotiate phase 1 without any troubles when the client never requests the configuration data from the server. I tried all sorts of configuration combinations hoping to find something that worked with no luck. Eventually I ran across an old and unanswered post to the ipsec-tools users mailing list from a few years back describing the same problem I’m having with the 0.7.0 version of racoon. Probably safe to assume that this behavior is what I’m running into on the version 0.7.1.

At this point my options were to upgrade to a later version and hope the bug was fixed or use hybrid auth. Guess which one I chose … hybrid auth ain’t so bad 🙂 Yeah typing in a password is a PITA but both client and server can still be configured to check each others certs and asn1dns identifiers in phase 1 so very little (if any) security is compromised. 2 out of 3 requirements isn’t bad. None of the desired functionality was lost but I do have to supply a password each time I connect to the VPN. Meh.

Configurations

Since the articles on howto forge and netbsd.org are so good I won’t bore you with a full description of my racoon configuration since it’s very similar. I will include them here for completeness and cover the parts where they differ.

The server.racoon.conf is very similar except for the credential verification for the client and some details in the mode_cfg. I’m using the split_network directive to send routing information to the client so we don’t have to hardcode any routes. The scripts on the client side had to be changed to accommodate this but it wasn’t that hard (I’ll get to this in a second). Also notice that I’m using all class C networks (/24 in CIDR) so no routes need to be specified on systems plugged into the management network directly.

In my client.racoon.conf the only difference is in the verification of the servers credentials (certs). I started out testing using certificates generated from my own root CA. When this was deployed I got certificates from cacert.org which is a great service.

The significant changes on the client side were in the phase one up and down networking scripts. I really didn’t like the scripts from the howto forge article (some of it didn’t seem necessary). They were a great starting place though but since I’m using the split_network I had to be able to properly handle dynamically creating and removing these routes. The final scripts can be found here: client.phaseone-up.sh and client.phaseone-down.sh

If you look closely you’ll notice that in the phaseone-down script I flush all SAs when taking down the VPN. Obviously this isn’t what we want: we want only to delete the relevant SAs. Unfortunately version 0.7.1 of the ipsec-tools package doesn’t play well with the way Linux manages SAs so the deleteall setkey function doesn’t work right. Flush is all we’re left with unless we’re gona parse the SADB output for the SPIs we need. This bug was reported on the ipsec-tools devel mailing list with a patch and it seemed well received so it’s likely in a later release. I’ll put off writing fancy bash script and just upgrade racoon soon.

Hope this is useful to everyone out there setting up a roadwarrior friendly racoon VPN. Leave me a comment if this was useful or if any of it’s unclear.