diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9350d086..458d48bf 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,7 +1,7 @@ + android:versionName="0.2.2.13-orbot-alpha-0.0.8" android:versionCode="8"> diff --git a/default.properties b/default.properties index c5d5335e..06c219ae 100644 --- a/default.properties +++ b/default.properties @@ -10,5 +10,5 @@ # Indicates whether an apk should be generated for each density. split.density=false # Project target. -target=android-8 +target=android-3 apk-configurations= diff --git a/res/drawable/toroff.png b/res/drawable/toroff.png index ddfc07b9..a5cfb97c 100644 Binary files a/res/drawable/toroff.png and b/res/drawable/toroff.png differ diff --git a/res/drawable/toron.png b/res/drawable/toron.png index 648efe2f..94ad2371 100644 Binary files a/res/drawable/toron.png and b/res/drawable/toron.png differ diff --git a/res/layout/layout_apps_item.xml b/res/layout/layout_apps_item.xml index c1538fe2..907f4353 100644 --- a/res/layout/layout_apps_item.xml +++ b/res/layout/layout_apps_item.xml @@ -4,11 +4,15 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" > - + + - + + + + diff --git a/res/layout/layout_log.xml b/res/layout/layout_log.xml index 911fc5ad..872c0509 100644 --- a/res/layout/layout_log.xml +++ b/res/layout/layout_log.xml @@ -1,17 +1,52 @@ + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 05a99569..4f230b3a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -15,7 +15,7 @@ Orbot is shutting down Starting Tor... -authenticating control connection... +Setting up control... complete. waiting. @@ -37,7 +37,7 @@ Orbot requires different configuration depending on the Android operating system version it is used on. Please visit https://www.torproject.org/docs/android.html for the latest information. -For non-rooted Android 1.x devices (G1, MyTouch3G, Hero): Please use the "ProxySurf" browser available in the Android Market, and set +For non-rooted Android 1.x devices: Please use the "ProxySurf" browser available in the Android Market, and set the HTTP Proxy to 127.0.0.1 and port 8118, for HTTP traffic only (HTTP/S will not work). For Instant Messaging, try "Beem" in the market, and set the SOCKS5 proxy to 127.0.0.1 / port 9050. @@ -52,4 +52,16 @@ and all DNS requests. This includes the built-in Browser, Gmail, YouTube and Map Exit powered by the Tor Project - press to start - + +Transparent Proxying (Requires Root) +Transparent Proxying +Automatic Torifying of Apps + +Tor Everything +Send traffic for all apps through Tor + +Tor binaries successfully installed! +The Tor binary files were unable to be installed. Please check the log and notify tor-assistants@torproject.org + +Application Error diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 99c0cd26..2f7b4412 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -1,20 +1,20 @@ - + +android:summary="@string/pref_transparent_all_summary" +android:enabled="true" +android:title="@string/pref_transparent_all_title"/> () { - public int compare(TorifiedApp o1, TorifiedApp o2) { - if (o1.isTorified() == o2.isTorified()) return o1.getName().compareTo(o2.getName()); - if (o1.isTorified()) return -1; - return 1; - } - }); - - final LayoutInflater inflater = getLayoutInflater(); - - final ListAdapter adapter = new ArrayAdapter(this,R.layout.layout_apps_item,R.id.itemtext,apps) { - public View getView(int position, View convertView, ViewGroup parent) { - ListEntry entry; - if (convertView == null) { - // Inflate a new view - convertView = inflater.inflate(R.layout.layout_apps_item, parent, false); - entry = new ListEntry(); - entry.box = (CheckBox) convertView.findViewById(R.id.itemcheck); - entry.text = (TextView) convertView.findViewById(R.id.itemtext); - convertView.setTag(entry); - entry.box.setOnCheckedChangeListener(Orbot.this); - } else { - // Convert an existing view - entry = (ListEntry) convertView.getTag(); - } - final TorifiedApp app = apps[position]; - - - entry.text.setText(app.getName()); - final CheckBox box = entry.box; - box.setTag(app); - box.setChecked(app.isTorified()); - return convertView; - } - }; - this.listApps.setAdapter(adapter); - - } - - /** - * Called an application is check/unchecked - */ - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - final TorifiedApp app = (TorifiedApp) buttonView.getTag(); - if (app != null) { - app.setTorified(isChecked); - } - - TorServiceUtils.saveAppSettings(this); - - } private static class ListEntry { private CheckBox box; @@ -424,7 +337,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On versionName.setText(R.string.app_version); new AlertDialog.Builder(this) - .setTitle(getString(R.string.menu_info)) + .setTitle(getString(R.string.button_about)) .setView(view) .setNeutralButton(getString(R.string.button_help), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { @@ -451,6 +364,25 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On StringBuilder msg = new StringBuilder(); msg.append(getString(R.string.help_text_1)); msg.append("\n\n"); + + if (hasRoot) + { + msg.append("Your device is ROOTED. Please enable the 'Transparent Proxying' setting to select which apps to send through Tor."); + } + else + { + + msg.append("Your device is NOT rooted.\n"); + + msg.append(getString(R.string.help_text_5)); + + msg.append("\n\n"); + + msg.append(getString(R.string.not_anonymous_yet)); + } + + /* + msg.append(getString(R.string.help_text_2)); msg.append("\n\n"); msg.append(getString(R.string.help_text_3)); @@ -459,6 +391,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On msg.append("\n\n"); msg.append(getString(R.string.help_text_5)); msg.append("\n\n"); + */ new AlertDialog.Builder(this) @@ -478,16 +411,14 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On .show(); } - private void showApps () + private void showHelpWizard () { - currentView = R.layout.layout_apps; - setContentView(currentView); - - listApps = (ListView)findViewById(R.id.applistview); - loadApps(); + //sshowAlert("Configure",getString(R.string.not_anonymous_yet)); } + + /* * Show the message log UI */ @@ -510,7 +441,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On private void showSettings () { - showingSettings = true; + startActivity(new Intent(this, SettingsPreferences.class)); @@ -520,7 +451,8 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On * Read in the Preferences and write then to the .torrc file */ - private void processSettings () + /* + private void processSettingsOld () { StringBuffer torrcText = new StringBuffer(); @@ -566,6 +498,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On return; } + torrcText.append("UseBridges 1"); torrcText.append('\n'); @@ -645,6 +578,111 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On Utils.saveTextFile(TorServiceConstants.TORRC_INSTALL_PATH, torrcText.toString()); } + */ + + private void processSettings () throws RemoteException + { + + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + boolean useBridges = prefs.getBoolean(PREF_BRIDGES_ENABLED, false); + + boolean autoUpdateBridges = prefs.getBoolean(PREF_BRIDGES_UPDATED, false); + + boolean becomeRelay = prefs.getBoolean(PREF_OR, false); + + boolean ReachableAddresses = prefs.getBoolean(PREF_REACHABLE_ADDRESSES,false); + + boolean enableTransparentProxy = prefs.getBoolean(PREF_TRANSPARENT, false); + + + String bridgeList = prefs.getString(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; + } + + mService.updateConfiguration("UseBridges", "1", false); + + if (autoUpdateBridges) + { + mService.updateConfiguration("UpdateBridgesFromAuthority", "1", false); + + } + else + { + mService.updateConfiguration("UpdateBridgesFromAuthority", "0", false); + } + + String bridgeDelim = "\n"; + + if (bridgeList.indexOf(",") != -1) + { + bridgeDelim = ","; + } + + StringTokenizer st = new StringTokenizer(bridgeList,bridgeDelim); + while (st.hasMoreTokens()) + { + + mService.updateConfiguration("bridge", st.nextToken(), false); + + } + } + else + { + mService.updateConfiguration("UseBridges", "0", false); + + } + + try + { + if (ReachableAddresses) + { + String ReachableAddressesPorts = + prefs.getString(PREF_REACHABLE_ADDRESSES_PORTS, "*:80,*:443"); + + mService.updateConfiguration("ReachableAddresses", ReachableAddressesPorts, false); + + } + } + catch (Exception e) + { + showAlert("Config Error","Your ReachableAddresses settings caused an exception!"); + } + + try + { + if (becomeRelay && (!useBridges) && (!ReachableAddresses)) + { + int ORPort = Integer.parseInt(prefs.getString(PREF_OR_PORT, "9001")); + String nickname = prefs.getString(PREF_OR_NICKNAME, "Orbot"); + + mService.updateConfiguration("ORPort", ORPort + "", false); + mService.updateConfiguration("Nickname", nickname, false); + mService.updateConfiguration("ExitPolicy", "reject *:*", false); + + } + } + catch (Exception e) + { + showAlert("Uh-oh!","Your relay settings caused an exception!"); + + return; + } + + mService.saveConfiguration(); + + } private void showAlert(String title, String msg) { @@ -679,9 +717,14 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On if (torStatus == STATUS_ON) { imgStatus.setImageResource(R.drawable.toron); - + imgStatus.clearAnimation(); + lblStatus.setText(getString(R.string.status_activated)); + showHelpWizard (); + + + /* if (progressDialog != null) { @@ -689,23 +732,28 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On progressDialog.hide(); progressDialog = null; - if (!enableTransparentProxy) - { - showAlert("Configure",getString(R.string.not_anonymous_yet)); - } - } - - // if (torServiceMsg != null && torServiceMsg.length()>0) - // Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show(); - - + + }*/ + } else if (torStatus == STATUS_CONNECTING) { imgStatus.setImageResource(R.drawable.torstarting); - lblStatus.setText(getString(R.string.status_starting_up)); + + /* + if (imgStatus.getAnimation()==null) + { + + imgStatus.setAnimation(AnimationUtils.loadAnimation(this, R.anim.starting)); + imgStatus.getAnimation().setRepeatMode(Animation.INFINITE); + + imgStatus.getAnimation().setRepeatCount(Animation.INFINITE); + }*/ + + + /* if (progressDialog == null) { progressDialog = new ProgressDialog(this); @@ -719,14 +767,18 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On } progressDialog.setMessage(torServiceMsg); - + */ + + lblStatus.setText(torServiceMsg); + + int idx = torServiceMsg.indexOf("%"); if (idx != -1) { String pComp = torServiceMsg.substring(idx-2,idx).trim(); int ipComp = Integer.parseInt(pComp); - progressDialog.setProgress(ipComp); + // progressDialog.setProgress(ipComp); } @@ -734,21 +786,16 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On else if (torStatus == STATUS_OFF) { imgStatus.setImageResource(R.drawable.torstopping); + imgStatus.clearAnimation(); + lblStatus.setText(getString(R.string.status_shutting_down)); - - //if (torServiceMsg != null && torServiceMsg.length()>0) - //Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show(); - - - + } else { - //if (torServiceMsg != null && torServiceMsg.length()>0) - //Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show(); - + /* if (progressDialog != null) { @@ -756,7 +803,8 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On progressDialog.hide(); progressDialog = null; } - + */ + imgStatus.clearAnimation(); imgStatus.setImageResource(R.drawable.toroff); lblStatus.setText(getString(R.string.status_disabled)); @@ -837,31 +885,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On } - private void doTorSetup (boolean enabled) - { - if (enabled) - { - processSettings(); - - - if (hasRoot && enableTransparentProxy) - { - - TorTransProxy.setDNSProxying(); - TorTransProxy.setTransparentProxying(this,TorServiceUtils.getApps(this)); - } - } - else - { - if (hasRoot && enableTransparentProxy) - { - TorTransProxy.purgeNatIptables(); - //TorRoot.setDNSProxying(false); - //TorRoot.setTransparentProxying(this,false); - } - } - } - + /** * This implementation is used to receive callbacks from the remote * service. @@ -876,21 +900,30 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On */ public void statusChanged(String value) { - Message msg = mHandler.obtainMessage(BUMP_MSG); + Message msg = mHandler.obtainMessage(STATUS_MSG); msg.getData().putString(HANDLER_TOR_MSG, value); mHandler.sendMessage(msg); } + + @Override + public void logMessage(String value) throws RemoteException { + + Message msg = mHandler.obtainMessage(LOG_MSG); + msg.getData().putString(HANDLER_TOR_MSG, value); + mHandler.sendMessage(msg); + + } }; - private static final int BUMP_MSG = 1; - + private static final int STATUS_MSG = 1; private static final int ENABLE_TOR_MSG = 2; private static final int DISABLE_TOR_MSG = 3; - + private static final int LOG_MSG = 4; + private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { - case BUMP_MSG: + case STATUS_MSG: String torServiceMsg = (String)msg.getData().getString(HANDLER_TOR_MSG); @@ -899,16 +932,24 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On if (torServiceMsg.length() > 0 && torServiceMsg.charAt(0)!='>') - updateStatus(torServiceMsg); + updateStatus(torServiceMsg); + + break; + case LOG_MSG: + + String torLogMsg = (String)msg.getData().getString(HANDLER_TOR_MSG); + + logBuffer.append(torLogMsg); + logBuffer.append('\n'); + break; case ENABLE_TOR_MSG: - doTorSetup(true); + break; case DISABLE_TOR_MSG: - doTorSetup(false); break; default: @@ -958,7 +999,6 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On boolean mIsBound = false; boolean hasRoot = false; - boolean enableTransparentProxy = false; private void bindService () { @@ -967,8 +1007,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants, On mIsBound = true; - hasRoot = TorTransProxy.hasRootAccess(); - + } diff --git a/src/org/torproject/android/SettingsPreferences.java b/src/org/torproject/android/SettingsPreferences.java index d7d407bc..2afb5837 100644 --- a/src/org/torproject/android/SettingsPreferences.java +++ b/src/org/torproject/android/SettingsPreferences.java @@ -21,12 +21,25 @@ public class SettingsPreferences private CheckBoxPreference prefcBTransProxyAll = null; private Preference prefTransProxyApps = null; - protected void onCreate(Bundle savedInstanceState) { + private boolean hasRoot = false; + + protected void onCreate(Bundle savedInstanceState) + { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); + hasRoot = TorServiceUtils.hasRoot(); - if (!TorServiceUtils.hasRoot()) + } + + + + @Override + protected void onResume() { + + super.onResume(); + + if (!hasRoot) { getPreferenceScreen().getPreference(0).setEnabled(false); } diff --git a/src/org/torproject/android/TorConstants.java b/src/org/torproject/android/TorConstants.java index 6d389073..e48056cc 100644 --- a/src/org/torproject/android/TorConstants.java +++ b/src/org/torproject/android/TorConstants.java @@ -6,6 +6,10 @@ package org.torproject.android; public interface TorConstants { public final static String TAG = "Orbot"; + + + public final static String PREFS_KEY = "OrbotPrefs"; + public final static String PREFS_KEY_TORIFIED = "PrefTord"; public final static int FILE_WRITE_BUFFER_SIZE = 2048; @@ -23,10 +27,12 @@ public interface TorConstants { public final static String NEWLINE = "\n"; + /* public final static String TORRC_DEFAULT = "SocksPort 9050\nSocksListenAddress 127.0.0.1\nSafeSocks 1\nDNSPort 5400\nLog debug syslog\nDataDirectory /data/data/org.torproject.android/cache\n" + "ControlPort 9051\nCookieAuthentication 1\nRelayBandwidthRate 20 KBytes\nRelayBandwidthBurst 20 KBytes\nAutomapHostsOnResolve 1\nTransPort 9040\n"; - + */ + public final static String INTENT_TOR_SERVICE = "org.torproject.android.service.TOR_SERVICE"; public final static String HANDLER_TOR_MSG = "torServiceMsg"; diff --git a/src/org/torproject/android/service/ITorService.aidl b/src/org/torproject/android/service/ITorService.aidl index aba9809d..4ddbd4df 100644 --- a/src/org/torproject/android/service/ITorService.aidl +++ b/src/org/torproject/android/service/ITorService.aidl @@ -6,19 +6,40 @@ import org.torproject.android.service.ITorServiceCallback; * an interface for calling on to a remote service */ interface ITorService { + /** - * Often you want to allow a service to call back to its clients. - * This shows how to do so, by registering a callback interface with - * the service. + * This allows Tor service to send messages back to the GUI */ void registerCallback(ITorServiceCallback cb); /** - * Remove a previously registered callback interface. + * Remove registered callback interface. */ void unregisterCallback(ITorServiceCallback cb); + /** + * Get a simple int status value for the state of Tor + **/ int getStatus(); + /** + * The profile value is the start/stop state for Tor + **/ void setProfile(int profile); + + /** + * Set configuration + **/ + boolean updateConfiguration (String name, String value, boolean saveToDisk); + + /** + * Set configuration + **/ + boolean saveConfiguration (); + + /** + * Get current configuration value from torrc + */ + String getConfiguration (String name); + } diff --git a/src/org/torproject/android/service/ITorServiceCallback.aidl b/src/org/torproject/android/service/ITorServiceCallback.aidl index 82df5027..86fe28f7 100644 --- a/src/org/torproject/android/service/ITorServiceCallback.aidl +++ b/src/org/torproject/android/service/ITorServiceCallback.aidl @@ -7,7 +7,13 @@ package org.torproject.android.service; */ oneway interface ITorServiceCallback { /** - * Called when the service has a new value for you. + * Called when the service has a something to display to the user */ void statusChanged(String value); + + /** + * Called when the service has something to add to the log + */ + void logMessage(String value); + } diff --git a/src/org/torproject/android/service/TorService.java b/src/org/torproject/android/service/TorService.java index 2341acee..60dcdb99 100644 --- a/src/org/torproject/android/service/TorService.java +++ b/src/org/torproject/android/service/TorService.java @@ -15,25 +15,28 @@ import net.freehaven.tor.control.ConfigEntry; import net.freehaven.tor.control.EventHandler; import net.freehaven.tor.control.TorControlConnection; +import org.torproject.android.AppManager; import org.torproject.android.Orbot; import org.torproject.android.R; +import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.IBinder; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.preference.PreferenceManager; import android.util.Log; public class TorService extends Service implements TorServiceConstants, Runnable, EventHandler { - private static int currentStatus = STATUS_READY; private TorControlConnection conn = null; @@ -44,7 +47,10 @@ public class TorService extends Service implements TorServiceConstants, Runnable private static final int MAX_START_TRIES = 3; - + private ArrayList configBuffer = null; + + private boolean hasRoot = false; + /** Called when the activity is first created. */ public void onCreate() { super.onCreate(); @@ -57,6 +63,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable _torInstance = this; + hasRoot = TorServiceUtils.hasRoot(); } @@ -130,19 +137,19 @@ public class TorService extends Service implements TorServiceConstants, Runnable } - private void showToolbarNotification (String title, String notifyMsg, int icon) + private void showToolbarNotification (String notifyMsg, int icon) { NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - CharSequence tickerText = title; + CharSequence tickerText = notifyMsg; long when = System.currentTimeMillis(); Notification notification = new Notification(icon, tickerText, when); Context context = getApplicationContext(); - CharSequence contentTitle = title; + CharSequence contentTitle = getString(R.string.app_name); CharSequence contentText = notifyMsg; Intent notificationIntent = new Intent(this, Orbot.class); @@ -189,7 +196,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable catch (Exception e) { currentStatus = STATUS_OFF; - this.showToolbarNotification("Orbot", "Unable to start Tor", R.drawable.tornotification); + this.showToolbarNotification(getString(R.string.status_disabled), R.drawable.tornotification); Log.i(TAG,"Unable to start Tor: " + e.getMessage(),e); } } @@ -220,9 +227,11 @@ public class TorService extends Service implements TorServiceConstants, Runnable currentStatus = STATUS_READY; - showToolbarNotification ("Orbot","Tor is disabled",R.drawable.tornotificationoff); - sendCallbackMessage("Tor is disabled"); + + showToolbarNotification (getString(R.string.status_disabled),R.drawable.tornotificationoff); + sendCallbackMessage(getString(R.string.status_disabled)); + setupTransProxy(false); } @@ -254,7 +263,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable if (conn != null) { try { - Log.i(TAG,"sending SHUTDOWN signal"); + logNotice("sending SHUTDOWN signal to Tor process"); + // conn.shutdownTor(arg0) conn.signal("SHUTDOWN"); } catch (Exception e) { Log.i(TAG,"error shutting down Tor via connection",e); @@ -269,7 +279,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable while (procId != -1) { - Log.i(TAG,"Found Tor PID=" + procId + " - killing now..."); + logNotice("Found Tor PID=" + procId + " - killing now..."); String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" }; TorServiceUtils.doShellCommand(cmd,log, false, false); @@ -290,22 +300,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable procId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH); } - /* - //removing this for now - if (_webProxy != null) - { - try - { - //shutdown web proxy - _webProxy.stop(); - _webProxy = null; - } - catch (Exception e) - { - Log.i(TAG,"error stopping web proxy",e); - } - }*/ - } private void logNotice (String msg) @@ -335,17 +329,17 @@ public class TorService extends Service implements TorServiceConstants, Runnable if (torBinaryExists && privoxyBinaryExists) { - logNotice("Tor, Privoxy, IPtables binaries installed!"); + logNotice(getString(R.string.status_install_success)); - this.showToolbarNotification("Orbot Installed!", "Tor was successfully extracted and installed", R.drawable.tornotification); + showToolbarNotification(getString(R.string.status_install_success), R.drawable.tornotification); } else { - logNotice("Binary install FAILED!"); - - this.showToolbarNotification("Orbot FAIL!", "The binaries were unable to be installed", R.drawable.tornotification); + + logNotice(getString(R.string.status_install_fail)); + showAlert(getString(R.string.title_error),getString(R.string.status_install_fail)); return false; } @@ -354,11 +348,11 @@ public class TorService extends Service implements TorServiceConstants, Runnable StringBuilder log = new StringBuilder (); - Log.i(TAG,"Setting permission on Tor binary"); + logNotice("Setting permission on Tor binary"); String[] cmd1 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + TOR_BINARY_INSTALL_PATH}; TorServiceUtils.doShellCommand(cmd1, log, false, true); - Log.i(TAG,"Setting permission on Privoxy binary"); + logNotice("Setting permission on Privoxy binary"); String[] cmd2 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + PRIVOXY_INSTALL_PATH}; TorServiceUtils.doShellCommand(cmd2, log, false, true); @@ -367,17 +361,19 @@ public class TorService extends Service implements TorServiceConstants, Runnable public void initTor () throws Exception { - + // android.os.Debug.waitForDebugger(); + currentStatus = STATUS_CONNECTING; - logNotice("Tor is starting up..."); - this.sendCallbackMessage("starting..."); + logNotice(getString(R.string.status_starting_up)); + + sendCallbackMessage(getString(R.string.status_starting_up)); killTorProcess (); checkTorBinaries (); - - + + new Thread() { @@ -401,6 +397,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable { try { runTorShellCmd(); + + setupTransProxy(true); } catch (Exception e) { Log.i(TAG,"Unable to start Tor: " + e.getMessage(),e); @@ -440,7 +438,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable { sendCallbackMessage("Couldn't start Tor process...\n" + log.toString()); Thread.sleep(1000); - sendCallbackMessage("Trying to start Tor again...\n" + log.toString()); + sendCallbackMessage(getString(R.string.status_starting_up)); Thread.sleep(3000); attempts++; } @@ -457,7 +455,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable logNotice("Tor process id=" + procId); - showToolbarNotification("Orbot starting...", "Tor is running", R.drawable.tornotification); + showToolbarNotification(getString(R.string.status_starting_up), R.drawable.tornotification); initControlConnection (); } @@ -489,7 +487,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable if (privoxyProcId == -1) { - this.sendCallbackMessage("Couldn't start Privoxy process... retrying...\n" + log); + logNotice("Couldn't start Privoxy process... retrying...\n" + log); Thread.sleep(3000); attempts++; } @@ -506,18 +504,16 @@ public class TorService extends Service implements TorServiceConstants, Runnable } - - - + /* public String generateHashPassword () { - /* + PasswordDigest d = PasswordDigest.generateDigest(); byte[] s = d.getSecret(); // pass this to authenticate String h = d.getHashedPassword(); // pass this to the Tor on startup. -*/ + return null; - } + }*/ public void initControlConnection () throws Exception, RuntimeException { @@ -534,7 +530,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable conn = TorControlConnection.getConnection(s); // conn.authenticate(new byte[0]); // See section 3.2 - sendCallbackMessage(baseMessage + ' ' + getString(R.string.tor_process_connecting_step2)); + sendCallbackMessage(getString(R.string.tor_process_connecting_step2)); Log.i(TAG,"SUCCESS connected to control port"); @@ -542,13 +538,20 @@ public class TorService extends Service implements TorServiceConstants, Runnable byte[] cookie = new byte[(int)fileCookie.length()]; new FileInputStream(new File(TOR_CONTROL_AUTH_COOKIE)).read(cookie); conn.authenticate(cookie); - + Log.i(TAG,"SUCCESS authenticated to control port"); - sendCallbackMessage(baseMessage + ' ' + getString(R.string.tor_process_connecting_step3)); + sendCallbackMessage(getString(R.string.tor_process_connecting_step2) + getString(R.string.tor_process_connecting_step3)); addEventHandler(); + if (configBuffer != null) + { + conn.setConf(configBuffer); + //conn.saveConf(); + configBuffer = null; + } + break; //don't need to retry } catch (Exception ce) @@ -568,29 +571,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable } - public void modifyConf () throws IOException - { - // Get one configuration variable. - List options = conn.getConf("contact"); - options.size(); - // Get a set of configuration variables. - // List options = conn.getConf(Arrays.asList(new String[]{ - // "contact", "orport", "socksport"})); - // Change a single configuration variable - conn.setConf("BandwidthRate", "1 MB"); - // Change several configuration variables - conn.setConf(Arrays.asList(new String[]{ - "HiddenServiceDir /home/tor/service1", - "HiddenServicePort 80", - })); - // Reset some variables to their defaults - conn.resetConf(Arrays.asList(new String[]{ - "contact", "socksport" - })); - // Flush the configuration to disk. - conn.saveConf(); - - } /* private void getTorStatus () throws IOException @@ -640,7 +620,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable conn.setEventHandler(this); conn.setEvents(Arrays.asList(new String[]{ - "ORCONN", "CIRC", "NOTICE", "ERR"})); + "ORCONN", "CIRC", "NOTICE", "WARN", "ERR"})); // conn.setEvents(Arrays.asList(new String[]{ // "DEBUG", "INFO", "NOTICE", "WARN", "ERR"})); @@ -701,7 +681,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1) { currentStatus = STATUS_ON; - showToolbarNotification ("Orbot","Tor is enabled",R.drawable.tornotification); + showToolbarNotification (getString(R.string.status_activated),R.drawable.tornotification); } @@ -709,6 +689,15 @@ public class TorService extends Service implements TorServiceConstants, Runnable } + private void showAlert(String title, String msg) + { + + new AlertDialog.Builder(this) + .setTitle(title) + .setMessage(msg) + .setPositiveButton(android.R.string.ok, null) + .show(); + } public void newDescriptors(List orList) { @@ -783,6 +772,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable } + private Intent launchContext = null; + public IBinder onBind(Intent intent) { // Select the interface to return. If your service only implements // a single interface, you can just return it here without checking @@ -807,6 +798,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable * The IRemoteInterface is defined through IDL */ private final ITorService.Stub mBinder = new ITorService.Stub() { + public void registerCallback(ITorServiceCallback cb) { if (cb != null) mCallbacks.register(cb); } @@ -820,10 +812,103 @@ public class TorService extends Service implements TorServiceConstants, Runnable public void setProfile (int profile) { setTorProfile(profile); - sendCallbackMessage(""); } + public String getConfiguration (String name) + { + try + { + if (conn != null) + { + StringBuffer result = new StringBuffer(); + + List listCe = conn.getConf(name); + + Iterator itCe = listCe.iterator(); + ConfigEntry ce = null; + + while (itCe.hasNext()) + { + ce = itCe.next(); + + result.append(ce.key); + result.append(' '); + result.append(ce.value); + result.append('\n'); + } + + return result.toString(); + } + } + catch (IOException ioe) + { + Log.e(TAG, "Unable to update Tor configuration", ioe); + logNotice("Unable to update Tor configuration: " + ioe.getMessage()); + } + + return null; + } + /** + * Set configuration + **/ + public boolean updateConfiguration (String name, String value, boolean saveToDisk) + { + try + { + if (conn != null) + { + conn.setConf(name, value); + + if (saveToDisk) + { + // Flush the configuration to disk. + //conn.saveConf(); //NF 22/07/10 this is crashing right now + } + + return true; + } + else + { + if (configBuffer == null) + configBuffer = new ArrayList(); + + configBuffer.add(name + ' ' + value); + } + } + catch (IOException ioe) + { + Log.e(TAG, "Unable to update Tor configuration", ioe); + logNotice("Unable to update Tor configuration: " + ioe.getMessage()); + } + + return false; + } + + public boolean saveConfiguration () + { + try + { + if (conn != null) + { + + + // Flush the configuration to disk. + //this is doing bad things right now NF 22/07/10 + //conn.saveConf(); + + return true; + } + } + catch (Exception ioe) + { + Log.e(TAG, "Unable to update Tor configuration", ioe); + logNotice("Unable to update Tor configuration: " + ioe.getMessage()); + } + + return false; + + } }; private ArrayList callbackBuffer = new ArrayList(); @@ -864,4 +949,40 @@ public class TorService extends Service implements TorServiceConstants, Runnable mCallbacks.finishBroadcast(); } + + private void setupTransProxy (boolean enabled) + { + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false); + boolean transProxyAll = prefs.getBoolean("pref_transparent_all", false); + + logNotice ("Transparent Proxying: " + enableTransparentProxy); + + if (enabled) + { + + + if (hasRoot && enableTransparentProxy) + { + + TorTransProxy.setDNSProxying(); + TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this),transProxyAll); + + } + else + { + TorTransProxy.purgeNatIptables(); + + } + } + else + { + if (hasRoot) + { + TorTransProxy.purgeNatIptables(); + } + } + } } diff --git a/src/org/torproject/android/service/TorServiceConstants.java b/src/org/torproject/android/service/TorServiceConstants.java index 1d193be6..a0b7ed1a 100644 --- a/src/org/torproject/android/service/TorServiceConstants.java +++ b/src/org/torproject/android/service/TorServiceConstants.java @@ -6,10 +6,12 @@ public interface TorServiceConstants { public final static String TAG = "TOR_SERVICE"; + public final static String TOR_APP_USERNAME = "org.torproject.android"; + //home directory of Android application - public final static String TOR_HOME = "/data/data/org.torproject.android/"; + public final static String TOR_HOME = "/data/data/" + TOR_APP_USERNAME + "/"; - public final static String TOR_HOME_DATA_DIR = TOR_HOME + "cache/"; + public final static String TOR_HOME_DATA_DIR = TOR_HOME + "data/"; //name of the tor C binary public final static String TOR_BINARY_ASSET_KEY = "tor"; diff --git a/src/org/torproject/android/service/TorServiceUtils.java b/src/org/torproject/android/service/TorServiceUtils.java index ebc36557..ada14271 100644 --- a/src/org/torproject/android/service/TorServiceUtils.java +++ b/src/org/torproject/android/service/TorServiceUtils.java @@ -21,94 +21,10 @@ import android.util.Log; public class TorServiceUtils implements TorServiceConstants { - private static TorifiedApp[] apps = null; private final static String PREFS_KEY = "OrbotPrefs"; private final static String PREFS_KEY_TORIFIED = "PrefTord"; - public static void saveAppSettings (Context context) - { - if (apps == null) - return; - - final SharedPreferences prefs = context.getSharedPreferences(PREFS_KEY, 0); - - StringBuilder tordApps = new StringBuilder(); - - for (int i = 0; i < apps.length; i++) - { - if (apps[i].isTorified()) - { - tordApps.append(apps[i].getUsername()); - tordApps.append("|"); - } - } - - Editor edit = prefs.edit(); - edit.putString(PREFS_KEY_TORIFIED, tordApps.toString()); - edit.commit(); - - } - - public static TorifiedApp[] getApps (Context context) - { - if (apps != null) - return apps; - - final SharedPreferences prefs = context.getSharedPreferences(PREFS_KEY, 0); - - String tordAppString = prefs.getString(PREFS_KEY_TORIFIED, ""); - String[] tordApps; - - StringTokenizer st = new StringTokenizer(tordAppString,"|"); - tordApps = new String[st.countTokens()]; - int tordIdx = 0; - while (st.hasMoreTokens()) - { - tordApps[tordIdx++] = st.nextToken(); - } - - Arrays.sort(tordApps); - - //else load the apps up - PackageManager pMgr = context.getPackageManager(); - - List lAppInfo = pMgr.getInstalledApplications(0); - - Iterator itAppInfo = lAppInfo.iterator(); - - apps = new TorifiedApp[lAppInfo.size()]; - - ApplicationInfo aInfo = null; - - int appIdx = 0; - - while (itAppInfo.hasNext()) - { - aInfo = itAppInfo.next(); - - apps[appIdx] = new TorifiedApp(); - - apps[appIdx].setEnabled(aInfo.enabled); - apps[appIdx].setUid(aInfo.uid); - apps[appIdx].setUsername(pMgr.getNameForUid(apps[appIdx].getUid())); - apps[appIdx].setProcname(aInfo.processName); - apps[appIdx].setName(pMgr.getApplicationLabel(aInfo).toString()); - - // check if this application is allowed - if (Arrays.binarySearch(tordApps, apps[appIdx].getUsername()) >= 0) { - apps[appIdx].setTorified(true); - } - else - { - apps[appIdx].setTorified(false); - } - - appIdx++; - } - - return apps; - } public static int findProcessId(String command) { diff --git a/src/org/torproject/android/service/TorTransProxy.java b/src/org/torproject/android/service/TorTransProxy.java index 8c93cc8e..f2315823 100644 --- a/src/org/torproject/android/service/TorTransProxy.java +++ b/src/org/torproject/android/service/TorTransProxy.java @@ -93,7 +93,7 @@ public class TorTransProxy { } } - public static boolean setTransparentProxying(Context context, TorifiedApp[] apps) { + public static boolean setTransparentProxyingByApp(Context context, TorifiedApp[] apps, boolean forceAll) { String command = null; @@ -101,14 +101,24 @@ public class TorTransProxy { final StringBuilder script = new StringBuilder(); + StringBuilder res = new StringBuilder(); + int code = -1; + try { - int code; + for (int i = 0; i < apps.length; i++) { - - if (apps[i].isTorified()) + if (forceAll || apps[i].isTorified()) { + + if (apps[i].getUsername().equals(TorServiceConstants.TOR_APP_USERNAME)) + { + Log.i(TAG,"detected Orbot app - will not transproxy"); + + continue; + } + Log.i(TAG,"enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")"); //TCP @@ -129,17 +139,16 @@ public class TorTransProxy { } } - StringBuilder res = new StringBuilder(); String[] cmd = {script.toString()}; code = TorServiceUtils.doShellCommand(cmd, res, true, true); - String msg = res.toString(); - Log.e(TAG, msg); + String msg = res.toString(); + Log.e(TAG, msg); } catch (Exception e) { - Log.w(TAG, "error refreshing iptables: " + e); + Log.w(TAG, "error refreshing iptables: err=" + code + "; resp=" + res.toString(), e); } return false; }