Saturday, April 15, 2006

OpenVPN + DNS + OS X

OpenVPNOS X has a very cool feature built into to its resolver: /etc/resolver. It allows you to specify different DNS servers for different domains. After creating the /etc/resolver directory, I can create a /etc/resolver/erdelynet.com file with "nameserver 192.168.25.10" in it. Now, my Mac will use 192.168.25.10 for resolving erdelynet.com and whatever my ISP assigned me for everythying else.

When is this useful? erdelynet.com runs a MySQL server. My firewall blocks attempts from the Internet to port 3306. But suppose I want to just run a MySQL admin tool from my PowerBook and don't want to mess around with SSH tunnels.

With OpenVPN & /etc/resolver/erdelynet.com, I can seemless move from external user to internal user with two clicks.



So, I pop open my PowerBook at Starbucks (their coffee sucks, but they're a common example). I get some DNS server. When I connect to erdelynet.com, I'm connecting via its public IP address and connect as anyone else would. But I want to manage my MySQL server or VNC to my wife's computer or access some internal, private web site. But these features are blocked at the firewall.

OpenVPN gets me halfway there. I can connect to my web server's private IP address directly, but I cannot resolve it's IP address. Starbucks' DNS server knows nothing of it.

Using OpenVPN's "up" and "down" script options, I add "up ~/bin/up.sh" and "down ~/bin/down.sh" to my ~/Library/openvpn.conf file. Then I create my up.sh and down.sh scripts...

up.sh:
#!/bin/bash -x
mkdir -p /etc/resolver 2> /dev/null
echo "nameserver 192.168.25.10" > /etc/resolver/erdelynet.com
# Added to script Mar 7 2007
killall lookupd
# Removed from script Mar 7 2007
# /usr/sbin/lookupd -flushcache
exit 0


down.sh:
#!/bin/bash -x
rm -Rf /etc/resolver/erdelynet.com
# Added to script Mar 7 2007
killall lookupd
# Removed from script Mar 7 2007
# /usr/sbin/lookupd -flushcache
exit 0


NOTE: If /etc/resolver didn't exist since the last time lookupd started (probably when you last rebooted), you have to restart it: sudo killall lookupd ; sudo /usr/sbin/lookupd.

I thought I'd mention, if you haven't tried it yet, Tunnelblick is an AWESOME OpenVPN GUI for Mac. It's what I use.

When I make my OpenVPN connection, I see that a new file, /etc/resolver/erdelynet.com, is created. And when I ping erdelynet.com, I now see it's private IP address instead of its public IP address. Assuming that I've allowed connections through OpenVPN to my MySQL server, I can just fire up my admin tool and connect directly to my MySQL server -- through the VPN.

Then, when I disconnect, the file automatically gets deleted. The "lookupd -flushcache" command tells OS X's resolver to forget about my internal network and it goes about using the ISP assigned DNS server for erdelynet.com again. Talk about easy.

There's only one problem: Suppose my Mac or the OpenVPN connection shutdown un-gracefully. The /etc/resolver/erdelynet.com file does not get deleted. Then, DNS to my domain is fubar'd. To prevent this from happening (only happened once that I can remember), I added "rm -rf /etc/resolver/erdelynet.com" to /etc/rc.local (I did have to create rc.local, but /etc/rc is configured to run commands from it upon bootup if the file exists).

Enjoy.

17 comments:

  1. [...] I was curious about how to make this go though, and what general solutions people had when I came across a post by Mike Erdely titled OpenVPN + DNS + OS X.  That is exactly what I wanted to do!  As a bonus ge’s even using Tunnelblick. [...]

    ReplyDelete
  2. Just an update:

    I added a "sleep 2" line before the "lookupd -flushcache" lines in each file. It seems that lookupd flushes the cache too soon and sometimes it doesn't "take" without pausing a second.

    ReplyDelete
  3. A method of doing this dynamically, and thus avoiding stale files, is:

    The recommended method for 10.4 (http://lists.apple.com/archives/Macnetworkprog/2005/Jun/msg00029.html) is:
    * create State:/Network/Service//IPv4, containing at least one sub-key (e.g. Addresses)
    * create State:/Network/Service//DNS, containing the keys ServerAddresses and SupplementalMatchDomains set to the VPN name server and domain, respectively

    e.g. the following example from an example OpenVPN “up” script creates a new Service/.../IPv4 key by “cloning” the physical interface settings (which for the OpenVPN tun interface should only be two keys: Addresses and DestAddresses), and adding the InterfaceName (why?). Then it creates the DNS key as above.

    - $tun_dev ⇒ tun interface (e.g. “tun0”)
    - $ns ⇒ list of name servers, space separated (e.g. “10.2.3.4 10.4.3.2”)
    - $domain ⇒ list of “supplemental” domain names, space separated (e.g. “A.private.lan B.private.lan”)

    $ sudo scutil

    ReplyDelete
  4. Oookay, the actual code went missing... try this:

    Feed this to scutil (e.g. via a shell heredoc):
    open
    d.init
    get State:/Network/Interface/$tun_dev/IPv4
    d.add InterfaceName $tun_dev
    set State:/Network/Service/openvpn-$tun_dev/IPv4
    d.init
    d.add ServerAddresses * $ns
    d.add SupplementalMatchDomains * $domain
    set State:/Network/Service/openvpn-$tun_dev/DNS

    ReplyDelete
  5. Thanks for the info, Ben. I've had severe problems when relying on the default "up" script with Tunnelblick. Both PPC and Intel. CPU goes through the roof. Have to kill openvpn and Tunnelblick.

    Creating a simple file in /etc/resolver and then deleting it seems like a much clearer approach even if it isn't the Apple way. It is, however, documented in the man pages.

    ReplyDelete
  6. I've found that sometimes lookupd doesn't reliably see the new DNS host and I end up having to kill and restart lookupd to get that to happen. Actually, I don't have to restart it, the OS will do that for me. So I just changed the script to have a killall lookupd rather than /usr/sbin/lookupd -flushcache. You can take out the sleep that way as well.

    ReplyDelete
  7. And actually, since openvpn by default downgrades itself after initialization to run as nobody/nobody, the down.sh script can't delete the /etc/resolver/* file because that's owned by root/wheel. You could have openvpn continue to run as root (it can be configured in openvpn.conf), but that strikes me as a somewhat bad idea...

    So instead, I set up multiple locations in the Network preference panel, then added a Location submenu to the Apple menu using Fruitmenu. Connect to VPN using TunnelBlick, then switch to the other network location using Fruitmenu. All the DNS then goes through the VPN, which is modestly non-optimal, but it's good enough.

    ReplyDelete
  8. I've been using Tunnelblick (actually as you describe with the "killall lookupd" instead of flushcache for exactly the reason you describe. It's always worked in deleting my /etc/resolver/my.domain.com file.

    So, I connected to a VPN endpoint and ran "ps -auxww | grep openvpn" and it's running as root. My configuration file says "User nobody" so I'm not sure why.

    ReplyDelete
  9. Mike
    These scripts work great.
    I just substituted the killall lookupd line for the flushcache and omitted the sleeps like you've done...

    What would be the best way to temporarily change the machine's own domain name during the connection to equal the new dns name?

    I just want to access remote services in the same way as when at the remote site, so all my connect to server bookmarks would work, etc? ie:

    ping hostname
    instead of
    ping hostname.domain.com

    i tried manually changing it in/etc/resolv.conf and killall lookupd but it remains the same. i think a change of network settings might have to happen from the network gui but i want to integrate this into your script.

    thanks!

    ReplyDelete
  10. Steve,

    If you're like me and really only care about two domains, you can go into your Network System Preferences and add a static domain search string. I have both my work domain and my home domain in there so that I can access resources with just the hostname.

    System Preferences -> Network -> Built-in Ethernet or Airport -> Search Domains.
    List them "domain1.net, domain2.net, ..."

    ReplyDelete
  11. thanks mike... the Search Domains trick works perfectly for being able to access simultaneously more than 1 DNS server.

    i also found another up script that works for me that i wanted to share for temporarily assigning a different VPN tunnel DNS:

    http://openvpn.net/archive/openvpn-users/2006-10/msg00120.html

    it pulls the DNS server from the VPN server config file's push directive.
    i havent yet tested whether i can simultaneously use tunnelblick to connect to 2 different VPNS with 2 different DNS servers.

    ReplyDelete
  12. OK. I can confirm that this method:
    http://openvpn.net/archive/openvpn-users/2006-10/msg00120.html

    only seems to add 1 DNS to your table at a time.
    upon connection to a simultaneous 2nd tunnel, the 1st tunnel's DNS server gets replaced.

    So... I think that if you only will connect to 1 tunnel at a time, this method is better in that you don't have to hardcode any domain in your up.sh script.

    but if you want more than one domain, adding them to OS X's Search Domain GUI seems best

    ReplyDelete
  13. What about this scenario:

    1. I'm using Tunnelblick to connect to the internet from another network. I'm using the DNS setting I received from my remote server connection rather than my local ISP to surf the net, etc.
    2. I'm connecting on a Mac laptop OS 10.4.x using airport.
    3. I've turned on sharing in the Preferences Pane....and I connect my Vonage box to it.
    4. Vonage doesn't work.

    note: when I have the tunnel turned off, the vonage box connects to it's server via the shared connection, but when I turn on the vpn tunnel, it can't "find" it's host server and forever tries to negotiate and "find" the server....

    Is there something with the DNS settings that I need to do so that the Vonage box can resolve it's host server and connect?

    ReplyDelete
  14. For all your DNS needs. http://www.dns-utils.com

    ReplyDelete
  15. Try the Viscosity OpenVPN client for the Mac, works fantastically!
    http://www.viscosityvpn.com/

    ReplyDelete
  16. Thanks for info, but my openvpn connection usually drop about 1-2 hours (not stable connection). How to fix this ?

    ReplyDelete
  17. You probably want to check with the actual OpenVPN group.

    ReplyDelete