diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d01b58e4..23c2805f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="org.torproject.android" android:versionName="0.2.2.25-orbot-alpha-1.0.5.3" android:versionCode="15"> diff --git a/CHANGELOG b/CHANGELOG index 449b037b..0721fdaa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ NOTE: Specific #s below correspond to Trac tickets logged and maintained at https://trac.torproject.org/projects/tor/ +1.0.5.3 +- added auto-tor of wireless and usb tethering + 1.0.5.1/.2 - small updates to layout of main screen to fit smaller screens - fixed preference setting of EntryNode torrc value diff --git a/res/raw/torrc b/res/raw/torrc index ba0b61e5..d1cd7fd3 100644 --- a/res/raw/torrc +++ b/res/raw/torrc @@ -7,5 +7,8 @@ RelayBandwidthRate 20 KBytes RelayBandwidthBurst 20 KBytes UseBridges 0 AutomapHostsOnResolve 1 +TransListenAddress 0.0.0.0 TransPort 9040 +DNSListenAddress 0.0.0.0 DNSPort 5400 + diff --git a/res/values/strings.xml b/res/values/strings.xml index bca3df91..1a5daf3f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -131,4 +131,8 @@ Start Orbot on Boot Automatically start Orbot and connect Tor when your Android device boots + Tor Tethering + Enable Tor Transparent Proxying for Wifi and USB Tethered Devices + + diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 067cd740..e1aaad40 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -39,6 +39,13 @@ android:title="Select Apps" android:summary="Choose Apps to Route Through Tor" android:enabled="true"/> + + diff --git a/src/org/torproject/android/Orbot.java b/src/org/torproject/android/Orbot.java index 4bc5695d..690ce108 100644 --- a/src/org/torproject/android/Orbot.java +++ b/src/org/torproject/android/Orbot.java @@ -1,9 +1,8 @@ -/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ +/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - https://guardianproject.info */ /* See LICENSE for licensing information */ package org.torproject.android; - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -45,43 +44,56 @@ import android.widget.TextView; public class Orbot extends Activity implements OnLongClickListener, TorConstants { - - /* Useful UI bits */ - private TextView lblStatus = null; //the main text display widget - private ImageView imgStatus = null; //the main touchable image for activating Orbot - private ProgressDialog progressDialog; - private MenuItem mItemOnOff = null; - - /* Some tracking bits */ - private int torStatus = STATUS_READY; //latest status reported from the tor service - - /* Tor Service interaction */ - /* The primary interface we will be calling on the service. */ - ITorService mService = null; - private boolean autoStartOnBind = false; + + /* Useful UI bits */ + // so this is probably pretty obvious, here, but also an area + // which we might see quite a bit of change+complexity was the main screen + // UI gets new features + private TextView lblStatus = null; //the main text display widget + private ImageView imgStatus = null; //the main touchable image for activating Orbot + private ProgressDialog progressDialog; //the spinning progress dialog that shows up now and then + private MenuItem mItemOnOff = null; //the menu item which we toggle based on Orbot state + + /* Some tracking bits */ + private int torStatus = STATUS_READY; //latest status reported from the tor service + // this is a value we get passed back from the TorService + + /* Tor Service interaction */ + /* The primary interface we will be calling on the service. */ + ITorService mService = null; //interface to remote TorService + private boolean autoStartOnBind = false; //controls whether service starts when class binds to it - SharedPreferences prefs; - - /** Called when the activity is first created. */ + SharedPreferences prefs; //what the user really wants! + + /** + * When the Orbot activity is created, we call startService + * to ensure the Tor remote service is running. However, it may + * already be running, and this should not create more than one instnace + */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //if Tor binary is not running, then start the service up - startService(new Intent(INTENT_TOR_SERVICE)); - - - setTheme(android.R.style.Theme_Black_NoTitleBar); - - prefs = PreferenceManager.getDefaultSharedPreferences(this); - - setContentView(R.layout.layout_main); - - lblStatus = (TextView)findViewById(R.id.lblStatus); - lblStatus.setOnLongClickListener(this); - imgStatus = (ImageView)findViewById(R.id.imgStatus); - imgStatus.setOnLongClickListener(this); - - + //might want to look at whether we need to call this every time + //or whether binding to the service is enough + startService(new Intent(INTENT_TOR_SERVICE)); + + //something to play with on the UI branch + setTheme(android.R.style.Theme_Black_NoTitleBar); + + prefs = PreferenceManager.getDefaultSharedPreferences(this); + + //same here - layout_main has been cleaned up since 1.0.5.2 a bit (removed table as you recmnd) + //but ther eis more to be done + setContentView(R.layout.layout_main); + + //obvious? -yep got everything so far + lblStatus = (TextView)findViewById(R.id.lblStatus); + lblStatus.setOnLongClickListener(this); + imgStatus = (ImageView)findViewById(R.id.imgStatus); + imgStatus.setOnLongClickListener(this); + + } @@ -119,562 +131,636 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants private void showAbout () - { - - LayoutInflater li = LayoutInflater.from(this); + { + + LayoutInflater li = LayoutInflater.from(this); View view = li.inflate(R.layout.layout_about, null); TextView versionName = (TextView)view.findViewById(R.id.versionName); versionName.setText(R.string.app_version); - new AlertDialog.Builder(this) + new AlertDialog.Builder(this) .setTitle(getString(R.string.button_about)) .setView(view) .show(); - } + } /* When a menu item is selected launch the appropriate view or activity * (non-Javadoc) - * @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem) - */ - public boolean onMenuItemSelected(int featureId, MenuItem item) { - - super.onMenuItemSelected(featureId, item); - - if (item.getItemId() == 1) - { - - try - { - - if (mService == null) - { - - } - else if (mService.getStatus() == STATUS_READY) - { - if (mItemOnOff != null) - mItemOnOff.setTitle(R.string.menu_stop); - startTor(); - - } - else - { - if (mItemOnOff != null) - mItemOnOff.setTitle(R.string.menu_start); - stopTor(); - - } - - } - catch (RemoteException re) - { - Log.w(TAG, "Unable to start/top Tor from menu UI", re); - } - } - else if (item.getItemId() == 4) - { - showSettings(); - } - else if (item.getItemId() == 3) - { - showHelp(); - } - else if (item.getItemId() == 7) - { - doTorCheck(); - } - else if (item.getItemId() == 8) - { - //exit app - doExit(); - - - } - else if (item.getItemId() == 6) - { - showAbout(); - - - } - + * @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem) + */ + public boolean onMenuItemSelected(int featureId, MenuItem item) { + + super.onMenuItemSelected(featureId, item); + + if (item.getItemId() == 1) + { + + try + { + + if (mService == null) + { + + } + else if (mService.getStatus() == STATUS_READY) + { + if (mItemOnOff != null) + mItemOnOff.setTitle(R.string.menu_stop); + startTor(); + + } + else + { + if (mItemOnOff != null) + mItemOnOff.setTitle(R.string.menu_start); + stopTor(); + + } + + } + catch (RemoteException re) + { + Log.w(TAG, "Unable to start/top Tor from menu UI", re); + } + } + else if (item.getItemId() == 4) + { + showSettings(); + } + else if (item.getItemId() == 3) + { + showHelp(); + } + else if (item.getItemId() == 7) + { + doTorCheck(); + } + else if (item.getItemId() == 8) + { + //exit app + doExit(); + + + } + else if (item.getItemId() == 6) + { + showAbout(); + + + } + return true; - } - - private void doExit () - { - try { - - stopTor(); - - stopService(new Intent(ITorService.class.getName())); - - NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.cancelAll(); - - - } catch (RemoteException e) { - Log.w(TAG, e); - } - - finish(); - - } - - /* Return to the main view when the back key is pressed - * (non-Javadoc) - * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent) - */ - /* - public boolean onKeyDown(int keyCode, KeyEvent event){ - - if(keyCode==KeyEvent.KEYCODE_BACK){ + } + + /** + * This is our attempt to REALLY exit Orbot, and stop the background service + * However, Android doesn't like people "quitting" apps, and/or our code may not + * be quite right b/c no matter what we do, it seems like the TorService still exists + **/ + private void doExit () + { + try { + + //one of the confusing things about all of this code is the multiple + //places where things like "stopTor" are called, both in the Activity and the Service + //not something to tackle in your first iteration, but i thin we can talk about fixing + //terminology but also making sure there are clear distinctions in control + stopTor(); + + //perhaps this should be referenced as INTENT_TOR_SERVICE as in startService + stopService(new Intent(ITorService.class.getName())); + + //clears all notifications from the status bar + NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationManager.cancelAll(); + + + } catch (RemoteException e) { + Log.w(TAG, e); + } + + finish(); + + } + + /* Return to the main view when the back key is pressed + * (non-Javadoc) + * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent) + */ + /* + public boolean onKeyDown(int keyCode, KeyEvent event){ + + //yeah this should probably go away now :) - or not + if(keyCode==KeyEvent.KEYCODE_BACK){ - if(currentView != R.layout.layout_main){ - - showMain (); - return true; - } - else{ - return super.onKeyDown(keyCode, event); - } - } - - return super.onKeyDown(keyCode, event); - - }*/ + if(currentView != R.layout.layout_main){ + + showMain (); + return true; + } + else{ + return super.onKeyDown(keyCode, event); + } + } + + return super.onKeyDown(keyCode, event); + + }*/ /* (non-Javadoc) - * @see android.app.Activity#onPause() - */ - protected void onPause() { - super.onPause(); - - hideProgressDialog(); + * @see android.app.Activity#onPause() + */ + protected void onPause() { + super.onPause(); + + hideProgressDialog(); - if (aDialog != null) - aDialog.dismiss(); - } + if (aDialog != null) + aDialog.dismiss(); + } - public void onSaveInstanceState(Bundle savedInstanceState) { - // Save UI state changes to the savedInstanceState. - // This bundle will be passed to onCreate if the process is - // killed and restarted. - // etc. - super.onSaveInstanceState(savedInstanceState); - } - - public void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - // Restore UI state from the savedInstanceState. - // This bundle has also been passed to onCreate. - - } - - private void doTorCheck () - { - - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which){ - case DialogInterface.BUTTON_POSITIVE: - - openBrowser(URL_TOR_CHECK); +/** +* i think we need to suport this onSave/Restore code more b/c i think +* when someone rotates the screen, and the state is lost during setup +* etc it causes problems. this might be the place to solve that in the wizard - hmm this prob coz android restarts the activity when the screen is rotated. this will prob be fixed(?) when +we redesign the wizard into a view not just a dialogbox +cool +**/ + public void onSaveInstanceState(Bundle savedInstanceState) { + // Save UI state changes to the savedInstanceState. + // This bundle will be passed to onCreate if the process is + // killed and restarted. + // etc. + super.onSaveInstanceState(savedInstanceState); + } + + public void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + // Restore UI state from the savedInstanceState. + // This bundle has also been passed to onCreate. + + //we do nothing here + } + + /** + * confirm with the user that they want to open a browser to connect to https://check.torproject.org + and then launch the URL. + this may be where the TorCheck API code/UI is added, though always offering the web-based confirm + should be an option, since users know it + + **/ + private void doTorCheck () + { + + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which){ + case DialogInterface.BUTTON_POSITIVE: + + openBrowser(URL_TOR_CHECK); - - - break; + + + break; - case DialogInterface.BUTTON_NEGATIVE: - - //do nothing - break; - } - } - }; + case DialogInterface.BUTTON_NEGATIVE: + + //do nothing + break; + } + } + }; - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(R.string.tor_check).setPositiveButton(R.string.btn_okay, dialogClickListener) - .setNegativeButton(R.string.btn_cancel, dialogClickListener).show(); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.tor_check).setPositiveButton(R.string.btn_okay, dialogClickListener) + .setNegativeButton(R.string.btn_cancel, dialogClickListener).show(); - } - - private void enableHiddenServicePort (int hsPort) - { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - Editor pEdit = prefs.edit(); - - String hsPortString = prefs.getString("pref_hs_ports", ""); - - if (hsPortString.length() > 0 && hsPortString.indexOf(hsPort+"")==-1) - hsPortString += ',' + hsPort; - else - hsPortString = hsPort + ""; - - pEdit.putString("pref_hs_ports", hsPortString); - pEdit.putBoolean("pref_hs_enable", true); - - pEdit.commit(); - - String onionHostname = prefs.getString("pref_hs_hostname",""); + } + + /** + * this adds a port to the list of hidden service ports + * we might want to add remove/disable port too + * this is used by external apps that launch an intent + * to request a hidden service on a specific port + * currently, we haven't promoted this intent API or capability + * that much, but we hope to + **/ + private void enableHiddenServicePort (int hsPort) + { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + Editor pEdit = prefs.edit(); + + String hsPortString = prefs.getString("pref_hs_ports", ""); + + if (hsPortString.length() > 0 && hsPortString.indexOf(hsPort+"")==-1) + hsPortString += ',' + hsPort; + else + hsPortString = hsPort + ""; + + pEdit.putString("pref_hs_ports", hsPortString); + pEdit.putBoolean("pref_hs_enable", true); + + pEdit.commit(); + + String onionHostname = prefs.getString("pref_hs_hostname",""); - Intent nResult = new Intent(); - nResult.putExtra("hs_host", onionHostname); - setResult(RESULT_OK, nResult); - - } - - /* (non-Javadoc) - * @see android.app.Activity#onResume() - */ - protected void onResume() { - super.onResume(); - - bindService(); - - updateStatus(""); - - if (getIntent() == null) - return; - - String action = getIntent().getAction(); - - if (action == null) - return; - - if (action.equals("org.torproject.android.REQUEST_HS_PORT")) - { - - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which){ - case DialogInterface.BUTTON_POSITIVE: - - int hsPort = getIntent().getIntExtra("hs_port", -1); - - enableHiddenServicePort (hsPort); - - finish(); - - - break; + Intent nResult = new Intent(); + nResult.putExtra("hs_host", onionHostname); + setResult(RESULT_OK, nResult); + + } + + /* (non-Javadoc) + * @see android.app.Activity#onResume() + */ + protected void onResume() { + super.onResume(); + + //this is where we make sure we have a handle to ITorService + bindService(); + + //this is a hack which basically pings the ITorService to update our status for the UI + // - the dialogbox/progressbar ? + // right, this was for when the label displayed the status, and not the progress, so it may + // not make as much sense now; there is a bunch of loose ends like this that should be + // cleaned up with the transition to the progressdialog - ok + updateStatus(""); + + //this checks if we were launched via an Intent call from another app or activity + //- how does this matter? if Orbot has been launched via an Intent or not ? + //we want to know if this is a launch by the user from the home screen, or via back, or some + // standard interaction, or if it is another app launching Orbot for a programmatic/API request + // this is how we can add more functionality into ORlib, for instance via Intent launching - hmm ok + if (getIntent() == null) + return; + + String action = getIntent().getAction(); + + if (action == null) + return; + + //this relates to the previously discussed hidden port capability + if (action.equals("org.torproject.android.REQUEST_HS_PORT")) + { + + //tell the user an app is trying to open a hidden port and ask for permission + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which){ + case DialogInterface.BUTTON_POSITIVE: + + int hsPort = getIntent().getIntExtra("hs_port", -1); + + enableHiddenServicePort (hsPort); + + finish(); + + + break; - case DialogInterface.BUTTON_NEGATIVE: - //No button clicked - finish(); - break; - } - } - }; + case DialogInterface.BUTTON_NEGATIVE: + //No button clicked + finish(); + break; + } + } + }; - int hsPort = getIntent().getIntExtra("hs_port", -1); + int hsPort = getIntent().getIntExtra("hs_port", -1); - String requestMsg = "An app wants to open a server port (" + hsPort + ") to the Tor network. This is safe if you trust the app."; - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(requestMsg).setPositiveButton("Allow", dialogClickListener) - .setNegativeButton("Deny", dialogClickListener).show(); - - - } - else if (action.equals("org.torproject.android.START_TOR")) - { - autoStartOnBind = true; - - if (mService == null) - bindService(); - - } - else - { - - //setTitle(getString(R.string.app_name) + ' ' + getString(R.string.app_version)); - - NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.cancelAll(); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - boolean showWizard = prefs.getBoolean("show_wizard",true); - - if (showWizard) - { - - Editor pEdit = prefs.edit(); - - pEdit.putBoolean("show_wizard",false); - - pEdit.commit(); - - new WizardHelper(this).showWizard(); + String requestMsg = "An app wants to open a server port (" + hsPort + ") to the Tor network. This is safe if you trust the app."; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(requestMsg).setPositiveButton("Allow", dialogClickListener) + .setNegativeButton("Deny", dialogClickListener).show(); + + + } + else if (action.equals("org.torproject.android.START_TOR")) //this is the intent used to start Tor from another app, again meant for ORlib functionality + { + autoStartOnBind = true; + + if (mService == null) + bindService(); + + } + else + { + //hmm not sure when this is ever reached honestly ;P + //but it looks like a general UI reset + + NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationManager.cancelAll(); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + boolean showWizard = prefs.getBoolean("show_wizard",true); + + if (showWizard) + { + + Editor pEdit = prefs.edit(); + + pEdit.putBoolean("show_wizard",false); + + pEdit.commit(); + + new WizardHelper(this).showWizard(); - } - - } - } + } + + } + } - /* (non-Javadoc) - * @see android.app.Activity#onStart() - */ - protected void onStart() { - super.onStart(); - - - updateStatus (""); - - } + /* (non-Javadoc) + * @see android.app.Activity#onStart() + */ + protected void onStart() { + super.onStart(); + + + updateStatus (""); + + } - /* (non-Javadoc) - * @see android.app.Activity#onStop() - */ - protected void onStop() { - super.onStop(); - - //unbindService(); - } + /* (non-Javadoc) + * @see android.app.Activity#onStop() + */ + protected void onStop() { + super.onStop(); + + //unbindService(); + } - /* - * Launch the system activity for Uri viewing with the provided url - */ - private void openBrowser(String url) - { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); - - } - - - - /* - * Show the help view - a popup dialog - */ - private void showHelp () - { - + /* + * Launch the system activity for Uri viewing with the provided url + */ + private void openBrowser(String url) + { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); + + } + + + + /* + * Show the help view - a popup dialog + */ + private void showHelp () + { + new WizardHelper(this).showWizard(); - } - - + } + + /* * Load the basic settings application to display torrc */ - private void showSettings () - { - - startActivityForResult(new Intent(this, SettingsPreferences.class), 1); - } - - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (requestCode == 1 && resultCode == 1010 && mService != null) - { - new ProcessSettingsAsyncTask().execute(mService); - } - } - - AlertDialog aDialog = null; - - private void showAlert(String title, String msg, boolean button) - { - try - { - if (aDialog != null && aDialog.isShowing()) - aDialog.dismiss(); - } - catch (Exception e){} //swallow any errors - - if (button) - { - aDialog = new AlertDialog.Builder(this) - .setIcon(R.drawable.icon) - .setTitle(title) - .setMessage(msg) - .setPositiveButton(android.R.string.ok, null) - .show(); - } - else - { - aDialog = new AlertDialog.Builder(this) - .setIcon(R.drawable.icon) - .setTitle(title) - .setMessage(msg) - .show(); - } - - aDialog.setCanceledOnTouchOutside(true); - } + private void showSettings () + { + + startActivityForResult(new Intent(this, SettingsPreferences.class), 1); + } + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + //if we get a response from an activity we launched (like from line 527 where we launch the Settings/Prefs screen) + //and the resultCode matches our arbitrary 1010 value, AND Tor is running + //then update the preferences in an async background task + if (requestCode == 1 && resultCode == 1010 && mService != null) + { + new ProcessSettingsAsyncTask().execute(mService); + } + } + + AlertDialog aDialog = null; + + //general alert dialog for mostly Tor warning messages + //sometimes this can go haywire or crazy with too many error + //messages from Tor, and the user cannot stop or exit Orbot + //so need to ensure repeated error messages are not spamming this method + private void showAlert(String title, String msg, boolean button) + { + try + { + if (aDialog != null && aDialog.isShowing()) + aDialog.dismiss(); + } + catch (Exception e){} //swallow any errors + + if (button) + { + aDialog = new AlertDialog.Builder(this) + .setIcon(R.drawable.icon) + .setTitle(title) + .setMessage(msg) + .setPositiveButton(android.R.string.ok, null) + .show(); + } + else + { + aDialog = new AlertDialog.Builder(this) + .setIcon(R.drawable.icon) + .setTitle(title) + .setMessage(msg) + .show(); + } + + aDialog.setCanceledOnTouchOutside(true); + } /* * Set the state of the running/not running graphic and label + * this all needs to be looked at w/ the shift to progressDialog */ public void updateStatus (String torServiceMsg) { - try - { - - if (mService != null) - torStatus = mService.getStatus(); - - if (imgStatus != null) - { - - if (torStatus == STATUS_ON) - { - imgStatus.setImageResource(R.drawable.toron); + try + { + //if the serivce is bound, query it for the curren status value (int) + if (mService != null) + torStatus = mService.getStatus(); + + //now update the layout_main UI based on the status + if (imgStatus != null) + { + + if (torStatus == STATUS_ON) + { + imgStatus.setImageResource(R.drawable.toron); - hideProgressDialog(); - - String lblMsg = getString(R.string.status_activated); - //+ "\n" + torServiceMsg; - - lblStatus.setText(lblMsg); - - if (torServiceMsg.length() > 0) - showAlert("Update", torServiceMsg, false); - - boolean showFirstTime = prefs.getBoolean("connect_first_time",true); - - if (showFirstTime) - { - - Editor pEdit = prefs.edit(); - - pEdit.putBoolean("connect_first_time",false); - - pEdit.commit(); - - showAlert(getString(R.string.status_activated),getString(R.string.connect_first_time),true); - - } - - if (mItemOnOff != null) - mItemOnOff.setTitle(R.string.menu_stop); - + hideProgressDialog(); + + String lblMsg = getString(R.string.status_activated); + //+ "\n" + torServiceMsg; + + lblStatus.setText(lblMsg); + + if (torServiceMsg.length() > 0) + showAlert("Update", torServiceMsg, false); + + boolean showFirstTime = prefs.getBoolean("connect_first_time",true); + + if (showFirstTime) + { + + Editor pEdit = prefs.edit(); + + pEdit.putBoolean("connect_first_time",false); + + pEdit.commit(); + + showAlert(getString(R.string.status_activated),getString(R.string.connect_first_time),true); + + } + + if (mItemOnOff != null) + mItemOnOff.setTitle(R.string.menu_stop); + - } - else if (torStatus == STATUS_CONNECTING) - { - - imgStatus.setImageResource(R.drawable.torstarting); - - if (progressDialog != null) - progressDialog.setMessage(torServiceMsg); - - if (mItemOnOff != null) - mItemOnOff.setTitle(R.string.menu_stop); - - } - else if (torStatus == STATUS_OFF) - { - imgStatus.setImageResource(R.drawable.toroff); - + } + else if (torStatus == STATUS_CONNECTING) + { + + imgStatus.setImageResource(R.drawable.torstarting); + + if (progressDialog != null) + progressDialog.setMessage(torServiceMsg); + + if (mItemOnOff != null) + mItemOnOff.setTitle(R.string.menu_stop); + + } + else if (torStatus == STATUS_OFF) + { + imgStatus.setImageResource(R.drawable.toroff); + - hideProgressDialog(); - - lblStatus.setText(getString(R.string.status_shutting_down)); - - if (mItemOnOff != null) - mItemOnOff.setTitle(R.string.menu_start); - } - else - { + hideProgressDialog(); + + lblStatus.setText(getString(R.string.status_shutting_down)); + + if (mItemOnOff != null) + mItemOnOff.setTitle(R.string.menu_start); + } + else + { - hideProgressDialog(); - - imgStatus.setImageResource(R.drawable.toroff); - lblStatus.setText(getString(R.string.status_disabled) + "\n" + getString(R.string.press_to_start)); - - if (mItemOnOff != null) - mItemOnOff.setTitle(R.string.menu_start); - - } - } - - } - catch (RemoteException e) - { - Log.e(TAG,"remote exception updating status",e); - } - + hideProgressDialog(); + + imgStatus.setImageResource(R.drawable.toroff); + lblStatus.setText(getString(R.string.status_disabled) + "\n" + getString(R.string.press_to_start)); + + if (mItemOnOff != null) + mItemOnOff.setTitle(R.string.menu_start); + + } + } + + } + catch (RemoteException e) + { + Log.e(TAG,"remote exception updating status",e); + } + } + // guess what? this start's Tor! actually no it just requests via the local ITorService to the remote TorService instance + // to start Tor private void startTor () throws RemoteException { - - bindService(); - - mService.setProfile(TorServiceConstants.PROFILE_ON); //this means turn on - - imgStatus.setImageResource(R.drawable.torstarting); - lblStatus.setText(getString(R.string.status_starting_up)); - - Message msg = mHandler.obtainMessage(TorServiceConstants.ENABLE_TOR_MSG); - mHandler.sendMessage(msg); - - - + // here we bind AGAIN - at some point i think we had to bind multiple times just in case + // but i would love to clarify, clean this up + bindService(); + + // this is a bit of a strange/old/borrowed code/design i used to change the service state + // not sure it really makes sense when what we want to say is just "startTor" + mService.setProfile(TorServiceConstants.PROFILE_ON); //this means turn on + + //here we update the UI which is a bit sloppy and mixed up code wise + //might be best to just call updateStatus() instead of directly manipulating UI in this method - yep makes sense + imgStatus.setImageResource(R.drawable.torstarting); + lblStatus.setText(getString(R.string.status_starting_up)); + + + //we send a message here to the progressDialog i believe, but we can clarify that shortly + Message msg = mHandler.obtainMessage(TorServiceConstants.ENABLE_TOR_MSG); + mHandler.sendMessage(msg); + + + } + //now we stop Tor! amazing! private void stopTor () throws RemoteException { - if (mService != null) - { - mService.setProfile(TorServiceConstants.PROFILE_OFF); - Message msg = mHandler.obtainMessage(TorServiceConstants.DISABLE_TOR_MSG); - mHandler.sendMessage(msg); - } - + //if the service is bound, then turn it off, using the same "PROFILE_" technique + if (mService != null) + { + mService.setProfile(TorServiceConstants.PROFILE_OFF); + + //again this is related to the progress dialog or some other threaded UI object + Message msg = mHandler.obtainMessage(TorServiceConstants.DISABLE_TOR_MSG); + mHandler.sendMessage(msg); + } + } - /* + /* * (non-Javadoc) * @see android.view.View.OnClickListener#onClick(android.view.View) */ - public boolean onLongClick(View view) { - - - try - { - - if (mService == null) - { - - } - else if (mService.getStatus() == STATUS_READY) - { - - createProgressDialog(getString(R.string.status_starting_up)); + public boolean onLongClick(View view) { + + + try + { + + if (mService == null) + { + + } + else if (mService.getStatus() == STATUS_READY) + { + + createProgressDialog(getString(R.string.status_starting_up)); - startTor(); - } - else - { - - stopTor(); - - } - - } - catch (Exception e) - { - Log.d(TAG,"error onclick",e); - } - - return true; - } - + startTor(); + } + else + { + + stopTor(); + + } + + } + catch (Exception e) + { + Log.d(TAG,"error onclick",e); + } + + return true; + } + /** * This implementation is used to receive callbacks from the remote - * service. + * service. + * + * If we have this setup probably, we shouldn't have to poll or query status + * to the service, as it should send it as it changes or when we bind/unbind to it + * from this activity */ private ITorServiceCallback mCallback = new ITorServiceCallback.Stub() { /** @@ -684,50 +770,55 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants * NOT be running in our main thread like most other things -- so, * to update the UI, we need to use a Handler to hop over there. */ + + //receive a new string vaule end-user displayable message from the ITorService public void statusChanged(String value) { - Message msg = mHandler.obtainMessage(TorServiceConstants.STATUS_MSG); - msg.getData().putString(HANDLER_TOR_MSG, value); - mHandler.sendMessage(msg); + //pass it off to the progressDialog + Message msg = mHandler.obtainMessage(TorServiceConstants.STATUS_MSG); + msg.getData().putString(HANDLER_TOR_MSG, value); + mHandler.sendMessage(msg); } - @Override - public void logMessage(String value) throws RemoteException { - - Message msg = mHandler.obtainMessage(TorServiceConstants.LOG_MSG); - msg.getData().putString(HANDLER_TOR_MSG, value); - mHandler.sendMessage(msg); - - } + @Override //this was when we displayed the log in the main Activity; can prob take this out now + public void logMessage(String value) throws RemoteException { + + Message msg = mHandler.obtainMessage(TorServiceConstants.LOG_MSG); + msg.getData().putString(HANDLER_TOR_MSG, value); + mHandler.sendMessage(msg); + + } }; +// this is what takes messages or values from the callback threads or other non-mainUI threads +//and passes them back into the main UI thread for display to the user private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case TorServiceConstants.STATUS_MSG: - String torServiceMsg = (String)msg.getData().getString(HANDLER_TOR_MSG); - - updateStatus(torServiceMsg); - + String torServiceMsg = (String)msg.getData().getString(HANDLER_TOR_MSG); + + updateStatus(torServiceMsg); + break; case TorServiceConstants.LOG_MSG: - - + + break; case TorServiceConstants.ENABLE_TOR_MSG: - - - updateStatus((String)msg.getData().getString(HANDLER_TOR_MSG)); - - break; + + + updateStatus((String)msg.getData().getString(HANDLER_TOR_MSG)); + + break; case TorServiceConstants.DISABLE_TOR_MSG: - - updateStatus((String)msg.getData().getString(HANDLER_TOR_MSG)); - - break; - + + updateStatus((String)msg.getData().getString(HANDLER_TOR_MSG)); + + break; + default: super.handleMessage(msg); } @@ -741,6 +832,10 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants /** * Class for interacting with the main interface of the service. */ + // this is the connection that gets called back when a successfull bind occurs + // we should use this to activity monitor unbind so that we don't have to call + // bindService() a million times + private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { @@ -756,14 +851,15 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants try { mService.registerCallback(mCallback); + //again with the update status?!? :P updateStatus(""); if (autoStartOnBind) { - autoStartOnBind = false; - - startTor(); - + autoStartOnBind = false; + + startTor(); + } } catch (RemoteException e) { @@ -771,7 +867,7 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants // do anything with it; we can count on soon being // disconnected (and then reconnected if it can be restarted) // so there is no need to do anything here. - Log.d(TAG,"error registering callback to service",e); + Log.d(TAG,"error registering callback to service",e); } @@ -789,20 +885,26 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants } }; + //should move this up with all the other class variables boolean mIsBound = false; + //this is where we bind! private void bindService () { - bindService(new Intent(ITorService.class.getName()), + //since its auto create, we prob don't ever need to call startService + //also we should again be consistent with using either iTorService.class.getName() + //or the variable constant + bindService(new Intent(ITorService.class.getName()), mConnection, Context.BIND_AUTO_CREATE); - - mIsBound = true; + + mIsBound = true; } + //unbind removes the callback, and unbinds the service private void unbindService () { - if (mIsBound) { + if (mIsBound) { // If we have received the service, and hence registered with // it, then now is the time to unregister. if (mService != null) { @@ -813,7 +915,10 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants // There is nothing special we need to do if the service // has crashed. } - } + } + + //maybe needs this? + mService = null; // Detach our existing connection. unbindService(mConnection); @@ -821,26 +926,26 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants } } - + private void createProgressDialog (String msg) { - if (progressDialog != null && progressDialog.isShowing()) - return; - - progressDialog = ProgressDialog.show(Orbot.this, "", msg); - progressDialog.setCancelable(true); + if (progressDialog != null && progressDialog.isShowing()) + return; + + progressDialog = ProgressDialog.show(Orbot.this, "", msg); + progressDialog.setCancelable(true); } private void hideProgressDialog () { - if (progressDialog != null && progressDialog.isShowing()) - { - progressDialog.dismiss(); + if (progressDialog != null && progressDialog.isShowing()) + { + progressDialog.dismiss(); - } - - + } + + } } diff --git a/src/org/torproject/android/boot/OnbootBroadcastReceiver.java b/src/org/torproject/android/boot/OnbootBroadcastReceiver.java deleted file mode 100644 index 163e708c..00000000 --- a/src/org/torproject/android/boot/OnbootBroadcastReceiver.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.torproject.android.boot; - -import org.torproject.android.service.ITorService; -import org.torproject.android.service.TorService; -import org.torproject.android.service.TorServiceConstants; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.util.Log; - -public class OnbootBroadcastReceiver extends BroadcastReceiver implements TorServiceConstants { - @Override - public void onReceive(Context context, Intent intent) { - - Log.d(TAG, "received on boot notification"); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - boolean startOnBoot = prefs.getBoolean("pref_start_boot",true); - - Log.d(TAG, "startOnBoot:" + startOnBoot); - - if (startOnBoot) - { - Intent serviceIntent = new Intent(context,TorService.class); - serviceIntent.setAction("onboot"); - context.startService(serviceIntent); - } - - //bindService(new Intent(ITorService.class.getName()), - // mConnection, Context.BIND_AUTO_CREATE); - } - -} \ No newline at end of file diff --git a/src/org/torproject/android/service/TorService.java b/src/org/torproject/android/service/TorService.java index 4be1eeef..1b114923 100644 --- a/src/org/torproject/android/service/TorService.java +++ b/src/org/torproject/android/service/TorService.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ +/* Copyright (c) 2009-2011, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ /* See LICENSE for licensing information */ package org.torproject.android.service; @@ -545,6 +545,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false); boolean transProxyAll = prefs.getBoolean("pref_transparent_all", false); boolean transProxyPortFallback = prefs.getBoolean("pref_transparent_port_fallback", false); + boolean transProxyTethering = prefs.getBoolean("pref_transparent_tethering", false); TorService.logMessage ("Transparent Proxying: " + enableTransparentProxy); @@ -581,6 +582,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable showAlert("Status", "Setting up app-based transparent proxying..."); code = TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this)); } + } TorService.logMessage ("TorTransProxy resp code: " + code); @@ -588,11 +590,22 @@ public class TorService extends Service implements TorServiceConstants, Runnable if (code == 0) { showAlert("Status", "Transparent proxying ENABLED"); + + + + if (transProxyTethering) + { + showAlert("Status", "TransProxy enabled for Tethering!"); + + TorTransProxy.enableTetheringRules(this); + } } else { showAlert("Status", "WARNING: error starting transparent proxying!"); } + + return true; diff --git a/src/org/torproject/android/service/TorTransProxy.java b/src/org/torproject/android/service/TorTransProxy.java index 548dda64..de8ea83c 100644 --- a/src/org/torproject/android/service/TorTransProxy.java +++ b/src/org/torproject/android/service/TorTransProxy.java @@ -313,14 +313,12 @@ public class TorTransProxy implements TorServiceConstants { return code; } - public static int enableWifiHotspotRules (Context context) throws Exception + public static int enableTetheringRules (Context context) throws Exception { boolean runRoot = true; boolean waitFor = true; - //redirectDNSResolvConf(); //not working yet - String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath(); StringBuilder script = new StringBuilder(); @@ -328,25 +326,24 @@ public class TorTransProxy implements TorServiceConstants { StringBuilder res = new StringBuilder(); int code = -1; - script.append(ipTablesPath); - script.append(" -I FORWARD"); - script.append(" -m state --state ESTABLISHED,RELATED -j ACCEPT"); - script.append(" || exit\n"); - - script.append(ipTablesPath); - script.append(" -I FORWARD"); - script.append(" -j ACCEPT"); - script.append(" || exit\n"); - - /* - script.append(ipTablesPath); - script.append(" -P FORWARD DROP"); - script.append(" || exit\n"); - */ - - script.append(ipTablesPath); - script.append(" -t nat -I POSTROUTING -j MASQUERADE"); - script.append(" || exit\n"); + String[] hwinterfaces = {"usb0","wl0.1"}; + + for (int i = 0; i < hwinterfaces.length; i++) + { + script.append(ipTablesPath); + script.append(" -t nat -A PREROUTING -i "); + script.append(hwinterfaces[i]); + script.append(" -p udp --dport 53 -j REDIRECT --to-ports "); + script.append(TOR_DNS_PORT); + script.append(" || exit\n"); + + script.append(ipTablesPath); + script.append(" -t nat -A PREROUTING -i "); + script.append(hwinterfaces[i]); + script.append(" -p tcp -j REDIRECT --to-ports "); + script.append(TOR_TRANSPROXY_PORT); + script.append(" || exit\n"); + } String[] cmdAdd = {script.toString()}; @@ -374,8 +371,6 @@ public class TorTransProxy implements TorServiceConstants { purgeIptables(context); - enableWifiHotspotRules(context); - int torUid = context.getApplicationInfo().uid; // Set up port redirection