pysmtp/mayordomo/resolver.py

122 lines
3.8 KiB
Python

# 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():
updateExitoso = True
pendientes = 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():
# await log.info('Destinatario {}'.format(destinatario.direccionid))
pendientes = pendientes + 1
result = await db.execute(select(Direccion).where(Direccion.id==destinatario.direccionid))
dbemail = result.scalar_one_or_none()
tieneMXValido = False
valido = int(time.time())
dbmx = await db.execute(select(MXRecord).where(MXRecord.fqdnid==dbemail.dominioid))
for mx_record in dbmx.scalars():
# await log.debug('mxrecord: {}'.format(mx_record.id))
if mx_record.validohasta > valido:
tieneMXValido = True
if tieneMXValido is not True:
await servidores_correo(dbemail.dominioid)
updateExitoso = False
await log.info('Actualización Incompleta')
except:
await log.error('Traceback {}'.format(traceback.format_exc()))
if tieneMXValido is True and pendientes > 0:
await log.info('Actualización exitosa')
return updateExitoso
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.warning("No se pudo resolver los servidores de correo de '{}'".format(dominio.fqdn))
return
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())+600
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()
# 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.info(u'Quedan {} intentos'.format(retry))
continue
raise asyncio.exceptions.TimeoutError('Intentos excedidos')