# coding: utf-8 import traceback import asyncio import time import os from async_dns.core import types, Address from async_dns.resolver import DNSClient from sqlalchemy.future import select from .model import db, update_mx, update_a, FQDN, MXRecord, ARecord, IPV4Addr, Direccion, Destinatario from .registro import log if not os.environ.get('DNS_RELAY'): dns_relay = '192.168.0.1' else: dns_relay = os.environ.get('DNS_RELAY') async def updateDNS(): pendientes = 0 destinos = 0 # await log.debug('Updatedns') try: rdestino = await db.execute(select(Destinatario).join(Direccion).join(FQDN).where(Destinatario.enviado==0).distinct(FQDN.id)) for destinatario in rdestino.scalars(): result = await db.execute(select(Direccion).where(Direccion.id==destinatario.direccionid)) dbemail = result.scalar_one_or_none() destinos += 1 tieneMXValido = False valido = int(time.time()) retries = 3 while tieneMXValido is False and retries > 0: retries -= 1 dbmx = await db.execute(select(MXRecord).where(MXRecord.fqdnid==dbemail.dominioid)) for mx_record in dbmx.scalars(): if mx_record.validohasta > valido: tieneMXValido = True break if tieneMXValido is False: updateExitoso = updateExitoso and await servidores_correo(dbemail.dominioid) if retries <= 0: await log.error('Error al actualizar los servidores MX de {}'.format(dbemail.direccion)) pendientes += 1 except: await log.error('Traceback {}'.format(traceback.format_exc())) if destinos>0 and pendientes == 0: await log.info('Todos los servidores MX estan disponibles para enviar los correos') elif destinos>0 and pendientes>0: await log.info('Algunos servidores MX no pudieron resolverse') if destinos > pendientes: return True #hay correos que mandar else: return False #nada que hacer async def servidores_correo(dominioid): try: result = await db.execute(select(FQDN).where(FQDN.id==dominioid)) dominio = result.scalar_one_or_none() servidores = await resolver(types.MX, dominio.fqdn) except: # await log.error('Traceback {}'.format(traceback.format_exc())) await log.error("No se pudo resolver los servidores de correo de '{}'".format(dominio.fqdn)) return False await log.info("Actualizando los servidores de correo de: {}".format(dominio.fqdn)) for host in servidores: typename = host.data.type_name prioridad, fqdn = host.data.data tiempo = int(time.time())+10 #add the 10, because of the sleep delay validohasta = tiempo try: direcciones = await resolver(types.A, fqdn) except: # await log.error('Traceback {}'.format(traceback.format_exc())) # await log.debug("No se pudo resolver la dirección A => {}".format(fqdn)) continue dbmx = await update_mx(dominio.id, fqdn, prioridad) # await log.debug("Servidor {}: '{}' prioridad {} validohasta: {}".format(typename, fqdn, prioridad, dbmx.validohasta)) for direccion in direcciones: if direccion.qtype == types.A: ttl = direccion.ttl + tiempo typename = direccion.data.type_name ipv4 = direccion.data.data if ttl > validohasta: validohasta = ttl await update_a(dbmx.fqdnmxid, ipv4, ttl) # await log.debug("Dirección {}: '{}' TTL {} (time:{}, ttl:{})".format(typename, ipv4, ttl, tiempo, direccion.ttl)) dbmx.validohasta = validohasta await db.commit() return True # await log.debug("Servidor {}: '{}' prioridad {} validohasta: {}".format(typename, fqdn, prioridad, dbmx.validohasta)) async def resolver(tipo=types.A, fqdn='ilab.cl'): client = DNSClient() retry = 10 while retry > 0: try: return await client.query(fqdn, tipo, Address.parse(dns_relay)) # for valor in res: # await log.debug('valor => {}'.format(valor)) # typename = valor.data.type_name # if tipo == types.A: # fqdn = valor.data.data # await log.debug('data => {}'.format(fqdn)) # else: # await log.debug('data => {}'.format(valor.data)) # prioridad, fqdn = valor.data.data # return res except asyncio.exceptions.TimeoutError: retry = retry - 1 log.warning(u'Quedan {} intentos'.format(retry)) continue raise asyncio.exceptions.TimeoutError('Intentos excedidos')