Verified Commit 86c2cfdc authored by Sarath's avatar Sarath
Browse files

new tor service

parent 23f3db4e
/build
/.idea
*.iml
\ No newline at end of file
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
sourceSets {
main {
jniLibs.srcDirs = ['./src/main/libs']
}
}
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
aaptOptions {
cruncherEnabled = false
}
lintOptions {
abortOnError false
}
packagingOptions {
exclude 'assets/arm/obfs4proxy' //this is redundant
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'org.torproject:tor-android-binary:0.4.2.5'
implementation 'info.pluggabletransports.aptds:apt-dispatch-library:1.0.9'
implementation 'info.pluggabletransports.aptds:apt-meek-obfs4-legacy:1.0.9'
implementation 'info.pluggabletransports.aptds:jsocksAndroid:1.0.4'
implementation 'org.torproject:tor-android-binary:0.4.2.7a'
implementation 'com.jaredrummler:android-shell:1.0.0'
implementation fileTree(dir: 'libs', include: ['.so'])
testImplementation 'junit:junit:4.13'
implementation ('com.offbynull.portmapper:portmapper:2.0.5'){
transitive = true
}
implementation 'org.briarproject:jtorctl:0.3'
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.msopentech.thali.toronionproxy.android">
package="com.invertedx.torservice" >
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
package com.msopentech.thali.android.toronionproxy;
package com.invertedx.torservice;
import android.content.BroadcastReceiver;
import android.content.Context;
......
package com.msopentech.thali.android.toronionproxy;
import java.util.concurrent.TimeUnit;
package com.invertedx.torservice;
import io.reactivex.Observable;
import io.reactivex.Observer;
......
package com.invertedx.torservice;
import android.text.TextUtils;
import android.util.Log;
import com.invertedx.torservice.util.Prefs;
import net.freehaven.tor.control.EventHandler;
import org.jetbrains.annotations.NotNull;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
/**
* Created by n8fr8 on 9/25/16.
*/
public class TorEventHandler implements EventHandler, TorServiceConstants {
private TorProxyManager torProxyManager;
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 {
public String status;
public String id;
public String name;
public String ipAddress;
public String country;
public String organization;
public boolean isFetchingInfo = false;
}
public HashMap<String, Node> getNodes() {
return hmBuiltNodes;
}
public TorEventHandler(TorProxyManager receiver) {
torProxyManager = receiver;
mNumberFormat = NumberFormat.getInstance(Locale.getDefault()); //localized numbers!
}
@Override
public void newDescriptors(List<String> orList) {
Iterator<String> iterator = orList.iterator();
StringBuilder stringBuilder = new StringBuilder();
while (iterator.hasNext()) {
stringBuilder.append(iterator.next());
}
}
@Override
public void orConnStatus(String status, String orName) {
StringBuilder sb = new StringBuilder();
sb.append("orConnStatus (");
sb.append(parseNodeName(orName));
sb.append("): ");
sb.append(status);
torProxyManager.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);
torProxyManager.setCircuitStatus(sb.toString());
}
@Override
public void message(String severity, String msg) {
torProxyManager.setCircuitStatus(severity + ": " + msg);
}
@Override
public void unrecognized(String type, String msg) {
torProxyManager.setCircuitStatus(msg);
torProxyManager.logNotice(msg);
}
@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");
torProxyManager.bandWidthUpdate(sb.toString(), read, written);
mTotalTrafficWritten += written;
mTotalTrafficRead += read;
}
lastWritten = written;
lastRead = read;
torProxyManager.bandwidthUsed(read, written);
}
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 (torProxyManager.getCurrentStatus() == TorProxyManager.ConnectionStatus.CONNECTING && TextUtils.equals(status, "BUILT")) {
torProxyManager.setStatus(TorProxyManager.ConnectionStatus.CONNECTED);
torProxyManager.sendLogs("Connected to the Tor network");
}
String msg = "CircuitStatus: " + circID + " " + status;
//String purpose = info.get("PURPOSE");
//if(purpose != null) msg += ", purpose: " + purpose;
//String hsState = info.get("HS_STATE");
//if(hsState != null) msg += ", state: " + hsState;
//String rendQuery = info.get("REND_QUERY");
//if(rendQuery != null) msg += ", service: " + rendQuery;
if (!path.isEmpty()) msg += ", path: " + shortenPath(path);
torProxyManager.setCircuitStatus(msg);
// LOG.info(msg);
if (Prefs.viewCircuitStatus()) {
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;
boolean isFirstNode = true;
int nodeCount = st.countTokens();
while (st.hasMoreTokens()) {
String nodePath = st.nextToken();
String nodeId = null, nodeName = null;
String[] nodeParts;
if (nodePath.contains("="))
nodeParts = nodePath.split("=");
else
nodeParts = nodePath.split("~");
if (nodeParts.length == 1) {
nodeId = nodeParts[0].substring(1);
if (node != null) {
nodeName = node.id;
}
} else if (nodeParts.length == 2) {
nodeId = nodeParts[0].substring(1);
nodeName = nodeParts[1];
}
if (nodeId == null)
continue;
node = hmBuiltNodes.get(nodeId);
if (node == null) {
node = new Node();
node.id = nodeId;
node.name = nodeName;
}
node.status = status;
sb.append(node.name);
if (!TextUtils.isEmpty(node.ipAddress))
sb.append("(").append(node.ipAddress).append(")");
if (st.hasMoreTokens())
sb.append(" > ");
// torProxyManager.setCircuitStatus(status);
if (status.equals("EXTENDED")) {
if (isFirstNode) {
hmBuiltNodes.put(node.id, node);
if (node.ipAddress == null && (!node.isFetchingInfo) && Prefs.useDebugLogging()) {
node.isFetchingInfo = true;
// torProxyManager.exec(new ExternalIPFetcher(torProxyManager, node, OrbotService.mPortHTTP));
}
isFirstNode = false;
}
} else if (status.equals("BUILT")) {
torProxyManager.logNotice(sb.toString());
// torProxyManager.setCircuitStatus(hmBuiltNodes.toString());
} else if (status.equals("CLOSED")) {
torProxyManager.logNotice(sb.toString());
hmBuiltNodes.remove(node.id);
}
}
}
}
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;
}
@NotNull
private String shortenPath(String id) {
StringBuilder s = new StringBuilder();
if (s.length() > 0) s.append(',');
s.append(id.substring(1, 7));
return s.toString();
}
}
/* Copyright (c) 2009, Nathan Freitas, Orbot/The Guardian Project - http://openideals.com/guardian */
/* See LICENSE for licensing information */
package com.invertedx.torservice;
public interface TorPrefernceConstants {
String TAG = "TorServiceManager";
String PREF_OR = "pref_or";
String PREF_OR_PORT = "pref_or_port";
String PREF_OR_NICKNAME = "pref_or_nickname";
String DIRECTORY_TOR_BINARY = "app_torfiles";
String PREF_REACHABLE_ADDRESSES = "pref_reachable_addresses";
String PREF_REACHABLE_ADDRESSES_PORTS = "pref_reachable_addresses_ports";
String PREF_DISABLE_NETWORK = "pref_disable_network";
String PREF_TOR_SHARED_PREFS = "tor_preferences";
String PREF_SOCKS = "pref_socks";
String PREF_HTTP = "pref_http";
String PREF_ISOLATE_DEST = "pref_isolate_dest";
String PREF_CONNECTION_PADDING = "pref_connection_padding";
String PREF_REDUCED_CONNECTION_PADDING = "pref_reduced_connection_padding";
String PREF_CIRCUIT_PADDING = "pref_circuit_padding";
String PREF_REDUCED_CIRCUIT_PADDING = "pref_reduced_circuit_padding";
String PREF_PREFER_IPV6 = "pref_prefer_ipv6";
String PREF_DISABLE_IPV4 = "pref_disable_ipv4";
String APP_TOR_KEY = "_app_tor";
String APP_DATA_KEY = "_app_data";
String APP_WIFI_KEY = "_app_wifi";
}
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
/* See LICENSE for licensing information */
package com.invertedx.torservice;
import android.content.Intent;
public interface TorServiceConstants {
String DIRECTORY_TOR_DATA = "data";
String TOR_CONTROL_PORT_FILE = "control.txt";
String TOR_PID_FILE = "torpid";
//torrc (tor config file)
String TORRC_ASSET_KEY = "torrc";
String TOR_CONTROL_COOKIE = "control_auth_cookie";
//geoip data file asset key
String GEOIP_ASSET_KEY = "geoip";
String GEOIP6_ASSET_KEY = "geoip6";
String IP_LOCALHOST = "127.0.0.1";
int TOR_TRANSPROXY_PORT_DEFAULT = 9040;
// int TOR_DNS_PORT_DEFAULT = 5400;
// String HTTP_PROXY_PORT_DEFAULT = "8118"; // like Privoxy!
String SOCKS_PROXY_PORT_DEFAULT = "auto";
String PREF_BINARY_TOR_VERSION_INSTALLED = "BINARY_TOR_VERSION_INSTALLED";
//obfsproxy
String OBFSCLIENT_ASSET_KEY = "obfs4proxy";
String HIDDEN_SERVICES_DIR = "hidden_services";
}
package com.invertedx.torservice.util;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class CustomNativeLoader {
private final static String TAG = "CNL";
private static boolean loadFromZip(Context context, String libname, File destLocalFile, String arch) {
ZipFile zipFile = null;
InputStream stream = null;
try {
zipFile = new ZipFile(context.getApplicationInfo().sourceDir);
ZipEntry entry = zipFile.getEntry("lib/" + arch + "/" + libname + ".so");
if (entry == null) {
entry = zipFile.getEntry("jni/" + arch + "/" + libname + ".so");
if (entry == null)
throw new Exception("Unable to find file in apk:" + "lib/" + arch + "/" + libname);
}
//how we wrap this in another stream because the native .so is zipped itself
stream = zipFile.getInputStream(entry);
OutputStream out = new FileOutputStream(destLocalFile);
byte[] buf = new byte[4096];
int len;
while ((len = stream.read(buf)) > 0) {
Thread.yield();
out.write(buf, 0, len);
}
out.close();
destLocalFile.setReadable(true, false);
destLocalFile.setExecutable(true, false);
destLocalFile.setWritable(true);
return true;
} catch (Exception e) {
Log.e(TAG, e.getMessage());
} finally {
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
if (zipFile != null) {
try {
zipFile.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
}
return false;
}
public static File loadNativeBinary(Context context, String libname, File destLocalFile) {
try {
File fileNativeBin = new File(getNativeLibraryDir(context),libname + ".so");
if (!fileNativeBin.exists())
fileNativeBin = new File(getNativeLibraryDir(context),"lib" + libname + ".so");
if (fileNativeBin.exists())
{
if (fileNativeBin.canExecute())
return fileNativeBin;
else
{
setExecutable(fileNativeBin);
if (fileNativeBin.canExecute())
return fileNativeBin;