Internet Sharing from WiFi to Ethernet doesn't work in Mountain Lion

After upgrading from Lion to Mountain Lion, it seems like internet sharing no longer works.

With the settings:

  • Share network from: WiFi
  • To computers using: Ethernet

When Internet Sharing is enabled, the host can't access the internet, and neither can connected clients. Clients are given an IP address via DHCP, and the correct route is setup, but that's it.

It seems like the host can't access the internet because the bridge0 device is set as the default route:

# Before enabling internet sharing
$ route -n get default
   route to: default
destination: default
       mask: default
    gateway: 192.168.1.1
  interface: en1
      flags: 
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire
       0         0         0         0         0         0      1500         0 
$ ping 4.2.2.1
PING 4.2.2.1 (4.2.2.1): 56 data bytes
64 bytes from 4.2.2.1: icmp_seq=0 ttl=54 time=33.418 ms
…

# And after enabling internet sharing
$ route -n get default
   route to: default
destination: default
       mask: default
  interface: bridge0
      flags: 
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire
       0         0         0         0         0         0      1500        -1 
$ ping 4.2.2.1
PING 4.2.2.1 (4.2.2.1): 56 data bytes
ping: sendto: Host is down
Request timeout for icmp_seq 0
…

Additionally, disabling Internet Sharing leaves the routing table broken. I've got to manually add the default route back in before things start working again:

# After disabling internet sharing
$ route -n get default
route: writing to routing socket: not in table
$ ping 4.2.2.1
PING 4.2.2.1 (4.2.2.1): 56 data bytes
ping: sendto: Host is down
Request timeout for icmp_seq 0
…
$ route -n add default 192.168.1.1
$ ping 4.2.2.1
PING 4.2.2.1 (4.2.2.1): 56 data bytes
64 bytes from 4.2.2.1: icmp_seq=0 ttl=54 time=33.418 ms
…

Finally, checking the output of pfctl before and after enabling internet sharing doesn't show any (significant) changes. Should there be?

And various bits of info:

  • This is with OS X 10.8.2
  • Output of ifconfig when sharing is enabled (with irrelevant adapters p2p0, fw0, gif0, and stf0 removed):
lo0: flags=8049 mtu 16384
    options=3
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
    inet 127.0.0.1 netmask 0xff000000 
    inet6 ::1 prefixlen 128 
en1: flags=8863 mtu 1500
    ether 60:c5:47:93:47:66 
    inet6 fe80::62c5:47ff:fe93:4766%en1 prefixlen 64 scopeid 0x5 
    inet 192.168.1.118 netmask 0xffffff00 broadcast 192.168.1.255
    media: autoselect
    status: active
en0: flags=8963 mtu 1500
    options=2b
    ether 3c:07:54:1a:83:89 
    media: autoselect (none)
    status: inactive
bridge0: flags=8863 mtu 1500
    ether ac:de:48:11:fa:4e 
    inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
    Configuration:
        priority 0 hellotime 0 fwddelay 0 maxage 0
        ipfilter disabled flags 0x2
    member: en0 flags=3
             port 7 priority 0 path cost 0

Solution 1:

This is indeed quite broken in Mountain Lion. Once you've fixed up the default route as you describe in the question, you're still left with the problem that Mountain Lion is giving its bridge interface address to clients as both the router address (which is correct) and as the DNS server address (which isn't).

Verify that this is the problem by entering an HTTP server IP address into the address bar on a client web browser when connected through your Mac after you fix default routes, and it should load up fine.

My solution to this problem is to fix up the route as you describe -- which could be automated, of course -- and to keep BIND (aka /usr/sbin/named) running in the background on my Mac in a forward-only configuration, forwarding all queries to Google's public DNS servers. This doesn't fix the underlying brokenness in Mountain Lion, but it makes things start working for the clients.

A couple useful resources:

http://www.macshadows.com/kb/index.php?title=How_To:_Enable_BIND_-_Mac_OS_X%27s_Built-in_DNS_Server (how to fire up BIND on OS X)

http://gleamynode.net/articles/2267/ (how to configure BIND for forward-only operation -- of course you will not want to make BIND only listen on 127.0.0.1)

It would be far preferable for Apple to make this feature of their OS work as advertised, but in the meantime I've found this is a viable workaround.

Solution 2:

Actually, there is a bind process started after activating internet sharing:

22.12.12 09:21:01,687 named[23072]: starting BIND 9.8.3-P1 -c /etc/com.apple.named.proxy.conf -f

The config in /etc/com.apple.named.proxy.conf forwards dns requests to reasonable DNS servers.

The problem is that the named daemon doesn't stay alive. There are times were it stayed alive, and everything works OK, but at least every second day it does not.