diff --git a/gandyndns.py b/gandyndns.py index 07435f6..57358d3 100644 --- a/gandyndns.py +++ b/gandyndns.py @@ -2,8 +2,8 @@ # -*- coding: utf-8 -*- # @author: polarolouis -import requests import argparse +import requests parser = argparse.ArgumentParser( description="A script which connect to Gandi.net API to change IP associated to a DNS record") @@ -14,10 +14,12 @@ parser.add_argument("domain", metavar="DOMAIN", parser.add_argument("subdomain", metavar="SUBDOMAIN", help="The subdomain to point to. Examples: 'sub' or '@'") parser.add_argument("apikey", metavar="APIKEY", help="Your Gandi.net API key") -parser.add_argument("--destination", metavar="DESTINATION", default="public_ip", +parser.add_argument("--destination", metavar="DESTINATION", default="public_ip", help="The destination to point the subdomain to. Might be an IP, for instance 10.0.0.1, might be a subdomain, for instance @. Default: public_ip, which retrieves the machine public ip") parser.add_argument("--type", metavar="TYPE", default='A', - help="The type of DNS record to create. Default: A", choices=['A','CNAME']) + help="The type of DNS record to create. Default: A", choices=['A', 'CNAME']) +parser.add_argument("--ttl", metavar="TTL", default=10800, + help="The Time To Live in seconds. This is the number of seconds the record must be stored in cache. Default value is 10800s (3hrs).", type=int) args = parser.parse_args() print(args) @@ -25,20 +27,21 @@ verbose = args.verbose domain = args.domain apikey = args.apikey subdomain = args.subdomain -type = args.type +record_type = args.type +ttl = args.ttl destination = args.destination -domain_record_string = f"DNS {type} record for {subdomain}.{domain}" +domain_record_string = f"DNS {record_type} record for {subdomain}.{domain}" domain_record_string_lenght = len(domain_record_string) -apiUrl = f"https://api.gandi.net/v5/livedns/domains/{domain}/records/{subdomain}/{type}" +api_url = f"https://api.gandi.net/v5/livedns/domains/{domain}/records/{subdomain}/{record_type}" headers = {"Authorization": f"Apikey {apikey}", 'User-Agent': 'Mozilla/5.0', "Content-Type": "application/json"} -def retrieve_public_IP(): +def retrieve_public_ip(): """Retrieves the public IP by connecting to ipinfo.io API Returns: @@ -50,54 +53,67 @@ def retrieve_public_IP(): return data['ip'] -def retrieve_dns_IP(apiUrl, headers): +def retrieve_dns_ip(api_url, headers): """Retrieves the IP in the DNS record using the domain, rrset_name (for instance subdomain like www etc) and rrset_type (the DNS record type A, CNAME ...). The function uses requests library and connect to Gandi.net API Returns: - retrievedDnsIp (str): string of the IP address in the DNS record""" + retrieved_dns_ip (str): string of the IP address in the DNS record""" if verbose: print("Retrieving the DNS IP") - response = requests.get(apiUrl, headers=headers) + response = requests.get(api_url, headers=headers) - responseJson = response.json() # IPs are stored in a list as string + response_json = response.json() # IPs are stored in a list as string try: - retrievedDnsIp = responseJson['rrset_values'][0] + retrieved_dns_ip = response_json['rrset_values'][0] + retrieved_ttl = response_json['rrset_ttl'] except KeyError as key_error: print( f"{key_error} means the record doesn't exist, we'll return an empty string instead") - retrievedDnsIp = "" - return retrievedDnsIp + retrieved_dns_ip = "" + return retrieved_dns_ip, retrieved_ttl -def update_dns_IP(apiUrl, headers): - """Updates the IP in the DNS record using the IP provided (acquired by retrieve_public_IP) if it is different from the DNS IP""" +def update_dns_ip(api_url, headers): + """Updates the IP in the DNS record using the IP provided (acquired by retrieve_public_ip) if it is different from the DNS IP""" if destination == "public_ip": - publicIP = retrieve_public_IP() + publicIP = retrieve_public_ip() else: publicIP = destination - dnsIP = retrieve_dns_IP(apiUrl, headers) + dnsIP, dns_ttl = retrieve_dns_ip(api_url, headers) if verbose: print(f"Public IP is : {publicIP}") if dnsIP: print(f"DNS IP is : {dnsIP}") else: print("The subdomain doesn't exist, no DNS IP associated") - if not publicIP == dnsIP: - if verbose: - print("IPs do not match, setting DNS IP") - data = { - "rrset_values": [publicIP] - } + print(f"DNS TTL is {dns_ttl}") + if publicIP != dnsIP or dns_ttl != ttl: + + data = dict() + + data["rrset_values"] = [publicIP] print(f"{domain_record_string : <{domain_record_string_lenght}} | Old IP : {dnsIP} replaced -> by New IP : {publicIP}") - response = requests.put(url=apiUrl, headers=headers, json=data) + + if dns_ttl != ttl: + data["rrset_ttl"] = ttl + if verbose: + print(f"TTL are differents. DNS TTL {dns_ttl} where wanted TTL is {ttl}") + + if verbose: + print(f"The data to be sent is : {data}") + response = requests.put(url=api_url, headers=headers, json=data) if verbose: print(f"Request exited with status code : {response.status_code}") else: - print( - f"{domain_record_string : <{domain_record_string_lenght}} | {'IPs are the same.':<17}") + if publicIP == dnsIP: + print( + f"{domain_record_string : <{domain_record_string_lenght}} | {'IPs are the same.':<17}") + if dns_ttl == ttl: + print( + f"{domain_record_string : <{domain_record_string_lenght}} | {'TTL are the same':<17}") if __name__ == '__main__': - update_dns_IP(apiUrl, headers) + update_dns_ip(api_url, headers)