commit 74fce069df64b5cd35003c8bad75cc0f0a2622d2 Author: n8fr8 nathan@guardianproject.info Date: Wed Aug 12 14:53:24 2020 -0400
update jtorctl to 0.4 and add more tor DataDirectory corruption debug capabilties --- .../org/torproject/android/OrbotMainActivity.java | 29 ++++++ orbotservice/src/main/AndroidManifest.xml | 2 + .../torproject/android/service/OrbotService.java | 112 +++++++++++++++------ .../android/service/TorEventHandler.java | 22 ++-- .../org/torproject/android/service/util/Utils.java | 92 ++++++++++++++++- 5 files changed, 218 insertions(+), 39 deletions(-)
diff --git a/app/src/main/java/org/torproject/android/OrbotMainActivity.java b/app/src/main/java/org/torproject/android/OrbotMainActivity.java index 1d2e1493..af311c34 100644 --- a/app/src/main/java/org/torproject/android/OrbotMainActivity.java +++ b/app/src/main/java/org/torproject/android/OrbotMainActivity.java @@ -5,6 +5,7 @@ package org.torproject.android;
import android.app.AlertDialog;
+import android.app.Application; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; @@ -19,7 +20,9 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.net.VpnService; +import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; import android.os.Message; import android.text.TextUtils; @@ -39,6 +42,7 @@ import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast;
+import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.Toolbar; @@ -54,6 +58,7 @@ import org.torproject.android.service.OrbotConstants; import org.torproject.android.service.OrbotService; import org.torproject.android.service.TorServiceConstants; import org.torproject.android.service.util.Prefs; +import org.torproject.android.service.util.Utils; import org.torproject.android.service.vpn.VpnConstants; import org.torproject.android.service.vpn.VpnPrefs; import org.torproject.android.service.vpn.VpnUtils; @@ -77,6 +82,7 @@ import java.net.URLDecoder; import java.net.URLEncoder; import java.text.NumberFormat; import java.util.ArrayList; +import java.util.Date; import java.util.Locale; import java.util.StringTokenizer;
@@ -89,6 +95,7 @@ import static org.torproject.android.MainConstants.URL_TOR_CHECK; 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_VPN; +import static org.torproject.android.service.TorServiceConstants.DIRECTORY_TOR_DATA; import static org.torproject.android.service.vpn.VpnPrefs.PREFS_KEY_TORIFIED;
public class OrbotMainActivity extends AppCompatActivity implements OrbotConstants { @@ -198,6 +205,11 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan VpnUtils.getSharedPrefs(getApplicationContext()).edit().putInt(VpnPrefs.PREFS_DNS_PORT, VpnConstants.TOR_DNS_PORT_DEFAULT).apply();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (Prefs.useDebugLogging()) + exportTorData(); + } + }
private void sendIntentToService(final String action) { @@ -1250,4 +1262,21 @@ public class OrbotMainActivity extends AppCompatActivity implements OrbotConstan llBoxShortcuts.addView(tv); }
+ @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void exportTorData () + { + File fileTorData = null; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + fileTorData = new File(getDataDir(),DIRECTORY_TOR_DATA); + } + else { + fileTorData = getDir(DIRECTORY_TOR_DATA, Application.MODE_PRIVATE); + } + + File fileZip = new File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS),"orbotdata" + new Date().getTime() + ".zip"); + Utils.zipFileAtPath(fileTorData.getAbsolutePath(), fileZip.getAbsolutePath()); + fileZip.setReadable(true,false); + Log.d (TAG,"debugdata: " + fileZip.getAbsolutePath()); + + } } diff --git a/orbotservice/src/main/AndroidManifest.xml b/orbotservice/src/main/AndroidManifest.xml index 801a9c18..962fe09c 100644 --- a/orbotservice/src/main/AndroidManifest.xml +++ b/orbotservice/src/main/AndroidManifest.xml @@ -1,4 +1,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.torproject.android.service"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + </manifest> 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 7bf6ade0..a3aa2d98 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java +++ b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java @@ -28,6 +28,8 @@ import android.database.Cursor; import android.net.Uri; import android.net.VpnService; import android.os.Build; +import android.os.Environment; +import android.os.Handler; import android.os.IBinder; import android.provider.BaseColumns; import androidx.annotation.RequiresApi; @@ -39,8 +41,10 @@ import android.util.Log; import com.jaredrummler.android.shell.CommandResult;
import net.freehaven.tor.control.ConfigEntry; +import net.freehaven.tor.control.RawEventListener; import net.freehaven.tor.control.TorControlConnection;
+import org.apache.commons.io.FileUtils; import org.torproject.android.service.util.CustomShell; import org.torproject.android.service.util.CustomTorResourceInstaller; import org.torproject.android.service.util.DummyActivity; @@ -66,9 +70,12 @@ import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -133,6 +140,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
OrbotVpnManager mVpnManager;
+ Handler mHandler; + public static final class HiddenService implements BaseColumns { public static final String NAME = "name"; public static final String PORT = "port"; @@ -174,10 +183,12 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
public void debug(String msg) { + + Log.d(OrbotConstants.TAG,msg); + if (Prefs.useDebugLogging()) { - Log.d(OrbotConstants.TAG,msg); - sendCallbackLogMessage(msg); + sendCallbackLogMessage(msg);
} } @@ -535,6 +546,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
try { + mHandler = new Handler(); + appBinHome = getFilesDir();//getDir(TorServiceConstants.DIRECTORY_TOR_BINARY, Application.MODE_PRIVATE); if (!appBinHome.exists()) appBinHome.mkdirs(); @@ -549,6 +562,20 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb if (!appCacheHome.exists()) appCacheHome.mkdirs();
+ + debug("listing files in DataDirectory: " + appCacheHome.getAbsolutePath()); + Iterator<File> files = FileUtils.iterateFiles(appCacheHome,null,true); + while (files.hasNext()) + { + File fileNext = files.next(); + debug(fileNext.getAbsolutePath() + + " length=" + fileNext.length() + + " rw=" + fileNext.canRead() + "/" + fileNext.canWrite() + + " lastMod=" + new Date(fileNext.lastModified()).toLocaleString() + + ); + } + fileTorRc = new File(appBinHome, TORRC_ASSET_KEY); fileControlPort = new File(getFilesDir(), TOR_CONTROL_PORT_FILE); filePid = new File(getFilesDir(), TOR_PID_FILE); @@ -680,8 +707,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
extraLines.append("PidFile").append(' ').append(filePid.getCanonicalPath()).append('\n');
- //extraLines.append("RunAsDaemon 1").append('\n'); - //extraLines.append("AvoidDiskWrites 1").append('\n'); + extraLines.append("RunAsDaemon 1").append('\n'); + extraLines.append("AvoidDiskWrites 1").append('\n');
String socksPortPref = prefs.getString(OrbotConstants.PREF_SOCKS, (TorServiceConstants.SOCKS_PROXY_PORT_DEFAULT));
@@ -756,8 +783,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb extraLines.append("VirtualAddrNetwork 10.192.0.0/10").append('\n'); extraLines.append("AutomapHostsOnResolve 1").append('\n');
- extraLines.append("DormantClientTimeout 10 minutes").append('\n'); - extraLines.append("DormantOnFirstStartup 0").append('\n'); + // extraLines.append("DormantClientTimeout 10 minutes").append('\n'); + // extraLines.append("DormantOnFirstStartup 0").append('\n');
extraLines.append("DisableNetwork 0").append('\n');
@@ -992,10 +1019,10 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
sendCallbackLogMessage(getString(R.string.status_starting_up));
- String torCmdString = fileTor.getCanonicalPath() - + " DataDirectory " + appCacheHome.getCanonicalPath() - + " --defaults-torrc " + fileTorRc.getCanonicalPath() - + " -f " + fileTorrcCustom.getCanonicalPath(); + String torCmdString = fileTor.getAbsolutePath() + + " DataDirectory " + appCacheHome.getAbsolutePath() + + " --defaults-torrc " + fileTorRc.getAbsolutePath() + + " -f " + fileTorrcCustom.getAbsolutePath();
int exitCode = -1;
@@ -1122,16 +1149,42 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb if (fileCookie.exists()) {
+ // We extend NullEventHandler so that we don't need to provide empty + // implementations for all the events we don't care about. + logNotice( "adding control port event handler"); + + if (Prefs.useDebugLogging()) { + conn.setDebugging(System.out); + conn.addRawEventListener(new RawEventListener() { + @Override + public void onEvent(String keyword, String data) { + + + debug(keyword + ": " + data); + } + }); + } + + conn.setEventHandler(mEventHandler); + + logNotice( "SUCCESS added control port event handler"); byte[] cookie = new byte[(int)fileCookie.length()]; DataInputStream fis = new DataInputStream(new FileInputStream(fileCookie)); fis.read(cookie); fis.close(); conn.authenticate(cookie);
- addEventHandler(); - logNotice( "SUCCESS - authenticated to control port.");
+ // conn.setEvents(Arrays.asList(new String[]{"DEBUG","STATUS_CLIENT","STATUS_GENERAL","BW"})); + + if (Prefs.useDebugLogging()) + conn.setEvents(Arrays.asList(new String[]{ + "CIRC","STREAM", "ORCONN" , "BW" , "INFO" ,"NOTICE" , "WARN" , "DEBUG","ERR" , "NEWDESC" , "ADDRMAP"})); + else + conn.setEvents(Arrays.asList(new String[]{ + "CIRC","STREAM", "ORCONN" , "BW" , "NOTICE" ,"ERR" , "NEWDESC" , "ADDRMAP"})); + // sendCallbackLogMessage(getString(R.string.tor_process_starting) + ' ' + getString(R.string.tor_process_complete));
String torProcId = conn.getInfo("process/pid"); @@ -1169,6 +1222,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb
sendCallbackPorts(mPortSOCKS, mPortHTTP, mPortDns, mPortTrans);
+ setTorNetworkEnabled(true);
return Integer.parseInt(torProcId);
@@ -1221,20 +1275,6 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb return result; }
- 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. - // ... - logNotice( "adding control port event handler"); - - - conn.setEvents(Arrays.asList(new String[]{ - "CIRC","STREAM", "ORCONN" , "BW" , "INFO" ,"NOTICE" , "WARN" , "ERR" , "NEWDESC" , "ADDRMAP"})); - - conn.setEventHandler(mEventHandler); - - logNotice( "SUCCESS added control port event handler"); - }
/** * Returns the port number that the HTTP proxy is running on @@ -1453,15 +1493,23 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb LocalBroadcastManager.getInstance(this).sendBroadcast(intent); }
- private void sendCallbackLogMessage (String logMessage) + private void sendCallbackLogMessage (final String logMessage) {
- Intent intent = new Intent(LOCAL_ACTION_LOG); - // You can also include some extra data. - intent.putExtra(LOCAL_EXTRA_LOG, logMessage); - intent.putExtra(EXTRA_STATUS, mCurrentStatus); + mHandler.post(new Runnable () { + + public void run () + { + + Intent intent = new Intent(LOCAL_ACTION_LOG); + // You can also include some extra data. + intent.putExtra(LOCAL_EXTRA_LOG, logMessage); + intent.putExtra(EXTRA_STATUS, mCurrentStatus); + + LocalBroadcastManager.getInstance(OrbotService.this).sendBroadcast(intent); + }
- LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + });
}
diff --git a/orbotservice/src/main/java/org/torproject/android/service/TorEventHandler.java b/orbotservice/src/main/java/org/torproject/android/service/TorEventHandler.java index ce7a6633..7cebd794 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/TorEventHandler.java +++ b/orbotservice/src/main/java/org/torproject/android/service/TorEventHandler.java @@ -57,7 +57,11 @@ public class TorEventHandler implements EventHandler, TorServiceConstants {
@Override public void message(String severity, String msg) { - mService.logNotice(severity + ": " + msg); + + if (severity.equalsIgnoreCase("debug")) + mService.debug(severity + ": " + msg); + else + mService.logNotice(severity + ": " + msg); }
@Override @@ -89,7 +93,7 @@ public class TorEventHandler implements EventHandler, TorServiceConstants { sb.append("): "); sb.append(status);
- mService.logNotice(sb.toString()); + mService.debug(sb.toString()); }
@Override @@ -104,10 +108,12 @@ public class TorEventHandler implements EventHandler, TorServiceConstants { mService.logNotice(sb.toString()); }
+ private final static int BW_THRESDHOLD = 10000; + @Override public void bandwidthUsed(long read, long written) {
- if (read != lastRead || written != lastWritten) + if (lastWritten > BW_THRESDHOLD || lastRead > BW_THRESDHOLD) { StringBuilder sb = new StringBuilder(); sb.append(formatCount(read)); @@ -125,12 +131,16 @@ public class TorEventHandler implements EventHandler, TorServiceConstants {
mTotalTrafficWritten += written; mTotalTrafficRead += read; + + mService.sendCallbackBandwidth(lastWritten, lastRead, mTotalTrafficWritten, mTotalTrafficRead); + + lastWritten = 0; + lastRead = 0; }
- lastWritten = written; - lastRead = read; + lastWritten += written; + lastRead += read;
- mService.sendCallbackBandwidth(lastWritten, lastRead, mTotalTrafficWritten, mTotalTrafficRead); }
private String formatCount(long count) { diff --git a/orbotservice/src/main/java/org/torproject/android/service/util/Utils.java b/orbotservice/src/main/java/org/torproject/android/service/util/Utils.java index 0fac4019..e6e203e3 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/util/Utils.java +++ b/orbotservice/src/main/java/org/torproject/android/service/util/Utils.java @@ -4,13 +4,19 @@
package org.torproject.android.service.util;
+import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream;
public class Utils {
@@ -94,7 +100,91 @@ public class Utils { } -
+ /* + * + * Zips a file at a location and places the resulting zip file at the toLocation + * Example: zipFileAtPath("downloads/myfolder", "downloads/myFolder.zip"); + */ + + public static boolean zipFileAtPath(String sourcePath, String toLocation) { + final int BUFFER = 2048; + + File sourceFile = new File(sourcePath); + try { + BufferedInputStream origin = null; + FileOutputStream dest = new FileOutputStream(toLocation); + ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream( + dest)); + if (sourceFile.isDirectory()) { + zipSubFolder(out, sourceFile, sourceFile.getParent().length()); + } else { + byte data[] = new byte[BUFFER]; + FileInputStream fi = new FileInputStream(sourcePath); + origin = new BufferedInputStream(fi, BUFFER); + ZipEntry entry = new ZipEntry(getLastPathComponent(sourcePath)); + entry.setTime(sourceFile.lastModified()); // to keep modification time after unzipping + out.putNextEntry(entry); + int count; + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + } + } + out.close(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /* + * + * Zips a subfolder + * + */ + + private static void zipSubFolder(ZipOutputStream out, File folder, + int basePathLength) throws IOException { + + final int BUFFER = 2048; + + File[] fileList = folder.listFiles(); + BufferedInputStream origin = null; + for (File file : fileList) { + if (file.isDirectory()) { + zipSubFolder(out, file, basePathLength); + } else { + byte data[] = new byte[BUFFER]; + String unmodifiedFilePath = file.getPath(); + String relativePath = unmodifiedFilePath + .substring(basePathLength); + FileInputStream fi = new FileInputStream(unmodifiedFilePath); + origin = new BufferedInputStream(fi, BUFFER); + ZipEntry entry = new ZipEntry(relativePath); + entry.setTime(file.lastModified()); // to keep modification time after unzipping + out.putNextEntry(entry); + int count; + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + } + origin.close(); + } + } + } + + /* + * gets the last path component + * + * Example: getLastPathComponent("downloads/example/fileToZip"); + * Result: "fileToZip" + */ + public static String getLastPathComponent(String filePath) { + String[] segments = filePath.split("/"); + if (segments.length == 0) + return ""; + String lastPathComponent = segments[segments.length - 1]; + return lastPathComponent; + } }
tor-commits@lists.torproject.org