added "check" yes/no dialog prompt; debuged iptables/transprox settings on Android 1.6 and 2.2

svn:r22901
This commit is contained in:
Nathan Freitas 2010-08-14 05:08:55 +00:00
parent 22caae8989
commit c288383db1
12 changed files with 534 additions and 185 deletions

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.torproject.android" package="org.torproject.android" android:versionName="0.2.2.14-orbot-alpha-1.0.2" android:versionCode="8">
android:versionName="0.2.2.14-orbot-alpha-1.0.2" android:versionCode="8">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="false">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Orbot" <activity android:name=".Orbot"
android:theme="@android:style/Theme.NoTitleBar" android:theme="@android:style/Theme.NoTitleBar"
@ -19,13 +19,22 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
</intent-filter> </intent-filter>
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="org.torproject.android.REQUEST_HS_PORT" />
</intent-filter>
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="org.torproject.android.START_TOR" />
</intent-filter>
</activity> </activity>
<activity android:name=".SettingsPreferences" android:label="@string/app_name"/> <activity android:name=".SettingsPreferences" android:label="@string/app_name"/>
<activity android:name=".AppManager" android:label="@string/app_name"/> <activity android:name=".AppManager" android:label="@string/app_name"/>
<activity android:name=".WizardActivity" android:label="@string/app_name"/> <activity android:name=".WizardActivity" android:label="@string/app_name"/>
<service android:name=".service.TorService" android:process=":remote" android:debuggable="false"> <service android:name=".service.TorService" android:process=":remote">
<intent-filter> <intent-filter>
<action android:name="org.torproject.android.service.ITorService" /> <action android:name="org.torproject.android.service.ITorService" />
<action android:name="org.torproject.android.service.TOR_SERVICE" /> <action android:name="org.torproject.android.service.TOR_SERVICE" />

Binary file not shown.

View File

@ -1,9 +1,8 @@
SocksPort 9050 SocksPort 9050
SocksListenAddress 127.0.0.1 SocksListenAddress 127.0.0.1
SafeSocks 1 SafeSocks 1
DNSPort 5400
Log notice stdout Log notice stdout
Log debug syslog ##Log debug syslog
DataDirectory /data/data/org.torproject.android/data DataDirectory /data/data/org.torproject.android/data
ControlPort 9051 ControlPort 9051
CookieAuthentication 1 CookieAuthentication 1
@ -12,3 +11,4 @@ RelayBandwidthBurst 20 KBytes
UseBridges 0 UseBridges 0
AutomapHostsOnResolve 1 AutomapHostsOnResolve 1
TransPort 9040 TransPort 9040
DNSPort 5400

View File

@ -10,5 +10,5 @@
# Indicates whether an apk should be generated for each density. # Indicates whether an apk should be generated for each density.
split.density=false split.density=false
# Project target. # Project target.
target=Google Inc.:Google APIs:3 target=android-3
apk-configurations= apk-configurations=

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="pref_hs_group">Hidden Services</string>
<string name="app_name">Orbot</string> <string name="app_name">Orbot</string>
<string name="app_version">1.0.2</string> <string name="app_version">1.0.2</string>
<string name="internal_web_url">http://orbot/</string> <string name="internal_web_url">http://orbot/</string>
@ -72,6 +73,9 @@ and all DNS requests. This includes the built-in Browser, Gmail, YouTube and Map
<string name="btn_back">Back</string> <string name="btn_back">Back</string>
<string name="btn_finish">Finish</string> <string name="btn_finish">Finish</string>
<string name="btn_okay">Okay</string>
<string name="btn_cancel">Cancel</string>
<!-- Welcome Wizard strings (DJH) --> <!-- Welcome Wizard strings (DJH) -->
<string name="wizard_welcome_msg">Orbot brings Tor to Android. Tor is free software and an open network that helps you defend against a form of network surveillance that threatens personal freedom and privacy, confidential business activities and relationships, and state security known as traffic analysis.\n\n*WARNING:* Simply installing Orbot will _not_ magically anonymize your mobile traffic! This wizard will help you get started.</string> <string name="wizard_welcome_msg">Orbot brings Tor to Android. Tor is free software and an open network that helps you defend against a form of network surveillance that threatens personal freedom and privacy, confidential business activities and relationships, and state security known as traffic analysis.\n\n*WARNING:* Simply installing Orbot will _not_ magically anonymize your mobile traffic! This wizard will help you get started.</string>
@ -115,4 +119,5 @@ and all DNS requests. This includes the built-in Browser, Gmail, YouTube and Map
<string name="connect_first_time"> You\'ve successfully connected to the Tor network - but this does NOT mean your device is secure. You can use the \'Check\' option from the menu to test your browser. \n\nVisit us at https://guardianproject.info/apps/orbot or send an email to help@guardianproject.info to learn more.</string> <string name="connect_first_time"> You\'ve successfully connected to the Tor network - but this does NOT mean your device is secure. You can use the \'Check\' option from the menu to test your browser. \n\nVisit us at https://guardianproject.info/apps/orbot or send an email to help@guardianproject.info to learn more.</string>
<string name="tor_check">This will open your default web browser to https://check.torproject.org in order to see if Orbot is probably configured and you are connected to Tor.</string>
</resources> </resources>

