-
Notifications
You must be signed in to change notification settings - Fork 62
/
godaddy_ddns.py
executable file
·162 lines (140 loc) · 6.85 KB
/
godaddy_ddns.py
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python3
#
# Update GoDaddy DNS "A" Record.
#
# usage: godaddy_ddns.py [-h] [--version] [--ip IP] [--key KEY]
# [--secret SECRET] [--ttl TTL] [--force]
# hostname
#
# positional arguments:
# hostname DNS fully-qualified host name with an 'A' record. If the hostname consists of only a domain name
# (i.e., it contains only one period), the record for '@' is updated.
#
# optional arguments:
# -h, --help show this help message and exit
# --version show program's version number and exit
# --ip IP DNS Address (defaults to public WAN address from https://checkip.amazonaws.com/)
# --key KEY GoDaddy production key
# --secret SECRET GoDaddy production secret
# --ttl TTL DNS TTL.
# --force force update of GoDaddy DNS record even if DNS query indicates that record is already correct
#
# GoDaddy customers can obtain values for the KEY and SECRET arguments by creating a production key at
# https://developer.godaddy.com/keys/.
#
# Note that command line arguments may be specified in a FILE, one to a line, by instead giving
# the argument "%FILE". For security reasons, it is particularly recommended to supply the
# KEY and SECRET arguments in such a file, rather than directly on the command line:
#
# Create a file named, e.g., `godaddy-ddns.config` with the content:
# MY.FULLY.QUALIFIED.HOSTNAME.COM
# --key
# MY-KEY-FROM-GODADDY
# --secret
# MY-SECRET-FROM-GODADDY
#
# Then just invoke `godaddy-ddns %godaddy-ddns.config`
prog='godaddy-ddns'
version='0.4'
author='Carl Edman ([email protected])'
import sys, json, argparse, socket
if sys.version_info > (3,):
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError
else:
from urllib2 import urlopen, Request
from urllib2 import URLError, HTTPError
parser = argparse.ArgumentParser(description='Update GoDaddy DNS "A" Record.', fromfile_prefix_chars='%', epilog= \
'''GoDaddy customers can obtain values for the KEY and SECRET arguments by creating a production key at
https://developer.godaddy.com/keys/.
Note that command line arguments may be specified in a FILE, one to a line, by instead giving
the argument "%FILE". For security reasons, it is particularly recommended to supply the
KEY and SECRET arguments in such a file, rather than directly on the command line.''')
parser.add_argument('--version', action='version',
version='{} {}'.format(prog, version))
parser.add_argument('hostname', type=str,
help='DNS fully-qualified host name with an A record. If the hostname consists of only a domain name (i.e., it contains only one period), the record for @ is updated.')
parser.add_argument('--ip', type=str, default=None,
help='IPv4 address to write to DNS record (defaults to public WAN address from https://checkip.amazonaws.com/)')
parser.add_argument('--key', type=str, default='',
help='GoDaddy production key')
parser.add_argument('--secret', type=str, default='',
help='GoDaddy production secret')
parser.add_argument('--ttl', type=int, default=3600,
help='DNS TTL.')
parser.add_argument('--force', type=bool, default=False,
help='force update of GoDaddy DNS record even if DNS query indicates that record is already correct.')
args = parser.parse_args()
def main():
hostnames = args.hostname.split('.')
if len(hostnames)<2:
msg = 'Hostname "{}" is not a fully-qualified host name of form "HOST.DOMAIN.TOP".'.format(args.hostname)
raise Exception(msg)
elif len(hostnames)<3:
hostnames.insert(0,'@')
if not args.ip:
try:
with urlopen(Request("https://checkip.amazonaws.com/", headers={'User-Agent': 'Mozilla'})) as f: resp=f.read()
if sys.version_info > (3,): resp = resp.decode('utf-8')
args.ip = resp.strip()
except URLError:
msg = 'Unable to automatically obtain IP address from https://checkip.amazonaws.com/.'
raise Exception(msg)
ipslist = args.ip.split(",")
for ipsiter in ipslist:
ips = ipsiter.split('.')
if len(ips)!=4 or \
not ips[0].isdigit() or not ips[1].isdigit() or not ips[2].isdigit() or not ips[3].isdigit() or \
int(ips[0])>255 or int(ips[1])>255 or int(ips[2])>255 or int(ips[3])>255:
msg = '"{}" is not valid IP address.'.format(ips)
raise Exception(msg)
if not args.force and len(ipslist)==1:
try:
dnsaddr = socket.gethostbyname(args.hostname)
if ipslist[0] == dnsaddr:
msg = '{} already has IP address {}.'.format(args.hostname, dnsaddr)
raise Exception(msg)
except:
pass
url = 'https://api.godaddy.com/v1/domains/{}/records/A/{}'.format('.'.join(hostnames[1:]),hostnames[0])
data = json.dumps([ { "data": ip, "ttl": args.ttl, "name": hostnames[0], "type": "A" } for ip in ipslist])
if sys.version_info > (3,): data = data.encode('utf-8')
req = Request(url, method='PUT', data=data)
req.add_header("Content-Type","application/json")
req.add_header("Accept","application/json")
if args.key and args.secret:
req.add_header("Authorization", "sso-key {}:{}".format(args.key,args.secret))
try:
with urlopen(req) as f: resp = f.read()
if sys.version_info > (3,): resp = resp.decode('utf-8')
# resp = json.loads(resp)
except HTTPError as e:
if e.code==400:
msg = 'Unable to set IP address: GoDaddy API URL ({}) was malformed.'.format(req.full_url)
elif e.code==401:
if args.key and args.secret:
msg = '''Unable to set IP address: --key or --secret option incorrect.
Correct values can be obtained from from https://developer.godaddy.com/keys/ and are ideally placed in a % file.'''
else:
msg = '''Unable to set IP address: --key or --secret option missing.
Correct values can be obtained from from https://developer.godaddy.com/keys/ and are ideally placed in a % file.'''
elif e.code==403:
msg = '''Unable to set IP address: customer identified by --key and --secret options denied permission.
Correct values can be obtained from from https://developer.godaddy.com/keys/ and are ideally placed in a % file.'''
elif e.code==404:
msg = 'Unable to set IP address: {} not found at GoDaddy.'.format(args.hostname)
elif e.code==422:
msg = 'Unable to set IP address: "{}" has invalid domain or lacks A record.'.format(args.hostname)
elif e.code==429:
msg = 'Unable to set IP address: too many requests to GoDaddy within brief period.'
elif e.code==503:
msg = 'Unable to set IP address: "{}" is unavailable.'.format(args.hostname)
else:
msg = 'Unable to set IP address: GoDaddy API failure because "{}".'.format(e.reason)
raise Exception(msg)
except URLError as e:
msg = 'Unable to set IP address: GoDaddy API failure because "{}".'.format(e.reason)
raise Exception(msg)
print('IP address for {} set to {}.'.format(args.hostname,args.ip))
if __name__ == '__main__':
main()