|
import argparse |
|
import json |
|
import os |
|
import base64 |
|
import logging |
|
from logging.handlers import RotatingFileHandler |
|
import requests |
|
|
|
parser = argparse.ArgumentParser( |
|
description="DDNS service for domain on name.com. Periodically check the current host IP, and update record by API of name.com" |
|
) |
|
parser.add_argument("domain", help="top domain, for example: example.com") |
|
parser.add_argument("fqdn", help="domain for DDNS, for example: xxx.example.com") |
|
parser.add_argument("--api_username", help="api username", required=True) |
|
parser.add_argument("--api_token", help="api token", required=True) |
|
parser.add_argument( |
|
"--proxy", help="proxy url,for example socks5://localhost:1086", required=False |
|
) |
|
parser.add_argument( |
|
"--log", |
|
default=os.path.join( |
|
os.path.dirname(os.path.realpath(__file__)), "ddns_name_com.log" |
|
), |
|
help="path for log file", |
|
required=False, |
|
) |
|
|
|
logger = logging.getLogger("DDNS") |
|
logger.setLevel(logging.INFO) |
|
formatter = logging.Formatter( |
|
"%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S" |
|
) |
|
|
|
ch = logging.StreamHandler() |
|
logger.addHandler(ch) |
|
ch.setFormatter(formatter) |
|
|
|
|
|
def get_host_id(domain, fqdn: str, api_username, api_password, proxies=None): |
|
cache_config = os.path.join( |
|
os.path.dirname(os.path.realpath(__file__)), ".ddns_config" |
|
) |
|
if os.path.exists(cache_config): |
|
with open(cache_config, encoding="utf-8") as f: |
|
items = json.loads(f.read()) |
|
host_id = items.get("host_id") |
|
if host_id: |
|
return host_id |
|
url = f"https://api.name.com/v4/domains/{domain}/records" |
|
|
|
headers = { |
|
"Authorization": "Basic %s" |
|
% base64.b64encode(str.encode(f"{api_username}:{api_password}")).decode() |
|
} |
|
|
|
if not fqdn.endswith("."): |
|
fqdn = fqdn + "." |
|
|
|
r = requests.get(url, headers=headers, proxies=proxies) |
|
|
|
if r.status_code == 200 and (records := r.json().get("records", None)) is not None: |
|
for record in records: |
|
if record["fqdn"] == fqdn: |
|
with open(cache_config, encoding="utf-8", mode="w+") as f: |
|
if (host_id := str(record["id"])) is not None: |
|
json.dump({"host_id": host_id}, f) |
|
return record["id"] |
|
|
|
|
|
def update_ip(fqdn, host_id, ip, api_username, api_password, proxies=None): |
|
url = f"https://api.name.com/v4/domains/{fqdn}/records/{host_id}" |
|
|
|
payload = json.dumps({"type": "A", "answer": ip, "ttl": 300}) |
|
headers = { |
|
"Authorization": "Basic %s" |
|
% base64.b64encode(str.encode(f"{api_username}:{api_password}")).decode() |
|
} |
|
|
|
r = requests.put(url, headers=headers, data=payload, proxies=proxies) |
|
|
|
result = r.text |
|
logger.info("Update Result:" + result.strip()) |
|
return result |
|
|
|
|
|
def ddns(domain, fqdn, api_username, api_password, proxy_url): |
|
proxies = None |
|
if proxy_url: |
|
proxies = { |
|
"http": proxy_url, |
|
"https": proxy_url, |
|
} |
|
|
|
host_id = get_host_id(domain, fqdn, api_username, api_password, proxies) |
|
|
|
last_ip = None |
|
file_cache_ip = os.path.join( |
|
os.path.dirname(os.path.realpath(__file__)), ".ddns_ip.txt" |
|
) |
|
if os.path.exists(file_cache_ip): |
|
with open(file_cache_ip, encoding="utf-8") as f: |
|
last_ip = f.read() |
|
|
|
current_ip = requests.get( |
|
"https://ipinfo.io/ip", headers={"User-Agent": "curl/7.71.1"} |
|
).text |
|
logger.info(f"Current IP: {current_ip}") |
|
|
|
if current_ip != last_ip: |
|
logger.warning( |
|
f"IP changed,current IP:{current_ip}, last IP:{last_ip},now update DNS record" |
|
) |
|
with open(file_cache_ip, encoding="utf-8", mode="w+") as f: |
|
f.write(current_ip) |
|
update_ip(fqdn, host_id, current_ip, api_username, api_password, proxies) |
|
|
|
|
|
if __name__ == "__main__": |
|
args = parser.parse_args() |
|
if not os.path.exists(args.log): |
|
mode = "w+" |
|
else: |
|
mode = "a" |
|
fh = RotatingFileHandler( |
|
args.log, |
|
mode=mode, |
|
maxBytes=5 * 1024 * 1024, |
|
backupCount=2, |
|
encoding="utf-8", |
|
delay=0, |
|
) |
|
|
|
logger.addHandler(fh) |
|
fh.setFormatter(formatter) |
|
|
|
ddns(args.domain, args.fqdn, args.api_username, args.api_token, args.proxy) |