diff --git a/plinth/modules/names/forms.py b/plinth/modules/names/forms.py index 186b611f9..8f89fa1d9 100644 --- a/plinth/modules/names/forms.py +++ b/plinth/modules/names/forms.py @@ -37,3 +37,30 @@ class NamesConfigurationForm(forms.Form): 'No.
Do not encrypt domain name ' 'resolutions.
', allow_markup=True)), ], initial='no') + + dnssec = forms.ChoiceField( + label=_('Use DNSSEC when resolving domains (global preference)'), + widget=forms.RadioSelect, choices=[ + ('yes', + format_lazy( + 'Yes. Verify authenticity and integrity of domain ' + 'resolutions.This improves security. ' + 'If the configured DNS servers do not support DNSSEC, all ' + 'name resolutions will fail. If your DNS provider (likely ' + 'your ISP) does not support DNSSEC or is manipulating ' + 'responses, you can configure well-known public DNS servers ' + 'in individual network connection settings.
', + allow_markup=True)), + ('allow-downgrade', + format_lazy( + 'Allow downgrade.Verify name ' + 'resolutions done by the DNS server if the server supports ' + 'DNSSEC. Otherwise, allow unverified resolutions. Limited ' + 'improvement to security. Detecting whether a DNS server ' + 'supports DNSSEC is not very reliable currently.
', + allow_markup=True)), + ('no', + format_lazy( + 'No.Do not verify domain name ' + 'resolutions.
', allow_markup=True)), + ], initial='no') diff --git a/plinth/modules/names/privileged.py b/plinth/modules/names/privileged.py index 84c8186bc..2870044d8 100644 --- a/plinth/modules/names/privileged.py +++ b/plinth/modules/names/privileged.py @@ -18,13 +18,14 @@ source_fallback_conf = pathlib.Path( @privileged def set_resolved_configuration(dns_fallback: bool | None = None, - dns_over_tls: str | None = None): + dns_over_tls: str | None = None, + dnssec: str | None = None): """Set systemd-resolved configuration options.""" if dns_fallback is not None: _set_enable_dns_fallback(dns_fallback) - if dns_over_tls is not None: - _set_resolved_configuration(dns_over_tls) + if dns_over_tls is not None or dnssec is not None: + _set_resolved_configuration(dns_over_tls, dnssec) # Workaround buggy reload that does not apply DNS-over-TLS changes # properly. @@ -61,14 +62,23 @@ def _load_augeas(): def _get_resolved_configuration(): """Return overridden configuration for systemd-resolved.""" aug = _load_augeas() - return {'dns_over_tls': aug.get('Resolve/DNSOverTLS/value') or 'no'} + # Default value for DNSSEC upstream is 'allow-downgrade', but in Debian it + # is 'no'. + return { + 'dns_over_tls': aug.get('Resolve/DNSOverTLS/value') or 'no', + 'dnssec': aug.get('Resolve/DNSSEC/value') or 'no' + } -def _set_resolved_configuration(dns_over_tls: str | None = None): +def _set_resolved_configuration(dns_over_tls: str | None = None, + dnssec: str | None = None): """Write configuration into a systemd-resolved override file.""" aug = _load_augeas() if dns_over_tls is not None: aug.set('Resolve/DNSOverTLS/value', dns_over_tls) + if dnssec is not None: + aug.set('Resolve/DNSSEC/value', dnssec) + aug.save() diff --git a/plinth/modules/names/views.py b/plinth/modules/names/views.py index a01a7bbd7..af5990b37 100644 --- a/plinth/modules/names/views.py +++ b/plinth/modules/names/views.py @@ -37,9 +37,15 @@ class NamesAppView(AppView): old_data = form.initial form_data = form.cleaned_data + changes = {} if old_data['dns_over_tls'] != form_data['dns_over_tls']: - privileged.set_resolved_configuration( - dns_over_tls=form_data['dns_over_tls']) + changes['dns_over_tls'] = form_data['dns_over_tls'] + + if old_data['dnssec'] != form_data['dnssec']: + changes['dnssec'] = form_data['dnssec'] + + if changes: + privileged.set_resolved_configuration(**changes) messages.success(self.request, _('Configuration updated')) return super().form_valid(form)