summaryrefslogtreecommitdiffstats
path: root/update-dns
blob: 21d66db6c354482087053848cf4d75903c14fcef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python3

import sys
from errno import ENOENT
from argparse import ArgumentParser
from datetime import datetime
from getpass import getpass
from ipaddress import ip_address

import requests

LIVEDNS_API = "https://dns.api.gandi.net/api/v5"

def host_ips():
    def host_ip(n):
        r = requests.get(f"https://dyndns-v{n}.moegger.de/myip")
        r.raise_for_status()
        return r.json()["address"]
    return host_ip(4), host_ip(6)

def record_ips(domain, key):
    ipv4, = get_record(domain, "A", key)
    ipv6, = get_record(domain, "AAAA", key)
    return ipv4, ipv6

def host_ip_changed(ip):
    previous_ip = None
    filename = "/var/log/ip-v{}.log".format(ip_address(ip).version)
    try:
        with open(filename, "r") as fh:
            try:
                _, previous_ip = fh.readlines()[-1].split()
            except IndexError:
                pass
    except OSError as e:
        if e.errno == ENOENT:
            with open(filename, "x") as fh:
                pass
        else:
            raise
    if ip != previous_ip:
        with open(filename, "a") as fh:
            fh.write("{:26s}\t{}\n".format(datetime.today().isoformat(), ip))
        return True
    return False

def split_domain(domain):
    domain = [d for d in domain.split(".") if d]
    name = ".".join(domain[:-2]) if len(domain) > 2 else "@"
    domain = ".".join(domain[-2:])
    return name, domain

def get_record(domain, record, key):
    name, domain = split_domain(domain)
    r = requests.get(f"{LIVEDNS_API}/domains/{domain}/records/{name}/{record}",
                     headers={"X-Api-Key": key})
    response = r.json()
    if r.status_code == 404:
        return [None]
    r.raise_for_status()
    return response["rrset_values"]

def update_record(domain, record, val, key):
    name, domain = split_domain(domain)
    r = requests.put(f"{LIVEDNS_API}/domains/{domain}/records/{name}/{record}",
                     json={"rrset_ttl": 3600, "rrset_values": [val]},
                     headers={"X-Api-Key": key})
    r.raise_for_status()

def update_address_records(domain, key, force=False):
    host_ipv4, host_ipv6 = host_ips()
    record_ipv4, record_ipv6 = record_ips(domain, key)
    print((host_ipv4, host_ipv6))
    print((record_ipv4, record_ipv6))
    if force or host_ipv4 != record_ipv4 or host_ip_changed(host_ipv4):
        update_record(domain, "A", host_ipv4, key)
    if force or host_ipv6 != record_ipv6 or host_ip_changed(host_ipv6):
        update_record(domain, "AAAA", host_ipv6, key)
    record_ipv4, record_ipv6 = record_ips(domain, key)
    print((record_ipv4, record_ipv6))

def main(argv):
    parser = ArgumentParser()
    parser.add_argument("domain", nargs="+")
    parser.add_argument("--force", "-f", action="store_true")
    parser.add_argument("--key", "-k")

    args = parser.parse_args(argv)
    key = getpass("API Key: ") if args.key is None else args.key
    for domain in args.domain:
        update_address_records(domain, key, force=args.force)

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))