Last active
December 28, 2016 14:05
-
-
Save darth-veitcher/7d0e81069e8fe29bfcb0297fa89fbb06 to your computer and use it in GitHub Desktop.
Update Cloudflare DNS record for Dynamic IP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| # https://github.com/cloudflare/python-cloudflare/blob/master/examples/example_update_dynamic_dns.py | |
| """CloudFlare API code - example""" | |
| import os | |
| import sys | |
| import re | |
| import json | |
| import requests | |
| sys.path.insert(0, os.path.abspath('..')) | |
| import CloudFlare | |
| cf = CloudFlare.CloudFlare() | |
| def my_ip_address(): | |
| """CloudFlare API code - example""" | |
| # This list is adjustable - plus some v6 enabled services are needed | |
| # url = 'http://myip.dnsomatic.com' | |
| # url = 'http://www.trackip.net/ip' | |
| # url = 'http://myexternalip.com/raw' | |
| url = 'https://api.ipify.org' | |
| try: | |
| ip_address = requests.get(url).text | |
| except: | |
| exit('%s: failed' % (url)) | |
| if ip_address == '': | |
| exit('%s: failed' % (url)) | |
| if ':' in ip_address: | |
| ip_address_type = 'AAAA' | |
| else: | |
| ip_address_type = 'A' | |
| print("External IP Address: {0}, {1}".format(ip_address, ip_address_type)) | |
| return ip_address, ip_address_type | |
| def do_dns_update(cf, zone_name, zone_id, dns_name, ip_address, ip_address_type): | |
| """CloudFlare API code - example""" | |
| try: | |
| params = {'name':dns_name, 'match':'all', 'type':ip_address_type} | |
| dns_records = cf.zones.dns_records.get(zone_id, params=params) | |
| except CloudFlare.CloudFlareAPIError as e: | |
| exit('/zones/dns_records %s - %d %s - api call failed' % (dns_name, e, e)) | |
| updated = False | |
| # update the record - unless it's already correct | |
| for dns_record in dns_records: | |
| old_ip_address = dns_record['content'] | |
| old_ip_address_type = dns_record['type'] | |
| if ip_address_type not in ['A', 'AAAA']: | |
| # we only deal with A / AAAA records | |
| continue | |
| if ip_address_type != old_ip_address_type: | |
| # only update the correct address type (A or AAAA) | |
| # we don't see this becuase of the search params above | |
| print 'IGNORED: %s %s ; wrong address family' % (dns_name, old_ip_address) | |
| continue | |
| if ip_address == old_ip_address: | |
| print 'UNCHANGED: %s %s' % (dns_name, ip_address) | |
| updated = True | |
| continue | |
| # Yes, we need to update this record - we know it's the same address type | |
| dns_record_id = dns_record['id'] | |
| dns_record = { | |
| 'name':dns_name, | |
| 'type':ip_address_type, | |
| 'content':ip_address | |
| } | |
| try: | |
| dns_record = cf.zones.dns_records.put(zone_id, dns_record_id, data=dns_record) | |
| except CloudFlare.CloudFlareAPIError as e: | |
| exit('/zones.dns_records.put %s - %d %s - api call failed' % (dns_name, e, e)) | |
| print 'UPDATED: %s %s -> %s' % (dns_name, old_ip_address, ip_address) | |
| updated = True | |
| if updated: | |
| return | |
| # no exsiting dns record to update - so create dns record | |
| dns_record = { | |
| 'name':dns_name, | |
| 'type':ip_address_type, | |
| 'content':ip_address | |
| } | |
| try: | |
| dns_record = cf.zones.dns_records.post(zone_id, data=dns_record) | |
| except CloudFlare.CloudFlareAPIError as e: | |
| exit('/zones.dns_records.post %s - %d %s - api call failed' % (dns_name, e, e)) | |
| print 'CREATED: %s %s' % (dns_name, ip_address) | |
| def main(args): | |
| """CloudFlare API code - example. Modified to allow multiple records""" | |
| ip_address, ip_address_type = my_ip_address() | |
| cf = CloudFlare.CloudFlare() | |
| for dns_name in args.dns_names: | |
| print 'MY IP: %s %s' % (dns_name, ip_address) | |
| host_name, zone_name = dns_name.split('.', 1) | |
| # grab the zone identifier | |
| try: | |
| params = {'name':zone_name} | |
| zones = cf.zones.get(params=params) | |
| except CloudFlare.CloudFlareAPIError as e: | |
| exit('/zones %d %s - api call failed' % (e, e)) | |
| except Exception as e: | |
| exit('/zones.get - %s - api call failed' % (e)) | |
| if len(zones) == 0: | |
| print('/zones.get - %s - zone not found' % (zone_name)) | |
| try: | |
| params = {'name':dns_name} | |
| zones = cf.zones.get(params=params) | |
| except Exception as e: | |
| exit('/zones.get - %s - api call failed with root attempt' % (e)) | |
| if len(zones) != 1: | |
| exit('/zones.get - %s - api call returned %d items' % (zone_name, len(zones))) | |
| zone = zones[0] | |
| zone_name = zone['name'] | |
| zone_id = zone['id'] | |
| do_dns_update(cf, zone_name, zone_id, dns_name, ip_address, ip_address_type) | |
| exit(0) | |
| if __name__ == '__main__': | |
| # do stuff | |
| import argparse | |
| parser = argparse.ArgumentParser(description='Commandline settings') | |
| parser.add_argument('dns_names', nargs='*', help='list of records to update') | |
| args = parser.parse_args() | |
| main(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Script that can be called with
cronto update (potentially) multiple DNS records and associate them with the IP of the calling device.e.g. to update at **:05 every hour