#!/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: # 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()