Quick'n'Dirty DNS Swapper

NOTE: This isn't plug-and-play production software—it illustrates a quick and dirty way to swap between OpenDNS and TorDNS using a locally installed copy of Dnsmasq. Tested with Python 2.7.5 on Debian jessie.

Caveats: The script's owner (weilawei), group (defaults to the owner), home directory (/home/weilawei/code/rst), target (/etc/dnsmasq.conf), and base name for the replacement (/home/weilawei/code/rst/etc/dnsmasq.conf.) are hardcoded, but it's not meant to do anything else. It also expects a directory structure (below rst_home) looking something like:

rst_home/

bin/
etc/
bin/sdns
etc/dnsmasq.conf.opendns
etc/dnsmasq.conf.tordns
etc/.backup/

The .backup directory is used to store a copy of the current configuration before swapping in the new one. (Just In Case.)

You'll also need to edit /etc/sudoers and add rst_home/bin (/home/weilawei/code/rst/bin in my case) to secure_path or sudo won't let you execute it without specifying the full path.

Finally, /etc/dhcp/dhclient.conf contains a directive telling it to supersede the DHCP-supplied DNS servers with the value 127.0.0.1 (our Dnsmasq server) in /etc/resolv.conf and additionally, does not request nameservers:

/etc/dhcp/dhclient.conf

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
send host-name = gethostname();
supersede domain-name-servers 127.0.0.1;
request subnet-mask, 
    broadcast-address,
    time-offset, 
    routers,
    host-name, 
    netbios-name-servers, 
    netbios-scope, 
    interface-mtu,
    rfc3442-classless-static-routes, 
    ntp-servers;

Usage: sudo sdns alternative where alternative is a suffix applied to the base name of the replacement.

Examples: sudo sdns opendns, sudo sdns tordns

rst_home/bin/sdns

#!/usr/bin/env python

import sys
import hashlib
import subprocess

if (len(sys.argv) < 2):
    print("No alternative given")
    sys.exit(1)

owner       = "weilawei"
group       = owner
rst_home    = "/home/%s/code/rst" % owner
target      = "/etc/dnsmasq.conf"
replacement = "%s/etc/dnsmasq.conf.%s" % (rst_home, sys.argv[1])

backup_file     = open("/etc/dnsmasq.conf", 'rb')
backup_shasum   = hashlib.sha1(backup_file.read()).hexdigest()
backup_file.close()
backup          = "%s/etc/.backup/dnsmasq.conf.%s" % (rst_home, backup_shasum)

def call_or_die(parameters):
    retcode = subprocess.call(parameters)
    if (retcode != 0): sys.exit(retcode)

call_or_die(['cp', target, backup])
call_or_die(['chmod', '640', backup])
call_or_die(['chown', owner, backup])
call_or_die(['chgrp', group, backup])
call_or_die(['cp', replacement, target])
call_or_die(['service', 'dnsmasq', 'restart'])

rst_home/etc/dnsmasq.conf.opendns

listen-address=127.0.0.1

server=208.67.220.220
server=208.67.222.222
bogus-nxdomain=67.215.65.132

rst_home/etc/dnsmasq.conf.tordns

listen-address=127.0.0.1

server=127.0.0.1#9053
cache-size=0
max-cache-ttl=0
no-negcache

Sections