179 lines
6.9 KiB
Python
Executable file
179 lines
6.9 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
|
|
import json
|
|
import ovh
|
|
import sys
|
|
import requests, time
|
|
import yaml
|
|
|
|
from yaml.loader import SafeLoader
|
|
with open ('/etc/ovh-dns-updater.conf', 'r') as file:
|
|
config = yaml.safe_load(file)
|
|
|
|
checkDNS_interval_hrs = 0 # when the saved IP addresses are old, check the DNS record, even if the addresses did not change
|
|
#save last known address in local file.
|
|
current_ip_file = "/tmp/current_ip.json"
|
|
|
|
|
|
def send_email(msg, sender = 'no_reply@mydomain.com', receiver = 'admin@mydomain.com') :
|
|
import smtplib
|
|
|
|
try :
|
|
smtpObj = smtplib.SMTP('localhost')
|
|
smtpObj.sendmail(sender, receiver,
|
|
"From: {}\nTo: {}\nSubject: DNS update problem\n\nThe ovh-dns-updater.py script reports:\n{}\n".format(sender, receiver, msg)
|
|
)
|
|
except smtplib.SMTPException:
|
|
print( timestamp()," : Error unable to send email")
|
|
|
|
def get_current_ip(v = 4):
|
|
if v == 4 :
|
|
url_list = ["https://api.ipify.org", "https://ipv4.lafibre.info/ip.php", "https://v4.ident.me"]
|
|
else :
|
|
url_list = ["https://api6.ipify.org", "https://ipv6.lafibre.info/ip.php", "https://v6.ident.me"]
|
|
ip = ""
|
|
message = ""
|
|
for url in url_list :
|
|
try :
|
|
r = requests.get(url, timeout=30.0)
|
|
except requests.exceptions.RequestException as e:
|
|
message += "failed getting ipv{} address from {} because {} occurred\n".format(v, url, str(e))
|
|
continue
|
|
if r.status_code == requests.codes.ok :
|
|
ip = r.text
|
|
break
|
|
else :
|
|
message += "{} : Cannot get IPv{} from {}: requests.get returned status_code {}.\n".format(timestamp(), v, url, r.status_code)
|
|
if ip != "":
|
|
return ip
|
|
elif v in ip_versions_required :
|
|
message += "Failed getting required IPv{}. There is most likely a real connectivity problem. Aborting". format( v)
|
|
print(message)
|
|
send_email (message)
|
|
quit()
|
|
else :
|
|
return False
|
|
|
|
def timestamp() :
|
|
return time.asctime( time.localtime(time.time()) )
|
|
|
|
def update_record(domain, subdomain, new_ip, _ttl = 600):
|
|
#Update the (A or AAAA) record with the provided IP
|
|
|
|
global records_changed
|
|
typ = 'AAAA' if ":" in new_ip else 'A'
|
|
#print("checking record {} for {}.{}".format(typ,subdomain,domain))
|
|
path = "/domain/zone/{}/record".format(domain)
|
|
result = client.get(path,
|
|
fieldType = typ,
|
|
subDomain = subdomain
|
|
)
|
|
|
|
if len(result) != 1:
|
|
#creating NEW record
|
|
result = client.post(path,
|
|
fieldType = typ,
|
|
subDomain = subdomain,
|
|
target = new_ip,
|
|
ttl = _ttl
|
|
)
|
|
client.post('/domain/zone/{}/refresh'.format(domain))
|
|
result = client.get(path,
|
|
fieldType=typ,
|
|
subDomain=subdomain
|
|
)
|
|
record_id = result[0]
|
|
records_changed += 1
|
|
print("{} : ### created new record {} for {}.{}".format(timestamp(),typ,subdomain,domain))
|
|
else :
|
|
# record exists
|
|
record_id = result[0]
|
|
path = "/domain/zone/{}/record/{}".format(domain,record_id)
|
|
result = client.get(path)
|
|
oldip = result['target']
|
|
#print('record exists, with ip :',oldip)
|
|
if oldip == new_ip :
|
|
#print('nothing to do')
|
|
return
|
|
else :
|
|
#print('updating to ', new_ip)
|
|
result = client.put(path,
|
|
subDomain = subdomain,
|
|
target = new_ip,
|
|
ttl = _ttl
|
|
)
|
|
client.post('/domain/zone/{}/refresh'.format(domain))
|
|
records_changed += 1
|
|
#checking changes
|
|
result = client.get("/domain/zone/{}/record/{}".format(domain,record_id))
|
|
if new_ip != result['target'] :
|
|
records_changed -= 1
|
|
raise Exception("Error updating {}.{} with {}".format(subdomain,domain,new_ip))
|
|
|
|
|
|
def delete_record(domain, subdomain, typ):
|
|
"""
|
|
if it exists, delete an A or AAAA record
|
|
(because the corresponding IP is not available)
|
|
"""
|
|
#print("checking record {} for {}.{}".format(typ,subdomain,domain))
|
|
global records_changed
|
|
result = client.get("/domain/zone/{}/record".format(domain),
|
|
fieldType = typ,
|
|
subDomain = subdomain
|
|
)
|
|
if len(result) == 1:
|
|
# record exists, delete it
|
|
record_id = result[0]
|
|
print("{} : ### deleting record {} for {}.{}".format(timestamp(),typ,subdomain,domain))
|
|
client.delete("/domain/zone/{}/record/{}".format(domain,record_id))
|
|
client.post('/domain/zone/{}/refresh'.format(domain))
|
|
records_changed += 1
|
|
|
|
|
|
records_changed = 0
|
|
for zone in config['zones']:
|
|
domain = zone['domain']
|
|
|
|
try :
|
|
for subdomain in zone['subdomains']:
|
|
client = ovh.Client(
|
|
endpoint=config['endpoint'],
|
|
application_key=zone['application_key'],
|
|
application_secret=zone['application_secret'],
|
|
consumer_key=zone['consumer_key']
|
|
)
|
|
|
|
ip_versions_required = config['ip_versions_required']
|
|
|
|
current_ipv4 = get_current_ip(4)
|
|
current_ipv6 = get_current_ip(6)
|
|
|
|
if ('ipv4' not in config) or (config['ipv4'] != False) :
|
|
if current_ipv4 :
|
|
ttl = default_ttl if ('ttl' not in config) else config['ttl']
|
|
update_record(domain, subdomain, current_ipv4, _ttl = ttl)
|
|
else :
|
|
delete_record(domain, subdomain, 'A')
|
|
else :
|
|
print("Not touching A record for {}.{}, as instructed".format(subdomain, domain))
|
|
pass
|
|
if ('ipv6' not in config) or (config['ipv6'] != False) :
|
|
if current_ipv6 :
|
|
ttl = default_ttl if ('ttl' not in config) else config['ttl']
|
|
update_record(domain, subdomain, current_ipv6, _ttl = ttl)
|
|
else :
|
|
delete_record(domain, subdomain, 'AAAA')
|
|
else :
|
|
print("Not touching AAAA record for {}.{}, as instructed".format(subdomain, domain))
|
|
pass
|
|
#all hosts records have been updated without errors, log change and save current addresses
|
|
print("{} : checked {}.{} for {} ; {} -- {} records updates".format(timestamp(), subdomain, domain, current_ipv4, current_ipv6, records_changed))
|
|
with open(current_ip_file, 'w') as f:
|
|
json.dump([time.time(), current_ipv4, current_ipv6],f)
|
|
except Exception as e: #some error occured (API down, keys expired...?),
|
|
msg = "{} : ### error {} while updating records!! {} records updated with new addresses {} ; {}".format(timestamp(), str(e), records_changed, current_ipv4, current_ipv6)
|
|
print(msg)
|
|
|