Update 21-Sep-2011: Added an Installation section and updated the binaries on Bitbucket.
As you may know, I have a couple of Apple devices. Apple is fond of using Multicast DNS (mDNS) for their service discovery. The recent addition to these services being AirPrint (wireless printing service) and AirPlay (wireless audio/video streaming) from your iOS devices.
My home is setup in such a way that the wired and wireless networks are on 2 separate subnets. mDNS uses a multicast address that is “administratively scoped”, meaning the packets will not travel across subnets. I tried fiddling around with iptables rules and looked around for how I can route these packets across the subnets, but to no avail.
There is another solution – a repeater daemon that sits on the router and repeats packets between the 2 subnets. Avahi is used to provide mDNS services and it has a reflector mode that does exactly this. A more lightweight solution was TiVoBridge, which supposedly performs the same task but it’s much smaller. I tried to compile and set up TiVoBridge, but it required a config file and I couldn’t really get it to work the way I wanted it to. There’s an even lighter-weight solution called SAY, but it uses libpcap.
Enter mdns-repeater – a small Linux daemon that does exactly what I want it to do. I have a Linksys WRT54G which runs dd-wrt. This program was intended to be compiled for and installed on the Linksys router. As with all other programs that run on the router, it requires no configuration.
The default dd-wrt configuration has 2 interfaces –
vlan1 for the WAN interface and
br0 for the wireless interface (and 4-port switch). The program accepts the arguments
br0 and begins repeating packets from
br0 and vice-versa. I can now get my iOS devices to detect wired servers like a print server for AirPrint.
mdns-repeater is released under GPLv2. Feel free to change it to repeat whatever protocol you want. Patches to add functionality and bug fixes are welcome. You can contact me via bitbucket.org, or if you clone the repository my email is in the commits.
To compile for my router, I had to download the cross-compilation toolchain. My router uses the mipsel architecture. The toolchain that I downloaded from the dd-wrt site as recommended by the Development wiki page was useless. When I unpacked it, it had so many directories and trying to compile a simple hello-world program with the toolchain couldn’t even work.
In the end, I used the OpenWRT toolchain instead – it only has a single unmistakable set of gcc and binutils. You can download the toolchain from http://downloads.openwrt.org/whiterussian/rc6/. I chose to use the x86-64 one, since I was running the 64-bit Fedora Core 14.
Setting it up is easy: download, unpack, set your PATH to include the
OpenWrt-SDK-xxx/staging_dir_mipsel/bin directory. You can now execute
mipsel-linux-uclibc-gcc to compile your programs. When using configure scripts, specify
--host=mipsel-linux-uclibc and it will work automatically, as it was with TiVoBridge.
If you’re using dd-wrt, there’s a couple of methods to install mdns-repeater on your router (this is not a complete list):
- Using a writable filesystem like JFFS, then copying the binary onto the filesystem
- Downloading mdns-repeater on every startup
- Rebuilding the dd-wrt image with mdns-repeater and re-flashing your router
My router uses a stock installation, and I do not have any wish to use a writable filesystem, therefore I’m choosing method #2: a startup script that downloads the binary and executes it.
Unfortunately the wget in dd-wrt does not support SSL and Bitbucket does not allow you to use normal HTTP to download the binary (which is a good thing!), therefore I had to resort to putting the mdns-repeater binary on a HTTP server on my network. The command used was (all in a single line):
wget -O /tmp/mdns-repeater http://192.168.0.1/mdns-repeater && chmod +x /tmp/mdns-repeater && /tmp/mdns-repeater br0 vlan1
You can either save this under command under Startup or Firewall, but I found Startup to be a little unreliable – sometimes it works, sometimes it doesn’t. The Firewall command on the other hand, seems to have run more than once. I have therefore added code to use a pid file which will (most likely) prevent multiple instances from being started.
Note that this is potentially a security risk as someone could spoof the HTTP server and replace it with a malicious binary. Also, you need to have a HTTP server already running on your local network.
I would advise you to go with method #1, unless you are lazy like me and understand the risks.
If you use mdns-repeater, it should work fine. I used Bonjour Browser from Tildesoft to check that the services were detected correctly. I also used pybonjour to create services for testing. And how can network testing be complete without Wireshark?