[tor-commits] [orbot/master] cleaned up iptables binary handling

n8fr8 at torproject.org n8fr8 at torproject.org
Fri Jan 13 16:02:28 UTC 2012


commit b8af143d5f32445163b761ce49618cc232339311
Author: Nathan Freitas <nathan at freitas.net>
Date:   Thu Jan 12 20:58:21 2012 -0500

    cleaned up iptables binary handling
---
 src/org/torproject/android/TorConstants.java       |    1 +
 .../android/service/IptablesManager.java           | 1058 --------------------
 .../android/service/TorBinaryInstaller.java        |   98 ++
 src/org/torproject/android/service/TorService.java |   26 +-
 .../torproject/android/service/TorTransProxy.java  |   73 ++-
 src/org/torproject/android/wizard/Permissions.java |    2 +-
 .../torproject/android/wizard/WizardHelper.java    |   22 +-
 7 files changed, 183 insertions(+), 1097 deletions(-)

diff --git a/src/org/torproject/android/TorConstants.java b/src/org/torproject/android/TorConstants.java
index df430c6..755a209 100644
--- a/src/org/torproject/android/TorConstants.java
+++ b/src/org/torproject/android/TorConstants.java
@@ -43,5 +43,6 @@ public interface TorConstants {
 	public final static String PREF_HAS_ROOT = "has_root";
 	public final static  int RESULT_CLOSE_ALL = 0;
 	
+	public final static String PREF_USE_SYSTEM_IPTABLES = "pref_use_sys_iptables";
 	
 }
