From d88904e105458ef8911fa9bb19431fdb2e5b3a44 Mon Sep 17 00:00:00 2001 From: Thomas Kleinendorst Date: Wed, 10 Apr 2024 19:14:52 +0200 Subject: [PATCH] Split Python methods in own files --- .gitignore | 1 + cloudflare ddns/cloudflare_api.py | 43 ++++++++++++++++++ cloudflare ddns/cloudflare_ddns.py | 72 +++--------------------------- cloudflare ddns/ip_helpers.py | 27 +++++++++++ 4 files changed, 77 insertions(+), 66 deletions(-) create mode 100644 cloudflare ddns/cloudflare_api.py create mode 100644 cloudflare ddns/ip_helpers.py diff --git a/.gitignore b/.gitignore index 5c5a429..644a107 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ cloudflare ddns/ddns_config.ini .vscode .vault_pass .ansible_facts.json +__pycache__ diff --git a/cloudflare ddns/cloudflare_api.py b/cloudflare ddns/cloudflare_api.py new file mode 100644 index 0000000..a4d6f94 --- /dev/null +++ b/cloudflare ddns/cloudflare_api.py @@ -0,0 +1,43 @@ +import requests +import logging + +class CloudFlare: + def __init__(self, api_token): + self.headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {api_token}'} + + def get_zone_id(self, domain): + response = requests.get(f'https://api.cloudflare.com/client/v4/zones?name={domain}', headers=self.headers) + + if response.status_code != 200: + raise Exception('Something went wrong requesting the zone of the domain on Cloudflare...') + + zone_id = response.json()['result'][0]['id'] + return zone_id + + def get_record_id(self, zoneId, record): + logging.debug('Getting record id...') + response = requests.get(f'https://api.cloudflare.com/client/v4/zones/{zoneId}/dns_records?name={record}', headers=self.headers) + + if response.status_code != 200: + raise Exception('Something went wrong requesting the record id of the domain name on Cloudflare...') + + return response.json()['result'][0]['id'] + + + def change_record(self, subdomain, zoneId, recordId, targetIp): + logging.info(f'Changing record for {subdomain} to point to {targetIp}...') + dns_change_response = requests.put(f'https://api.cloudflare.com/client/v4/zones/{zoneId}ffff/dns_records/{recordId}', + headers=self.headers, + json={ + 'content': targetIp, + 'name': subdomain, + 'proxied': False, + 'type': 'A', + 'comment': 'Is set to change with my DDNS script (on the Raspberry Pi).', + 'ttl': 1 # Meaning "Automatic", see: https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-update-dns-record + }) + + if dns_change_response.status_code != 200: + raise Exception('Something went wrong updating the dns record...') + + logging.info('Succesfully updated the record ✅!') diff --git a/cloudflare ddns/cloudflare_ddns.py b/cloudflare ddns/cloudflare_ddns.py index 493f08e..ac33b37 100644 --- a/cloudflare ddns/cloudflare_ddns.py +++ b/cloudflare ddns/cloudflare_ddns.py @@ -1,76 +1,16 @@ #!/usr/bin/python3 # Fetches the public IP and updates the record on Cloudflare which is provided as an argument # to match this public record. -import requests import logging import sys import configparser import argparse -import dns.resolver +from cloudflare_api import CloudFlare +from ip_helpers import get_public_IP, resolve_name logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(levelname)s - %(message)s') -def get_public_IP(): - logging.info('Retrieving the public IP for this machine...') - response = requests.get('https://api.ipify.org?format=json') - - if response.status_code != 200: - raise Exception('Something went wrong requesting the public ip, exiting...') - - public_ip = response.json()['ip'] - logging.info(f'The public IP address for this machine is: {public_ip}.') - return public_ip - -def resolve_name(domain): - logging.info(f'Resolving {domain}...') - try: - result = dns.resolver.resolve(domain, 'A') - except dns.resolver.NXDOMAIN: - logging.error(f'No DNS record exists for {domain}, configure it first before using this ddns script. Exiting...') - exit(1) - - resolved_address = result[0].address - logging.info(f'Resolved {domain} to: {resolved_address}.') - return resolved_address - -def get_zone_id(domain): - response = requests.get(f'https://api.cloudflare.com/client/v4/zones?name={domain}', headers=cloudflare_request_headers) - - if response.status_code != 200: - raise Exception('Something went wrong requesting the zone of the domain on Cloudflare...') - - zone_id = response.json()['result'][0]['id'] - return zone_id - -def get_record_id(zoneId, record): - logging.debug('Getting record id...') - response = requests.get(f'https://api.cloudflare.com/client/v4/zones/{zoneId}/dns_records?name={record}', headers=cloudflare_request_headers) - - if response.status_code != 200: - raise Exception('Something went wrong requesting the record id of the domain name on Cloudflare...') - - return response.json()['result'][0]['id'] - - -def change_record(subdomain, zoneId, recordId): - logging.info(f'Changing record for {subdomain} to point to {publicIP}...') - dns_change_response = requests.put(f'https://api.cloudflare.com/client/v4/zones/{zoneId}/dns_records/{recordId}', - headers=cloudflare_request_headers, - json={ - 'content': publicIP, - 'name': subdomain, - 'proxied': False, - 'type': 'A', - 'comment': 'Is set to change with my DDNS script (on the Raspberry Pi).', - 'ttl': 1 # Meaning "Automatic", see: https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-update-dns-record - }) - - if dns_change_response.status_code != 200: - raise Exception('Something went wrong updating the dns record...') - - logging.info('Succesfully updated the record ✅!') - parser = argparse.ArgumentParser() parser.add_argument('subdomain') parser.add_argument('-c', '--config-file', dest='config') @@ -87,7 +27,7 @@ config = configparser.ConfigParser() config.read(config_file_path) cloudflare_api_credentials = config['credentials']['dns_cloudflare_token'] -cloudflare_request_headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {cloudflare_api_credentials}'} +cloudflare = CloudFlare(cloudflare_api_credentials) log_path = config.get('log_changes', 'log_path', fallback=None) if log_path is not None: @@ -100,9 +40,9 @@ if resolvedIP == publicIP: logging.info(f'Currently resolved name already matches the public ip ({publicIP}), exiting...') exit(0) -zoneId = get_zone_id(fixedTopLevelDomain) -recordId = get_record_id(zoneId, fullDomainName) -change_record(subdomain, zoneId, recordId) +zoneId = cloudflare.get_zone_id(fixedTopLevelDomain) +recordId = cloudflare.get_record_id(zoneId, fullDomainName) +cloudflare.change_record(subdomain, zoneId, recordId, publicIP) with open(log_path, 'a+') as log_file: msg = f'Address for FQDN {fullDomainName} altered from: {resolvedIP} - {publicIP}.' diff --git a/cloudflare ddns/ip_helpers.py b/cloudflare ddns/ip_helpers.py new file mode 100644 index 0000000..e48d25d --- /dev/null +++ b/cloudflare ddns/ip_helpers.py @@ -0,0 +1,27 @@ +import logging +import requests +import dns.resolver + + +def get_public_IP(): + logging.info('Retrieving the public IP for this machine...') + response = requests.get('https://api.ipify.org?format=json') + + if response.status_code != 200: + raise Exception('Something went wrong requesting the public ip, exiting...') + + public_ip = response.json()['ip'] + logging.info(f'The public IP address for this machine is: {public_ip}.') + return public_ip + +def resolve_name(domain): + logging.info(f'Resolving {domain}...') + try: + result = dns.resolver.resolve(domain, 'A') + except dns.resolver.NXDOMAIN: + logging.error(f'No DNS record exists for {domain}, configure it first before using this ddns script. Exiting...') + exit(1) + + resolved_address = result[0].address + logging.info(f'Resolved {domain} to: {resolved_address}.') + return resolved_address