def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" if not ip: raise ServiceError("IP must be defined.") self._init_auth() opts = dict_of_opts(options) if 'zone' not in opts: raise ServiceError('Required option zone= missing, giving up.') session = Session() opts['zone_id'] = self._get_zoneid(session, opts) dnsrecords = self._get_dnsrecords(session, hostname, opts) ipv4_id, ipv4 = _get_ipv4_from_dnsrecords(dnsrecords) ipv6_id, ipv6 = _get_ipv6_from_dnsrecords(dnsrecords) log.debug("host=%s existing_ipv4=%s existing_ipv6=%s", hostname, ipv4, ipv6) if ip.v4: if ipv4 != ip.v4: record = {'type': 'A', 'name': hostname, 'content': ip.v4} if ipv4_id: log.debug( "method=update_A host=%s existing=%s expected=%s", hostname, ipv4, ip.v4) ipv4_id, ipv4 = self._update_dnsrecord( session, ipv4_id, record, opts) else: log.debug( "method=create_A host=%s existing=%s expected=%s", hostname, ipv4, ip.v4) ipv4_id, ipv4 = self._create_dnsrecord( session, record, opts) log.debug("ipv4_id=%s updated_ipv4=%s", ipv4_id, ipv4) else: log.info("Existing ipv4 record matches, skipping update") if ip.v6: if ipv6 != ip.v6: record = {'type': 'AAAA', 'name': hostname, 'content': ip.v6} if ipv6_id: log.debug( "method=update_AAAA host=%s existing=%s expected=%s", hostname, ipv6, ip.v6) ipv6_id, ipv6 = self._update_dnsrecord( session, ipv6_id, record, opts) else: log.debug( "method=create_AAAA host=%s existing=%s expected=%s", hostname, ipv6, ip.v6) ipv6_id, ipv6 = self._create_dnsrecord( session, record, opts) log.debug("ipv6_id=%s updated_ipv6=%s", ipv6_id, ipv6) else: log.info("Existing ipv6 record matches, skipping update")
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register.""" url = self._url.format(hostname) http_basic_auth_setup(url) html = get_response(log, url) if html.split()[0] not in ['nochg', 'good']: raise ServiceError("Bad update reply: " + html)
def register(self, log, hostname, ip, options): """ Based on http://freedns.afraid.org/api/, needs _url below to update. The sha parameter is sha1sum of login|password. This returns a list of host|currentIP|updateURL lines. Pick the line that matches myhost, and fetch the URL. word 'Updated' for success, 'fail' for failure. """ def build_shasum(): """Compute sha1sum('user|password') used in url.""" user, password = get_netrc_auth('freedns.afraid.org') token = "{0}|{1}".format(user, password) return hashlib.sha1(token.encode()).hexdigest() shasum = build_shasum() url = self._url.format(shasum) if ip and ip.v6: url += "&address=" + str(ip.v6) elif ip and ip.v4: url += "&address=" + str(ip.v4) html = get_response(log, url) update_url = None for line in html.split("\n"): log.debug("Got line: " + line) tokens = line.split("|") if tokens[0] == hostname: update_url = tokens[2] break if not update_url: raise ServiceError("Cannot see %s being set up at this account" % hostname) log.debug("Contacting freedns for update on %s", update_url) get_response(log, update_url)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register.""" opts = dict_of_opts(options) log.debug(opts) if 'server' not in opts: log.error("Required server option missing, giving up") sys.exit(2) args = ('nsupdate', ) if 'key' in opts: args += ('-k', opts['key'].encode('ascii')) p = Popen(args, stdout=PIPE, stdin=PIPE) p.stdin.write(b'server ' + opts['server'].encode('ascii') + b'\n') try: p.stdin.write(b'zone ' + opts['zone'].encode('ascii') + b'\n') except KeyError: pass hostname = hostname.encode('ascii') if ip: if ip.v4: addr = ip.v4.encode('ascii') p.stdin.write(b'update delete ' + hostname + b' A\n') p.stdin.write(b'update add ' + hostname + b' 60 A ' + addr + b'\n') if ip.v6: addr = ip.v6.encode('ascii') p.stdin.write(b'update delete ' + hostname + b' AAAA\n') p.stdin.write(b'update add ' + hostname + b' 60 AAAA ' + addr + b'\n') p.stdin.write(b'send\n') stdout, err = p.communicate() if not (err is None): raise ServiceError("Bad update reply: " + stdout.decode('ascii'))
def _call(session, request): """Call Cloudflare V4 API.""" try: prepped = session.prepare_request(request) res = session.send(prepped) if res.status_code / 100 != 2: raise ServiceError("Error retrieving %s: status %d" % (request.url, res.status_code)) json = res.json() if not json['success']: raise ServiceError("Error retrieving %s: errors %s" % (request.url, json['errors'])) return json['result'] except ValueError as err: raise ServiceError("Error parsing response %s: %s" % (request.url, err))
def register(self, log, hostname, ip, options): """Implement AddressPlugin.get_ip().""" if not ip: log.warn(self._ip_warning) user, password = get_netrc_auth('update.dnsexit.com') url = self._url.format(self._api_host, user, password, hostname) if ip: url += "&myip=" + ip.v4 # if debugging: # url += "&force=Y" # override 8 minutes server limit html = get_response(log, url).split('\n') if '200' not in html[0]: raise ServiceError("Bad HTML response: " + html) code = html[1].split('=')[0] if int(code) > 1: raise ServiceError("Bad update response: " + html[1]) log.info("Response: " + html[1])
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register.""" url = self._url.format(hostname) if ip: url += "&ip=" + ip.v4 http_basic_auth_setup(url) html = get_response(log, url) if 'uccessful' not in html: raise ServiceError("Bad update reply: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" url = self._url.format(hostname) if ip: url += '&myip=' + ip.v4 http_basic_auth_setup(url) html = get_response(log, request) if html not in ['good', 'nochg']: raise ServiceError('Bad server reply: ' + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" url = self._url.format(hostname) if ip and ip.v4: url += "&ip=" + ip.v4 http_basic_auth_setup(url) reply = get_response(log, url).strip() if reply not in ['ok', 'nochange']: raise ServiceError("Unexpected update reply: " + reply)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" password = get_netrc_auth('dynv6.com')[1] query = {"hostname": hostname, "token": password} query['ipv4'] = ip.v4 if ip and ip.v4 else "auto" query['ipv6'] = ip.v6 if ip and ip.v6 else "auto" html = get_response(log, self._url + urllib.parse.urlencode(query)) if not ('updated' in html or 'unchanged' in html): raise ServiceError("Update error, got: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" password = get_netrc_auth('dynv6.com')[1] url = self._url.format(hostname, password) if ip and ip.v4: url += "&ipv4=" + ip.v4 if ip and ip.v6: url += "&ipv6=" + ip.v6 html = get_response(log, url) if not ('updated' in html or 'unchanged' in html): raise ServiceError("Update error, got: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" password = get_netrc_auth('system-ns.com')[1] url = self._url.format(self._apihost, hostname, password) if ip: url += "&ip=" + ip.v4 html = get_response(log, url) reply = json.loads(html) if reply['code'] > 2: raise ServiceError('Bad reply code {0}, message: {1}'.format( reply['code'], reply['msg'])) log.info("Server reply: " + reply['msg'])
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" password = get_netrc_auth('www.duckdns.org')[1] host = hostname.split('.duckdns.org')[0] url = self._url.format(host, password) if ip and ip.v4: url += "&ip=" + ip.v4 if ip and ip.v6: url += "&ipv6=" + ip.v6 html = get_response(log, url) if html.strip() != "OK": raise ServiceError("Update error, got: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" url = self._url.format(hostname) if ip.v4: url += "&myipv4=" + ip.v4 if ip.v6: url += "&myipv6=" + ip.v6 password = get_netrc_auth(hostname)[1] hdr = ('Authorization', 'Token ' + password) reply = get_response(log, url, header=hdr) if not ('good' in reply or 'throttled' in reply): raise ServiceError("Cannot update address: " + reply)
def _get_zoneid(self, session, opts): """Retrieve an identifier for a given zone name.""" zone = opts['zone'] params = {'name': zone, 'per_page': 1} request = Request('GET', self._url + "/zones", params=params, auth=self._auth) res = _call(session, request) if res and len(res) == 1 and 'id' in res[0] and res[0]['id']: return res[0]['id'] raise ServiceError("Zone %s not found" % zone)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" url = self._url.format(hostname) if ip and ip.v4: url += "&ip=" + ip.v4 if ip and ip.v6: url += "&ip6=" + ip.v6 http_basic_auth_setup(url) html = get_response(log, url) key = html.split()[0] if key not in ['OK', 'good', 'nochg']: raise ServiceError("Bad server reply: " + html) log.info("Server reply: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" url = self._url.format(hostname) if ip: url += '&myip=' + ip.v4 api_host = urlparse(url).hostname username, password = get_netrc_auth(api_host) user_pw = ('%s:%s' % (username, password)) credentials = base64.b64encode(user_pw.encode('ascii')) auth_header = ('Authorization', 'Basic ' + credentials.decode("ascii")) reply = get_response(log, url, header=auth_header) if not ('good' in reply or 'nochg' in reply): raise ServiceError('Bad server reply: ' + reply)
def register(self, log, hostname, ip, options): """ Based on http://freedns.afraid.org/api/, needs _url below to update. """ user, password = get_netrc_auth('freedns.afraid.org') url = self._url.format(user, password, hostname) if ip and ip.v6: url += "&ip=" + str(ip.v6) elif ip and ip.v4: url += "&ip=" + str(ip.v4) html = get_response(log, url) if not ('Updated' in html or 'skipping' in html): raise ServiceError("Error updating %s" % hostname)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" url = self._url.format(hostname) if ip: url += '&myip=' + ip.v4 user, password = get_netrc_auth('now-dns.com') credentials = '%s:%s' % (user, password) encoded_credentials = base64.b64encode(credentials.encode('ascii')) req = urllib.request.Request(url) req.add_header('Authorization', 'Basic %s' % encoded_credentials.decode("ascii")) try: with urllib.request.urlopen(req) as response: code = response.getcode() html = response.read().decode('ascii').strip() except urllib.error.HTTPError as err: raise ServiceError("Error reading %s :%s" % (url, err)) if code != 200: raise ServiceError('Bad server reply code: ' + code) if html not in ['good', 'nochg']: raise ServiceError('Bad server reply: ' + html) log.info("Server reply: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" password = get_netrc_auth('ip.duiadns.net')[1] url = self._url.format(hostname, password) if not ip: log.warn("This plugin requires an ip address.") if ip and ip.v4: url += "&ip4=" + ip.v4 if ip and ip.v6: url += "&ip6=" + ip.v6 try: html = get_response(log, url) except ServiceError: resp = requests.get(url, verify=False) if resp.status_code != 200: raise ServiceError("Cannot access update url: " + url) \ from None html = resp.content.decode('ascii') parser = DuiadnsParser() parser.feed(html) if 'error' in parser.data or 'Ipv4' not in parser.data: raise ServiceError('Cannot parse server reply (see debug log)') log.info('New ip address: ' + parser.data['Ipv4'])
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" user, password = get_netrc_auth('www.dtdns.com') url = self._url.format(hostname, password) if ip: url += "&ip=" + ip.v4 try: html = get_response(log, url) except TimeoutError: # one more try... html = get_response(log, url) if 'points to' not in html: raise ServiceError("Bad update reply: " + html) log.info("Update completed: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" password = get_netrc_auth('ip.duiadns.net')[1] url = self._url.format(hostname, password) if not ip: log.warn("This plugin requires an ip address.") if ip and ip.v4: url += "&ip4=" + ip.v4 if ip and ip.v6: url += "&ip6=" + ip.v6 html = get_response(log, url) parser = DuiadnsParser() parser.feed(html) if 'error' in parser.data or 'Ipv4' not in parser.data: raise ServiceError('Cannot parse server reply (see debug log)') log.info('New ip address: ' + parser.data['Ipv4'])
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" url = self._url.format(hostname) api_host = urlparse(url).hostname username, password = get_netrc_auth(api_host) user_pw = ('%s:%s' % (username, password)) credentials = base64.b64encode(user_pw.encode('ascii')) auth_header = ('Authorization', 'Basic ' + credentials.decode("ascii")) url = self._url.format(hostname) if ip and ip.v4: url += "&ip=" + ip.v4 if ip and ip.v6: url += "&ip6=" + ip.v6 html = get_response(log, url, header=auth_header) key = html.split()[0] if key not in ['OK', 'good', 'nochg']: raise ServiceError("Bad server reply: " + html) log.info("Server reply: " + html)
def register(self, log, hostname, ip, options): """Implement ServicePlugin.register().""" query = { 'hostname': hostname, } # IP address is optional for IPv4 if ip: query['myip'] = ip.v6 or ip.v4 url = "{}?{}".format(self._url, urllib.parse.urlencode(query)) http_basic_auth_setup(url) request = urllib.request.Request(url=url, method='POST') html = get_response(log, request) code = html.split()[0] if code not in ['good', 'nochg']: raise ServiceError("Bad server reply: " + html)
def register(self, log: Logger, hostname: str, ip: IpAddr, options): """Implement ServicePlugin.register. Expects the `ip` to be filtered already according to the _global_ `--ip-version` option. """ url = self._url.format(hostname) if ip: if ip.v4: url += '&ip=' + ip.v4 if ip.v6: url += '&ip6=' + ip.v6 http_basic_auth_setup(url) body = get_response(log, url) # Get ASCII encoded body-content if not DeDnsHomeAddressPlugin.is_success(body): raise ServiceError("Bad update reply.\nMessage: " + body)
def error(self, message): """Implement HTMLParser.error().""" raise ServiceError("HTML parser error: " + message)
def error(message): """Just a shorthand.""" raise ServiceError("HTML parser error: " + message)