-
Notifications
You must be signed in to change notification settings - Fork 1
/
ddns.py
187 lines (159 loc) · 5.67 KB
/
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
"""
General help:
to run from the commandline:
python -m pyfooware.ddns godaddy
run with -h for a list of options
GoDaddy help:
to update GoDaddy DNS, first create the file $HOME/.godaddyrc with the
following three properties:
username=myuser
password=mypass
[email protected],www.domain2.org
the following updates GoDaddy and logs output to syslog (good for cron)
python -m pyfooware.ddns godaddy -l
"""
import network
import os.path
import sys
import syslog
class DDNSError(Exception):
def __init__(self, message, error=None):
self.message = message
self.error = error
def __repr__(self):
return self.message
def __str__(self):
return self.message
class DNSProvider(object):
def __init__(self, syslog_ident):
if syslog_ident:
self.syslogging_on = True
syslog.openlog(syslog_ident, facility=syslog.LOG_USER)
else:
self.syslogging_on = False
def update(self):
pass
def log(self, message):
print message
if self.syslogging_on:
syslog.syslog(syslog.LOG_ALERT, message)
def error(self, message):
if self.logging_on:
print >> sys.stderr, message
if self.syslogging_on:
syslog.syslog(syslog.LOG_ALERT, message)
class GoDaddy(DNSProvider):
def __init__(self, config_path=None, syslog_ident=None):
DNSProvider.__init__(self, syslog_ident)
self.config_path = config_path
if not self.config_path:
self.config_path = os.path.expanduser("~/.godaddyrc")
self._init_from_config()
def _init_from_config(self):
props = {}
lnbr = 0
try:
for line in open(self.config_path):
lnbr += 1
line = line.strip()
i = line.find("#")
if i >= 0:
line = line[:i]
if not line:
continue
name, value = line.split("=")
props[name] = value
except ValueError as e:
msg = "invalid config value [line %s]: %s" % (lnbr, line)
self.error(msg)
raise DDNSError(msg)
except Exception as e:
msg = "error reading %s (%s)" % (self.config_path, `e`)
self.error(msg)
raise DDNSError(msg, e)
self.username = props.get("username", None)
if not self.username:
msg = "no godaddy username configured"
self.error(msg)
raise DDNSError(msg)
self.password = props.get("password", None)
if not self.password:
msg = "no godaddy password configured"
self.error(msg)
raise DDNSError(msg)
self.hosts = filter(lambda d: d != '', props.get("hosts", "").split(","))
if not self.hosts:
msg = "no godaddy hosts configured"
self.error(msg)
raise DDNSError(msg)
def update(self):
try:
wan_ip = network.Network().get_wan_ip()
except Exception as e:
raise DDNSError('error getting WAN IP', e)
self.log("router wan ip is " + wan_ip)
godaddy = pygodaddy.GoDaddyClient()
if not godaddy.login(self.username, self.password):
msg = "godaddy login failure for " + self.username
self.error(msg)
raise DDNSError(msg)
for host in self.hosts:
name, domain = host.split(".", 1)
recs = godaddy.find_dns_records(domain)
if recs:
for rec in recs:
if rec.hostname != name:
continue
if rec.value == wan_ip:
self.log("%s already set to %s, skipping" % (host, wan_ip))
else:
self.log("updating %s from %s to %s" %
(host, rec.value, wan_ip))
dns_entry = domain if name == "@" else host
if not godaddy.update_dns_record(dns_entry, wan_ip):
self.log("failed to update %s dns record" % dns_entry)
break
else:
self.log("no record found for %s" % host)
else:
self.log("no records for %s" % host)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("provider",
metavar="provider",
help="dns provider name")
parser.add_argument("-l", "--log",
dest="logging",
action="store_true",
help="log to syslog")
parser.add_argument("-i", "--ident",
metavar="name",
dest="syslog_ident",
nargs="?",
help="syslog identifier (default: ddns_<provider>)")
args = parser.parse_args(sys.argv[1:])
try:
if args.provider == "godaddy":
try:
import pygodaddy
except ImportError as e:
msg = "pygodaddy module not found: " + \
"https://pygodaddy.readthedocs.org/"
print >> sys.stderr, msg
raise DDNSError(msg)
if args.logging:
ident = args.syslog_ident
if not args.syslog_ident:
ident = "ddns_" + args.provider
else:
ident=None
provider = GoDaddy(syslog_ident=ident)
else:
msg = "unknown dns provider: " + args.provider
print >> sys.stderr, msg
raise DDNSError(msg)
provider.update()
except DDNSError as e:
print "fatal error:", e
sys.exit(1)