From 4d5ccee0f808462f99947b150c6b20d4693d3c39 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Fri, 1 Nov 2019 16:59:29 +0700 Subject: [PATCH 01/13] temp --- cf-dns-update.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ config.ini | 10 +++++ 2 files changed, 108 insertions(+) create mode 100644 cf-dns-update.py create mode 100644 config.ini diff --git a/cf-dns-update.py b/cf-dns-update.py new file mode 100644 index 0000000..8c226eb --- /dev/null +++ b/cf-dns-update.py @@ -0,0 +1,98 @@ +import configparser +import json +import urllib.error +import urllib.parse +import urllib.request + + +def make_request(method="GET", url="", request_body=None): + headers = { + 'Authorization': "Bearer {}".format(CF_API_TOKEN), + 'Content-Type': 'application/json' + } + + data = urllib.parse.urlencode(request_body) + data = data.encode('ascii') + + try: + req = urllib.request.Request(url, headers=headers, data=data, method=method) + with urllib.request.urlopen(req) as response: + resp_content = response.read() + return resp_content + except urllib.error.HTTPError as e: + print(e.code) + print(e.read()) + except urllib.error.URLError as e: + print(e.reason) + + return False + + +def get_local_ip(): + """ + Get current public IP of server + :return: string + """ + pass + + +def get_record_id(zone_id, record_name): + """ + Get CloudFlare record id from domain/sub-domain name + :return: + """ + endpoint = "https://api.cloudflare.com/client/v4/zones/{}/dns_records?name={}&type=A".format( + zone_id, + record_name + ) + response = make_request("GET", endpoint) + data = json.loads(response) + if not data['success']: + return False + + for record in data['result']: + if record['name'] == record_name: + return record['id'] + + return False + + +def update_host(zone_id, record_name): + record_id = get_record_id(zone_id, record_name) + + if not record_id: + return False + + endpoint = "https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}".format( + zone_id, + record_id + ) + + body = '{"type":"A","name":"$2","content":"$ip"}' + + make_request("PUT", endpoint, body) + + +config_file = 'config.ini' + +config = configparser.ConfigParser() + +config.read(config_file) + +if "common" not in config: + raise Exception("Common config not found.") + +if "CF_API_TOKEN" not in config['common'] or not config['common']['CF_API_TOKEN']: + raise Exception("Missing CloudFlare API Token on config file") + +CF_API_TOKEN = config['common']['CF_API_TOKEN'] + +config_sections = config.sections() +config_sections.remove("common") + +if not config_sections: + raise Exception("Empty site to update DNS") + + +for domain in config_sections: + update_host(domain['zone_id'], domain['record']) diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..84a8c17 --- /dev/null +++ b/config.ini @@ -0,0 +1,10 @@ +[common] +CF_API_TOKEN = "xxx" + +[dungnt.net] +zone_id = "xxx" +record = "test.dungnt.net" + +[nhymxu.info] +zone_id = "xxx" +record = "yyy.dungnt.net" \ No newline at end of file From 49c4e1e47d91335538c2c281e9fe30d6209aa45a Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 20:43:37 +0700 Subject: [PATCH 02/13] remove config.ini --- config.ini => config.ini.sample | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config.ini => config.ini.sample (100%) diff --git a/config.ini b/config.ini.sample similarity index 100% rename from config.ini rename to config.ini.sample From ebc541fcc9ea07a8f060efff39ee68bc607352a5 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 20:44:20 +0700 Subject: [PATCH 03/13] ignore config file --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 894a44c..799acba 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,6 @@ venv.bak/ # mypy .mypy_cache/ + +# Self-project setting +config.ini From b0ca1bf59bf35487b45594022ea4b0da06640027 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 21:21:35 +0700 Subject: [PATCH 04/13] update sample config --- config.ini.sample | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config.ini.sample b/config.ini.sample index 84a8c17..e04b5c2 100644 --- a/config.ini.sample +++ b/config.ini.sample @@ -1,10 +1,10 @@ [common] -CF_API_TOKEN = "xxx" +CF_API_TOKEN = xxx [dungnt.net] -zone_id = "xxx" -record = "test.dungnt.net" +zone_id = xxx +record = test.dungnt.net [nhymxu.info] -zone_id = "xxx" -record = "yyy.dungnt.net" \ No newline at end of file +zone_id = xxx +record = yyy.nhymxu.info From 96bc0465a4c5a82b8e80dcebaea5ff7c0f4f0d6c Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 21:23:00 +0700 Subject: [PATCH 05/13] finish dev --- cf-dns-update.py | 59 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/cf-dns-update.py b/cf-dns-update.py index 8c226eb..f3f4240 100644 --- a/cf-dns-update.py +++ b/cf-dns-update.py @@ -4,6 +4,8 @@ import urllib.parse import urllib.request +old_ip = None + def make_request(method="GET", url="", request_body=None): headers = { @@ -11,8 +13,10 @@ def make_request(method="GET", url="", request_body=None): 'Content-Type': 'application/json' } - data = urllib.parse.urlencode(request_body) - data = data.encode('ascii') + data = None + if request_body: + data = urllib.parse.urlencode(request_body) + data = data.encode('ascii') try: req = urllib.request.Request(url, headers=headers, data=data, method=method) @@ -33,7 +37,28 @@ def get_local_ip(): Get current public IP of server :return: string """ - pass + endpoint = "https://checkip.amazonaws.com/" + + return make_request(url=endpoint).strip() + + +def get_old_ip(): + """ + + :return: + """ + global old_ip + + if not old_ip: + with open('old_ip.txt', 'r') as fp: + old_ip = fp.read().strip() + + return old_ip + + +def save_old_ip(ip): + with open('old_ip.txt', 'w+') as fp: + fp.write(ip) def get_record_id(zone_id, record_name): @@ -63,22 +88,42 @@ def update_host(zone_id, record_name): if not record_id: return False + public_ip = get_local_ip() + if public_ip == get_old_ip(): + return False + + save_old_ip(public_ip) + endpoint = "https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}".format( zone_id, record_id ) - body = '{"type":"A","name":"$2","content":"$ip"}' + payload = { + "type": "A", + "name": record_name, + "content": public_ip + } + + response = make_request( + method="PUT", + url=endpoint, + request_body=json.dumps(payload) + ) + data = json.loads(response) + + if not data['success']: + return False - make_request("PUT", endpoint, body) + return True config_file = 'config.ini' config = configparser.ConfigParser() - config.read(config_file) + if "common" not in config: raise Exception("Common config not found.") @@ -95,4 +140,4 @@ def update_host(zone_id, record_name): for domain in config_sections: - update_host(domain['zone_id'], domain['record']) + update_host(config[domain]['zone_id'], config[domain]['record']) From a7c01918f649b49d1ece4261cc1bf02ded0bcf55 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 21:28:57 +0700 Subject: [PATCH 06/13] add run file for cron --- .gitignore | 1 + run.sh | 4 ++++ 2 files changed, 5 insertions(+) create mode 100755 run.sh diff --git a/.gitignore b/.gitignore index 799acba..dff0ef9 100644 --- a/.gitignore +++ b/.gitignore @@ -105,3 +105,4 @@ venv.bak/ # Self-project setting config.ini +old_ip.txt diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..4607b57 --- /dev/null +++ b/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +cd "$(dirname "$0")" +python cf-dns-update.py From 1381ac8997b3d94a45ca72ddd8461da4fede56a0 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 21:31:31 +0700 Subject: [PATCH 07/13] using python3 if exist --- run.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/run.sh b/run.sh index 4607b57..33aca92 100755 --- a/run.sh +++ b/run.sh @@ -1,4 +1,9 @@ #!/bin/bash cd "$(dirname "$0")" -python cf-dns-update.py + +if command -v python3 &>/dev/null; then + python3 cf-dns-update.py +else + python cf-dns-update.py +fi From 48e9446961afc53f309996073dbb28a58863ba9b Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 21:48:08 +0700 Subject: [PATCH 08/13] check path exist for local file --- cf-dns-update.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cf-dns-update.py b/cf-dns-update.py index f3f4240..c9a930b 100644 --- a/cf-dns-update.py +++ b/cf-dns-update.py @@ -3,6 +3,7 @@ import urllib.error import urllib.parse import urllib.request +from os import path old_ip = None @@ -39,7 +40,7 @@ def get_local_ip(): """ endpoint = "https://checkip.amazonaws.com/" - return make_request(url=endpoint).strip() + return make_request(url=endpoint).strip().decode('utf-8') def get_old_ip(): @@ -49,7 +50,7 @@ def get_old_ip(): """ global old_ip - if not old_ip: + if not old_ip and path.exists("old_ip.txt"): with open('old_ip.txt', 'r') as fp: old_ip = fp.read().strip() @@ -120,10 +121,12 @@ def update_host(zone_id, record_name): config_file = 'config.ini' +if not path.exists(config_file): + raise RuntimeError("config file not found") + config = configparser.ConfigParser() config.read(config_file) - if "common" not in config: raise Exception("Common config not found.") @@ -138,6 +141,5 @@ def update_host(zone_id, record_name): if not config_sections: raise Exception("Empty site to update DNS") - for domain in config_sections: update_host(config[domain]['zone_id'], config[domain]['record']) From c3a04afd29a50968dc7d0493c63a6d5869c56373 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 21:48:38 +0700 Subject: [PATCH 09/13] remove urlencode payload --- cf-dns-update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cf-dns-update.py b/cf-dns-update.py index c9a930b..027bdc3 100644 --- a/cf-dns-update.py +++ b/cf-dns-update.py @@ -16,7 +16,7 @@ def make_request(method="GET", url="", request_body=None): data = None if request_body: - data = urllib.parse.urlencode(request_body) + # data = urllib.parse.urlencode(request_body) data = data.encode('ascii') try: From 51ca8eebb54194727293d5dc2d60a60be855ce5a Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 21:59:39 +0700 Subject: [PATCH 10/13] fix typo --- cf-dns-update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cf-dns-update.py b/cf-dns-update.py index 027bdc3..fd15ffd 100644 --- a/cf-dns-update.py +++ b/cf-dns-update.py @@ -17,7 +17,7 @@ def make_request(method="GET", url="", request_body=None): data = None if request_body: # data = urllib.parse.urlencode(request_body) - data = data.encode('ascii') + data = request_body.encode('ascii') try: req = urllib.request.Request(url, headers=headers, data=data, method=method) From 9f9aadec6bdda61272a1f22dab2c810751688c84 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 22:07:59 +0700 Subject: [PATCH 11/13] add some log info --- cf-dns-update.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cf-dns-update.py b/cf-dns-update.py index fd15ffd..bb1f22b 100644 --- a/cf-dns-update.py +++ b/cf-dns-update.py @@ -90,11 +90,11 @@ def update_host(zone_id, record_name): return False public_ip = get_local_ip() + print("Public IP: {}".format(public_ip)) if public_ip == get_old_ip(): + print("Skip update {}".format(record_name)) return False - save_old_ip(public_ip) - endpoint = "https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}".format( zone_id, record_id @@ -114,8 +114,13 @@ def update_host(zone_id, record_name): data = json.loads(response) if not data['success']: + print("Failed to update {}:{}".format(record_name, public_ip)) return False + print("Success update {}:{}".format(record_name, public_ip)) + + save_old_ip(public_ip) + return True From 05b3dfa97cc2d7763fa34d32eb8445d18da9e9f6 Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 22:09:56 +0700 Subject: [PATCH 12/13] get public ip one time per run --- cf-dns-update.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cf-dns-update.py b/cf-dns-update.py index bb1f22b..da6251a 100644 --- a/cf-dns-update.py +++ b/cf-dns-update.py @@ -6,6 +6,7 @@ from os import path old_ip = None +public_ip = None def make_request(method="GET", url="", request_body=None): @@ -38,9 +39,13 @@ def get_local_ip(): Get current public IP of server :return: string """ - endpoint = "https://checkip.amazonaws.com/" + global public_ip - return make_request(url=endpoint).strip().decode('utf-8') + if not public_ip: + endpoint = "https://checkip.amazonaws.com/" + public_ip = make_request(url=endpoint).strip().decode('utf-8') + + return public_ip def get_old_ip(): From 5c75c637d2c5b0302146c1d514a0c082a2b31a3a Mon Sep 17 00:00:00 2001 From: Dung Nguyen Date: Mon, 11 Nov 2019 22:17:24 +0700 Subject: [PATCH 13/13] move ip block to main script --- cf-dns-update.py | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/cf-dns-update.py b/cf-dns-update.py index da6251a..e8bdae0 100644 --- a/cf-dns-update.py +++ b/cf-dns-update.py @@ -5,9 +5,6 @@ import urllib.request from os import path -old_ip = None -public_ip = None - def make_request(method="GET", url="", request_body=None): headers = { @@ -39,13 +36,9 @@ def get_local_ip(): Get current public IP of server :return: string """ - global public_ip - - if not public_ip: - endpoint = "https://checkip.amazonaws.com/" - public_ip = make_request(url=endpoint).strip().decode('utf-8') + endpoint = "https://checkip.amazonaws.com/" - return public_ip + return make_request(url=endpoint).strip().decode('utf-8') def get_old_ip(): @@ -53,9 +46,9 @@ def get_old_ip(): :return: """ - global old_ip + old_ip = None - if not old_ip and path.exists("old_ip.txt"): + if path.exists("old_ip.txt"): with open('old_ip.txt', 'r') as fp: old_ip = fp.read().strip() @@ -94,12 +87,6 @@ def update_host(zone_id, record_name): if not record_id: return False - public_ip = get_local_ip() - print("Public IP: {}".format(public_ip)) - if public_ip == get_old_ip(): - print("Skip update {}".format(record_name)) - return False - endpoint = "https://api.cloudflare.com/client/v4/zones/{}/dns_records/{}".format( zone_id, record_id @@ -124,8 +111,6 @@ def update_host(zone_id, record_name): print("Success update {}:{}".format(record_name, public_ip)) - save_old_ip(public_ip) - return True @@ -151,5 +136,15 @@ def update_host(zone_id, record_name): if not config_sections: raise Exception("Empty site to update DNS") +public_ip = get_local_ip() +print("Public IP: {}".format(public_ip)) +if public_ip == get_old_ip(): + print("Skip update") + exit() + for domain in config_sections: + print("--- Updating {} ---".format(domain)) update_host(config[domain]['zone_id'], config[domain]['record']) + +print("Save old IP") +save_old_ip(public_ip)