cleaned up iptables binary handling

This commit is contained in:
Nathan Freitas 2012-01-12 20:58:21 -05:00
parent 4bbca2927d
commit b8af143d5f
7 changed files with 183 additions and 1097 deletions

View File

@ -43,5 +43,6 @@ public interface TorConstants {
public final static String PREF_HAS_ROOT = "has_root"; public final static String PREF_HAS_ROOT = "has_root";
public final static int RESULT_CLOSE_ALL = 0; public final static int RESULT_CLOSE_ALL = 0;
public final static String PREF_USE_SYSTEM_IPTABLES = "pref_use_sys_iptables";
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,10 +3,12 @@
package org.torproject.android.service; package org.torproject.android.service;
import java.io.BufferedReader;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -22,6 +24,7 @@ import org.torproject.android.TorConstants;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
public class TorBinaryInstaller implements TorServiceConstants { public class TorBinaryInstaller implements TorServiceConstants {
@ -29,6 +32,8 @@ public class TorBinaryInstaller implements TorServiceConstants {
File installFolder; File installFolder;
Context context; Context context;
private static int isARMv6 = -1;
public TorBinaryInstaller (Context context, File installFolder) public TorBinaryInstaller (Context context, File installFolder)
{ {
this.installFolder = 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;
}
} }

View File

@ -1,11 +1,20 @@
/* Copyright (c) 2009-2011, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ /* Copyright (c) 2009-2011, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
/* See LICENSE for licensing information */ /* 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; package org.torproject.android.service;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -39,6 +48,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException; import android.os.RemoteException;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
public class TorService extends Service implements TorServiceConstants, TorConstants, Runnable, EventHandler 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 private boolean checkTorBinaries () throws Exception
{ {
//check and install iptables //check and install iptables
IptablesManager.assertBinaries(this, true); TorBinaryInstaller.assertIpTablesBinaries(this, true);
appBinHome = getDir("bin",0); appBinHome = getDir("bin",0);
appDataHome = getCacheDir(); appDataHome = getCacheDir();
@ -520,6 +529,8 @@ public class TorService extends Service implements TorServiceConstants, TorConst
boolean hasRoot = prefs.getBoolean(PREF_HAS_ROOT,false); boolean hasRoot = prefs.getBoolean(PREF_HAS_ROOT,false);
boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false); boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false);
TorTransProxy ttProxy = new TorTransProxy();
if (hasRoot && enableTransparentProxy) if (hasRoot && enableTransparentProxy)
{ {
@ -544,7 +555,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
int status = code; int status = code;
while (st.hasMoreTokens()) while (st.hasMoreTokens())
{ {
status = TorTransProxy.setTransparentProxyingByPort(this, Integer.parseInt(st.nextToken())); status = ttProxy.setTransparentProxyingByPort(this, Integer.parseInt(st.nextToken()));
if(status != 0) if(status != 0)
code = status; code = status;
} }
@ -554,12 +565,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst
if(transProxyAll) if(transProxyAll)
{ {
showAlert(getString(R.string.status), getString(R.string.setting_up_full_transparent_proxying_)); showAlert(getString(R.string.status), getString(R.string.setting_up_full_transparent_proxying_));
code = TorTransProxy.setTransparentProxyingAll(this); code = ttProxy.setTransparentProxyingAll(this);
} }
else else
{ {
showAlert(getString(R.string.status), getString(R.string.setting_up_app_based_transparent_proxying_)); 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_)); 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 hasRoot = prefs.getBoolean(PREF_HAS_ROOT,false);
boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false); boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false);
if (hasRoot && enableTransparentProxy) if (hasRoot && enableTransparentProxy)
{ {
TorService.logMessage ("Clearing TransProxy rules"); TorService.logMessage ("Clearing TransProxy rules");
TorTransProxy.flushIptables(this); new TorTransProxy().flushIptables(this);
showAlert(getString(R.string.status), getString(R.string.transproxy_rules_cleared)); showAlert(getString(R.string.status), getString(R.string.transproxy_rules_cleared));

View File

@ -6,16 +6,58 @@ import org.torproject.android.TorConstants;
import org.torproject.android.settings.TorifiedApp; import org.torproject.android.settings.TorifiedApp;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
public class TorTransProxy implements TorServiceConstants { public class TorTransProxy implements TorServiceConstants {
private final static String TAG = TorConstants.TAG; private String ipTablesPath;
public String getIpTablesPath (Context context)
{
public static int flushIptables(Context context) throws Exception { if (ipTablesPath == null)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath(); 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
ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath();
}
}
return ipTablesPath;
}
public int flushIptables(Context context) throws Exception {
String ipTablesPath = getIpTablesPath(context);
final StringBuilder script = new StringBuilder(); final StringBuilder script = 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 runRoot = true;
boolean waitFor = true; boolean waitFor = true;
//redirectDNSResolvConf(); //not working yet
int torUid = context.getApplicationInfo().uid; int torUid = context.getApplicationInfo().uid;
String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath(); String ipTablesPath = getIpTablesPath(context);
StringBuilder script = new StringBuilder(); 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; boolean runRoot = true;
@ -169,7 +212,7 @@ public class TorTransProxy implements TorServiceConstants {
//redirectDNSResolvConf(); //not working yet //redirectDNSResolvConf(); //not working yet
String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath(); String ipTablesPath = getIpTablesPath(context);
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();
@ -261,7 +304,7 @@ public class TorTransProxy implements TorServiceConstants {
return code; 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(); //android.os.Debug.waitForDebugger();
@ -269,7 +312,7 @@ public class TorTransProxy implements TorServiceConstants {
//redirectDNSResolvConf(); //not working yet //redirectDNSResolvConf(); //not working yet
//String baseDir = context.getDir("bin",0).getAbsolutePath() + '/'; //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(); StringBuilder script = new StringBuilder();
@ -318,13 +361,13 @@ public class TorTransProxy implements TorServiceConstants {
return code; return code;
} }
public static int enableTetheringRules (Context context) throws Exception public int enableTetheringRules (Context context) throws Exception
{ {
boolean runRoot = true; boolean runRoot = true;
boolean waitFor = true; boolean waitFor = true;
String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath(); String ipTablesPath = getIpTablesPath(context);
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();
@ -360,14 +403,14 @@ public class TorTransProxy implements TorServiceConstants {
return code; return code;
} }
public static int setTransparentProxyingAll(Context context) throws Exception public int setTransparentProxyingAll(Context context) throws Exception
{ {
boolean runRoot = true; boolean runRoot = true;
boolean waitFor = true; boolean waitFor = true;
//redirectDNSResolvConf(); //not working yet //redirectDNSResolvConf(); //not working yet
String ipTablesPath = new File(context.getDir("bin", 0),"iptables").getAbsolutePath(); String ipTablesPath = getIpTablesPath(context);
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -164,7 +164,7 @@ public class Permissions extends Activity implements TorConstants {
if (hasRoot) if (hasRoot)
{ {
try { try {
int resp = TorTransProxy.testOwnerModule(context); int resp = new TorTransProxy().testOwnerModule(context);
if (resp < 0) if (resp < 0)
{ {

View File

@ -93,17 +93,16 @@ public class WizardHelper implements TorConstants {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
boolean iCanHazRoot = TorServiceUtils.isRootPossible();
boolean isRootPossible = TorServiceUtils.isRootPossible(); if (iCanHazRoot)
if (isRootPossible)
{ {
try { try {
int resp = TorTransProxy.testOwnerModule(context); int resp = new TorTransProxy().testOwnerModule(context);
if (resp < 0) if (resp < 0)
{ {
isRootPossible = false; iCanHazRoot = false;
Toast.makeText(context, "ERROR: IPTables OWNER module not available", Toast.LENGTH_LONG).show(); Toast.makeText(context, "ERROR: IPTables OWNER module not available", Toast.LENGTH_LONG).show();
Log.i(TorService.TAG,"ERROR: IPTables OWNER module not available"); Log.i(TorService.TAG,"ERROR: IPTables OWNER module not available");
@ -111,21 +110,12 @@ public class WizardHelper implements TorConstants {
} catch (Exception e) { } catch (Exception e) {
isRootPossible = false; iCanHazRoot = false;
Log.d(TorService.TAG,"ERROR: IPTables OWNER module not available",e); Log.d(TorService.TAG,"ERROR: IPTables OWNER module not available",e);
} }
} }
/* if (iCanHazRoot)
* 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)
{ {
currentDialog.dismiss(); currentDialog.dismiss();
showWizardStep2Root(); showWizardStep2Root();