diff --git a/src/org/torproject/android/service/IptablesManager.java b/src/org/torproject/android/service/IptablesManager.java
deleted file mode 100644
index 2781705..0000000
--- a/src/org/torproject/android/service/IptablesManager.java
+++ /dev/null
@@ -1,1058 +0,0 @@
-/**
- * Contains shared programming interfaces.
- * All iptables "communication" is handled by this class.
- * 
- * Copyright (C) 2009-2010  Rodrigo Zechin Rosauro
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * @author Rodrigo Zechin Rosauro
- * @version 1.0
- */
-
-package org.torproject.android.service;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.StringReader;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.StringTokenizer;
-
-import org.torproject.android.R;
-
-import android.Manifest;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.Intent;
-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.widget.Toast;
-
-/**
- * Contains shared programming interfaces.
- * All iptables "communication" is handled by this class.
- */
-public final class IptablesManager {
-	/** application version string */
-	public static final String VERSION = "1.5.1-dev";
-	/** special application UID used to indicate "any application" */
-	public static final int SPECIAL_UID_ANY	= -10;
-	/** special application UID used to indicate the Linux Kernel */
-	public static final int SPECIAL_UID_KERNEL	= -11;
-	/** root script filename */
-	private static final String SCRIPT_FILE = "droidwall.sh";
-	
-	// Preferences
-	public static final String PREFS_NAME 		= "DroidWallPrefs";
-	public static final String PREF_3G_UIDS		= "AllowedUids3G";
-	public static final String PREF_WIFI_UIDS	= "AllowedUidsWifi";
-	public static final String PREF_PASSWORD 	= "Password";
-	public static final String PREF_MODE 		= "BlockMode";
-	public static final String PREF_ENABLED		= "Enabled";
-	public static final String PREF_LOGENABLED	= "LogEnabled";
-	// Modes
-	public static final String MODE_WHITELIST = "whitelist";
-	public static final String MODE_BLACKLIST = "blacklist";
-	// Messages
-	public static final String STATUS_CHANGED_MSG 	= "com.googlecode.droidwall.intent.action.STATUS_CHANGED";
-	public static final String TOGGLE_REQUEST_MSG	= "com.googlecode.droidwall.intent.action.TOGGLE_REQUEST";
-	public static final String STATUS_EXTRA			= "com.googlecode.droidwall.intent.extra.STATUS";
-	
-	// Cached applications
-	public static DroidApp applications[] = null;
-	// Do we have root access?
-	private static boolean hasroot = false;
-	// Flag indicating if this is an ARMv6 device (-1: unknown, 0: no,  1: yes)
-	private static int isARMv6 = -1;
-
-    /**
-     * Display a simple alert box
-     * @param ctx context
-     * @param msg message
-     */
-	public static void alert(Context ctx, CharSequence msg) {
-    	if (ctx != null) {
-        	new AlertDialog.Builder(ctx)
-        	.setNeutralButton(android.R.string.ok, null)
-        	.setMessage(msg)
-        	.show();
-    	}
-    }
-	/**
-	 * Check if this is an ARMv6 device
-	 * @return true if this is ARMv6
-	 */
-	private static boolean isARMv6() {
-		if (isARMv6 == -1) {
-			BufferedReader r = null;
-			try {
-				isARMv6 = 0;
-				r = new BufferedReader(new FileReader("/proc/cpuinfo"));
-				for (String line = r.readLine(); line != null; line = r.readLine()) {
-					if (line.startsWith("Processor") && line.contains("ARMv6")) {
-						isARMv6 = 1;
-						break;
-					} else if (line.startsWith("CPU architecture") && (line.contains("6TE") || line.contains("5TE"))) {
-						isARMv6 = 1;
-						break;
-					}
-				}
-			} catch (Exception ex) {
-			} finally {
-				if (r != null) try {r.close();} catch (Exception ex) {}
-			}
-		}
-		return (isARMv6 == 1);
-	}
-	/**
-	 * Create the generic shell script header used to determine which iptables binary to use.
-	 * @param ctx context
-	 * @return script header
-	 */
-	private static String scriptHeader(Context ctx) {
-		final String dir = ctx.getDir("bin",0).getAbsolutePath();
-		final String myiptables = dir + (isARMv6() ? "/iptables_g1" : "/iptables_n1");
-		return "" +
-			"IPTABLES=iptables\n" +
-			"BUSYBOX=busybox\n" +
-			"GREP=grep\n" +
-			"ECHO=echo\n" +
-			"# Try to find busybox\n" +
-			"if " + dir + "/busybox_g1 --help >/dev/null 2>/dev/null ; then\n" +
-			"	BUSYBOX="+dir+"/busybox_g1\n" +
-			"	GREP=\"$BUSYBOX grep\"\n" +
-			"	ECHO=\"$BUSYBOX echo\"\n" +
-			"elif busybox --help >/dev/null 2>/dev/null ; then\n" +
-			"	BUSYBOX=busybox\n" +
-			"elif /system/xbin/busybox --help >/dev/null 2>/dev/null ; then\n" +
-			"	BUSYBOX=/system/xbin/busybox\n" +
-			"elif /system/bin/busybox --help >/dev/null 2>/dev/null ; then\n" +
-			"	BUSYBOX=/system/bin/busybox\n" +
-			"fi\n" +
-			"# Try to find grep\n" +
-			"if ! $ECHO 1 | $GREP -q 1 >/dev/null 2>/dev/null ; then\n" +
-			"	if $ECHO 1 | $BUSYBOX grep -q 1 >/dev/null 2>/dev/null ; then\n" +
-			"		GREP=\"$BUSYBOX grep\"\n" +
-			"	fi\n" +
-			"	# Grep is absolutely required\n" +
-			"	if ! $ECHO 1 | $GREP -q 1 >/dev/null 2>/dev/null ; then\n" +
-			"		$ECHO The grep command is required. DroidWall will not work.\n" +
-			"		exit 1\n" +
-			"	fi\n" +
-			"fi\n" +
-			"# Try to find iptables\n" +
-			"if " + myiptables + " --version >/dev/null 2>/dev/null ; then\n" +
-			"	IPTABLES="+myiptables+"\n" +
-			"fi\n" +
-			"";
-	}
-	/**
-	 * Copies a raw resource file, given its ID to the given location
-	 * @param ctx context
-	 * @param resid resource id
-	 * @param file destination file
-	 * @param mode file permissions (E.g.: "755")
-	 * @throws IOException on error
-	 * @throws InterruptedException when interrupted
-	 */
-	private static void copyRawFile(Context ctx, int resid, File file, String mode) throws IOException, InterruptedException
-	{
-		final String abspath = file.getAbsolutePath();
-		// Write the iptables binary
-		final FileOutputStream out = new FileOutputStream(file);
-		final InputStream is = ctx.getResources().openRawResource(resid);
-		byte buf[] = new byte[1024];
-		int len;
-		while ((len = is.read(buf)) > 0) {
-			out.write(buf, 0, len);
-		}
-		out.close();
-		is.close();
-		// Change the permissions
-		Runtime.getRuntime().exec("chmod "+mode+" "+abspath).waitFor();
-	}
-    /**
-     * Purge and re-add all rules (internal implementation).
-     * @param ctx application context (mandatory)
-     * @param uidsWifi list of selected UIDs for WIFI to allow or disallow (depending on the working mode)
-     * @param uids3g list of selected UIDs for 2G/3G to allow or disallow (depending on the working mode)
-     * @param showErrors indicates if errors should be alerted
-     */
-	private static boolean applyIptablesRulesImpl(Context ctx, List<Integer> uidsWifi, List<Integer> uids3g, boolean showErrors) {
-		if (ctx == null) {
-			return false;
-		}
-		assertBinaries(ctx, showErrors);
-		final String ITFS_WIFI[] = {"tiwlan+", "wlan+", "eth+"};
-		final String ITFS_3G[] = {"rmnet+","pdp+","ppp+","uwbr+","wimax+","vsnet+"};
-		final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);
-		final boolean whitelist = prefs.getString(PREF_MODE, MODE_WHITELIST).equals(MODE_WHITELIST);
-		final boolean blacklist = !whitelist;
-		final boolean logenabled = ctx.getSharedPreferences(PREFS_NAME, 0).getBoolean(PREF_LOGENABLED, false);
-
-    	final StringBuilder script = new StringBuilder();
-		try {
-			int code;
-			script.append(scriptHeader(ctx));
-			script.append("" +
-				"$IPTABLES --version || exit 1\n" +
-				"# Create the droidwall chains if necessary\n" +
-				"$IPTABLES -L droidwall >/dev/null 2>/dev/null || $IPTABLES --new droidwall || exit 2\n" +
-				"$IPTABLES -L droidwall-3g >/dev/null 2>/dev/null || $IPTABLES --new droidwall-3g || exit 3\n" +
-				"$IPTABLES -L droidwall-wifi >/dev/null 2>/dev/null || $IPTABLES --new droidwall-wifi || exit 4\n" +
-				"$IPTABLES -L droidwall-reject >/dev/null 2>/dev/null || $IPTABLES --new droidwall-reject || exit 5\n" +
-				"# Add droidwall chain to OUTPUT chain if necessary\n" +
-				"$IPTABLES -L OUTPUT | $GREP -q droidwall || $IPTABLES -A OUTPUT -j droidwall || exit 6\n" +
-				"# Flush existing rules\n" +
-				"$IPTABLES -F droidwall || exit 7\n" +
-				"$IPTABLES -F droidwall-3g || exit 8\n" +
-				"$IPTABLES -F droidwall-wifi || exit 9\n" +
-				"$IPTABLES -F droidwall-reject || exit 10\n" +
-			"");
-			// Check if logging is enabled
-			if (logenabled) {
-				script.append("" +
-					"# Create the log and reject rules (ignore errors on the LOG target just in case it is not available)\n" +
-					"$IPTABLES -A droidwall-reject -j LOG --log-prefix \"[DROIDWALL] \" --log-uid\n" +
-					"$IPTABLES -A droidwall-reject -j REJECT || exit 11\n" +
-				"");
-			} else {
-				script.append("" +
-					"# Create the reject rule (log disabled)\n" +
-					"$IPTABLES -A droidwall-reject -j REJECT || exit 11\n" +
-				"");
-			}
-			if (whitelist && logenabled) {
-				script.append("# Allow DNS lookups on white-list for a better logging (ignore errors)\n");
-				script.append("$IPTABLES -A droidwall -p udp --dport 53 -j RETURN\n");
-			}
-			script.append("# Main rules (per interface)\n");
-			for (final String itf : ITFS_3G) {
-				script.append("$IPTABLES -A droidwall -o ").append(itf).append(" -j droidwall-3g || exit\n");
-			}
-			for (final String itf : ITFS_WIFI) {
-				script.append("$IPTABLES -A droidwall -o ").append(itf).append(" -j droidwall-wifi || exit\n");
-			}
-			
-			script.append("# Filtering rules\n");
-			final String targetRule = (whitelist ? "RETURN" : "droidwall-reject");
-			final boolean any_3g = uids3g.indexOf(SPECIAL_UID_ANY) >= 0;
-			final boolean any_wifi = uidsWifi.indexOf(SPECIAL_UID_ANY) >= 0;
-			if (whitelist && !any_wifi) {
-				// When "white listing" wifi, we need to ensure that the dhcp and wifi users are allowed
-				int uid = android.os.Process.getUidForName("dhcp");
-				if (uid != -1) {
-					script.append("# dhcp user\n");
-					script.append("$IPTABLES -A droidwall-wifi -m owner --uid-owner ").append(uid).append(" -j RETURN || exit\n");
-				}
-				uid = android.os.Process.getUidForName("wifi");
-				if (uid != -1) {
-					script.append("# wifi user\n");
-					script.append("$IPTABLES -A droidwall-wifi -m owner --uid-owner ").append(uid).append(" -j RETURN || exit\n");
-				}
-			}
-			if (any_3g) {
-				if (blacklist) {
-					/* block any application on this interface */
-					script.append("$IPTABLES -A droidwall-3g -j ").append(targetRule).append(" || exit\n");
-				}
-			} else {
-				/* release/block individual applications on this interface */
-				for (final Integer uid : uids3g) {
-					if (uid >= 0) script.append("$IPTABLES -A droidwall-3g -m owner --uid-owner ").append(uid).append(" -j ").append(targetRule).append(" || exit\n");
-				}
-			}
-			if (any_wifi) {
-				if (blacklist) {
-					/* block any application on this interface */
-					script.append("$IPTABLES -A droidwall-wifi -j ").append(targetRule).append(" || exit\n");
-				}
-			} else {
-				/* release/block individual applications on this interface */
-				for (final Integer uid : uidsWifi) {
-					if (uid >= 0) script.append("$IPTABLES -A droidwall-wifi -m owner --uid-owner ").append(uid).append(" -j ").append(targetRule).append(" || exit\n");
-				}
-			}
-			if (whitelist) {
-				if (!any_3g) {
-					if (uids3g.indexOf(SPECIAL_UID_KERNEL) >= 0) {
-						script.append("# hack to allow kernel packets on white-list\n");
-						script.append("$IPTABLES -A droidwall-3g -m owner --uid-owner 0:999999999 -j droidwall-reject || exit\n");
-					} else {
-						script.append("$IPTABLES -A droidwall-3g -j droidwall-reject || exit\n");
-					}
-				}
-				if (!any_wifi) {
-					if (uidsWifi.indexOf(SPECIAL_UID_KERNEL) >= 0) {
-						script.append("# hack to allow kernel packets on white-list\n");
-						script.append("$IPTABLES -A droidwall-wifi -m owner --uid-owner 0:999999999 -j droidwall-reject || exit\n");
-					} else {
-						script.append("$IPTABLES -A droidwall-wifi -j droidwall-reject || exit\n");
-					}
-				}
-			} else {
-				if (uids3g.indexOf(SPECIAL_UID_KERNEL) >= 0) {
-					script.append("# hack to BLOCK kernel packets on black-list\n");
-					script.append("$IPTABLES -A droidwall-3g -m owner --uid-owner 0:999999999 -j RETURN || exit\n");
-					script.append("$IPTABLES -A droidwall-3g -j droidwall-reject || exit\n");
-				}
-				if (uidsWifi.indexOf(SPECIAL_UID_KERNEL) >= 0) {
-					script.append("# hack to BLOCK kernel packets on black-list\n");
-					script.append("$IPTABLES -A droidwall-wifi -m owner --uid-owner 0:999999999 -j RETURN || exit\n");
-					script.append("$IPTABLES -A droidwall-wifi -j droidwall-reject || exit\n");
-				}
-			}
-	    	final StringBuilder res = new StringBuilder();
-			code = runScriptAsRoot(ctx, script.toString(), res);
-			if (showErrors && code != 0) {
-				String msg = res.toString();
-				Log.e("DroidWall", msg);
-				// Remove unnecessary help message from output
-				if (msg.indexOf("\nTry `iptables -h' or 'iptables --help' for more information.") != -1) {
-					msg = msg.replace("\nTry `iptables -h' or 'iptables --help' for more information.", "");
-				}
-				alert(ctx, "Error applying iptables rules. Exit code: " + code + "\n\n" + msg.trim());
-			} else {
-				return true;
-			}
-		} catch (Exception e) {
-			if (showErrors) alert(ctx, "error refreshing iptables: " + e);
-		}
-		return false;
-    }
-    /**
-     * Purge and re-add all saved rules (not in-memory ones).
-     * This is much faster than just calling "applyIptablesRules", since it don't need to read installed applications.
-     * @param ctx application context (mandatory)
-     * @param showErrors indicates if errors should be alerted
-     */
-	public static boolean applySavedIptablesRules(Context ctx, boolean showErrors) {
-		if (ctx == null) {
-			return false;
-		}
-		final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);
-		final String savedUids_wifi = prefs.getString(PREF_WIFI_UIDS, "");
-		final String savedUids_3g = prefs.getString(PREF_3G_UIDS, "");
-		final List<Integer> uids_wifi = new LinkedList<Integer>();
-		if (savedUids_wifi.length() > 0) {
-			// Check which applications are allowed on wifi
-			final StringTokenizer tok = new StringTokenizer(savedUids_wifi, "|");
-			while (tok.hasMoreTokens()) {
-				final String uid = tok.nextToken();
-				if (!uid.equals("")) {
-					try {
-						uids_wifi.add(Integer.parseInt(uid));
-					} catch (Exception ex) {
-					}
-				}
-			}
-		}
-		final List<Integer> uids_3g = new LinkedList<Integer>();
-		if (savedUids_3g.length() > 0) {
-			// Check which applications are allowed on 2G/3G
-			final StringTokenizer tok = new StringTokenizer(savedUids_3g, "|");
-			while (tok.hasMoreTokens()) {
-				final String uid = tok.nextToken();
-				if (!uid.equals("")) {
-					try {
-						uids_3g.add(Integer.parseInt(uid));
-					} catch (Exception ex) {
-					}
-				}
-			}
-		}
-		return applyIptablesRulesImpl(ctx, uids_wifi, uids_3g, showErrors);
-	}
-	
-    /**
-     * Purge and re-add all rules.
-     * @param ctx application context (mandatory)
-     * @param showErrors indicates if errors should be alerted
-     */
-	public static boolean applyIptablesRules(Context ctx, boolean showErrors) {
-		if (ctx == null) {
-			return false;
-		}
-		saveRules(ctx);
-		return applySavedIptablesRules(ctx, showErrors);
-    }
-	
-	/**
-	 * Save current rules using the preferences storage.
-	 * @param ctx application context (mandatory)
-	 */
-	public static void saveRules(Context ctx) {
-		final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);
-		final DroidApp[] apps = getApps(ctx);
-		// Builds a pipe-separated list of names
-		final StringBuilder newuids_wifi = new StringBuilder();
-		final StringBuilder newuids_3g = new StringBuilder();
-		for (int i=0; i<apps.length; i++) {
-			if (apps[i].selected_wifi) {
-				if (newuids_wifi.length() != 0) newuids_wifi.append('|');
-				newuids_wifi.append(apps[i].uid);
-			}
-			if (apps[i].selected_3g) {
-				if (newuids_3g.length() != 0) newuids_3g.append('|');
-				newuids_3g.append(apps[i].uid);
-			}
-		}
-		// save the new list of UIDs
-		final Editor edit = prefs.edit();
-		edit.putString(PREF_WIFI_UIDS, newuids_wifi.toString());
-		edit.putString(PREF_3G_UIDS, newuids_3g.toString());
-		edit.commit();
-    }
-    
-    /**
-     * Purge all iptables rules.
-     * @param ctx mandatory context
-     * @param showErrors indicates if errors should be alerted
-     * @return true if the rules were purged
-     */
-	public static boolean purgeIptables(Context ctx, boolean showErrors) {
-    	StringBuilder res = new StringBuilder();
-		try {
-			assertBinaries(ctx, showErrors);
-			int code = runScriptAsRoot(ctx, scriptHeader(ctx) +
-					"$IPTABLES -F droidwall\n" +
-					"$IPTABLES -F droidwall-reject\n" +
-					"$IPTABLES -F droidwall-3g\n" +
-					"$IPTABLES -F droidwall-wifi\n", res);
-			if (code == -1) {
-				if (showErrors) alert(ctx, "error purging iptables. exit code: " + code + "\n" + res);
-				return false;
-			}
-			return true;
-		} catch (Exception e) {
-			if (showErrors) alert(ctx, "error purging iptables: " + e);
-			return false;
-		}
-    }
-	
-	/**
-	 * Display iptables rules output
-	 * @param ctx application context
-	 */
-	public static void showIptablesRules(Context ctx) {
-		try {
-    		final StringBuilder res = new StringBuilder();
-			runScriptAsRoot(ctx, scriptHeader(ctx) +
-								 "$ECHO $IPTABLES\n" +
-								 "$IPTABLES -L -v\n", res);
-			alert(ctx, res);
-		} catch (Exception e) {
-			alert(ctx, "error: " + e);
-		}
-	}
-
-	/**
-	 * Display logs
-	 * @param ctx application context
-     * @return true if the clogs were cleared
-	 */
-	public static boolean clearLog(Context ctx) {
-		try {
-			final StringBuilder res = new StringBuilder();
-			int code = runScriptAsRoot(ctx, "dmesg -c >/dev/null || exit\n", res);
-			if (code != 0) {
-				alert(ctx, res);
-				return false;
-			}
-			return true;
-		} catch (Exception e) {
-			alert(ctx, "error: " + e);
-		}
-		return false;
-	}
-	/**
-	 * Display logs
-	 * @param ctx application context
-	 */
-	public static void showLog(Context ctx) {
-		try {
-    		StringBuilder res = new StringBuilder();
-			int code = runScriptAsRoot(ctx, scriptHeader(ctx) +
-					"dmesg | $GREP DROIDWALL\n", res);
-			if (code != 0) {
-				if (res.length() == 0) {
-					res.append("Log is empty");
-				}
-				alert(ctx, res);
-				return;
-			}
-			final BufferedReader r = new BufferedReader(new StringReader(res.toString()));
-			final Integer unknownUID = -99;
-			res = new StringBuilder();
-			String line;
-			int start, end;
-			Integer appid;
-			final HashMap<Integer, LogInfo> map = new HashMap<Integer, LogInfo>();
-			LogInfo loginfo = null;
-			while ((line = r.readLine()) != null) {
-				if (line.indexOf("[DROIDWALL]") == -1) continue;
-				appid = unknownUID;
-				if (((start=line.indexOf("UID=")) != -1) && ((end=line.indexOf(" ", start)) != -1)) {
-					appid = Integer.parseInt(line.substring(start+4, end));
-				}
-				loginfo = map.get(appid);
-				if (loginfo == null) {
-					loginfo = new LogInfo();
-					map.put(appid, loginfo);
-				}
-				loginfo.totalBlocked += 1;
-				if (((start=line.indexOf("DST=")) != -1) && ((end=line.indexOf(" ", start)) != -1)) {
-					String dst = line.substring(start+4, end);
-					if (loginfo.dstBlocked.containsKey(dst)) {
-						loginfo.dstBlocked.put(dst, loginfo.dstBlocked.get(dst) + 1);
-					} else {
-						loginfo.dstBlocked.put(dst, 1);
-					}
-				}
-			}
-			final DroidApp[] apps = getApps(ctx);
-			for (Integer id : map.keySet()) {
-				res.append("App ID ");
-				if (id != unknownUID) {
-					res.append(id);
-					for (DroidApp app : apps) {
-						if (app.uid == id) {
-							res.append(" (").append(app.names[0]);
-							if (app.names.length > 1) {
-								res.append(", ...)");
-							} else {
-								res.append(")");
-							}
-							break;
-						}
-					}
-				} else {
-					res.append("(kernel)");
-				}
-				loginfo = map.get(id);
-				res.append(" - Blocked ").append(loginfo.totalBlocked).append(" packets");
-				if (loginfo.dstBlocked.size() > 0) {
-					res.append(" (");
-					boolean first = true;
-					for (String dst : loginfo.dstBlocked.keySet()) {
-						if (!first) {
-							res.append(", ");
-						}
-						res.append(loginfo.dstBlocked.get(dst)).append(" packets for ").append(dst);
-						first = false;
-					}
-					res.append(")");
-				}
-				res.append("\n\n");
-			}
-			if (res.length() == 0) {
-				res.append("Log is empty");
-			}
-			alert(ctx, res);
-		} catch (Exception e) {
-			alert(ctx, "error: " + e);
-		}
-	}
-
-    /**
-     * @param ctx application context (mandatory)
-     * @return a list of applications
-     */
-	public static DroidApp[] getApps(Context ctx) {
-		if (applications != null) {
-			// return cached instance
-			return applications;
-		}
-		final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);
-		// allowed application names separated by pipe '|' (persisted)
-		final String savedUids_wifi = prefs.getString(PREF_WIFI_UIDS, "");
-		final String savedUids_3g = prefs.getString(PREF_3G_UIDS, "");
-		int selected_wifi[] = new int[0];
-		int selected_3g[] = new int[0];
-		if (savedUids_wifi.length() > 0) {
-			// Check which applications are allowed
-			final StringTokenizer tok = new StringTokenizer(savedUids_wifi, "|");
-			selected_wifi = new int[tok.countTokens()];
-			for (int i=0; i<selected_wifi.length; i++) {
-				final String uid = tok.nextToken();
-				if (!uid.equals("")) {
-					try {
-						selected_wifi[i] = Integer.parseInt(uid);
-					} catch (Exception ex) {
-						selected_wifi[i] = -1;
-					}
-				}
-			}
-			// Sort the array to allow using "Arrays.binarySearch" later
-			Arrays.sort(selected_wifi);
-		}
-		if (savedUids_3g.length() > 0) {
-			// Check which applications are allowed
-			final StringTokenizer tok = new StringTokenizer(savedUids_3g, "|");
-			selected_3g = new int[tok.countTokens()];
-			for (int i=0; i<selected_3g.length; i++) {
-				final String uid = tok.nextToken();
-				if (!uid.equals("")) {
-					try {
-						selected_3g[i] = Integer.parseInt(uid);
-					} catch (Exception ex) {
-						selected_3g[i] = -1;
-					}
-				}
-			}
-			// Sort the array to allow using "Arrays.binarySearch" later
-			Arrays.sort(selected_3g);
-		}
-		try {
-			final PackageManager pkgmanager = ctx.getPackageManager();
-			final List<ApplicationInfo> installed = pkgmanager.getInstalledApplications(0);
-			final HashMap<Integer, DroidApp> map = new HashMap<Integer, DroidApp>();
-			final Editor edit = prefs.edit();
-			boolean changed = false;
-			String name = null;
-			String cachekey = null;
-			DroidApp app = null;
-			for (final ApplicationInfo apinfo : installed) {
-				app = map.get(apinfo.uid);
-				// filter applications which are not allowed to access the Internet
-				if (app == null && PackageManager.PERMISSION_GRANTED != pkgmanager.checkPermission(Manifest.permission.INTERNET, apinfo.packageName)) {
-					continue;
-				}
-				// try to get the application label from our cache - getApplicationLabel() is horribly slow!!!!
-				cachekey = "cache.label."+apinfo.packageName;
-				name = prefs.getString(cachekey, "");
-				if (name.length() == 0) {
-					// get label and put on cache
-					name = pkgmanager.getApplicationLabel(apinfo).toString();
-					edit.putString(cachekey, name);
-					changed = true;
-				}
-				if (app == null) {
-					app = new DroidApp();
-					app.uid = apinfo.uid;
-					app.names = new String[] { name };
-					map.put(apinfo.uid, app);
-				} else {
-					final String newnames[] = new String[app.names.length + 1];
-					System.arraycopy(app.names, 0, newnames, 0, app.names.length);
-					newnames[app.names.length] = name;
-					app.names = newnames;
-				}
-				// check if this application is selected
-				if (!app.selected_wifi && Arrays.binarySearch(selected_wifi, app.uid) >= 0) {
-					app.selected_wifi = true;
-				}
-				if (!app.selected_3g && Arrays.binarySearch(selected_3g, app.uid) >= 0) {
-					app.selected_3g = true;
-				}
-			}
-			if (changed) {
-				edit.commit();
-			}
-			/* add special applications to the list */
-			final DroidApp special[] = {
-				new DroidApp(SPECIAL_UID_ANY,"(Any application) - Same as selecting all applications", false, false),
-				new DroidApp(SPECIAL_UID_KERNEL,"(Kernel) - Linux kernel", false, false),
-				new DroidApp(android.os.Process.getUidForName("root"), "(root) - Applications running as root", false, false),
-				new DroidApp(android.os.Process.getUidForName("media"), "Media server", false, false),
-				new DroidApp(android.os.Process.getUidForName("vpn"), "VPN networking", false, false),
-				new DroidApp(android.os.Process.getUidForName("shell"), "Linux shell", false, false),
-			};
-			for (int i=0; i<special.length; i++) {
-				app = special[i];
-				if (app.uid != -1 && !map.containsKey(app.uid)) {
-					// check if this application is allowed
-					if (Arrays.binarySearch(selected_wifi, app.uid) >= 0) {
-						app.selected_wifi = true;
-					}
-					if (Arrays.binarySearch(selected_3g, app.uid) >= 0) {
-						app.selected_3g = true;
-					}
-					map.put(app.uid, app);
-				}
-			}
-			applications = new DroidApp[map.size()];
-			int index = 0;
-			for (DroidApp application : map.values()) applications[index++] = application;
-			return applications;
-		} catch (Exception e) {
-			alert(ctx, "error: " + e);
-		}
-		return null;
-	}
-	/**
-	 * Check if we have root access
-	 * @param ctx mandatory context
-     * @param showErrors indicates if errors should be alerted
-	 * @return boolean true if we have root
-	 */
-	public static boolean hasRootAccess(Context ctx, boolean showErrors) {
-		if (hasroot) return true;
-		final StringBuilder res = new StringBuilder();
-		try {
-			// Run an empty script just to check root access
-			if (runScriptAsRoot(ctx, "exit 0", res) == 0) {
-				hasroot = true;
-				return true;
-			}
-		} catch (Exception e) {
-		}
-		if (showErrors) {
-			alert(ctx, "Could not acquire root access.\n" +
-				"You need a rooted phone to run DroidWall.\n\n" +
-				"If this phone is already rooted, please make sure DroidWall has enough permissions to execute the \"su\" command.\n" +
-				"Error message: " + res.toString());
-		}
-		return false;
-	}
-    /**
-     * Runs a script, wither as root or as a regular user (multiple commands separated by "\n").
-	 * @param ctx mandatory context
-     * @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 runScript(Context ctx, String script, StringBuilder res, long timeout, boolean asroot) {
-		final File file = new File(ctx.getDir("bin",0), SCRIPT_FILE);
-		final ScriptRunner runner = new ScriptRunner(file, script, res, asroot);
-		runner.start();
-		try {
-			if (timeout > 0) {
-				runner.join(timeout);
-			} else {
-				runner.join();
-			}
-			if (runner.isAlive()) {
-				// Timed-out
-				runner.interrupt();
-				runner.join(150);
-				runner.destroy();
-				runner.join(50);
-			}
-		} catch (InterruptedException ex) {}
-		return runner.exitcode;
-	}
-    /**
-     * Runs a script as root (multiple commands separated by "\n").
-	 * @param ctx mandatory context
-     * @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(Context ctx, String script, StringBuilder res, long timeout) {
-		return runScript(ctx, script, res, timeout, true);
-    }
-    /**
-     * Runs a script as root (multiple commands separated by "\n") with a default timeout of 20 seconds.
-	 * @param ctx mandatory context
-     * @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(Context ctx, String script, StringBuilder res) throws IOException {
-		return runScriptAsRoot(ctx, script, res, 40000);
-	}
-    /**
-     * Runs a script as a regular user (multiple commands separated by "\n") with a default timeout of 20 seconds.
-	 * @param ctx mandatory context
-     * @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 runScript(Context ctx, String script, StringBuilder res) throws IOException {
-		return runScript(ctx, script, res, 40000, false);
-	}
-	/**
-	 * Asserts that the binary files are installed in the cache directory.
-	 * @param ctx context
-     * @param showErrors indicates if errors should be alerted
-	 * @return false if the binary files could not be installed
-	 */
-	public static boolean assertBinaries(Context ctx, boolean showErrors) {
-		boolean changed = false;
-		try {
-			// Check iptables_g1
-			File file = new File(ctx.getDir("bin",0), "iptables");
-			
-			if ((!file.exists()) && isARMv6()) {
-				copyRawFile(ctx, R.raw.iptables_g1, file, "755");
-				changed = true;
-			}
-			
-			// Check iptables_n1
-			file = new File(ctx.getDir("bin",0), "iptables");
-			if ((!file.exists()) && (!isARMv6())) {
-				copyRawFile(ctx, R.raw.iptables_n1, file, "755");
-				changed = true;
-			}
-			
-			// Check busybox
-			/*
-			file = new File(ctx.getDir("bin",0), "busybox_g1");
-			if (!file.exists()) {
-				copyRawFile(ctx, R.raw.busybox_g1, file, "755");
-				changed = true;
-			}
-			*/
-			
-			if (changed) {
-				Toast.makeText(ctx, R.string.status_install_success, Toast.LENGTH_LONG).show();
-			}
-		} catch (Exception e) {
-			if (showErrors) alert(ctx, "Error installing binary files: " + e);
-			return false;
-		}
-		return true;
-	}
-	/**
-	 * Check if the firewall is enabled
-	 * @param ctx mandatory context
-	 * @return boolean
-	 */
-	public static boolean isEnabled(Context ctx) {
-		if (ctx == null) return false;
-		return ctx.getSharedPreferences(PREFS_NAME, 0).getBoolean(PREF_ENABLED, false);
-	}
-	
-	/**
-	 * Defines if the firewall is enabled and broadcasts the new status
-	 * @param ctx mandatory context
-	 * @param enabled enabled flag
-	 */
-	public static void setEnabled(Context ctx, boolean enabled) {
-		if (ctx == null) return;
-		final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);
-		if (prefs.getBoolean(PREF_ENABLED, false) == enabled) {
-			return;
-		}
-		final Editor edit = prefs.edit();
-		edit.putBoolean(PREF_ENABLED, enabled);
-		if (!edit.commit()) {
-			alert(ctx, "Error writing to preferences");
-			return;
-		}
-		/* notify */
-		final Intent message = new Intent(IptablesManager.STATUS_CHANGED_MSG);
-        message.putExtra(IptablesManager.STATUS_EXTRA, enabled);
-        ctx.sendBroadcast(message);
-	}
-	/**
-	 * Called when an application in removed (un-installed) from the system.
-	 * This will look for that application in the selected list and update the persisted values if necessary
-	 * @param ctx mandatory app context
-	 * @param uid UID of the application that has been removed
-	 */
-	public static void applicationRemoved(Context ctx, int uid) {
-		final SharedPreferences prefs = ctx.getSharedPreferences(PREFS_NAME, 0);
-		final Editor editor = prefs.edit();
-		// allowed application names separated by pipe '|' (persisted)
-		final String savedUids_wifi = prefs.getString(PREF_WIFI_UIDS, "");
-		final String savedUids_3g = prefs.getString(PREF_3G_UIDS, "");
-		final String uid_str = uid + "";
-		boolean changed = false;
-		// look for the removed application in the "wi-fi" list
-		if (savedUids_wifi.length() > 0) {
-			final StringBuilder newuids = new StringBuilder();
-			final StringTokenizer tok = new StringTokenizer(savedUids_wifi, "|");
-			while (tok.hasMoreTokens()) {
-				final String token = tok.nextToken();
-				if (uid_str.equals(token)) {
-					Log.d("DroidWall", "Removing UID " + token + " from the wi-fi list (package removed)!");
-					changed = true;
-				} else {
-					if (newuids.length() > 0) newuids.append('|');
-					newuids.append(token);
-				}
-			}
-			if (changed) {
-				editor.putString(PREF_WIFI_UIDS, newuids.toString());
-			}
-		}
-		// look for the removed application in the "3g" list
-		if (savedUids_3g.length() > 0) {
-			final StringBuilder newuids = new StringBuilder();
-			final StringTokenizer tok = new StringTokenizer(savedUids_3g, "|");
-			while (tok.hasMoreTokens()) {
-				final String token = tok.nextToken();
-				if (uid_str.equals(token)) {
-					Log.d("DroidWall", "Removing UID " + token + " from the 3G list (package removed)!");
-					changed = true;
-				} else {
-					if (newuids.length() > 0) newuids.append('|');
-					newuids.append(token);
-				}
-			}
-			if (changed) {
-				editor.putString(PREF_3G_UIDS, newuids.toString());
-			}
-		}
-		// if anything has changed, save the new prefs...
-		if (changed) {
-			editor.commit();
-			if (isEnabled(ctx)) {
-				// .. and also re-apply the rules if the firewall is enabled
-				applySavedIptablesRules(ctx, false);
-			}
-		}
-	}
-
-    /**
-     * Small structure to hold an application info
-     */
-	public static final class DroidApp {
-		/** linux user id */
-    	int uid;
-    	/** application names belonging to this user id */
-    	String names[];
-    	/** indicates if this application is selected for wifi */
-    	boolean selected_wifi;
-    	/** indicates if this application is selected for 3g */
-    	boolean selected_3g;
-    	/** toString cache */
-    	String tostr;
-    	
-    	public DroidApp() {
-    	}
-    	public DroidApp(int uid, String name, boolean selected_wifi, boolean selected_3g) {
-    		this.uid = uid;
-    		this.names = new String[] {name};
-    		this.selected_wifi = selected_wifi;
-    		this.selected_3g = selected_3g;
-    	}
-    	/**
-    	 * Screen representation of this application
-    	 */
-    	@Override
-    	public String toString() {
-    		if (tostr == null) {
-        		final StringBuilder s = new StringBuilder();
-        		if (uid > 0) s.append(uid + ": ");
-        		for (int i=0; i<names.length; i++) {
-        			if (i != 0) s.append(", ");
-        			s.append(names[i]);
-        		}
-        		s.append("\n");
-        		tostr = s.toString();
-    		}
-    		return tostr;
-    	}
-    }
-    /**
-     * Small internal structure used to hold log information
-     */
-	private static final class LogInfo {
-		private int totalBlocked; // Total number of packets blocked
-		private HashMap<String, Integer> dstBlocked; // Number of packets blocked per destination IP address
-		private LogInfo() {
-			this.dstBlocked = new HashMap<String, Integer>();
-		}
-	}
-	/**
-	 * Internal thread used to execute scripts (as root or not).
-	 */
-	private static final class ScriptRunner extends Thread {
-		private final File file;
-		private final String script;
-		private final StringBuilder res;
-		private final boolean asroot;
-		public int exitcode = -1;
-		private Process exec;
-		
-		/**
-		 * Creates a new script runner.
-		 * @param file temporary script file
-		 * @param script script to run
-		 * @param res response output
-		 * @param asroot if true, executes the script as root
-		 */
-		public ScriptRunner(File file, String script, StringBuilder res, boolean asroot) {
-			this.file = file;
-			this.script = script;
-			this.res = res;
-			this.asroot = asroot;
-		}
-		@Override
-		public void run() {
-			try {
-				file.createNewFile();
-				final String abspath = file.getAbsolutePath();
-				// make sure we have execution permission on the script file
-				Runtime.getRuntime().exec("chmod 777 "+abspath).waitFor();
-				// Write the script to be executed
-				final OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file));
-				if (new File("/system/bin/sh").exists()) {
-					out.write("#!/system/bin/sh\n");
-				}
-				out.write(script);
-				if (!script.endsWith("\n")) out.write("\n");
-				out.write("exit\n");
-				out.flush();
-				out.close();
-				if (this.asroot) {
-					// Create the "su" request to run the script
-					exec = Runtime.getRuntime().exec("su -c "+abspath);
-				} else {
-					// Create the "sh" request to run the script
-					exec = Runtime.getRuntime().exec("sh "+abspath);
-				}
-				InputStreamReader r = new InputStreamReader(exec.getInputStream());
-				final char buf[] = new char[1024];
-				int read = 0;
-				// Consume the "stdout"
-				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;
-		}
-	}
-}
diff --git a/src/org/torproject/android/service/TorBinaryInstaller.java b/src/org/torproject/android/service/TorBinaryInstaller.java
index ff1e720..07b5049 100644
--- a/src/org/torproject/android/service/TorBinaryInstaller.java
+++ b/src/org/torproject/android/service/TorBinaryInstaller.java
@@ -3,10 +3,12 @@
 
 package org.torproject.android.service;
 
