migrating Orbot codebase from old repo and updating to 0.0.3a
svn:r21593
|
@ -3,7 +3,7 @@
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="src" path="gen"/>
|
<classpathentry kind="src" path="gen"/>
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
<classpathentry kind="lib" path="libs/jsocks.jar"/>
|
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/jtorctrl"/>
|
<classpathentry combineaccessrules="false" kind="src" path="/jtorctrl"/>
|
||||||
|
<classpathentry kind="lib" path="libs/asocks.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|
|
@ -1,26 +1,42 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.torproject.android"
|
package="org.torproject.android"
|
||||||
android:versionCode="1"
|
android:versionName="011301.2" android:versionCode="2">
|
||||||
android:versionName="1.0">
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
|
||||||
|
|
||||||
<application android:icon="@drawable/icon" android:label="@string/app_name"
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
android:debuggable="false">
|
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||||
<activity android:name=".TorControlPanel"
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
|
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="false">
|
||||||
|
<activity android:name=".Orbot"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity android:name=".SettingsPreferences" android:label="@string/app_name">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|
||||||
|
<service android:name=".service.TorService" android:process=":remote">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.torproject.android.service.ITorService" />
|
||||||
|
<action android:name="org.torproject.android.service.TOR_SERVICE" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
<service android:name=".TorService" android:enabled="true" android:exported="true"/>
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
<uses-sdk android:minSdkVersion="3"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
22
Orbot/BUILD
|
@ -7,6 +7,7 @@ Please install the following prerequisites (instructions for each follows):
|
||||||
droid-wrapper: http://github.com/tmurakam/droid-wrapper
|
droid-wrapper: http://github.com/tmurakam/droid-wrapper
|
||||||
libevent source (1.4.12-stable from svn)
|
libevent source (1.4.12-stable from svn)
|
||||||
Tor source (most recent git master branch)
|
Tor source (most recent git master branch)
|
||||||
|
Privoxy source (http://sourceforge.net/projects/ijbswa/)
|
||||||
|
|
||||||
Install and prepare the Android OS SDK ( http://source.android.com/download )
|
Install and prepare the Android OS SDK ( http://source.android.com/download )
|
||||||
on Debian Lenny:
|
on Debian Lenny:
|
||||||
|
@ -42,14 +43,27 @@ Install droid-wrapper:
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
zlib and OpenSSL are included with the Android OS SDK. You'll need to build
|
zlib and OpenSSL are included with the Android OS SDK. You'll need to build
|
||||||
libevent and finally Tor. We'll create an externals directory for this code:
|
libevent, Privoxy and finally Tor. We'll create an externals directory for this code:
|
||||||
|
|
||||||
mkdir -p ~/mydroid/external/{libevent,tor}
|
mkdir -p ~/mydroid/external/{libevent,tor,privoxy}
|
||||||
|
|
||||||
We need to set to environment variables for droid-gcc:
|
We need to set to environment variables for droid-gcc:
|
||||||
export DROID_ROOT=~/mydroid/
|
export DROID_ROOT=~/mydroid/
|
||||||
export DROID_TARGET=generic
|
export DROID_TARGET=generic
|
||||||
|
|
||||||
|
Fetch and build Privoxy:
|
||||||
|
cd ~/mydroid/external/privoxy
|
||||||
|
wget http://sourceforge.net/projects/ijbswa/files/Sources/3.0.12%20%28stable%29/privoxy-3.0.12-stable-src.tar.gz/download
|
||||||
|
tar xzvf privoxy-3.0.12-stable-src.tar.gz
|
||||||
|
cd privoxy-3.0.12-stable
|
||||||
|
autoheader
|
||||||
|
autoconf
|
||||||
|
#need to disable setpgrp check in configure
|
||||||
|
export ac_cv_func_setpgrp_void=yes
|
||||||
|
CC=droid-gcc LD=droid-ld ./configure --host=arm-none-linux-gnueabi
|
||||||
|
#don't mind the "unrecognized option '-pthred'" error message that you'll see when you run make
|
||||||
|
make
|
||||||
|
|
||||||
Fetch and build libevent:
|
Fetch and build libevent:
|
||||||
|
|
||||||
cd ~/mydroid/external/libevent
|
cd ~/mydroid/external/libevent
|
||||||
|
@ -62,7 +76,6 @@ Fetch and build libevent:
|
||||||
make
|
make
|
||||||
|
|
||||||
Copy over the libevent library:
|
Copy over the libevent library:
|
||||||
|
|
||||||
cp .libs/libevent.a ~/mydroid/out/target/product/generic/obj/lib
|
cp .libs/libevent.a ~/mydroid/out/target/product/generic/obj/lib
|
||||||
|
|
||||||
Fetch and build Tor:
|
Fetch and build Tor:
|
||||||
|
@ -71,7 +84,7 @@ Fetch and build Tor:
|
||||||
export ZLIBDIR=`cd ~/mydroid/external/zlib && pwd`
|
export ZLIBDIR=`cd ~/mydroid/external/zlib && pwd`
|
||||||
|
|
||||||
cd ~/mydroid/external/tor
|
cd ~/mydroid/external/tor
|
||||||
git clone https://git.torproject.org/git/tor.git
|
git clone git://git.torproject.org/git/tor.git
|
||||||
cd tor/
|
cd tor/
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
CC=droid-gcc LD=droid-ld ./configure --host=arm-none-linux-gnueabi \
|
CC=droid-gcc LD=droid-ld ./configure --host=arm-none-linux-gnueabi \
|
||||||
|
@ -105,6 +118,7 @@ Finally, we'll make a proper Android package with ant and the Android App SDK:
|
||||||
|
|
||||||
export APP_SDK=~/Documents/projects/android/android-sdk-linux_x86-1.5_r3/tools
|
export APP_SDK=~/Documents/projects/android/android-sdk-linux_x86-1.5_r3/tools
|
||||||
cd ../Orbot/
|
cd ../Orbot/
|
||||||
|
cp ~/mydroid/external/privoxy/privoxy-3.0.12-stable/privoxy assets/privoxy
|
||||||
cp ~/mydroid/external/tor/tor/src/or/tor assets/tor
|
cp ~/mydroid/external/tor/tor/src/or/tor assets/tor
|
||||||
$APP_SDK/android update project --name Orbot --target 1 --path .
|
$APP_SDK/android update project --name Orbot --target 1 --path .
|
||||||
ant release
|
ant release
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
0.0.3a - 2010-02-07
|
||||||
|
- Integrated iptables support for transparenty proxying of outbound port 80 and DNS
|
||||||
|
- Privoxy is now used as HTTP Proxy server (cross-compiled to ARM)
|
||||||
|
- New UI layout and graphics
|
||||||
|
- Android settings screen for generated torrc file
|
||||||
|
- Improved performance and error handling
|
||||||
|
|
||||||
0.0.2a - 2009-11-30
|
0.0.2a - 2009-11-30
|
||||||
- Update user interace layout and graphics
|
- Update user interace layout and graphics
|
||||||
- Modified service launch, shutdown and handling
|
- Modified service launch, shutdown and handling
|
||||||
|
|
174
Orbot/LICENSE
|
@ -94,108 +94,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
===============================================================================
|
===============================================================================
|
||||||
src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
|
||||||
under the following license:
|
|
||||||
|
|
||||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
||||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
||||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
|
||||||
under the following license:
|
|
||||||
|
|
||||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
||||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
||||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
|
||||||
under the following license:
|
|
||||||
|
|
||||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
||||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCD FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
||||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
|
||||||
under the following license:
|
|
||||||
|
|
||||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
||||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
||||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
||||||
under the following license:
|
under the following license:
|
||||||
|
@ -230,79 +128,7 @@ If you got Tor as a static binary with OpenSSL included, then you should know:
|
||||||
"This product includes software developed by the OpenSSL Project
|
"This product includes software developed by the OpenSSL Project
|
||||||
for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||||
===============================================================================
|
===============================================================================
|
||||||
"This program uses the IP-to-Country Database provided by
|
|
||||||
WebHosting.Info (http://www.webhosting.info), available from
|
|
||||||
http://ip-to-country.webhosting.info."
|
|
||||||
See the src/config/geoip file in particular.
|
|
||||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
|
||||||
under the following license:
|
|
||||||
|
|
||||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
||||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
||||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
If you got Tor as a static binary with OpenSSL included, then you should know:
|
|
||||||
"This product includes software developed by the OpenSSL Project
|
|
||||||
for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
|
||||||
===============================================================================
|
|
||||||
"This program uses the IP-to-Country Database provided by
|
|
||||||
WebHosting.Info (http://www.webhosting.info), available from
|
|
||||||
http://ip-to-country.webhosting.info."
|
|
||||||
See the src/config/geoip file in particular.
|
|
||||||
:src/common/strlcat.c and src/common/strlcpy.c by Todd C. Miller are licensed
|
|
||||||
under the following license:
|
|
||||||
|
|
||||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
||||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
||||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
||||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
If you got Tor as a static binary with OpenSSL included, then you should know:
|
|
||||||
"This product includes software developed by the OpenSSL Project
|
|
||||||
for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
"This program uses the IP-to-Country Database provided by
|
"This program uses the IP-to-Country Database provided by
|
||||||
WebHosting.Info (http://www.webhosting.info), available from
|
WebHosting.Info (http://www.webhosting.info), available from
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>help.html</title>
|
|
||||||
|
|
||||||
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
|
|
||||||
<meta http-equiv="description" content="this is my page">
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
||||||
|
|
||||||
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
|
|
||||||
<style>
|
|
||||||
body
|
|
||||||
{
|
|
||||||
background:black;
|
|
||||||
color:white;
|
|
||||||
font-family:arial;
|
|
||||||
}
|
|
||||||
|
|
||||||
a, a:link, a:visited
|
|
||||||
{
|
|
||||||
color:#00ff00;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<h2>ORbot</h2>
|
|
||||||
<i>Onion Routing Robot - v0.0.2a / November 30, 2009</i><br/>
|
|
||||||
<hr/>
|
|
||||||
<h3>How to use ORbot</h3>
|
|
||||||
Simply touch the Orbot icon on the main screen and wait for it to fully connect to the Tor network. You can use the Menu -> Log option to view
|
|
||||||
more detailed information about the attempt to connect to the network.
|
|
||||||
<h3>How to surf anonymously</h3>
|
|
||||||
Once you have Orbot running and connected to the Tor network, you can utilize the anonymous proxy service in multiple ways:
|
|
||||||
<ul>
|
|
||||||
<li>Set your Android APN Proxy (Settings -> Wireless Networks -> Mobile networks -> Access Point Names) to 127.0.0.1/8118</li>
|
|
||||||
<li>Tell your application to use Web Proxy: 127.0.0.1:8118</li>
|
|
||||||
<li>Download and use the 'Shadow' browser from the Android Market</li>
|
|
||||||
</ul>
|
|
||||||
You can always visit <a href="http://check.torproject.org">http://check.torproject.org</a> to ensure that you are properly connected to the Tor network.
|
|
||||||
<h3>Bridges and Other Settings</h3>
|
|
||||||
You can modify the TORRC settings file using the Menu -> Settings option. This is where you can copy and paste in Tor Bridge node addresses
|
|
||||||
if they are needed in your local area.
|
|
||||||
<h3>Even More Information!</h3>
|
|
||||||
If you'd like to learn more about the Tor Project, please visit <a href="http://torproject.org">http://torproject.org</a>.
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Generally, this file goes in /etc/privoxy/config
|
||||||
|
#
|
||||||
|
# Tor listens as a SOCKS4a proxy here:
|
||||||
|
forward-socks4a / 127.0.0.1:9050 .
|
||||||
|
confdir /data/data/org.torproject.android
|
||||||
|
logdir /data/data/org.torproject.android
|
||||||
|
# actionsfile standard # Internal purpose, recommended
|
||||||
|
#actionsfile default.action # Main actions file
|
||||||
|
#actionsfile user.action # User customizations
|
||||||
|
#filterfile default.filter
|
||||||
|
|
||||||
|
# Don't log interesting things, only startup messages, warnings and errors
|
||||||
|
#logfile logfile
|
||||||
|
#jarfile jarfile
|
||||||
|
#debug 1
|
||||||
|
#debug 0 # show each GET/POST/CONNECT request
|
||||||
|
#debug 4096 # Startup banner and warnings
|
||||||
|
#debug 8192 # Errors - *we highly recommended enabling this*
|
||||||
|
|
||||||
|
#user-manual /usr/share/doc/privoxy/user-manual
|
||||||
|
listen-address 127.0.0.1:8118
|
||||||
|
toggle 1
|
||||||
|
accept-intercepted-requests 1
|
||||||
|
enable-remote-toggle 0
|
||||||
|
enable-edit-actions 0
|
||||||
|
enable-remote-http-toggle 0
|
||||||
|
buffer-limit 4096
|
|
@ -1,169 +1,16 @@
|
||||||
## Configuration file for a typical Tor user
|
SocksPort 9050
|
||||||
## Last updated 16 July 2009 for Tor 0.2.2.1-alpha.
|
SocksListenAddress 127.0.0.1
|
||||||
## (May or may not work for much older or much newer versions of Tor.)
|
SafeSocks 1
|
||||||
##
|
DNSPort 5400
|
||||||
## Lines that begin with "## " try to explain what's going on. Lines
|
Log notice stdout
|
||||||
## that begin with just "#" are disabled commands: you can enable them
|
Log debug syslog
|
||||||
## by removing the "#" symbol.
|
|
||||||
##
|
|
||||||
## See 'man tor', or https://www.torproject.org/tor-manual.html,
|
|
||||||
## for more options you can use in this file.
|
|
||||||
##
|
|
||||||
## Tor will look for this file in various places based on your platform:
|
|
||||||
## https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#torrc
|
|
||||||
|
|
||||||
|
|
||||||
## Replace this with "SocksPort 0" if you plan to run Tor only as a
|
|
||||||
## relay, and not make any local application connections yourself.
|
|
||||||
SocksPort 9050 # what port to open for local application connections
|
|
||||||
SocksListenAddress 127.0.0.1 # accept connections only from localhost
|
|
||||||
SocksListenAddress 127.0.0.1:1080 # listen on this IP:port also
|
|
||||||
|
|
||||||
## Entry policies to allow/deny SOCKS requests based on IP address.
|
|
||||||
## First entry that matches wins. If no SocksPolicy is set, we accept
|
|
||||||
## all (and only) requests from SocksListenAddress.
|
|
||||||
#SocksPolicy accept 192.168.0.0/16
|
|
||||||
#SocksPolicy reject *
|
|
||||||
|
|
||||||
## Logs go to stdout at level "notice" unless redirected by something
|
|
||||||
## else, like one of the below lines. You can have as many Log lines as
|
|
||||||
## you want.
|
|
||||||
##
|
|
||||||
## We advise using "notice" in most cases, since anything more verbose
|
|
||||||
## may provide sensitive information to an attacker who obtains the logs.
|
|
||||||
##
|
|
||||||
## Send all messages of level 'notice' or higher to @LOCALSTATEDIR@/log/tor/notices.log
|
|
||||||
Log notice file /data/data/org.torproject.android/notices.log
|
|
||||||
## Send every possible message to @LOCALSTATEDIR@/log/tor/debug.log
|
|
||||||
#Log debug file /data/data/org.torproject.android/debug.log
|
|
||||||
## Use the system log instead of Tor's logfiles
|
|
||||||
#Log notice syslog
|
|
||||||
## To send all messages to stderr:
|
|
||||||
#Log debug stderr
|
|
||||||
|
|
||||||
## Uncomment this to start the process in the background... or use
|
|
||||||
## --runasdaemon 1 on the command line. This is ignored on Windows;
|
|
||||||
## see the FAQ entry if you want Tor to run as an NT service.
|
|
||||||
#RunAsDaemon 1
|
|
||||||
|
|
||||||
## The directory for keeping all the keys/etc. By default, we store
|
|
||||||
## things in $HOME/.tor on Unix, and in Application Data\tor on Windows.
|
|
||||||
DataDirectory /data/data/org.torproject.android/data
|
DataDirectory /data/data/org.torproject.android/data
|
||||||
|
|
||||||
## The port on which Tor will listen for local connections from Tor
|
|
||||||
## controller applications, as documented in control-spec.txt.
|
|
||||||
ControlPort 9051
|
ControlPort 9051
|
||||||
## If you enable the controlport, be sure to enable one of these
|
|
||||||
## authentication methods, to prevent attackers from accessing it.
|
|
||||||
#HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C
|
|
||||||
CookieAuthentication 1
|
CookieAuthentication 1
|
||||||
|
RelayBandwidthRate 20 KBytes
|
||||||
############### This section is just for location-hidden services ###
|
RelayBandwidthBurst 20 KBytes
|
||||||
|
UseBridges 0
|
||||||
## Once you have configured a hidden service, you can look at the
|
UpdateBridgesFromAuthority 1
|
||||||
## contents of the file ".../hidden_service/hostname" for the address
|
bridge 74.82.1.191:19030
|
||||||
## to tell people.
|
bridge 221.31.40.135:4430
|
||||||
##
|
bridge 24.110.168.130:443
|
||||||
## HiddenServicePort x y:z says to redirect requests on port x to the
|
|
||||||
## address y:z.
|
|
||||||
|
|
||||||
#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/hidden_service/
|
|
||||||
#HiddenServicePort 80 127.0.0.1:80
|
|
||||||
|
|
||||||
#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/other_hidden_service/
|
|
||||||
#HiddenServicePort 80 127.0.0.1:80
|
|
||||||
#HiddenServicePort 22 127.0.0.1:22
|
|
||||||
|
|
||||||
################ This section is just for relays #####################
|
|
||||||
#
|
|
||||||
## See https://www.torproject.org/docs/tor-doc-relay for details.
|
|
||||||
|
|
||||||
## Required: what port to advertise for incoming Tor connections.
|
|
||||||
#ORPort 9001
|
|
||||||
## If you want to listen on a port other than the one advertised
|
|
||||||
## in ORPort (e.g. to advertise 443 but bind to 9090), uncomment the
|
|
||||||
## line below too. You'll need to do ipchains or other port forwarding
|
|
||||||
## yourself to make this work.
|
|
||||||
#ORListenAddress 0.0.0.0:9090
|
|
||||||
|
|
||||||
## A handle for your relay, so people don't have to refer to it by key.
|
|
||||||
#Nickname ididnteditheconfig
|
|
||||||
|
|
||||||
## The IP address or full DNS name for your relay. Leave commented out
|
|
||||||
## and Tor will guess.
|
|
||||||
#Address noname.example.com
|
|
||||||
|
|
||||||
## Define these to limit how much relayed traffic you will allow. Your
|
|
||||||
## own traffic is still unthrottled. Note that RelayBandwidthRate must
|
|
||||||
## be at least 20 KBytes.
|
|
||||||
#RelayBandwidthRate 100 KBytes # Throttle traffic to 100KB/s (800Kbps)
|
|
||||||
#RelayBandwidthBurst 200 KBytes # But allow bursts up to 200KB/s (1600Kbps)
|
|
||||||
|
|
||||||
## Use these to restrict the maximum traffic per day, week, or month.
|
|
||||||
## Note that this threshold applies to sent _and_ to received bytes,
|
|
||||||
## not to their sum: Setting "4 GBytes" may allow up to 8 GBytes
|
|
||||||
## total before hibernating.
|
|
||||||
##
|
|
||||||
## Set a maximum of 4 gigabytes each way per period.
|
|
||||||
#AccountingMax 4 GBytes
|
|
||||||
## Each period starts daily at midnight (AccountingMax is per day)
|
|
||||||
#AccountingStart day 00:00
|
|
||||||
## Each period starts on the 3rd of the month at 15:00 (AccountingMax
|
|
||||||
## is per month)
|
|
||||||
#AccountingStart month 3 15:00
|
|
||||||
|
|
||||||
## Contact info to be published in the directory, so we can contact you
|
|
||||||
## if your relay is misconfigured or something else goes wrong. Google
|
|
||||||
## indexes this, so spammers might also collect it.
|
|
||||||
#ContactInfo Random Person <nobody AT example dot com>
|
|
||||||
## You might also include your PGP or GPG fingerprint if you have one:
|
|
||||||
#ContactInfo 1234D/FFFFFFFF Random Person <nobody AT example dot com>
|
|
||||||
|
|
||||||
## Uncomment this to mirror directory information for others. Please do
|
|
||||||
## if you have enough bandwidth.
|
|
||||||
#DirPort 9030 # what port to advertise for directory connections
|
|
||||||
## If you want to listen on a port other than the one advertised
|
|
||||||
## in DirPort (e.g. to advertise 80 but bind to 9091), uncomment the line
|
|
||||||
## below too. You'll need to do ipchains or other port forwarding yourself
|
|
||||||
## to make this work.
|
|
||||||
#DirListenAddress 0.0.0.0:9091
|
|
||||||
## Uncomment to return an arbitrary blob of html on your DirPort. Now you
|
|
||||||
## can explain what Tor is if anybody wonders why your IP address is
|
|
||||||
## contacting them. See contrib/tor-exit-notice.html for a sample.
|
|
||||||
#DirPortFrontPage /etc/tor/exit-notice.html
|
|
||||||
|
|
||||||
## Uncomment this if you run more than one Tor relay, and add the identity
|
|
||||||
## key fingerprint of each Tor relay you control, even if they're on
|
|
||||||
## different networks. You declare it here so Tor clients can avoid
|
|
||||||
## using more than one of your relays in a single circuit. See
|
|
||||||
## https://wiki.torproject.org/noreply/TheOnionRouter/TorFAQ#MultipleServers
|
|
||||||
#MyFamily $keyid,$keyid,...
|
|
||||||
|
|
||||||
## A comma-separated list of exit policies. They're considered first
|
|
||||||
## to last, and the first match wins. If you want to _replace_
|
|
||||||
## the default exit policy, end this with either a reject *:* or an
|
|
||||||
## accept *:*. Otherwise, you're _augmenting_ (prepending to) the
|
|
||||||
## default exit policy. Leave commented to just use the default, which is
|
|
||||||
## described in the man page or at
|
|
||||||
## https://www.torproject.org/documentation.html
|
|
||||||
##
|
|
||||||
## Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
|
|
||||||
## for issues you might encounter if you use the default exit policy.
|
|
||||||
##
|
|
||||||
## If certain IPs and ports are blocked externally, e.g. by your firewall,
|
|
||||||
## you should update your exit policy to reflect this -- otherwise Tor
|
|
||||||
## users will be told that those destinations are down.
|
|
||||||
##
|
|
||||||
#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more
|
|
||||||
#ExitPolicy accept *:119 # accept nntp as well as default exit policy
|
|
||||||
#ExitPolicy reject *:* # no exits allowed
|
|
||||||
#
|
|
||||||
## Bridge relays (or "bridges") are Tor relays that aren't listed in the
|
|
||||||
## main directory. Since there is no complete public list of them, even if an
|
|
||||||
## ISP is filtering connections to all the known Tor relays, they probably
|
|
||||||
## won't be able to block all the bridges. Also, websites won't treat you
|
|
||||||
## differently because they won't know you're running Tor. If you can
|
|
||||||
## be a real relay, please do; but if not, be a bridge!
|
|
||||||
#BridgeRelay 1
|
|
||||||
#ExitPolicy reject *:*
|
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
# "build.properties", and override values to adapt the script to your
|
# "build.properties", and override values to adapt the script to your
|
||||||
# project structure.
|
# project structure.
|
||||||
|
|
||||||
apk-configurations=
|
|
||||||
# Project target.
|
|
||||||
target=android-4
|
|
||||||
# Indicates whether an apk should be generated for each density.
|
# Indicates whether an apk should be generated for each density.
|
||||||
split.density=false
|
split.density=false
|
||||||
|
# Project target.
|
||||||
|
target=android-4
|
||||||
|
apk-configurations=
|
||||||
|
|
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
<ScrollView android:id="@+id/aboutscrollview"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
<TextView android:text="Version: "
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="15px"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="- Unkown -"
|
||||||
|
android:id="@+id/versionName"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="Project-Home: "
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="15px"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="http://torproject.org/orbot"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:textColorLink="#ffffff"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="License: "
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="15px"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="The Tor License"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="http://torproject.org"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:textColorLink="#ffffff"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="3rd-Party-Software: "
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="15px"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="Tor vX.x: http://www.torproject.org"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:textColorLink="#ffffff"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
<TextView android:text="LibEvent vX.x: http://www.monkey.org/~provos/libevent/"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autoLink="web"
|
||||||
|
android:textColorLink="#ffffff"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
<ScrollView android:id="@+id/helpscrollview"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
<TextView android:text="@string/help_text"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="15px"
|
||||||
|
android:paddingLeft="15px"
|
||||||
|
android:textColor="#ffffff" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
|
@ -1,27 +1,19 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
|
|
||||||
<ScrollView android:layout_height="380px"
|
<ScrollView android:orientation="vertical"
|
||||||
android:layout_width="fill_parent" android:id="@+id/logScrollView">
|
android:layout_height="480px"
|
||||||
|
android:layout_width="fill_parent" android:id="@+id/logScrollView"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
>
|
||||||
|
|
||||||
<TextView android:id="@+id/messageLog"
|
<TextView android:id="@+id/messageLog"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_weight="1.0"
|
android:layout_x="2px"
|
||||||
android:textSize="11px"
|
android:layout_y="2px"
|
||||||
|
android:textSize="12px"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
|
||||||
<Button android:id="@+id/btnLogClear"
|
|
||||||
android:layout_height="40px"
|
|
||||||
android:text="Clear Log"
|
|
||||||
android:layout_margin="0sp"
|
|
||||||
android:layout_width="fill_parent"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
|
@ -3,7 +3,34 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:background="@drawable/bgdarkdroid">
|
android:background="@drawable/background">
|
||||||
|
|
||||||
|
<RelativeLayout android:id="@+id/layoutHeaderMain"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:background="#A0909090">
|
||||||
|
<ImageView android:id="@+id/radioModeImage"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3px"
|
||||||
|
android:layout_marginRight="3px"
|
||||||
|
android:gravity="right"
|
||||||
|
android:layout_toRightOf="@+id/radioModeLabel"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:src="@drawable/tor25"
|
||||||
|
/>
|
||||||
|
<TextView android:id="@+id/radioModeText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="powered by the tor project "
|
||||||
|
android:layout_marginTop="8px"
|
||||||
|
android:layout_marginRight="0px"
|
||||||
|
android:gravity="right"
|
||||||
|
android:layout_toLeftOf="@+id/radioModeImage"
|
||||||
|
android:textColor="#cccccc" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<ScrollView android:id="@+id/mainview"
|
<ScrollView android:id="@+id/mainview"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
@ -19,8 +46,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content">
|
android:layout_width="wrap_content">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imgStatus"
|
android:id="@+id/imgStatus"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -29,14 +54,14 @@ android:src="@drawable/toroff"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TextView android:id="@+id/lblStatus"
|
<TextView android:id="@+id/lblStatus"
|
||||||
android:text=" \n "
|
android:text="- Press to enable - "
|
||||||
android:paddingTop="15px"
|
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:width="240px"
|
android:width="240px"
|
||||||
android:height="100px"
|
android:height="100px"
|
||||||
android:textColor="#ffffff" />
|
android:textColor="#ffffff"
|
||||||
|
/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
**
|
|
||||||
** Copyright 2008, Google Inc.
|
|
||||||
**
|
|
||||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
** you may not use this file except in compliance with the License.
|
|
||||||
** You may obtain a copy of the License at
|
|
||||||
**
|
|
||||||
** http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
**
|
|
||||||
** Unless required by applicable law or agreed to in writing, software
|
|
||||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
** See the License for the specific language governing permissions and
|
|
||||||
** limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
>
|
|
||||||
|
|
||||||
<WebView
|
|
||||||
android:id="@+id/webview"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1,6 +1,45 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">ORbot</string>
|
<string name="app_name">Orbot</string>
|
||||||
<string name="app_version">0.0.2a</string>
|
<string name="app_version">0.0.3a</string>
|
||||||
|
<string name="internal_web_url">http://orbot/</string>
|
||||||
|
<string name="default_web_url">http://check.torproject.org</string>
|
||||||
|
<string name="control_permission_label">start and stop the anonymous data connection</string>
|
||||||
|
<string name="tor_proxy_service_process">torproxyservice</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="status_starting_up">Starting up...</string>
|
||||||
|
<string name="status_activated">"Orbot is Activated\n<< TOUCH TO DISCONNECT >></string>
|
||||||
|
<string name="status_disabled">"Orbot is Disabled\n<< TOUCH TO START >></string>
|
||||||
|
<string name="status_shutting_down">Orbot is shutting down</string>
|
||||||
|
|
||||||
|
<string name="tor_process_connecting">Starting Tor engine...</string>
|
||||||
|
<string name="tor_process_connecting_step2">authenticating...</string>
|
||||||
|
<string name="tor_process_connecting_step3">complete.</string>
|
||||||
|
<string name="tor_process_connecting_step4">waiting.</string>
|
||||||
|
|
||||||
|
<string name="menu_home">Home</string>
|
||||||
|
<string name="menu_browse">Browse</string>
|
||||||
|
<string name="menu_settings">Settings</string>
|
||||||
|
<string name="menu_log">Log</string>
|
||||||
|
<string name="menu_info">Info</string>
|
||||||
|
|
||||||
|
<string name="button_help">Help</string>
|
||||||
|
<string name="button_close">Close</string>
|
||||||
|
<string name="button_about">About</string>
|
||||||
|
|
||||||
|
<string name="help_text">Orbot requires different configuration depending on the Android operating system version it is used on.
|
||||||
|
\n\n
|
||||||
|
For non-rooted Android 1.x devices (G1, MyTouch3G, Hero): Please use the "ProxySurf" browser available in the Android Market, and set
|
||||||
|
the HTTP Proxy to 127.0.0.1 and port 8118. For Instant Messsaging, try "Beem" in the market, and set the HTTP or SOCKS5 proxy (to port 9050).
|
||||||
|
\n\n
|
||||||
|
For Android 2.x devices, you MUST ROOT your device in order for Orbot to work transparently for all web and DNS traffic. Otherwise, the "Beem" app will allow
|
||||||
|
you to set the SOCKS5 proxy to 127.0.0.1 and port 9050. You should also enable SSL to protect your username and password.
|
||||||
|
\n\n
|
||||||
|
If you root your device, whether it is 1.x or 2.x based, Orbot will automatically, transparently proxy all web traffic on port 80
|
||||||
|
and all DNS requests. This includes the built-in Browser, Gmail, YouTube, Maps and any other application that uses standard port 80
|
||||||
|
traffic.
|
||||||
|
\n\n
|
||||||
|
At this time, Orbot cannot proxy standard HTTPS traffic unless the application supports proxy via HTTP or SOCKS.
|
||||||
|
</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,639 +0,0 @@
|
||||||
package org.torproject.android;
|
|
||||||
/* <!-- in case someone opens this in a browser... --> <pre> */
|
|
||||||
/*
|
|
||||||
* This is a simple multi-threaded Java proxy server
|
|
||||||
* for HTTP requests (HTTPS doesn't seem to work, because
|
|
||||||
* the CONNECT requests aren't always handled properly).
|
|
||||||
* I implemented the class as a thread so you can call it
|
|
||||||
* from other programs and kill it, if necessary (by using
|
|
||||||
* the closeSocket() method).
|
|
||||||
*
|
|
||||||
* We'll call this the 1.1 version of this class. All I
|
|
||||||
* changed was to separate the HTTP header elements with
|
|
||||||
* \r\n instead of just \n, to comply with the official
|
|
||||||
* HTTP specification.
|
|
||||||
*
|
|
||||||
* This can be used either as a direct proxy to other
|
|
||||||
* servers, or as a forwarding proxy to another proxy
|
|
||||||
* server. This makes it useful if you want to monitor
|
|
||||||
* traffic going to and from a proxy server (for example,
|
|
||||||
* you can run this on your local machine and set the
|
|
||||||
* fwdServer and fwdPort to a real proxy server, and then
|
|
||||||
* tell your browser to use "localhost" as the proxy, and
|
|
||||||
* you can watch the browser traffic going in and out).
|
|
||||||
*
|
|
||||||
* One limitation of this implementation is that it doesn't
|
|
||||||
* close the ProxyThread socket if the client disconnects
|
|
||||||
* or the server never responds, so you could end up with
|
|
||||||
* a bunch of loose threads running amuck and waiting for
|
|
||||||
* connections. As a band-aid, you can set the server socket
|
|
||||||
* to timeout after a certain amount of time (use the
|
|
||||||
* setTimeout() method in the ProxyThread class), although
|
|
||||||
* this can cause false timeouts if a remote server is simply
|
|
||||||
* slow to respond.
|
|
||||||
*
|
|
||||||
* Another thing is that it doesn't limit the number of
|
|
||||||
* socket threads it will create, so if you use this on a
|
|
||||||
* really busy machine that processed a bunch of requests,
|
|
||||||
* you may have problems. You should use thread pools if
|
|
||||||
* you're going to try something like this in a "real"
|
|
||||||
* application.
|
|
||||||
*
|
|
||||||
* Note that if you're using the "main" method to run this
|
|
||||||
* by itself and you don't need the debug output, it will
|
|
||||||
* run a bit faster if you pipe the std output to 'nul'.
|
|
||||||
*
|
|
||||||
* You may use this code as you wish, just don't pretend
|
|
||||||
* that you wrote it yourself, and don't hold me liable for
|
|
||||||
* anything that it does or doesn't do. If you're feeling
|
|
||||||
* especially honest, please include a link to nsftools.com
|
|
||||||
* along with the code. Thanks, and good luck.
|
|
||||||
*
|
|
||||||
* Julian Robichaux -- http://www.nsftools.com
|
|
||||||
*/
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import net.sourceforge.jsocks.socks.Socks5Proxy;
|
|
||||||
import net.sourceforge.jsocks.socks.SocksSocket;
|
|
||||||
|
|
||||||
|
|
||||||
public class HttpProxy extends Thread
|
|
||||||
{
|
|
||||||
public static final int DEFAULT_PORT = 8888;
|
|
||||||
|
|
||||||
private ServerSocket server = null;
|
|
||||||
private int thisPort = DEFAULT_PORT;
|
|
||||||
private String fwdServer = "";
|
|
||||||
private int fwdPort = 0;
|
|
||||||
private int ptTimeout = ProxyThread.DEFAULT_TIMEOUT;
|
|
||||||
private int debugLevel = 1;
|
|
||||||
private PrintStream debugOut = System.out;
|
|
||||||
private boolean keepRunning = true;
|
|
||||||
private boolean doSocks = false;
|
|
||||||
|
|
||||||
private Socks5Proxy sProxy = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the doSocks
|
|
||||||
*/
|
|
||||||
public boolean isDoSocks() {
|
|
||||||
return doSocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param doSocks the doSocks to set
|
|
||||||
*/
|
|
||||||
public void setDoSocks(boolean doSocks) {
|
|
||||||
this.doSocks = doSocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* here's a main method, in case you want to run this by itself */
|
|
||||||
public static void main (String args[])
|
|
||||||
{
|
|
||||||
int port = 0;
|
|
||||||
String fwdProxyServer = "";
|
|
||||||
int fwdProxyPort = 0;
|
|
||||||
|
|
||||||
if (args.length == 0)
|
|
||||||
{
|
|
||||||
System.err.println("USAGE: java jProxy <port number> [<fwd proxy> <fwd port>]");
|
|
||||||
System.err.println(" <port number> the port this service listens on");
|
|
||||||
System.err.println(" <fwd proxy> optional proxy server to forward requests to");
|
|
||||||
System.err.println(" <fwd port> the port that the optional proxy server is on");
|
|
||||||
System.err.println("\nHINT: if you don't want to see all the debug information flying by,");
|
|
||||||
System.err.println("you can pipe the output to a file or to 'nul' using \">\". For example:");
|
|
||||||
System.err.println(" to send output to the file prox.txt: java jProxy 8080 > prox.txt");
|
|
||||||
System.err.println(" to make the output go away: java jProxy 8080 > nul");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the command-line parameters
|
|
||||||
port = Integer.parseInt(args[0]);
|
|
||||||
if (args.length > 2)
|
|
||||||
{
|
|
||||||
fwdProxyServer = args[1];
|
|
||||||
fwdProxyPort = Integer.parseInt(args[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create and start the jProxy thread, using a 20 second timeout
|
|
||||||
// value to keep the threads from piling up too much
|
|
||||||
System.err.println(" ** Starting jProxy on port " + port + ". Press CTRL-C to end. **\n");
|
|
||||||
HttpProxy jp = new HttpProxy(port, fwdProxyServer, fwdProxyPort, 20);
|
|
||||||
jp.setDebug(1, System.out); // or set the debug level to 2 for tons of output
|
|
||||||
jp.start();
|
|
||||||
|
|
||||||
// run forever; if you were calling this class from another
|
|
||||||
// program and you wanted to stop the jProxy thread at some
|
|
||||||
// point, you could write a loop that waits for a certain
|
|
||||||
// condition and then calls jProxy.closeSocket() to kill
|
|
||||||
// the running jProxy thread
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
try { Thread.sleep(3000); } catch (Exception e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we ever had a condition that stopped the loop above,
|
|
||||||
// we'd want to do this to kill the running thread
|
|
||||||
//jp.closeSocket();
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* the proxy server just listens for connections and creates
|
|
||||||
* a new thread for each connection attempt (the ProxyThread
|
|
||||||
* class really does all the work)
|
|
||||||
*/
|
|
||||||
public HttpProxy (int port)
|
|
||||||
{
|
|
||||||
thisPort = port;
|
|
||||||
|
|
||||||
try {
|
|
||||||
sProxy = new Socks5Proxy(TorConstants.IP_LOCALHOST,TorConstants.PORT_SOCKS);
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
sProxy.resolveAddrLocally(false);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpProxy (int port, String proxyServer, int proxyPort)
|
|
||||||
{
|
|
||||||
thisPort = port;
|
|
||||||
fwdServer = proxyServer;
|
|
||||||
fwdPort = proxyPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpProxy (int port, String proxyServer, int proxyPort, int timeout)
|
|
||||||
{
|
|
||||||
thisPort = port;
|
|
||||||
fwdServer = proxyServer;
|
|
||||||
fwdPort = proxyPort;
|
|
||||||
ptTimeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* allow the user to decide whether or not to send debug
|
|
||||||
* output to the console or some other PrintStream
|
|
||||||
*/
|
|
||||||
public void setDebug (int level, PrintStream out)
|
|
||||||
{
|
|
||||||
debugLevel = level;
|
|
||||||
debugOut = out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* get the port that we're supposed to be listening on
|
|
||||||
*/
|
|
||||||
public int getPort ()
|
|
||||||
{
|
|
||||||
return thisPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* return whether or not the socket is currently open
|
|
||||||
*/
|
|
||||||
public boolean isRunning ()
|
|
||||||
{
|
|
||||||
if (server == null)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* closeSocket will close the open ServerSocket; use this
|
|
||||||
* to halt a running jProxy thread
|
|
||||||
*/
|
|
||||||
public void closeSocket ()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
keepRunning = false;
|
|
||||||
// close the open server socket
|
|
||||||
server.close();
|
|
||||||
// send it a message to make it stop waiting immediately
|
|
||||||
// (not really necessary)
|
|
||||||
/*Socket s = new Socket("localhost", thisPort);
|
|
||||||
OutputStream os = s.getOutputStream();
|
|
||||||
os.write((byte)0);
|
|
||||||
os.close();
|
|
||||||
s.close();*/
|
|
||||||
} catch(Exception e) {
|
|
||||||
if (debugLevel > 0)
|
|
||||||
debugOut.println(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
server = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
// create a server socket, and loop forever listening for
|
|
||||||
// client connections
|
|
||||||
server = new ServerSocket(thisPort);
|
|
||||||
|
|
||||||
while (keepRunning)
|
|
||||||
{
|
|
||||||
Socket client = server.accept();
|
|
||||||
ProxyThread t = new ProxyThread(client, doSocks, sProxy);
|
|
||||||
//t.setDebug(debugLevel, debugOut);
|
|
||||||
//t.setTimeout(ptTimeout);
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (debugLevel > 0)
|
|
||||||
debugOut.println("jProxy Thread error: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
closeSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The ProxyThread will take an HTTP request from the client
|
|
||||||
* socket and send it to either the server that the client is
|
|
||||||
* trying to contact, or another proxy server
|
|
||||||
*/
|
|
||||||
class ProxyThread extends Thread
|
|
||||||
{
|
|
||||||
private Socket pSocket;
|
|
||||||
private String fwdServer = "";
|
|
||||||
private int fwdPort = 0;
|
|
||||||
private int debugLevel = 0;
|
|
||||||
private PrintStream debugOut = System.out;
|
|
||||||
|
|
||||||
// the socketTimeout is used to time out the connection to
|
|
||||||
// the remote server after a certain period of inactivity;
|
|
||||||
// the value is in milliseconds -- use zero if you don't want
|
|
||||||
// a timeout
|
|
||||||
public static final int DEFAULT_TIMEOUT = 20 * 1000;
|
|
||||||
private int socketTimeout = DEFAULT_TIMEOUT;
|
|
||||||
|
|
||||||
private boolean doSocks = false;
|
|
||||||
|
|
||||||
private static Socks5Proxy sProxy = null;
|
|
||||||
|
|
||||||
public ProxyThread(Socket s, boolean doSocks, Socks5Proxy sProxy)
|
|
||||||
{
|
|
||||||
pSocket = s;
|
|
||||||
|
|
||||||
this.sProxy = sProxy;
|
|
||||||
this.doSocks = doSocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProxyThread(Socket s, String proxy, int port)
|
|
||||||
{
|
|
||||||
pSocket = s;
|
|
||||||
fwdServer = proxy;
|
|
||||||
fwdPort = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setTimeout (int timeout)
|
|
||||||
{
|
|
||||||
// assume that the user will pass the timeout value
|
|
||||||
// in seconds (because that's just more intuitive)
|
|
||||||
socketTimeout = timeout * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setDebug (int level, PrintStream out)
|
|
||||||
{
|
|
||||||
debugLevel = level;
|
|
||||||
debugOut = out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
// client streams (make sure you're using streams that use
|
|
||||||
// byte arrays, so things like GIF and JPEG files and file
|
|
||||||
// downloads will transfer properly)
|
|
||||||
BufferedInputStream clientIn = new BufferedInputStream(pSocket.getInputStream());
|
|
||||||
BufferedOutputStream clientOut = new BufferedOutputStream(pSocket.getOutputStream());
|
|
||||||
|
|
||||||
// the socket to the remote server
|
|
||||||
Socket server = null;
|
|
||||||
|
|
||||||
// other variables
|
|
||||||
byte[] request = null;
|
|
||||||
byte[] response = null;
|
|
||||||
int requestLength = 0;
|
|
||||||
int responseLength = 0;
|
|
||||||
int pos = -1;
|
|
||||||
StringBuffer host = new StringBuffer("");
|
|
||||||
String hostName = "";
|
|
||||||
int hostPort = 80;
|
|
||||||
|
|
||||||
// get the header info (the web browser won't disconnect after
|
|
||||||
// it's sent a request, so make sure the waitForDisconnect
|
|
||||||
// parameter is false)
|
|
||||||
request = getHTTPData(clientIn, host, false);
|
|
||||||
requestLength = Array.getLength(request);
|
|
||||||
|
|
||||||
// separate the host name from the host port, if necessary
|
|
||||||
// (like if it's "servername:8000")
|
|
||||||
hostName = host.toString();
|
|
||||||
pos = hostName.indexOf(":");
|
|
||||||
if (pos > 0)
|
|
||||||
{
|
|
||||||
try { hostPort = Integer.parseInt(hostName.substring(pos + 1));
|
|
||||||
} catch (Exception e) { }
|
|
||||||
hostName = hostName.substring(0, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// either forward this request to another proxy server or
|
|
||||||
// send it straight to the Host
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!doSocks)
|
|
||||||
{
|
|
||||||
if ((fwdServer.length() > 0) && (fwdPort > 0))
|
|
||||||
{
|
|
||||||
server = new Socket(fwdServer, fwdPort);
|
|
||||||
} else {
|
|
||||||
server = new Socket(hostName, hostPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
server = new SocksSocket(sProxy,hostName, hostPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
// tell the client there was an error
|
|
||||||
String errMsg = "HTTP/1.0 500\nContent Type: text/plain\n\n" +
|
|
||||||
"Error connecting to the server:\n" + e + "\n";
|
|
||||||
clientOut.write(errMsg.getBytes(), 0, errMsg.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (server != null)
|
|
||||||
{
|
|
||||||
server.setSoTimeout(socketTimeout);
|
|
||||||
BufferedInputStream serverIn = new BufferedInputStream(server.getInputStream());
|
|
||||||
BufferedOutputStream serverOut = new BufferedOutputStream(server.getOutputStream());
|
|
||||||
|
|
||||||
// send the request out
|
|
||||||
serverOut.write(request, 0, requestLength);
|
|
||||||
serverOut.flush();
|
|
||||||
|
|
||||||
// and get the response; if we're not at a debug level that
|
|
||||||
// requires us to return the data in the response, just stream
|
|
||||||
// it back to the client to save ourselves from having to
|
|
||||||
// create and destroy an unnecessary byte array. Also, we
|
|
||||||
// should set the waitForDisconnect parameter to 'true',
|
|
||||||
// because some servers (like Google) don't always set the
|
|
||||||
// Content-Length header field, so we have to listen until
|
|
||||||
// they decide to disconnect (or the connection times out).
|
|
||||||
if (debugLevel > 1)
|
|
||||||
{
|
|
||||||
response = getHTTPData(serverIn, true);
|
|
||||||
responseLength = Array.getLength(response);
|
|
||||||
} else {
|
|
||||||
responseLength = streamHTTPData(serverIn, clientOut, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
serverIn.close();
|
|
||||||
serverOut.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// send the response back to the client, if we haven't already
|
|
||||||
if (debugLevel > 1)
|
|
||||||
clientOut.write(response, 0, responseLength);
|
|
||||||
|
|
||||||
// if the user wants debug info, send them debug info; however,
|
|
||||||
// keep in mind that because we're using threads, the output won't
|
|
||||||
// necessarily be synchronous
|
|
||||||
if (debugLevel > 0)
|
|
||||||
{
|
|
||||||
long endTime = System.currentTimeMillis();
|
|
||||||
debugOut.println("Request from " + pSocket.getInetAddress().getHostAddress() +
|
|
||||||
" on Port " + pSocket.getLocalPort() +
|
|
||||||
" to host " + hostName + ":" + hostPort +
|
|
||||||
"\n (" + requestLength + " bytes sent, " +
|
|
||||||
responseLength + " bytes returned, " +
|
|
||||||
Long.toString(endTime - startTime) + " ms elapsed)");
|
|
||||||
debugOut.flush();
|
|
||||||
}
|
|
||||||
if (debugLevel > 1)
|
|
||||||
{
|
|
||||||
debugOut.println("REQUEST:\n" + (new String(request)));
|
|
||||||
debugOut.println("RESPONSE:\n" + (new String(response)));
|
|
||||||
debugOut.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
// close all the client streams so we can listen again
|
|
||||||
clientOut.close();
|
|
||||||
clientIn.close();
|
|
||||||
pSocket.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (debugLevel > 0)
|
|
||||||
debugOut.println("Error in ProxyThread: " + e);
|
|
||||||
//e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private byte[] getHTTPData (InputStream in, boolean waitForDisconnect)
|
|
||||||
{
|
|
||||||
// get the HTTP data from an InputStream, and return it as
|
|
||||||
// a byte array
|
|
||||||
// the waitForDisconnect parameter tells us what to do in case
|
|
||||||
// the HTTP header doesn't specify the Content-Length of the
|
|
||||||
// transmission
|
|
||||||
StringBuffer foo = new StringBuffer("");
|
|
||||||
return getHTTPData(in, foo, waitForDisconnect);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private byte[] getHTTPData (InputStream in, StringBuffer host, boolean waitForDisconnect)
|
|
||||||
{
|
|
||||||
// get the HTTP data from an InputStream, and return it as
|
|
||||||
// a byte array, and also return the Host entry in the header,
|
|
||||||
// if it's specified -- note that we have to use a StringBuffer
|
|
||||||
// for the 'host' variable, because a String won't return any
|
|
||||||
// information when it's used as a parameter like that
|
|
||||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
|
||||||
streamHTTPData(in, bs, host, waitForDisconnect);
|
|
||||||
return bs.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private int streamHTTPData (InputStream in, OutputStream out, boolean waitForDisconnect)
|
|
||||||
{
|
|
||||||
StringBuffer foo = new StringBuffer("");
|
|
||||||
return streamHTTPData(in, out, foo, waitForDisconnect);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int streamHTTPData (InputStream in, OutputStream out,
|
|
||||||
StringBuffer host, boolean waitForDisconnect)
|
|
||||||
{
|
|
||||||
// get the HTTP data from an InputStream, and send it to
|
|
||||||
// the designated OutputStream
|
|
||||||
StringBuffer header = new StringBuffer("");
|
|
||||||
String data = "";
|
|
||||||
int responseCode = 200;
|
|
||||||
int contentLength = 0;
|
|
||||||
int pos = -1;
|
|
||||||
int byteCount = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// get the first line of the header, so we know the response code
|
|
||||||
data = readLine(in);
|
|
||||||
if (data != null)
|
|
||||||
{
|
|
||||||
header.append(data + "\r\n");
|
|
||||||
pos = data.indexOf(" ");
|
|
||||||
if ((data.toLowerCase().startsWith("http")) &&
|
|
||||||
(pos >= 0) && (data.indexOf(" ", pos+1) >= 0))
|
|
||||||
{
|
|
||||||
String rcString = data.substring(pos+1, data.indexOf(" ", pos+1));
|
|
||||||
try
|
|
||||||
{
|
|
||||||
responseCode = Integer.parseInt(rcString);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (debugLevel > 0)
|
|
||||||
debugOut.println("Error parsing response code " + rcString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the rest of the header info
|
|
||||||
while ((data = readLine(in)) != null)
|
|
||||||
{
|
|
||||||
// the header ends at the first blank line
|
|
||||||
if (data.length() == 0)
|
|
||||||
break;
|
|
||||||
header.append(data + "\r\n");
|
|
||||||
|
|
||||||
// check for the Host header
|
|
||||||
pos = data.toLowerCase().indexOf("host:");
|
|
||||||
if (pos >= 0)
|
|
||||||
{
|
|
||||||
host.setLength(0);
|
|
||||||
host.append(data.substring(pos + 5).trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for the Content-Length header
|
|
||||||
pos = data.toLowerCase().indexOf("content-length:");
|
|
||||||
if (pos >= 0)
|
|
||||||
contentLength = Integer.parseInt(data.substring(pos + 15).trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a blank line to terminate the header info
|
|
||||||
header.append("\r\n");
|
|
||||||
|
|
||||||
// convert the header to a byte array, and write it to our stream
|
|
||||||
out.write(header.toString().getBytes(), 0, header.length());
|
|
||||||
|
|
||||||
// if the header indicated that this was not a 200 response,
|
|
||||||
// just return what we've got if there is no Content-Length,
|
|
||||||
// because we may not be getting anything else
|
|
||||||
if ((responseCode != 200) && (contentLength == 0))
|
|
||||||
{
|
|
||||||
out.flush();
|
|
||||||
return header.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the body, if any; we try to use the Content-Length header to
|
|
||||||
// determine how much data we're supposed to be getting, because
|
|
||||||
// sometimes the client/server won't disconnect after sending us
|
|
||||||
// information...
|
|
||||||
if (contentLength > 0)
|
|
||||||
waitForDisconnect = false;
|
|
||||||
|
|
||||||
if ((contentLength > 0) || (waitForDisconnect))
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
byte[] buf = new byte[4096];
|
|
||||||
int bytesIn = 0;
|
|
||||||
while ( ((byteCount < contentLength) || (waitForDisconnect))
|
|
||||||
&& ((bytesIn = in.read(buf)) >= 0) )
|
|
||||||
{
|
|
||||||
out.write(buf, 0, bytesIn);
|
|
||||||
byteCount += bytesIn;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
String errMsg = "Error getting HTTP body: " + e;
|
|
||||||
if (debugLevel > 0)
|
|
||||||
debugOut.println(errMsg);
|
|
||||||
//bs.write(errMsg.getBytes(), 0, errMsg.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (debugLevel > 0)
|
|
||||||
debugOut.println("Error getting HTTP data: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
//flush the OutputStream and return
|
|
||||||
try { out.flush(); } catch (Exception e) {}
|
|
||||||
return (header.length() + byteCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private String readLine (InputStream in)
|
|
||||||
{
|
|
||||||
// reads a line of text from an InputStream
|
|
||||||
StringBuffer data = new StringBuffer("");
|
|
||||||
int c;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// if we have nothing to read, just return null
|
|
||||||
in.mark(1);
|
|
||||||
if (in.read() == -1)
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
in.reset();
|
|
||||||
|
|
||||||
while ((c = in.read()) >= 0)
|
|
||||||
{
|
|
||||||
// check for an end-of-line character
|
|
||||||
if ((c == 0) || (c == 10) || (c == 13))
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
data.append((char)c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// deal with the case where the end-of-line terminator is \r\n
|
|
||||||
if (c == 13)
|
|
||||||
{
|
|
||||||
in.mark(1);
|
|
||||||
if (in.read() != 10)
|
|
||||||
in.reset();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (debugLevel > 0)
|
|
||||||
debugOut.println("Error getting header: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// and return what we have
|
|
||||||
return data.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,642 @@
|
||||||
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
package org.torproject.android;
|
||||||
|
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import org.torproject.android.service.ITorService;
|
||||||
|
import org.torproject.android.service.ITorServiceCallback;
|
||||||
|
import org.torproject.android.service.TorRoot;
|
||||||
|
import org.torproject.android.service.TorServiceConstants;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
public class Orbot extends Activity implements OnClickListener, TorConstants
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Useful UI bits */
|
||||||
|
private TextView txtMessageLog = null; //the full screen log view of Tor control messages
|
||||||
|
private TextView lblStatus = null; //the main text display widget
|
||||||
|
private ImageView imgStatus = null; //the main touchable image for activating Orbot
|
||||||
|
private ProgressDialog progressDialog;
|
||||||
|
|
||||||
|
/* Some tracking bits */
|
||||||
|
private int torStatus = STATUS_REQUIRES_DEMAND; //latest status reported from the tor service
|
||||||
|
private int currentView = 0; //the currently displayed UI view
|
||||||
|
private StringBuffer logBuffer = new StringBuffer(); //the output of the service log messages
|
||||||
|
private String lastUrl = null;
|
||||||
|
|
||||||
|
/* Tor Service interaction */
|
||||||
|
/* The primary interface we will be calling on the service. */
|
||||||
|
ITorService mService = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Called when the activity is first created. */
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setTheme(android.R.style.Theme_Black);
|
||||||
|
setTitle(getString(R.string.app_name) + ' ' + getString(R.string.app_version));
|
||||||
|
showMain();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the UI Options Menu (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
|
||||||
|
*/
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
super.onCreateOptionsMenu(menu);
|
||||||
|
|
||||||
|
MenuItem mItem = null;
|
||||||
|
|
||||||
|
mItem = menu.add(0, 1, Menu.NONE, getString(R.string.menu_home));
|
||||||
|
mItem.setIcon(R.drawable.ic_menu_home);
|
||||||
|
|
||||||
|
mItem = menu.add(0, 2, Menu.NONE, getString(R.string.menu_browse));
|
||||||
|
mItem.setIcon(R.drawable.ic_menu_goto);
|
||||||
|
|
||||||
|
mItem = menu.add(0, 3, Menu.NONE, getString(R.string.menu_settings));
|
||||||
|
mItem.setIcon(R.drawable.ic_menu_register);
|
||||||
|
|
||||||
|
mItem = menu.add(0, 4, Menu.NONE, getString(R.string.menu_log));
|
||||||
|
mItem.setIcon(R.drawable.ic_menu_reports);
|
||||||
|
|
||||||
|
mItem = menu.add(0, 5, Menu.NONE, getString(R.string.menu_info));
|
||||||
|
mItem.setIcon(R.drawable.ic_menu_about);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When a menu item is selected launch the appropriate view or activity
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||||
|
|
||||||
|
super.onMenuItemSelected(featureId, item);
|
||||||
|
|
||||||
|
if (item.getItemId() == 1)
|
||||||
|
{
|
||||||
|
this.showMain();
|
||||||
|
}
|
||||||
|
else if (item.getItemId() == 3)
|
||||||
|
{
|
||||||
|
this.showSettings();
|
||||||
|
}
|
||||||
|
else if (item.getItemId() == 4)
|
||||||
|
{
|
||||||
|
this.showMessageLog();
|
||||||
|
}
|
||||||
|
else if (item.getItemId() == 2)
|
||||||
|
{
|
||||||
|
openBrowser(URL_TOR_CHECK);
|
||||||
|
}
|
||||||
|
else if (item.getItemId() == 5)
|
||||||
|
{
|
||||||
|
showHelp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return to the main view when the back key is pressed
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
|
||||||
|
*/
|
||||||
|
public boolean onKeyDown(int keyCode, KeyEvent event){
|
||||||
|
|
||||||
|
if(keyCode==KeyEvent.KEYCODE_BACK){
|
||||||
|
|
||||||
|
if(currentView != R.layout.layout_main){
|
||||||
|
|
||||||
|
showMain ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return super.onKeyDown(keyCode, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onKeyDown(keyCode, event);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onPause()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onResume()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
updateStatus (""); //update the status, which checks the service status
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onStart()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
|
||||||
|
//if Tor binary is not running, then start the service up
|
||||||
|
startService(new Intent(INTENT_TOR_SERVICE));
|
||||||
|
bindService ();
|
||||||
|
|
||||||
|
updateStatus ("");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Activity#onStop()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
|
||||||
|
unbindService();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show the main form UI
|
||||||
|
*/
|
||||||
|
private void showMain ()
|
||||||
|
{
|
||||||
|
bindService(); //connect the UI activity to the remote service
|
||||||
|
|
||||||
|
currentView = R.layout.layout_main;
|
||||||
|
setContentView(currentView);
|
||||||
|
|
||||||
|
//add touch listeners for the image and the text label
|
||||||
|
findViewById(R.id.imgStatus).setOnClickListener(this);
|
||||||
|
findViewById(R.id.lblStatus).setOnClickListener(this);
|
||||||
|
|
||||||
|
lblStatus = (TextView)findViewById(R.id.lblStatus);
|
||||||
|
imgStatus = (ImageView)findViewById(R.id.imgStatus);
|
||||||
|
|
||||||
|
updateStatus("");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Launch the system activity for Uri viewing with the provided url
|
||||||
|
*/
|
||||||
|
private void openBrowser(String url)
|
||||||
|
{
|
||||||
|
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show the about view - a popup dialog
|
||||||
|
*/
|
||||||
|
private void showAbout ()
|
||||||
|
{
|
||||||
|
|
||||||
|
LayoutInflater li = LayoutInflater.from(this);
|
||||||
|
View view = li.inflate(R.layout.layout_about, null);
|
||||||
|
TextView versionName = (TextView)view.findViewById(R.id.versionName);
|
||||||
|
versionName.setText(R.string.app_version);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(getString(R.string.menu_info))
|
||||||
|
.setView(view)
|
||||||
|
.setNeutralButton(getString(R.string.button_help), new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int whichButton) {
|
||||||
|
showHelp();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(getString(R.string.button_close), new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int whichButton) {
|
||||||
|
// Log.d(TAG, "Close pressed");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show the help view - a popup dialog
|
||||||
|
*/
|
||||||
|
private void showHelp ()
|
||||||
|
{
|
||||||
|
|
||||||
|
LayoutInflater li = LayoutInflater.from(this);
|
||||||
|
View view = li.inflate(R.layout.layout_help, null);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(getString(R.string.menu_info))
|
||||||
|
.setView(view)
|
||||||
|
.setNeutralButton(getString(R.string.button_about), new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int whichButton) {
|
||||||
|
|
||||||
|
showAbout();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(getString(R.string.button_close), new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int whichButton) {
|
||||||
|
// Log.d(TAG, "Close pressed");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show the message log UI
|
||||||
|
*/
|
||||||
|
private void showMessageLog ()
|
||||||
|
{
|
||||||
|
currentView = R.layout.layout_log;
|
||||||
|
setContentView(currentView);
|
||||||
|
|
||||||
|
txtMessageLog = (TextView)findViewById(R.id.messageLog);
|
||||||
|
txtMessageLog.setText(logBuffer.toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the basic settings application to display torrc
|
||||||
|
*/
|
||||||
|
private void showSettings ()
|
||||||
|
{
|
||||||
|
|
||||||
|
startActivity(new Intent(this, SettingsPreferences.class));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read in the Preferences and write then to the .torrc file
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void processSettings ()
|
||||||
|
{
|
||||||
|
StringBuffer torrcText = new StringBuffer();
|
||||||
|
|
||||||
|
torrcText.append(TorConstants.TORRC_DEFAULT);
|
||||||
|
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
boolean useBridges = prefs.getBoolean(PREF_BRIDGES_ENABLED, false);
|
||||||
|
|
||||||
|
boolean autoUpdateBridges = prefs.getBoolean(PREF_BRIDGES_UPDATED, false);
|
||||||
|
|
||||||
|
String bridgeList = prefs.getString(PREF_BRIDGES_LIST,"");
|
||||||
|
|
||||||
|
if (useBridges)
|
||||||
|
{
|
||||||
|
torrcText.append("UseBridges 1");
|
||||||
|
torrcText.append('\n');
|
||||||
|
|
||||||
|
torrcText.append("UpdateBridgesFromAuthority ");
|
||||||
|
|
||||||
|
if (autoUpdateBridges)
|
||||||
|
torrcText.append("1");
|
||||||
|
else
|
||||||
|
torrcText.append("0");
|
||||||
|
|
||||||
|
torrcText.append('\n');
|
||||||
|
|
||||||
|
String bridgeDelim = "\n";
|
||||||
|
|
||||||
|
if (bridgeList.indexOf(",") != -1)
|
||||||
|
{
|
||||||
|
bridgeDelim = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTokenizer st = new StringTokenizer(bridgeList,bridgeDelim);
|
||||||
|
while (st.hasMoreTokens())
|
||||||
|
{
|
||||||
|
torrcText.append("bridge ");
|
||||||
|
torrcText.append(st.nextToken());
|
||||||
|
torrcText.append('\n');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
torrcText.append("UseBridges 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.saveTextFile(TorServiceConstants.TORRC_INSTALL_PATH, torrcText.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the state of the running/not running graphic and label
|
||||||
|
*/
|
||||||
|
public void updateStatus (String torServiceMsg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
if (mService != null)
|
||||||
|
torStatus = mService.getStatus();
|
||||||
|
|
||||||
|
|
||||||
|
if (imgStatus != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (torStatus == STATUS_ON)
|
||||||
|
{
|
||||||
|
imgStatus.setImageResource(R.drawable.toron);
|
||||||
|
|
||||||
|
lblStatus.setText(getString(R.string.status_activated));
|
||||||
|
|
||||||
|
if (progressDialog != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
progressDialog.cancel();
|
||||||
|
progressDialog.hide();
|
||||||
|
progressDialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (torServiceMsg != null && torServiceMsg.length()>0)
|
||||||
|
Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (torStatus == STATUS_CONNECTING)
|
||||||
|
{
|
||||||
|
|
||||||
|
imgStatus.setImageResource(R.drawable.torstarting);
|
||||||
|
lblStatus.setText(getString(R.string.status_starting_up));
|
||||||
|
|
||||||
|
if (progressDialog == null)
|
||||||
|
{
|
||||||
|
progressDialog = new ProgressDialog(this);
|
||||||
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
progressDialog.setCancelable(true);
|
||||||
|
progressDialog.setMessage(getString(R.string.status_starting_up));
|
||||||
|
progressDialog.show();
|
||||||
|
|
||||||
|
progressDialog.setProgress(10);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
progressDialog.setMessage(torServiceMsg);
|
||||||
|
|
||||||
|
int idx = torServiceMsg.indexOf("%");
|
||||||
|
|
||||||
|
if (idx != -1)
|
||||||
|
{
|
||||||
|
String pComp = torServiceMsg.substring(idx-2,idx).trim();
|
||||||
|
int ipComp = Integer.parseInt(pComp);
|
||||||
|
progressDialog.setProgress(ipComp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (torStatus == STATUS_UNAVAILABLE)
|
||||||
|
{
|
||||||
|
imgStatus.setImageResource(R.drawable.torstopping);
|
||||||
|
lblStatus.setText(getString(R.string.status_shutting_down));
|
||||||
|
|
||||||
|
if (torServiceMsg != null && torServiceMsg.length()>0)
|
||||||
|
Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if (torServiceMsg != null && torServiceMsg.length()>0)
|
||||||
|
Toast.makeText(this, torServiceMsg, Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
|
|
||||||
|
if (progressDialog != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
progressDialog.cancel();
|
||||||
|
progressDialog.hide();
|
||||||
|
progressDialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
imgStatus.setImageResource(R.drawable.toroff);
|
||||||
|
lblStatus.setText(getString(R.string.status_disabled));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (RemoteException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see android.view.View.OnClickListener#onClick(android.view.View)
|
||||||
|
*/
|
||||||
|
public void onClick(View view) {
|
||||||
|
|
||||||
|
// the start button
|
||||||
|
if (view.getId()==R.id.imgStatus || view.getId()==R.id.lblStatus)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (mService == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (mService.getStatus() == STATUS_REQUIRES_DEMAND)
|
||||||
|
{
|
||||||
|
processSettings();
|
||||||
|
mService.setProfile(PROFILE_ON);
|
||||||
|
|
||||||
|
if (hasRoot)
|
||||||
|
{
|
||||||
|
TorRoot.enableDNSProxying();
|
||||||
|
TorRoot.enabledWebProxying();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
mService.setProfile(PROFILE_ONDEMAND);
|
||||||
|
|
||||||
|
if (hasRoot)
|
||||||
|
{
|
||||||
|
TorRoot.purgeNatIptables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.i(TAG,"error onclick",e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation is used to receive callbacks from the remote
|
||||||
|
* service.
|
||||||
|
*/
|
||||||
|
private ITorServiceCallback mCallback = new ITorServiceCallback.Stub() {
|
||||||
|
/**
|
||||||
|
* This is called by the remote service regularly to tell us about
|
||||||
|
* new values. Note that IPC calls are dispatched through a thread
|
||||||
|
* pool running in each process, so the code executing here will
|
||||||
|
* NOT be running in our main thread like most other things -- so,
|
||||||
|
* to update the UI, we need to use a Handler to hop over there.
|
||||||
|
*/
|
||||||
|
public void statusChanged(String value) {
|
||||||
|
|
||||||
|
Message msg = mHandler.obtainMessage(BUMP_MSG);
|
||||||
|
msg.getData().putString(HANDLER_TOR_MSG, value);
|
||||||
|
mHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int BUMP_MSG = 1;
|
||||||
|
|
||||||
|
|
||||||
|
private Handler mHandler = new Handler() {
|
||||||
|
@Override public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case BUMP_MSG:
|
||||||
|
|
||||||
|
String torServiceMsg = (String)msg.getData().getString(HANDLER_TOR_MSG);
|
||||||
|
|
||||||
|
logBuffer.append(torServiceMsg);
|
||||||
|
logBuffer.append('\n');
|
||||||
|
|
||||||
|
updateStatus(torServiceMsg);
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super.handleMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for interacting with the main interface of the service.
|
||||||
|
*/
|
||||||
|
private ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
public void onServiceConnected(ComponentName className,
|
||||||
|
IBinder service) {
|
||||||
|
// This is called when the connection with the service has been
|
||||||
|
// established, giving us the service object we can use to
|
||||||
|
// interact with the service. We are communicating with our
|
||||||
|
// service through an IDL interface, so get a client-side
|
||||||
|
// representation of that from the raw service object.
|
||||||
|
mService = ITorService.Stub.asInterface(service);
|
||||||
|
|
||||||
|
updateStatus ("");
|
||||||
|
|
||||||
|
// We want to monitor the service for as long as we are
|
||||||
|
// connected to it.
|
||||||
|
try {
|
||||||
|
mService.registerCallback(mCallback);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// In this case the service has crashed before we could even
|
||||||
|
// do anything with it; we can count on soon being
|
||||||
|
// disconnected (and then reconnected if it can be restarted)
|
||||||
|
// so there is no need to do anything here.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName className) {
|
||||||
|
// This is called when the connection with the service has been
|
||||||
|
// unexpectedly disconnected -- that is, its process crashed.
|
||||||
|
mService = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
boolean mIsBound = false;
|
||||||
|
boolean hasRoot = false;
|
||||||
|
|
||||||
|
private void bindService ()
|
||||||
|
{
|
||||||
|
bindService(new Intent(ITorService.class.getName()),
|
||||||
|
mConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
|
mIsBound = true;
|
||||||
|
|
||||||
|
hasRoot = TorRoot.hasRootAccess();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unbindService ()
|
||||||
|
{
|
||||||
|
if (mIsBound) {
|
||||||
|
// If we have received the service, and hence registered with
|
||||||
|
// it, then now is the time to unregister.
|
||||||
|
if (mService != null) {
|
||||||
|
try {
|
||||||
|
mService.unregisterCallback(mCallback);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// There is nothing special we need to do if the service
|
||||||
|
// has crashed.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach our existing connection.
|
||||||
|
unbindService(mConnection);
|
||||||
|
mIsBound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
package org.torproject.android;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceActivity;
|
||||||
|
|
||||||
|
public class SettingsPreferences
|
||||||
|
extends PreferenceActivity {
|
||||||
|
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,75 +1,37 @@
|
||||||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
|
/* Copyright (c) 2009, Nathan Freitas, Orbot/The Guardian Project - http://openideals.com/guardian */
|
||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
package org.torproject.android;
|
package org.torproject.android;
|
||||||
|
|
||||||
public interface TorConstants {
|
public interface TorConstants {
|
||||||
|
|
||||||
//home directory of Android application
|
public final static String TAG = "Orbot";
|
||||||
public final static String TOR_HOME = "/data/data/org.torproject.android/";
|
|
||||||
|
|
||||||
//name of the tor C binary
|
public final static int FILE_WRITE_BUFFER_SIZE = 2048;
|
||||||
public final static String TOR_BINARY_ASSET_KEY = "tor";
|
|
||||||
|
|
||||||
//path to install the Tor binary too
|
|
||||||
public final static String TOR_BINARY_INSTALL_PATH = TOR_HOME + TOR_BINARY_ASSET_KEY;
|
|
||||||
|
|
||||||
//key of the tor binary in the Zip file
|
|
||||||
public final static String TOR_BINARY_ZIP_KEY = "assets/" + TOR_BINARY_ASSET_KEY;
|
|
||||||
|
|
||||||
//torrc file name
|
|
||||||
public final static String TORRC_ASSET_KEY = "torrc";
|
|
||||||
|
|
||||||
//path to install torrc to within the android app data folder
|
|
||||||
public final static String TORRC_INSTALL_PATH = TOR_HOME + TORRC_ASSET_KEY;
|
|
||||||
|
|
||||||
//key of the torrc file in the Zip file
|
|
||||||
public final static String TORRC_ZIP_KEY = "assets/" + TORRC_ASSET_KEY;
|
|
||||||
|
|
||||||
//where to send the notices log
|
|
||||||
public final static String TOR_LOG_PATH = TOR_HOME + "notices.log";
|
|
||||||
|
|
||||||
//control port cookie path
|
|
||||||
public final static String TOR_CONTROL_AUTH_COOKIE = TOR_HOME + "data/control_auth_cookie";
|
|
||||||
|
|
||||||
//how to launch tor
|
|
||||||
public final static String TOR_COMMAND_LINE_ARGS = "-f " + TORRC_INSTALL_PATH;
|
|
||||||
|
|
||||||
//various console cmds
|
|
||||||
public final static String SHELL_CMD_CHMOD = "/system/bin/chmod";
|
|
||||||
public final static String SHELL_CMD_KILL = "/system/bin/kill";
|
|
||||||
public final static String SHELL_CMD_RM = "/system/bin/rm";
|
|
||||||
public final static String SHELL_CMD_PS = "ps";
|
|
||||||
public final static String CHMOD_EXE_VALUE = "777";
|
|
||||||
|
|
||||||
//path of the installed APK file
|
|
||||||
public final static String APK_PATH = "/data/app/org.torproject.android.apk";
|
|
||||||
|
|
||||||
//path to check Tor against
|
//path to check Tor against
|
||||||
public final static String URL_TOR_CHECK = "http://check.torproject.org";
|
public final static String URL_TOR_CHECK = "http://check.torproject.org";
|
||||||
|
|
||||||
public final static int FILE_WRITE_BUFFER_SIZE = 2048;
|
public final static int STATUS_UNAVAILABLE = -1;
|
||||||
|
public final static int STATUS_REQUIRES_DEMAND = 0;
|
||||||
//HTTP Proxy server port
|
|
||||||
public final static int PORT_HTTP = 8118; //just like Privoxy!
|
|
||||||
|
|
||||||
//Socks port client connects to, server is the Tor binary
|
|
||||||
public final static int PORT_SOCKS = 9050;
|
|
||||||
|
|
||||||
//what is says!
|
|
||||||
public final static String IP_LOCALHOST = "127.0.0.1";
|
|
||||||
public final static int TOR_CONTROL_PORT = 9051;
|
|
||||||
public final static int UPDATE_TIMEOUT = 3000;
|
|
||||||
|
|
||||||
public final static String DEFAULT_HOME_PAGE = "file:///android_asset/help.html";// "http://check.torproject.org";
|
|
||||||
|
|
||||||
//status to communicate state
|
|
||||||
public final static int STATUS_OFF = 0;
|
|
||||||
public final static int STATUS_ON = 1;
|
public final static int STATUS_ON = 1;
|
||||||
public final static int STATUS_STARTING_UP = 2;
|
public final static int STATUS_CONNECTING = 2;
|
||||||
public final static int STATUS_SHUTTING_DOWN = 3;
|
|
||||||
|
|
||||||
//control port
|
public final static int PROFILE_OFF = -1;
|
||||||
public final static String TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE = "Bootstrapped 100%";
|
public final static int PROFILE_ONDEMAND = 0;
|
||||||
|
public final static int PROFILE_ON = 1;
|
||||||
|
|
||||||
|
public final static String NEWLINE = "\n";
|
||||||
|
|
||||||
|
public final static String TORRC_DEFAULT =
|
||||||
|
"SocksPort 9050\nSocksListenAddress 127.0.0.1\nSafeSocks 1\nDNSPort 5400\nLog notice stdout\nLog debug syslog\nDataDirectory /data/data/org.torproject.android/data\n"
|
||||||
|
+ "ControlPort 9051\nCookieAuthentication 1\nRelayBandwidthRate 20 KBytes\nRelayBandwidthBurst 20 KBytes\n";
|
||||||
|
|
||||||
|
public final static String INTENT_TOR_SERVICE = "org.torproject.android.service.TOR_SERVICE";
|
||||||
|
|
||||||
|
public final static String HANDLER_TOR_MSG = "torServiceMsg";
|
||||||
|
|
||||||
|
public final static String PREF_BRIDGES_ENABLED = "pref_bridges_enabled";
|
||||||
|
public final static String PREF_BRIDGES_UPDATED = "pref_bridges_enabled";
|
||||||
|
public final static String PREF_BRIDGES_LIST = "pref_bridges_list";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,587 +0,0 @@
|
||||||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
|
|
||||||
/* See LICENSE for licensing information */
|
|
||||||
|
|
||||||
package org.torproject.android;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
import net.freehaven.tor.control.EventHandler;
|
|
||||||
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.webkit.JsResult;
|
|
||||||
import android.webkit.WebChromeClient;
|
|
||||||
import android.webkit.WebSettings;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
public class TorControlPanel extends Activity implements OnClickListener, TorConstants, EventHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
private final static String TAG = "Tor";
|
|
||||||
|
|
||||||
private static Intent torService = null;
|
|
||||||
|
|
||||||
private boolean updateLog = false;
|
|
||||||
private boolean updateStatus = false;
|
|
||||||
|
|
||||||
private TextView lblStatus = null;
|
|
||||||
private ImageView imgStatus = null;
|
|
||||||
private String txtStatus = "";
|
|
||||||
private int torStatus = STATUS_OFF;
|
|
||||||
|
|
||||||
private Thread threadStatus = null;
|
|
||||||
|
|
||||||
private WebView mWebView;
|
|
||||||
|
|
||||||
private int currentView = 0;
|
|
||||||
|
|
||||||
/** Called when the activity is first created. */
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
setTheme(android.R.style.Theme_Black);
|
|
||||||
|
|
||||||
|
|
||||||
showMain();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
super.onCreateOptionsMenu(menu);
|
|
||||||
|
|
||||||
MenuItem mItem = menu.add(0, 1, Menu.NONE, "Home");
|
|
||||||
MenuItem mItem2 = menu.add(0, 2, Menu.NONE, "Settings");
|
|
||||||
MenuItem mItem3 = menu.add(0, 3, Menu.NONE, "Log");
|
|
||||||
MenuItem mItem4 = menu.add(0, 4, Menu.NONE, "Help");
|
|
||||||
|
|
||||||
mItem.setIcon(R.drawable.ic_menu_home);
|
|
||||||
mItem2.setIcon(R.drawable.ic_menu_register);
|
|
||||||
mItem3.setIcon(R.drawable.ic_menu_reports);
|
|
||||||
mItem4.setIcon(R.drawable.ic_menu_about);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Activity#onMenuItemSelected(int, android.view.MenuItem)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
|
||||||
|
|
||||||
super.onMenuItemSelected(featureId, item);
|
|
||||||
|
|
||||||
if (item.getItemId() == 1)
|
|
||||||
{
|
|
||||||
this.showMain();
|
|
||||||
}
|
|
||||||
else if (item.getItemId() == 2)
|
|
||||||
{
|
|
||||||
this.showSettings();
|
|
||||||
}
|
|
||||||
else if (item.getItemId() == 3)
|
|
||||||
{
|
|
||||||
this.showMessageLog();
|
|
||||||
}
|
|
||||||
else if (item.getItemId() == 4)
|
|
||||||
{
|
|
||||||
this.showWeb(DEFAULT_HOME_PAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onKeyDown(int keyCode, KeyEvent event){
|
|
||||||
if(keyCode==KeyEvent.KEYCODE_BACK){
|
|
||||||
if(currentView != R.layout.layout_main){
|
|
||||||
|
|
||||||
showMain ();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return super.onKeyDown(keyCode, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onKeyDown(keyCode, event);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Activity#onPause()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
TorService.setStatus(torStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Activity#onResume()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
torStatus = TorService.getStatus();
|
|
||||||
|
|
||||||
updateStatus ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Activity#onStart()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onStart() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onStart();
|
|
||||||
|
|
||||||
torStatus = TorService.getStatus();
|
|
||||||
|
|
||||||
|
|
||||||
updateStatus ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Activity#onStop()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onStop() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onStop();
|
|
||||||
|
|
||||||
TorService.setStatus(torStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Show the main form UI
|
|
||||||
*/
|
|
||||||
private void showMain ()
|
|
||||||
{
|
|
||||||
updateLog = false;
|
|
||||||
updateStatus = true;
|
|
||||||
|
|
||||||
currentView = R.layout.layout_main;
|
|
||||||
setContentView(currentView);
|
|
||||||
|
|
||||||
findViewById(R.id.imgStatus).setOnClickListener(this);
|
|
||||||
|
|
||||||
lblStatus = (TextView)findViewById(R.id.lblStatus);
|
|
||||||
imgStatus = (ImageView)findViewById(R.id.imgStatus);
|
|
||||||
|
|
||||||
updateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showWeb (String url)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
currentView =R.layout.layout_web;
|
|
||||||
setContentView(currentView);
|
|
||||||
|
|
||||||
mWebView = (WebView) findViewById(R.id.webview);
|
|
||||||
|
|
||||||
WebSettings webSettings = mWebView.getSettings();
|
|
||||||
webSettings.setSavePassword(false);
|
|
||||||
webSettings.setSaveFormData(false);
|
|
||||||
webSettings.setJavaScriptEnabled(true);
|
|
||||||
|
|
||||||
|
|
||||||
mWebView.setWebChromeClient(new MyWebChromeClient());
|
|
||||||
|
|
||||||
mWebView.loadUrl(url);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Show the message log UI
|
|
||||||
*/
|
|
||||||
private void showMessageLog ()
|
|
||||||
{
|
|
||||||
currentView = R.layout.layout_log;
|
|
||||||
setContentView(currentView);
|
|
||||||
((Button)findViewById(R.id.btnLogClear)).setOnClickListener(this);
|
|
||||||
|
|
||||||
updateStatus = false;
|
|
||||||
updateLog = true;
|
|
||||||
|
|
||||||
Thread thread = new Thread ()
|
|
||||||
{
|
|
||||||
public void run ()
|
|
||||||
{
|
|
||||||
|
|
||||||
while (updateLog)
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(UPDATE_TIMEOUT);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.sendEmptyMessage(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
thread.start();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load the Tor log and display it in a text field
|
|
||||||
*/
|
|
||||||
private void updateMessageLog ()
|
|
||||||
{
|
|
||||||
|
|
||||||
TextView tvLog = (TextView)findViewById(R.id.messageLog);
|
|
||||||
|
|
||||||
if (tvLog != null)
|
|
||||||
{
|
|
||||||
String output = loadTextFile(TOR_LOG_PATH);
|
|
||||||
|
|
||||||
tvLog.setText(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle to reload Tor debug log every few seconds while viewing it
|
|
||||||
*/
|
|
||||||
private Handler handler = new Handler() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
|
|
||||||
updateMessageLog ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle to reload Tor debug log every few seconds while viewing it
|
|
||||||
*/
|
|
||||||
private Handler handlerStatus = new Handler() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
|
|
||||||
updateStatus();
|
|
||||||
|
|
||||||
// Toast.makeText(this,txtStatus, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load the basic settings application to display torrc
|
|
||||||
* TODO: these needs to be improved into an actual form GUI
|
|
||||||
*/
|
|
||||||
private void showSettings ()
|
|
||||||
{
|
|
||||||
updateStatus = false;
|
|
||||||
updateLog = false;
|
|
||||||
|
|
||||||
currentView = R.layout.layout_settings;
|
|
||||||
setContentView(currentView);
|
|
||||||
|
|
||||||
|
|
||||||
String output = loadTextFile(TORRC_INSTALL_PATH);
|
|
||||||
|
|
||||||
TextView tvSettings = (TextView)findViewById(R.id.textSettings);
|
|
||||||
((Button)findViewById(R.id.btnSettingsSave)).setOnClickListener(this);
|
|
||||||
tvSettings.setText(output);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the state of the running/not running graphic and label
|
|
||||||
*/
|
|
||||||
public void updateStatus ()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (imgStatus != null)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (torStatus == STATUS_ON)
|
|
||||||
{
|
|
||||||
imgStatus.setImageResource(R.drawable.toron);
|
|
||||||
lblStatus.setText("ORbot is running\n- touch the bot to stop -");
|
|
||||||
updateStatus = false;
|
|
||||||
}
|
|
||||||
else if (torStatus == STATUS_STARTING_UP)
|
|
||||||
{
|
|
||||||
imgStatus.setImageResource(R.drawable.torstarting);
|
|
||||||
|
|
||||||
lblStatus.setText("ORbot reports:\n\"" + txtStatus + "\"");
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (torStatus == STATUS_SHUTTING_DOWN)
|
|
||||||
{
|
|
||||||
imgStatus.setImageResource(R.drawable.torstopping);
|
|
||||||
lblStatus.setText("ORbot is shutting down\nplease wait...");
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
imgStatus.setImageResource(R.drawable.toroff);
|
|
||||||
lblStatus.setText("ORbot is not running\n- touch the bot to start -");
|
|
||||||
updateStatus = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see android.view.View.OnClickListener#onClick(android.view.View)
|
|
||||||
*/
|
|
||||||
public void onClick(View view) {
|
|
||||||
|
|
||||||
// the start button
|
|
||||||
if (view.getId()==R.id.imgStatus)
|
|
||||||
{
|
|
||||||
//if Tor binary is not running, then start the service up
|
|
||||||
if (TorService.getStatus()==STATUS_OFF)
|
|
||||||
{
|
|
||||||
torStatus = STATUS_STARTING_UP;
|
|
||||||
txtStatus = "Connecting to Tor...";
|
|
||||||
updateStatus();
|
|
||||||
|
|
||||||
startTorService ();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
torStatus = STATUS_SHUTTING_DOWN;
|
|
||||||
updateStatus();
|
|
||||||
|
|
||||||
stopService(torService);
|
|
||||||
|
|
||||||
torStatus = STATUS_OFF;
|
|
||||||
|
|
||||||
updateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (view.getId()==R.id.btnLogClear)
|
|
||||||
{
|
|
||||||
|
|
||||||
saveTextFile(TOR_LOG_PATH,"");
|
|
||||||
}
|
|
||||||
else if (view.getId()==R.id.btnSettingsSave)
|
|
||||||
{
|
|
||||||
|
|
||||||
TextView tvSettings = (TextView)findViewById(R.id.textSettings);
|
|
||||||
String newSettings = tvSettings.getText().toString();
|
|
||||||
saveTextFile(TORRC_INSTALL_PATH, newSettings);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startTorService ()
|
|
||||||
{
|
|
||||||
if (torService == null)
|
|
||||||
{
|
|
||||||
torService = new Intent(this, TorService.class);
|
|
||||||
//torService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
TorService.setActivity(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
startService(torService);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load the log file text
|
|
||||||
*/
|
|
||||||
public static String loadTextFile (String path)
|
|
||||||
{
|
|
||||||
String line = null;
|
|
||||||
|
|
||||||
StringBuffer out = new StringBuffer();
|
|
||||||
|
|
||||||
try {
|
|
||||||
BufferedReader reader = new BufferedReader((new FileReader(new File(path))));
|
|
||||||
|
|
||||||
while ((line = reader.readLine()) != null)
|
|
||||||
{
|
|
||||||
out.append(line);
|
|
||||||
out.append('\n');
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.toString();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load the log file text
|
|
||||||
*/
|
|
||||||
public static boolean saveTextFile (String path, String contents)
|
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
FileWriter writer = new FileWriter( path, false );
|
|
||||||
writer.write( contents );
|
|
||||||
|
|
||||||
writer.close();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Log.i(TAG, "error writing file: " + path, e);
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bandwidthUsed(long read, long written) {
|
|
||||||
Log.i(TAG,"BW Used: read=" + read + " written=" + written);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void circuitStatus(String status, String circID, String path) {
|
|
||||||
Log.i(TAG,"CircuitStatus=" + status + ": " + circID);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void message(String severity, String msg) {
|
|
||||||
|
|
||||||
// Log.println(priority, tag, msg)("["+severity+"] "+msg);
|
|
||||||
//Toast.makeText(, text, duration)
|
|
||||||
// Toast.makeText(ACTIVITY, severity + ": " + msg, Toast.LENGTH_SHORT);
|
|
||||||
Log.i(TAG, "[Tor Control Port] " + severity + ": " + msg);
|
|
||||||
|
|
||||||
if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1)
|
|
||||||
{
|
|
||||||
torStatus = STATUS_ON;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//setupWebProxy(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
txtStatus = msg;
|
|
||||||
handlerStatus.sendEmptyMessage(0);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newDescriptors(List<String> orList) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void orConnStatus(String status, String orName) {
|
|
||||||
|
|
||||||
Log.i(TAG,"OrConnStatus=" + status + ": " + orName);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void streamStatus(String status, String streamID, String target) {
|
|
||||||
Log.i(TAG,"StreamStatus=" + status + ": " + streamID);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unrecognized(String type, String msg) {
|
|
||||||
Log.i(TAG,"unrecognized log=" + type + ": " + msg);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a hook for calling "alert" from javascript. Useful for
|
|
||||||
* debugging your javascript.
|
|
||||||
*/
|
|
||||||
final class MyWebChromeClient extends WebChromeClient {
|
|
||||||
@Override
|
|
||||||
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
|
||||||
Log.d(TAG, message);
|
|
||||||
result.confirm();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,617 +0,0 @@
|
||||||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
|
|
||||||
/* See LICENSE for licensing information */
|
|
||||||
|
|
||||||
package org.torproject.android;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
import net.freehaven.tor.control.EventHandler;
|
|
||||||
import net.freehaven.tor.control.NullEventHandler;
|
|
||||||
import net.freehaven.tor.control.TorControlConnection;
|
|
||||||
import net.sourceforge.jsocks.socks.Proxy;
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
public class TorService extends Service implements TorConstants
|
|
||||||
{
|
|
||||||
|
|
||||||
private static TorControlPanel ACTIVITY = null;
|
|
||||||
|
|
||||||
private final static String TAG = "TorService";
|
|
||||||
|
|
||||||
private static HttpProxy webProxy = null;
|
|
||||||
|
|
||||||
private static int currentStatus = STATUS_OFF;
|
|
||||||
|
|
||||||
private TorControlConnection conn = null;
|
|
||||||
|
|
||||||
private Timer timer = new Timer ();
|
|
||||||
private final static int UPDATE_INTERVAL = 60000;
|
|
||||||
|
|
||||||
/** Called when the activity is first created. */
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
|
|
||||||
Log.i(TAG,"TorService: onCreate");
|
|
||||||
|
|
||||||
timer.scheduleAtFixedRate(
|
|
||||||
new TimerTask() {
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
//do nothing
|
|
||||||
// Log.i(TAG,"TorService: task is running");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
UPDATE_INTERVAL);
|
|
||||||
|
|
||||||
|
|
||||||
int procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
|
|
||||||
|
|
||||||
if (procId != -1)
|
|
||||||
{
|
|
||||||
Log.i(TAG,"Found existing Tor process");
|
|
||||||
|
|
||||||
try {
|
|
||||||
currentStatus = STATUS_STARTING_UP;
|
|
||||||
|
|
||||||
initControlConnection();
|
|
||||||
|
|
||||||
getTorStatus();
|
|
||||||
|
|
||||||
if (webProxy != null)
|
|
||||||
{
|
|
||||||
if (webProxy.isRunning())
|
|
||||||
{
|
|
||||||
//do nothing
|
|
||||||
Log.i(TAG, "Web Proxy is already running");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//do nothing
|
|
||||||
Log.i(TAG, "killing Web Proxy");
|
|
||||||
webProxy.closeSocket();
|
|
||||||
setupWebProxy(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else //do something
|
|
||||||
{
|
|
||||||
setupWebProxy(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
currentStatus = STATUS_ON;
|
|
||||||
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
|
||||||
currentStatus = STATUS_OFF;
|
|
||||||
this.stopTor();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
|
||||||
currentStatus = STATUS_OFF;
|
|
||||||
this.stopTor();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Service#onLowMemory()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onLowMemory() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onLowMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Service#onUnbind(android.content.Intent)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean onUnbind(Intent intent) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return super.onUnbind(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static int getStatus ()
|
|
||||||
{
|
|
||||||
|
|
||||||
return currentStatus;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setStatus (int newStatus)
|
|
||||||
{
|
|
||||||
currentStatus = newStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Service#onRebind(android.content.Intent)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onRebind(Intent intent) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onRebind(intent);
|
|
||||||
|
|
||||||
Log.i(TAG,"on rebind");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see android.app.Service#onStart(android.content.Intent, int)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onStart(Intent intent, int startId) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
super.onStart(intent, startId);
|
|
||||||
|
|
||||||
Log.i(TAG,"onStart called");
|
|
||||||
|
|
||||||
initTor();
|
|
||||||
|
|
||||||
setupWebProxy (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void onDestroy ()
|
|
||||||
{
|
|
||||||
super.onDestroy();
|
|
||||||
|
|
||||||
Log.i(TAG,"onDestroy called");
|
|
||||||
|
|
||||||
if (timer != null) timer.cancel();
|
|
||||||
|
|
||||||
stopTor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopTor ()
|
|
||||||
{
|
|
||||||
currentStatus = STATUS_SHUTTING_DOWN;
|
|
||||||
|
|
||||||
setupWebProxy(false);
|
|
||||||
|
|
||||||
killTorProcess ();
|
|
||||||
|
|
||||||
currentStatus = STATUS_OFF;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void setActivity(TorControlPanel activity) {
|
|
||||||
ACTIVITY = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupWebProxy (boolean enabled)
|
|
||||||
{
|
|
||||||
if (enabled)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (webProxy != null)
|
|
||||||
{
|
|
||||||
webProxy.closeSocket();
|
|
||||||
webProxy = null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG,"Starting up Web Proxy on port: " + PORT_HTTP);
|
|
||||||
//httpd s
|
|
||||||
webProxy = new HttpProxy(PORT_HTTP);
|
|
||||||
webProxy.setDoSocks(true);
|
|
||||||
webProxy.start();
|
|
||||||
|
|
||||||
//socks
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
Proxy.setDefaultProxy(IP_LOCALHOST,PORT_SOCKS);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.w(TAG,e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG,"Web Proxy enabled...");
|
|
||||||
|
|
||||||
|
|
||||||
//Settings.System.putString(getContentResolver(), Settings.System.HTTP_PROXY, proxySetting);//enable proxy
|
|
||||||
// Settings.Secure.putString(getContentResolver(), Settings.Secure.HTTP_PROXY, proxySetting);//enable proxy
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Log.i(TAG,"Turning off Socks/Tor routing on Web Proxy");
|
|
||||||
|
|
||||||
if (webProxy != null)
|
|
||||||
{
|
|
||||||
//logNotice("Tor is disabled - browsing is not anonymous!");
|
|
||||||
//webProxy.setDoSocks(false);
|
|
||||||
|
|
||||||
webProxy.closeSocket();
|
|
||||||
webProxy = null;
|
|
||||||
Log.i(TAG,"WebProxy ServerSocket closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reloadConfig ()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (conn == null)
|
|
||||||
{
|
|
||||||
initControlConnection ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conn != null)
|
|
||||||
{
|
|
||||||
conn.signal("RELOAD");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.i(TAG,"Unable to reload configuration",e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void killTorProcess ()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (conn != null)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
Log.i(TAG,"sending SHUTDOWN signal");
|
|
||||||
conn.signal("SHUTDOWN");
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
Log.i(TAG,"error shutting down Tor via connection",e);
|
|
||||||
}
|
|
||||||
conn = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(500);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
|
|
||||||
|
|
||||||
while (procId != -1)
|
|
||||||
{
|
|
||||||
|
|
||||||
Log.i(TAG,"Found Tor PID=" + procId + " - killing now...");
|
|
||||||
|
|
||||||
doCommand(SHELL_CMD_KILL, procId + "");
|
|
||||||
|
|
||||||
procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logNotice (String msg)
|
|
||||||
{
|
|
||||||
|
|
||||||
Log.i(TAG, msg);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkBinary ()
|
|
||||||
{
|
|
||||||
|
|
||||||
boolean binaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
|
|
||||||
|
|
||||||
if (!binaryExists)
|
|
||||||
{
|
|
||||||
killTorProcess ();
|
|
||||||
|
|
||||||
TorBinaryInstaller installer = new TorBinaryInstaller();
|
|
||||||
installer.start(true);
|
|
||||||
|
|
||||||
binaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
|
|
||||||
if (binaryExists)
|
|
||||||
{
|
|
||||||
logNotice("Tor binary installed!");
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logNotice("Tor binary install FAILED!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG,"Setting permission on Tor binary");
|
|
||||||
doCommand(SHELL_CMD_CHMOD, CHMOD_EXE_VALUE + ' ' + TOR_BINARY_INSTALL_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initTor ()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
|
|
||||||
currentStatus = STATUS_STARTING_UP;
|
|
||||||
|
|
||||||
killTorProcess ();
|
|
||||||
|
|
||||||
checkBinary ();
|
|
||||||
|
|
||||||
doCommand(SHELL_CMD_RM,TOR_LOG_PATH);
|
|
||||||
|
|
||||||
Log.i(TAG,"Starting tor process");
|
|
||||||
doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
|
|
||||||
|
|
||||||
int procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
|
|
||||||
|
|
||||||
if (procId == -1)
|
|
||||||
{
|
|
||||||
doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
|
|
||||||
procId = findProcessId(TorConstants.TOR_BINARY_INSTALL_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG,"Tor process id=" + procId);
|
|
||||||
|
|
||||||
currentStatus = STATUS_STARTING_UP;
|
|
||||||
logNotice("Tor is starting up...");
|
|
||||||
|
|
||||||
Thread.sleep(500);
|
|
||||||
initControlConnection ();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
Log.w(TAG,"unable to start Tor Process",e);
|
|
||||||
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logStream (InputStream is)
|
|
||||||
{
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
|
||||||
String line = null;
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
while ((line = reader.readLine()) != null)
|
|
||||||
{
|
|
||||||
Log.i(TAG, line);
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder onBind(Intent arg0) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int findProcessId(String command)
|
|
||||||
{
|
|
||||||
int procId = -1;
|
|
||||||
|
|
||||||
Runtime r = Runtime.getRuntime();
|
|
||||||
|
|
||||||
Process procPs = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
procPs = r.exec(SHELL_CMD_PS);
|
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
|
|
||||||
String line = null;
|
|
||||||
|
|
||||||
while ((line = reader.readLine())!=null)
|
|
||||||
{
|
|
||||||
if (line.indexOf(command)!=-1)
|
|
||||||
{
|
|
||||||
|
|
||||||
StringTokenizer st = new StringTokenizer(line," ");
|
|
||||||
st.nextToken(); //proc owner
|
|
||||||
|
|
||||||
procId = Integer.parseInt(st.nextToken().trim());
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "error: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return procId;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Process doCommand(String command, String arg1)
|
|
||||||
{
|
|
||||||
|
|
||||||
Runtime r = Runtime.getRuntime();
|
|
||||||
|
|
||||||
Process child = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if(child != null) {
|
|
||||||
child.destroy();
|
|
||||||
child = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
child = r.exec(command + ' ' + arg1);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "error: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return child;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String generateHashPassword ()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
PasswordDigest d = PasswordDigest.generateDigest();
|
|
||||||
byte[] s = d.getSecret(); // pass this to authenticate
|
|
||||||
String h = d.getHashedPassword(); // pass this to the Tor on startup.
|
|
||||||
*/
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initControlConnection () throws Exception, RuntimeException
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 50; i++)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Log.i(TAG,"Connecting to control port: " + TOR_CONTROL_PORT);
|
|
||||||
Socket s = new Socket(IP_LOCALHOST, TOR_CONTROL_PORT);
|
|
||||||
conn = TorControlConnection.getConnection(s);
|
|
||||||
// conn.authenticate(new byte[0]); // See section 3.2
|
|
||||||
|
|
||||||
Log.i(TAG,"SUCCESS connected to control port");
|
|
||||||
|
|
||||||
//
|
|
||||||
File fileCookie = new File(TOR_CONTROL_AUTH_COOKIE);
|
|
||||||
byte[] cookie = new byte[(int)fileCookie.length()];
|
|
||||||
new FileInputStream(new File(TOR_CONTROL_AUTH_COOKIE)).read(cookie);
|
|
||||||
conn.authenticate(cookie);
|
|
||||||
|
|
||||||
Log.i(TAG,"SUCCESS authenticated to control port");
|
|
||||||
|
|
||||||
addEventHandler();
|
|
||||||
|
|
||||||
break; //don't need to retry
|
|
||||||
}
|
|
||||||
catch (ConnectException ce)
|
|
||||||
{
|
|
||||||
Log.i(TAG,"Attempt " + i + ": Error connecting to control port; retrying...");
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void modifyConf () throws IOException
|
|
||||||
{
|
|
||||||
// Get one configuration variable.
|
|
||||||
List options = conn.getConf("contact");
|
|
||||||
// Get a set of configuration variables.
|
|
||||||
// List options = conn.getConf(Arrays.asList(new String[]{
|
|
||||||
// "contact", "orport", "socksport"}));
|
|
||||||
// Change a single configuration variable
|
|
||||||
conn.setConf("BandwidthRate", "1 MB");
|
|
||||||
// Change several configuration variables
|
|
||||||
conn.setConf(Arrays.asList(new String[]{
|
|
||||||
"HiddenServiceDir /home/tor/service1",
|
|
||||||
"HiddenServicePort 80",
|
|
||||||
}));
|
|
||||||
// Reset some variables to their defaults
|
|
||||||
conn.resetConf(Arrays.asList(new String[]{
|
|
||||||
"contact", "socksport"
|
|
||||||
}));
|
|
||||||
// Flush the configuration to disk.
|
|
||||||
conn.saveConf();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getTorStatus () throws IOException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (conn != null)
|
|
||||||
{
|
|
||||||
// get a single value.
|
|
||||||
|
|
||||||
// get several values
|
|
||||||
|
|
||||||
if (currentStatus == STATUS_STARTING_UP)
|
|
||||||
{
|
|
||||||
//Map vals = conn.getInfo(Arrays.asList(new String[]{
|
|
||||||
// "status/bootstrap-phase", "status","version"}));
|
|
||||||
|
|
||||||
String bsPhase = conn.getInfo("status/bootstrap-phase");
|
|
||||||
// Log.i(TAG, "bootstrap-phase: " + bsPhase);
|
|
||||||
|
|
||||||
if (bsPhase.indexOf("PROGRESS=100")!=-1)
|
|
||||||
{
|
|
||||||
currentStatus = STATUS_ON;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// String status = conn.getInfo("status/circuit-established");
|
|
||||||
// Log.i(TAG, "status/circuit-established=" + status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentStatus = STATUS_OFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.i(TAG, "Unable to get Tor status from control port");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void addEventHandler () throws IOException
|
|
||||||
{
|
|
||||||
// We extend NullEventHandler so that we don't need to provide empty
|
|
||||||
// implementations for all the events we don't care about.
|
|
||||||
// ...
|
|
||||||
Log.i(TAG,"adding control port event handler");
|
|
||||||
|
|
||||||
conn.setEventHandler(ACTIVITY);
|
|
||||||
|
|
||||||
conn.setEvents(Arrays.asList(new String[]{
|
|
||||||
"ORCONN", "CIRC", "NOTICE", "ERR"}));
|
|
||||||
// conn.setEvents(Arrays.asList(new String[]{
|
|
||||||
// "DEBUG", "INFO", "NOTICE", "WARN", "ERR"}));
|
|
||||||
|
|
||||||
Log.i(TAG,"SUCCESS added control port event handler");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
|
||||||
|
package org.torproject.android;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the log file text
|
||||||
|
*/
|
||||||
|
public static String loadTextFile (String path)
|
||||||
|
{
|
||||||
|
String line = null;
|
||||||
|
|
||||||
|
StringBuffer out = new StringBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedReader reader = new BufferedReader((new FileReader(new File(path))));
|
||||||
|
|
||||||
|
while ((line = reader.readLine()) != null)
|
||||||
|
{
|
||||||
|
out.append(line);
|
||||||
|
out.append('\n');
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the log file text
|
||||||
|
*/
|
||||||
|
public static boolean saveTextFile (String path, String contents)
|
||||||
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
FileWriter writer = new FileWriter( path, false );
|
||||||
|
writer.write( contents );
|
||||||
|
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Log.i(TAG, "error writing file: " + path, e);
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,27 +1,44 @@
|
||||||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
/** SOCKS aware echo client*/
|
/** SOCKS aware echo client*/
|
||||||
|
|
||||||
package org.torproject.android;
|
package org.torproject.android.net;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import net.sourceforge.jsocks.socks.*;
|
import net.sourceforge.jsocks.socks.InetRange;
|
||||||
|
import net.sourceforge.jsocks.socks.Proxy;
|
||||||
|
import net.sourceforge.jsocks.socks.SocksException;
|
||||||
|
import net.sourceforge.jsocks.socks.SocksSocket;
|
||||||
|
|
||||||
|
import org.torproject.android.TorConstants;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
||||||
public class SocksClient implements Runnable {
|
public class SocksClient implements Runnable {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private InetAddress hostIP;
|
private InetAddress hostIP;
|
||||||
|
|
||||||
private Socket ss;
|
private Socket ss;
|
||||||
private InputStream in;
|
private InputStream in;
|
||||||
private OutputStream out;
|
private OutputStream out;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final int BUF_SIZE = 1024;
|
private static final int BUF_SIZE = 1024;
|
||||||
|
private static final String IP_LOCALHOST = "127.0.0.1";
|
||||||
|
|
||||||
public SocksClient(String host,int port)
|
public SocksClient(String host,int port)
|
||||||
throws IOException,UnknownHostException,SocksException{
|
throws IOException,UnknownHostException,SocksException{
|
||||||
|
@ -30,9 +47,9 @@ public class SocksClient implements Runnable {
|
||||||
ss = new SocksSocket(host, port);
|
ss = new SocksSocket(host, port);
|
||||||
out = ss.getOutputStream();
|
out = ss.getOutputStream();
|
||||||
in = ss.getInputStream();
|
in = ss.getInputStream();
|
||||||
System.out.println("Connected...");
|
Log.i(getClass().getName(),"Connected...");
|
||||||
System.out.println("TO: "+host+":"+port);
|
Log.i(getClass().getName(),"TO: "+host+":"+port);
|
||||||
System.out.println("ViaProxy: "+ss.getLocalAddress().getHostAddress()
|
Log.i(getClass().getName(),"ViaProxy: "+ss.getLocalAddress().getHostAddress()
|
||||||
+":"+ss.getLocalPort());
|
+":"+ss.getLocalPort());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,11 +92,11 @@ public class SocksClient implements Runnable {
|
||||||
port = Integer.parseInt(args[1]);
|
port = Integer.parseInt(args[1]);
|
||||||
|
|
||||||
proxyPort =(args.length > 3)? Integer.parseInt(args[3])
|
proxyPort =(args.length > 3)? Integer.parseInt(args[3])
|
||||||
: TorConstants.PORT_SOCKS;
|
: 9050;
|
||||||
|
|
||||||
host = args[0];
|
host = args[0];
|
||||||
proxyHost =(args.length > 2)? args[2]
|
proxyHost =(args.length > 2)? args[2]
|
||||||
: TorConstants.IP_LOCALHOST;
|
: IP_LOCALHOST;
|
||||||
|
|
||||||
Proxy.setDefaultProxy(proxyHost,proxyPort,"KOUKY001");
|
Proxy.setDefaultProxy(proxyHost,proxyPort,"KOUKY001");
|
||||||
//Proxy.setDefaultProxy(proxyHost,proxyPort);
|
//Proxy.setDefaultProxy(proxyHost,proxyPort);
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.torproject.android.service;
|
||||||
|
|
||||||
|
import org.torproject.android.service.ITorServiceCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an interface for calling on to a remote service
|
||||||
|
*/
|
||||||
|
interface ITorService {
|
||||||
|
/**
|
||||||
|
* Often you want to allow a service to call back to its clients.
|
||||||
|
* This shows how to do so, by registering a callback interface with
|
||||||
|
* the service.
|
||||||
|
*/
|
||||||
|
void registerCallback(ITorServiceCallback cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a previously registered callback interface.
|
||||||
|
*/
|
||||||
|
void unregisterCallback(ITorServiceCallback cb);
|
||||||
|
|
||||||
|
int getStatus();
|
||||||
|
|
||||||
|
void setProfile(int profile);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.torproject.android.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface used to send
|
||||||
|
* synchronous notifications back to its clients. Note that this is a
|
||||||
|
* one-way interface so the server does not block waiting for the client.
|
||||||
|
*/
|
||||||
|
oneway interface ITorServiceCallback {
|
||||||
|
/**
|
||||||
|
* Called when the service has a new value for you.
|
||||||
|
*/
|
||||||
|
void statusChanged(String value);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/* Copyright (c) 2009, Nathan Freitas, The Guardian Project - http://openideals.com/guardian */
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
/* See LICENSE for licensing information */
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
package org.torproject.android;
|
package org.torproject.android.service;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
@ -14,9 +14,7 @@ import java.util.zip.ZipFile;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class TorBinaryInstaller implements TorConstants {
|
public class TorBinaryInstaller implements TorServiceConstants {
|
||||||
|
|
||||||
private final static String LOG_TAG = "Tor";
|
|
||||||
|
|
||||||
|
|
||||||
public TorBinaryInstaller ()
|
public TorBinaryInstaller ()
|
||||||
|
@ -28,11 +26,13 @@ public class TorBinaryInstaller implements TorConstants {
|
||||||
*/
|
*/
|
||||||
public void start (boolean force)
|
public void start (boolean force)
|
||||||
{
|
{
|
||||||
boolean binaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
|
boolean torBinaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
|
||||||
|
Log.i(TAG,"Tor binary exists=" + torBinaryExists);
|
||||||
|
|
||||||
Log.i(LOG_TAG,"Tor binary exists=" + binaryExists);
|
boolean privoxyBinaryExists = new File(PRIVOXY_INSTALL_PATH).exists();
|
||||||
|
Log.i(TAG,"Privoxy binary exists=" + privoxyBinaryExists);
|
||||||
|
|
||||||
if (!binaryExists || force)
|
if (!(torBinaryExists && privoxyBinaryExists) || force)
|
||||||
installFromZip ();
|
installFromZip ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,21 @@ public class TorBinaryInstaller implements TorConstants {
|
||||||
zipen = zip.getEntry(TORRC_ZIP_KEY);
|
zipen = zip.getEntry(TORRC_ZIP_KEY);
|
||||||
streamToFile(zip.getInputStream(zipen),TORRC_INSTALL_PATH);
|
streamToFile(zip.getInputStream(zipen),TORRC_INSTALL_PATH);
|
||||||
|
|
||||||
|
zipen = zip.getEntry(PRIVOXY_ZIP_KEY);
|
||||||
|
streamToFile(zip.getInputStream(zipen),PRIVOXY_INSTALL_PATH);
|
||||||
|
|
||||||
|
zipen = zip.getEntry(PRIVOXYCONFIG_ZIP_KEY);
|
||||||
|
streamToFile(zip.getInputStream(zipen),PRIVOXYCONFIG_INSTALL_PATH);
|
||||||
|
|
||||||
|
|
||||||
zip.close();
|
zip.close();
|
||||||
|
|
||||||
Log.i(LOG_TAG,"SUCCESS: unzipped tor binary from apk");
|
Log.i(TAG,"SUCCESS: unzipped tor, privoxy binaries from apk");
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (IOException ioe)
|
catch (IOException ioe)
|
||||||
{
|
{
|
||||||
Log.i(LOG_TAG,"FAIL: unable to unzip tor binary from apk",ioe);
|
Log.i(TAG,"FAIL: unable to unzip binaries from apk",ioe);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +98,7 @@ public class TorBinaryInstaller implements TorConstants {
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Log.i(LOG_TAG,"Error opening output file " + targetFilename,e);
|
Log.i(TAG,"Error opening output file " + targetFilename,e);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +125,7 @@ public class TorBinaryInstaller implements TorConstants {
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Log.i(LOG_TAG,"Error writing output file '" + targetFilename + "': " + e.toString());
|
Log.i(TAG,"Error writing output file '" + targetFilename + "': " + e.toString());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -135,12 +142,15 @@ public class TorBinaryInstaller implements TorConstants {
|
||||||
DataOutputStream out = new DataOutputStream(new FileOutputStream(outputFile));
|
DataOutputStream out = new DataOutputStream(new FileOutputStream(outputFile));
|
||||||
DataInputStream in = new DataInputStream(is);
|
DataInputStream in = new DataInputStream(is);
|
||||||
|
|
||||||
int b;
|
int b = -1;
|
||||||
byte[] data = new byte[1024];
|
byte[] data = new byte[1024];
|
||||||
|
|
||||||
while ((b = in.read(data)) != -1) {
|
while ((b = in.read(data)) != -1) {
|
||||||
out.write(data);
|
out.write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (b == -1); //rejoice
|
||||||
|
|
||||||
//
|
//
|
||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
|
@ -150,7 +160,7 @@ public class TorBinaryInstaller implements TorConstants {
|
||||||
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
Log.e(LOG_TAG, "error copying binary", ex);
|
Log.e(TAG, "error copying binary", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
package org.torproject.android.service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains shared programming interfaces.
|
||||||
|
* All iptables "communication" is handled by this class.
|
||||||
|
*/
|
||||||
|
public final class TorRoot {
|
||||||
|
private final static String TAG = "TOR_ROOT";
|
||||||
|
|
||||||
|
// Do we have root access?
|
||||||
|
private static boolean hasroot = false;
|
||||||
|
|
||||||
|
private final static String CMD_NAT_FLUSH = "iptables -t nat -F || exit\n";
|
||||||
|
private final static String CMD_NAT_IPTABLES_80 = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to 127.0.0.1:8118 || exit\n";
|
||||||
|
private final static String CMD_DNS_PROXYING = "iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to 127.0.0.1:5400 || exit\n";
|
||||||
|
|
||||||
|
public static boolean enableDNSProxying ()
|
||||||
|
{
|
||||||
|
|
||||||
|
final StringBuilder script = new StringBuilder();
|
||||||
|
int code;
|
||||||
|
|
||||||
|
//Enable UDP Proxying
|
||||||
|
script.append(CMD_DNS_PROXYING);
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
code = runScriptAsRoot(script.toString(), res);
|
||||||
|
|
||||||
|
if (code != 0)
|
||||||
|
{
|
||||||
|
Log.w(TAG, "error apply DNS proxying: " + res.toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG, "error apply DNS proxying: " + res.toString(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge and re-add all rules (internal implementation).
|
||||||
|
* @param ctx application context (mandatory)
|
||||||
|
* @param uids list of selected uids to allow or disallow (depending on the working mode)
|
||||||
|
* @param showErrors indicates if errors should be alerted
|
||||||
|
*/
|
||||||
|
public static boolean enabledWebProxying() {
|
||||||
|
|
||||||
|
final StringBuilder script = new StringBuilder();
|
||||||
|
try {
|
||||||
|
int code;
|
||||||
|
|
||||||
|
script.append(CMD_NAT_IPTABLES_80);
|
||||||
|
|
||||||
|
/*
|
||||||
|
int uid = android.os.Process.getUidForName("dhcp");
|
||||||
|
if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit\n");
|
||||||
|
uid = android.os.Process.getUidForName("wifi");
|
||||||
|
if (uid != -1) script.append("iptables -A OUTPUT " + itfFilter + " -m owner --uid-owner " + uid + " -j ACCEPT || exit\n");
|
||||||
|
*/
|
||||||
|
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
|
code = runScriptAsRoot(script.toString(), res);
|
||||||
|
|
||||||
|
String msg = res.toString();
|
||||||
|
Log.e(TAG, msg);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG, "error refreshing iptables: " + e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge all iptables rules.
|
||||||
|
* @return true if the rules were purged
|
||||||
|
*/
|
||||||
|
public static boolean purgeNatIptables() {
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
|
try {
|
||||||
|
int code = runScriptAsRoot(CMD_NAT_FLUSH, res);
|
||||||
|
if (code != 0) {
|
||||||
|
Log.w(TAG, "error purging iptables. exit code: " + code + "\n" + res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.w(TAG,"error purging iptables: " + e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we have root access
|
||||||
|
* @return boolean true if we have root
|
||||||
|
*/
|
||||||
|
public static boolean hasRootAccess() {
|
||||||
|
if (hasroot) return true;
|
||||||
|
try {
|
||||||
|
// Run an empty script just to check root access
|
||||||
|
if (runScriptAsRoot("exit 0", null, 20000) == 0) {
|
||||||
|
hasroot = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
Log.w(TAG, "Could not acquire root access.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a script as root (multiple commands separated by "\n").
|
||||||
|
*
|
||||||
|
* @param script the script to be executed
|
||||||
|
* @param res the script output response (stdout + stderr)
|
||||||
|
* @param timeout timeout in milliseconds (-1 for none)
|
||||||
|
* @return the script exit code
|
||||||
|
*/
|
||||||
|
public static int runScriptAsRoot(String script, StringBuilder res, final long timeout) {
|
||||||
|
Log.i(TAG,"executing script: " + script);
|
||||||
|
final ScriptRunner runner = new ScriptRunner(script, res);
|
||||||
|
runner.start();
|
||||||
|
try {
|
||||||
|
if (timeout > 0) {
|
||||||
|
runner.join(timeout);
|
||||||
|
} else {
|
||||||
|
runner.join();
|
||||||
|
}
|
||||||
|
if (runner.isAlive()) {
|
||||||
|
// Timed-out
|
||||||
|
runner.interrupt();
|
||||||
|
runner.destroy();
|
||||||
|
runner.join(50);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ex) {}
|
||||||
|
return runner.exitcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a script as root (multiple commands separated by "\n") with a default timeout of 5 seconds.
|
||||||
|
*
|
||||||
|
* @param script the script to be executed
|
||||||
|
* @param res the script output response (stdout + stderr)
|
||||||
|
* @param timeout timeout in milliseconds (-1 for none)
|
||||||
|
* @return the script exit code
|
||||||
|
* @throws IOException on any error executing the script, or writing it to disk
|
||||||
|
*/
|
||||||
|
public static int runScriptAsRoot(String script, StringBuilder res) throws IOException {
|
||||||
|
return runScriptAsRoot(script, res, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal thread used to execute scripts as root.
|
||||||
|
*/
|
||||||
|
private static final class ScriptRunner extends Thread {
|
||||||
|
private final String script;
|
||||||
|
private final StringBuilder res;
|
||||||
|
public int exitcode = -1;
|
||||||
|
private Process exec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new script runner.
|
||||||
|
* @param script script to run
|
||||||
|
* @param res response output
|
||||||
|
*/
|
||||||
|
public ScriptRunner(String script, StringBuilder res) {
|
||||||
|
this.script = script;
|
||||||
|
this.res = res;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
// Create the "su" request to run the command
|
||||||
|
// note that this will create a shell that we must interact to (using stdin/stdout)
|
||||||
|
exec = Runtime.getRuntime().exec("su");
|
||||||
|
final OutputStreamWriter out = new OutputStreamWriter(exec.getOutputStream());
|
||||||
|
// Write the script to be executed
|
||||||
|
out.write(script);
|
||||||
|
// Ensure that the last character is an "enter"
|
||||||
|
if (!script.endsWith("\n")) out.write("\n");
|
||||||
|
out.flush();
|
||||||
|
// Terminate the "su" process
|
||||||
|
out.write("exit\n");
|
||||||
|
out.flush();
|
||||||
|
final char buf[] = new char[1024];
|
||||||
|
// Consume the "stdout"
|
||||||
|
InputStreamReader r = new InputStreamReader(exec.getInputStream());
|
||||||
|
int read=0;
|
||||||
|
while ((read=r.read(buf)) != -1) {
|
||||||
|
if (res != null) res.append(buf, 0, read);
|
||||||
|
}
|
||||||
|
// Consume the "stderr"
|
||||||
|
r = new InputStreamReader(exec.getErrorStream());
|
||||||
|
read=0;
|
||||||
|
while ((read=r.read(buf)) != -1) {
|
||||||
|
if (res != null) res.append(buf, 0, read);
|
||||||
|
}
|
||||||
|
// get the process exit code
|
||||||
|
if (exec != null) this.exitcode = exec.waitFor();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
if (res != null) res.append("\nOperation timed-out");
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (res != null) res.append("\n" + ex);
|
||||||
|
} finally {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Destroy this script runner
|
||||||
|
*/
|
||||||
|
public synchronized void destroy() {
|
||||||
|
if (exec != null) exec.destroy();
|
||||||
|
exec = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,721 @@
|
||||||
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
package org.torproject.android.service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.freehaven.tor.control.ConfigEntry;
|
||||||
|
import net.freehaven.tor.control.EventHandler;
|
||||||
|
import net.freehaven.tor.control.TorControlConnection;
|
||||||
|
|
||||||
|
import org.torproject.android.Orbot;
|
||||||
|
import org.torproject.android.R;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteCallbackList;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class TorService extends Service implements TorServiceConstants, Runnable, EventHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static int currentStatus = STATUS_REQUIRES_DEMAND;
|
||||||
|
|
||||||
|
private TorControlConnection conn = null;
|
||||||
|
|
||||||
|
private static TorService _torInstance;
|
||||||
|
|
||||||
|
private static final int NOTIFY_ID = 1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Called when the activity is first created. */
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
Log.i(TAG,"TorService: onCreate");
|
||||||
|
|
||||||
|
checkTorBinaries();
|
||||||
|
|
||||||
|
findExistingProc ();
|
||||||
|
|
||||||
|
_torInstance = this;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean findExistingProc ()
|
||||||
|
{
|
||||||
|
int procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
|
||||||
|
|
||||||
|
if (procId != -1)
|
||||||
|
{
|
||||||
|
Log.i(TAG,"Found existing Tor process");
|
||||||
|
|
||||||
|
sendCallbackMessage ("found existing Tor process...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
currentStatus = STATUS_CONNECTING;
|
||||||
|
|
||||||
|
initControlConnection();
|
||||||
|
|
||||||
|
|
||||||
|
currentStatus = STATUS_ON;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
||||||
|
currentStatus = STATUS_REQUIRES_DEMAND;
|
||||||
|
this.stopTor();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.i(TAG,"Unable to connect to existing Tor instance,",e);
|
||||||
|
currentStatus = STATUS_REQUIRES_DEMAND;
|
||||||
|
this.stopTor();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Service#onLowMemory()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onLowMemory() {
|
||||||
|
super.onLowMemory();
|
||||||
|
|
||||||
|
Log.i(TAG, "Low Memory Called");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Service#onUnbind(android.content.Intent)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onUnbind(Intent intent) {
|
||||||
|
|
||||||
|
Log.i(TAG, "onUnbind Called: " + intent.getAction());
|
||||||
|
|
||||||
|
return super.onUnbind(intent);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTorStatus ()
|
||||||
|
{
|
||||||
|
|
||||||
|
return currentStatus;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void showToolbarNotification (String title, String notifyMsg, int icon)
|
||||||
|
{
|
||||||
|
|
||||||
|
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
|
|
||||||
|
CharSequence tickerText = title;
|
||||||
|
long when = System.currentTimeMillis();
|
||||||
|
|
||||||
|
Notification notification = new Notification(icon, tickerText, when);
|
||||||
|
|
||||||
|
Context context = getApplicationContext();
|
||||||
|
CharSequence contentTitle = title;
|
||||||
|
CharSequence contentText = notifyMsg;
|
||||||
|
|
||||||
|
Intent notificationIntent = new Intent(this, Orbot.class);
|
||||||
|
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
|
||||||
|
|
||||||
|
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
|
||||||
|
|
||||||
|
|
||||||
|
mNotificationManager.notify(NOTIFY_ID, notification);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Service#onRebind(android.content.Intent)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onRebind(Intent intent) {
|
||||||
|
super.onRebind(intent);
|
||||||
|
|
||||||
|
Log.i(TAG,"on rebind");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see android.app.Service#onStart(android.content.Intent, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onStart(Intent intent, int startId) {
|
||||||
|
super.onStart(intent, startId);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (currentStatus == STATUS_ON && conn != null && webProxy != null)
|
||||||
|
{
|
||||||
|
//we are good to go
|
||||||
|
Log.i(TAG,"onStart: Tor is running");
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.i(TAG,"onStart: Starting up Tor");
|
||||||
|
|
||||||
|
new Thread(this).start();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run ()
|
||||||
|
{
|
||||||
|
boolean isRunning = _torInstance.findExistingProc ();
|
||||||
|
|
||||||
|
if (!isRunning)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
initTor();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
currentStatus = STATUS_REQUIRES_DEMAND;
|
||||||
|
this.showToolbarNotification("Orbot", "Unable to start Tor", R.drawable.tornotification);
|
||||||
|
Log.i(TAG,"Unable to start Tor: " + e.getMessage(),e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void onDestroy ()
|
||||||
|
{
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
// Unregister all callbacks.
|
||||||
|
mCallbacks.kill();
|
||||||
|
|
||||||
|
|
||||||
|
Log.i(TAG,"onDestroy called");
|
||||||
|
|
||||||
|
stopTor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopTor ()
|
||||||
|
{
|
||||||
|
currentStatus = STATUS_UNAVAILABLE;
|
||||||
|
|
||||||
|
|
||||||
|
sendCallbackMessage("Web proxy shutdown");
|
||||||
|
|
||||||
|
killTorProcess ();
|
||||||
|
|
||||||
|
currentStatus = STATUS_REQUIRES_DEMAND;
|
||||||
|
|
||||||
|
showToolbarNotification ("Orbot","Anonymous browsing is disabled",R.drawable.tornotificationoff);
|
||||||
|
sendCallbackMessage("Anonymous browsing is disabled");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void reloadConfig ()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (conn == null)
|
||||||
|
{
|
||||||
|
initControlConnection ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != null)
|
||||||
|
{
|
||||||
|
conn.signal("RELOAD");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.i(TAG,"Unable to reload configuration",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void killTorProcess ()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (conn != null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Log.i(TAG,"sending SHUTDOWN signal");
|
||||||
|
conn.signal("SHUTDOWN");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.i(TAG,"error shutting down Tor via connection",e);
|
||||||
|
}
|
||||||
|
conn = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
|
||||||
|
|
||||||
|
while (procId != -1)
|
||||||
|
{
|
||||||
|
|
||||||
|
Log.i(TAG,"Found Tor PID=" + procId + " - killing now...");
|
||||||
|
|
||||||
|
TorServiceUtils.doCommand(SHELL_CMD_KILL, procId + "");
|
||||||
|
|
||||||
|
procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
procId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
|
||||||
|
|
||||||
|
while (procId != -1)
|
||||||
|
{
|
||||||
|
|
||||||
|
Log.i(TAG,"Found Privoxy PID=" + procId + " - killing now...");
|
||||||
|
|
||||||
|
TorServiceUtils.doCommand(SHELL_CMD_KILL, procId + "");
|
||||||
|
|
||||||
|
procId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logNotice (String msg)
|
||||||
|
{
|
||||||
|
|
||||||
|
Log.i(TAG, msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkTorBinaries ()
|
||||||
|
{
|
||||||
|
|
||||||
|
boolean torBinaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
|
||||||
|
boolean privoxyBinaryExists = new File(PRIVOXY_INSTALL_PATH).exists();
|
||||||
|
|
||||||
|
if (!(torBinaryExists && privoxyBinaryExists))
|
||||||
|
{
|
||||||
|
killTorProcess ();
|
||||||
|
|
||||||
|
TorBinaryInstaller installer = new TorBinaryInstaller();
|
||||||
|
installer.start(true);
|
||||||
|
|
||||||
|
torBinaryExists = new File(TOR_BINARY_INSTALL_PATH).exists();
|
||||||
|
privoxyBinaryExists = new File(PRIVOXY_INSTALL_PATH).exists();
|
||||||
|
|
||||||
|
if (torBinaryExists && privoxyBinaryExists)
|
||||||
|
{
|
||||||
|
logNotice("Tor, Privoxy, IPtables binaries installed!");
|
||||||
|
|
||||||
|
this.showToolbarNotification("Orbot Installed!", "The Tor binary was successfully extracted and installed", R.drawable.tornotification);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logNotice("Binary install FAILED!");
|
||||||
|
|
||||||
|
this.showToolbarNotification("Orbot FAIL!", "The binaries were unable to be installed", R.drawable.tornotification);
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Log.i(TAG,"Setting permission on Tor binary");
|
||||||
|
TorServiceUtils.doCommand(SHELL_CMD_CHMOD, CHMOD_EXE_VALUE + ' ' + TOR_BINARY_INSTALL_PATH);
|
||||||
|
|
||||||
|
Log.i(TAG,"Setting permission on Privoxy binary");
|
||||||
|
TorServiceUtils.doCommand(SHELL_CMD_CHMOD, CHMOD_EXE_VALUE + ' ' + PRIVOXY_INSTALL_PATH);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initTor () throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
currentStatus = STATUS_CONNECTING;
|
||||||
|
|
||||||
|
logNotice("Tor is starting up...");
|
||||||
|
this.sendCallbackMessage("starting...");
|
||||||
|
|
||||||
|
killTorProcess ();
|
||||||
|
|
||||||
|
checkTorBinaries ();
|
||||||
|
|
||||||
|
|
||||||
|
Log.i(TAG,"Starting tor process");
|
||||||
|
|
||||||
|
TorServiceUtils.doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
|
||||||
|
|
||||||
|
int procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
|
||||||
|
|
||||||
|
while (procId == -1)
|
||||||
|
{
|
||||||
|
TorServiceUtils.doCommand(TOR_BINARY_INSTALL_PATH, TOR_COMMAND_LINE_ARGS);
|
||||||
|
procId = TorServiceUtils.findProcessId(TorServiceConstants.TOR_BINARY_INSTALL_PATH);
|
||||||
|
|
||||||
|
if (procId == -1)
|
||||||
|
{
|
||||||
|
this.sendCallbackMessage("Couldn't start Tor process... retrying...");
|
||||||
|
Thread.sleep(3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG,"Tor process id=" + procId);
|
||||||
|
|
||||||
|
showToolbarNotification("Orbot starting...", "Orbot is starting up", R.drawable.tornotification);
|
||||||
|
|
||||||
|
initControlConnection ();
|
||||||
|
|
||||||
|
int privoxyProcId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
|
||||||
|
|
||||||
|
while (privoxyProcId == -1)
|
||||||
|
{
|
||||||
|
TorServiceUtils.doCommand(PRIVOXY_INSTALL_PATH, PRIVOXY_COMMAND_LINE_ARGS);
|
||||||
|
privoxyProcId = TorServiceUtils.findProcessId(TorServiceConstants.PRIVOXY_INSTALL_PATH);
|
||||||
|
|
||||||
|
if (privoxyProcId == -1)
|
||||||
|
{
|
||||||
|
this.sendCallbackMessage("Couldn't start Privoxy process... retrying...");
|
||||||
|
Thread.sleep(3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG,"Privoxy process id=" + privoxyProcId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public String generateHashPassword ()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
PasswordDigest d = PasswordDigest.generateDigest();
|
||||||
|
byte[] s = d.getSecret(); // pass this to authenticate
|
||||||
|
String h = d.getHashedPassword(); // pass this to the Tor on startup.
|
||||||
|
*/
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initControlConnection () throws Exception, RuntimeException
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.i(TAG,"Connecting to control port: " + TOR_CONTROL_PORT);
|
||||||
|
|
||||||
|
String baseMessage = getString(R.string.tor_process_connecting);
|
||||||
|
sendCallbackMessage(baseMessage);
|
||||||
|
|
||||||
|
Socket s = new Socket(IP_LOCALHOST, TOR_CONTROL_PORT);
|
||||||
|
conn = TorControlConnection.getConnection(s);
|
||||||
|
// conn.authenticate(new byte[0]); // See section 3.2
|
||||||
|
|
||||||
|
sendCallbackMessage(baseMessage + ' ' + getString(R.string.tor_process_connecting_step2));
|
||||||
|
|
||||||
|
Log.i(TAG,"SUCCESS connected to control port");
|
||||||
|
|
||||||
|
File fileCookie = new File(TOR_CONTROL_AUTH_COOKIE);
|
||||||
|
byte[] cookie = new byte[(int)fileCookie.length()];
|
||||||
|
new FileInputStream(new File(TOR_CONTROL_AUTH_COOKIE)).read(cookie);
|
||||||
|
conn.authenticate(cookie);
|
||||||
|
|
||||||
|
Log.i(TAG,"SUCCESS authenticated to control port");
|
||||||
|
|
||||||
|
sendCallbackMessage(baseMessage + ' ' + getString(R.string.tor_process_connecting_step3));
|
||||||
|
|
||||||
|
addEventHandler();
|
||||||
|
|
||||||
|
break; //don't need to retry
|
||||||
|
}
|
||||||
|
catch (Exception ce)
|
||||||
|
{
|
||||||
|
conn = null;
|
||||||
|
Log.i(TAG,"Attempt: Error connecting to control port: " + ce.getLocalizedMessage(),ce);
|
||||||
|
|
||||||
|
sendCallbackMessage(getString(R.string.tor_process_connecting_step4));
|
||||||
|
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void modifyConf () throws IOException
|
||||||
|
{
|
||||||
|
// Get one configuration variable.
|
||||||
|
List<ConfigEntry> options = conn.getConf("contact");
|
||||||
|
options.size();
|
||||||
|
// Get a set of configuration variables.
|
||||||
|
// List options = conn.getConf(Arrays.asList(new String[]{
|
||||||
|
// "contact", "orport", "socksport"}));
|
||||||
|
// Change a single configuration variable
|
||||||
|
conn.setConf("BandwidthRate", "1 MB");
|
||||||
|
// Change several configuration variables
|
||||||
|
conn.setConf(Arrays.asList(new String[]{
|
||||||
|
"HiddenServiceDir /home/tor/service1",
|
||||||
|
"HiddenServicePort 80",
|
||||||
|
}));
|
||||||
|
// Reset some variables to their defaults
|
||||||
|
conn.resetConf(Arrays.asList(new String[]{
|
||||||
|
"contact", "socksport"
|
||||||
|
}));
|
||||||
|
// Flush the configuration to disk.
|
||||||
|
conn.saveConf();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private void getTorStatus () throws IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
if (conn != null)
|
||||||
|
{
|
||||||
|
// get a single value.
|
||||||
|
|
||||||
|
// get several values
|
||||||
|
|
||||||
|
if (currentStatus == STATUS_CONNECTING)
|
||||||
|
{
|
||||||
|
//Map vals = conn.getInfo(Arrays.asList(new String[]{
|
||||||
|
// "status/bootstrap-phase", "status","version"}));
|
||||||
|
|
||||||
|
String bsPhase = conn.getInfo("status/bootstrap-phase");
|
||||||
|
Log.i(TAG, "bootstrap-phase: " + bsPhase);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// String status = conn.getInfo("status/circuit-established");
|
||||||
|
// Log.i(TAG, "status/circuit-established=" + status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.i(TAG, "Unable to get Tor status from control port");
|
||||||
|
currentStatus = STATUS_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
public void addEventHandler () throws IOException
|
||||||
|
{
|
||||||
|
// We extend NullEventHandler so that we don't need to provide empty
|
||||||
|
// implementations for all the events we don't care about.
|
||||||
|
// ...
|
||||||
|
Log.i(TAG,"adding control port event handler");
|
||||||
|
|
||||||
|
conn.setEventHandler(this);
|
||||||
|
|
||||||
|
conn.setEvents(Arrays.asList(new String[]{
|
||||||
|
"ORCONN", "CIRC", "NOTICE", "ERR"}));
|
||||||
|
// conn.setEvents(Arrays.asList(new String[]{
|
||||||
|
// "DEBUG", "INFO", "NOTICE", "WARN", "ERR"}));
|
||||||
|
|
||||||
|
Log.i(TAG,"SUCCESS added control port event handler");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the port number that the HTTP proxy is running on
|
||||||
|
*/
|
||||||
|
public int getHTTPPort() throws RemoteException {
|
||||||
|
return TorServiceConstants.PORT_HTTP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the port number that the SOCKS proxy is running on
|
||||||
|
*/
|
||||||
|
public int getSOCKSPort() throws RemoteException {
|
||||||
|
return TorServiceConstants.PORT_SOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public int getProfile() throws RemoteException {
|
||||||
|
//return mProfile;
|
||||||
|
return PROFILE_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTorProfile(int profile) {
|
||||||
|
|
||||||
|
if (profile == PROFILE_ON)
|
||||||
|
{
|
||||||
|
currentStatus = STATUS_CONNECTING;
|
||||||
|
sendCallbackMessage ("starting...");
|
||||||
|
|
||||||
|
new Thread(_torInstance).start();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentStatus = STATUS_UNAVAILABLE;
|
||||||
|
sendCallbackMessage ("shutting down...");
|
||||||
|
|
||||||
|
_torInstance.stopTor();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void message(String severity, String msg) {
|
||||||
|
|
||||||
|
Log.i(TAG, "[Tor Control Port] " + severity + ": " + msg);
|
||||||
|
|
||||||
|
if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1)
|
||||||
|
{
|
||||||
|
currentStatus = STATUS_ON;
|
||||||
|
showToolbarNotification ("Orbot","Anonymous browsing is enabled",R.drawable.tornotification);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showToolbarNotification("Orbot", msg, R.drawable.tornotification);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCallbackMessage (msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void newDescriptors(List<String> orList) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void orConnStatus(String status, String orName) {
|
||||||
|
|
||||||
|
Log.i(TAG,"OrConnStatus=" + status + ": " + orName);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void streamStatus(String status, String streamID, String target) {
|
||||||
|
Log.i(TAG,"StreamStatus=" + status + ": " + streamID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unrecognized(String type, String msg) {
|
||||||
|
Log.i(TAG,"unrecognized log=" + type + ": " + msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bandwidthUsed(long read, long written) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void circuitStatus(String status, String circID, String path) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
// Select the interface to return. If your service only implements
|
||||||
|
// a single interface, you can just return it here without checking
|
||||||
|
// the Intent.
|
||||||
|
if (ITorService.class.getName().equals(intent.getAction())) {
|
||||||
|
return mBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a list of callbacks that have been registered with the
|
||||||
|
* service. Note that this is package scoped (instead of private) so
|
||||||
|
* that it can be accessed more efficiently from inner classes.
|
||||||
|
*/
|
||||||
|
final RemoteCallbackList<ITorServiceCallback> mCallbacks
|
||||||
|
= new RemoteCallbackList<ITorServiceCallback>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IRemoteInterface is defined through IDL
|
||||||
|
*/
|
||||||
|
private final ITorService.Stub mBinder = new ITorService.Stub() {
|
||||||
|
public void registerCallback(ITorServiceCallback cb) {
|
||||||
|
if (cb != null) mCallbacks.register(cb);
|
||||||
|
}
|
||||||
|
public void unregisterCallback(ITorServiceCallback cb) {
|
||||||
|
if (cb != null) mCallbacks.unregister(cb);
|
||||||
|
}
|
||||||
|
public int getStatus () {
|
||||||
|
return getTorStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfile (int profile)
|
||||||
|
{
|
||||||
|
setTorProfile(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private void sendCallbackMessage (String status)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Broadcast to all clients the new value.
|
||||||
|
final int N = mCallbacks.beginBroadcast();
|
||||||
|
for (int i=0; i<N; i++) {
|
||||||
|
try {
|
||||||
|
mCallbacks.getBroadcastItem(i).statusChanged(status);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// The RemoteCallbackList will take care of removing
|
||||||
|
// the dead object for us.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCallbacks.finishBroadcast();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
package org.torproject.android.service;
|
||||||
|
|
||||||
|
public interface TorServiceConstants {
|
||||||
|
|
||||||
|
public final static String TAG = "TOR_SERVICE";
|
||||||
|
|
||||||
|
//home directory of Android application
|
||||||
|
public final static String TOR_HOME = "/data/data/org.torproject.android/";
|
||||||
|
|
||||||
|
//name of the tor C binary
|
||||||
|
public final static String TOR_BINARY_ASSET_KEY = "tor";
|
||||||
|
public final static String TOR_BINARY_INSTALL_PATH = TOR_HOME + TOR_BINARY_ASSET_KEY; //path to install the Tor binary too
|
||||||
|
public final static String TOR_BINARY_ZIP_KEY = "assets/" + TOR_BINARY_ASSET_KEY;//key of the tor binary in the Zip file
|
||||||
|
|
||||||
|
//torrc (tor config file)
|
||||||
|
public final static String TORRC_ASSET_KEY = "torrc";
|
||||||
|
public final static String TORRC_INSTALL_PATH = TOR_HOME + TORRC_ASSET_KEY; //path to install torrc to within the android app data folder
|
||||||
|
public final static String TORRC_ZIP_KEY = "assets/" + TORRC_ASSET_KEY; //key of the torrc file in the Zip file
|
||||||
|
//how to launch tor
|
||||||
|
public final static String TOR_COMMAND_LINE_ARGS = "-f " + TORRC_INSTALL_PATH;
|
||||||
|
|
||||||
|
//privoxy
|
||||||
|
public final static String PRIVOXY_ASSET_KEY = "privoxy";
|
||||||
|
public final static String PRIVOXY_INSTALL_PATH = TOR_HOME + PRIVOXY_ASSET_KEY; //path to install privoxy to within the android app data folder
|
||||||
|
public final static String PRIVOXY_ZIP_KEY = "assets/" + PRIVOXY_ASSET_KEY; //key of the privoxy file in the Zip file
|
||||||
|
|
||||||
|
//privoxy.config
|
||||||
|
public final static String PRIVOXYCONFIG_ASSET_KEY = "privoxy.config";
|
||||||
|
public final static String PRIVOXYCONFIG_INSTALL_PATH = TOR_HOME + PRIVOXYCONFIG_ASSET_KEY; //path to install privoxy to within the android app data folder
|
||||||
|
public final static String PRIVOXYCONFIG_ZIP_KEY = "assets/" + PRIVOXYCONFIG_ASSET_KEY; //key of the privoxy file in the Zip file
|
||||||
|
|
||||||
|
//how to launch privoxy
|
||||||
|
public final static String PRIVOXY_COMMAND_LINE_ARGS = ' ' + PRIVOXYCONFIG_INSTALL_PATH;
|
||||||
|
|
||||||
|
//where to send the notices log
|
||||||
|
public final static String TOR_LOG_PATH = TOR_HOME + "notices.log";
|
||||||
|
|
||||||
|
//control port cookie path
|
||||||
|
public final static String TOR_CONTROL_AUTH_COOKIE = TOR_HOME + "data/control_auth_cookie";
|
||||||
|
|
||||||
|
|
||||||
|
//various console cmds
|
||||||
|
public final static String SHELL_CMD_CHMOD = "chmod";
|
||||||
|
public final static String SHELL_CMD_KILL = "kill";
|
||||||
|
public final static String SHELL_CMD_RM = "rm";
|
||||||
|
public final static String SHELL_CMD_PS = "ps";
|
||||||
|
public final static String CHMOD_EXE_VALUE = "777";
|
||||||
|
|
||||||
|
//path of the installed APK file
|
||||||
|
public final static String APK_PATH = "/data/app/org.torproject.android.apk";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public final static int FILE_WRITE_BUFFER_SIZE = 2048;
|
||||||
|
|
||||||
|
//HTTP Proxy server port
|
||||||
|
public final static int PORT_HTTP = 8118; //just like Privoxy!
|
||||||
|
|
||||||
|
//Socks port client connects to, server is the Tor binary
|
||||||
|
public final static int PORT_SOCKS = 9050;
|
||||||
|
|
||||||
|
//what is says!
|
||||||
|
public final static String IP_LOCALHOST = "127.0.0.1";
|
||||||
|
public final static int TOR_CONTROL_PORT = 9051;
|
||||||
|
public final static int UPDATE_TIMEOUT = 1000;
|
||||||
|
|
||||||
|
//path to check Tor against
|
||||||
|
public final static String URL_TOR_CHECK = "http://check.torproject.org";
|
||||||
|
|
||||||
|
//IPTABLES
|
||||||
|
// public final static String CMD_IPTABLES_PREROUTING = "iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to 127.0.0.1:8118 || exit\n";
|
||||||
|
//public final static String CMD_IPTABLES_PREROUTING_FLUSH = "iptables -t nat -F || exit\n";
|
||||||
|
|
||||||
|
//control port
|
||||||
|
public final static String TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE = "Bootstrapped 100%";
|
||||||
|
|
||||||
|
public final static int STATUS_UNAVAILABLE = -1;
|
||||||
|
public final static int STATUS_REQUIRES_DEMAND = 0;
|
||||||
|
public final static int STATUS_ON = 1;
|
||||||
|
public final static int STATUS_CONNECTING = 2;
|
||||||
|
|
||||||
|
public final static int PROFILE_OFF = -1;
|
||||||
|
public final static int PROFILE_ONDEMAND = 0;
|
||||||
|
public final static int PROFILE_ON = 1;
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
package org.torproject.android.service;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class TorServiceUtils implements TorServiceConstants {
|
||||||
|
|
||||||
|
|
||||||
|
public static int findProcessId(String command)
|
||||||
|
{
|
||||||
|
int procId = -1;
|
||||||
|
|
||||||
|
Runtime r = Runtime.getRuntime();
|
||||||
|
|
||||||
|
Process procPs = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
procPs = r.exec(SHELL_CMD_PS);
|
||||||
|
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
|
||||||
|
String line = null;
|
||||||
|
|
||||||
|
while ((line = reader.readLine())!=null)
|
||||||
|
{
|
||||||
|
if (line.indexOf(command)!=-1)
|
||||||
|
{
|
||||||
|
|
||||||
|
StringTokenizer st = new StringTokenizer(line," ");
|
||||||
|
st.nextToken(); //proc owner
|
||||||
|
|
||||||
|
procId = Integer.parseInt(st.nextToken().trim());
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "error: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return procId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Process doCommand(String command, String arg1)
|
||||||
|
{
|
||||||
|
Log.i(TAG,"executing command: " + command + ' ' + arg1);
|
||||||
|
|
||||||
|
Runtime r = Runtime.getRuntime();
|
||||||
|
|
||||||
|
Process proc = null;
|
||||||
|
|
||||||
|
StringBuilder log = new StringBuilder();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
proc = r.exec(command + ' ' + arg1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
final char buf[] = new char[1024];
|
||||||
|
// Consume the "stdout"
|
||||||
|
InputStreamReader reader = new InputStreamReader(proc.getInputStream());
|
||||||
|
int read=0;
|
||||||
|
while ((read=reader.read(buf)) != -1) {
|
||||||
|
if (log != null) log.append(buf, 0, read);
|
||||||
|
}
|
||||||
|
// Consume the "stderr"
|
||||||
|
reader = new InputStreamReader(proc.getErrorStream());
|
||||||
|
read=0;
|
||||||
|
while ((read=reader.read(buf)) != -1) {
|
||||||
|
if (log != null) log.append(buf, 0, read);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
Log.i(TAG,"command process exit value: " + proc.exitValue());
|
||||||
|
Log.i(TAG, "shell cmd output: " + log.toString());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "error: " + e.getMessage());
|
||||||
|
Log.e(TAG, "shell cmd output: " + log.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return proc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasRoot ()
|
||||||
|
{
|
||||||
|
String[] cmds = {"exit 0"};
|
||||||
|
|
||||||
|
int code = doRootCommand(cmds,null);
|
||||||
|
|
||||||
|
return (code == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int doRootCommand(String[] cmds, StringBuilder log)
|
||||||
|
{
|
||||||
|
Log.i(TAG,"executing commands: " + cmds.length);
|
||||||
|
|
||||||
|
Runtime runtime = Runtime.getRuntime();
|
||||||
|
|
||||||
|
Process proc = null;
|
||||||
|
int exitCode = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
proc = runtime.exec(cmds[0]);
|
||||||
|
|
||||||
|
OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());
|
||||||
|
|
||||||
|
for (int i = 1; i < cmds.length; i++)
|
||||||
|
{
|
||||||
|
out.write(cmds[i]);
|
||||||
|
out.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
out.flush();
|
||||||
|
out.write("exit\n");
|
||||||
|
|
||||||
|
final char buf[] = new char[1024];
|
||||||
|
// Consume the "stdout"
|
||||||
|
InputStreamReader reader = new InputStreamReader(proc.getInputStream());
|
||||||
|
int read=0;
|
||||||
|
while ((read=reader.read(buf)) != -1) {
|
||||||
|
if (log != null) log.append(buf, 0, read);
|
||||||
|
}
|
||||||
|
// Consume the "stderr"
|
||||||
|
reader = new InputStreamReader(proc.getErrorStream());
|
||||||
|
read=0;
|
||||||
|
while ((read=reader.read(buf)) != -1) {
|
||||||
|
if (log != null) log.append(buf, 0, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
exitCode = proc.waitFor();
|
||||||
|
|
||||||
|
Log.i(TAG,"command process exit value: " + exitCode);
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error executing shell cmd: " + e.getMessage(),e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return exitCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|