diff --git a/.gitignore b/.gitignore index 6d26e0c..5c5a429 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -cloudflare_token.ini -.vscode/settings.json +cloudflare ddns/ddns_config.ini +.vscode .vault_pass .ansible_facts.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index bf8eff2..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python Debugger: Current File with Arguments", - "type": "debugpy", - "request": "launch", - "program": "${file}", - "console": "integratedTerminal", - "args": [ - "wireguard.arnhem", - "--credential-file", "./cloudflare_token.ini" - ] - } - ] -} \ No newline at end of file diff --git a/cloudflare ddns/cloudflare_ddns.py b/cloudflare ddns/cloudflare_ddns.py index fca091d..493f08e 100644 --- a/cloudflare ddns/cloudflare_ddns.py +++ b/cloudflare ddns/cloudflare_ddns.py @@ -24,7 +24,11 @@ def get_public_IP(): def resolve_name(domain): logging.info(f'Resolving {domain}...') - result = dns.resolver.resolve(domain, 'A') + 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}.') @@ -32,26 +36,26 @@ def resolve_name(domain): 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}', + dns_change_response = requests.put(f'https://api.cloudflare.com/client/v4/zones/{zoneId}/dns_records/{recordId}', headers=cloudflare_request_headers, json={ 'content': publicIP, @@ -64,33 +68,43 @@ def change_record(subdomain, zoneId, recordId): 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', '--credential-file', dest='token') +parser.add_argument('-c', '--config-file', dest='config') args = parser.parse_args() subdomain = args.subdomain -cloudflare_token_path = args.token +config_file_path = args.config fixedTopLevelDomain = 'kleinendorst.info' fullDomainName = f'{subdomain}.{fixedTopLevelDomain}' -publicIP = get_public_IP() - -if resolve_name(fullDomainName) == publicIP: - logging.info(f'Currently resolved name already matches the public ip ({publicIP}), exiting...') - exit(0) - config = configparser.ConfigParser() -config.read(cloudflare_token_path) +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}'} +log_path = config.get('log_changes', 'log_path', fallback=None) +if log_path is not None: + log_path = config['log_changes']['log_path'] + logging.info(f'Logging DNS name changes to {log_path} on IP updates.') + +resolvedIP = resolve_name(fullDomainName) +publicIP = get_public_IP() +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) + +with open(log_path, 'a+') as log_file: + msg = f'Address for FQDN {fullDomainName} altered from: {resolvedIP} - {publicIP}.' + logging.info(f'Writing: "{msg}" to log file at {log_path}...') + log_file.write(msg + '\n')