+import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -22,6 +24,7 @@ import org.torproject.android.TorConstants;
 
 import android.content.Context;
 import android.util.Log;
+import android.widget.Toast;
 
 public class TorBinaryInstaller implements TorServiceConstants {
 
@@ -29,6 +32,8 @@ public class TorBinaryInstaller implements TorServiceConstants {
 	File installFolder;
 	Context context;
 	
+    private static int isARMv6 = -1;
+
 	public TorBinaryInstaller (Context context, File installFolder)
 	{
 		this.installFolder = installFolder;
@@ -151,4 +156,97 @@ public class TorBinaryInstaller implements TorServiceConstants {
 	
 	
 
+    /**
+	 * Check if this is an ARMv6 device
+	 * @return true if this is ARMv6
+	 */
+	private static boolean isARMv6() {
+		if (isARMv6 == -1) {
+			BufferedReader r = null;
+			try {
+				isARMv6 = 0;
+				r = new BufferedReader(new FileReader("/proc/cpuinfo"));
+				for (String line = r.readLine(); line != null; line = r.readLine()) {
+					if (line.startsWith("Processor") && line.contains("ARMv6")) {
+						isARMv6 = 1;
+						break;
+					} else if (line.startsWith("CPU architecture") && (line.contains("6TE") || line.contains("5TE"))) {
+						isARMv6 = 1;
+						break;
+					}
+				}
+			} catch (Exception ex) {
+			} finally {
+				if (r != null) try {r.close();} catch (Exception ex) {}
+			}
+		}
+		return (isARMv6 == 1);
+	}
+	
+	/**
+	 * Copies a raw resource file, given its ID to the given location
+	 * @param ctx context
+	 * @param resid resource id
+	 * @param file destination file
+	 * @param mode file permissions (E.g.: "755")
+	 * @throws IOException on error
+	 * @throws InterruptedException when interrupted
+	 */
+	private static void copyRawFile(Context ctx, int resid, File file, String mode) throws IOException, InterruptedException
+	{
+		final String abspath = file.getAbsolutePath();
+		// Write the iptables binary
+		final FileOutputStream out = new FileOutputStream(file);
+		final InputStream is = ctx.getResources().openRawResource(resid);
+		byte buf[] = new byte[1024];
+		int len;
+		while ((len = is.read(buf)) > 0) {
+			out.write(buf, 0, len);
+		}
+		out.close();
+		is.close();
+		// Change the permissions
+		Runtime.getRuntime().exec("chmod "+mode+" "+abspath).waitFor();
+	}
+    /**
+	 * Asserts that the binary files are installed in the cache directory.
+	 * @param ctx context
+     * @param showErrors indicates if errors should be alerted
+	 * @return false if the binary files could not be installed
+	 */
+	public static boolean assertIpTablesBinaries(Context ctx, boolean showErrors) throws Exception {
+		boolean changed = false;
+		
+		// Check iptables_g1
+		File file = new File(ctx.getDir("bin",0), "iptables");
+		
+		if ((!file.exists()) && isARMv6()) {
+			copyRawFile(ctx, R.raw.iptables_g1, file, "755");
+			changed = true;
+		}
+		
+		// Check iptables_n1
+		file = new File(ctx.getDir("bin",0), "iptables");
+		if ((!file.exists()) && (!isARMv6())) {
+			copyRawFile(ctx, R.raw.iptables_n1, file, "755");
+			changed = true;
+		}
+		
+		// Check busybox
+		/*
+		file = new File(ctx.getDir("bin",0), "busybox_g1");
+		if (!file.exists()) {
+			copyRawFile(ctx, R.raw.busybox_g1, file, "755");
+			changed = true;
+		}
+		*/
+		
+		if (changed) {
+				Toast.makeText(ctx, R.string.status_install_success, Toast.LENGTH_LONG).show();
+			}
+		
+		return true;
+	}
+	
+
 }
diff --git a/src/org/torproject/android/service/TorService.java b/src/org/torproject/android/service/TorService.java
index df2990d..2b1c91d 100644
--- a/src/org/torproject/android/service/TorService.java
+++ b/src/org/torproject/android/service/TorService.java
@@ -1,11 +1,20 @@
 /* Copyright (c) 2009-2011, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
 /* See LICENSE for licensing information */
+/*
+ * Code for iptables binary management taken from DroidWall GPLv3
+ * Copyright (C) 2009-2010  Rodrigo Zechin Rosauro
+ */
+
 package org.torproject.android.service;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.Socket;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -39,6 +48,7 @@ import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.preference.PreferenceManager;
 import android.util.Log;
+import android.widget.Toast;
 
 public class TorService extends Service implements TorServiceConstants, TorConstants, Runnable, EventHandler
 {
@@ -414,8 +424,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
     private boolean checkTorBinaries () throws Exception
     {
     	//check and install iptables
-    	IptablesManager.assertBinaries(this, true);
-    	
+    	TorBinaryInstaller.assertIpTablesBinaries(this, true);
     	
     	appBinHome = getDir("bin",0);
     	appDataHome = getCacheDir();
@@ -520,6 +529,8 @@ public class TorService extends Service implements TorServiceConstants, TorConst
  		boolean hasRoot = prefs.getBoolean(PREF_HAS_ROOT,false);
  		boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false);
  		
+ 		TorTransProxy ttProxy = new TorTransProxy();
+ 		
  		if (hasRoot && enableTransparentProxy)
     	{
 	 		
@@ -544,7 +555,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
 				int status = code;
 				while (st.hasMoreTokens())
 				{
-					status = TorTransProxy.setTransparentProxyingByPort(this, Integer.parseInt(st.nextToken()));
+					status = ttProxy.setTransparentProxyingByPort(this, Integer.parseInt(st.nextToken()));
 					if(status != 0)
 						code = status;
 				}
@@ -554,12 +565,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst
 				if(transProxyAll)
 				{
 					showAlert(getString(R.string.status), getString(R.string.setting_up_full_transparent_proxying_));
-					code = TorTransProxy.setTransparentProxyingAll(this);
+					code = ttProxy.setTransparentProxyingAll(this);
 				}
 				else
 				{
 					showAlert(getString(R.string.status), getString(R.string.setting_up_app_based_transparent_proxying_));
-					code = TorTransProxy.setTransparentProxyingByApp(this,AppManager.getApps(this));
+					code = ttProxy.setTransparentProxyingByApp(this,AppManager.getApps(this));
 				}
 				
 			}
@@ -576,7 +587,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
 				{
 					showAlert(getString(R.string.status), getString(R.string.transproxy_enabled_for_tethering_));
 
-					TorTransProxy.enableTetheringRules(this);
+					ttProxy.enableTetheringRules(this);
 					  
 				}
 			}
@@ -604,12 +615,13 @@ public class TorService extends Service implements TorServiceConstants, TorConst
  		boolean hasRoot = prefs.getBoolean(PREF_HAS_ROOT,false);
  		boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false);
  		
+ 		
  		if (hasRoot && enableTransparentProxy)
     	{
 	 		
 	     	TorService.logMessage ("Clearing TransProxy rules");
 	     	
-	     	TorTransProxy.flushIptables(this);
+	     	new TorTransProxy().flushIptables(this);
 	     	
 			showAlert(getString(R.string.status), getString(R.string.transproxy_rules_cleared));
 	     	
diff --git a/src/org/torproject/android/service/TorTransProxy.java b/src/org/torproject/android/service/TorTransProxy.java
index bf5fee2..462d2f0 100644
--- a/src/org/torproject/android/service/TorTransProxy.java
+++ b/src/org/torproject/android/service/TorTransProxy.java
@@ -6,17 +6,59 @@ import org.torproject.android.TorConstants;
 import org.torproject.android.settings.TorifiedApp;
 
 import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
 import android.util.Log;
 
 public class TorTransProxy implements TorServiceConstants {
 	
-	private final static String TAG = TorConstants.TAG;
-		
+	private String ipTablesPath;
+
+	public String getIpTablesPath (Context context)
+	{
+	
+		if (ipTablesPath == null)
+		{
+			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+			
+			if (prefs.getBoolean(TorConstants.PREF_USE_SYSTEM_IPTABLES, false))
+			{
+				//if the user wants us to use the built-in iptables, then we have to find it
+				File fileIpt = new File("/system/bin/iptables");
+				
+				if (fileIpt.exists())
+					 ipTablesPath = fileIpt.getAbsolutePath();
+				else
+				{
+				
+					fileIpt = new File("/system/xbin/iptables");
+					
+					if (fileIpt.exists())
+						return (ipTablesPath = fileIpt.getAbsolutePath());
+					else
+					{
+						//use the bundled version
+						ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+					}
+				}				
+			}
+			else
+			{
+				//use the bundled version
 	
-	public static int flushIptables(Context context) throws Exception {
+				ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+			}
+			
+		}
+			
+		return ipTablesPath;
 		
-	String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+	}
+	
+	public int flushIptables(Context context) throws Exception {
 		
+		String ipTablesPath = getIpTablesPath(context);
+	
     	final StringBuilder script = new StringBuilder();
     	
     	StringBuilder res = new StringBuilder();
@@ -124,16 +166,17 @@ public class TorTransProxy implements TorServiceConstants {
 	}
 	*/
 	
-	public static int testOwnerModule(Context context) throws Exception
+	public int testOwnerModule(Context context) throws Exception
 	{
 
+		TorBinaryInstaller.assertIpTablesBinaries(context, false);
+		
 		boolean runRoot = true;
     	boolean waitFor = true;
     	
-		//redirectDNSResolvConf(); //not working yet
     	int torUid = context.getApplicationInfo().uid;
 
-		String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+		String ipTablesPath = getIpTablesPath(context);
 		
     	StringBuilder script = new StringBuilder();
     	
@@ -161,7 +204,7 @@ public class TorTransProxy implements TorServiceConstants {
 	
 	
 	
-	public static int setTransparentProxyingByApp(Context context, TorifiedApp[] apps) throws Exception
+	public int setTransparentProxyingByApp(Context context, TorifiedApp[] apps) throws Exception
 	{
 
 		boolean runRoot = true;
@@ -169,7 +212,7 @@ public class TorTransProxy implements TorServiceConstants {
     	
 		//redirectDNSResolvConf(); //not working yet
 		
-		String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+		String ipTablesPath = getIpTablesPath(context);
 		
     	StringBuilder script = new StringBuilder();
     	
@@ -261,7 +304,7 @@ public class TorTransProxy implements TorServiceConstants {
 		return code;
     }	
 	
-	public static int setTransparentProxyingByPort(Context context, int port) throws Exception
+	public int setTransparentProxyingByPort(Context context, int port) throws Exception
 	{
 
 		//android.os.Debug.waitForDebugger();
@@ -269,7 +312,7 @@ public class TorTransProxy implements TorServiceConstants {
 		//redirectDNSResolvConf(); //not working yet
 		
 		//String baseDir = context.getDir("bin",0).getAbsolutePath() + '/';
-		String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+		String ipTablesPath = getIpTablesPath(context);
 		
     	StringBuilder script = new StringBuilder();
     	
@@ -318,13 +361,13 @@ public class TorTransProxy implements TorServiceConstants {
 		return code;
     }
 
-	public static int enableTetheringRules (Context context) throws Exception
+	public int enableTetheringRules (Context context) throws Exception
 	{
 		
 		boolean runRoot = true;
     	boolean waitFor = true;
     	
-		String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+		String ipTablesPath = getIpTablesPath(context);
 		
     	StringBuilder script = new StringBuilder();
     	
@@ -360,14 +403,14 @@ public class TorTransProxy implements TorServiceConstants {
 		return code;
 	}
 	
-	public static int setTransparentProxyingAll(Context context) throws Exception 
+	public int setTransparentProxyingAll(Context context) throws Exception 
 	{
 		boolean runRoot = true;
     	boolean waitFor = true;
     	
 		//redirectDNSResolvConf(); //not working yet
 		
-		String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
+		String ipTablesPath = getIpTablesPath(context);
 		
     	StringBuilder script = new StringBuilder();
     	
diff --git a/src/org/torproject/android/wizard/Permissions.java b/src/org/torproject/android/wizard/Permissions.java
index 151e6cb..5e17b67 100644
--- a/src/org/torproject/android/wizard/Permissions.java
+++ b/src/org/torproject/android/wizard/Permissions.java
@@ -164,7 +164,7 @@ public class Permissions extends Activity implements TorConstants {
 				if (hasRoot)
 				{
 					try {
-						int resp = TorTransProxy.testOwnerModule(context);
+						int resp = new TorTransProxy().testOwnerModule(context);
 						
 						if (resp < 0)
 						{
diff --git a/src/org/torproject/android/wizard/WizardHelper.java b/src/org/torproject/android/wizard/WizardHelper.java
index 18be47f..881d38d 100644
--- a/src/org/torproject/android/wizard/WizardHelper.java
+++ b/src/org/torproject/android/wizard/WizardHelper.java
@@ -93,17 +93,16 @@ public class WizardHelper implements TorConstants {
 			@Override
 			public void onClick(View view) {
 				
+				boolean iCanHazRoot = TorServiceUtils.isRootPossible();
 				
-				boolean isRootPossible = TorServiceUtils.isRootPossible();
-				
-				if (isRootPossible)
+				if (iCanHazRoot)
 				{
 					try {
-						int resp = TorTransProxy.testOwnerModule(context);
+						int resp = new TorTransProxy().testOwnerModule(context);
 						
 						if (resp < 0)
 						{
-							isRootPossible = false;
+							iCanHazRoot = false;
 							Toast.makeText(context, "ERROR: IPTables OWNER module not available", Toast.LENGTH_LONG).show();
 
 							Log.i(TorService.TAG,"ERROR: IPTables OWNER module not available");
@@ -111,21 +110,12 @@ public class WizardHelper implements TorConstants {
 						
 					} catch (Exception e) {
 						
-						isRootPossible = false;
+						iCanHazRoot = false;
 						Log.d(TorService.TAG,"ERROR: IPTables OWNER module not available",e);
 					}
 				}
 
-				/*
-				 * we shouldn't store root here, as this step is just chekcing to see if root is possible
-				SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-
-				Editor pEdit = prefs.edit();
-				pEdit.putBoolean("has_root",hasRoot);
-				pEdit.commit();
-				*/
-				
-				if (isRootPossible)
+				if (iCanHazRoot)
 				{
 					currentDialog.dismiss();
 					showWizardStep2Root();





More information about the tor-commits mailing list