Wednesday, January 29, 2014

How to make a (real) network bridge with a Mac (mini) and OS X (Mavricks)

This is a quick post about setting up a simple layer 2 network bridge using a Mac (in this case a 2011 Mac Mini) running OS X (Mavricks). My goal was to setup the Mac, henceforth referred to as the mini, as an access point for my main network. I found no resources on line that covered doing this so I decided to write it up for those are interested.

What we’re not doing

I found many posts online that covered setting up “Internet Sharing” with a Mac. Some of those referred to this as ‘bridging’ which it is not. At least, in it’s simplest form it is little more than Network Address Translation (NAT) with packets being forwarded from one interface to another.  The problem with that approach is that only IP Traffic is passed and even that is adulterated such that clients on one side (the inside) of the link are not directly addressable by hosts on the other side (the outside) of the link.

It’s great for letting multiple machines browse the web but not good for having multiple machines  talk to each other whether they’re plugged in at the switch or connecting over Wifi and pulling from a common DHCP pool of addresses.


Configure Primary Interface

Primary is conceptual here. I’m taking about the interface that I’ll use to configure the host from over the network. The IP address for this interface will be the (main) address for this host. For me the primary interface is the ethernet port on the back of the Mini. Yours could be any of USB, BlueTooth, USB, FireWire, etc.

We want to make sure that the interface is properly setup on the network. For you that may mean DHCP configuration, manually IP-ing it,  or something else. I’m not going to spend time telling you how to do this. You’ll know it’s working when you can ping something external to the box (preferably external to the network).

In my case I set a static lease in my DHCP server so that every time the mac address for the Mini shows up it gets the same IP. The interface happens to be en0.

Reboot and make sure it works on start up.

Turn on Internet Sharing

Yes, I know what I said before. We’re using this to make sure that we can actually connect to the WIFI access point and get packets out on the network.

Go to System Preferences -> Sharing

On the left-hand side under Service click on Internet Sharing but make sure you do not click the ‘on’ checkbox next to it.

Share your connection from: should be set to Ethernet (at least for me).
To computers using: should have (only) Wi-Fi selected (the checkbox to the left). 

Click on  Wi-Fi Options and setup the SSID, password, and channel you plan to use in the end. You can use test values if you want, just remember to set them appropriately before you’re done with the final step.

When you’re sure everything is setup as you desire, click the checkbox next to Internet Sharing to enable it and click OK or Start if prompted by a subsequent dialog box to (re)start Internet Sharing.

Now configure a wireless client to connect to your Mac’s wireless network. Try to ping something to make sure it works.

Reboot and make sure it works on startup.

Bridge the interfaces

Internet Sharing is going to interfere with binding the two interfaces together into a bridge.  So the first thing we have to do is open a terminal window and type:

sudo launchctl unload -w\
/System/Library/LaunchDaemons/com.apple.InternetSharing.plist

That disables Internet Sharing. The actual command to create the bridge is remarkably simple. At the command line type in: 

sudo ifconfig bridge create

The output of this command depends on what other bridge devices may exist already.  If you get something like bridgeX where X is a number then that is your new bridge device and  you now only have to add interfaces to it:

sudo ifconfig bridge0 addm en0 addm en1 up

For me en0 is my ethernet port, en1 is the Wi-Fi device, and bridge0 is the name of the device returned by the previous command. Your device names/numbers may be different. Use ifconfig to help figure it out. 

Once you’re done with the above you need to re-enable Internet Sharing: 

sudo launchctl load -w\
/System/Library/LaunchDaemons/com.apple.InternetSharing.plist


Connect your devices and test to make sure that you can get a proper LAN IP address.


Making it last

You’ll want to run the command line steps every time the system starts. I do this with a cronjob for the root user.  I store it in ~root/bin/ (/var/root/bin) and invoke it with the line:

@reboot /var/root/bin/bridge.sh


The script contains:

#!/bin/sh -x 
#Name:      bridge.sh
#Purpose:   To create a layer 2 bridge between two interfaces allowing Ethernet
#           frames to pass between them. 
PATH=/sbin:/bin

if1=${1:="en0"}  # If no primary interface is passed assume en0
if2=${2:="en1"}  # if no secondary interface is passed assume en1

ifconfig >> /tmp/ifconfig.out
echo "#############################################################################"
runas_root(){
    #Helper funciton to insert "sudo" if succeeding command is invoked a non-root user
    case ${UID} in
        0) echo "" ;;
        *) echo "sudo " ;;
    esac
}

