diff --git a/modoboa/admin/app_settings.py b/modoboa/admin/app_settings.py index f551790e3..bbfe2317a 100644 --- a/modoboa/admin/app_settings.py +++ b/modoboa/admin/app_settings.py @@ -61,6 +61,17 @@ class AdminParametersForm(parameters.AdminParametersForm): ) ) + valid_mxs = forms.CharField( + label=ugettext_lazy("Valid MXs"), + initial="", + help_text=ugettext_lazy( + "IP(s) or network(s) " + "of the MX that should match with domains' MX records. " + "On per line." + ), + widget=forms.Textarea + ) + enable_dnsbl_checks = YesNoField( label=ugettext_lazy("Enable DNSBL checks"), initial="yes", diff --git a/modoboa/admin/management/commands/subcommands/_mx.py b/modoboa/admin/management/commands/subcommands/_mx.py index 92dabb429..b16e48729 100644 --- a/modoboa/admin/management/commands/subcommands/_mx.py +++ b/modoboa/admin/management/commands/subcommands/_mx.py @@ -38,12 +38,15 @@ class CheckMXRecords(BaseCommand): """Return sender address for notifications.""" return parameters.get_admin("SENDER_ADDRESS", app="core") + @cached_property + def valid_mxs(self): + """Return valid MXs set in admin.""" + valid_mxs = parameters.get_admin("VALID_MXS", app="admin") + return [ipaddress.ip_network(u"{}".format(v.strip())) + for v in valid_mxs.split() if v.strip()] + def add_arguments(self, parser): """Add extra arguments to command.""" - parser.add_argument( - "--valid-mx", type=str, action="append", default=[], - help="Valid MX ip(s) or subnet(s) used to check that domain's MX " - "are your own.") parser.add_argument( "--no-dnsbl", action="store_true", default=False, help="Skip DNSBL queries.") @@ -158,7 +161,7 @@ class CheckMXRecords(BaseCommand): if not status: print(msg) - def check_valid_mx(self, domain, mx_list, valid_mx=None, **options): + def check_valid_mx(self, domain, mx_list, **options): """Check that domain's MX record exist. If `valid_mx` is provided, retrieved MX records must be @@ -166,14 +169,17 @@ class CheckMXRecords(BaseCommand): """ alerts = [] check = False - mxs = [ipaddress.ip_address(u"%s" % mx.address) for mx in mx_list] + mxs = [(mx, ipaddress.ip_address(u"%s" % mx.address)) + for mx in mx_list] + valid_mxs = self.valid_mxs if not mxs: alerts.append(_("Domain {} as no MX record").format(domain)) - elif valid_mx: - for subnet in valid_mx: - check = True in [mx in subnet for mx in mxs] - if check is True: - break + elif valid_mxs: + for subnet in valid_mxs: + for mx, addr in mxs: + if addr in subnet: + mx.managed = check = True + mx.save() if check is False: mx_names = [ "{0.name} ({0.address})".format(mx) for mx in mx_list] @@ -192,7 +198,7 @@ class CheckMXRecords(BaseCommand): return content = render_to_string( "admin/notifications/domain_invalid_mx.html", { - "domain": domain, "valid_mx": valid_mx, "alerts": alerts + "domain": domain, "alerts": alerts }) subject = _("[modoboa] MX issue(s) for domain {}").format( domain.name) @@ -227,11 +233,6 @@ class CheckMXRecords(BaseCommand): def handle(self, *args, **options): """Command entry point.""" - # Check that user provide valid network addresses - valid_mx = options["valid_mx"] - options["valid_mx"] = [ - ipaddress.ip_network(u"{}".format(v)) for v in valid_mx] - # Remove deprecated records first models.DNSBLResult.objects.exclude( provider__in=self.providers).delete() diff --git a/modoboa/admin/models/domain.py b/modoboa/admin/models/domain.py index e27023fd1..f38dd5977 100644 --- a/modoboa/admin/models/domain.py +++ b/modoboa/admin/models/domain.py @@ -224,6 +224,17 @@ class Domain(AdminObject): reversion.register(Domain) +class MXQuerySet(models.QuerySet): + """Custom manager for MXRecord.""" + + def has_valids(self): + """Return managed results.""" + if parameters.get_admin("ENABLE_MX_CHECKS"): + if parameters.get_admin("VALID_MXS", app="admin").strip(): + return self.filter(managed=True).exists() + return self.exists() + + class MXRecord(models.Model): """A model used to store MX records for Domain.""" @@ -233,6 +244,13 @@ class MXRecord(models.Model): managed = models.BooleanField(default=False) updated = models.DateTimeField() + objects = models.Manager.from_queryset(MXQuerySet)() + + def is_managed(self): + if not parameters.get_admin("ENABLE_MX_CHECKS"): + return False + return bool(parameters.get_admin("VALID_MXS", app="admin").strip()) + def __unicode__(self): return u'{0.name} ({0.address}) for {0.domain} '.format(self) diff --git a/modoboa/admin/templates/admin/domain_detail.html b/modoboa/admin/templates/admin/domain_detail.html index e464d57cc..20bd70225 100644 --- a/modoboa/admin/templates/admin/domain_detail.html +++ b/modoboa/admin/templates/admin/domain_detail.html @@ -23,7 +23,7 @@