improve tor service event handling and display
This commit is contained in:
parent
ebc046e92d
commit
9f61afcdef
|
@ -0,0 +1,328 @@
|
|||
package org.torproject.android.service;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.torproject.android.control.ConfigEntry;
|
||||
import org.torproject.android.control.EventHandler;
|
||||
import org.torproject.android.control.TorControlConnection;
|
||||
|
||||
/**
|
||||
* Created by n8fr8 on 9/25/16.
|
||||
*/
|
||||
public class TorEventHandler implements EventHandler, TorServiceConstants {
|
||||
|
||||
private TorService mService;
|
||||
|
||||
|
||||
private long lastRead = -1;
|
||||
private long lastWritten = -1;
|
||||
private long mTotalTrafficWritten = 0;
|
||||
private long mTotalTrafficRead = 0;
|
||||
|
||||
private NumberFormat mNumberFormat = null;
|
||||
|
||||
|
||||
private HashMap<String,Node> hmBuiltNodes = new HashMap<String,Node>();
|
||||
|
||||
public class Node
|
||||
{
|
||||
String status;
|
||||
String id;
|
||||
String name;
|
||||
String ipAddress;
|
||||
String country;
|
||||
String organization;
|
||||
}
|
||||
|
||||
public HashMap<String,Node> getNodes ()
|
||||
{
|
||||
return hmBuiltNodes;
|
||||
}
|
||||
|
||||
public TorEventHandler (TorService service)
|
||||
{
|
||||
mService = service;
|
||||
mNumberFormat = NumberFormat.getInstance(Locale.getDefault()); //localized numbers!
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(String severity, String msg) {
|
||||
mService.logNotice(severity + ": " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newDescriptors(List<String> orList) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orConnStatus(String status, String orName) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("orConnStatus (");
|
||||
sb.append(parseNodeName(orName) );
|
||||
sb.append("): ");
|
||||
sb.append(status);
|
||||
|
||||
mService.debug(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamStatus(String status, String streamID, String target) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("StreamStatus (");
|
||||
sb.append((streamID));
|
||||
sb.append("): ");
|
||||
sb.append(status);
|
||||
|
||||
mService.logNotice(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unrecognized(String type, String msg) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Message (");
|
||||
sb.append(type);
|
||||
sb.append("): ");
|
||||
sb.append(msg);
|
||||
|
||||
mService.logNotice(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bandwidthUsed(long read, long written) {
|
||||
|
||||
if (read != lastRead || written != lastWritten)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(formatCount(read));
|
||||
sb.append(" \u2193");
|
||||
sb.append(" / ");
|
||||
sb.append(formatCount(written));
|
||||
sb.append(" \u2191");
|
||||
|
||||
int iconId = R.drawable.ic_stat_tor;
|
||||
|
||||
if (read > 0 || written > 0)
|
||||
iconId = R.drawable.ic_stat_tor_xfer;
|
||||
|
||||
if (mService.hasConnectivity() && Prefs.expandedNotifications())
|
||||
mService.showToolbarNotification(sb.toString(), mService.getNotifyId(), iconId);
|
||||
|
||||
mTotalTrafficWritten += written;
|
||||
mTotalTrafficRead += read;
|
||||
}
|
||||
|
||||
lastWritten = written;
|
||||
lastRead = read;
|
||||
|
||||
mService.sendCallbackBandwidth(lastWritten, lastRead, mTotalTrafficWritten, mTotalTrafficRead);
|
||||
}
|
||||
|
||||
private String formatCount(long count) {
|
||||
// Converts the supplied argument into a string.
|
||||
|
||||
// Under 2Mb, returns "xxx.xKb"
|
||||
// Over 2Mb, returns "xxx.xxMb"
|
||||
if (mNumberFormat != null)
|
||||
if (count < 1e6)
|
||||
return mNumberFormat.format(Math.round((float)((int)(count*10/1024))/10)) + "kbps";
|
||||
else
|
||||
return mNumberFormat.format(Math.round((float)((int)(count*100/1024/1024))/100)) + "mbps";
|
||||
else
|
||||
return "";
|
||||
|
||||
//return count+" kB";
|
||||
}
|
||||
|
||||
public void circuitStatus(String status, String circID, String path) {
|
||||
|
||||
/* once the first circuit is complete, then announce that Orbot is on*/
|
||||
if (mService.getCurrentStatus() == STATUS_STARTING && TextUtils.equals(status, "BUILT"))
|
||||
mService.sendCallbackStatus(STATUS_ON);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Circuit (");
|
||||
sb.append((circID));
|
||||
sb.append(") ");
|
||||
sb.append(status);
|
||||
sb.append(": ");
|
||||
|
||||
StringTokenizer st = new StringTokenizer(path,",");
|
||||
Node node = null;
|
||||
|
||||
while (st.hasMoreTokens())
|
||||
{
|
||||
String nodePath = st.nextToken();
|
||||
node = new Node();
|
||||
|
||||
String[] nodeParts;
|
||||
|
||||
if (nodePath.contains("="))
|
||||
nodeParts = nodePath.split("=");
|
||||
else
|
||||
nodeParts = nodePath.split("~");
|
||||
|
||||
if (nodeParts.length == 1)
|
||||
{
|
||||
node.id = nodeParts[0].substring(1);
|
||||
node.name = node.id;
|
||||
}
|
||||
else if (nodeParts.length == 2)
|
||||
{
|
||||
node.id = nodeParts[0].substring(1);
|
||||
node.name = nodeParts[1];
|
||||
}
|
||||
|
||||
node.status = status;
|
||||
|
||||
sb.append(node.name);
|
||||
|
||||
if (st.hasMoreTokens())
|
||||
sb.append (" > ");
|
||||
}
|
||||
|
||||
if (Prefs.useDebugLogging())
|
||||
mService.debug(sb.toString());
|
||||
else if(status.equals("BUILT"))
|
||||
mService.logNotice(sb.toString());
|
||||
else if (status.equals("CLOSED"))
|
||||
mService.logNotice(sb.toString());
|
||||
|
||||
if (Prefs.expandedNotifications())
|
||||
{
|
||||
//get IP from last nodename
|
||||
if(status.equals("BUILT")){
|
||||
|
||||
if (node.ipAddress == null)
|
||||
mService.exec(new ExternalIPFetcher(node));
|
||||
|
||||
hmBuiltNodes.put(node.id, node);
|
||||
}
|
||||
|
||||
if (status.equals("CLOSED"))
|
||||
{
|
||||
hmBuiltNodes.remove(node.id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ExternalIPFetcher implements Runnable {
|
||||
|
||||
private Node mNode;
|
||||
private int MAX_ATTEMPTS = 3;
|
||||
private final static String ONIONOO_BASE_URL = "https://onionoo.torproject.org/details?fields=country_name,as_name,or_addresses&lookup=";
|
||||
|
||||
public ExternalIPFetcher (Node node)
|
||||
{
|
||||
mNode = node;
|
||||
}
|
||||
|
||||
public void run ()
|
||||
{
|
||||
|
||||
for (int i = 0; i < MAX_ATTEMPTS; i++)
|
||||
{
|
||||
if (mService.getControlConnection() != null)
|
||||
{
|
||||
try {
|
||||
|
||||
URLConnection conn = null;
|
||||
|
||||
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8118));
|
||||
conn = new URL(ONIONOO_BASE_URL + mNode.id).openConnection(proxy);
|
||||
|
||||
conn.setRequestProperty("Connection","Close");
|
||||
conn.setConnectTimeout(60000);
|
||||
conn.setReadTimeout(60000);
|
||||
|
||||
InputStream is = conn.getInputStream();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
// getting JSON string from URL
|
||||
|
||||
StringBuffer json = new StringBuffer();
|
||||
String line = null;
|
||||
|
||||
while ((line = reader.readLine())!=null)
|
||||
json.append(line);
|
||||
|
||||
JSONObject jsonNodeInfo = new org.json.JSONObject(json.toString());
|
||||
|
||||
JSONArray jsonRelays = jsonNodeInfo.getJSONArray("relays");
|
||||
|
||||
if (jsonRelays.length() > 0)
|
||||
{
|
||||
mNode.ipAddress = jsonRelays.getJSONObject(0).getJSONArray("or_addresses").getString(0).split(":")[0];
|
||||
mNode.country = jsonRelays.getJSONObject(0).getString("country_name");
|
||||
mNode.organization = jsonRelays.getJSONObject(0).getString("as_name");
|
||||
|
||||
StringBuffer sbInfo = new StringBuffer();
|
||||
sbInfo.append(mNode.ipAddress);
|
||||
|
||||
if (mNode.country != null)
|
||||
sbInfo.append(' ').append(mNode.country);
|
||||
|
||||
if (mNode.organization != null)
|
||||
sbInfo.append(" (").append(mNode.organization).append(')');
|
||||
|
||||
mService.logNotice(sbInfo.toString());
|
||||
|
||||
}
|
||||
|
||||
reader.close();
|
||||
is.close();
|
||||
|
||||
break;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
mService.debug ("Error getting node details from onionoo: " + e.getMessage());
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String parseNodeName(String node)
|
||||
{
|
||||
if (node.indexOf('=')!=-1)
|
||||
{
|
||||
return (node.substring(node.indexOf("=")+1));
|
||||
}
|
||||
else if (node.indexOf('~')!=-1)
|
||||
{
|
||||
return (node.substring(node.indexOf("~")+1));
|
||||
}
|
||||
else
|
||||
return node;
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class TorService extends Service implements TorServiceConstants, OrbotConstants, EventHandler
|
||||
public class TorService extends Service implements TorServiceConstants, OrbotConstants
|
||||
{
|
||||
|
||||
private String mCurrentStatus = STATUS_OFF;
|
||||
|
@ -106,14 +106,9 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
|
||||
private TorTransProxy mTransProxy;
|
||||
|
||||
private long mTotalTrafficWritten = 0;
|
||||
private long mTotalTrafficRead = 0;
|
||||
private boolean mConnectivity = true;
|
||||
private boolean mConnectivity = true;
|
||||
private int mNetworkType = -1;
|
||||
|
||||
private long lastRead = -1;
|
||||
private long lastWritten = -1;
|
||||
|
||||
private NotificationManager mNotificationManager = null;
|
||||
private Notification.Builder mNotifyBuilder;
|
||||
private Notification mNotification;
|
||||
|
@ -123,8 +118,9 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
|
||||
private ExecutorService mExecutor = Executors.newFixedThreadPool(1);
|
||||
|
||||
private NumberFormat mNumberFormat = null;
|
||||
|
||||
|
||||
TorEventHandler mEventHandler;
|
||||
|
||||
// private OrbotVpnManager mVpnManager;
|
||||
|
||||
public static File appBinHome;
|
||||
|
@ -133,7 +129,6 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
public static File fileTor;
|
||||
public static File filePolipo;
|
||||
public static File fileObfsclient;
|
||||
// public static File fileMeekclient;
|
||||
public static File fileXtables;
|
||||
public static File fileTorRc;
|
||||
public static File filePdnsd;
|
||||
|
@ -198,12 +193,12 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
mNotificationManager.cancelAll();
|
||||
|
||||
|
||||
hmBuiltNodes.clear();
|
||||
mEventHandler.getNodes().clear();
|
||||
mNotificationShowing = false;
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void showToolbarNotification (String notifyMsg, int notifyType, int icon)
|
||||
protected void showToolbarNotification (String notifyMsg, int notifyType, int icon)
|
||||
{
|
||||
|
||||
//Reusable code.
|
||||
|
@ -258,12 +253,12 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
expandedView.setTextViewText(R.id.info, notifyMsg);
|
||||
}
|
||||
|
||||
if (hmBuiltNodes.size() > 0)
|
||||
if (mEventHandler.getNodes().size() > 0)
|
||||
{
|
||||
Set<String> itBuiltNodes = hmBuiltNodes.keySet();
|
||||
Set<String> itBuiltNodes = mEventHandler.getNodes().keySet();
|
||||
for (String key : itBuiltNodes)
|
||||
{
|
||||
Node node = hmBuiltNodes.get(key);
|
||||
TorEventHandler.Node node = mEventHandler.getNodes().get(key);
|
||||
|
||||
if (node.ipAddress != null)
|
||||
{
|
||||
|
@ -374,17 +369,6 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
@Override
|
||||
public void onRevoke ()
|
||||
{
|
||||
//if (mVpnManager != null)
|
||||
// mVpnManager.onRevoke();
|
||||
|
||||
super.onRevoke();
|
||||
|
||||
}**/
|
||||
|
||||
private void stopTor ()
|
||||
{
|
||||
mExecutor.execute(new Runnable ()
|
||||
|
@ -515,31 +499,6 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
|
||||
}
|
||||
|
||||
// try these separately in case one fails, then it can try the next
|
||||
/**
|
||||
File cannotKillFile = null;
|
||||
try {
|
||||
TorServiceUtils.killProcess(fileObfsclient);
|
||||
} catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
Log.w(OrbotConstants.TAG,"could not kill obfsclient",e);
|
||||
cannotKillFile = fileObfsclient;
|
||||
}
|
||||
|
||||
try {
|
||||
TorServiceUtils.killProcess(filePolipo);
|
||||
} catch (IOException e) {
|
||||
Log.w(OrbotConstants.TAG,"could not kill polipo",e);
|
||||
cannotKillFile = filePolipo;
|
||||
}
|
||||
|
||||
try {
|
||||
TorServiceUtils.killProcess(fileTor);
|
||||
} catch (IOException e) {
|
||||
Log.w(OrbotConstants.TAG,"could not kill tor",e);
|
||||
cannotKillFile = fileTor;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private void requestTorRereadConfig() {
|
||||
|
@ -557,7 +516,7 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
}
|
||||
}
|
||||
|
||||
private void logNotice (String msg)
|
||||
protected void logNotice (String msg)
|
||||
{
|
||||
if (msg != null && msg.trim().length() > 0)
|
||||
{
|
||||
|
@ -584,7 +543,6 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
fileTorRc = new File(appBinHome, TorServiceConstants.TORRC_ASSET_KEY);
|
||||
filePdnsd = new File(appBinHome, TorServiceConstants.PDNSD_ASSET_KEY);
|
||||
|
||||
mNumberFormat = NumberFormat.getInstance(Locale.getDefault()); //localized numbers!
|
||||
|
||||
if (mNotificationManager == null)
|
||||
{
|
||||
|
@ -627,6 +585,11 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
Log.i("TorService", "onCreate end");
|
||||
}
|
||||
|
||||
protected String getCurrentStatus ()
|
||||
{
|
||||
return mCurrentStatus;
|
||||
}
|
||||
|
||||
private void torUpgradeAndConfig() throws IOException, TimeoutException {
|
||||
if (isTorUpgradeAndConfigComplete)
|
||||
return;
|
||||
|
@ -890,7 +853,7 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
}
|
||||
else
|
||||
{
|
||||
ArrayList<TorifiedApp> apps = getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
||||
ArrayList<TorifiedApp> apps = TorTransProxy.getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
||||
|
||||
code = mTransProxy.setTransparentProxyingByApp(this,apps, true);
|
||||
}
|
||||
|
@ -923,114 +886,6 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
return true;
|
||||
}
|
||||
|
||||
public static ArrayList<TorifiedApp> getApps (Context context, SharedPreferences prefs)
|
||||
{
|
||||
|
||||
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();
|
||||
|
||||
ArrayList<TorifiedApp> apps = new ArrayList<TorifiedApp>();
|
||||
|
||||
ApplicationInfo aInfo = null;
|
||||
|
||||
int appIdx = 0;
|
||||
TorifiedApp app = null;
|
||||
|
||||
while (itAppInfo.hasNext())
|
||||
{
|
||||
aInfo = itAppInfo.next();
|
||||
|
||||
app = new TorifiedApp();
|
||||
|
||||
try {
|
||||
PackageInfo pInfo = pMgr.getPackageInfo(aInfo.packageName, PackageManager.GET_PERMISSIONS);
|
||||
|
||||
if (pInfo != null && pInfo.requestedPermissions != null)
|
||||
{
|
||||
for (String permInfo:pInfo.requestedPermissions)
|
||||
{
|
||||
if (permInfo.equals("android.permission.INTERNET"))
|
||||
{
|
||||
app.setUsesInternet(true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1)
|
||||
{
|
||||
//System app
|
||||
app.setUsesInternet(true);
|
||||
}
|
||||
|
||||
|
||||
if (!app.usesInternet())
|
||||
continue;
|
||||
else
|
||||
{
|
||||
apps.add(app);
|
||||
}
|
||||
|
||||
|
||||
app.setEnabled(aInfo.enabled);
|
||||
app.setUid(aInfo.uid);
|
||||
app.setUsername(pMgr.getNameForUid(app.getUid()));
|
||||
app.setProcname(aInfo.processName);
|
||||
app.setPackageName(aInfo.packageName);
|
||||
|
||||
try
|
||||
{
|
||||
app.setName(pMgr.getApplicationLabel(aInfo).toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
app.setName(aInfo.packageName);
|
||||
}
|
||||
|
||||
|
||||
//app.setIcon(pMgr.getApplicationIcon(aInfo));
|
||||
|
||||
// check if this application is allowed
|
||||
if (Arrays.binarySearch(tordApps, app.getUsername()) >= 0) {
|
||||
app.setTorified(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
app.setTorified(false);
|
||||
}
|
||||
|
||||
appIdx++;
|
||||
}
|
||||
|
||||
Collections.sort(apps);
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
/*
|
||||
* activate means whether to apply the users preferences
|
||||
* or clear them out
|
||||
|
@ -1046,7 +901,7 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
mTransProxy = new TorTransProxy(this, fileXtables);
|
||||
|
||||
mTransProxy.setTransparentProxyingAll(this, false);
|
||||
ArrayList<TorifiedApp> apps = getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
||||
ArrayList<TorifiedApp> apps = TorTransProxy.getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
||||
mTransProxy.setTransparentProxyingByApp(this, apps, false);
|
||||
|
||||
return true;
|
||||
|
@ -1112,6 +967,12 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected void exec (Runnable runn)
|
||||
{
|
||||
mExecutor.execute(runn);
|
||||
}
|
||||
|
||||
private Process exec (String cmd, boolean wait) throws Exception
|
||||
{
|
||||
Process proc = Runtime.getRuntime().exec(cmd);
|
||||
|
@ -1157,6 +1018,11 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
logNotice("Polipo is running");
|
||||
|
||||
}
|
||||
|
||||
protected TorControlConnection getControlConnection ()
|
||||
{
|
||||
return conn;
|
||||
}
|
||||
|
||||
private int initControlConnection (int maxTries, boolean isReconnect) throws Exception, RuntimeException
|
||||
{
|
||||
|
@ -1298,7 +1164,8 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
// ...
|
||||
logNotice( "adding control port event handler");
|
||||
|
||||
conn.setEventHandler(this);
|
||||
mEventHandler = new TorEventHandler(this);
|
||||
conn.setEventHandler(mEventHandler);
|
||||
|
||||
conn.setEvents(Arrays.asList(new String[]{
|
||||
"ORCONN", "CIRC", "NOTICE", "WARN", "ERR","BW"}));
|
||||
|
@ -1361,278 +1228,9 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(String severity, String msg) {
|
||||
logNotice(severity + ": " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newDescriptors(List<String> orList) {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void orConnStatus(String status, String orName) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("orConnStatus (");
|
||||
sb.append(parseNodeName(orName) );
|
||||
sb.append("): ");
|
||||
sb.append(status);
|
||||
|
||||
debug(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamStatus(String status, String streamID, String target) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("StreamStatus (");
|
||||
sb.append((streamID));
|
||||
sb.append("): ");
|
||||
sb.append(status);
|
||||
|
||||
logNotice(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unrecognized(String type, String msg) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Message (");
|
||||
sb.append(type);
|
||||
sb.append("): ");
|
||||
sb.append(msg);
|
||||
|
||||
logNotice(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bandwidthUsed(long read, long written) {
|
||||
|
||||
if (read != lastRead || written != lastWritten)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(formatCount(read));
|
||||
sb.append(" \u2193");
|
||||
sb.append(" / ");
|
||||
sb.append(formatCount(written));
|
||||
sb.append(" \u2191");
|
||||
|
||||
int iconId = R.drawable.ic_stat_tor;
|
||||
|
||||
if (read > 0 || written > 0)
|
||||
iconId = R.drawable.ic_stat_tor_xfer;
|
||||
|
||||
if (mConnectivity && Prefs.persistNotifications())
|
||||
showToolbarNotification(sb.toString(), NOTIFY_ID, iconId);
|
||||
|
||||
mTotalTrafficWritten += written;
|
||||
mTotalTrafficRead += read;
|
||||
}
|
||||
|
||||
lastWritten = written;
|
||||
lastRead = read;
|
||||
|
||||
sendCallbackBandwidth(lastWritten, lastRead, mTotalTrafficWritten, mTotalTrafficRead);
|
||||
}
|
||||
|
||||
private String formatCount(long count) {
|
||||
// Converts the supplied argument into a string.
|
||||
|
||||
// Under 2Mb, returns "xxx.xKb"
|
||||
// Over 2Mb, returns "xxx.xxMb"
|
||||
if (mNumberFormat != null)
|
||||
if (count < 1e6)
|
||||
return mNumberFormat.format(Math.round((float)((int)(count*10/1024))/10)) + "kbps";
|
||||
else
|
||||
return mNumberFormat.format(Math.round((float)((int)(count*100/1024/1024))/100)) + "mbps";
|
||||
else
|
||||
return "";
|
||||
|
||||
//return count+" kB";
|
||||
}
|
||||
|
||||
public void circuitStatus(String status, String circID, String path) {
|
||||
|
||||
/* once the first circuit is complete, then announce that Orbot is on*/
|
||||
if (mCurrentStatus == STATUS_STARTING && TextUtils.equals(status, "BUILT"))
|
||||
sendCallbackStatus(STATUS_ON);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Circuit (");
|
||||
sb.append((circID));
|
||||
sb.append(") ");
|
||||
sb.append(status);
|
||||
sb.append(": ");
|
||||
|
||||
StringTokenizer st = new StringTokenizer(path,",");
|
||||
Node node = null;
|
||||
|
||||
while (st.hasMoreTokens())
|
||||
{
|
||||
String nodePath = st.nextToken();
|
||||
node = new Node();
|
||||
|
||||
String[] nodeParts;
|
||||
|
||||
if (nodePath.contains("="))
|
||||
nodeParts = nodePath.split("=");
|
||||
else
|
||||
nodeParts = nodePath.split("~");
|
||||
|
||||
if (nodeParts.length == 1)
|
||||
{
|
||||
node.id = nodeParts[0].substring(1);
|
||||
node.name = node.id;
|
||||
}
|
||||
else if (nodeParts.length == 2)
|
||||
{
|
||||
node.id = nodeParts[0].substring(1);
|
||||
node.name = nodeParts[1];
|
||||
}
|
||||
|
||||
node.status = status;
|
||||
|
||||
sb.append(node.name);
|
||||
|
||||
if (st.hasMoreTokens())
|
||||
sb.append (" > ");
|
||||
}
|
||||
|
||||
if (Prefs.useDebugLogging())
|
||||
debug(sb.toString());
|
||||
else if(status.equals("BUILT"))
|
||||
logNotice(sb.toString());
|
||||
else if (status.equals("CLOSED"))
|
||||
logNotice(sb.toString());
|
||||
|
||||
if (Prefs.expandedNotifications())
|
||||
{
|
||||
//get IP from last nodename
|
||||
if(status.equals("BUILT")){
|
||||
|
||||
if (node.ipAddress == null)
|
||||
mExecutor.execute(new ExternalIPFetcher(node));
|
||||
|
||||
hmBuiltNodes.put(node.id, node);
|
||||
}
|
||||
|
||||
if (status.equals("CLOSED"))
|
||||
{
|
||||
hmBuiltNodes.remove(node.id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private HashMap<String,Node> hmBuiltNodes = new HashMap<String,Node>();
|
||||
|
||||
class Node
|
||||
{
|
||||
String status;
|
||||
String id;
|
||||
String name;
|
||||
String ipAddress;
|
||||
String country;
|
||||
String organization;
|
||||
}
|
||||
|
||||
private class ExternalIPFetcher implements Runnable {
|
||||
|
||||
private Node mNode;
|
||||
private int MAX_ATTEMPTS = 3;
|
||||
private final static String ONIONOO_BASE_URL = "https://onionoo.torproject.org/details?fields=country_name,as_name,or_addresses&lookup=";
|
||||
|
||||
public ExternalIPFetcher (Node node)
|
||||
{
|
||||
mNode = node;
|
||||
}
|
||||
|
||||
public void run ()
|
||||
{
|
||||
|
||||
for (int i = 0; i < MAX_ATTEMPTS; i++)
|
||||
{
|
||||
if (conn != null)
|
||||
{
|
||||
try {
|
||||
|
||||
URLConnection conn = null;
|
||||
|
||||
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8118));
|
||||
conn = new URL(ONIONOO_BASE_URL + mNode.id).openConnection(proxy);
|
||||
|
||||
conn.setRequestProperty("Connection","Close");
|
||||
conn.setConnectTimeout(60000);
|
||||
conn.setReadTimeout(60000);
|
||||
|
||||
InputStream is = conn.getInputStream();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||
|
||||
// getting JSON string from URL
|
||||
|
||||
StringBuffer json = new StringBuffer();
|
||||
String line = null;
|
||||
|
||||
while ((line = reader.readLine())!=null)
|
||||
json.append(line);
|
||||
|
||||
JSONObject jsonNodeInfo = new org.json.JSONObject(json.toString());
|
||||
|
||||
JSONArray jsonRelays = jsonNodeInfo.getJSONArray("relays");
|
||||
|
||||
if (jsonRelays.length() > 0)
|
||||
{
|
||||
mNode.ipAddress = jsonRelays.getJSONObject(0).getJSONArray("or_addresses").getString(0).split(":")[0];
|
||||
mNode.country = jsonRelays.getJSONObject(0).getString("country_name");
|
||||
mNode.organization = jsonRelays.getJSONObject(0).getString("as_name");
|
||||
|
||||
StringBuffer sbInfo = new StringBuffer();
|
||||
sbInfo.append(mNode.ipAddress);
|
||||
|
||||
if (mNode.country != null)
|
||||
sbInfo.append(' ').append(mNode.country);
|
||||
|
||||
if (mNode.organization != null)
|
||||
sbInfo.append(" (").append(mNode.organization).append(')');
|
||||
|
||||
logNotice(sbInfo.toString());
|
||||
|
||||
}
|
||||
|
||||
reader.close();
|
||||
is.close();
|
||||
|
||||
break;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
debug ("Error getting node details from onionoo: " + e.getMessage());
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String parseNodeName(String node)
|
||||
{
|
||||
if (node.indexOf('=')!=-1)
|
||||
{
|
||||
return (node.substring(node.indexOf("=")+1));
|
||||
}
|
||||
else if (node.indexOf('~')!=-1)
|
||||
{
|
||||
return (node.substring(node.indexOf("~")+1));
|
||||
}
|
||||
else
|
||||
return node;
|
||||
}
|
||||
|
||||
public void processTransparentProxying() {
|
||||
try{
|
||||
|
@ -1835,14 +1433,14 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
return false;
|
||||
}
|
||||
|
||||
private void sendCallbackBandwidth(long upload, long download, long written, long read) {
|
||||
protected void sendCallbackBandwidth(long upload, long download, long written, long read) {
|
||||
Intent intent = new Intent(LOCAL_ACTION_BANDWIDTH);
|
||||
|
||||
intent.putExtra("up",upload);
|
||||
intent.putExtra("down",download);
|
||||
intent.putExtra("written",written);
|
||||
intent.putExtra("read",read);
|
||||
intent.putExtra(EXTRA_STATUS, mCurrentStatus);
|
||||
intent.putExtra("down",download);
|
||||
intent.putExtra("written",written);
|
||||
intent.putExtra("read",read);
|
||||
intent.putExtra(EXTRA_STATUS, mCurrentStatus);
|
||||
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||
}
|
||||
|
@ -1859,7 +1457,7 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
|
||||
}
|
||||
|
||||
private void sendCallbackStatus(String currentStatus) {
|
||||
protected void sendCallbackStatus(String currentStatus) {
|
||||
mCurrentStatus = currentStatus;
|
||||
Intent intent = getActionStatusIntent(currentStatus);
|
||||
// send for Orbot internals, using secure local broadcast
|
||||
|
@ -2401,4 +1999,14 @@ public class TorService extends Service implements TorServiceConstants, OrbotCon
|
|||
|
||||
}
|
||||
|
||||
public boolean hasConnectivity ()
|
||||
{
|
||||
return mConnectivity;
|
||||
}
|
||||
|
||||
public int getNotifyId ()
|
||||
{
|
||||
return NOTIFY_ID;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,8 +2,17 @@ package org.torproject.android.service;
|
|||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
public class TorTransProxy implements TorServiceConstants {
|
||||
|
||||
|
@ -169,6 +178,114 @@ public class TorTransProxy implements TorServiceConstants {
|
|||
script.append(" -t nat -m owner --uid-owner ");
|
||||
script.append(tApp.getUid());
|
||||
script.append(" -F || exit\n");
|
||||
public static ArrayList<TorifiedApp> getApps (Context context, SharedPreferences prefs)
|
||||
{
|
||||
|
||||
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();
|
||||
|
||||
ArrayList<TorifiedApp> apps = new ArrayList<TorifiedApp>();
|
||||
|
||||
ApplicationInfo aInfo = null;
|
||||
|
||||
int appIdx = 0;
|
||||
TorifiedApp app = null;
|
||||
|
||||
while (itAppInfo.hasNext())
|
||||
{
|
||||
aInfo = itAppInfo.next();
|
||||
|
||||
app = new TorifiedApp();
|
||||
|
||||
try {
|
||||
PackageInfo pInfo = pMgr.getPackageInfo(aInfo.packageName, PackageManager.GET_PERMISSIONS);
|
||||
|
||||
if (pInfo != null && pInfo.requestedPermissions != null)
|
||||
{
|
||||
for (String permInfo:pInfo.requestedPermissions)
|
||||
{
|
||||
if (permInfo.equals("android.permission.INTERNET"))
|
||||
{
|
||||
app.setUsesInternet(true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1)
|
||||
{
|
||||
//System app
|
||||
app.setUsesInternet(true);
|
||||
}
|
||||
|
||||
|
||||
if (!app.usesInternet())
|
||||
continue;
|
||||
else
|
||||
{
|
||||
apps.add(app);
|
||||
}
|
||||
|
||||
|
||||
app.setEnabled(aInfo.enabled);
|
||||
app.setUid(aInfo.uid);
|
||||
app.setUsername(pMgr.getNameForUid(app.getUid()));
|
||||
app.setProcname(aInfo.processName);
|
||||
app.setPackageName(aInfo.packageName);
|
||||
|
||||
try
|
||||
{
|
||||
app.setName(pMgr.getApplicationLabel(aInfo).toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
app.setName(aInfo.packageName);
|
||||
}
|
||||
|
||||
|
||||
//app.setIcon(pMgr.getApplicationIcon(aInfo));
|
||||
|
||||
// check if this application is allowed
|
||||
if (Arrays.binarySearch(tordApps, app.getUsername()) >= 0) {
|
||||
app.setTorified(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
app.setTorified(false);
|
||||
}
|
||||
|
||||
appIdx++;
|
||||
}
|
||||
|
||||
Collections.sort(apps);
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
|
||||
script.append(ipTablesPath);
|
||||
script.append(" -t filter -m owner --uid-owner ");
|
||||
|
@ -747,7 +864,115 @@ public class TorTransProxy implements TorServiceConstants {
|
|||
// fixTransproxyLeak (context);
|
||||
|
||||
return lastExit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static ArrayList<TorifiedApp> getApps (Context context, SharedPreferences prefs)
|
||||
{
|
||||
|
||||
String tordAppString = prefs.getString(OrbotConstants.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();
|
||||
|
||||
ArrayList<TorifiedApp> apps = new ArrayList<TorifiedApp>();
|
||||
|
||||
ApplicationInfo aInfo = null;
|
||||
|
||||
int appIdx = 0;
|
||||
TorifiedApp app = null;
|
||||
|
||||
while (itAppInfo.hasNext())
|
||||
{
|
||||
aInfo = itAppInfo.next();
|
||||
|
||||
app = new TorifiedApp();
|
||||
|
||||
try {
|
||||
PackageInfo pInfo = pMgr.getPackageInfo(aInfo.packageName, PackageManager.GET_PERMISSIONS);
|
||||
|
||||
if (pInfo != null && pInfo.requestedPermissions != null)
|
||||
{
|
||||
for (String permInfo:pInfo.requestedPermissions)
|
||||
{
|
||||
if (permInfo.equals("android.permission.INTERNET"))
|
||||
{
|
||||
app.setUsesInternet(true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1)
|
||||
{
|
||||
//System app
|
||||
app.setUsesInternet(true);
|
||||
}
|
||||
|
||||
|
||||
if (!app.usesInternet())
|
||||
continue;
|
||||
else
|
||||
{
|
||||
apps.add(app);
|
||||
}
|
||||
|
||||
|
||||
app.setEnabled(aInfo.enabled);
|
||||
app.setUid(aInfo.uid);
|
||||
app.setUsername(pMgr.getNameForUid(app.getUid()));
|
||||
app.setProcname(aInfo.processName);
|
||||
app.setPackageName(aInfo.packageName);
|
||||
|
||||
try
|
||||
{
|
||||
app.setName(pMgr.getApplicationLabel(aInfo).toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
app.setName(aInfo.packageName);
|
||||
}
|
||||
|
||||
|
||||
//app.setIcon(pMgr.getApplicationIcon(aInfo));
|
||||
|
||||
// check if this application is allowed
|
||||
if (Arrays.binarySearch(tordApps, app.getUsername()) >= 0) {
|
||||
app.setTorified(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
app.setTorified(false);
|
||||
}
|
||||
|
||||
appIdx++;
|
||||
}
|
||||
|
||||
Collections.sort(apps);
|
||||
|
||||
return apps;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue