#!/usr/bin/env python

import os, re, sys

nameservers = []
search_domains = []

foreign_option_vars = [k for k in os.environ.iterkeys()
                       if k.startswith('foreign_option_')]
foreign_option_vars.sort()
dhcp_options = [os.environ[k].split(None, 2)[1:] for k in foreign_option_vars
                if os.environ[k].startswith('dhcp-option ')]
for option, value in dhcp_options:
    if option == 'DOMAIN':
        search_domains.append(value)
    elif option == 'DNS':
        nameservers.append(value)

def usage(msg):
    print >> sys.stderr, '%s: %s' % (sys.argv[0], msg)
    sys.exit(1)

if sys.argv[1] not in ('up', 'down'): usage('expected "up" or "down"')
going_up = sys.argv[1] == 'up'

if not search_domains: usage('no search domains (dhcp-option DOMAIN) provided')
if not nameservers: usage('no nameservers (dhcp-option DNS) provided')

try:
    tun_dev, tun_mtu, link_mtu, ifconfig_local_ip, ifconfig_remote_ip, \
      command = sys.argv[2:]
except: usage('expected arguments from OpenVPN')

try:
    # for Mac OS X Tiger and later, use supplemental match domains
    # see this thread for more information:
    # <http://lists.apple.com/archives/Macnetworkprog/2005/Jun/msg00011.html>
    from SystemConfiguration import *
    SC_IPV4_PATH, SC_DNS_PATH = ['/'.join((kSCDynamicStoreDomainState,
					   kSCCompNetwork, kSCCompService,
					   'net.openvpn.vpn-' + tun_dev, ent))
				 for ent in (kSCEntNetIPv4, kSCEntNetDNS)]
    store = UNSystemConfigurationDynamicStore.alloc().initWithName_('OpenVPN')
    if going_up:
	ipv4 = {kSCPropNetIPv4Addresses: [ifconfig_local_ip],
		kSCPropNetIPv4DestAddresses: [ifconfig_remote_ip],
		kSCPropInterfaceName: tun_dev}
	kSCPropSupplementalMatchDomains = 'SupplementalMatchDomains'
	dns = {kSCPropNetDNSServerAddresses: nameservers,
	       kSCPropSupplementalMatchDomains: search_domains}
	store.setValue_forKey_(ipv4, SC_IPV4_PATH)
	store.setValue_forKey_(dns, SC_DNS_PATH)
    else:
	store.removeValueForKey_(SC_IPV4_PATH)
	store.removeValueForKey_(SC_DNS_PATH)
except ImportError:
    pass

resolv_file_path = '/etc/resolv.conf'
if os.path.exists('/var/run/resolv.conf'):
    resolv_file_path = '/var/run/resolv.conf'

resolv_file = file(resolv_file_path, 'r+')
resolv_lines = resolv_file.readlines()

START_SKIP = '# begin %s OpenVPN tunnel modifications' % tun_dev
END_SKIP = '# end %s OpenVPN tunnel modifications' % tun_dev
search_domains = ['search'] + search_domains

in_skip = False
search_line = ' '.join(search_domains)

resolv_file.seek(0)
resolv_file.truncate()
for line in resolv_lines:
    if in_skip:
	if re.match(END_SKIP, line):
	    in_skip = False
	continue
    else:
	if re.match(START_SKIP, line):
	    in_skip = True
	    continue
    if line == '\n': continue
    if going_up:
	if re.match('nameserver ', line):
	    resolv_file.write('# ')
	if re.match('search ', line):
	    resolv_file.write('# ')
	    search_line = ' '.join(search_domains + \
                                   [domain for domain in line[:-1].split(' ')
                                    if domain not in search_domains])
    else:
	line = re.sub('# ', '', line)
    resolv_file.write(line)

if going_up:
    print >> resolv_file
    print >> resolv_file, START_SKIP
    for nameserver in nameservers:
	print >> resolv_file, 'nameserver', nameserver
    print >> resolv_file, search_line
    print >> resolv_file, END_SKIP

resolv_file.close()
