longchute

about

Quick'n'Dirty DNS Swapper

06 Oct 2013

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

1
2
3
4
5
6
7
8
9
10
11
12
13
    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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/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

1
2
3
4
5
    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

1
2
3
4
5
6
    listen-address=127.0.0.1
    
    server=127.0.0.1#9053
    cache-size=0
    max-cache-ttl=0
    no-negcache