parent
8c177d4725
commit
8005519517
|
@ -3,11 +3,14 @@
|
||||||
|
|
||||||
package org.torproject.android;
|
package org.torproject.android;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
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.TorRoot;
|
import org.torproject.android.service.TorServiceUtils;
|
||||||
|
import org.torproject.android.service.TorTransProxy;
|
||||||
import org.torproject.android.service.TorServiceConstants;
|
import org.torproject.android.service.TorServiceConstants;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
@ -32,12 +35,19 @@ import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
|
|
||||||
public class Orbot extends Activity implements OnClickListener, TorConstants
|
public class Orbot extends Activity implements OnClickListener, TorConstants, OnCheckedChangeListener
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Useful UI bits */
|
/* Useful UI bits */
|
||||||
|
@ -45,18 +55,17 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
private TextView lblStatus = null; //the main text display widget
|
private TextView lblStatus = null; //the main text display widget
|
||||||
private ImageView imgStatus = null; //the main touchable image for activating Orbot
|
private ImageView imgStatus = null; //the main touchable image for activating Orbot
|
||||||
private ProgressDialog progressDialog;
|
private ProgressDialog progressDialog;
|
||||||
|
private ListView listApps;
|
||||||
|
private boolean showingSettings = false;
|
||||||
|
|
||||||
/* Some tracking bits */
|
/* Some tracking bits */
|
||||||
private int torStatus = STATUS_REQUIRES_DEMAND; //latest status reported from the tor service
|
private int torStatus = STATUS_READY; //latest status reported from the tor service
|
||||||
private int currentView = 0; //the currently displayed UI view
|
private int currentView = 0; //the currently displayed UI view
|
||||||
private StringBuffer logBuffer = new StringBuffer(); //the output of the service log messages
|
private StringBuffer logBuffer = new StringBuffer(); //the output of the service log messages
|
||||||
private String lastUrl = null;
|
|
||||||
|
|
||||||
/* 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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Called when the activity is first created. */
|
/** Called when the activity is first created. */
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,15 +92,22 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
|
|
||||||
mItem = menu.add(0, 2, Menu.NONE, getString(R.string.menu_browse));
|
mItem = menu.add(0, 2, Menu.NONE, getString(R.string.menu_browse));
|
||||||
mItem.setIcon(R.drawable.ic_menu_goto);
|
mItem.setIcon(R.drawable.ic_menu_goto);
|
||||||
|
|
||||||
|
mItem = menu.add(0, 3, Menu.NONE, getString(R.string.menu_info));
|
||||||
|
mItem.setIcon(R.drawable.ic_menu_about);
|
||||||
|
|
||||||
mItem = menu.add(0, 3, Menu.NONE, getString(R.string.menu_settings));
|
mItem = menu.add(0, 4, Menu.NONE, getString(R.string.menu_settings));
|
||||||
mItem.setIcon(R.drawable.ic_menu_register);
|
mItem.setIcon(R.drawable.ic_menu_register);
|
||||||
|
|
||||||
|
mItem = menu.add(0, 5, Menu.NONE, getString(R.string.menu_apps));
|
||||||
|
mItem.setIcon(R.drawable.ic_menu_register);
|
||||||
|
|
||||||
|
if (!TorServiceUtils.hasRoot())
|
||||||
|
mItem.setEnabled(false);
|
||||||
|
|
||||||
mItem = menu.add(0, 4, Menu.NONE, getString(R.string.menu_log));
|
mItem = menu.add(0,6, Menu.NONE, getString(R.string.menu_log));
|
||||||
mItem.setIcon(R.drawable.ic_menu_reports);
|
mItem.setIcon(R.drawable.ic_menu_reports);
|
||||||
|
|
||||||
mItem = menu.add(0, 5, Menu.NONE, getString(R.string.menu_info));
|
|
||||||
mItem.setIcon(R.drawable.ic_menu_about);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -109,11 +125,11 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
{
|
{
|
||||||
this.showMain();
|
this.showMain();
|
||||||
}
|
}
|
||||||
else if (item.getItemId() == 3)
|
else if (item.getItemId() == 4)
|
||||||
{
|
{
|
||||||
this.showSettings();
|
this.showSettings();
|
||||||
}
|
}
|
||||||
else if (item.getItemId() == 4)
|
else if (item.getItemId() == 6)
|
||||||
{
|
{
|
||||||
this.showMessageLog();
|
this.showMessageLog();
|
||||||
}
|
}
|
||||||
|
@ -121,10 +137,14 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
{
|
{
|
||||||
openBrowser(URL_TOR_CHECK);
|
openBrowser(URL_TOR_CHECK);
|
||||||
}
|
}
|
||||||
else if (item.getItemId() == 5)
|
else if (item.getItemId() == 3)
|
||||||
{
|
{
|
||||||
showHelp();
|
showHelp();
|
||||||
}
|
}
|
||||||
|
else if (item.getItemId() == 5)
|
||||||
|
{
|
||||||
|
showApps();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -158,11 +178,9 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see android.app.Activity#onResume()
|
* @see android.app.Activity#onResume()
|
||||||
*/
|
*/
|
||||||
|
@ -171,6 +189,17 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
updateStatus (""); //update the status, which checks the service status
|
updateStatus (""); //update the status, which checks the service status
|
||||||
|
|
||||||
|
if (showingSettings)
|
||||||
|
{
|
||||||
|
|
||||||
|
showingSettings = false;
|
||||||
|
processSettings();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -198,6 +227,8 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
|
|
||||||
|
TorServiceUtils.saveAppSettings(this);
|
||||||
|
|
||||||
unbindService();
|
unbindService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +241,24 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
{
|
{
|
||||||
bindService(); //connect the UI activity to the remote service
|
bindService(); //connect the UI activity to the remote service
|
||||||
|
|
||||||
|
if (currentView == R.layout.layout_apps)
|
||||||
|
{
|
||||||
|
if (hasRoot)
|
||||||
|
{
|
||||||
|
|
||||||
|
TorServiceUtils.saveAppSettings(this);
|
||||||
|
|
||||||
|
if (enableTransparentProxy)
|
||||||
|
{
|
||||||
|
TorTransProxy.purgeNatIptables();
|
||||||
|
TorTransProxy.setDNSProxying();
|
||||||
|
TorTransProxy.setTransparentProxying(this, TorServiceUtils.getApps(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
currentView = R.layout.layout_main;
|
currentView = R.layout.layout_main;
|
||||||
setContentView(currentView);
|
setContentView(currentView);
|
||||||
|
|
||||||
|
@ -232,6 +281,67 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadApps ()
|
||||||
|
{
|
||||||
|
final TorifiedApp[] apps = TorServiceUtils.getApps(this);
|
||||||
|
|
||||||
|
Arrays.sort(apps, new Comparator<TorifiedApp>() {
|
||||||
|
@Override
|
||||||
|
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<TorifiedApp>(this,R.layout.layout_apps_item,R.id.itemtext,apps) {
|
||||||
|
@Override
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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;
|
||||||
|
private TextView text;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Show the about view - a popup dialog
|
* Show the about view - a popup dialog
|
||||||
*/
|
*/
|
||||||
|
@ -285,7 +395,16 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showApps ()
|
||||||
|
{
|
||||||
|
currentView = R.layout.layout_apps;
|
||||||
|
setContentView(currentView);
|
||||||
|
|
||||||
|
listApps = (ListView)findViewById(R.id.applistview);
|
||||||
|
|
||||||
|
loadApps();
|
||||||
|
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Show the message log UI
|
* Show the message log UI
|
||||||
*/
|
*/
|
||||||
|
@ -308,6 +427,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
private void showSettings ()
|
private void showSettings ()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
showingSettings = true;
|
||||||
startActivity(new Intent(this, SettingsPreferences.class));
|
startActivity(new Intent(this, SettingsPreferences.class));
|
||||||
|
|
||||||
|
|
||||||
|
@ -331,6 +451,19 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
|
|
||||||
enableTransparentProxy = prefs.getBoolean(PREF_TRANSPARENT, false);
|
enableTransparentProxy = prefs.getBoolean(PREF_TRANSPARENT, false);
|
||||||
|
|
||||||
|
if (hasRoot)
|
||||||
|
{
|
||||||
|
if (enableTransparentProxy)
|
||||||
|
{
|
||||||
|
TorTransProxy.setDNSProxying();
|
||||||
|
TorTransProxy.setTransparentProxying(this, TorServiceUtils.getApps(this));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TorTransProxy.purgeNatIptables();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
String bridgeList = prefs.getString(PREF_BRIDGES_LIST,"");
|
String bridgeList = prefs.getString(PREF_BRIDGES_LIST,"");
|
||||||
|
|
||||||
if (useBridges)
|
if (useBridges)
|
||||||
|
@ -436,7 +569,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (torStatus == STATUS_UNAVAILABLE)
|
else if (torStatus == STATUS_OFF)
|
||||||
{
|
{
|
||||||
imgStatus.setImageResource(R.drawable.torstopping);
|
imgStatus.setImageResource(R.drawable.torstopping);
|
||||||
lblStatus.setText(getString(R.string.status_shutting_down));
|
lblStatus.setText(getString(R.string.status_shutting_down));
|
||||||
|
@ -493,15 +626,16 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (mService.getStatus() == STATUS_REQUIRES_DEMAND)
|
else if (mService.getStatus() == STATUS_READY)
|
||||||
{
|
{
|
||||||
processSettings();
|
processSettings();
|
||||||
mService.setProfile(PROFILE_ON);
|
mService.setProfile(PROFILE_ON);
|
||||||
|
|
||||||
if (hasRoot && enableTransparentProxy)
|
if (hasRoot && enableTransparentProxy)
|
||||||
{
|
{
|
||||||
TorRoot.enableDNSProxying();
|
|
||||||
TorRoot.enabledWebProxying();
|
TorTransProxy.setDNSProxying();
|
||||||
|
TorTransProxy.setTransparentProxying(this,TorServiceUtils.getApps(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -511,7 +645,9 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
|
|
||||||
if (hasRoot && enableTransparentProxy)
|
if (hasRoot && enableTransparentProxy)
|
||||||
{
|
{
|
||||||
TorRoot.purgeNatIptables();
|
TorTransProxy.purgeNatIptables();
|
||||||
|
//TorRoot.setDNSProxying(false);
|
||||||
|
//TorRoot.setTransparentProxying(this,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -617,7 +753,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
|
|
||||||
mIsBound = true;
|
mIsBound = true;
|
||||||
|
|
||||||
hasRoot = TorRoot.hasRootAccess();
|
hasRoot = TorTransProxy.hasRootAccess();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ package org.torproject.android;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
public class SettingsPreferences
|
public class SettingsPreferences
|
||||||
extends PreferenceActivity {
|
extends PreferenceActivity {
|
||||||
|
@ -13,4 +14,15 @@ public class SettingsPreferences
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onStop()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
|
||||||
|
Log.i(getClass().getName(),"Exiting Preferences");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ public interface TorConstants {
|
||||||
//path to check Tor against
|
//path to check Tor against
|
||||||
public final static String URL_TOR_CHECK = "https://check.torproject.org";
|
public final static String URL_TOR_CHECK = "https://check.torproject.org";
|
||||||
|
|
||||||
public final static int STATUS_UNAVAILABLE = -1;
|
public final static int STATUS_OFF = -1;
|
||||||
public final static int STATUS_REQUIRES_DEMAND = 0;
|
public final static int STATUS_READY = 0;
|
||||||
public final static int STATUS_ON = 1;
|
public final static int STATUS_ON = 1;
|
||||||
public final static int STATUS_CONNECTING = 2;
|
public final static int STATUS_CONNECTING = 2;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
package org.torproject.android;
|
||||||
|
|
||||||
|
public class TorifiedApp {
|
||||||
|
|
||||||
|
private boolean enabled;
|
||||||
|
private int uid;
|
||||||
|
private String username;
|
||||||
|
private String procname;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private boolean torified = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the torified
|
||||||
|
*/
|
||||||
|
public boolean isTorified() {
|
||||||
|
return torified;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param torified the torified to set
|
||||||
|
*/
|
||||||
|
public void setTorified(boolean torified) {
|
||||||
|
this.torified = torified;
|
||||||
|
}
|
||||||
|
private int[] enabledPorts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the enabledPorts
|
||||||
|
*/
|
||||||
|
public int[] getEnabledPorts() {
|
||||||
|
return enabledPorts;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param enabledPorts the enabledPorts to set
|
||||||
|
*/
|
||||||
|
public void setEnabledPorts(int[] enabledPorts) {
|
||||||
|
this.enabledPorts = enabledPorts;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the enabled
|
||||||
|
*/
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param enabled the enabled to set
|
||||||
|
*/
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the uid
|
||||||
|
*/
|
||||||
|
public int getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param uid the uid to set
|
||||||
|
*/
|
||||||
|
public void setUid(int uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the username
|
||||||
|
*/
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param username the username to set
|
||||||
|
*/
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the procname
|
||||||
|
*/
|
||||||
|
public String getProcname() {
|
||||||
|
return procname;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param procname the procname to set
|
||||||
|
*/
|
||||||
|
public void setProcname(String procname) {
|
||||||
|
this.procname = procname;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param name the name to set
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,259 +0,0 @@
|
||||||
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
|
||||||
/* See LICENSE for licensing information */
|
|
||||||
package org.torproject.android.service;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains shared programming interfaces.
|
|
||||||
* All iptables "communication" is handled by this class.
|
|
||||||
*/
|
|
||||||
public final class TorRoot {
|
|
||||||
private final static String TAG = "TOR_ROOT";
|
|
||||||
|
|
||||||
// Do we have root access?
|
|
||||||
private static boolean hasroot = false;
|
|
||||||
|
|
||||||
private final static String CMD_NAT_FLUSH = "iptables -t nat -F || exit\n";
|
|
||||||
private final static String CMD_NAT_IPTABLES_80 = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to 127.0.0.1:8118 || exit\n";
|
|
||||||
private final static String CMD_NAT_IPTABLES_443 = "iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to 127.0.0.1:9040 || exit\n";
|
|
||||||
|
|
||||||
private final static String CMD_DNS_PROXYING = "iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to 127.0.0.1:5400 || exit\n";
|
|
||||||
|
|
||||||
public static boolean enableDNSProxying ()
|
|
||||||
{
|
|
||||||
|
|
||||||
final StringBuilder script = new StringBuilder();
|
|
||||||
int code;
|
|
||||||
|
|
||||||
//Enable UDP Proxying
|
|
||||||
script.append(CMD_DNS_PROXYING);
|
|
||||||
StringBuilder res = new StringBuilder();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
code = runScriptAsRoot(script.toString(), res);
|
|
||||||
|
|
||||||
if (code != 0)
|
|
||||||
{
|
|
||||||
Log.w(TAG, "error apply DNS proxying: " + res.toString());
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.w(TAG, "error apply DNS proxying: " + res.toString(), e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Purge and re-add all rules (internal implementation).
|
|
||||||
* @param ctx application context (mandatory)
|
|
||||||
* @param uids list of selected uids to allow or disallow (depending on the working mode)
|
|
||||||
* @param showErrors indicates if errors should be alerted
|
|
||||||
*/
|
|
||||||
public static boolean enabledWebProxying() {
|
|
||||||
|
|
||||||
final StringBuilder script = new StringBuilder();
|
|
||||||
try {
|
|
||||||
int code;
|
|
||||||
|
|
||||||
script.append(CMD_NAT_IPTABLES_80);
|
|
||||||
script.append(CMD_NAT_IPTABLES_443);
|
|
||||||
/*
|
|
||||||
int uid = android.os.Process.getUidForName("dhcp");
|
|
||||||
if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit\n");
|
|
||||||
uid = android.os.Process.getUidForName("wifi");
|
|
||||||
if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit\n");
|
|
||||||
*/
|
|
||||||
|
|
||||||
StringBuilder res = new StringBuilder();
|
|
||||||
code = runScriptAsRoot(script.toString(), res);
|
|
||||||
|
|
||||||
String msg = res.toString();
|
|
||||||
Log.e(TAG, msg);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.w(TAG, "error refreshing iptables: " + e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Purge all iptables rules.
|
|
||||||
* @return true if the rules were purged
|
|
||||||
*/
|
|
||||||
public static boolean purgeNatIptables() {
|
|
||||||
StringBuilder res = new StringBuilder();
|
|
||||||
try {
|
|
||||||
int code = runScriptAsRoot(CMD_NAT_FLUSH, res);
|
|
||||||
if (code != 0) {
|
|
||||||
Log.w(TAG, "error purging iptables. exit code: " + code + "\n" + res);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.w(TAG,"error purging iptables: " + e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if we have root access
|
|
||||||
* @return boolean true if we have root
|
|
||||||
*/
|
|
||||||
public static boolean hasRootAccess() {
|
|
||||||
if (hasroot) return true;
|
|
||||||
try {
|
|
||||||
// Run an empty script just to check root access
|
|
||||||
if (runScriptAsRoot("exit 0", null, 20000) == 0) {
|
|
||||||
hasroot = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
Log.w(TAG, "Could not acquire root access.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs a script as root (multiple commands separated by "\n").
|
|
||||||
*
|
|
||||||
* @param script the script to be executed
|
|
||||||
* @param res the script output response (stdout + stderr)
|
|
||||||
* @param timeout timeout in milliseconds (-1 for none)
|
|
||||||
* @return the script exit code
|
|
||||||
*/
|
|
||||||
public static int runScriptAsRoot(String script, StringBuilder res, final long timeout) {
|
|
||||||
Log.i(TAG,"executing script: " + script);
|
|
||||||
final ScriptRunner runner = new ScriptRunner(script, res);
|
|
||||||
runner.start();
|
|
||||||
try {
|
|
||||||
if (timeout > 0) {
|
|
||||||
runner.join(timeout);
|
|
||||||
} else {
|
|
||||||
runner.join();
|
|
||||||
}
|
|
||||||
if (runner.isAlive()) {
|
|
||||||
// Timed-out
|
|
||||||
runner.interrupt();
|
|
||||||
runner.destroy();
|
|
||||||
runner.join(50);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException ex) {}
|
|
||||||
return runner.exitcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs a script as root (multiple commands separated by "\n") with a default timeout of 5 seconds.
|
|
||||||
*
|
|
||||||
* @param script the script to be executed
|
|
||||||
* @param res the script output response (stdout + stderr)
|
|
||||||
* @param timeout timeout in milliseconds (-1 for none)
|
|
||||||
* @return the script exit code
|
|
||||||
* @throws IOException on any error executing the script, or writing it to disk
|
|
||||||
*/
|
|
||||||
public static int runScriptAsRoot(String script, StringBuilder res) throws IOException {
|
|
||||||
return runScriptAsRoot(script, res, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal thread used to execute scripts as root.
|
|
||||||
*/
|
|
||||||
private static final class ScriptRunner extends Thread {
|
|
||||||
private final String script;
|
|
||||||
private final StringBuilder res;
|
|
||||||
public int exitcode = -1;
|
|
||||||
private Process exec;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new script runner.
|
|
||||||
* @param script script to run
|
|
||||||
* @param res response output
|
|
||||||
*/
|
|
||||||
public ScriptRunner(String script, StringBuilder res) {
|
|
||||||
this.script = script;
|
|
||||||
this.res = res;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
// Create the "su" request to run the command
|
|
||||||
// note that this will create a shell that we must interact to (using stdin/stdout)
|
|
||||||
exec = Runtime.getRuntime().exec("su");
|
|
||||||
final OutputStreamWriter out = new OutputStreamWriter(exec.getOutputStream());
|
|
||||||
// Write the script to be executed
|
|
||||||
out.write(script);
|
|
||||||
// Ensure that the last character is an "enter"
|
|
||||||
if (!script.endsWith("\n")) out.write("\n");
|
|
||||||
out.flush();
|
|
||||||
// Terminate the "su" process
|
|
||||||
out.write("exit\n");
|
|
||||||
out.flush();
|
|
||||||
final char buf[] = new char[1024];
|
|
||||||
// Consume the "stdout"
|
|
||||||
InputStreamReader r = new InputStreamReader(exec.getInputStream());
|
|
||||||
int read=0;
|
|
||||||
while ((read=r.read(buf)) != -1) {
|
|
||||||
if (res != null) res.append(buf, 0, read);
|
|
||||||
}
|
|
||||||
// Consume the "stderr"
|
|
||||||
r = new InputStreamReader(exec.getErrorStream());
|
|
||||||
read=0;
|
|
||||||
while ((read=r.read(buf)) != -1) {
|
|
||||||
if (res != null) res.append(buf, 0, read);
|
|
||||||
}
|
|
||||||
// get the process exit code
|
|
||||||
if (exec != null) this.exitcode = exec.waitFor();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
if (res != null) res.append("\nOperation timed-out");
|
|
||||||
} catch (Exception ex) {
|
|
||||||
if (res != null) res.append("\n" + ex);
|
|
||||||
} finally {
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Destroy this script runner
|
|
||||||
*/
|
|
||||||
public synchronized void destroy() {
|
|
||||||
if (exec != null) exec.destroy();
|
|
||||||
exec = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getApps (Context context)
|
|
||||||
{
|
|
||||||
PackageManager pMgr = context.getPackageManager();
|
|
||||||
|
|
||||||
List<ApplicationInfo> lAppInfo = pMgr.getInstalledApplications(0);
|
|
||||||
|
|
||||||
Iterator<ApplicationInfo> itAppInfo = lAppInfo.iterator();
|
|
||||||
|
|
||||||
ApplicationInfo aInfo = null;
|
|
||||||
|
|
||||||
while (itAppInfo.hasNext())
|
|
||||||
{
|
|
||||||
aInfo = itAppInfo.next();
|
|
||||||
|
|
||||||
boolean appEnabled = aInfo.enabled;
|
|
||||||
int uid = aInfo.uid; //-m owner --uid-owner
|
|
||||||
String username = pMgr.getNameForUid(uid);
|
|
||||||
String procName = aInfo.processName;
|
|
||||||
String name = aInfo.name;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -32,7 +32,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static int currentStatus = STATUS_REQUIRES_DEMAND;
|
private static int currentStatus = STATUS_READY;
|
||||||
|
|
||||||
private TorControlConnection conn = null;
|
private TorControlConnection conn = null;
|
||||||
|
|
||||||
|
@ -80,12 +80,12 @@ public class TorService extends Service implements TorServiceConstants, Runnable
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
||||||
currentStatus = STATUS_REQUIRES_DEMAND;
|
currentStatus = STATUS_OFF;
|
||||||
this.stopTor();
|
this.stopTor();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
||||||
currentStatus = STATUS_REQUIRES_DEMAND;
|
currentStatus = STATUS_OFF;
|
||||||
this.stopTor();
|
this.stopTor();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
currentStatus = STATUS_REQUIRES_DEMAND;
|
currentStatus = STATUS_OFF;
|
||||||
this.showToolbarNotification("Orbot", "Unable to start Tor", R.drawable.tornotification);
|
this.showToolbarNotification("Orbot", "Unable to start Tor", R.drawable.tornotification);
|
||||||
Log.i(TAG,"Unable to start Tor: " + e.getMessage(),e);
|
Log.i(TAG,"Unable to start Tor: " + e.getMessage(),e);
|
||||||
}
|
}
|
||||||
|
@ -226,14 +226,14 @@ public class TorService extends Service implements TorServiceConstants, Runnable
|
||||||
|
|
||||||
private void stopTor ()
|
private void stopTor ()
|
||||||
{
|
{
|
||||||
currentStatus = STATUS_UNAVAILABLE;
|
currentStatus = STATUS_OFF;
|
||||||
|
|
||||||
|
|
||||||
sendCallbackMessage("Web proxy shutdown");
|
sendCallbackMessage("Web proxy shutdown");
|
||||||
|
|
||||||
killTorProcess ();
|
killTorProcess ();
|
||||||
|
|
||||||
currentStatus = STATUS_REQUIRES_DEMAND;
|
currentStatus = STATUS_READY;
|
||||||
|
|
||||||
showToolbarNotification ("Orbot","Anonymous browsing is disabled",R.drawable.tornotificationoff);
|
showToolbarNotification ("Orbot","Anonymous browsing is disabled",R.drawable.tornotificationoff);
|
||||||
sendCallbackMessage("Anonymous browsing is disabled");
|
sendCallbackMessage("Anonymous browsing is disabled");
|
||||||
|
@ -591,7 +591,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currentStatus = STATUS_UNAVAILABLE;
|
currentStatus = STATUS_OFF;
|
||||||
sendCallbackMessage ("shutting down...");
|
sendCallbackMessage ("shutting down...");
|
||||||
|
|
||||||
_torInstance.stopTor();
|
_torInstance.stopTor();
|
||||||
|
|
|
@ -76,12 +76,11 @@ public interface TorServiceConstants {
|
||||||
//control port
|
//control port
|
||||||
public final static String TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE = "Bootstrapped 100%";
|
public final static String TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE = "Bootstrapped 100%";
|
||||||
|
|
||||||
public final static int STATUS_UNAVAILABLE = -1;
|
public final static int STATUS_OFF = -1;
|
||||||
public final static int STATUS_REQUIRES_DEMAND = 0;
|
public final static int STATUS_READY = 0;
|
||||||
public final static int STATUS_ON = 1;
|
public final static int STATUS_ON = 1;
|
||||||
public final static int STATUS_CONNECTING = 2;
|
public final static int STATUS_CONNECTING = 2;
|
||||||
|
|
||||||
public final static int PROFILE_OFF = -1;
|
public final static int PROFILE_OFF = -1;
|
||||||
public final static int PROFILE_ONDEMAND = 0;
|
|
||||||
public final static int PROFILE_ON = 1;
|
public final static int PROFILE_ON = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,109 @@ package org.torproject.android.service;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import org.torproject.android.TorifiedApp;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class TorServiceUtils implements TorServiceConstants {
|
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<ApplicationInfo> lAppInfo = pMgr.getInstalledApplications(0);
|
||||||
|
|
||||||
|
Iterator<ApplicationInfo> 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)
|
public static int findProcessId(String command)
|
||||||
{
|
{
|
||||||
|
@ -104,18 +201,17 @@ public class TorServiceUtils implements TorServiceConstants {
|
||||||
{
|
{
|
||||||
Log.i(TAG,"executing commands: " + cmds.length);
|
Log.i(TAG,"executing commands: " + cmds.length);
|
||||||
|
|
||||||
Runtime runtime = Runtime.getRuntime();
|
|
||||||
|
|
||||||
Process proc = null;
|
Process proc = null;
|
||||||
int exitCode = -1;
|
int exitCode = -1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
proc = runtime.exec(cmds[0]);
|
proc = Runtime.getRuntime().exec("su");
|
||||||
|
|
||||||
OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());
|
OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());
|
||||||
|
|
||||||
for (int i = 1; i < cmds.length; i++)
|
for (int i = 0; i < cmds.length; i++)
|
||||||
{
|
{
|
||||||
out.write(cmds[i]);
|
out.write(cmds[i]);
|
||||||
out.write("\n");
|
out.write("\n");
|
||||||
|
@ -123,7 +219,8 @@ public class TorServiceUtils implements TorServiceConstants {
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
out.write("exit\n");
|
out.write("exit\n");
|
||||||
|
out.flush();
|
||||||
|
/*
|
||||||
final char buf[] = new char[1024];
|
final char buf[] = new char[1024];
|
||||||
// Consume the "stdout"
|
// Consume the "stdout"
|
||||||
InputStreamReader reader = new InputStreamReader(proc.getInputStream());
|
InputStreamReader reader = new InputStreamReader(proc.getInputStream());
|
||||||
|
@ -136,7 +233,7 @@ public class TorServiceUtils implements TorServiceConstants {
|
||||||
read=0;
|
read=0;
|
||||||
while ((read=reader.read(buf)) != -1) {
|
while ((read=reader.read(buf)) != -1) {
|
||||||
if (log != null) log.append(buf, 0, read);
|
if (log != null) log.append(buf, 0, read);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
exitCode = proc.waitFor();
|
exitCode = proc.waitFor();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
package org.torproject.android.service;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.torproject.android.TorifiedApp;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class TorTransProxy {
|
||||||
|
|
||||||
|
private final static String TAG = "TorTransProxy";
|
||||||
|
|
||||||
|
private final static String CMD_NAT_FLUSH = "iptables -t nat -F || exit\n";
|
||||||
|
// private final static String CMD_NAT_IPTABLES_ALL = "iptables -t nat -A OUTPUT -j DNAT --to 127.0.0.1:9040 || exit\n";
|
||||||
|
|
||||||
|
private final static String CMD_DNS_PROXYING_ADD = "iptables -t nat -A 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";
|
||||||
|
|
||||||
|
private final static String IPTABLES_ADD = " -A ";
|
||||||
|
private final static String IPTABLES_DELETE = " -D ";
|
||||||
|
|
||||||
|
private static boolean hasRoot = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we have root access
|
||||||
|
* @return boolean true if we have root
|
||||||
|
*/
|
||||||
|
public static boolean hasRootAccess() {
|
||||||
|
if (hasRoot) return true;
|
||||||
|
try {
|
||||||
|
// Run an empty script just to check root access
|
||||||
|
String[] cmd = {"exit 0"};
|
||||||
|
if (TorServiceUtils.doRootCommand(cmd, null) == 0) {
|
||||||
|
hasRoot = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
Log.w(TAG, "Could not acquire root access.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int setDNSProxying ()
|
||||||
|
{
|
||||||
|
|
||||||
|
final StringBuilder log = new StringBuilder();
|
||||||
|
int code;
|
||||||
|
|
||||||
|
String[] cmds = {CMD_DNS_PROXYING_ADD};
|
||||||
|
|
||||||
|
|
||||||
|
code = TorServiceUtils.doRootCommand(cmds, log);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean purgeNatIptables() {
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
|
try {
|
||||||
|
String[] cmds = {CMD_NAT_FLUSH};
|
||||||
|
int code = TorServiceUtils.doRootCommand(cmds, res);
|
||||||
|
if (code != 0) {
|
||||||
|
Log.w(TAG, "error purging iptables. exit code: " + code + "\n" + res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG,"error purging iptables: " + e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean setTransparentProxying(Context context, TorifiedApp[] apps) {
|
||||||
|
|
||||||
|
String command = null;
|
||||||
|
|
||||||
|
command = IPTABLES_ADD; //ADD
|
||||||
|
|
||||||
|
final StringBuilder script = new StringBuilder();
|
||||||
|
|
||||||
|
try {
|
||||||
|
int code;
|
||||||
|
|
||||||
|
for (int i = 0; i < apps.length; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (apps[i].getUsername().startsWith("org.torproject.android")) //we never want to Tor this!
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (apps[i].isTorified())
|
||||||
|
{
|
||||||
|
Log.i(TAG,"enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")");
|
||||||
|
|
||||||
|
script.append("iptables -t nat");
|
||||||
|
script.append(command);
|
||||||
|
script.append("OUTPUT -p tcp -m owner --uid-owner ");
|
||||||
|
script.append(apps[i].getUid());
|
||||||
|
script.append(" -j DNAT --to 127.0.0.1:9040");
|
||||||
|
script.append(" || exit\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
|
|
||||||
|
String[] cmd = {script.toString()};
|
||||||
|
|
||||||
|
code = TorServiceUtils.doRootCommand(cmd, res);
|
||||||
|
|
||||||
|
String msg = res.toString();
|
||||||
|
Log.e(TAG, msg);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG, "error refreshing iptables: " + e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue