Improved transproxy code for background service

svn:r24645
This commit is contained in:
Nathan Freitas 2011-04-17 06:04:27 +00:00
parent 79179e28d9
commit 0c60572ef6
6 changed files with 477 additions and 346 deletions

View File

@ -801,23 +801,29 @@ public final class Api {
boolean changed = false; boolean changed = false;
try { try {
// Check iptables_g1 // Check iptables_g1
File file = new File(ctx.getDir("bin",0), "iptables_g1"); File file = new File(ctx.getDir("bin",0), "iptables");
if ((!file.exists()) && isARMv6()) { if ((!file.exists()) && isARMv6()) {
copyRawFile(ctx, R.raw.iptables_g1, file, "755"); copyRawFile(ctx, R.raw.iptables_g1, file, "755");
changed = true; changed = true;
} }
// Check iptables_n1 // Check iptables_n1
file = new File(ctx.getDir("bin",0), "iptables_n1"); file = new File(ctx.getDir("bin",0), "iptables");
if ((!file.exists()) && (!isARMv6())) { if ((!file.exists()) && (!isARMv6())) {
copyRawFile(ctx, R.raw.iptables_n1, file, "755"); copyRawFile(ctx, R.raw.iptables_n1, file, "755");
changed = true; changed = true;
} }
// Check busybox // Check busybox
/*
file = new File(ctx.getDir("bin",0), "busybox_g1"); file = new File(ctx.getDir("bin",0), "busybox_g1");
if (!file.exists()) { if (!file.exists()) {
copyRawFile(ctx, R.raw.busybox_g1, file, "755"); copyRawFile(ctx, R.raw.busybox_g1, file, "755");
changed = true; changed = true;
} }
*/
if (changed) { if (changed) {
Toast.makeText(ctx, R.string.status_install_success, Toast.LENGTH_LONG).show(); Toast.makeText(ctx, R.string.status_install_success, Toast.LENGTH_LONG).show();
} }

View File

@ -38,6 +38,11 @@ interface ITorService {
**/ **/
boolean updateConfiguration (String name, String value, boolean saveToDisk); boolean updateConfiguration (String name, String value, boolean saveToDisk);
/**
* Set configuration
**/
void processSettings();
/** /**
* Set configuration * Set configuration
**/ **/

View File

@ -4,6 +4,7 @@ package org.torproject.android.service;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
@ -18,8 +19,10 @@ import net.freehaven.tor.control.TorControlConnection;
import org.torproject.android.AppManager; import org.torproject.android.AppManager;
import org.torproject.android.Orbot; import org.torproject.android.Orbot;
import org.torproject.android.ProcessSettingsAsyncTask;
import org.torproject.android.R; import org.torproject.android.R;
import org.torproject.android.TorConstants; import org.torproject.android.TorConstants;
import org.torproject.android.Utils;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Notification; import android.app.Notification;
@ -31,6 +34,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteCallbackList; import android.os.RemoteCallbackList;
import android.os.RemoteException; import android.os.RemoteException;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@ -39,6 +43,7 @@ import android.util.Log;
public class TorService extends Service implements TorServiceConstants, Runnable, EventHandler public class TorService extends Service implements TorServiceConstants, Runnable, EventHandler
{ {
private static boolean ENABLE_DEBUG_LOG = false;
private static int currentStatus = STATUS_READY; private static int currentStatus = STATUS_READY;
@ -48,6 +53,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
private static TorService _torInstance; private static TorService _torInstance;
private static final int NOTIFY_ID = 1; private static final int NOTIFY_ID = 1;
private static int NOTIFY_ID_ERROR = 2;
private static final int MAX_START_TRIES = 3; private static final int MAX_START_TRIES = 3;
@ -69,10 +75,22 @@ public class TorService extends Service implements TorServiceConstants, Runnable
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
Log.i(TAG, "serviced created"); logMessage("serviced created");
} }
public static void logMessage(String msg)
{
if (ENABLE_DEBUG_LOG)
Log.d(TAG,msg);
}
public static void logException(String msg, Exception e)
{
if (ENABLE_DEBUG_LOG)
Log.e(TAG,msg,e);
}
private boolean findExistingProc () private boolean findExistingProc ()
{ {
@ -96,12 +114,11 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.d(TAG,"Unable to connect to existing Tor instance,",e); Log.d(TAG,"Unable to connect to existing Tor instance,",e);
currentStatus = STATUS_OFF; currentStatus = STATUS_OFF;
this.stopTor();
} catch (Exception e) { } catch (Exception e) {
Log.d(TAG,"Unable to connect to existing Tor instance,",e); Log.d(TAG,"Unable to connect to existing Tor instance,",e);
currentStatus = STATUS_OFF; currentStatus = STATUS_OFF;
this.stopTor();
} }
} }
@ -144,7 +161,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} }
private void showToolbarNotification (String notifyMsg, int icon) private void showToolbarNotification (String notifyMsg, int notifyId, int icon)
{ {
@ -166,7 +183,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
mNotificationManager.notify(NOTIFY_ID, notification); mNotificationManager.notify(notifyId, notification);
} }
@ -196,7 +213,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} catch (Exception e) { } catch (Exception e) {
logNotice("unable to find tor binaries: " + e.getMessage()); logNotice("unable to find tor binaries: " + e.getMessage());
showToolbarNotification(e.getMessage(), R.drawable.tornotificationoff); showToolbarNotification(e.getMessage(), NOTIFY_ID_ERROR, R.drawable.tornotificationoff);
Log.e(TAG, "error checking tor binaries", e); Log.e(TAG, "error checking tor binaries", e);
} }
@ -226,13 +243,12 @@ public class TorService extends Service implements TorServiceConstants, Runnable
try try
{ {
initTor(); initTor();
isRunning = true;
} }
catch (Exception e) catch (Exception e)
{ {
currentStatus = STATUS_OFF; currentStatus = STATUS_OFF;
this.showToolbarNotification(getString(R.string.status_disabled), R.drawable.tornotification); this.showToolbarNotification(getString(R.string.status_disabled), NOTIFY_ID_ERROR, R.drawable.tornotification);
Log.d(TAG,"Unable to start Tor: " + e.getMessage(),e); Log.d(TAG,"Unable to start Tor: " + e.getMessage(),e);
} }
} }
@ -243,10 +259,11 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
super.onDestroy(); super.onDestroy();
Log.d(TAG,"onDestroy called");
// Unregister all callbacks. // Unregister all callbacks.
mCallbacks.kill(); mCallbacks.kill();
stopTor();
} }
private void stopTor () private void stopTor ()
@ -259,7 +276,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
currentStatus = STATUS_READY; currentStatus = STATUS_READY;
showToolbarNotification (getString(R.string.status_disabled),R.drawable.tornotificationoff); showToolbarNotification (getString(R.string.status_disabled),NOTIFY_ID,R.drawable.tornotificationoff);
sendCallbackStatusMessage(getString(R.string.status_disabled)); sendCallbackStatusMessage(getString(R.string.status_disabled));
setupTransProxy(false); setupTransProxy(false);
@ -275,7 +292,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
/*
public void reloadConfig () public void reloadConfig ()
{ {
try try
@ -294,8 +311,212 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
Log.d(TAG,"Unable to reload configuration",e); Log.d(TAG,"Unable to reload configuration",e);
} }
}*/
/*
private void loadTorSettingsFromPreferences () throws RemoteException
{
try
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
ENABLE_DEBUG_LOG = prefs.getBoolean("pref_enable_logging",false);
Log.i(TAG,"debug logging:" + ENABLE_DEBUG_LOG);
boolean useBridges = prefs.getBoolean(TorConstants.PREF_BRIDGES_ENABLED, false);
//boolean autoUpdateBridges = prefs.getBoolean(PREF_BRIDGES_UPDATED, false);
boolean becomeRelay = prefs.getBoolean(TorConstants.PREF_OR, false);
boolean ReachableAddresses = prefs.getBoolean(TorConstants.PREF_REACHABLE_ADDRESSES,false);
boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false);
boolean enableTransparentProxy = prefs.getBoolean(TorConstants.PREF_TRANSPARENT, false);
mBinder.updateTransProxy();
String bridgeList = prefs.getString(TorConstants.PREF_BRIDGES_LIST,"");
if (useBridges)
{
if (bridgeList == null || bridgeList.length() == 0)
{
showAlert("Bridge Error","In order to use the bridge feature, you must enter at least one bridge IP address." +
"Send an email to bridges@torproject.org with the line \"get bridges\" by itself in the body of the mail from a gmail account.");
return;
} }
mBinder.updateConfiguration("UseBridges", "1", false);
String bridgeDelim = "\n";
if (bridgeList.indexOf(",") != -1)
{
bridgeDelim = ",";
}
StringTokenizer st = new StringTokenizer(bridgeList,bridgeDelim);
while (st.hasMoreTokens())
{
mBinder.updateConfiguration("bridge", st.nextToken(), false);
}
mBinder.updateConfiguration("UpdateBridgesFromAuthority", "0", false);
}
else
{
mBinder.updateConfiguration("UseBridges", "0", false);
}
try
{
if (ReachableAddresses)
{
String ReachableAddressesPorts =
prefs.getString(TorConstants.PREF_REACHABLE_ADDRESSES_PORTS, "*:80,*:443");
mBinder.updateConfiguration("ReachableAddresses", ReachableAddressesPorts, false);
}
else
{
mBinder.updateConfiguration("ReachableAddresses", "", false);
}
}
catch (Exception e)
{
showAlert("Config Error","Your ReachableAddresses settings caused an exception!");
}
try
{
if (becomeRelay && (!useBridges) && (!ReachableAddresses))
{
int ORPort = Integer.parseInt(prefs.getString(TorConstants.PREF_OR_PORT, "9001"));
String nickname = prefs.getString(TorConstants.PREF_OR_NICKNAME, "Orbot");
mBinder.updateConfiguration("ORPort", ORPort + "", false);
mBinder.updateConfiguration("Nickname", nickname, false);
mBinder.updateConfiguration("ExitPolicy", "reject *:*", false);
}
else
{
mBinder.updateConfiguration("ORPort", "", false);
mBinder.updateConfiguration("Nickname", "", false);
mBinder.updateConfiguration("ExitPolicy", "", false);
}
}
catch (Exception e)
{
showAlert("Uh-oh!","Your relay settings caused an exception!");
return;
}
if (enableHiddenServices)
{
mBinder.updateConfiguration("HiddenServiceDir","/data/data/org.torproject.android/", false);
String hsPorts = prefs.getString("pref_hs_ports","");
StringTokenizer st = new StringTokenizer (hsPorts,",");
String hsPortConfig = null;
while (st.hasMoreTokens())
{
hsPortConfig = st.nextToken();
if (hsPortConfig.indexOf(":")==-1) //setup the port to localhost if not specifed
{
hsPortConfig = hsPortConfig + " 127.0.0.1:" + hsPortConfig;
}
mBinder.updateConfiguration("HiddenServicePort",hsPortConfig, false);
}
//force save now so the hostname file gets generated
mBinder.saveConfiguration();
String onionHostname = getHiddenServiceHostname();
if (onionHostname != null)
{
Editor pEdit = prefs.edit();
pEdit.putString("pref_hs_hostname",onionHostname);
pEdit.commit();
}
}
else
{
mBinder.updateConfiguration("HiddenServiceDir","", false);
}
mBinder.saveConfiguration();
}
catch (Exception e)
{
showAlert("Uh-oh!","There was an error updating your settings");
Log.w(TAG, "processSettings()", e);
return;
}
}*/
private void getHiddenServiceHostname ()
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false);
if (enableHiddenServices)
{
File file = new File(appDataHome, "hostname");
if (file.exists())
{
try {
String onionHostname = Utils.readString(new FileInputStream(file));
showToolbarNotification("hidden service on: " + onionHostname, NOTIFY_ID_ERROR, R.drawable.tornotification);
Editor pEdit = prefs.edit();
pEdit.putString("pref_hs_hostname",onionHostname);
pEdit.commit();
} catch (FileNotFoundException e) {
logException("unable to read onion hostname file",e);
showToolbarNotification("unable to read hidden service name", NOTIFY_ID_ERROR, R.drawable.tornotification);
return;
}
}
else
{
showToolbarNotification("unable to read hidden service name", NOTIFY_ID_ERROR, R.drawable.tornotification);
}
}
return;
}
private void killTorProcess () throws Exception private void killTorProcess () throws Exception
{ {
//android.os.Debug.waitForDebugger(); //android.os.Debug.waitForDebugger();
@ -348,94 +569,13 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
if (msg != null && msg.trim().length() > 0) if (msg != null && msg.trim().length() > 0)
{ {
if (LOG_OUTPUT_TO_DEBUG) if (ENABLE_DEBUG_LOG)
Log.d(TAG, msg); Log.d(TAG, msg);
sendCallbackLogMessage(msg); sendCallbackLogMessage(msg);
} }
} }
/*
private String findAPK ()
{
String apkBase = "/data/app/";
String APK_EXT = ".apk";
int MAX_TRIES = 10;
String buildPath = apkBase + TOR_APP_USERNAME + APK_EXT;
logNotice("Checking APK location: " + buildPath);
File fileApk = new File(buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
for (int i = 0; i < MAX_TRIES; i++)
{
buildPath = apkBase + TOR_APP_USERNAME + '-' + i + APK_EXT;
fileApk = new File(buildPath);
logNotice( "Checking APK location: " + buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
}
String apkBaseExt = "/mnt/asec/" + TOR_APP_USERNAME;
String pkgFile = "/pkg.apk";
buildPath = apkBaseExt + pkgFile;
fileApk = new File(buildPath);
logNotice( "Checking external storage APK location: " + buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
for (int i = 0; i < MAX_TRIES; i++)
{
buildPath = apkBaseExt + '-' + i + pkgFile;
fileApk = new File(buildPath);
logNotice( "Checking external storage APK location: " + buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
}
apkBase = "/sd-ext/app/";
APK_EXT = ".apk";
MAX_TRIES = 10;
buildPath = apkBase + TOR_APP_USERNAME + APK_EXT;
logNotice("Checking Apps2SD APK location: " + buildPath);
fileApk = new File(buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
for (int i = 0; i < MAX_TRIES; i++)
{
buildPath = apkBase + TOR_APP_USERNAME + '-' + i + APK_EXT;
fileApk = new File(buildPath);
logNotice( "Checking Apps2SD location: " + buildPath);
if (fileApk.exists())
return fileApk.getAbsolutePath();
}
return null;
}*/
private boolean checkTorBinaries () throws Exception private boolean checkTorBinaries () throws Exception
@ -475,7 +615,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
logNotice(getString(R.string.status_install_success)); logNotice(getString(R.string.status_install_success));
showToolbarNotification(getString(R.string.status_install_success), R.drawable.tornotification); showToolbarNotification(getString(R.string.status_install_success), NOTIFY_ID, R.drawable.tornotification);
} }
else else
@ -522,28 +662,98 @@ public class TorService extends Service implements TorServiceConstants, Runnable
killTorProcess (); killTorProcess ();
new Thread()
{
public void run ()
{
try { try {
runTorShellCmd();
runTorShellCmd();
runPrivoxyShellCmd();
setupTransProxy(true); setupTransProxy(true);
runPrivoxyShellCmd();
} catch (Exception e) { } catch (Exception e) {
Log.d(TAG,"Unable to start Tor: " + e.getMessage(),e); logException("Unable to start Tor: " + e.getMessage(),e);
sendCallbackStatusMessage("Unable to start Tor: " + e.getMessage()); sendCallbackStatusMessage("Unable to start Tor: " + e.getMessage());
stopTor();
} }
} }
}.start();
private boolean setupTransProxy (boolean activate) throws Exception
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean hasRoot;
if (prefs.contains("has_root"))
{
hasRoot = prefs.getBoolean("has_root",false);
}
else
{
hasRoot = TorServiceUtils.checkRootAccess();
Editor pEdit = prefs.edit();
pEdit.putBoolean("has_root",hasRoot);
pEdit.commit();
}
if (!hasRoot)
return false;
if (activate)
{
boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false);
boolean transProxyAll = prefs.getBoolean("pref_transparent_all", false);
boolean transProxyPortFallback = prefs.getBoolean("pref_transparent_port_fallback", false);
TorService.logMessage ("Transparent Proxying: " + enableTransparentProxy);
String portProxyList = prefs.getString("pref_port_list", "");
if (enableTransparentProxy)
{
showAlert("Status", "Setting up transparent proxying...");
//TorTransProxy.setDNSProxying();
int code = TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this),transProxyAll);
TorService.logMessage ("TorTransProxy resp code: " + code);
if (code == 0)
{
showAlert("Status", "Transparent proxying ENABLED");
}
else
{
showAlert("Status", "WARNING: error starting transparent proxying!");
}
//this is for Androids w/o owner module support as a circumvention only fallback
if (transProxyPortFallback)
{
StringTokenizer st = new StringTokenizer(portProxyList, ",");
while (st.hasMoreTokens())
TorTransProxy.setTransparentProxyingByPort(this, Integer.parseInt(st.nextToken()));
}
return true;
}
else
{
TorTransProxy.purgeIptables(this);
showAlert("Status", "Transparent proxying DISABLED");
}
}
else
{
TorTransProxy.purgeIptables(this);
showAlert("Status", "Transparent proxying DISABLED");
}
return true;
} }
private void runTorShellCmd() throws Exception private void runTorShellCmd() throws Exception
@ -598,9 +808,11 @@ public class TorService extends Service implements TorServiceConstants, Runnable
logNotice("Tor process id=" + procId); logNotice("Tor process id=" + procId);
showToolbarNotification(getString(R.string.status_starting_up), R.drawable.tornotification); showToolbarNotification(getString(R.string.status_starting_up), NOTIFY_ID, R.drawable.tornotification);
initControlConnection (); initControlConnection ();
applyPreferences();
} }
} }
@ -644,7 +856,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} }
sendCallbackLogMessage("Privoxy is running on port: " + PORT_HTTP); sendCallbackLogMessage("Privoxy is running on port: " + PORT_HTTP);
Thread.sleep(100);
logNotice("Privoxy process id=" + privoxyProcId); logNotice("Privoxy process id=" + privoxyProcId);
@ -699,7 +910,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable
addEventHandler(); addEventHandler();
applyPreferences();
} }
break; //don't need to retry break; //don't need to retry
@ -813,7 +1023,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
thread.start(); thread.start();
} }
else else if (profile == PROFILE_OFF)
{ {
currentStatus = STATUS_OFF; currentStatus = STATUS_OFF;
sendCallbackStatusMessage ("shutting down..."); sendCallbackStatusMessage ("shutting down...");
@ -828,27 +1038,35 @@ public class TorService extends Service implements TorServiceConstants, Runnable
public void message(String severity, String msg) { public void message(String severity, String msg) {
logNotice( "[Tor Control Port] " + severity + ": " + msg); logNotice( "[Tor Control Port] " + severity + ": " + msg);
if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1) if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1)
{ {
currentStatus = STATUS_ON; currentStatus = STATUS_ON;
showToolbarNotification (getString(R.string.status_activated),R.drawable.tornotificationon);
getHiddenServiceHostname ();
} }
showToolbarNotification (getString(R.string.status_activated),NOTIFY_ID,R.drawable.tornotificationon);
sendCallbackStatusMessage (msg); sendCallbackStatusMessage (msg);
} }
private void showAlert(String title, String msg) private void showAlert(String title, String msg)
{ {
/*
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setTitle(title) .setTitle(title)
.setMessage(msg) .setMessage(msg)
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.show(); .show();
*/
showToolbarNotification(msg, NOTIFY_ID_ERROR, R.drawable.tornotification);
} }
public void newDescriptors(List<String> orList) { public void newDescriptors(List<String> orList) {
@ -858,7 +1076,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
public void orConnStatus(String status, String orName) { public void orConnStatus(String status, String orName) {
if (LOG_OUTPUT_TO_DEBUG) if (ENABLE_DEBUG_LOG)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("orConnStatus ("); sb.append("orConnStatus (");
@ -873,7 +1091,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
public void streamStatus(String status, String streamID, String target) { public void streamStatus(String status, String streamID, String target) {
if (LOG_OUTPUT_TO_DEBUG) if (ENABLE_DEBUG_LOG)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("StreamStatus ("); sb.append("StreamStatus (");
@ -888,7 +1106,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
public void unrecognized(String type, String msg) { public void unrecognized(String type, String msg) {
if (LOG_OUTPUT_TO_DEBUG) if (ENABLE_DEBUG_LOG)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Message ("); sb.append("Message (");
@ -903,6 +1121,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable
public void bandwidthUsed(long read, long written) { public void bandwidthUsed(long read, long written) {
if (ENABLE_DEBUG_LOG)
{
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Bandwidth used: "); sb.append("Bandwidth used: ");
sb.append(read/1000); sb.append(read/1000);
@ -911,12 +1131,13 @@ public class TorService extends Service implements TorServiceConstants, Runnable
sb.append("kb written"); sb.append("kb written");
logNotice(sb.toString()); logNotice(sb.toString());
}
} }
public void circuitStatus(String status, String circID, String path) { public void circuitStatus(String status, String circID, String path) {
if (LOG_OUTPUT_TO_DEBUG) if (ENABLE_DEBUG_LOG)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Circuit ("); sb.append("Circuit (");
@ -947,7 +1168,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
catch (Exception e) catch (Exception e)
{ {
logNotice("unable to find tor binaries: " + e.getMessage()); logNotice("unable to find tor binaries: " + e.getMessage());
showToolbarNotification(e.getMessage(), R.drawable.tornotificationoff); showToolbarNotification(e.getMessage(), NOTIFY_ID_ERROR, R.drawable.tornotificationoff);
Log.d(TAG,"Unable to check for Tor binaries",e); Log.d(TAG,"Unable to check for Tor binaries",e);
return null; return null;
@ -977,6 +1198,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
*/ */
private final ITorService.Stub mBinder = new ITorService.Stub() { private final ITorService.Stub mBinder = new ITorService.Stub() {
public void registerCallback(ITorServiceCallback cb) { public void registerCallback(ITorServiceCallback cb) {
if (cb != null) mCallbacks.register(cb); if (cb != null) mCallbacks.register(cb);
} }
@ -993,6 +1215,18 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} }
public void processSettings ()
{
try {
applyPreferences();
} catch (RemoteException e) {
logException ("error applying prefs",e);
}
}
public boolean updateTransProxy () public boolean updateTransProxy ()
{ {
@ -1044,6 +1278,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
return null; return null;
} }
/** /**
* Set configuration * Set configuration
**/ **/
@ -1057,7 +1292,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
if (value == null || value.length() == 0) if (value == null || value.length() == 0)
{ {
resetBuffer.add(name);
/* /*
if (conn != null) if (conn != null)
{ {
@ -1066,10 +1301,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, "Unable to reset conf",e); Log.w(TAG, "Unable to reset conf",e);
} }
} }*/
*/
resetBuffer.add(name);
} }
else else
configBuffer.add(name + ' ' + value); configBuffer.add(name + ' ' + value);
@ -1083,13 +1315,13 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
if (conn != null) if (conn != null)
{ {
if (resetBuffer != null && resetBuffer.size() > 0) if (resetBuffer != null && resetBuffer.size() > 0)
{ {
conn.resetConf(resetBuffer); conn.resetConf(resetBuffer);
resetBuffer = null; resetBuffer = null;
} }
if (configBuffer != null && configBuffer.size() > 0) if (configBuffer != null && configBuffer.size() > 0)
{ {
@ -1117,24 +1349,21 @@ public class TorService extends Service implements TorServiceConstants, Runnable
private ArrayList<String> callbackBuffer = new ArrayList<String>(); private ArrayList<String> callbackBuffer = new ArrayList<String>();
private boolean inCallbackStatus = false; private boolean inCallbackStatus = false;
private boolean inCallbackLog = false; private boolean inCallback = false;
private void sendCallbackStatusMessage (String newStatus) private synchronized void sendCallbackStatusMessage (String newStatus)
{ {
if (mCallbacks == null) if (mCallbacks == null)
return; return;
// Broadcast to all clients the new value. // Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast(); final int N = mCallbacks.beginBroadcast();
inCallbackStatus = true; inCallback = true;
if (N > 0) if (N > 0)
{ {
for (int i=0; i<N; i++) { for (int i=0; i<N; i++) {
try { try {
mCallbacks.getBroadcastItem(i).statusChanged(newStatus); mCallbacks.getBroadcastItem(i).statusChanged(newStatus);
@ -1148,10 +1377,10 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} }
mCallbacks.finishBroadcast(); mCallbacks.finishBroadcast();
inCallbackStatus = false; inCallback = false;
} }
private void sendCallbackLogMessage (String logMessage) private synchronized void sendCallbackLogMessage (String logMessage)
{ {
if (mCallbacks == null) if (mCallbacks == null)
@ -1159,12 +1388,13 @@ public class TorService extends Service implements TorServiceConstants, Runnable
callbackBuffer.add(logMessage); callbackBuffer.add(logMessage);
if (!inCallback)
{
inCallback = true;
// Broadcast to all clients the new value. // Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast(); final int N = mCallbacks.beginBroadcast();
inCallbackLog = true;
if (N > 0) if (N > 0)
{ {
@ -1180,7 +1410,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable
try { try {
mCallbacks.getBroadcastItem(i).logMessage(status); mCallbacks.getBroadcastItem(i).logMessage(status);
} catch (RemoteException e) { } catch (RemoteException e) {
// The RemoteCallbackList will take care of removing // The RemoteCallbackList will take care of removing
// the dead object for us. // the dead object for us.
@ -1192,14 +1421,14 @@ public class TorService extends Service implements TorServiceConstants, Runnable
} }
mCallbacks.finishBroadcast(); mCallbacks.finishBroadcast();
inCallbackLog = false; inCallback = false;
} }
private void applyPreferences () throws RemoteException }
private boolean applyPreferences () throws RemoteException
{ {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean useBridges = prefs.getBoolean(TorConstants.PREF_BRIDGES_ENABLED, false); boolean useBridges = prefs.getBoolean(TorConstants.PREF_BRIDGES_ENABLED, false);
@ -1214,11 +1443,19 @@ public class TorService extends Service implements TorServiceConstants, Runnable
boolean enableTransparentProxy = prefs.getBoolean(TorConstants.PREF_TRANSPARENT, false); boolean enableTransparentProxy = prefs.getBoolean(TorConstants.PREF_TRANSPARENT, false);
try
String bridgeList = prefs.getString(TorConstants.PREF_BRIDGES_LIST,""); {
setupTransProxy(currentStatus != STATUS_OFF);
}
catch (Exception e)
{
logException("unable to setup transproxy",e);
}
if (useBridges) if (useBridges)
{ {
String bridgeList = prefs.getString(TorConstants.PREF_BRIDGES_LIST,"");
if (bridgeList == null || bridgeList.length() == 0) if (bridgeList == null || bridgeList.length() == 0)
{ {
@ -1226,7 +1463,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
"Send an email to bridges@torproject.org with the line \"get bridges\" by itself in the body of the mail from a gmail account."); "Send an email to bridges@torproject.org with the line \"get bridges\" by itself in the body of the mail from a gmail account.");
return; return false;
} }
@ -1274,6 +1511,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable
catch (Exception e) catch (Exception e)
{ {
showAlert("Config Error","Your ReachableAddresses settings caused an exception!"); showAlert("Config Error","Your ReachableAddresses settings caused an exception!");
return false;
} }
try try
@ -1299,12 +1538,12 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
showAlert("Uh-oh!","Your relay settings caused an exception!"); showAlert("Uh-oh!","Your relay settings caused an exception!");
return; return false;
} }
if (enableHiddenServices) if (enableHiddenServices)
{ {
mBinder.updateConfiguration("HiddenServiceDir","/data/data/org.torproject.android/", false); mBinder.updateConfiguration("HiddenServiceDir",appDataHome, false);
String hsPorts = prefs.getString("pref_hs_ports",""); String hsPorts = prefs.getString("pref_hs_ports","");
@ -1333,76 +1572,9 @@ public class TorService extends Service implements TorServiceConstants, Runnable
mBinder.saveConfiguration(); mBinder.saveConfiguration();
}
private boolean setupTransProxy (boolean enabled) throws Exception
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplication());
if (prefs.contains("has_root"))
{
hasRoot = prefs.getBoolean("has_root",false);//TorServiceUtils.checkRootAccess();
}
else
{
hasRoot = TorServiceUtils.checkRootAccess();
Editor pEdit = prefs.edit();
pEdit.putBoolean("has_root",hasRoot);
pEdit.commit();
}
boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false);
boolean transProxyAll = prefs.getBoolean("pref_transparent_all", false);
boolean transProxyPortFallback = prefs.getBoolean("pref_transparent_port_fallback", false);
logNotice ("Transparent Proxying: " + enableTransparentProxy);
String portProxyList = prefs.getString("pref_port_list", "");
if (enabled)
{
if (hasRoot)
{
if (enableTransparentProxy)
{
//TorTransProxy.setDNSProxying();
int code = TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this),transProxyAll);
logNotice ("TorTransProxy resp code: " + code);
//this is for Androids w/o owner module support as a circumvention only fallback
if (transProxyPortFallback)
{
StringTokenizer st = new StringTokenizer(portProxyList, ",");
while (st.hasMoreTokens())
TorTransProxy.setTransparentProxyingByPort(this, Integer.parseInt(st.nextToken()));
}
return true;
}
else
{
TorTransProxy.purgeIptables(this);
}
}
}
else if (hasRoot)
{
TorTransProxy.purgeIptables(this);
}
return true; return true;
} }
} }

View File

@ -6,8 +6,6 @@ public interface TorServiceConstants {
public final static String TAG = "ORBOT"; public final static String TAG = "ORBOT";
public static boolean LOG_OUTPUT_TO_DEBUG = true;
public final static String TOR_APP_USERNAME = "org.torproject.android"; public final static String TOR_APP_USERNAME = "org.torproject.android";
public final static String ASSETS_BASE = "assets/"; public final static String ASSETS_BASE = "assets/";
@ -78,4 +76,9 @@ public interface TorServiceConstants {
public final static int PROFILE_OFF = -1; public final static int PROFILE_OFF = -1;
public final static int PROFILE_ON = 1; public final static int PROFILE_ON = 1;
public static final int STATUS_MSG = 1;
public static final int ENABLE_TOR_MSG = 2;
public static final int DISABLE_TOR_MSG = 3;
public static final int LOG_MSG = 4;
} }

View File

@ -34,22 +34,19 @@ public class TorServiceUtils implements TorServiceConstants {
} catch (IOException e) { } catch (IOException e) {
//this means that there is no root to be had (normally) so we won't log anything //this means that there is no root to be had (normally) so we won't log anything
TorService.logException("Error checking for root access",e);
} }
catch (Exception e) { catch (Exception e) {
Log.w(TAG,"Error checking for root access: " + e.getMessage()); TorService.logException("Error checking for root access",e);
//this means that there is no root to be had (normally) //this means that there is no root to be had (normally)
} }
logNotice("Could not acquire root permissions"); TorService.logMessage("Could not acquire root permissions");
return false; return false;
} }
private static void logNotice (String msg)
{
if (LOG_OUTPUT_TO_DEBUG)
Log.d(TAG, msg);
}
public static int findProcessId(String command) public static int findProcessId(String command)
{ {
@ -106,7 +103,7 @@ public class TorServiceUtils implements TorServiceConstants {
} }
catch (NumberFormatException e) catch (NumberFormatException e)
{ {
logNotice("unable to parse process pid: " + line); TorService.logException("unable to parse process pid: " + line,e);
} }
} }
@ -153,7 +150,7 @@ public class TorServiceUtils implements TorServiceConstants {
public static int doShellCommand(String[] cmds, StringBuilder log, boolean runAsRoot, boolean waitFor) throws Exception public static int doShellCommand(String[] cmds, StringBuilder log, boolean runAsRoot, boolean waitFor) throws Exception
{ {
logNotice("executing shell cmds: " + cmds[0] + "; runAsRoot=" + runAsRoot); TorService.logMessage("executing shell cmds: " + cmds[0] + "; runAsRoot=" + runAsRoot);
Process proc = null; Process proc = null;
@ -201,7 +198,7 @@ public class TorServiceUtils implements TorServiceConstants {
log.append(exitCode); log.append(exitCode);
log.append("\n"); log.append("\n");
logNotice("command process exit value: " + exitCode); TorService.logMessage("command process exit value: " + exitCode);
} }

View File

@ -11,55 +11,11 @@ public class TorTransProxy implements TorServiceConstants {
private final static String TAG = TorServiceConstants.TAG; private final static String TAG = TorServiceConstants.TAG;
//private static String BASE_DIR = "/data/data/" + TorServiceConstants.TOR_APP_USERNAME + "/";
private static void logNotice (String msg)
{
if (LOG_OUTPUT_TO_DEBUG)
Log.d(TAG, msg);
}
/**
* Check if we have root access
* @return boolean true if we have root
*/
/*
public static String getIPTablesVersion() {
StringBuilder log = new StringBuilder();
try {
// Run an empty script just to check root access
String[] cmd = {"iptables -v"};
int code = TorServiceUtils.doShellCommand(cmd, log, true, true);
String msg = log.toString();
logNotice(cmd[0] + ";errCode=" + code + ";resp=" + msg);
String out = log.toString();
if (out.indexOf(" v")!=-1)
{
out = out.substring(out.indexOf(" v")+2);
out = out.substring(0,out.indexOf(":"));
return out.trim();
}
} catch (Exception e) {
Log.w(TAG,"Error checking iptables version: " + e.getMessage() ,e);
}
logNotice("Could not acquire check iptables: " + log.toString());
return null;
}*/
public static int purgeIptables(Context context) throws Exception { public static int purgeIptables(Context context) throws Exception {
String ipTablesPath = new File(context.getDir("bin", 0),"iptables_n1").getAbsolutePath(); String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
final StringBuilder script = new StringBuilder(); final StringBuilder script = new StringBuilder();
@ -78,7 +34,8 @@ public class TorTransProxy implements TorServiceConstants {
String[] cmd = {script.toString()}; String[] cmd = {script.toString()};
code = TorServiceUtils.doShellCommand(cmd, res, true, true); code = TorServiceUtils.doShellCommand(cmd, res, true, true);
String msg = res.toString(); String msg = res.toString();
logNotice(cmd[0] + ";errCode=" + code + ";resp=" + msg);
TorService.logMessage(cmd[0] + ";errCode=" + code + ";resp=" + msg);
return code; return code;
@ -90,7 +47,7 @@ public class TorTransProxy implements TorServiceConstants {
//restoreDNSResolvConf(); //not working yet //restoreDNSResolvConf(); //not working yet
String ipTablesPath = new File(context.getDir("bin", 0),"iptables_n1").getAbsolutePath(); String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
final StringBuilder script = new StringBuilder(); final StringBuilder script = new StringBuilder();
@ -171,12 +128,14 @@ public class TorTransProxy implements TorServiceConstants {
public static int setTransparentProxyingByApp(Context context, TorifiedApp[] apps, boolean forceAll) throws Exception public static int setTransparentProxyingByApp(Context context, TorifiedApp[] apps, boolean forceAll) throws Exception
{ {
boolean runRoot = true;
boolean waitFor = true;
//android.os.Debug.waitForDebugger(); //android.os.Debug.waitForDebugger();
//redirectDNSResolvConf(); //not working yet //redirectDNSResolvConf(); //not working yet
//String baseDir = context.getDir("bin", 0).getAbsolutePath() + "/"; String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
String ipTablesPath = new File(context.getDir("bin", 0),"iptables_n1").getAbsolutePath();
boolean ipTablesOld = false; boolean ipTablesOld = false;
@ -202,16 +161,7 @@ public class TorTransProxy implements TorServiceConstants {
continue; continue;
} }
logNotice("enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")"); TorService.logMessage("enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")");
/*
* iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner anonymous -m tcp --syn -j REDIRECT --to-ports 9040
iptables -t nat -A OUTPUT -p udp -m owner --uid-owner anonymous -m udp --dport 53 -j REDIRECT --to-ports 53
iptables -t nat -A OUTPUT -m owner --uid-owner anonymous -j DROP
*/
//iptables -t nat -A output -p tcp -m owner --uid-owner 100 -m tcp --sync -j REDIRECT --to-ports 9040
//TCP //TCP
script.append(ipTablesPath); script.append(ipTablesPath);
@ -248,7 +198,6 @@ iptables -t nat -A OUTPUT -m owner --uid-owner anonymous -j DROP
script.append(" || exit\n"); script.append(" || exit\n");
//EVERYTHING ELSE - DROP!
if (ipTablesOld) //for some reason this doesn't work on iptables 1.3.7 if (ipTablesOld) //for some reason this doesn't work on iptables 1.3.7
{ {
script.append(ipTablesPath); script.append(ipTablesPath);
@ -288,17 +237,16 @@ iptables -t nat -A OUTPUT -m owner --uid-owner anonymous -j DROP
} }
}
else
{
}
}
}
}
String[] cmdAdd = {script.toString()}; String[] cmdAdd = {script.toString()};
code = TorServiceUtils.doShellCommand(cmdAdd, res, true, true);
code = TorServiceUtils.doShellCommand(cmdAdd, res, runRoot, waitFor);
String msg = res.toString(); String msg = res.toString();
logNotice(cmdAdd[0] + ";errCode=" + code + ";resp=" + msg); TorService.logMessage(cmdAdd[0] + ";errCode=" + code + ";resp=" + msg);
return code; return code;
} }
@ -311,7 +259,7 @@ iptables -t nat -A OUTPUT -m owner --uid-owner anonymous -j DROP
//redirectDNSResolvConf(); //not working yet //redirectDNSResolvConf(); //not working yet
//String baseDir = context.getDir("bin",0).getAbsolutePath() + '/'; //String baseDir = context.getDir("bin",0).getAbsolutePath() + '/';
String ipTablesPath = new File(context.getDir("bin", 0),"iptables_n1").getAbsolutePath(); String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
boolean ipTablesOld = false; boolean ipTablesOld = false;
@ -380,7 +328,7 @@ iptables -t nat -A OUTPUT -m owner --uid-owner anonymous -j DROP
String[] cmdAdd = {script.toString()}; String[] cmdAdd = {script.toString()};
code = TorServiceUtils.doShellCommand(cmdAdd, res, true, true); code = TorServiceUtils.doShellCommand(cmdAdd, res, true, true);
String msg = res.toString(); String msg = res.toString();
logNotice(cmdAdd[0] + ";errCode=" + code + ";resp=" + msg); TorService.logMessage(cmdAdd[0] + ";errCode=" + code + ";resp=" + msg);
return code; return code;
} }