$(runas_root) launchctl unload -w /System/Library/LaunchDaemons/com.apple.InternetSharing.plist
bridge_if=$( $(runas_root) ifconfig bridge create)
$(runas_root) ifconfig ${bridge_if} addm ${if1} addm ${if2} up
$(runas_root) launchctl load -w /System/Library/LaunchDaemons/com.apple.InternetSharing.plist
echo "#############################################################################"
ifconfig >> /tmp/ifconfig.out


Reboot and make sure it all works on start up

Happy hacking...


8 comments:

  1. Hi there,

    thanks for the writeup. I was able to establish the bridge using the internal wired Ethernet en0 and an external USB-to-Ethernet adapter en4. en0 is the main connection to the network and en4 connects a single other device (Elgato Netstream 4Sat).

    The part that is working: The Netstream behind en4 gets a proper DHCP IP through the bridge. I can ping and access the Netstream from other devices in the network (e.g. iPad in the Wifi).

    The part that is not working: I cannot ping or access the Netstream behind en4 from the Mac Mini itself that has the bridge configured on it. I assume this is related to the routes on the Mac. Do you have any idea on this?

    Thanks,
    Torben

    ReplyDelete
    Replies
    1. Hard to say. If it’s bridged properly your routes shouldn’t matter provided that you have them pulling from addresses on the same subnet. Feel free to email me your configs and the output of ifconfig -a and netstat -nr

      Delete
  2. Many, many thanks for your help! I have been looking for this solution for a few years and yours seems to be the only place it exists.
    I do have a problem, though: I am using a mid-2007 iMac running Mavericks (10.9.4) and have implemented the steps above to create the bridge (but not the startup script.) My iPhone gets the same address as my iPad (10.0.1.2) using DHCP. I have set the en0 to static 10.0.1.6) and the Network Pref panel shows en1 with an IP of 169.254.186.16 - self-assigned. I can not see my iMac from my iPhone but can see my Apple TV (both via an airport attached to my cable modem and on the 10.0.1.x net.) I'm not a net expert by any means so I am stumped. Any help would be appreciated. I don't have your email address or I would attach the outputs mentioned above.
    Also, where would I put the start-up script?
    Many thanks

    ReplyDelete
  3. Tried this repeatedly and can't get it to work. The only thing I get up and running is regular Internet Sharing (i.e. a network that can't be reached from the outside unless you setup routing to that network). Seems from the other commenters they have similar problems. I am yet to find a solution to setting up a bridge on a Mac between two networks.

    ReplyDelete
    Replies
    1. To follow up on my original comment further up. I got it to work with these three commands. The Internet Sharing is disabled all the time:

      sudo ifconfig bridge create
      sudo ifconfig bridge0 addm en0 addm en3 up
      sudo ipconfig set bridge0 DHCP

      Hope this helps,
      Torben

      Delete
  4. Cant get it working, the bridge interface appears with the 2 physical interfaces allocated.. but there is no connectivity inbetween (on DHCP or IP)

    0: flags=8963 mtu 1500
    options=27
    ether 00:25:4b:b4:1c:5e
    nd6 options=1
    media: autoselect (1000baseT )
    status: active
    en1: flags=8963 mtu 1500
    ether 00:25:00:f6:a3:12
    inet6 fe80::225:ff:fef6:a312%en1 prefixlen 64 scopeid 0x5
    inet 192.168.1.79 netmask 0xffffff00 broadcast 192.168.1.255
    nd6 options=1
    media: autoselect
    status: active
    fw0: flags=8863 mtu 4078
    lladdr 00:25:4b:ff:fe:b4:1c:5e
    nd6 options=1
    media: autoselect
    status: inactive
    bridge0: flags=8863 mtu 1500
    options=3
    ether 02:25:4b:4b:9f:00
    Configuration:
    id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
    maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
    root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
    ipfilter disabled flags 0x2
    member: en1 flags=3
    ifmaxaddr 0 port 5 priority 0 path cost 0
    member: en0 flags=3
    ifmaxaddr 0 port 4 priority 0 path cost 0
    media: autoselect
    status: active


    Any help would be greatly appreciated!!!

    ReplyDelete
  5. Apparently Apple within OS X 10.10.x somewhere change the code for wi-fi so that this no longer works. Is there any possibility that you could update this so it would work in that environment?

    Many thanks-

    ReplyDelete
  6. Thanks for the post! I looked for some more background on having a Raspberry Pi connecting trough my Macbook to the internet. In fact, I was just looking for "internet sharing" which I did not know. But the idea of creating a bridge from the command line sounds interesting. I saw some new entry in the output of "ifconfig" after I enabled internet sharing. It would be interesting to drill down even more to the concepts one day (e.g. questions: Why do I see 2 subnets 192.168.2.X and 192.168.3.X? How are routes added? What output to see when pinging the broadcast address ?)

    ReplyDelete