Skip to content

Instantly share code, notes, and snippets.

@letenkov
Forked from pklaus/ddns.py
Created February 11, 2013 08:44
Show Gist options
  • Save letenkov/4753314 to your computer and use it in GitHub Desktop.
Save letenkov/4753314 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Written on 2013-02-04 by Philipp Klaus <philipp.l.klaus →AT→ web.de>.
Check <https://gist.github.com/4707775> for newer versions.
A script to update the A and AAAA RRs of HOSTNAME on a DNS server
according to your actual ones using nsupdate / TSIG.
This script is ready to run on Mac OS X (10.8) but you should be able
to get it up and running in almost no time on other Unix or Linux systems.
Uses dnspython: install using `pip3 install dnspython3`
"""
import argparse, sys
global Verbose
Verbose = False
def get_external_IP(get_ipv6=False):
import urllib.request
import ipaddress
ADDR = "http://v6.ipv6-test.com/api/myip.php" if get_ipv6 else "http://v4.ipv6-test.com/api/myip.php"
retval = urllib.request.urlopen(ADDR).read().decode('ascii')
try:
ip = ipaddress.ip_address('192.168.0.1')
return retval
except:
return None
def get_RR_value(FQDN, kind="A"):
import dns.resolver
try:
answer = dns.resolver.query(FQDN, kind)
if len(answer) == 0:
return None
return answer[0].to_text()
except dns.resolver.NXDOMAIN:
return None
def IPs_match_current_RRs(FQDN):
my_IPv4 = get_external_IP(get_ipv6=False)
my_IPv6 = get_external_IP(get_ipv6=True)
if Verbose: print("Current IPv4 and IPv6 addresses: %s and %s." % (my_IPv4, my_IPv6))
cur_RR_v4 = get_RR_value(FQDN, 'A')
cur_RR_v6 = get_RR_value('sb.dyn.klaus.bz.', 'AAAA')
if Verbose: print("Current IPv4 and IPv6 RRs in DNS: %s and %s." % (cur_RR_v4, cur_RR_v6))
return (my_IPv4 == cur_RR_v4 and my_IPv6 == cur_RR_v6)
def update_dns(server, zone, keyfile, domain, IPv4_addr=None, IPv6_addr=None, TTL=30):
import subprocess
command = "server %s\n" % server
command += "zone %s\n" % zone
command += "update delete %s A\n" % domain
command += "update delete %s AAAA\n" % domain
if IPv4_addr:
command += "update add %s %s A %s\n" % (domain, TTL, IPv4_addr)
if IPv6_addr:
command += "update add %s %s AAAA %s\n" % (domain, TTL, IPv6_addr)
command += "show\nsend\n"
command = "nsupdate -k {0} -v << EOF\n{1}\nEOF\n".format(keyfile, command)
subprocess.call(command, shell=True)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Update the RRs of HOSTNAME on a DNS server according to your actual ones.')
parser.add_argument('-v', '--verbose', action='store_true',
help='Create more detailed output.')
parser.add_argument('-z', '--zone', metavar='ZONE',
help='The zone of the host to update.', required=True)
parser.add_argument('-k', '--keyfile', metavar='DNSSEC-file.key',
help='The key file for TSIG.', required=True)
parser.add_argument('-n', '--nameserver', metavar='NS',
help='The name server to update.', required=True)
parser.add_argument('host', metavar='HOSTNAME',
help='The hostname you want updated.')
args = parser.parse_args()
if args.verbose: Verbose = True
if not IPs_match_current_RRs(args.host):
if Verbose: print("The current IPs and the RRs do not match. Updating the DNS server...")
update_dns(args.nameserver, args.zone, args.keyfile, args.host, get_external_IP(), get_external_IP(True))
else:
if Verbose: print("The current IPs and the RRs are matching. Everyting OK.")
sys.exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment