From f8b1fceb35d037b4d52a33e4bf381e4edcc36cbe Mon Sep 17 00:00:00 2001 From: bim Date: Fri, 22 May 2020 17:41:52 -0400 Subject: [PATCH 1/2] Fixes #329 Tor Wont Fully Stop With VPN Enabled Before the Intnet to stop OrbotService is fired off, the service needs to close the tun2socks interface if it was running for OrbotService to gracefully be destroyed. --- .../torproject/android/OrbotMainActivity.java | 53 +++----- .../android/service/OrbotService.java | 37 ++---- .../android/service/vpn/OrbotVpnManager.java | 123 ++++-------------- 3 files changed, 55 insertions(+), 158 deletions(-) diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java index 7c4528d53..ec7db2baf 100644 --- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java +++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java @@ -31,7 +31,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.View.OnLongClickListener; import android.view.animation.AccelerateInterpolator; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; @@ -61,6 +60,7 @@ import org.torproject.android.service.util.Prefs; import org.torproject.android.service.vpn.VpnConstants; import org.torproject.android.service.vpn.VpnPrefs; +import org.torproject.android.service.vpn.VpnUtils; import org.torproject.android.settings.Languages; import org.torproject.android.settings.LocaleHelper; import org.torproject.android.settings.SettingsPreferences; @@ -96,10 +96,8 @@ import static org.torproject.android.service.TorServiceConstants.ACTION_START_VPN; import static org.torproject.android.service.TorServiceConstants.ACTION_STOP_VPN; import static org.torproject.android.service.vpn.VpnPrefs.PREFS_KEY_TORIFIED; -import static org.torproject.android.service.vpn.VpnUtils.getSharedPrefs; -public class OrbotMainActivity extends AppCompatActivity - implements OrbotConstants, OnLongClickListener { +public class OrbotMainActivity extends AppCompatActivity implements OrbotConstants { /* Useful UI bits */ private TextView lblStatus = null; //the main text display widget @@ -203,7 +201,7 @@ public void onCreate(Bundle savedInstanceState) { } // Resets previous DNS Port to the default. - getSharedPrefs(getApplicationContext()).edit().putInt(VpnPrefs.PREFS_DNS_PORT, + VpnUtils.getSharedPrefs(getApplicationContext()).edit().putInt(VpnPrefs.PREFS_DNS_PORT, VpnConstants.TOR_DNS_PORT_DEFAULT).apply(); } @@ -215,9 +213,7 @@ private void sendIntentToService(final String action) { } private void stopTor() { - -// requestTorStatus(); - + if (mBtnVPN.isChecked()) mBtnVPN.setChecked(false); // indirectly closes tun2socks interface Intent intent = new Intent(OrbotMainActivity.this, OrbotService.class); stopService(intent); @@ -309,7 +305,13 @@ public void onClick(View v) { lblPorts = findViewById(R.id.lblPorts); imgStatus = findViewById(R.id.imgStatus); - imgStatus.setOnLongClickListener(this); + imgStatus.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + toggleTor(); + return true; + } + }); downloadText = findViewById(R.id.trafficDown); uploadText = findViewById(R.id.trafficUp); @@ -322,14 +324,7 @@ public void onClick(View v) { mBtnStart.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - - if (torStatus.equals(TorServiceConstants.STATUS_OFF)) { - lblStatus.setText(getString(R.string.status_starting_up)); - startTor(); - } else { - lblStatus.setText(getString(R.string.status_shutting_down)); - stopTor(); - } + toggleTor(); } }); @@ -367,7 +362,16 @@ public void onClick(View v) { setCountrySpinner(); mPulsator = findViewById(R.id.pulsator); + } + private void toggleTor() { // UI entry point for (dis)connecting to Tor + if (torStatus.equals(TorServiceConstants.STATUS_OFF)) { + lblStatus.setText(getString(R.string.status_starting_up)); + startTor(); + } else { + lblStatus.setText(getString(R.string.status_shutting_down)); + stopTor(); + } } private void setCountrySpinner() { @@ -885,7 +889,6 @@ else if (request == REQUEST_VPN && response == RESULT_OK) { } else if (request == REQUEST_VPN && response == RESULT_CANCELED) { mBtnVPN.setChecked(false); - Prefs.putUseVpn(false); } IntentResult scanResult = IntentIntegrator.parseActivityResult(request, response, data); @@ -1136,20 +1139,6 @@ private boolean isTorServiceRunning() { return false; } - public boolean onLongClick(View view) { - - if (torStatus.equals(TorServiceConstants.STATUS_OFF)) { - lblStatus.setText(getString(R.string.status_starting_up)); - startTor(); - } else { - lblStatus.setText(getString(R.string.status_shutting_down)); - - stopTor(); - } - - return true; - - } // this is what takes messages or values from the callback threads or other non-mainUI threads //and passes them back into the main UI thread for display to the user diff --git a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java index 9ecd9c963..d2d0eb673 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java +++ b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java @@ -28,9 +28,7 @@ import android.net.Uri; import android.net.VpnService; import android.os.Build; -import android.os.Debug; import android.os.IBinder; -import android.os.RemoteException; import android.provider.BaseColumns; import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; @@ -1198,20 +1196,16 @@ private int initControlConnection (int maxTries, boolean isReconnect) throws Exc } - private int getControlPort () - { + private int getControlPort () { int result = -1; - try - { - if (fileControlPort.exists()) - { + try { + if (fileControlPort.exists()) { debug("Reading control port config file: " + fileControlPort.getCanonicalPath()); BufferedReader bufferedReader = new BufferedReader(new FileReader(fileControlPort)); String line = bufferedReader.readLine(); - if (line != null) - { + if (line != null) { String[] lineParts = line.split(":"); result = Integer.parseInt(lineParts[1]); } @@ -1222,30 +1216,22 @@ private int getControlPort () //store last valid control port SharedPreferences prefs = Prefs.getSharedPrefs(getApplicationContext()); prefs.edit().putInt("controlport", result).commit(); - } - else - { + else { debug("Control Port config file does not yet exist (waiting for tor): " + fileControlPort.getCanonicalPath()); - } - - } - catch (FileNotFoundException e) - { + catch (FileNotFoundException e) { debug("unable to get control port; file not found"); } - catch (Exception e) - { + catch (Exception e) { debug("unable to read control port config file"); } return result; } - public void addEventHandler () throws Exception - { + public void addEventHandler () throws Exception { // We extend NullEventHandler so that we don't need to provide empty // implementations for all the events we don't care about. // ... @@ -1258,14 +1244,12 @@ public void addEventHandler () throws Exception conn.setEventHandler(mEventHandler); logNotice( "SUCCESS added control port event handler"); - - } /** * Returns the port number that the HTTP proxy is running on */ - public int getHTTPPort() throws RemoteException { + public int getHTTPPort() { return mPortHTTP; } @@ -1273,11 +1257,10 @@ public int getHTTPPort() throws RemoteException { /** * Returns the port number that the HTTP proxy is running on */ - public int getSOCKSPort() throws RemoteException { + public int getSOCKSPort() { return mPortSOCKS; } - public String getInfo (String key) { try { if(conn !=null){ diff --git a/orbotservice/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java b/orbotservice/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java index 81e8f1a05..5194e5c38 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java +++ b/orbotservice/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java @@ -17,14 +17,12 @@ package org.torproject.android.service.vpn; import android.annotation.TargetApi; -import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; import android.net.VpnService; -import android.net.VpnService.Builder; import android.os.Build; import android.os.Handler; import android.os.Message; @@ -56,16 +54,11 @@ import static org.torproject.android.service.TorServiceConstants.ACTION_START; import static org.torproject.android.service.TorServiceConstants.ACTION_START_VPN; -import static org.torproject.android.service.TorServiceConstants.ACTION_STOP; import static org.torproject.android.service.TorServiceConstants.ACTION_STOP_VPN; -import static org.torproject.android.service.vpn.VpnUtils.getSharedPrefs; -import static org.torproject.android.service.vpn.VpnUtils.killProcess; public class OrbotVpnManager implements Handler.Callback { private static final String TAG = "OrbotVpnService"; - private PendingIntent mConfigureIntent; - private Thread mThreadVPN; private String mSessionName = "OrbotVPN"; @@ -91,30 +84,19 @@ public class OrbotVpnManager implements Handler.Callback { private VpnService mService; - private Builder mLastBuilder; - public OrbotVpnManager (VpnService service) throws IOException, TimeoutException { mService = service; - - filePdnsd = CustomNativeLoader.loadNativeBinary(service.getApplicationContext(),PDNSD_BIN,new File(service.getFilesDir(),PDNSD_BIN)); - - Tun2Socks.init(); - - } boolean isStarted = false; - public int handleIntent(Builder builder, Intent intent) { - - if (intent != null) - { + public int handleIntent(VpnService.Builder builder, Intent intent) { + if (intent != null) { String action = intent.getAction(); - if (action.equals(ACTION_START_VPN)||action.equals(ACTION_START)) - { + if (action.equals(ACTION_START_VPN)||action.equals(ACTION_START)) { Log.d(TAG,"starting VPN"); isStarted = true; @@ -123,8 +105,6 @@ public int handleIntent(Builder builder, Intent intent) { if (mThreadVPN != null && mThreadVPN.isAlive()) stopVPN(); - mLastBuilder = builder; - if (mTorSocks != -1) { if (!mIsLollipop) @@ -135,19 +115,15 @@ public int handleIntent(Builder builder, Intent intent) { setupTun2Socks(builder); } - - } - else if (action.equals(ACTION_STOP_VPN)) - { + else if (action.equals(ACTION_STOP_VPN)) { isStarted = false; Log.d(TAG,"stopping VPN"); stopVPN(); } - else if (action.equals(TorServiceConstants.LOCAL_ACTION_PORTS)) - { + else if (action.equals(TorServiceConstants.LOCAL_ACTION_PORTS)) { Log.d(TAG,"setting VPN ports"); int torSocks = intent.getIntExtra(OrbotService.EXTRA_SOCKS_PROXY_PORT,-1); @@ -174,14 +150,9 @@ else if (action.equals(TorServiceConstants.LOCAL_ACTION_PORTS)) return Service.START_STICKY; } - private void startSocksBypass() - { - - new Thread () - { - - public void run () - { + private void startSocksBypass() { + new Thread () { + public void run () { //generate the proxy port that the if (sSocksProxyServerPort == -1) @@ -218,22 +189,16 @@ public void run () } } }.start(); - } - private synchronized void stopSocksBypass () - { - - if (mSocksProxyServer != null){ + private synchronized void stopSocksBypass () { + if (mSocksProxyServer != null) { mSocksProxyServer.stop(); mSocksProxyServer = null; } - - } - private void stopVPN () - { + private void stopVPN () { if (mIsLollipop) stopSocksBypass (); @@ -257,13 +222,8 @@ private void stopVPN () Log.d(TAG,"error stopping tun2socks",e); } } - - stopDns(); - mThreadVPN = null; - - } @Override @@ -275,9 +235,7 @@ public boolean handleMessage(Message message) { } - private synchronized void setupTun2Socks(final Builder builder) { - - + private synchronized void setupTun2Socks(final VpnService.Builder builder) { if (mInterface != null) //stop tun2socks now to give it time to clean up { isRestart = true; @@ -290,13 +248,10 @@ private synchronized void setupTun2Socks(final Builder builder) { mThreadVPN = new Thread () { - public void run () - { - try - { + public void run () { + try { - if (isRestart) - { + if (isRestart) { Log.d(TAG,"is a restart... let's wait for a few seconds"); Thread.sleep(3000); } @@ -332,7 +287,7 @@ public void run () // Create a new interface using the builder and save the parameters. ParcelFileDescriptor newInterface = builder.setSession(mSessionName) - .setConfigureIntent(mConfigureIntent) + .setConfigureIntent(null) // previously this was set to a null member variable .establish(); if (mInterface != null) @@ -371,12 +326,10 @@ public void run () @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void doLollipopAppRouting (Builder builder) throws NameNotFoundException - { - - ArrayList apps = TorifiedApp.getApps(mService, getSharedPrefs(mService.getApplicationContext())); + private void doLollipopAppRouting (VpnService.Builder builder) throws NameNotFoundException { + SharedPreferences prefs = VpnUtils.getSharedPrefs(mService.getApplicationContext()); + ArrayList apps = TorifiedApp.getApps(mService, prefs); - SharedPreferences prefs = getSharedPrefs(mService.getApplicationContext()); boolean perAppEnabled = false; @@ -400,26 +353,7 @@ private void doLollipopAppRouting (Builder builder) throws NameNotFoundException } - - public void onRevoke() { - - Log.w(TAG,"VPNService REVOKED!"); - - if (!isRestart) - { - SharedPreferences prefs = getSharedPrefs(mService.getApplicationContext()); - prefs.edit().putBoolean("pref_vpn", false).commit(); - stopVPN(); - } - - isRestart = false; - - //super.onRevoke(); - - } - - private void startDNS (String pdnsPath, String torDnsHost, int torDnsPort, String pdnsdHost, int pdnsdPort) throws IOException, TimeoutException - { + private void startDNS (String pdnsPath, String torDnsHost, int torDnsPort, String pdnsdHost, int pdnsdPort) throws IOException, TimeoutException { File fileConf = makePdnsdConf(mService, mService.getFilesDir(), torDnsHost, torDnsPort, pdnsdHost, pdnsdPort); @@ -446,23 +380,20 @@ private void startDNS (String pdnsPath, String torDnsHost, int torDnsPort, Strin File filePdnsPid; - private boolean stopDns () - { + private boolean stopDns () { if (filePdnsPid != null && filePdnsPid.exists()) { List lines = null; try { lines = IOUtils.readLines(new FileReader(filePdnsPid)); String dnsPid = lines.get(0); - killProcess(dnsPid, ""); + VpnUtils.killProcess(dnsPid, ""); filePdnsPid.delete(); filePdnsPid = null; } catch (Exception e) { Log.e("OrbotVPN", "error killing dns process", e); } } - return false; - } public static File makePdnsdConf(Context context, File fileDir, String torDnsHost, int torDnsPort, String pdnsdHost, int pdnsdPort) throws FileNotFoundException, IOException { @@ -486,18 +417,12 @@ public static File makePdnsdConf(Context context, File fileDir, String torDnsHo if (!cache.exists()) { try { cache.createNewFile(); - } catch (Exception e) { - - } + } catch (Exception e) { } } - return fPid; } - public boolean isStarted () - { + public boolean isStarted () { return isStarted; } - - } From b2b92d6b55f20890d28a52fed51a759ae4371ef1 Mon Sep 17 00:00:00 2001 From: n8fr8 Date: Sat, 30 May 2020 06:29:43 -0400 Subject: [PATCH 2/2] leave VPN toggle enabled, just stop the service --- .../main/java/org/torproject/android/OrbotMainActivity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java index 61e4b4f27..328476a9f 100644 --- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java +++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java @@ -210,10 +210,12 @@ private void sendIntentToService(final String action) { } private void stopTor() { - if (mBtnVPN.isChecked()) mBtnVPN.setChecked(false); // indirectly closes tun2socks interface + if (mBtnVPN.isChecked()) sendIntentToService(ACTION_STOP_VPN); + Intent intent = new Intent(OrbotMainActivity.this, OrbotService.class); stopService(intent); + } /**