IP multicast is an interesting technology. It’s main purpose is to save network bandwidth as much as possible – traffic is sent to hosts which asked for it only (as opposed to broadcast). On the other side, you need smarter (manageable) switches and separate and non-trivial configuration on both routers and switches. Even more complicated it is when you try to make it work over VPN.
I have a server, which can join multicasts using IGMP on one interface and has a public IP on another interface. I wanted it to make those multicasts available via VPN.
It has a static route for multicast to know where to join them:
route add -net 220.127.116.11/4 dev eth1
So my first try was to use OpenVPN with tun device (routed IP packets). I set it up to push route to clients:
push "route 18.104.22.168 240.0.0.0"
Next, I needed to make my server join on eth1 and route multicasts to tun0 interface. Linux has a native support for multicast routing but it needs to be managed by an userspace application which statically or dynamically manages routes. For this I used igmpproxy. It listens for IGMP packets on tun0, joins/unjoins multicasts on eth1 and install multicast routes accordingly.
# ip mroute show (10.2.3.1, 22.214.171.124) Iif: eth1 Oifs: tun0
This was working ok, but it has one huge disadvantage: OpenVPN treats multicasts as broadcast and sends them to all clients. If you have VPN clients with poor network or CPU performance, you can effectively make the VPN unusable for them.
igmpproxy can listen on multiple interfaces (even dynamically created) so if each client had it’s own tun interface the above problem would disappear, but unfortunately OVPN can’t do this. There are VPNs which do this by default e.g. pptpd (I tested it and it works) but I wanted to stay with OpenVPN.
So I came to an idea to use tap device. Even though OVPN does the same as in TUN mode and brodacasts packets to all clients (there are some efforts to change it), I got a new opportunity: to direct the packets using Ethernet header.
The idea is following: I’ll write a daemon, which will listen and process IGMP joins on VPN tap interface. When it gets one, it will record senders MAC address, join requested group on upstream interface a listen for incoming multicast packets. It will then take the whole IP packet, prepends recorded destination MAC, some source MAC and send it to the tap interface. This should cause the packet to be sent only to one client but keep the IP payload unchanged.
So I wrote a prototype and for my surprise it also WORKS! At least on Linux. You can find it here. Feel free to test it. Now to explain the title, this daemon can be also used for network with stupid switches to avoid network flooding. The traffic effectively changes to unicast on link layer and is delivered directly to subscribers.
I hope this helps someone with similar problem.
Looking forward for your comments and suggestions.