View File

@ -27,16 +27,6 @@ android:enabled="true"/>
</PreferenceCategory> </PreferenceCategory>
<!--
<PreferenceCategory android:title="Web Proxy">
<Preference
android:defaultValue=""
android:key="pref_web_proxy"
android:title="Open Proxy Panel"
android:summary="Set HTTP Settings (Android 2.x Experimental)"
android:enabled="true"/>
</PreferenceCategory>
-->
<PreferenceCategory android:title="Bridges"> <PreferenceCategory android:title="Bridges">
@ -100,4 +90,9 @@ android:dialogTitle="Enter ports"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_hs_group"><CheckBoxPreference android:title="Enable Hidden Services" android:summary="run servers accessible via the Tor network" android:key="pref_hs_enable"></CheckBoxPreference>
<EditTextPreference android:summary="enter localhost ports for hidden services" android:title="Hidden Service Ports" android:enabled="false" android:key="pref_hs_ports"></EditTextPreference>
<EditTextPreference android:key="pref_hs_hostname" android:summary="the addressable name for your hidden service (generated automatically)" android:title=".Onion Hostname"></EditTextPreference>
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@ -3,10 +3,15 @@
package org.torproject.android; package org.torproject.android;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.torproject.android.service.ITorService; import org.torproject.android.service.ITorService;
import org.torproject.android.service.ITorServiceCallback; import org.torproject.android.service.ITorServiceCallback;
import org.torproject.android.service.TorServiceConstants;
import org.torproject.android.service.TorTransProxy; import org.torproject.android.service.TorTransProxy;
import android.app.Activity; import android.app.Activity;
@ -62,6 +67,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
/* Tor Service interaction */ /* Tor Service interaction */
/* The primary interface we will be calling on the service. */ /* The primary interface we will be calling on the service. */
ITorService mService = null; ITorService mService = null;
private boolean autoStartOnBind = false;
Orbot mOrbot = null; Orbot mOrbot = null;
@ -147,15 +153,11 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
} }
else if (item.getItemId() == 4) else if (item.getItemId() == 4)
{ {
this.showSettings(); showSettings();
} }
else if (item.getItemId() == 6) else if (item.getItemId() == 6)
{ {
this.showMessageLog(); showMessageLog();
}
else if (item.getItemId() == 2)
{
openBrowser(URL_TOR_CHECK);
} }
else if (item.getItemId() == 3) else if (item.getItemId() == 3)
{ {
@ -163,8 +165,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
} }
else if (item.getItemId() == 7) else if (item.getItemId() == 7)
{ {
//launch check.torproject.org doTorCheck();
openBrowser(URL_TOR_CHECK);
} }
else if (item.getItemId() == 8) else if (item.getItemId() == 8)
{ {
@ -180,15 +181,17 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
private void doExit () private void doExit ()
{ {
try { try {
stopTor(); stopTor();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancelAll();
unbindService(); unbindService();
stopService(new Intent(ITorService.class.getName())); stopService(new Intent(ITorService.class.getName()));
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancelAll();
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w(TAG, e); Log.w(TAG, e);
@ -247,6 +250,69 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
logBuffer.append(logText); logBuffer.append(logText);
} }
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;
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();
}
private void enableHiddenServicePort (int hsPort)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mOrbot);
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();
try {
processSettings();
String onionHostname = getHiddenServiceHostname();
Intent nResult = new Intent();
nResult.putExtra("hs_host", onionHostname);
setResult(RESULT_OK, nResult);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/* (non-Javadoc) /* (non-Javadoc)
* @see android.app.Activity#onResume() * @see android.app.Activity#onResume()
*/ */
@ -254,33 +320,80 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
super.onResume(); super.onResume();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancelAll();
String action = getIntent().getAction();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mOrbot); if (action != null)
boolean showWizard = prefs.getBoolean("show_wizard",true);
if (showWizard)
{ {
if (action.equals("org.torproject.android.REQUEST_HS_PORT"))
{
Editor pEdit = prefs.edit(); DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
pEdit.putBoolean("show_wizard",false); int hsPort = getIntent().getIntExtra("hs_port", -1);
pEdit.commit(); enableHiddenServicePort (hsPort);
finish();
break;
case DialogInterface.BUTTON_NEGATIVE:
//No button clicked
finish();
break;
}
}
};
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();
}
showHelp();
} }
else else
{ {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancelAll();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mOrbot);
boolean showWizard = prefs.getBoolean("show_wizard",true);
if (showWizard)
{
Editor pEdit = prefs.edit();
pEdit.putBoolean("show_wizard",false);
pEdit.commit();
showHelp();
}
} }
} }
/* (non-Javadoc) /* (non-Javadoc)
@ -293,8 +406,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
startService(new Intent(INTENT_TOR_SERVICE)); startService(new Intent(INTENT_TOR_SERVICE));
bindService (); bindService ();
//updateStatus (""); updateStatus ("");
} }
@ -414,8 +526,12 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
boolean ReachableAddresses = prefs.getBoolean(PREF_REACHABLE_ADDRESSES,false); boolean ReachableAddresses = prefs.getBoolean(PREF_REACHABLE_ADDRESSES,false);
boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false);
boolean enableTransparentProxy = prefs.getBoolean(PREF_TRANSPARENT, false); boolean enableTransparentProxy = prefs.getBoolean(PREF_TRANSPARENT, false);
mService.updateTransProxy(); mService.updateTransProxy();
String bridgeList = prefs.getString(PREF_BRIDGES_LIST,""); String bridgeList = prefs.getString(PREF_BRIDGES_LIST,"");
@ -469,6 +585,10 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
mService.updateConfiguration("ReachableAddresses", ReachableAddressesPorts, false); mService.updateConfiguration("ReachableAddresses", ReachableAddressesPorts, false);
} }
else
{
mService.updateConfiguration("ReachableAddresses", "", false);
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -487,6 +607,12 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
mService.updateConfiguration("ExitPolicy", "reject *:*", false); mService.updateConfiguration("ExitPolicy", "reject *:*", false);
} }
else
{
mService.updateConfiguration("ORPort", "", false);
mService.updateConfiguration("Nickname", "", false);
mService.updateConfiguration("ExitPolicy", "", false);
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -495,8 +621,48 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
return; return;
} }
if (mService != null) if (enableHiddenServices)
mService.saveConfiguration(); {
mService.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;
}
mService.updateConfiguration("HiddenServicePort",hsPortConfig, false);
}
//force save now so the hostname file gets generated
mService.saveConfiguration();
String onionHostname = getHiddenServiceHostname();
if (onionHostname != null)
{
Editor pEdit = prefs.edit();
pEdit.putString("pref_hs_hostname",onionHostname);
pEdit.commit();
}
}
else
{
mService.updateConfiguration("HiddenServiceDir","", false);
}
mService.saveConfiguration();
} }
catch (Exception e) catch (Exception e)
{ {
@ -509,6 +675,20 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
} }
private String getHiddenServiceHostname ()
{
String appHome = "/data/data/" + TorServiceConstants.TOR_APP_USERNAME + "/";
File file = new File(appHome, "hostname");
try {
String onionHostname = Utils.readString(new FileInputStream(file));
return onionHostname.trim();
} catch (FileNotFoundException e) {
Log.i(TAG, "unable to read onion hostname file",e);
return null;
}
}
private void showAlert(String title, String msg) private void showAlert(String title, String msg)
{ {
@ -561,7 +741,21 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
} }
boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false);
if (enableHiddenServices)
{
String onionHostname = getHiddenServiceHostname();
if (onionHostname != null)
{
Editor pEdit = prefs.edit();
pEdit.putString("pref_hs_hostname",onionHostname);
pEdit.commit();
}
}
} }
@ -651,14 +845,18 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
else if (mService.getStatus() == STATUS_READY) else if (mService.getStatus() == STATUS_READY)
{ {
startTor(); if (event.getAction() == MotionEvent.ACTION_UP)
{
startTor();
}
} }
else else
{ {
stopTor(); if (event.getAction() == MotionEvent.ACTION_DOWN)
{
stopTor();
}
} }
} }
@ -804,11 +1002,22 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
// connected to it. // connected to it.
try { try {
mService.registerCallback(mCallback); mService.registerCallback(mCallback);
if (autoStartOnBind)
{
autoStartOnBind = false;
startTor();
}
} catch (RemoteException e) { } catch (RemoteException e) {
// In this case the service has crashed before we could even // In this case the service has crashed before we could even
// do anything with it; we can count on soon being // do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted) // disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here. // so there is no need to do anything here.
Log.i(TAG,"error registering callback to service",e);
} }
@ -844,8 +1053,6 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
try { try {
mService.unregisterCallback(mCallback); mService.unregisterCallback(mCallback);
} catch (RemoteException e) { } catch (RemoteException e) {
// There is nothing special we need to do if the service // There is nothing special we need to do if the service
// has crashed. // has crashed.

View File

@ -3,7 +3,6 @@
package org.torproject.android; package org.torproject.android;
import org.torproject.android.service.TorServiceUtils;
import org.torproject.android.service.TorTransProxy; import org.torproject.android.service.TorTransProxy;
import android.content.Intent; import android.content.Intent;
@ -21,8 +20,7 @@ public class SettingsPreferences
private CheckBoxPreference prefCBTransProxy = null; private CheckBoxPreference prefCBTransProxy = null;
private CheckBoxPreference prefcBTransProxyAll = null; private CheckBoxPreference prefcBTransProxyAll = null;
private Preference prefTransProxyApps = null; private Preference prefTransProxyApps = null;
private Preference prefWebProxy = null; private CheckBoxPreference prefHiddenServices = null;
private boolean hasRoot = false; private boolean hasRoot = false;
@ -37,7 +35,6 @@ public class SettingsPreferences
} }
@Override @Override
protected void onResume() { protected void onResume() {
@ -63,10 +60,13 @@ public class SettingsPreferences
} }
//disabled for now 28/07 nf prefHiddenServices = ((CheckBoxPreference)((PreferenceCategory)this.getPreferenceScreen().getPreference(4)).getPreference(0));
//prefWebProxy = ((PreferenceCategory)this.getPreferenceScreen().getPreference(1)).getPreference(0); prefHiddenServices.setOnPreferenceClickListener(this);
//prefWebProxy.setOnPreferenceClickListener(this); ((PreferenceCategory)this.getPreferenceScreen().getPreference(4)).getPreference(1).setEnabled(prefHiddenServices.isChecked());
} ((PreferenceCategory)this.getPreferenceScreen().getPreference(4)).getPreference(2).setEnabled(prefHiddenServices.isChecked());
};
@ -89,18 +89,13 @@ public class SettingsPreferences
{ {
startActivity(new Intent(this, AppManager.class)); startActivity(new Intent(this, AppManager.class));
} }
/* else if (preference == prefHiddenServices)
else if (preference == prefWebProxy)
{ {
Intent intent = new Intent();
intent.setClassName(this,"com.android.settings.ProxySelector");
intent.putExtra("title", "Set host=127.0.0.1 and port=8118");
intent.putExtra("button-label", "Save");
startActivity(intent); ((PreferenceCategory)this.getPreferenceScreen().getPreference(4)).getPreference(1).setEnabled(prefHiddenServices.isChecked());
((PreferenceCategory)this.getPreferenceScreen().getPreference(4)).getPreference(2).setEnabled(prefHiddenServices.isChecked());
}
}*/
else else
{ {
prefcBTransProxyAll.setEnabled(prefCBTransProxy.isChecked()); prefcBTransProxyAll.setEnabled(prefCBTransProxy.isChecked());

View File

@ -38,10 +38,7 @@ public class TorBinaryInstaller implements TorServiceConstants {
boolean privoxyBinaryExists = new File(installPath + PRIVOXY_ASSET_KEY).exists(); boolean privoxyBinaryExists = new File(installPath + PRIVOXY_ASSET_KEY).exists();
Log.i(TAG,"Privoxy binary exists=" + privoxyBinaryExists); Log.i(TAG,"Privoxy binary exists=" + privoxyBinaryExists);
boolean iptablesBinaryExists = new File(installPath + IPTABLES_ASSET_KEY).exists(); if (!(torBinaryExists && privoxyBinaryExists) || force)
Log.i(TAG,"IPTables binary exists=" + iptablesBinaryExists);
if (!(torBinaryExists && privoxyBinaryExists && iptablesBinaryExists) || force)
installFromZip (); installFromZip ();
} }
@ -72,9 +69,6 @@ public class TorBinaryInstaller implements TorServiceConstants {
zipen = zip.getEntry(ASSETS_BASE + PRIVOXYCONFIG_ASSET_KEY); zipen = zip.getEntry(ASSETS_BASE + PRIVOXYCONFIG_ASSET_KEY);
streamToFile(zip.getInputStream(zipen),installPath + PRIVOXYCONFIG_ASSET_KEY); streamToFile(zip.getInputStream(zipen),installPath + PRIVOXYCONFIG_ASSET_KEY);
zipen = zip.getEntry(ASSETS_BASE + IPTABLES_ASSET_KEY);
streamToFile(zip.getInputStream(zipen),installPath + IPTABLES_ASSET_KEY);
zip.close(); zip.close();

View File

@ -401,13 +401,11 @@ public class TorService extends Service implements TorServiceConstants, Runnable
torBinaryPath = appHome + TOR_BINARY_ASSET_KEY; torBinaryPath = appHome + TOR_BINARY_ASSET_KEY;
privoxyPath = appHome + PRIVOXY_ASSET_KEY; privoxyPath = appHome + PRIVOXY_ASSET_KEY;
String iptablesPath = appHome + IPTABLES_ASSET_KEY;
boolean torBinaryExists = new File(torBinaryPath).exists(); boolean torBinaryExists = new File(torBinaryPath).exists();
boolean privoxyBinaryExists = new File(privoxyPath).exists(); boolean privoxyBinaryExists = new File(privoxyPath).exists();
boolean iptablesBinaryExists = new File(iptablesPath).exists();
if (!(torBinaryExists && privoxyBinaryExists && iptablesBinaryExists)) if (!(torBinaryExists && privoxyBinaryExists))
{ {
killTorProcess (); killTorProcess ();
@ -417,7 +415,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
torBinaryExists = new File(torBinaryPath).exists(); torBinaryExists = new File(torBinaryPath).exists();
privoxyBinaryExists = new File(privoxyPath).exists(); privoxyBinaryExists = new File(privoxyPath).exists();
if (torBinaryExists && privoxyBinaryExists && iptablesBinaryExists) if (torBinaryExists && privoxyBinaryExists)
{ {
logNotice(getString(R.string.status_install_success)); logNotice(getString(R.string.status_install_success));
@ -439,9 +437,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
logNotice("Found Tor binary: " + torBinaryPath); logNotice("Found Tor binary: " + torBinaryPath);
logNotice("Found privoxy binary: " + privoxyPath); logNotice("Found Privoxy binary: " + privoxyPath);
logNotice("Found iptables binary: " + iptablesPath);
} }
@ -455,9 +452,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable
String[] cmd2 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + privoxyPath}; String[] cmd2 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + privoxyPath};
TorServiceUtils.doShellCommand(cmd2, log, false, true); TorServiceUtils.doShellCommand(cmd2, log, false, true);
logNotice("(re)Setting permission on iptables binary");
String[] cmd3 = {SHELL_CMD_CHMOD + ' ' + CHMOD_EXE_VALUE + ' ' + iptablesPath};
TorServiceUtils.doShellCommand(cmd3, log, false, true);
return true; return true;
} }
@ -947,8 +941,17 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
//turn on //turn on
try
{
setupTransProxy(currentStatus == STATUS_ON);
return true;
}
catch (Exception e)
{
Log.i(TAG, "error enabling transproxy",e);
return setupTransProxy(currentStatus == STATUS_ON); return false;
}
} }
public String getConfiguration (String name) public String getConfiguration (String name)
@ -993,7 +996,19 @@ public class TorService extends Service implements TorServiceConstants, Runnable
if (configBuffer == null) if (configBuffer == null)
configBuffer = new ArrayList<String>(); configBuffer = new ArrayList<String>();
configBuffer.add(name + ' ' + value); if (value == null || value.length() == 0)
{
if (conn != null)
{
try {
conn.resetConf(Arrays.asList(new String[]{name}));
} catch (IOException e) {
Log.w(TAG, "Unable to reset conf",e);
}
}
}
else
configBuffer.add(name + ' ' + value);
return false; return false;
} }
@ -1007,7 +1022,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable
if (configBuffer != null) if (configBuffer != null)
{ {
conn.setConf(configBuffer); conn.setConf(configBuffer);
//conn.saveConf();
configBuffer = null; configBuffer = null;
} }
@ -1083,6 +1097,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable
boolean ReachableAddresses = prefs.getBoolean(TorConstants.PREF_REACHABLE_ADDRESSES,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); boolean enableTransparentProxy = prefs.getBoolean(TorConstants.PREF_TRANSPARENT, false);
@ -1137,6 +1153,10 @@ public class TorService extends Service implements TorServiceConstants, Runnable
mBinder.updateConfiguration("ReachableAddresses", ReachableAddressesPorts, false); mBinder.updateConfiguration("ReachableAddresses", ReachableAddressesPorts, false);
} }
else
{
mBinder.updateConfiguration("ReachableAddresses", "", false);
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -1155,6 +1175,12 @@ public class TorService extends Service implements TorServiceConstants, Runnable
mBinder.updateConfiguration("ExitPolicy", "reject *:*", false); mBinder.updateConfiguration("ExitPolicy", "reject *:*", false);
} }
else
{
mBinder.updateConfiguration("ORPort", "", false);
mBinder.updateConfiguration("Nickname", "", false);
mBinder.updateConfiguration("ExitPolicy", "", false);
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -1163,12 +1189,41 @@ public class TorService extends Service implements TorServiceConstants, Runnable
return; 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);
}
}
else
{
mBinder.updateConfiguration("HiddenServiceDir","", false);
}
mBinder.saveConfiguration(); mBinder.saveConfiguration();
} }
private boolean setupTransProxy (boolean enabled) private boolean setupTransProxy (boolean enabled) throws Exception
{ {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplication()); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplication());
@ -1187,27 +1242,19 @@ public class TorService extends Service implements TorServiceConstants, Runnable
if (hasRoot && enableTransparentProxy) if (hasRoot && enableTransparentProxy)
{ {
try
{
TorTransProxy.setDNSProxying();
boolean success = TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this),transProxyAll);
logNotice ("TorTransProxy enabled: " + success); //TorTransProxy.setDNSProxying();
int code = TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this),transProxyAll);
logNotice ("TorTransProxy resp code: " + code);
return true; return true;
} catch (Exception e) {
logNotice("WARNING: Error configuring transparenty proxying: " + e.getMessage());
Log.w(TAG, "error refreshing iptables: err=" + e.getMessage(), e);
return false;
}
} }
else else
{ {
TorTransProxy.purgeIptables(); TorTransProxy.purgeIptables(this,AppManager.getApps(this));
} }
} }
@ -1215,7 +1262,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
{ {
if (hasRoot) if (hasRoot)
{ {
TorTransProxy.purgeIptables(); TorTransProxy.purgeIptables(this,AppManager.getApps(this));
} }
} }

View File

@ -27,9 +27,6 @@ public interface TorServiceConstants {
//privoxy.config //privoxy.config
public final static String PRIVOXYCONFIG_ASSET_KEY = "privoxy.config"; public final static String PRIVOXYCONFIG_ASSET_KEY = "privoxy.config";
//iptables key
public final static String IPTABLES_ASSET_KEY = "iptables";
//various console cmds //various console cmds
public final static String SHELL_CMD_CHMOD = "chmod"; public final static String SHELL_CMD_CHMOD = "chmod";
public final static String SHELL_CMD_KILL = "kill"; public final static String SHELL_CMD_KILL = "kill";

View File

@ -20,6 +20,7 @@ public class TorTransProxy {
private final static String IPTABLES_ADD = " -A "; private final static String IPTABLES_ADD = " -A ";
//private final static String CMD_DNS_PROXYING_DELETE = "iptables -t nat -D PREROUTING -p udp --dport 53 -j DNAT --to 127.0.0.1:5400 || exit\n"; //private final static String CMD_DNS_PROXYING_DELETE = "iptables -t nat -D PREROUTING -p udp --dport 53 -j DNAT --to 127.0.0.1:5400 || exit\n";
// - just calling a system wide flush of iptables rules // - just calling a system wide flush of iptables rules
//private final static String IPTABLES_DELETE = " -D "; //not deleting manually anymore - just calling a system wide flush of iptables rules //private final static String IPTABLES_DELETE = " -D "; //not deleting manually anymore - just calling a system wide flush of iptables rules
@ -51,6 +52,40 @@ public class TorTransProxy {
return false; return false;
} }
/**
* 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 exitCode = TorServiceUtils.doShellCommand(cmd, log, true, true);
String out = log.toString();
if (out.indexOf(" v")!=-1)
{
out = out.substring(out.indexOf(" v")+2);
out = out.substring(0,out.indexOf(":"));
return out;
}
} catch (Exception e) {
Log.w(TAG,"Error checking iptables version: " + e.getMessage() ,e);
}
Log.w(TAG, "Could not acquire check iptables: " + log.toString());
return null;
}
private static String findBaseDir () private static String findBaseDir ()
{ {
/* /*
@ -72,10 +107,11 @@ public class TorTransProxy {
return BASE_DIR; return BASE_DIR;
}*/ }*/
return "/system/bin/"; return "";
} }
/*
public static int setDNSProxying () throws Exception public static int setDNSProxying () throws Exception
{ {
String baseDir = findBaseDir(); String baseDir = findBaseDir();
@ -91,7 +127,7 @@ public class TorTransProxy {
return code; return code;
} }*/
/* /*
public static int setIptablesDropAll() { public static int setIptablesDropAll() {
@ -109,6 +145,45 @@ public class TorTransProxy {
} }
*/ */
public static int purgeIptables(Context context, TorifiedApp[] apps) throws Exception {
String baseDir = findBaseDir();
final StringBuilder script = new StringBuilder();
StringBuilder res = new StringBuilder();
int code = -1;
for (int i = 0; i < apps.length; i++)
{
//flush nat for every app
script.append(baseDir);
script.append("iptables -t nat -m owner --uid-owner ");
script.append(apps[i].getUid());
script.append(" -F || exit\n");
script.append("iptables -t filter -m owner --uid-owner ");
script.append(apps[i].getUid());
script.append(" -F || exit\n");
}
String[] cmd = {script.toString()};
Log.i(TAG, cmd[0]);
code = TorServiceUtils.doShellCommand(cmd, res, true, true);
String msg = res.toString();
Log.i(TAG, msg);
return code;
}
/*
public static boolean purgeIptables() { public static boolean purgeIptables() {
String baseDir = findBaseDir(); String baseDir = findBaseDir();
@ -129,96 +204,121 @@ public class TorTransProxy {
Log.w(TAG,"error purging iptables: " + e); Log.w(TAG,"error purging iptables: " + e);
return false; return false;
} }
} }*/
public static boolean setTransparentProxyingByApp(Context context, TorifiedApp[] apps, boolean forceAll) throws Exception public static int setTransparentProxyingByApp(Context context, TorifiedApp[] apps, boolean forceAll) throws Exception
{ {
String baseDir = findBaseDir(); String baseDir = findBaseDir();
String command = null; String iptablesVersion = getIPTablesVersion();
Log.i(TAG, "iptables version: " + iptablesVersion);
command = IPTABLES_ADD; //ADD boolean ipTablesOld = false;
if (iptablesVersion != null && iptablesVersion.startsWith("1.3")){
ipTablesOld = true;
}
final StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();
//first we have to flush old settings
script.append(baseDir);
script.append(CMD_NAT_FLUSH);
script.append(" || exit\n");
script.append(baseDir);
script.append(CMD_FILTER_FLUSH);
script.append(" || exit\n");
StringBuilder res = new StringBuilder(); StringBuilder res = new StringBuilder();
int code = -1; int code = -1;
for (int i = 0; i < apps.length; i++) for (int i = 0; i < apps.length; i++)
{
//flush nat for every app
script.append(baseDir);
script.append("iptables -t nat -m owner --uid-owner ");
script.append(apps[i].getUid());
script.append(" -F || exit\n");
script.append("iptables -t filter -m owner --uid-owner ");
script.append(apps[i].getUid());
script.append(" -F || exit\n");
}
String[] cmdFlush = {script.toString()};
Log.i(TAG, cmdFlush[0]);
code = TorServiceUtils.doShellCommand(cmdFlush, res, true, true);
String msg = res.toString();
Log.i(TAG, msg);
script = new StringBuilder();
for (int i = 0; i < apps.length; i++)
{
if (forceAll || 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");
if (apps[i].getUsername().equals(TorServiceConstants.TOR_APP_USERNAME)) continue;
{ }
Log.i(TAG,"detected Orbot app - will not transproxy");
continue; Log.i(TAG,"enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")");
}
Log.i(TAG,"enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")");
//TCP
script.append(baseDir);
script.append("iptables -t nat");
script.append(" -A OUTPUT -p tcp --syn");
script.append(" -m owner --uid-owner ");
script.append(apps[i].getUid());
script.append(" -m tcp ");
//TCP if (ipTablesOld)
script.append(" -j DNAT --to 127.0.0.1:9040");
else
script.append(" -j REDIRECT --to-ports 9040");
script.append(" || exit\n");
//DNS
script.append(baseDir);
script.append("iptables -t nat");
script.append(" -A OUTPUT -p udp -m owner --uid-owner ");
script.append(apps[i].getUid());
script.append(" -m udp --dport 53");
if (ipTablesOld)
script.append(" -j DNAT --to 127.0.0.1:5400");
else
script.append(" -j REDIRECT --to-ports 5400");
script.append(" || exit\n");
//EVERYTHING ELSE UDP - DROP!
if (!ipTablesOld) //for some reason this doesn't work on iptables 1.3.7
{
script.append(baseDir); script.append(baseDir);
script.append("iptables -t nat"); script.append("iptables");
script.append(" -A OUTPUT -p tcp -m owner --uid-owner ");
script.append(apps[i].getUid());
// script.append(" -j DNAT --to 127.0.0.1:9040");
script.append(" -m tcp --syn -j REDIRECT --to-ports 9040");
script.append(" || exit\n");
//UDP
script.append(baseDir);
script.append("iptables -t nat");
script.append(" -A OUTPUT -p udp -m owner --uid-owner "); script.append(" -A OUTPUT -p udp -m owner --uid-owner ");
script.append(apps[i].getUid()); script.append(apps[i].getUid());
script.append(" --dport 53 -j REDIRECT --to-ports 5400"); //drop all UDP packets as Tor won't handle them
script.append(" || exit\n");
/*
script.append(baseDir);
script.append("iptables -t nat");
script.append(" -A OUTPUT -m owner --uid-owner ");
script.append(apps[i].getUid());
script.append(" -j DROP"); //drop all other packets as Tor won't handle them script.append(" -j DROP"); //drop all other packets as Tor won't handle them
script.append(" || exit\n"); script.append(" || exit\n");
*/
/*
* iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner anonymous -m tcp -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 filter -A OUTPUT -p tcp -m owner --uid-owner anonymous -m tcp --dport 9040 -j ACCEPT
iptables -t filter -A OUTPUT -p udp -m owner --uid-owner anonymous -m udp --dport 53 -j ACCEPT
iptables -t filter -A OUTPUT -m owner --uid-owner anonymous -j DROP
*/
} }
} }
}
String[] cmd = {script.toString()}; String[] cmdAdd = {script.toString()};
Log.i(TAG, cmd[0]); Log.i(TAG, cmdAdd[0]);
code = TorServiceUtils.doShellCommand(cmd, res, true, true); code = TorServiceUtils.doShellCommand(cmdAdd, res, true, true);
String msg = res.toString(); msg = res.toString();
Log.i(TAG, msg); Log.i(TAG, msg);
return false; return code;
} }