Fixed bug: Some exceptions were not caught.
[toast/tdyndns.git] / bin / nsupdate_dyndns
1 #!/usr/bin/python
2 import re
3 import argparse
4 from subprocess import Popen, PIPE
5 import ipaddr
6
7
8 def ipfamily_by_ip(ip):
9         if isinstance(ip, ipaddr.IPv4Address):
10                 return 'A'
11         elif isinstance(ip, ipaddr.IPv6Address):
12                 return 'AAAA'
13         assert False
14
15
16 def nsupdate_add(hostname, domain, ttl, ip):
17         """ip_family: A or AAAA"""
18         command = "update add {hostname}.{domain} {ttl} IN {ip_family} {ip}\n\n".format(hostname=hostname, domain=domain, ttl=ttl, ip_family=ipfamily_by_ip(ip), ip=ip)
19         p = Popen(['nsupdate', '-l'], stdin=PIPE)
20         p.communicate(command)
21
22
23 def nsupdate_delete(hostname, domain, ip_family):
24         """ip_family: A or AAAA"""
25         command = "update delete {hostname}.{domain} {ip_family}\n\n".format(hostname=hostname, domain=domain, ip_family=ip_family)
26         p = Popen(['nsupdate', '-l'], stdin=PIPE)
27         p.communicate(command)
28
29
30 def main(args):
31         if args.delete:
32                 if args.ip is None:
33                         nsupdate_delete(args.hostname, args.domain, 'A')
34                         nsupdate_delete(args.hostname, args.domain, 'AAAA')
35                 else:
36                         nsupdate_delete(args.hostname, args.domain, ipfamily_by_ip(args.ip))
37         else:
38                 nsupdate_delete(args.hostname, args.domain, ipfamily_by_ip(args.ip))
39                 nsupdate_add(args.hostname, args.domain, args.ttl, args.ip)
40
41
42 if __name__ == '__main__':
43         parser = argparse.ArgumentParser(description='Add or delete a hostname from dyndns (simplifies call to nsupdate).')
44         parser.add_argument('-d', '--delete', action='store_true', help='delete instead of add')
45         parser.add_argument('-i', '--ip', help='IP address (either IPv4 or IPv6)')
46         # parser.add_argument('-t', '--ttl', type=int, default=600, help='TTL (default: 600)')
47         parser.add_argument('hostname', help='hostname to add or delete, e.g. myserver')
48         args = parser.parse_args()
49
50         args.domain = 'dyn.colgarra.priv.at' # <---- TODO
51         args.ttl = 600 # <---- TODO
52
53         # check ip
54         if not args.delete and not args.ip:
55                 parser.error('The IP address is mandatory')
56         if args.ip:
57                 try:
58                         args.ip = ipaddr.IPAddress(args.ip) # throws an exception if the IP address is not valid
59                 except ValueError:
60                         parser.error('The IP address is not valid')
61
62         # check hostname
63         if re.match(r'[-0-9a-z]+(\.[-0-9a-z]+)*$', args.hostname) is None:
64                 parser.error('The hostname has an invalid format.')
65
66         main(args)