diff --git a/Orbot/.classpath b/Orbot/.classpath
index 4db39efd..888751ae 100644
--- a/Orbot/.classpath
+++ b/Orbot/.classpath
@@ -3,7 +3,7 @@
-
+
diff --git a/Orbot/AndroidManifest.xml b/Orbot/AndroidManifest.xml
index 636ad29f..b47ccf21 100644
--- a/Orbot/AndroidManifest.xml
+++ b/Orbot/AndroidManifest.xml
@@ -1,26 +1,42 @@
-
-
+ android:versionName="011301.2" android:versionCode="2">
+
+
+
-
-
+
-
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Orbot/BUILD b/Orbot/BUILD
index 4c93a408..32054756 100644
--- a/Orbot/BUILD
+++ b/Orbot/BUILD
@@ -7,7 +7,8 @@ Please install the following prerequisites (instructions for each follows):
droid-wrapper: http://github.com/tmurakam/droid-wrapper
libevent source (1.4.12-stable from svn)
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 )
on Debian Lenny:
@@ -42,14 +43,27 @@ Install droid-wrapper:
sudo make install
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:
export DROID_ROOT=~/mydroid/
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:
cd ~/mydroid/external/libevent
@@ -62,7 +76,6 @@ Fetch and build libevent:
make
Copy over the libevent library:
-
cp .libs/libevent.a ~/mydroid/out/target/product/generic/obj/lib
Fetch and build Tor:
@@ -71,7 +84,7 @@ Fetch and build Tor:
export ZLIBDIR=`cd ~/mydroid/external/zlib && pwd`
cd ~/mydroid/external/tor
- git clone https://git.torproject.org/git/tor.git
+ git clone git://git.torproject.org/git/tor.git
cd tor/
./autogen.sh
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
cd ../Orbot/
+ cp ~/mydroid/external/privoxy/privoxy-3.0.12-stable/privoxy assets/privoxy
cp ~/mydroid/external/tor/tor/src/or/tor assets/tor
$APP_SDK/android update project --name Orbot --target 1 --path .
ant release
diff --git a/Orbot/CHANGELOG b/Orbot/CHANGELOG
index e9b3be25..b32721d7 100644
--- a/Orbot/CHANGELOG
+++ b/Orbot/CHANGELOG
@@ -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
- Update user interace layout and graphics
- Modified service launch, shutdown and handling
diff --git a/Orbot/LICENSE b/Orbot/LICENSE
index 884008cd..0c1a1a28 100644
--- a/Orbot/LICENSE
+++ b/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
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
- * 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
- * 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
- * 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
- * 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
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
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
- * 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
- * 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
diff --git a/Orbot/assets/help.html b/Orbot/assets/help.html
deleted file mode 100644
index 1a1382b4..00000000
--- a/Orbot/assets/help.html
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
- help.html
-
-
-
-
-
-
-
-
-
-
-
- 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.
-
How to surf anonymously
- Once you have Orbot running and connected to the Tor network, you can utilize the anonymous proxy service in multiple ways:
-
-
Set your Android APN Proxy (Settings -> Wireless Networks -> Mobile networks -> Access Point Names) to 127.0.0.1/8118
-
Tell your application to use Web Proxy: 127.0.0.1:8118
-
Download and use the 'Shadow' browser from the Android Market
-
- You can always visit http://check.torproject.org to ensure that you are properly connected to the Tor network.
-
Bridges and Other Settings
- 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.
-
Even More Information!
- If you'd like to learn more about the Tor Project, please visit http://torproject.org.
-
-
diff --git a/Orbot/assets/privoxy.config b/Orbot/assets/privoxy.config
new file mode 100644
index 00000000..525b58a6
--- /dev/null
+++ b/Orbot/assets/privoxy.config
@@ -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
\ No newline at end of file
diff --git a/Orbot/assets/torrc b/Orbot/assets/torrc
index b1af5560..09bb25ca 100644
--- a/Orbot/assets/torrc
+++ b/Orbot/assets/torrc
@@ -1,169 +1,16 @@
-## Configuration file for a typical Tor user
-## Last updated 16 July 2009 for Tor 0.2.2.1-alpha.
-## (May or may not work for much older or much newer versions of Tor.)
-##
-## Lines that begin with "## " try to explain what's going on. Lines
-## that begin with just "#" are disabled commands: you can enable them
-## 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.
+SocksPort 9050
+SocksListenAddress 127.0.0.1
+SafeSocks 1
+DNSPort 5400
+Log notice stdout
+Log debug syslog
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
-## 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
-
-############### This section is just for location-hidden services ###
-
-## Once you have configured a hidden service, you can look at the
-## contents of the file ".../hidden_service/hostname" for the address
-## to tell people.
-##
-## 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
-## You might also include your PGP or GPG fingerprint if you have one:
-#ContactInfo 1234D/FFFFFFFF Random Person
-
-## 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 *:*
-
+RelayBandwidthRate 20 KBytes
+RelayBandwidthBurst 20 KBytes
+UseBridges 0
+UpdateBridgesFromAuthority 1
+bridge 74.82.1.191:19030
+bridge 221.31.40.135:4430
+bridge 24.110.168.130:443
diff --git a/Orbot/default.properties b/Orbot/default.properties
index 62bef18a..08ad68f1 100644
--- a/Orbot/default.properties
+++ b/Orbot/default.properties
@@ -7,8 +7,8 @@
# "build.properties", and override values to adapt the script to your
# project structure.
-apk-configurations=
-# Project target.
-target=android-4
# Indicates whether an apk should be generated for each density.
split.density=false
+# Project target.
+target=android-4
+apk-configurations=
diff --git a/Orbot/res/drawable/bgdarkdroid.jpg b/Orbot/res/drawable/bgdarkdroid.jpg
deleted file mode 100644
index 6c0570ad..00000000
Binary files a/Orbot/res/drawable/bgdarkdroid.jpg and /dev/null differ
diff --git a/Orbot/res/drawable/icon.png b/Orbot/res/drawable/icon.png
index 8fb58d4b..f98e3b76 100644
Binary files a/Orbot/res/drawable/icon.png and b/Orbot/res/drawable/icon.png differ
diff --git a/Orbot/res/drawable/toroff.png b/Orbot/res/drawable/toroff.png
index 466eb615..7e2602b7 100644
Binary files a/Orbot/res/drawable/toroff.png and b/Orbot/res/drawable/toroff.png differ
diff --git a/Orbot/res/drawable/toron.png b/Orbot/res/drawable/toron.png
index fee8023e..5a8bd362 100644
Binary files a/Orbot/res/drawable/toron.png and b/Orbot/res/drawable/toron.png differ
diff --git a/Orbot/res/drawable/torstarting.png b/Orbot/res/drawable/torstarting.png
index f4d36cdd..e0bca5da 100644
Binary files a/Orbot/res/drawable/torstarting.png and b/Orbot/res/drawable/torstarting.png differ
diff --git a/Orbot/res/layout/layout_about.xml b/Orbot/res/layout/layout_about.xml
new file mode 100644
index 00000000..e390bbb3
--- /dev/null
+++ b/Orbot/res/layout/layout_about.xml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Orbot/res/layout/layout_help.xml b/Orbot/res/layout/layout_help.xml
new file mode 100644
index 00000000..5084903d
--- /dev/null
+++ b/Orbot/res/layout/layout_help.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Orbot/res/layout/layout_log.xml b/Orbot/res/layout/layout_log.xml
index adadbdce..677f9acf 100644
--- a/Orbot/res/layout/layout_log.xml
+++ b/Orbot/res/layout/layout_log.xml
@@ -1,27 +1,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Orbot/res/layout/layout_main.xml b/Orbot/res/layout/layout_main.xml
index 7fd25ece..b79e922d 100644
--- a/Orbot/res/layout/layout_main.xml
+++ b/Orbot/res/layout/layout_main.xml
@@ -3,13 +3,40 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="@drawable/bgdarkdroid">
+ android:background="@drawable/background">
+
+
+
+
+
-
@@ -19,30 +46,28 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content">
-
-
+ android:id="@+id/imgStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/toroff"/>
+ android:textColor="#ffffff"
+ />
-
+
diff --git a/Orbot/res/layout/layout_web.xml b/Orbot/res/layout/layout_web.xml
deleted file mode 100644
index 4773d1b3..00000000
--- a/Orbot/res/layout/layout_web.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/Orbot/res/values/strings.xml b/Orbot/res/values/strings.xml
index 8c2303e9..eab22c2b 100644
--- a/Orbot/res/values/strings.xml
+++ b/Orbot/res/values/strings.xml
@@ -1,6 +1,45 @@
- ORbot
- 0.0.2a
+ Orbot
+ 0.0.3a
+ http://orbot/
+ http://check.torproject.org
+ start and stop the anonymous data connection
+ torproxyservice
+
+Starting up...
+"Orbot is Activated\n<< TOUCH TO DISCONNECT >>
+"Orbot is Disabled\n<< TOUCH TO START >>
+Orbot is shutting down
+
+Starting Tor engine...
+authenticating...
+complete.
+waiting.
+
+Home
+Browse
+Settings
+Log
+Info
+
+Help
+Close
+About
+
+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.
+
diff --git a/Orbot/src/org/torproject/android/HttpProxy.java b/Orbot/src/org/torproject/android/HttpProxy.java
deleted file mode 100644
index 1da7c719..00000000
--- a/Orbot/src/org/torproject/android/HttpProxy.java
+++ /dev/null
@@ -1,639 +0,0 @@
-package org.torproject.android;
-/*
*/
-/*
- * 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 []");
- System.err.println(" the port this service listens on");
- System.err.println(" optional proxy server to forward requests to");
- System.err.println(" 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();
- }
-
-}
-
diff --git a/Orbot/src/org/torproject/android/Orbot.java b/Orbot/src/org/torproject/android/Orbot.java
new file mode 100644
index 00000000..ac79eb83
--- /dev/null
+++ b/Orbot/src/org/torproject/android/Orbot.java
@@ -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;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Orbot/src/org/torproject/android/SettingsPreferences.java b/Orbot/src/org/torproject/android/SettingsPreferences.java
new file mode 100644
index 00000000..cdd5befa
--- /dev/null
+++ b/Orbot/src/org/torproject/android/SettingsPreferences.java
@@ -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);
+ }
+}
diff --git a/Orbot/src/org/torproject/android/TorConstants.java b/Orbot/src/org/torproject/android/TorConstants.java
index 92b34efb..c31f2522 100644
--- a/Orbot/src/org/torproject/android/TorConstants.java
+++ b/Orbot/src/org/torproject/android/TorConstants.java
@@ -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 */
package org.torproject.android;
public interface TorConstants {
- //home directory of Android application
- public final static String TOR_HOME = "/data/data/org.torproject.android/";
+ public final static String TAG = "Orbot";
- //name of the tor C binary
- 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";
+ public final static int FILE_WRITE_BUFFER_SIZE = 2048;
//path to check Tor against
public final static String URL_TOR_CHECK = "http://check.torproject.org";
- 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 = 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_UNAVAILABLE = -1;
+ public final static int STATUS_REQUIRES_DEMAND = 0;
public final static int STATUS_ON = 1;
- public final static int STATUS_STARTING_UP = 2;
- public final static int STATUS_SHUTTING_DOWN = 3;
+ public final static int STATUS_CONNECTING = 2;
- //control port
- public final static String TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE = "Bootstrapped 100%";
+ public final static int PROFILE_OFF = -1;
+ 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";
}
diff --git a/Orbot/src/org/torproject/android/TorControlPanel.java b/Orbot/src/org/torproject/android/TorControlPanel.java
deleted file mode 100644
index 546cc00b..00000000
--- a/Orbot/src/org/torproject/android/TorControlPanel.java
+++ /dev/null
@@ -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 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;
- }
-
-
- }
-
-}
\ No newline at end of file
diff --git a/Orbot/src/org/torproject/android/TorService.java b/Orbot/src/org/torproject/android/TorService.java
deleted file mode 100644
index bb1cca97..00000000
--- a/Orbot/src/org/torproject/android/TorService.java
+++ /dev/null
@@ -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");
-
- }
-}
\ No newline at end of file
diff --git a/Orbot/src/org/torproject/android/Utils.java b/Orbot/src/org/torproject/android/Utils.java
new file mode 100644
index 00000000..0d5c6afa
--- /dev/null
+++ b/Orbot/src/org/torproject/android/Utils.java
@@ -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;
+ }
+
+
+
+ }
+
+
+
+}
diff --git a/Orbot/src/org/torproject/android/SocksClient.java b/Orbot/src/org/torproject/android/net/SocksClient.java
similarity index 69%
rename from Orbot/src/org/torproject/android/SocksClient.java
rename to Orbot/src/org/torproject/android/net/SocksClient.java
index 188ebc1e..4113a292 100644
--- a/Orbot/src/org/torproject/android/SocksClient.java
+++ b/Orbot/src/org/torproject/android/net/SocksClient.java
@@ -1,28 +1,45 @@
-/* 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 */
+
/** 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.Socket;
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 {
+ @SuppressWarnings("unused")
private int port;
+
+ @SuppressWarnings("unused")
private InetAddress hostIP;
private Socket ss;
private InputStream in;
private OutputStream out;
- private static final int BUF_SIZE = 1024;
-
+ @SuppressWarnings("unused")
+private static final int BUF_SIZE = 1024;
+ private static final String IP_LOCALHOST = "127.0.0.1";
+
public SocksClient(String host,int port)
throws IOException,UnknownHostException,SocksException{
this.port = port;
@@ -30,9 +47,9 @@ public class SocksClient implements Runnable {
ss = new SocksSocket(host, port);
out = ss.getOutputStream();
in = ss.getInputStream();
- System.out.println("Connected...");
- System.out.println("TO: "+host+":"+port);
- System.out.println("ViaProxy: "+ss.getLocalAddress().getHostAddress()
+ Log.i(getClass().getName(),"Connected...");
+ Log.i(getClass().getName(),"TO: "+host+":"+port);
+ Log.i(getClass().getName(),"ViaProxy: "+ss.getLocalAddress().getHostAddress()
+":"+ss.getLocalPort());
}
@@ -75,11 +92,11 @@ public class SocksClient implements Runnable {
port = Integer.parseInt(args[1]);
proxyPort =(args.length > 3)? Integer.parseInt(args[3])
- : TorConstants.PORT_SOCKS;
+ : 9050;
host = args[0];
proxyHost =(args.length > 2)? args[2]
- : TorConstants.IP_LOCALHOST;
+ : IP_LOCALHOST;
Proxy.setDefaultProxy(proxyHost,proxyPort,"KOUKY001");
//Proxy.setDefaultProxy(proxyHost,proxyPort);
diff --git a/Orbot/src/org/torproject/android/service/ITorService.aidl b/Orbot/src/org/torproject/android/service/ITorService.aidl
new file mode 100644
index 00000000..aba9809d
--- /dev/null
+++ b/Orbot/src/org/torproject/android/service/ITorService.aidl
@@ -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);
+}
diff --git a/Orbot/src/org/torproject/android/service/ITorServiceCallback.aidl b/Orbot/src/org/torproject/android/service/ITorServiceCallback.aidl
new file mode 100644
index 00000000..82df5027
--- /dev/null
+++ b/Orbot/src/org/torproject/android/service/ITorServiceCallback.aidl
@@ -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);
+}
diff --git a/Orbot/src/org/torproject/android/TorBinaryInstaller.java b/Orbot/src/org/torproject/android/service/TorBinaryInstaller.java
similarity index 66%
rename from Orbot/src/org/torproject/android/TorBinaryInstaller.java
rename to Orbot/src/org/torproject/android/service/TorBinaryInstaller.java
index e69af7b1..9df1ebe7 100644
--- a/Orbot/src/org/torproject/android/TorBinaryInstaller.java
+++ b/Orbot/src/org/torproject/android/service/TorBinaryInstaller.java
@@ -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 */
-package org.torproject.android;
+package org.torproject.android.service;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -14,9 +14,7 @@ import java.util.zip.ZipFile;
import android.util.Log;
-public class TorBinaryInstaller implements TorConstants {
-
- private final static String LOG_TAG = "Tor";
+public class TorBinaryInstaller implements TorServiceConstants {
public TorBinaryInstaller ()
@@ -28,11 +26,13 @@ public class TorBinaryInstaller implements TorConstants {
*/
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 ();
}
@@ -53,14 +53,21 @@ public class TorBinaryInstaller implements TorConstants {
zipen = zip.getEntry(TORRC_ZIP_KEY);
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();
- Log.i(LOG_TAG,"SUCCESS: unzipped tor binary from apk");
+ Log.i(TAG,"SUCCESS: unzipped tor, privoxy binaries from apk");
}
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;
}
@@ -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;
@@ -135,12 +142,15 @@ public class TorBinaryInstaller implements TorConstants {
DataOutputStream out = new DataOutputStream(new FileOutputStream(outputFile));
DataInputStream in = new DataInputStream(is);
- int b;
+ int b = -1;
byte[] data = new byte[1024];
while ((b = in.read(data)) != -1) {
out.write(data);
}
+
+ if (b == -1); //rejoice
+
//
out.flush();
out.close();
@@ -150,7 +160,7 @@ public class TorBinaryInstaller implements TorConstants {
} catch (IOException ex) {
- Log.e(LOG_TAG, "error copying binary", ex);
+ Log.e(TAG, "error copying binary", ex);
}
}
diff --git a/Orbot/src/org/torproject/android/service/TorRoot.java b/Orbot/src/org/torproject/android/service/TorRoot.java
new file mode 100644
index 00000000..d2f9fcfd
--- /dev/null
+++ b/Orbot/src/org/torproject/android/service/TorRoot.java
@@ -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;
+ }
+ }
+}
diff --git a/Orbot/src/org/torproject/android/service/TorService.java b/Orbot/src/org/torproject/android/service/TorService.java
new file mode 100644
index 00000000..19c46e92
--- /dev/null
+++ b/Orbot/src/org/torproject/android/service/TorService.java
@@ -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 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 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 mCallbacks
+ = new RemoteCallbackList();
+
+
+ /**
+ * 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