mdns-repeater: mDNS across subnets

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 vlan1 and br0 and begins repeating packets from vlan1 to 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.

Compilation

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.

Installation

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):

  1. Using a writable filesystem like JFFS, then copying the binary onto the filesystem
  2. Downloading mdns-repeater on every startup
  3. 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.

Troubleshooting

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?

Advertisements

42 comments on “mdns-repeater: mDNS across subnets

  1. Brad Parker says:

    Thanks! that’s exactly what I need to print from my ipad.

    can you post a binary?

  2. Works great with an AirPort Express streaming audio, but I can’t get it to work with an Apple TV 2 (on the latest 4.4.2 firmware). It won’t do 4S screen mirroring, audio or video AirPlay, and the Remote app doesn’t work all the time (although it does SOMETIMES).

    Any ideas? Packet traces don’t really reveal much to me as I’m not familiar with the mdns and AirPlay protocol. I wonder what could be different between the two.

    • darell tan says:

      Typically mDNS is only used for discovery, so that your iPhone can find your AppleTV. The actual data transfer (for AirPlay, at least in the previous versions) happens over a point-to-point connection after discovering the peer’s IP address. I am inclined to believe that it might be a router configuration issue, but I may be wrong. Unfortunately I don’t have an AppleTV to try to replicate the issue.

  3. john says:

    Hi,

    are you available for hire as a consultant? I really need this to work and would be more be more then happy to compensate you for your time.

  4. FYI: I have mDNS-tunnelling working with Avahi on one side and mdns-repeater on the other. There is yet another bug in Avahi that prevented mDNS over PTP working, see http://avahi.org/ticket/355
    On the OpenWRT side, I’m running mDNS-repeater. On the other side I don’t, because my OpenVPN does not “see” the other side of it’s tunnel correctly, and this would cause mdns-repeater to start repeating itself. This is because an OpenVPN server works like this:
    The first side sees itself as: 10.0.0.1 ptp 10.0.0.2
    The other side sees: 10.0.0.13 ptp 10.0.0.12

    … but they do receive each other’s multicast information. 10.0.0.1 sees information coming from 10.0.0.13 and vv. Thus, mdns-repeater would start echoing back, hence the setup with Avahi at one side and mdns-repeater on the other.

    • darell tan says:

      sorry i haven’t setup nor used OpenVPN before and i do not know your network configuration, but mdns-repeater should not repeat packets back into the same interface which it receives them. is this a bug? or could functionality be added to mdns-repeater to make it work in your configuration? could you provide me with more information? thanks!

      • This is the culprit:
        if ((fromaddr.sin_addr.s_addr & socks[j].mask.s_addr) == socks[j].net.s_addr)

        (For more information, please see the e-mail I sent you).

        • n9yty says:

          If you found a fix, any chance you could post the details here? The repo doesn’t seem to have been updated since this post so I assume the “fix” is not in place. Thanks!

  5. Farhan says:

    iOS also supports DNS-SD for environments where the client and server are on different broadcast domains (e.g. different subnets in an enterprise environment). I’m not sure if it would be easy to setup a DNS server and configure Service Discovery records in your case but, I bet a lot of enterprise environments have this challenge and a DNS server somewhere on the network.

    • darell tan says:

      Hi Farhan, I have never tried DNS-SD for ad-hoc service discovery but there are some challenges to it. For one, you need to allow your iOS devices to update the DNS server, which might have security implications (and is it supported?) Secondly, in order for ad-hoc service discovery & announcements to work effectively, you would need DNS extensions like Long-Lived Queries (LLQ) for both the DNS server and the clients, which I don’t think is widely supported.

      But I think DNS-SD is fine for static records such as printers or HTTP, FTP or SMB servers.

      • Farhan says:

        Yup, Darell…I was referring to static records from an enterprise perspective where broadcast traffic is blocked at the routers.

        I agree with the security concerns around allowing devices to add service discovery records in DNS. Also, it would be pretty messy if every personal device on the network was able to advertise its services via DNS-SD :).

  6. Tom says:

    Can you help? How to run on Linksys E3000. mdns-repeater not run, I get “can’t resolve symbol ‘__uClibc_start_main'”.

    Router Model Linksys E3000
    Firmware Version DD-WRT v24-sp2 (06/08/12) mega – build 19342
    CPU Model Broadcom BCM4716 chip rev 1

    • darell tan says:

      Hi Tom, a quick search suggests that it’s most likely that your dd-wrt build uses a different version of uClibc. You can probably solve this problem by re-compiling mdns-repeater with an updated dd-wrt toolchain.

      • james says:

        Tom: not sure if you’re still monitoring this page, but…. the right version is posted on the bitbucket page: get the 1.10 “asus” version, and it works on an e3000.

  7. Kasteleman says:

    Installed it on my tomatousb router. My Ipad now sees the AppleTV, but there it stops. No airplay. So unable to transfer the file. What ports are used for this, so i can open up the firewall, or set some forwarding rules

    • darell tan says:

      AirPlay typically uses TCP ports 7000 and 7100, and Mirroring may use other ports above 7000 as well. AirTunes (the audio-only streaming protocol) uses RTSP. Do note that the port numbers are advertised in mDNS and in the AirPlay protocol too, so nothing is really fixed and could change in future.

      For my network the wireless router will route incoming traffic from the WAN side (dd-wrt has a mode for this) so that the wired machines can contact the wireless (iPad, for example).

      • kasteleman says:

        Darell, what do you mean by dd-wrt has a mode for this? Can you point me in the right direction? At this moment i’m using tomatousb from Shibby and struggling with the firewall rules. Is it easier setup with dd-wrt? If so, maybe i have to flash my asus rt-n66u with a dd-wrt version instead

        • darell tan says:

          I may be assuming too much about your network here, but for mine I connect the WAN connection to my wired LAN and the wireless router is configured to use another subnet. By default the wireless router does not pass packets from the WAN to the wireless clients, so I had to set the routing mode in dd-wrt to “Router” instead of “Gateway”. In this mode, WAN traffic will pass through without setting any firewall or forwarding rules. Tomato should have a similar setting.

  8. JG says:

    98% awesome. Unfortunately, on many multicast stacks, you need just a bit more code:

    From *BSD man ip(4):
    For hosts with multiple interfaces, each multicast transmission is sent
    from the primary network interface. The IP_MULTICAST_IF option overrides
    the default for subsequent transmissions from a given socket:

    struct in_addr addr;
    setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));

    Your code is awesomely all set to have this added right after the IP_MULTICAST_LOOP, it looks like it’s sufficient to add

    if ((r = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, if_addr, sizeof(struct in_addr))) < 0) {
    log_message(LOG_ERR, "send setsockopt(IP_MULTICAST_IF): %m");
    return r;
    }

    Tested on recent FreeBSD, nothing else yet.

    It's funny, I'd been meaning to write this for about a year because it seemed like such an obvious omission, and I was just about to sit down and write something, when I decided to Google it just in case.

    • darell tan says:

      Hi JG, thanks for the patch. When I tested it on Linux, it transmits the packet on a single interface only – maybe it has to do with the SO_BINDTODEVICE option, which I think doesn’t exist on BSD systems. As this was written for Linux, I did not test it on other platforms. I’ll add in the IP_MULTICAST_IF option so that this will work on *BSD systems as well.

  9. […] (which DD-WRT had) to forward requests to my main DHCP server and I need to be able to run mDNS Repeater to repeat mDNS packets between the wireless and wired subnets. It turns out that I could fulfill […]

  10. Karim says:

    Hi Darell,
    just want to say thank you for the great post :-). It took me some long nights to implement your solution on a Buffalo WHR-HB-G300N router running DD-WRT build 19154. This finally solved my long-lasting issue with Bonjour devices not always being visible across the network. I run the wireless repeater in Client Bridge + Virutal Interface mode. I had to change 3 lines of code in order to enable mdns-repeater to accept network interfaces belong to the same interface. Cheers, Karim.

    • Karim says:

      Sorry for the typo at the end of the last post; i meant that by default, mdns-repeater does not accept interfaces belonging to the same sub-net.

      • darell tan says:

        Hi Karim, glad that it works for you! While mdns-repeater does not prevent you from adding multiple interfaces that belong to the same subnet, it might be confused about the packet origin and refuse to repeat it.

        Would you mind sharing the IP & subnet masks for the interfaces and how you solved the problem?

  11. James says:

    Darell,
    It seems the only tools for Bonjour on DD-WRT routers are Avahi and mdns-repeater! I’ve been trying to get a simple scenario setup, but still not working, and searching has been fruitless.
    Since iOS only supports PPTP and L2TP, I have created a PPTP server on my router. When out-and-about in the city, I can then VPN from my iPad to my router, which creates the ppp0 interface on my router, etc.
    Generally, everything ‘works’ (ie. IP works, surfing the net, etc…), except that none of the nice Apple features work (namely, shared itunes libraries/movies in this case) because mDNS traffic doesn’t flow up the ppp0 tunnel.
    My idea was just to fire up mdns-repeater on the interface-up event in a small script.

    I tried using mdns-repeater, but it complains on PTP interfaces. Any ideas?

    root@mahou:/tmp# ./mdns-repeater -f br0 ppp0
    mdns-repeater: dev br0 addr 192.168.1.1 mask 255.255.255.0 net 192.168.1.0
    mdns-repeater: recv setsockopt(IP_ADD_MEMBERSHIP): Address already in use
    mdns-repeater: unable to create socket for interface ppp0
    mdns-repeater: exit.
    root@mahou:/tmp#

    The interfaces are as follows:

    root@mahou:/tmp# ifconfig br0
    br0 Link encap:Ethernet HWaddr 98:FC:11:77:AA:D8
    inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0
    UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
    RX packets:9272113 errors:0 dropped:0 overruns:0 frame:0
    TX packets:12954345 errors:0 dropped:0 overruns:0 carrier:0
    collisions:0 txqueuelen:0
    RX bytes:1845920068 (1.7 GiB) TX bytes:1815751578 (1.6 GiB)

    root@mahou:/tmp# ifconfig ppp0
    ppp0 Link encap:Point-to-Point Protocol
    inet addr:192.168.1.1 P-t-P:192.168.1.200 Mask:255.255.255.255
    UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1432 Metric:1
    RX packets:15 errors:0 dropped:0 overruns:0 frame:0
    TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
    collisions:0 txqueuelen:3
    RX bytes:512 (512.0 B) TX bytes:400 (400.0 B)

    root@mahou:/tmp# ping 192.168.1.200
    PING 192.168.1.200 (192.168.1.200): 56 data bytes
    64 bytes from 192.168.1.200: seq=0 ttl=64 time=216.416 ms
    64 bytes from 192.168.1.200: seq=1 ttl=64 time=177.190 ms

    — 192.168.1.200 ping statistics —
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 177.190/196.803/216.416 ms

    thanks!
    james

    • darell tan says:

      Hi James, mdns-repeater doesn’t work very well with PTP interfaces at the moment. The error you are receiving is due to ppp0 also having the same interface address as br0. I don’t have much experience with VPN services so I haven’t really figured out how this should be fixed yet.

    • Kailas Narendran says:

      I’m trying to do the exact same thing and thought that mdns-repeater might be the solution and sadly had the exact same problem. In my case I’m running it on my linux router/firewall/server system, so trying to repeat from my LAN (eth2) to ppp0. Any chance that you’ve figured out a solution?

  12. […] I can across this post by Darell that gave a good description of whats needed. Essentially he describes how to compile […]

  13. Andreas says:

    Hi,
    when I start mdns-repeater by console with telnet connection it runs perfectly on my netgear WNDR4000 with DDWRT installed on it.
    If I try to start it automatically using the startup script (/jffs/mdns-repeater br0 vlan2) i get the following error:
    DD-WRT daemon.err mdns-repeater[1217]: recv setsockopt(IP_ADD_MEMBERSHIP): No such device Jan 1 00:00:17 DD-WRT daemon.err mdns-repeater[1217]: unable to create socket for interface vlan2 Jan 1 00:00:17 DD-WRT daemon.info mdns-repeater[1217]: exit
    Any idea?
    Regards
    Andreas

    • Andreas says:

      One more thing. If i type ” /jffs/mdns-repeater br0 vlan2 ” into the command shell of DDWRT in my webbrowser and execute it, it is also working. Could it be some timing problem?

      • darell tan says:

        Hi Andreas, it could likely be that the interfaces have not been brought up yet. If you see my post on asuswrt, the script waits until the system initializes before starting mdns-repeater.

        • Andreas says:

          Hi Darell,
          thank you for answering. I looked at your script and i don’t know if it is working with DDWRT and also don’t know how to test it. Meanwhile i found a solution for my problem. I entered the startcode into the firewall script. This script is called more often by the Opsys and after some calls it is workting. Sure not the best solution but it works.
          Regards
          Andreas

  14. Yann says:

    Hi Darel
    i try to execute your mdns repeater on a Netgear WNDR3700 v2 with an

    Firmware: DD-WRT v24-sp2 (06/14/11) std
    But when i launch your script i got the following error message :

    # ./mdns-repeater vlan1 br0
    # ./mdns-repeater: line 1: syntax error: “(” unexpected

    what can be the root cause of this error ?

    Many thanks

  15. Yann says:

    root@router:/jffs# ./mdns-repeater vlan1 br0
    ./mdns-repeater: line 1: syntax error: “(” unexpected

  16. Millard says:

    Hello to every body, it’s my first pay a visit of this webpage; this website includes awesome and really excellent material designed for visitors.

  17. Seleo says:

    TRENDnet’s Wi-fi AC Easy-Upgrader, Type TEW-820AP, contributes a wireless AC community with a wireless as well as feeling stimulated router. Merely connect the particular TEW-820AP straight into a obtainable Ethernet dock within the returning of your respective existing router – and also you will be completed. On your advantage the particular Wi-fi AC community is usually create and also pre-encrypted outside the package.

  18. majenko says:

    Brilliant! Now my PC can see my Chromecasts! Perfect.

  19. Justin says:

    Thank you for this; very useful. I’ve noticed that Jon Crooke has compiled with an ARM toolchain and made it available here: https://bitbucket.org/joncrooke/mdns-repeater/downloads . This build is working on my Netgear AC1450 (and presumably his ASUS RT-AC68U).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s