From bd8fceca35e2b2dca29adb08e933d4ac98cda835 Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 5 Jan 2024 19:21:26 +0100 Subject: [PATCH] Added options for custom resolver and enforcing DNSSEC --- .../java/eu/faircode/email/DnsHelper.java | 31 +++++++++++++------ .../email/FragmentOptionsConnection.java | 28 ++++++++++++++++- .../eu/faircode/email/ServiceSynchronize.java | 4 ++- .../layout/fragment_options_connection.xml | 25 ++++++++++++++- app/src/main/res/values/strings.xml | 2 ++ 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/DnsHelper.java b/app/src/main/java/eu/faircode/email/DnsHelper.java index e68194bac4..e75fcc953f 100644 --- a/app/src/main/java/eu/faircode/email/DnsHelper.java +++ b/app/src/main/java/eu/faircode/email/DnsHelper.java @@ -90,7 +90,7 @@ public class DnsHelper { String domain = UriHelper.getEmailDomain(email); if (domain == null) continue; - DnsRecord[] records = _lookup(context, domain, "mx", CHECK_TIMEOUT, false); + DnsRecord[] records = _lookup(context, domain, "mx", CHECK_TIMEOUT); if (records.length == 0) throw new UnknownHostException(domain); } @@ -98,12 +98,14 @@ public class DnsHelper { @NonNull static DnsRecord[] lookup(Context context, String name, String type) { - return _lookup(context, name, type, LOOKUP_TIMEOUT, false); + return _lookup(context, name, type, LOOKUP_TIMEOUT); } @NonNull - private static DnsRecord[] _lookup( - Context context, String name, String type, int timeout, boolean require_authentic) { + private static DnsRecord[] _lookup(Context context, String name, String type, int timeout) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean dns_secure = prefs.getBoolean("dns_secure", false); + String filter = null; int colon = type.indexOf(':'); if (colon > 0) { @@ -234,7 +236,7 @@ public class DnsHelper { data.throwIfErrorResponse(); boolean secure = (data.getUnverifiedReasons() != null); - if (secure && require_authentic) { + if (secure && dns_secure) { DnssecResultNotAuthenticException ex = data.getDnssecResultNotAuthenticException(); if (ex != null) throw ex; @@ -321,8 +323,9 @@ public class DnsHelper { return result.toArray(new DnsRecord[0]); } catch (Throwable ex) { - if (ex instanceof DnssecValidationFailedException || - ex instanceof MultipleIoException) + if (ex instanceof MultipleIoException || + ex instanceof DnssecValidationFailedException || + ex instanceof DnssecResultNotAuthenticException) Log.i(ex); else Log.e(ex); @@ -332,7 +335,7 @@ public class DnsHelper { static InetAddress getByName(Context context, String host) throws UnknownHostException { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean dns_custom = prefs.getBoolean("dns_custom", BuildConfig.DEBUG); + boolean dns_custom = prefs.getBoolean("dns_custom", false); if (!dns_custom) return InetAddress.getByName(host); @@ -341,12 +344,11 @@ public class DnsHelper { return InetAddress.getByName(host); return getAllByName(context, host)[0]; - } static InetAddress[] getAllByName(Context context, String host) throws UnknownHostException { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean dns_custom = prefs.getBoolean("dns_custom", BuildConfig.DEBUG); + boolean dns_custom = prefs.getBoolean("dns_custom", false); if (!dns_custom) return InetAddress.getAllByName(host); @@ -436,6 +438,15 @@ public class DnsHelper { return result; } + static void clear(Context context) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences.Editor editor = prefs.edit(); + for (String key : prefs.getAll().keySet()) + if (key != null && key.startsWith("dns.")) + editor.remove(key); + editor.apply(); + } + static void test(Context context) throws UnknownHostException { test(context, "gmail.com", "ns"); test(context, "web.de", "mx"); diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java index 1564814215..41a7a8e007 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java @@ -95,6 +95,8 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private SwitchCompat swBindSocket; private SwitchCompat swStandaloneVpn; private EditText etDns; + private SwitchCompat swDnsCustom; + private SwitchCompat swDnsSecure; private SwitchCompat swTcpKeepAlive; private SwitchCompat swSslUpdate; private SwitchCompat swSslHarden; @@ -126,7 +128,9 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre "metered", "download", "download_limited", "roaming", "rlah", "download_headers", "download_eml", "download_plain", "require_validated", "require_validated_captive", "vpn_only", - "timeout", "prefer_ip4", "bind_socket", "standalone_vpn", "dns_extra", "tcp_keep_alive", + "timeout", "prefer_ip4", "bind_socket", "standalone_vpn", + "dns_extra", "dns_custom", "dns_secure", + "tcp_keep_alive", "ssl_update", "ssl_harden", "ssl_harden_strict", "cert_strict", "cert_transparency", "check_names", "open_safe", "http_redirect", "bouncy_castle", "bc_fips" @@ -159,6 +163,8 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre swBindSocket = view.findViewById(R.id.swBindSocket); swStandaloneVpn = view.findViewById(R.id.swStandaloneVpn); etDns = view.findViewById(R.id.etDns); + swDnsCustom = view.findViewById(R.id.swDnsCustom); + swDnsSecure = view.findViewById(R.id.swDnsSecure); swTcpKeepAlive = view.findViewById(R.id.swTcpKeepAlive); swSslUpdate = view.findViewById(R.id.swSslUpdate); swSslHarden = view.findViewById(R.id.swSslHarden); @@ -354,6 +360,23 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre } }); + swDnsCustom.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean checked) { + DnsHelper.clear(buttonView.getContext()); + prefs.edit().putBoolean("dns_custom", checked).apply(); + swDnsSecure.setEnabled(checked); + } + }); + + swDnsSecure.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean checked) { + DnsHelper.clear(buttonView.getContext()); + prefs.edit().putBoolean("dns_secure", checked).apply(); + } + }); + swTcpKeepAlive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @@ -736,6 +759,9 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre swBindSocket.setChecked(prefs.getBoolean("bind_socket", false)); swStandaloneVpn.setChecked(prefs.getBoolean("standalone_vpn", false)); etDns.setText(prefs.getString("dns_extra", null)); + swDnsCustom.setChecked(prefs.getBoolean("dns_custom", false)); + swDnsSecure.setChecked(prefs.getBoolean("dns_secure", false)); + swDnsSecure.setEnabled(swDnsCustom.isChecked()); swTcpKeepAlive.setChecked(prefs.getBoolean("tcp_keep_alive", false)); swSslUpdate.setChecked(prefs.getBoolean("ssl_update", true)); swSslHarden.setChecked(prefs.getBoolean("ssl_harden", false)); diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index e9a87dded8..9cf291bb9b 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -171,7 +171,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences "sync_folders", "sync_shared_folders", "download_headers", "download_eml", - "prefer_ip4", "bind_socket", "standalone_vpn", "tcp_keep_alive", // force reconnect + "prefer_ip4", "bind_socket", "standalone_vpn", // force reconnect + "dns_extra", "dns_custom", "dns_secure", // force reconnect + "tcp_keep_alive", // force reconnect "ssl_harden", "ssl_harden_strict", "cert_strict", "cert_transparency", "check_names", "bouncy_castle", "bc_fips", // force reconnect "experiments", "debug", "protocol", // force reconnect "auth_plain", "auth_login", "auth_ntlm", "auth_sasl", "auth_apop", // force reconnect diff --git a/app/src/main/res/layout/fragment_options_connection.xml b/app/src/main/res/layout/fragment_options_connection.xml index 96b05c38ea..a97fe9a6f3 100644 --- a/app/src/main/res/layout/fragment_options_connection.xml +++ b/app/src/main/res/layout/fragment_options_connection.xml @@ -448,6 +448,29 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvDns" /> + + + + Bind sockets to the active network Standalone VPN Additional DNS server addresses (comma separated) + Use custom DNS resolver + Enforce DNSSEC TCP keep alive Use updated SSL provider Harden SSL connections