From 5f683ca3070cf16431cf85789ff8b8667ab807a1 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 13 Apr 2026 09:08:09 +0100 Subject: [PATCH] Initial files push for DDNS Updater --- daily_report.py | 51 +++++++++++++++++++++++ ddns.py | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ test_report.py | 23 +++++++++++ 3 files changed, 181 insertions(+) create mode 100755 daily_report.py create mode 100755 ddns.py create mode 100755 test_report.py diff --git a/daily_report.py b/daily_report.py new file mode 100755 index 0000000..e36a87d --- /dev/null +++ b/daily_report.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +import smtplib +from email.mime.text import MIMEText +import re + +# Gmail SMTP settings +SMTP_SERVER = "smtp.gmail.com" +SMTP_PORT = 587 +EMAIL_ADDRESS = "ddns.updates@gmail.com" +EMAIL_PASSWORD = "tacssyofvkgqvbzo" +TO_EMAIL = "rafjaniak@outlook.com" + + +# Log file path +LOG_FILE = "/var/log/ddns.log" + +def send_email(subject, body): + msg = MIMEText(body) + msg["Subject"] = subject + msg["From"] = EMAIL_ADDRESS + msg["To"] = TO_EMAIL + + try: + with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server: + server.ehlo() + server.starttls() + server.login(EMAIL_ADDRESS, EMAIL_PASSWORD) + server.send_message(msg) + print("✅ Email sent successfully") + except Exception as e: + print(f"❌ Failed to send email: {e}") + +def get_last_log_entries(): + last_entries = {} + with open(LOG_FILE) as f: + for line in f: + # Match domain entries with status ✅ or ❌ + match = re.search(r"\] (✅|❌|🌍) (\S+)", line) + if match: + status, domain = match.groups() + last_entries[domain] = line.strip() + return last_entries + +if __name__ == "__main__": + entries = get_last_log_entries() + if entries: + body = "\n".join(entries.values()) + else: + body = "No log entries found." + + send_email("DDNS Daily Report", body) diff --git a/ddns.py b/ddns.py new file mode 100755 index 0000000..790a279 --- /dev/null +++ b/ddns.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +import requests +import sys +from datetime import datetime + +# ----------------------------- +# CONFIG - only edit this: +API_TOKEN = "HLNmBZ-4fyCSvR6BErdFtch4jQj3GACePD4yD0xs" +DOMAINS = [ + "snieznykoczkodan.com", # root domain + "proxy.snieznykoczkodan.com", # Nginx Proxy Manager .102 + "proxmox.snieznykoczkodan.com", # Proxmox GUI .5 + "nas.snieznykoczkodan.com", # Synology - rafnasbox .3 + "jellyfin.snieznykoczkodan.com", # Jellyfin .104 + "seer.snieznykoczkodan.com", # jellyseer .105 + "prowlarr.snieznykoczkodan.com", # porwlarr .105 9696 + "radarr.snieznykoczkodan.com", # radarr .105 7878 + "sonarr.snieznykoczkodan.com", # sonarr .105 8989 + "torrent.snieznykoczkodan.com", # qbitorrent .106 + "grafana.snieznykoczkodan.com", # grafana .108 + "git.snieznykoczkodan.com" # gittea .111 3000 +] +TTL = 120 # 2 minutes +PROXIED = False # True = Cloudflare proxy (orange cloud), False = DNS only +# ----------------------------- + +BASE_URL = "https://api.cloudflare.com/client/v4" +HEADERS = { + "Authorization": f"Bearer {API_TOKEN}", + "Content-Type": "application/json" +} + +def log(msg): + now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + print(f"[{now}] {msg}") + +def get_public_ip(): + try: + return requests.get("https://api.ipify.org", timeout=10).text.strip() + except Exception as e: + log(f"❌ Failed to get public IP: {e}") + sys.exit(1) + +def get_zone_id(domain): + try: + # extract the root domain (last two parts) + parts = domain.split('.') + root_domain = '.'.join(parts[-2:]) + r = requests.get(f"{BASE_URL}/zones?name={root_domain}", headers=HEADERS) + r.raise_for_status() + zones = r.json()["result"] + if not zones: + log(f"❌ No zone found for {root_domain}") + sys.exit(1) + return zones[0]["id"] + except Exception as e: + log(f"❌ Error fetching Zone ID for {domain}: {e}") + sys.exit(1) + +def get_record_id(zone_id, domain): + try: + r = requests.get(f"{BASE_URL}/zones/{zone_id}/dns_records?type=A&name={domain}", headers=HEADERS) + r.raise_for_status() + records = r.json()["result"] + if not records: + log(f"❌ No A record found for {domain}") + sys.exit(1) + return records[0]["id"], records[0]["content"] + except Exception as e: + log(f"❌ Error fetching DNS record for {domain}: {e}") + sys.exit(1) + +def update_dns_record(zone_id, record_id, domain, ip): + data = { + "type": "A", + "name": domain, + "content": ip, + "ttl": TTL, + "proxied": PROXIED + } + try: + r = requests.put(f"{BASE_URL}/zones/{zone_id}/dns_records/{record_id}", headers=HEADERS, json=data) + r.raise_for_status() + return r.json().get("success", False) + except Exception as e: + log(f"❌ Failed to update DNS record for {domain}: {e}") + return False + +def main(): + ip = get_public_ip() + log(f"🌍 Current public IP: {ip}") + + for domain in DOMAINS: + zone_id = get_zone_id(domain) + record_id, current_ip = get_record_id(zone_id, domain) + + if current_ip == ip: + log(f"✅ {domain} already up to date") + else: + log(f"🔄 Updating {domain} from {current_ip} → {ip}") + if update_dns_record(zone_id, record_id, domain, ip): + log(f"✅ {domain} updated successfully") + else: + log(f"❌ {domain} update failed") + +if __name__ == "__main__": + main() diff --git a/test_report.py b/test_report.py new file mode 100755 index 0000000..5219101 --- /dev/null +++ b/test_report.py @@ -0,0 +1,23 @@ +import smtplib +from email.mime.text import MIMEText + +SMTP_SERVER = "smtp.office365.com" +SMTP_PORT = 587 +EMAIL_ADDRESS = "ddnsupdater@outlook.com" +EMAIL_PASSWORD = "ltehpesmqnkjenah" +TO_EMAIL = "rafjaniak@outlook.com" + +msg = MIMEText("This is a test email from DDNS updater.") +msg["Subject"] = "Test Email" +msg["From"] = EMAIL_ADDRESS +msg["To"] = TO_EMAIL + +try: + with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server: + server.ehlo() + server.starttls() + server.login(EMAIL_ADDRESS, EMAIL_PASSWORD) + server.send_message(msg) + print("✅ Email sent successfully") +except Exception as e: + print(f"❌ Failed to send email: {e}")