mirror of
https://github.com/KevinMidboe/cloudflare-ddns.git
synced 2025-10-29 17:40:17 +00:00
WIP for checking public ip against known CF A record value
This commit is contained in:
146
bulk_dns_update.py
Normal file
146
bulk_dns_update.py
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/python3
|
||||
'''
|
||||
Cloudflare bulk DNS A record updater.
|
||||
|
||||
Designed to easily update all A records in cloudflare
|
||||
from one IP to another. Usually after a new IP is
|
||||
leased by ISP.
|
||||
|
||||
BEFORE RUNNING replace API_KEY with a key that holds
|
||||
permission: DNS:Edit for one or more zones.
|
||||
'''
|
||||
|
||||
import re
|
||||
import requests
|
||||
|
||||
API_KEY = ''
|
||||
|
||||
|
||||
def setAPIKey(apiKey):
|
||||
global API_KEY
|
||||
API_KEY = apiKey
|
||||
|
||||
|
||||
def cloudflareRequest(url):
|
||||
headers = {
|
||||
'Authorization': 'Bearer {}'.format(API_KEY),
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
r = requests.get(url, headers=headers)
|
||||
return r.json()
|
||||
|
||||
|
||||
def cloudflareUpdateRequest(url, data):
|
||||
headers = {
|
||||
'Authorization': 'Bearer {}'.format(API_KEY),
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
r = requests.patch(url, headers=headers, json=data)
|
||||
return r.json()
|
||||
|
||||
|
||||
def getZoneInfo(zone):
|
||||
return {
|
||||
'name': zone['name'],
|
||||
'id': zone['id']
|
||||
}
|
||||
|
||||
|
||||
def getRecordInfo(record):
|
||||
return {
|
||||
'content': record['content'],
|
||||
'name': record['name'],
|
||||
'id': record['id'],
|
||||
'ttl': record['ttl'],
|
||||
'proxied': record['proxied']
|
||||
}
|
||||
|
||||
|
||||
def getZones():
|
||||
url = 'https://api.cloudflare.com/client/v4/zones'
|
||||
data = cloudflareRequest(url)
|
||||
|
||||
if data['success'] is False:
|
||||
print('Request to cloudflare was unsuccessful, error:')
|
||||
print(data['errors'])
|
||||
raise Exception('Unexpected Cloudflare error! Check logs.')
|
||||
|
||||
if data['result'] is None or len(data['result']) < 1:
|
||||
# TODO
|
||||
print('no zones!')
|
||||
|
||||
zones = list(map(lambda zone: getZoneInfo(zone), data['result']))
|
||||
return zones
|
||||
|
||||
|
||||
def getRecordsForZone(zoneId):
|
||||
url = 'https://api.cloudflare.com/client/v4/zones/{}/dns_records?type=A'.format(zoneId)
|
||||
data = cloudflareRequest(url)
|
||||
|
||||
if data['success'] is False:
|
||||
print('Request from cloudflare was unsuccessful, error:')
|
||||
print(data['errors'])
|
||||
raise Exception('Unexpected Cloudflare error! Check logs.')
|
||||
|
||||
if data['result'] is None or len(data['result']) < 1:
|
||||
# TODO
|
||||
print('no records!')
|
||||
|
||||
records = list(map(lambda record: getRecordInfo(record), data['result']))
|
||||
return records
|
||||
|
||||
|
||||
def getDDNSAddresszoneId(ddnsZone):
|
||||
records = getRecordsForZone(ddnsZone)
|
||||
|
||||
for record in records:
|
||||
if not re.match(r"^addr\.", record['name']):
|
||||
continue
|
||||
return record
|
||||
|
||||
raise Exception('No ddns record found for zone: {}'.format(DDNS_ZONE))
|
||||
|
||||
|
||||
def updateRecord(zoneId, recordId, name, newIP, ttl, proxied):
|
||||
url = 'https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}'.format(zoneId, recordId)
|
||||
data = {
|
||||
'type': 'A',
|
||||
'name': name,
|
||||
'content': newIP,
|
||||
'ttl': ttl,
|
||||
'proxied': proxied
|
||||
}
|
||||
|
||||
response = cloudflareUpdateRequest(url, data)
|
||||
print('\tRecord updated: {}'.format('✅' if response['success'] is True else '❌'))
|
||||
|
||||
|
||||
def getMatchingRecordsForZone(zoneId, oldIP):
|
||||
records = getRecordsForZone(zoneId)
|
||||
return list(filter(lambda record: record['content'] == oldIP, records))
|
||||
|
||||
|
||||
def updateZone(zone, oldIP, newIP):
|
||||
print('Updating records for {}'.format(zone['name']))
|
||||
records = getMatchingRecordsForZone(zone['id'], oldIP)
|
||||
if len(records) < 1:
|
||||
print('No matching records for {}\n'.format(zone['name']))
|
||||
return
|
||||
|
||||
for record in records:
|
||||
print('\tRecord {}: {} -> {}'.format(record['name'], record['content'], newIP))
|
||||
updateRecord(zone['id'], record['id'], record['name'], newIP, record['ttl'], record['proxied'])
|
||||
|
||||
def updateAllZones(oldIP, newIP):
|
||||
zones = getZones()
|
||||
|
||||
for zone in zones:
|
||||
updateZone(zone, oldIP, newIP)
|
||||
|
||||
if __name__ == '__main__':
|
||||
oldIP = input('Old IP address: ')
|
||||
newIP = input('New IP address: ')
|
||||
|
||||
updateAllZones(oldIP, newIP)
|
||||
48
main.py
Normal file
48
main.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import os
|
||||
import requests
|
||||
from bulk_dns_update import updateAllZones, setAPIKey, getDDNSAddresszoneId
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
currentIP = None
|
||||
DDNS_ZONE = os.getenv('DDNS_ZONE')
|
||||
|
||||
|
||||
def publicAddress():
|
||||
global currentIP
|
||||
print('Getting public IP from ifconfg.me...')
|
||||
|
||||
r = requests.get('https://ifconfig.me')
|
||||
currentIP = r.text
|
||||
print('Public IP: {}'.format(currentIP))
|
||||
|
||||
|
||||
def cloudflareDDNS():
|
||||
print('Checking IP recorded in Cloudflare...')
|
||||
ddnsRecord = getDDNSAddresszoneId(DDNS_ZONE)
|
||||
recordedIP = ddnsRecord['content']
|
||||
print('Found ddns recorded IP: {}'.format(recordedIP))
|
||||
|
||||
if currentIP != recordedIP:
|
||||
print('Public IP has changed, updating all A records.')
|
||||
updateAllZones(recordedIP, currentIP)
|
||||
else:
|
||||
print('is same, exiting')
|
||||
|
||||
|
||||
def main():
|
||||
apiKey = os.getenv('API_KEY')
|
||||
if apiKey is None:
|
||||
raise Exception('In .env file or environment set Cloudflare variable: API_KEY')
|
||||
if DDNS_ZONE is None:
|
||||
raise Exception('In .env file or environment; set Cloudflare zone where addr. points to current IP.')
|
||||
|
||||
setAPIKey(apiKey)
|
||||
|
||||
publicAddress()
|
||||
cloudflareDDNS()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user