Created
January 14, 2019 04:16
-
-
Save solicomo/343d37348647bbefe3d498772b821c16 to your computer and use it in GitHub Desktop.
CloudFlare Dynamic DNS
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 python3 | |
#-*- coding: utf-8 -*- | |
import sys | |
import requests | |
import json | |
from datetime import datetime | |
EMAIL='Your Email' | |
APIKEY='Your API Key from CloudFlare' | |
ZONEID='ZONE ID which can be found at left of Overview page' | |
DOMAINS=['domain.org', '*.domain.org', 'www.domain.org'] | |
def log(msg): | |
print('[{}] {}'.format(datetime.now().isoformat(' '), msg)) | |
pass | |
def request(method, url, data = None): | |
headers = { | |
'X-Auth-Email': EMAIL, | |
'X-Auth-Key': APIKEY, | |
'Content-Type': 'application/json', | |
} | |
rsp = None | |
try: | |
if method == 'get': | |
rsp = requests.get(url, headers=headers) | |
elif method == 'post': | |
rsp = requests.post(url, headers=headers, data=data) | |
elif method == 'put': | |
rsp = requests.put(url, headers=headers, data=data) | |
else: | |
return None | |
rsp.raise_for_status() | |
except requests.exceptions.RequestException as e: | |
log('Request Failed: {}:\n{} {}\n{}'.format(e, method, data, rsp.text)) | |
return None | |
data = rsp.json() | |
if not data['success']: | |
log('List DNS Records Failed: {}'.format(json.dumps(data, indent=4))) | |
return None | |
return data | |
def getMyIP(): | |
try: | |
rsp = requests.get('https://ifconfig.me/all.json') | |
rsp.raise_for_status() | |
return 'A', rsp.json()['ip_addr'] | |
except requests.exceptions.RequestException as e: | |
log('Request Failed: {}'.format(e.message)) | |
return None, None | |
def getRecordIDs(): | |
rsp = request('get', 'https://api.cloudflare.com/client/v4/zones/{}/dns_records'.format(ZONEID)) | |
if rsp is None: | |
return False | |
rids = {} | |
for record in rsp['result']: | |
rids[record['name']] = { | |
'id': record['id'], | |
'ip': record['content'], | |
} | |
return rids | |
def create(domain, ipType, ip): | |
data = { | |
'name': domain, | |
'type': ipType, | |
'content': ip, | |
} | |
rsp = request('post', 'https://api.cloudflare.com/client/v4/zones/{}/dns_records'.format(ZONEID), json.dumps(data)) | |
if rsp is None: | |
return False | |
result = rsp['result'] | |
log('Created record {}: {} - {} - {}'.format(result['id'], result['type'], result['name'], result['content'])) | |
return True | |
def update(rid, domain, ipType, ip): | |
data = { | |
'name': domain, | |
'type': ipType, | |
'content': ip, | |
} | |
rsp = request('put', 'https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}'.format(ZONEID, rid), json.dumps(data)) | |
if rsp is None: | |
return False | |
result = rsp['result'] | |
log('Updated record {}: {} - {} - {}'.format(result['id'], result['type'], result['name'], result['content'])) | |
return True | |
def createOrUpdate(): | |
ipType, ip = getMyIP() | |
if ip is None: | |
return False | |
rids = getRecordIDs() | |
for domain in DOMAINS: | |
if domain in rids: | |
if ip == rids[domain]['ip']: | |
log('Omitted record {}: {} - {}'.format(rids[domain]['id'], domain, ip)) | |
else: | |
update(rids[domain]['id'], domain, ipType, ip) | |
else: | |
create(domain, ipType, ip) | |
return True | |
def main(argv): | |
createOrUpdate() | |
if __name__ == '__main__': | |
try: | |
main(sys.argv) | |
except KeyboardInterrupt: | |
log ("Crtl+C Pressed. Shutting down.") | |
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment