Linux bridge forward EAPOL 8021x frames

XenClient is no different from other Xen configurations in that the networking hardware is shared between guests through a bridge hosted in dom0 (or a network driver domain in the case of XenClient XT). For most use cases the standard Linux bridge will route your traffic as expected. We ran into an interesting problem however when a customer doing a pilot on XenClient XT tried to authenticate their guest VMs using EAPOL (8021x auth over ethernet). The bridge gobbled up their packets and we got some pretty strange bug reports as a result.

Just throwing “linux bridge EAPOL 8021x” into a search engine will return a number of hits from various mailing lists where users report similar issues. The fix is literally a one line change that drops a check on the destination MAC address. This check is to ensure compliance with the 8021d standard which requires layer 2 bridges to drop packets from the “bridge filter MAC address group“. Since XenClient is a commercial product and the fix is in code that is responsible for our guest networking (which is pretty important) we wanted to code up a way to selectively enable this feature on a per-bridge basis using a sysfs node. We / I also tested the hell out of it for a few days straight.

The end result is a neat little patch that allows users to selectively pass EAPOL packets from their guests across the layer 2 bridge in dom0 / ndvm and out to their authentication infrastructure. The patch is available opensource just like the kernel and is available on the XenClient source CD. It’s also available here for your convenience 🙂

mod_mono group initialization patch

About a month back I installed the latest mono release on on one of my servers. A friend of a friend needed a place to do some ASP.Net development. He’d previously had an account with a Windows ASP.Net web host but wasn’t happy with the support he was getting and was trying to cut costs (as everyone always is).

I had the space and the know how to get him up and running so I pointed him to the mono-project ASP.Net page and told him to be sure all of the .Net features he was using were supported by Mono. On my end I installed all of the necessary mono stuff from source which, on Debian 5.0 (Lenny) was very simple. I then set him up with an account just like everyone else that uses this system.

Typically I use Unix DAC Groups to separate users from eachother on the shared host. I create a group for each user (call it www-username) and add both the user and the apache user to this group. This way users can make files they wish to be served up by the web server readable by this group. Nothing fancy, standard DAC stuff.

Funny thing though: this set-up works for static web pages, php scripts etc but didn’t work for the mod-mono-server. The apache error logs showed a stack trace leading back to a permission denied exception on the directory serving up the test ASP web page I was using. This directory had the following permissions as showed by ls -l

drwxr-s--- 3 username    www-username 4096 2009-11-01 16:50 web_dir

The DAC permissions are set up to keep everyone out except the owner and the web server. The server is given read access through the shared group and I’ve also set the sticky bit on the directory to keep files created by the user readable by this group. This last bit isn’t relevant to the denial but it’s useful and apparent in the output above.

Time to debug! We know the apache user (www-data) is in this group and can access files owned by the shared group (www-username) but why not mono? First off the Apache2 server only starts the mono server, it doesn’t process the ASP.Net pages itself. Through the modules interface Apache2 forks off the mod-mono-server2 process which it then feeds requests for the ASP.Net pages. Looking at the output of ps we can check to see that the mod-mono-server2 process has the right effective user and group (which were both correct) but I don’t know of a tool to inspect the supplementary groups for a running process. So we turn to the mod_mono source code for details. Note: Wikipedia has a good explanation of what Unix supplementary groups are if you need more background.

I’m a pretty good C coder but I’ve never looked at the mod_mono code in my life and I know nothing about writing modules for Apache2. But to debug this all I needed was a basic understanding of Unix DAC users and groups. The first thing I looked for was the place in the code where the mono server is started: either a fork or an exec system call is where we should start. These calls are both made in a function called ‘fork_mod_mono_server’ in the mod_mono.c file … yeah that’s probably where we should start looking.

This function also makes calls to setuid and setgid which is the forked process dropping the root privileges of its parent and taking on the identity of a lesser privileged user and group (specified in the apache configuration). On Debian this is the www-data user and group. As I say above we’ve already verified that the uid and gid are being set properly, it’s the supplementary groups that seem to be missing. We can check to see what group membership the forked process has by calling getgroups. Add a few debug statements (ouput the group ids from getgroups to the apache log file), rebuild the module, install it and restart the server and we can see that our suspicions have been confirmed: the only group id returned is 0, the root group?

Yeah, that’s not right. After flipping through a few man pages it looks like the initgroups has the functionality we’re looking for. All we need to do now is pass it the group name for the apache group and it does all the hard work for us. A quick test shows that after rebuilding the module and restarting the server it now has the expected behavior: the mod-mono-server2 process is able to access files that are readable by this shared group!

Now that the problem’s been fixed we want to contribute the it back to the Mono project. I’ve never submitted a patch to a project as high profile as Mono before so I was very conscious about making this patch clean and easy. This wasn’t hard since it was only one system call 🙂 Still it’s important to use formatting and logging statements that are consistent with the rest of the code. After looking at the code around my small fix I added a debug statement to output some information about the group membership initialization and some error handling to output an error message should the system call fail.

After running this fix on two of my servers for a few days I sent the patch to the mono-devel mailing list. Kinda sucks that the mail archive thinks the attachment is a binary. ::shrug:: Either way I got an off-list reply the same day from Marek Harbersack saying that the patch had bee accepted and applied to the mod_mono svn tree! The patch is revision #145618 and they even gave me credit in the svn log!

Awesome.

Extracting table schema from database

As part of rehabilitating an old project I’ve had to go through a fairly sizable MySQL database and extract the table structure. I’m doing this for knowledge capture. Currently the schema is only known to the internals of the software that operates on the database, there’s no documentation to speak of (oh what I’d do to get an ER diagram and some notes from the original developers).

In the scheme of things this is a pretty small database (well two of them actually), with only a few dozen tables. Doing the extraction by hand wouldn’t be overly time consuming but it would be overly mind numbing. And as the adage goes: “anything worth doing once is worth scripting”, so I wrote up a quick shell script that will dump the CREATE TABLE statements for each table in a set of databases.

#!/bin/sh
#  extract table schema from some set of databases
#
DB_USER=you
DB_PASSWD=yourpasswd
PARAMS="--skip-column-names -u ${DB_USER} -p${DB_PASSWD}"
DB_SELECTOR='^(db0|db1|db2)$'
TABLE_SELECTOR='.*'

echo "SHOW DATABASES;" 
    | mysql ${PARAMS} 
    | grep ${DB_SELECTOR} 
    | while read DB; do
    echo "CONNECT ${DB}; SHOW TABLES;" 
        | grep "${TABLE_SELECTOR}" 
        | mysql ${PARAMS} 
        | while read TABLE; do
        echo "CONNECT ${DB}; SHOW CREATE TABLE ${TABLE}" 
            | mysql ${PARAMS} 
            | sed -e  "s/\\n/\n/g;s/^${TABLE}[t]//;s/AUTO_INCREMENT=[0-9]*//
g" > ${DB}-${TABLE}.sql;
    done;
done;

I’m a big fan of piping things into while read VAR statements. I’m sure some hate it since it’s a bit hard to read / see where the loop begins but it seems elegant to me and it’s very useful.

The script is basically three sql commands:

  • The first gets the names of all databases the user has access to. This could feasibly be a large number of databases so we add a “selector” to give us a regex we can use to narrow this set down.
  • The second SQL command gets the tables from the selected database. This is within a while loop so it is executed once for each database. This set of tables is also filtered through another regex.
  • Finally in the third SQL command we dump the create table statement for each table (within yet another while loop).

This gets us the CREATE TABLE statements but MySQL puts some stuff in here we don’t want:

  • It prefixes each CREATE TABLE statement with the table name for some reason
  • It also includes the AUTO_INCREMENT value which we don’t care about either
  • It also doesn’t put new line characters in the output but does put the string “n”.

We pipe this output through a pretty gnarly looking sed find/replace to clean it up. The output is then redirected to a file with a name formatted to contain both the name of database and the name of the table. That’s all there is to it. I’ve put up dummy values for some of the selectors as an example.

The script can be downloaded here.

NOTE: The grep and sed regexs can be pretty confusing because of some bash double quoting and escaping. Knowing the rules for bash escaping is essential … and not covered here 🙂

Cheers!

Minimal GStreamer App

So in my last post (way back when) I was talking about transcoding some video. I wanted to use GStreamer to do the job but HandBreak was so much easier (pretty cool app too). So after I got the transcoding working with HandBreak I started playing around with GStreamer to see what it would take to code up a small app to do the job.

The first thing is just to code up a little bit of C to get the video playing. The GStreamer part here is pretty simple. It’s just like the gst-launch command I laid out in my last post. I’ve added a few bells and whistles to get command line parameters and to do some input validation. I’m using as much glib as I can for practice.

The result is a pretty short (for C) application that is a bare-bones GStreamer media player. Naturally you’d want a few additional things from a media player but that’s not our end goal. We want to take the playbin (or something like it) and hook it up to another pipeline of our own design that will encode the video & audio for our specific purposes. This is what’s coming up … soon hopefully. Honestly with the class I’m currently taking at SU it may be a while.

For now read the code and enjoy. It’s available for download below. I even made a Makefile for ya.

Download: gst-play-min.tar.gz