diff --git a/app/src/main/java/com/sun/mail/util/SocketFetcher.java b/app/src/main/java/com/sun/mail/util/SocketFetcher.java index 8de8cb9ed9..d51d92d690 100644 --- a/app/src/main/java/com/sun/mail/util/SocketFetcher.java +++ b/app/src/main/java/com/sun/mail/util/SocketFetcher.java @@ -309,8 +309,11 @@ public class SocketFetcher { prefix + ".usesocketchannels", false)) { logger.finer("using SocketChannels"); socket = SocketChannel.open().socket(); - } else - socket = new Socket(); + } else { + SocketFactory f = (SocketFactory) props.get("fairemail.factory"); + eu.faircode.email.Log.i("Using socket factory=" + f); + socket = (f == null ? new Socket() : f.createSocket()); + } } if (to >= 0) { if (logger.isLoggable(Level.FINEST)) @@ -333,6 +336,7 @@ public class SocketFetcher { iaddr = InetAddress.getByAddress(server, iaddr.getAddress()); eu.faircode.email.Log.i("Socket connect " + iaddr + " timeout=" + cto + + " server=" + server + " reuse=" + socket.getReuseAddress() + " local=" + socket.getLocalSocketAddress()); logger.finest("connecting..."); diff --git a/app/src/main/java/eu/faircode/email/EmailService.java b/app/src/main/java/eu/faircode/email/EmailService.java index 6ab535966e..edb70f8d5b 100644 --- a/app/src/main/java/eu/faircode/email/EmailService.java +++ b/app/src/main/java/eu/faircode/email/EmailService.java @@ -24,6 +24,10 @@ import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_OAUTH; import android.content.Context; import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkInfo; +import android.os.Build; import android.os.ParcelFileDescriptor; import android.security.KeyChain; import android.system.ErrnoException; @@ -353,6 +357,19 @@ public class EmailService implements AutoCloseable { String certificate, String fingerprint) throws MessagingException { properties.put("fairemail.server", host); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean bind_socket = prefs.getBoolean("bind_socket", false); + if (bind_socket && + Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + try { + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + Network active = cm.getActiveNetwork(); + if (active != null) + properties.put("fairemail.factory", active.getSocketFactory()); + } catch (Throwable ex) { + Log.e(ex); + } + SSLSocketFactoryService factory = null; try { PrivateKey key = null; diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java index c119ec7611..3ff8c7a4cc 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsConnection.java @@ -65,6 +65,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private SwitchCompat swValidated; private EditText etTimeout; private SwitchCompat swPreferIp4; + private SwitchCompat swBindSocket; private SwitchCompat swStandaloneVpn; private SwitchCompat swTcpKeepAlive; private TextView tvTcpKeepAliveHint; @@ -80,7 +81,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre private final static String[] RESET_OPTIONS = new String[]{ "metered", "download", "roaming", "rlah", "download_headers", "download_eml", - "require_validated", "timeout", "prefer_ip4", "standalone_vpn", "tcp_keep_alive", "ssl_harden" + "require_validated", "timeout", "prefer_ip4", "bind_socket", "standalone_vpn", "tcp_keep_alive", "ssl_harden" }; @Override @@ -102,6 +103,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre swValidated = view.findViewById(R.id.swValidated); etTimeout = view.findViewById(R.id.etTimeout); swPreferIp4 = view.findViewById(R.id.swPreferIp4); + swBindSocket = view.findViewById(R.id.swBindSocket); swStandaloneVpn = view.findViewById(R.id.swStandaloneVpn); swTcpKeepAlive = view.findViewById(R.id.swTcpKeepAlive); tvTcpKeepAliveHint = view.findViewById(R.id.tvTcpKeepAliveHint); @@ -211,6 +213,15 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre } }); + swBindSocket.setVisibility(debug || BuildConfig.DEBUG ? View.VISIBLE : View.GONE); + + swBindSocket.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("bind_socket", checked).apply(); + } + }); + swStandaloneVpn.setVisibility(debug || BuildConfig.DEBUG ? View.VISIBLE : View.GONE); swStandaloneVpn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @@ -348,6 +359,7 @@ public class FragmentOptionsConnection extends FragmentBase implements SharedPre etTimeout.setHint(Integer.toString(EmailService.DEFAULT_CONNECT_TIMEOUT)); swPreferIp4.setChecked(prefs.getBoolean("prefer_ip4", true)); + swBindSocket.setChecked(prefs.getBoolean("bind_socket", false)); swStandaloneVpn.setChecked(prefs.getBoolean("standalone_vpn", false)); swTcpKeepAlive.setChecked(prefs.getBoolean("tcp_keep_alive", false)); 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 f2d053b798..0692fd0293 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -148,7 +148,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences "sync_folders", "sync_shared_folders", "download_headers", "download_eml", - "prefer_ip4", "standalone_vpn", "tcp_keep_alive", "ssl_harden", // force reconnect + "prefer_ip4", "bind_socket", "standalone_vpn", "tcp_keep_alive", "ssl_harden", // force reconnect "experiments", "debug", "protocol", // force reconnect "auth_plain", "auth_login", "auth_ntlm", "auth_sasl", // force reconnect "exact_alarms" // force schedule diff --git a/app/src/main/res/layout/fragment_options_connection.xml b/app/src/main/res/layout/fragment_options_connection.xml index 3086822633..3303bbe295 100644 --- a/app/src/main/res/layout/fragment_options_connection.xml +++ b/app/src/main/res/layout/fragment_options_connection.xml @@ -319,6 +319,18 @@ app:layout_constraintTop_toBottomOf="@id/etTimeout" app:switchPadding="12dp" /> + + Require a validated (checked) connection Connection timeout (seconds) Prefer IPv4 over IPv6 + Bind sockets to the active network Standalone VPN TCP keep alive Harden SSL connections