Skip to content

Instantly share code, notes, and snippets.

@darth-veitcher
Last active December 28, 2016 14:05
Show Gist options
  • Save darth-veitcher/7d0e81069e8fe29bfcb0297fa89fbb06 to your computer and use it in GitHub Desktop.
Save darth-veitcher/7d0e81069e8fe29bfcb0297fa89fbb06 to your computer and use it in GitHub Desktop.
Update Cloudflare DNS record for Dynamic IP
#!/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)
@darth-veitcher
Copy link
Author

Script that can be called with cron to update (potentially) multiple DNS records and associate them with the IP of the calling device.

e.g. to update at **:05 every hour

# Wildcard * and tld update
0 5 * * *  cloudflare_dyndns.py *.mywebsite.com mywebsite.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment