Created
January 6, 2010 18:33
-
-
Save edwardgeorge/270506 to your computer and use it in GitHub Desktop.
save dhcp provided dns servers to resolv.conf compatible file (OSX)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
"""OSX-based script to watch for changes to network state and write out a | |
second resolv.conf file containing the DHCP provided nameservers, intended | |
for use with a local resolver such as dnsmasq. This is to workaround the | |
changes in Snow Leopard from Leopard with regards to DNS resolution. | |
ie: the inability to have both manually configured nameservers and | |
DHCP provided ones as well as the issues with split-DNS. | |
usage: python automasq.py /path/to/second/resolv.conf | |
""" | |
import optparse | |
import sys | |
from SystemConfiguration import * | |
GLOBAL_KEY = 'State:/Network/Global/IPv4' | |
class Watcher(object): | |
def __init__(self, filename, defaults_filename=None, | |
append_defaults=False): | |
self.filename = filename | |
self.defaults = defaults_filename | |
self.append = append_defaults | |
store = self.store = SCDynamicStoreCreate(None, "automasq", | |
self.dynamicStoreChanged, None) | |
SCDynamicStoreSetNotificationKeys(store, None, [GLOBAL_KEY]) | |
source = self.source = SCDynamicStoreCreateRunLoopSource(None, | |
store, 0) | |
self.write_file(self.get_primary_dns(store)) | |
loop = self.loop = CFRunLoopGetCurrent() | |
CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes) | |
CFRunLoopRun() | |
def write_file(self, servers=[]): | |
with open(self.filename, 'w+') as f: | |
for server in servers: | |
f.write('nameserver %s\n' % server) | |
if (self.append or not servers) and self.defaults is not None: | |
with open(self.defaults) as d: | |
f.write(d.read()) | |
def process_dns_for_service(self, store, service): | |
key = 'State:/Network/Service/%s/DNS' % service | |
val = SCDynamicStoreCopyValue(store, key) | |
data = list(dict(val)['ServerAddresses']) | |
return data | |
def get_primary_dns(self, store=None): | |
store = store or self.store | |
val = SCDynamicStoreCopyValue(store, GLOBAL_KEY) | |
if val: | |
data = dict(val) | |
svcid = data['PrimaryService'] | |
return self.process_dns_for_service(store, svcid) | |
else: | |
return [] | |
def dynamicStoreChanged(self, store, changedKeys, info): | |
servers = [] | |
for key in list(changedKeys): | |
#if key == GLOBAL_KEY: | |
servers = self.get_primary_dns(store) | |
self.write_file(servers) | |
def dummy_timer(*args): | |
pass | |
def main(filename, options): | |
# this gives us a callback into python every 1s for signal handling | |
CFRunLoopAddTimer(CFRunLoopGetCurrent(), | |
CFRunLoopTimerCreate(None, CFAbsoluteTimeGetCurrent(), 1.0, 0, 0, | |
dummy_timer, None), | |
kCFRunLoopCommonModes) | |
try: | |
watcher = Watcher(filename, defaults_filename=options.default, | |
append_defaults=options.append_defaults) | |
except KeyboardInterrupt, e: | |
# exiting | |
pass | |
if __name__ == '__main__': | |
usage = "usage: %prog [options] output-file" | |
parser = optparse.OptionParser(usage) | |
parser.add_option('-d', '--default-conf', dest='default', | |
help='default conf if no resolvers provided', metavar='RESOLVCONF') | |
parser.add_option('-a', '--append', dest='append_defaults', | |
action='store_true', | |
help='always append defaults to generated resolv.conf') | |
opts, args = parser.parse_args() | |
if len(args) != 1: | |
parser.error("specify a single output-file") | |
if opts.append_defaults and not opts.default: | |
parser.error("default conf must be specified to be able to append") | |
main(args[0], opts) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>KeepAlive</key> | |
<true/> | |
<key>Label</key> | |
<string>org.insectsarerubbish.automasq</string> | |
<key>ProgramArguments</key> | |
<array> | |
<string>/Users/edwardgeorge/bin/automasq.py</string> | |
<string>-d</string> | |
<string>/Users/edwardgeorge/etc/resolv.external.conf</string> | |
<string>/Users/edwardgeorge/etc/resolv.auto.conf</string> | |
</array> | |
<key>RunAtLoad</key> | |
<true/> | |
</dict> | |
</plist> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment