Compare commits

..

6 Commits
dev ... master

2 changed files with 65 additions and 43 deletions

View File

@ -68,15 +68,17 @@ def load_conf():
def ping(hostname): def ping(hostname):
cmd = "ping -c1 -w3 %s" % hostname cmd = "ping -4 -c1 -w3 %s" % hostname
ret = subprocess.run(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) ret = subprocess.run(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return 0 if ret.returncode else 1 return 0 if ret.returncode else 1
def get_hosts(): def get_hosts():
r = sysbus.requete('Devices:get') r = sysbus.requete('Devices:get', silent=True)
hosts = { 'A': {}, 'AAAA': {} } hosts = { 'A': {}, 'AAAA': {} }
if not r:
return hosts
for h in r['status']: for h in r['status']:
ns = {} ns = {}
for n in h['Names']: for n in h['Names']:
@ -102,8 +104,11 @@ def get_hosts():
def get_wan_addr(): def get_wan_addr():
r = sysbus.requete('NMC:getWANStatus') r = sysbus.requete('NMC:getWANStatus', silent=True)
wan = dict() wan = dict()
if not r or not r.get('data') or not r['data'].get('IPAddress') or not r['data'].get('IPv6Address'):
log('get_wan_addr: {}'.format(r))
return None
wan['ipv4'] = r['data']['IPAddress'] wan['ipv4'] = r['data']['IPAddress']
wan['ipv6'] = r['data']['IPv6Address'] wan['ipv6'] = r['data']['IPv6Address']
if wan['ipv4'] == '0.0.0.0': if wan['ipv4'] == '0.0.0.0':
@ -159,17 +164,18 @@ def process_zone(zone, stamp, grace_period, sync_zone):
update = { 'add': [], 'delete': [] } update = { 'add': [], 'delete': [] }
for prot in zone: for prot in zone:
for name in zone[prot]: for name in zone[prot]:
add = False active = False
for addr in zone[prot][name]: for addr in zone[prot][name]:
e = zone[prot][name][addr] e = zone[prot][name][addr]
if e['first'] == stamp and not sync_zone: if e['first'] == stamp:
update['add'].append([prot, name, addr]) update['add'].append([prot, name, addr])
add = True if e['last'] == stamp:
active = True
for addr in zone[prot][name]: for addr in zone[prot][name]:
e = zone[prot][name][addr] e = zone[prot][name][addr]
if add and e['last'] < stamp: if active and e['last'] < stamp:
update['delete'].append([prot, name, addr]) update['delete'].append([prot, name, addr])
elif not add and stamp - e['last'] > grace_period: elif not active and stamp - e['last'] > grace_period:
update['delete'].append([prot, name, addr]) update['delete'].append([prot, name, addr])
elif sync_zone: elif sync_zone:
update['add'].append([prot, name, addr]) update['add'].append([prot, name, addr])
@ -201,6 +207,10 @@ def write_zone_list(zone_filename, zone, update):
def log(msg): def log(msg):
stamp = time.strftime("%Y-%m-%d %H:%M:%S") stamp = time.strftime("%Y-%m-%d %H:%M:%S")
if sys.stdout.isatty():
for line in msg.split('\n'):
print("%s - %s" % (stamp, msg))
else:
with open(log_filename, 'a') as logfile: with open(log_filename, 'a') as logfile:
for line in msg.split('\n'): for line in msg.split('\n'):
logfile.write("%s - %s\n" % (stamp, msg)) logfile.write("%s - %s\n" % (stamp, msg))
@ -226,7 +236,7 @@ def ovh_update_zone(domain, zone, update, sync_zone):
result = client.get('/domain/zone/{}/record'.format(domain), result = client.get('/domain/zone/{}/record'.format(domain),
fieldType=prot, subDomain=name) fieldType=prot, subDomain=name)
for id in result: for id in result:
print('OVH: delete entry #{} {} {}'.format(id, name, prot)) log('OVH: delete entry #{} {} {}'.format(id, name, prot))
client.delete('/domain/zone/{}/record/{}'.format(domain, id)) client.delete('/domain/zone/{}/record/{}'.format(domain, id))
for prot, name, addr in update['delete']: for prot, name, addr in update['delete']:
@ -238,57 +248,59 @@ def ovh_update_zone(domain, zone, update, sync_zone):
for id in result: for id in result:
r = client.get('/domain/zone/%s/record/%d' % (domain, id)) r = client.get('/domain/zone/%s/record/%d' % (domain, id))
if r['fieldType'] == prot and r['target'] == addr: if r['fieldType'] == prot and r['target'] == addr:
print("OVH: delete entry for %s %s %s (#%s)" % (name, prot, addr, id)) log("OVH: delete entry for %s %s %s (#%s)" % (name, prot, addr, id))
client.delete('/domain/zone/%s/record/%d' % (domain, id)) client.delete('/domain/zone/%s/record/%d' % (domain, id))
for prot, name, addr in update['add']: for prot, name, addr in update['add']:
if not prot in ['A', 'AAAA']: if not prot in ['A', 'AAAA']:
continue continue
print("OVH: create entry for %s %s %s" % (name, prot, addr)) log("OVH: create entry for %s %s %s" % (name, prot, addr))
client.post('/domain/zone/%s/record' % domain, client.post('/domain/zone/%s/record' % domain,
fieldType=prot, fieldType=prot,
subDomain=name, subDomain=name,
target=addr, target=addr,
ttl=60) ttl=60)
print("OVH: Refresh zone %s" % domain) log("OVH: Refresh zone %s" % domain)
client.post('/domain/zone/%s/refresh' % domain) client.post('/domain/zone/%s/refresh' % domain)
return True return True
except: except:
print('OVH update error\n') log('OVH update error\n')
return False return False
def livebox_rule_id(words): def livebox_rule_id(words):
id='dyndomain_{}'.format('_'.join(words)) id='dyndomain_{}'.format('_'.join(words))
id = id.replace('.', '_') id = id.replace('.', '_')
return id return id
def livebox_delete_port_nat(port, addr): def livebox_delete_port_nat(port, addr):
print('livebox: delete PortNat {} to {}'.format(port, addr)) log('livebox: delete PortNat {} to {}'.format(port, addr))
id = livebox_rule_id([port]) id = livebox_rule_id([port])
r = sysbus.requete('Firewall:deletePortForwarding', { 'id': id, 'origin': 'webui' }) r = sysbus.requete('Firewall:deletePortForwarding', { 'id': id, 'origin': 'webui' }, silent=True)
def livebox_delete_pinhole(port, addr): def livebox_delete_pinhole(port, addr):
print('livebox: delete pinhole {} to {}'.format(port, addr)) log('livebox: delete pinhole {} to {}'.format(port, addr))
id = livebox_rule_id([port, addr]) id = livebox_rule_id([port, addr])
r = sysbus.requete('Firewall:deletePinhole', { 'id': id, 'origin': 'webui' }) r = sysbus.requete('Firewall:deletePinhole', { 'id': id, 'origin': 'webui' }, silent=True)
def livebox_add_port_nat(port, addr): def livebox_add_port_nat(port, addr):
print('livebox: add PortNat {} to {}'.format(port, addr)) log('livebox: add PortNat {} to {}'.format(port, addr))
id = livebox_rule_id([port]) id = livebox_rule_id([port])
a = { a = {
'id': id, 'id': id,
'origin': 'webui', 'origin': 'webui',
'sourceInterface': 'data', 'sourceInterface': 'data',
'destinationIPAddress': addr, 'destinationIPAddress': addr,
'protocol': '6', 'protocol': '6,17',
'internalPort': port, 'internalPort': port,
'enable': True, 'enable': True,
} }
r = sysbus.requete('Firewall:setPortForwarding', a) r = sysbus.requete('Firewall:setPortForwarding', a, silent=True)
def livebox_add_pinhole(port, addr): def livebox_add_pinhole(port, addr):
print('livebox: add pinhole {} to {}'.format(port, addr)) log('livebox: add pinhole {} to {}'.format(port, addr))
id = livebox_rule_id([port, addr]) id = livebox_rule_id([port, addr])
a = { a = {
'id': id, 'id': id,
@ -296,10 +308,11 @@ def livebox_add_pinhole(port, addr):
'sourceInterface': 'data', 'sourceInterface': 'data',
'destinationPort': port, 'destinationPort': port,
'destinationIPAddress': addr, 'destinationIPAddress': addr,
'protocol': '6', 'protocol': '6,17',
'ipversion': '6',
'enable': True, 'enable': True,
} }
r = sysbus.requete('Firewall:setPinhole', a) r = sysbus.requete('Firewall:setPinhole', a, silent=True)
def livebox_update_fw(zone, update, sync_zone): def livebox_update_fw(zone, update, sync_zone):
for prot, addr, port in update['delete']: for prot, addr, port in update['delete']:
@ -326,7 +339,7 @@ def send_update_mail(mail_to, mail_from, zone_domain, update, mail_ignore_list,
if not okmail: if not okmail:
return return
print('Send email to %s' % mail_to) log('Send email to %s' % mail_to)
msg = EmailMessage() msg = EmailMessage()
msg['Subject'] = "Livebox update in %s" % zone_domain msg['Subject'] = "Livebox update in %s" % zone_domain
@ -334,27 +347,27 @@ def send_update_mail(mail_to, mail_from, zone_domain, update, mail_ignore_list,
msg['To' ] = mail_to msg['To' ] = mail_to
txt = "Livebox update\n\n" 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
if updated['add']:
txt = txt + "\nUpdated entries:\n"
for prot,name,addr in update['add']: for prot,name,addr in update['add']:
txt = txt + " %-20s %-4s %s\n" % (name,prot,addr) txt = txt + " %-20s %-4s %s\n" % (name,prot,addr)
if update['delete']:
txt = txt + "\nRemoved entries:\n" txt = txt + "\nRemoved entries:\n"
for prot,name,addr in update['delete']: for prot,name,addr in update['delete']:
txt = txt + " %-20s %-4s %s\n" % (name,prot,addr) txt = txt + " %-20s %-4s %s\n" % (name,prot,addr)
txt = txt + '\n' txt = txt + '\n'
txt = txt + "WAN IPv4 : %s\n" % wan['ipv4']
txt = txt + "WAN IPv6 : %s\n" % wan['ipv6']
msg.set_content(txt) msg.set_content(txt)
s = smtplib.SMTP('localhost') s = smtplib.SMTP('localhost')
s.send_message(msg) s.send_message(msg)
s.quit() s.quit()
#print(txt)
load_conf() load_conf()
@ -364,13 +377,19 @@ if not ping(wan_hostname):
sys.exit(0) sys.exit(0)
sysbus.load_conf() sysbus.load_conf()
try:
r = sysbus.auth(False) r = sysbus.auth(False)
if not r: if not r:
print('Error: cannot authenticate on livebox') log('Error: cannot authenticate on livebox')
sys.exit(1)
except Exception as e:
log('Error: %s'.format(e))
sys.exit(1) sys.exit(1)
hosts = get_hosts() hosts = get_hosts()
wan = get_wan_addr() wan = get_wan_addr()
if not wan:
sys.exit(0)
zone = read_zone_list(zone_filename) zone = read_zone_list(zone_filename)
sync_zone = False sync_zone = False
@ -386,6 +405,9 @@ if update:
success = ovh_update_zone(zone_domain, zone, update, sync_zone) success = ovh_update_zone(zone_domain, zone, update, sync_zone)
livebox_update_fw(zone, update, sync_zone) livebox_update_fw(zone, update, sync_zone)
if success: if success:
try:
send_update_mail(mail_to, mail_from, zone_domain, update, mail_ignore_list, wan) send_update_mail(mail_to, mail_from, zone_domain, update, mail_ignore_list, wan)
except:
pass
write_zone_list(zone_filename, zone, update) write_zone_list(zone_filename, zone, update)

2
sysbus

@ -1 +1 @@
Subproject commit 5526cb53641e5620dfe9d688b9a4b90a40076f91 Subproject commit 87040a0906df80ade21ea863452838a8a574bdbd