mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge pull request #3111 from modoboa/optional-IPV6-check
Added option to disable IPV6 mx checks
This commit is contained in:
@@ -181,6 +181,7 @@ class AdminGlobalParametersSerializer(serializers.Serializer):
|
||||
enable_mx_checks = serializers.BooleanField(default=True)
|
||||
valid_mxs = serializers.CharField(allow_blank=True)
|
||||
domains_must_have_authorized_mx = serializers.BooleanField(default=False)
|
||||
enable_ipv6_mx_checks = serializers.BooleanField(default=True)
|
||||
enable_spf_checks = serializers.BooleanField(default=True)
|
||||
enable_dkim_checks = serializers.BooleanField(default=True)
|
||||
enable_dmarc_checks = serializers.BooleanField(default=True)
|
||||
@@ -274,6 +275,8 @@ class AdminGlobalParametersSerializer(serializers.Serializer):
|
||||
raise serializers.ValidationError({
|
||||
"valid_mxs": _("Define at least one authorized network / address")
|
||||
})
|
||||
if not data.get("enable_mx_checks"):
|
||||
data["enable_ipv6_mx_checks"] = False
|
||||
return data
|
||||
|
||||
|
||||
|
||||
@@ -50,6 +50,14 @@ class AdminParametersForm(param_forms.AdminParametersForm):
|
||||
)
|
||||
)
|
||||
|
||||
enable_ipv6_mx_checks = YesNoField(
|
||||
label=gettext_lazy("Enable IPV6 checks"),
|
||||
initial=True,
|
||||
help_text=gettext_lazy(
|
||||
"Check if MX setup for ipv6 is valid"
|
||||
)
|
||||
)
|
||||
|
||||
enable_spf_checks = YesNoField(
|
||||
label=gettext_lazy("Enable SPF checks"),
|
||||
initial=True,
|
||||
@@ -194,7 +202,8 @@ class AdminParametersForm(param_forms.AdminParametersForm):
|
||||
# Visibility rules
|
||||
visibility_rules = {
|
||||
"valid_mxs": "enable_mx_checks=True",
|
||||
"domains_must_have_authorized_mx": "enable_mx_checks=True"
|
||||
"domains_must_have_authorized_mx": "enable_mx_checks=True",
|
||||
"enable_ipv6_mx_checks": "enable_mx_checks=True"
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -292,6 +301,8 @@ class AdminParametersForm(param_forms.AdminParametersForm):
|
||||
"valid_mxs",
|
||||
_("Define at least one authorized network / address")
|
||||
)
|
||||
if not cleaned_data.get("enable_mx_checks"):
|
||||
cleaned_data["enable_ipv6_mx_checks"] = False
|
||||
return cleaned_data
|
||||
|
||||
|
||||
@@ -322,6 +333,13 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([
|
||||
"does not use one of the defined addresses."
|
||||
)
|
||||
}),
|
||||
("enable_ipv6_mx_checks", {
|
||||
"label": gettext_lazy("Enable IPV6 checks"),
|
||||
"display": "enable_mx_checks=true",
|
||||
"help_text": gettext_lazy(
|
||||
"Check if MX setup for ipv6 is valid"
|
||||
)
|
||||
}),
|
||||
("enable_spf_checks", {
|
||||
"label": gettext_lazy("Enable SPF checks"),
|
||||
"help_text": gettext_lazy(
|
||||
|
||||
@@ -226,7 +226,10 @@ def get_domain_mx_list(domain):
|
||||
for dns_answer in dns_answers:
|
||||
mx_domain = dns_answer.exchange.to_unicode(
|
||||
omit_final_dot=True, idna_codec=IDNA_2008_UTS_46)
|
||||
for rtype in ["A", "AAAA"]:
|
||||
rtypes = ["A"]
|
||||
if param_tools.get_global_parameter("enable_ipv6_mx_checks", app="admin"):
|
||||
rtypes.append("AAAA")
|
||||
for rtype in rtypes:
|
||||
ip_answers = get_dns_records(mx_domain, rtype, resolver)
|
||||
if not ip_answers:
|
||||
continue
|
||||
|
||||
@@ -10,7 +10,8 @@ from django.test import override_settings
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from modoboa.core import factories as core_factories
|
||||
from modoboa.core import (
|
||||
models as core_models, factories as core_factories)
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
from . import utils
|
||||
from .. import factories, models
|
||||
@@ -171,6 +172,29 @@ class MXTestCase(ModoTestCase):
|
||||
% {"domain": "bad-response.example.com", "addr": "000.0.0.0"}),
|
||||
)
|
||||
|
||||
@mock.patch("ipaddress.ip_address")
|
||||
@mock.patch.object(dns.resolver.Resolver, "resolve")
|
||||
def test_ipv6_logging(self, mock_query, mock_ip_address):
|
||||
"""Test to check that AAAA missing record is logged consistently."""
|
||||
mock_query.side_effect = utils.mock_dns_query_result
|
||||
mock_ip_address.side_effect = utils.mock_ip_address_result
|
||||
localconfig = core_models.LocalConfig.objects.first()
|
||||
localconfig.parameters.set_value("enable_ipv6_mx_checks", True, "admin")
|
||||
localconfig.save()
|
||||
with LogCapture("modoboa.admin") as log:
|
||||
get_domain_mx_list("test3.com")
|
||||
log.check(
|
||||
("modoboa.admin", "ERROR",
|
||||
_("No AAAA record for %s")
|
||||
% "mx3.example.com")
|
||||
)
|
||||
localconfig = core_models.LocalConfig.objects.first()
|
||||
localconfig.parameters.set_value("enable_ipv6_mx_checks", False, "admin")
|
||||
localconfig.save()
|
||||
with LogCapture("modoboa.admin") as log2:
|
||||
get_domain_mx_list("test3.com")
|
||||
log2.check()
|
||||
|
||||
|
||||
@override_settings(DNSBL_PROVIDERS=["zen.spamhaus.org"])
|
||||
class DNSBLTestCase(ModoTestCase):
|
||||
|
||||
@@ -43,7 +43,7 @@ _BAD_IP_RECORD = (socket.AF_INET, socket.SOCK_STREAM, 6, "", ("BAD", 25))
|
||||
_IP_RECORDS = [_IPV4_RECORD_1, _IPV6_RECORD]
|
||||
|
||||
_POSSIBLE_DNS_RESULTS = {
|
||||
"test3.com": [_MX_RECORD_2],
|
||||
"test3.com": [_MX_RECORD_3],
|
||||
"no-mx.example.com": NoAnswer(),
|
||||
"does-not-exist.example.com": NXDOMAIN(),
|
||||
"timeout.example.com": Timeout(),
|
||||
@@ -79,12 +79,20 @@ _POSSIBLE_IP_RESULTS = {
|
||||
"000.0.0.0": ValueError(),
|
||||
}
|
||||
|
||||
_POSSIBLE_DNS_IPV6_RESULTS = {
|
||||
settings.REDIS_HOST: socket.getaddrinfo(settings.REDIS_HOST, settings.REDIS_PORT),
|
||||
"mx3.example.com": NoAnswer()
|
||||
}
|
||||
|
||||
|
||||
def mock_dns_query_result(qname, *args, **kwargs):
|
||||
if "MX" in args:
|
||||
if qname in _POSSIBLE_DNS_RESULTS:
|
||||
return get_mock_dns_query_response(_POSSIBLE_DNS_RESULTS, qname)
|
||||
return _MX_RECORDS
|
||||
elif "AAAA" in args:
|
||||
if qname in _POSSIBLE_DNS_IPV6_RESULTS:
|
||||
return get_mock_dns_query_response(_POSSIBLE_DNS_IPV6_RESULTS, qname)
|
||||
if qname in _POSSIBLE_DNS_RESULTS_NO_MX:
|
||||
return get_mock_dns_query_response(_POSSIBLE_DNS_RESULTS_NO_MX, qname)
|
||||
return _IP_SET_RECORDS
|
||||
|
||||
@@ -51,6 +51,7 @@ SETTINGS_SAMPLE = {
|
||||
"core-ldap_admin_groups": "",
|
||||
"core-ldap_groups_search_base": "",
|
||||
"admin-enable_mx_checks": "True",
|
||||
"admin-enable_ipv6_mx_checks": "True",
|
||||
"core-ldap_search_base": "",
|
||||
"admin-valid_mxs": "",
|
||||
"limits-deflt_user_domains_limit": "0",
|
||||
@@ -264,6 +265,15 @@ sha512crypt is not one of the available choices."]},
|
||||
self.assertIn(
|
||||
"sms_ovh_application_secret", errors["form_errors"])
|
||||
|
||||
def test_mx_check_settings_clean(self):
|
||||
settings = SETTINGS_SAMPLE.copy()
|
||||
settings["admin-enable_mx_checks"] = False
|
||||
url = reverse("core:parameters")
|
||||
response = self.client.post(url, settings, format="json")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertFalse(
|
||||
param_tools.get_global_parameter("enable_ipv6_mx_checks", "admin")
|
||||
)
|
||||
|
||||
class UserSettings(param_forms.UserParametersForm):
|
||||
"""Stupid user settings form."""
|
||||
|
||||
@@ -5,6 +5,7 @@ import ipaddress
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from modoboa.admin import lib as admin_lib
|
||||
from modoboa.parameters import tools as param_tools
|
||||
|
||||
from . import constants
|
||||
|
||||
@@ -43,7 +44,10 @@ def get_dmarc_record(domain):
|
||||
|
||||
def _get_simple_record(name):
|
||||
"""We just want to know if name is declared."""
|
||||
for rdtype in ["A", "CNAME", "AAAA"]:
|
||||
rtypes = ["A", "CNAME"]
|
||||
if param_tools.get_global_parameter("enable_ipv6_mx_checks", app="admin"):
|
||||
rtypes.append("AAAA")
|
||||
for rdtype in rtypes:
|
||||
records = admin_lib.get_dns_records(name, rdtype)
|
||||
if records is not None:
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user