Xbridge is an application that we recently began developing. It addresses a niche that the OS X operating system lacks: network bridging. Network bridging is a function found in Linux and Windows (since XP), but as yet has not made its way into OS X. For some time, OS X has included Internet Connecting Sharing, but this uses network address translation (NAT) to achieve its goal. 99% of the time, this is not an issue, but when your needs exceed the functionality that OS X provides, you’re left out in the cold.
There are a few cases when this might happen. NATs provide a nice service, wherein multiple devices behind the NAT can effectively share a single external IP address (that being the one of the computer or router providing the service) and traffic can freely flow out through the NAT and responses are duly transmitted back. Where NATs fall short is allowing external entities to initiate connections to devices behind the NAT: there is no systematic method by which the router can determine the correct device behind the NAT to which the connection should be forwarded. Technically-inclined readers will be aware of this issue and one common solution; port forwarding. This is usually easy enough to set up on the routers that many people have at home, but this is not the case for people using OS X’s internet connection sharing.
Mac OS X, other BSDs and Linux usually achieve network address translation by means of natd – the Network Address Translation daemon. A daemon is a computer program that runs in the background and provides a service; in this case, the service provided is NAT, allowing devices connected to our OS X-powered computer on one network interface access to services on another network interface. A common example is someone connecting their Xbox 360, PS3 or other gaming console to their computer through an Ethernet cable and accessing their Internet connection through the computer’s wireless connection. This allows the devices Internet connectivity, but they cannot work at full capacity without ports forwarded to them in the correct manner.
natd, like other NAT services, provides port-forwarding functionality by means of command-line options. Even then, the daemon must be restarted (effectively severing all current connections passing through it) for any port-forwarding changes to take effect. For OS X users unfamiliar with the terminal, this is a daunting, if not impossible prospect. To remedy this, a few third-party software vendors have released products to make this configuration easier. Two such products include Flying Buttress by Brian Hill, (US$25 shareware) and IPNetRouterX by Sustainable Softworks (US$100 commercial).
We were unhappy with this state of affairs, with Apple not providing the functionality we desired and third parties charging more than we thought reasonable, given that other platforms deliver this functionality for free, so we set out to develop our own solution. In doing so, we learned a lot about network bridging implementations in Windows, Linux and BSD operating systems as well as those implemented by virtualisation software, such as VMware Fusion and Virtualbox.
The first thing that we learned is that the network bridging functionality advertised by all these products is almost universally a misnomer. Network bridging functionality is standardised in IEEE 802.1D. Rather than providing bridging per se, these solutions all provide network routing. Wikipedia does a good job of differentiating between the two, which we will reproduce here for posterity:
Bridging and routing are both ways of performing data control, but work through different methods. Bridging takes place at OSI Model Layer 2 (data-link layer) while routing takes place at the OSI Model Layer 3 (network layer). This difference means that a bridge directs frames according to hardware assigned MAC addresses while a router makes its decisions according to arbitrarily assigned IP Addresses. As a result of this, bridges are not concerned with and are unable to distinguish networks while routers can.
The distinction is that a bridge can simply look at the MAC address of a frame to determine its destination, whereas a router must peer deeper into the packet (at the network layer) and look at the IP address to determine the appropriate destination. Not only this, but the router has to modify the frame and adjust the Ethernet header’s source and destination addresses accordingly. All in all, not insignificant work.
We determined this was the case through rudimentary detective work. When devices (e.g. virtual machines, gaming consoles, etc.) were connected to our computer by means of a NAT, the router that assigned our computer an address was completely unaware of any devices behind ours. Our router would assign our computer an IP address of 10.1.1.x and the devices behind our NAT would be assigned addresses in the 192.168.1.x range. When we connected these same devices to our computer by means of a network “bridge”, they would also be assigned IP addresses in the 10.1.1.x range. Though the devices were recognised by the router, its routing table indicated that these devices all shared our computer’s hardware (i.e. MAC) address. This meant that our computer was not bridging the two network segments (and forwarding packets unaltered), but routing: inspecting packets’ IP addresses, modifying the Ethernet header and forwarding according.
After initial testing, we realised that implementing a true bridge (in the 802.1D sense) was not possible, due to limitations in consumer-grade routers and switches (not allowed multiple hardware addresses to be assigned to a single network port) and network drivers (wireless cards discarding packets not intended for them before passing them onto the kernel, unless in monitor mode). It seems the term “bridge” as employed by operating system and virtualisation software developers is used to describe its functionality in lieu of its implementation. Hence, we figured we could get away with the deception, too.
All this meant that Xbridge would prove to be more work than we had initially planned. A router is a more complex (albeit more configurable) piece of hardware (and in this case; software!) than a bridge, on account of its increased “awareness” and responsibilities. We will delve into these responsibilities and how we dealt with them in a future post – stay tuned!
This deficiency amazed me when I first arrived from Linux land. I contemplated fixing it with a kernel extension but haven’t really found the time. I might help out if you considered truly 802.1d bridging. There should be no switch problem – at least none that I’ve yet encountered. Why not just borrow the BSD bridge code?