dyndomain/dyndomain

269 lines
8.4 KiB
Plaintext
Raw Normal View History

2018-02-19 23:42:57 +01:00
#!/usr/bin/python3
import sys
import os
import configparser
import subprocess
import smtplib
import time
from email.message import EmailMessage
from pprint import pprint
rundir=os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(rundir)
from sysbus import sysbus
from ovh import ovh
def load_conf():
global zone_filename, log_filename
global wan_hostname, zone_domain, zone_subdomain
2019-10-07 09:19:16 +02:00
global hosts_list, hosts_ipv4_nat_list, hosts_alias_list
2019-10-10 10:52:12 +02:00
global mail_from, mail_to, mail_ignore_list
2018-02-19 23:42:57 +01:00
conf = configparser.ConfigParser(allow_no_value=True)
conf.read('home.conf')
zone_filename = conf['Files']['zonefile']
log_filename = conf['Files']['logfile']
2019-12-16 18:27:32 +01:00
wan_hostname = conf['Wan']['hostname'].lower()
zone_domain = conf['Zone']['domain'].lower()
zone_subdomain = conf['Zone']['subdomain'].lower()
2018-02-19 23:42:57 +01:00
mail_from = conf['Mail']['from']
mail_to = conf['Mail']['to']
mail_ignore_list = [ host.lower() for host in conf['MailIgnore'] ]
mail_ignore_list = [ '.'.join([h, zone_subdomain]) if not h.endswith('.'+zone_subdomain) else h for h in mail_ignore_list ]
2018-02-19 23:42:57 +01:00
2019-12-16 18:27:32 +01:00
hosts_list = [ host.lower() for host in conf['Hosts'] ]
hosts_ipv4_nat_list = [ host.lower() for host in conf['NatHosts'] ]
hosts_alias_list = [ h.lower() for h in conf['Aliases'] ]
2018-02-19 23:42:57 +01:00
def ping(hostname):
cmd = "ping -c1 -w3 %s" % hostname
ret = subprocess.run(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return 0 if ret.returncode else 1
2019-10-07 09:19:16 +02:00
2018-02-19 23:42:57 +01:00
def get_ipv6_hosts():
2019-10-05 23:01:08 +02:00
r = sysbus.requete('Devices:get')
2018-02-19 23:42:57 +01:00
ipv6_hosts = dict()
2019-10-05 23:01:08 +02:00
for h in r['status']:
if not 'IPv6Address' in h or not h['IPv6Address']:
continue
2019-12-16 18:27:32 +01:00
hostname = h['Name'].lower()
2019-10-07 09:19:16 +02:00
if hostname in hosts_alias_list:
hostname = hosts_alias_list[hostname]
2019-10-05 23:01:08 +02:00
for a in h['IPv6Address']:
if a['Scope'] != 'global' or a['Status'] != 'reachable':
continue
if not hostname in ipv6_hosts:
ipv6_hosts[hostname] = []
ipv6_hosts[hostname].append(a['Address'])
2018-02-19 23:42:57 +01:00
return ipv6_hosts
def get_wan_addr():
r = sysbus.requete('NMC:getWANStatus')
wan = dict()
wan['ipv4'] = r['data']['IPAddress']
wan['ipv6'] = r['data']['IPv6Address']
return wan
def full_name(host, domain):
host = host.replace('_', '-')
return '.'.join([host, domain])
def make_zone_list(wan_hostname, wan_addr, hosts, hosts_nat, domain):
zone = []
2019-10-05 23:03:38 +02:00
2018-02-19 23:42:57 +01:00
wan_hostname = full_name(wan_hostname, domain)
if wan_addr['ipv4'] != '':
zone.append([wan_hostname, 'A', wan_addr['ipv4']])
for host in hosts_nat:
zone.append([full_name(host, domain), 'A', wan_addr['ipv4']])
if wan_addr['ipv6'] != '':
zone.append([wan_hostname, 'AAAA', wan_addr['ipv6']])
for host in hosts:
for addr in hosts[host]:
if host in hosts_list:
zone.append([full_name(host, domain), 'AAAA', addr])
return zone
def read_zone_list_from_file(zone_filename):
zone_list = []
config = configparser.ConfigParser()
config.read(zone_filename)
for host in config:
for p in config[host]:
for target in config[host][p].split('\n'):
2019-12-16 18:27:32 +01:00
zone_list.append([host.lower(), p.upper(), target])
2018-02-19 23:42:57 +01:00
return zone_list
2019-10-05 23:03:38 +02:00
def make_delete_zone_list(zone_list, prev_zone_list):
return make_update_zone_list(prev_zone_list, zone_list)
2018-02-19 23:42:57 +01:00
def make_update_zone_list(zone_list, prev_zone_list):
update_zone_list = []
for entry in zone_list:
if not any(entry == x for x in prev_zone_list):
update_zone_list.append(entry)
return update_zone_list
def write_zone_list_to_file(zone_filename, zone_list):
config = configparser.ConfigParser()
for host,typefield,target in zone_list:
if not host in config:
config[host] = {}
if typefield in config[host]:
config[host][typefield] += '\n'+target
else:
config[host][typefield] = target
2018-02-19 23:42:57 +01:00
with open(zone_filename, 'w') as configfile:
config.write(configfile)
def log(msg):
stamp = time.strftime("%Y-%m-%d %H:%M:%S")
with open(log_filename, 'a') as logfile:
for line in msg.split('\n'):
logfile.write("%s - %s\n" % (stamp, msg))
2019-10-05 23:03:38 +02:00
def log_update_zone(zone_list, delete_zone_list):
for host,typea,addr in delete_zone_list:
2019-10-07 09:19:39 +02:00
log("[DEL] %-20s %-6s %s" % (host, typea, addr))
for host,typea,addr in zone_list:
log(" %-20s %-6s %s" % (host, typea, addr))
2018-02-19 23:42:57 +01:00
2019-10-05 23:03:38 +02:00
def ovh_update_zone(domain, update_zone_list, delete_zone_list):
if not len(update_zone_list) and not len(delete_zone_list):
2018-02-19 23:42:57 +01:00
return False
2019-11-12 12:23:26 +01:00
try:
client = ovh.Client()
for host, fieldtype, target in delete_zone_list:
result = client.get('/domain/zone/%s/record' % domain,
fieldType=fieldtype,
subDomain=host)
for id in result:
r = client.get('/domain/zone/%s/record/%d' % (domain, id))
if r['fieldType'] == fieldtype and r['target'] == target:
#print("Delete entry for %s %s %s" % (host, fieldtype, target))
client.delete('/domain/zone/%s/record/%d' % (domain, id))
for host, fieldtype, target in update_zone_list:
result = client.get('/domain/zone/%s/record' % domain,
fieldType=fieldtype,
subDomain=host)
skip = False
for id in result:
r = client.get('/domain/zone/%s/record/%d' % (domain, id))
if r['fieldType'] == fieldtype and r['target'] == target:
skip = True
if skip:
continue
#print("Create new entry for %s %s %s" % (host, fieldtype, target))
client.post('/domain/zone/%s/record' % domain,
fieldType=fieldtype,
subDomain=host,
target=target,
ttl=60)
#print("Refresh zone %s" % domain)
client.post('/domain/zone/%s/refresh' % domain)
return True
except:
print('OVH update error\n')
return False
2018-02-19 23:42:57 +01:00
2019-10-10 10:52:12 +02:00
def send_update_mail(mail_to, mail_from, zone_domain, update_zone_list, delete_zone_list, mail_ignore_list, wan):
2018-02-19 23:42:57 +01:00
#print('Send email to %s' % mail_to)
msg = EmailMessage()
2019-10-05 23:03:38 +02:00
2018-02-19 23:42:57 +01:00
msg['Subject'] = "Livebox update in %s" % zone_domain
msg['From'] = mail_from
msg['To' ] = mail_to
txt = "Livebox update\n\n"
txt = txt + "WAN IPv4 : %s\n" % wan['ipv4']
txt = txt + "WAN IPv6 : %s\n" % wan['ipv6']
txt = txt + "\nZone %s has been updated:\n" % zone_domain
2019-10-05 23:03:38 +02:00
2019-10-10 10:52:12 +02:00
filtered_update_list = [ h for h in update_zone_list if not h[0] in mail_ignore_list ]
filtered_delete_list = [ h for h in delete_zone_list if not h[0] in mail_ignore_list ]
2019-10-05 23:03:38 +02:00
2019-10-10 10:52:12 +02:00
if len(filtered_update_list) or len(filtered_delete_list):
for host,tp,addr in update_zone_list:
txt = txt + " %-20s %-4s %s\n" % (host,tp,addr)
2019-10-05 23:03:38 +02:00
2019-10-10 10:52:12 +02:00
txt = txt + "\nRemoved entries:\n"
2019-10-05 23:03:38 +02:00
2019-10-10 10:52:12 +02:00
for host,tp,addr in delete_zone_list:
txt = txt + " %-20s %-4s %s\n" % (host,tp,addr)
2018-02-19 23:42:57 +01:00
2019-10-10 10:52:12 +02:00
txt = txt + '\n'
2018-02-19 23:42:57 +01:00
2019-10-10 10:52:12 +02:00
msg.set_content(txt)
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
2019-10-05 23:03:38 +02:00
2018-02-19 23:42:57 +01:00
load_conf()
if not ping(wan_hostname):
log("%s is down" % wan_hostname)
sys.exit(0)
sysbus.load_conf()
2019-10-05 23:03:38 +02:00
r = sysbus.auth(False)
if not r:
print('Error: cannot authenticate on livebox')
sys.exit(1)
2018-02-19 23:42:57 +01:00
hosts = get_ipv6_hosts()
wan = get_wan_addr()
zone_list = make_zone_list(wan_hostname, wan, hosts, hosts_ipv4_nat_list, zone_subdomain)
prev_zone_list = read_zone_list_from_file(zone_filename)
2019-10-05 23:03:38 +02:00
delete_zone_list = make_delete_zone_list(zone_list, prev_zone_list)
2018-02-19 23:42:57 +01:00
update_zone_list = make_update_zone_list(zone_list, prev_zone_list)
2019-11-12 12:19:27 +01:00
#if update_zone_list or delete_zone_list:
# print('zone_list:')
# pprint(zone_list)
# print('prev_zone_list:')
# pprint(prev_zone_list)
# print('update_zone_list:')
# pprint(update_zone_list)
# print('delete_zone_list:')
# pprint(delete_zone_list)
2018-02-19 23:42:57 +01:00
2019-10-05 23:03:38 +02:00
log_update_zone(update_zone_list, delete_zone_list)
2018-02-19 23:42:57 +01:00
2019-11-12 12:19:51 +01:00
success = ovh_update_zone(zone_domain, update_zone_list, delete_zone_list)
2018-02-19 23:42:57 +01:00
2019-11-12 12:19:51 +01:00
if success:
2019-10-05 23:03:38 +02:00
new_zone_list = write_zone_list_to_file(zone_filename, zone_list)
2019-10-10 10:52:12 +02:00
send_update_mail(mail_to, mail_from, zone_domain, update_zone_list, delete_zone_list, mail_ignore_list, wan)
2018-02-19 23:42:57 +01:00