Improve Bridge and VPN support, working in tandem

You can use Bridges with VPN "App Mode" proxying
On Pre-Lollipop this uses a local loop back SOCKS server to flag outbound sockets as not for the VPN network
On Lollipop+ this uses the "disallow app" feature to set anything in the Orbot process to not be sent through the VPN
This commit is contained in:
Nathan Freitas 2015-03-17 13:04:20 -04:00
parent 3e2b8cff1e
commit 6d05e27793
6 changed files with 81 additions and 88 deletions

View File

@ -174,15 +174,6 @@
android:layout_margin="3dp" android:layout_margin="3dp"
/> />
<ToggleButton
android:id="@+id/btnBridges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="@string/bridges"
android:textOn="@string/bridges"
android:background="@drawable/toggle"
android:layout_margin="3dp"
/>
<ToggleButton <ToggleButton
android:id="@+id/btnVPN" android:id="@+id/btnVPN"
@ -194,6 +185,17 @@
android:layout_margin="3dp" android:layout_margin="3dp"
/> />
<ToggleButton
android:id="@+id/btnBridges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="@string/bridges"
android:textOn="@string/bridges"
android:background="@drawable/toggle"
android:layout_margin="3dp"
/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -303,7 +303,7 @@
<string name="you_do_not_have_root_access_enabled">You do not have ROOT access enabled</string> <string name="you_do_not_have_root_access_enabled">You do not have ROOT access enabled</string>
<string name="you_may_need_to_stop_and_start_orbot_for_settings_change_to_be_enabled_">You may need to stop and start Orbot for settings change to be enabled.</string> <string name="you_may_need_to_stop_and_start_orbot_for_settings_change_to_be_enabled_">You may need to stop and start Orbot for settings change to be enabled.</string>
<string name="menu_vpn">VPN</string> <string name="menu_vpn">Apps</string>
<string name="kbps">kbps</string> <string name="kbps">kbps</string>

View File

@ -16,7 +16,7 @@ android:enabled="true"
android:title="@string/pref_use_persistent_notifications_title"/> android:title="@string/pref_use_persistent_notifications_title"/>
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="false" android:defaultValue="true"
android:key="pref_expanded_notifications" android:key="pref_expanded_notifications"
android:summary="@string/pref_use_expanded_notifications" android:summary="@string/pref_use_expanded_notifications"
android:enabled="true" android:enabled="true"

View File

@ -27,11 +27,13 @@ import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.text.NumberFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@ -94,6 +96,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
private int mPortHTTP = 8118; private int mPortHTTP = 8118;
private int mPortSOCKS = 9050; private int mPortSOCKS = 9050;
private int mVpnProxyPort = 7231;
private static final int NOTIFY_ID = 1; private static final int NOTIFY_ID = 1;
private static final int TRANSPROXY_NOTIFY_ID = 2; private static final int TRANSPROXY_NOTIFY_ID = 2;
@ -142,9 +145,13 @@ public class TorService extends Service implements TorServiceConstants, TorConst
private boolean mTransProxyNetworkRefresh = false; private boolean mTransProxyNetworkRefresh = false;
private boolean mUseVPN = false; private boolean mUseVPN = false;
boolean mIsLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
private ExecutorService mExecutor = Executors.newFixedThreadPool(1); private ExecutorService mExecutor = Executors.newFixedThreadPool(1);
private NumberFormat mNumberFormat = null;
public void debug(String msg) public void debug(String msg)
{ {
if (ENABLE_DEBUG_LOG) if (ENABLE_DEBUG_LOG)
@ -626,6 +633,8 @@ public class TorService extends Service implements TorServiceConstants, TorConst
} }
}).start(); }).start();
mNumberFormat = NumberFormat.getInstance(Locale.getDefault()); //localized numbers!
} }
catch (Exception e) catch (Exception e)
{ {
@ -805,8 +814,8 @@ public class TorService extends Service implements TorServiceConstants, TorConst
boolean useBridges = prefs.getBoolean(TorConstants.PREF_BRIDGES_ENABLED, false); boolean useBridges = prefs.getBoolean(TorConstants.PREF_BRIDGES_ENABLED, false);
if (useBridges) if (useBridges)
if (mUseVPN) if (mUseVPN && !mIsLollipop)
customEnv.add("TOR_PT_PROXY=socks5://127.0.0.1:9999"); customEnv.add("TOR_PT_PROXY=socks5://127.0.0.1:" + mVpnProxyPort);
String baseDirectory = fileTor.getParent(); String baseDirectory = fileTor.getParent();
Shell shellUser = Shell.startShell(customEnv, baseDirectory); Shell shellUser = Shell.startShell(customEnv, baseDirectory);
@ -1458,8 +1467,11 @@ public class TorService extends Service implements TorServiceConstants, TorConst
Intent intent = new Intent(TorService.this, OrbotVpnService.class); Intent intent = new Intent(TorService.this, OrbotVpnService.class);
intent.setAction("start"); intent.setAction("start");
startService(intent);
if (!mIsLollipop)
intent.putExtra("proxyPort",mVpnProxyPort);
startService(intent);
} }
@ -1585,8 +1597,9 @@ public class TorService extends Service implements TorServiceConstants, TorConst
// Under 2Mb, returns "xxx.xKb" // Under 2Mb, returns "xxx.xKb"
// Over 2Mb, returns "xxx.xxMb" // Over 2Mb, returns "xxx.xxMb"
if (count < 1e6) if (count < 1e6)
return ((float)((int)(count*10/1024))/10 + "Kbps"); return mNumberFormat.format(Math.round((float)((int)(count*10/1024))/10)) + "Kbps";
return ((float)((int)(count*100/1024/1024))/100 + "Mbps"); else
return mNumberFormat.format(Math.round((float)((int)(count*100/1024/1024))/100)) + "Mbps";
//return count+" kB"; //return count+" kB";
} }
@ -1932,12 +1945,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst
for (String value : configBuffer) for (String value : configBuffer)
{ {
debug("removing torrc conf: " + value); // debug("removing torrc conf: " + value);
} }
conn.resetConf(resetBuffer); // conn.resetConf(resetBuffer);
resetBuffer = null; resetBuffer = null;
} }
@ -2118,11 +2131,13 @@ public class TorService extends Service implements TorServiceConstants, TorConst
updateConfiguration("UseBridges", "0", false); updateConfiguration("UseBridges", "0", false);
if (mUseVPN) //set the proxy here if we aren't using a bridge if (mUseVPN) //set the proxy here if we aren't using a bridge
{
if (!mIsLollipop)
{ {
String proxyType = "socks5"; String proxyType = "socks5";
String proxyHost = "127.0.0.1"; String proxyHost = "127.0.0.1";
int proxyPort = 9999; updateConfiguration(proxyType + "Proxy", proxyHost + ':' + mVpnProxyPort, false);
updateConfiguration(proxyType + "Proxy", proxyHost + ':' + proxyPort, false); };
} }
else else
@ -2178,14 +2193,16 @@ public class TorService extends Service implements TorServiceConstants, TorConst
bridgeDelim = ","; bridgeDelim = ",";
} }
showToolbarNotification(getString(R.string.notification_using_bridges) + ": " + bridgeList, TRANSPROXY_NOTIFY_ID, R.drawable.ic_stat_tor);
StringTokenizer st = new StringTokenizer(bridgeList,bridgeDelim); StringTokenizer st = new StringTokenizer(bridgeList,bridgeDelim);
while (st.hasMoreTokens()) while (st.hasMoreTokens())
{ {
String bridgeConfigLine = st.nextToken().trim(); String bridgeConfigLine = st.nextToken().trim();
if (bridgeConfigLine != null && bridgeConfigLine.length() > 0)
{
debug("Adding bridge: " + bridgeConfigLine); debug("Adding bridge: " + bridgeConfigLine);
updateConfiguration(bridgeCfgKey, bridgeConfigLine, false); updateConfiguration(bridgeCfgKey, bridgeConfigLine, false);
}
} }
@ -2206,30 +2223,6 @@ public class TorService extends Service implements TorServiceConstants, TorConst
{ {
//time to do autobridges, aka meek //time to do autobridges, aka meek
String proxyBridge = "";
String proxyType = prefs.getString("pref_proxy_type", null);
if (mUseVPN)
{
proxyType = "http"; //"socks5";
String proxyHost = "127.0.0.1";
int proxyPort = 9998; //9999;
//proxyBridge = " proxy=" + proxyType + "://" + proxyHost + ':' + proxyPort; //proxy=http://127.0.0.1:9998
// updateConfiguration(proxyType + "Proxy", proxyHost + ':' + proxyPort, false);
}
else if (proxyType != null && proxyType.length() > 0)
{
String proxyHost = prefs.getString("pref_proxy_host", null);
String proxyPort = prefs.getString("pref_proxy_port", null);
//proxyBridge = " proxy=" + proxyType + "://" + proxyHost + ':' + proxyPort;
updateConfiguration(proxyType + "Proxy", proxyHost + ':' + proxyPort, false);
}
debug ("Using meek bridges"); debug ("Using meek bridges");
String bridgeConfig = "meek exec " + fileMeekclient.getCanonicalPath(); String bridgeConfig = "meek exec " + fileMeekclient.getCanonicalPath();
@ -2260,7 +2253,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
} }
} }
updateConfiguration(bridgeCfgKey, meekBridge[meekIdx] + proxyBridge, false); updateConfiguration(bridgeCfgKey, meekBridge[meekIdx], false);
} }

View File

@ -86,7 +86,7 @@ public interface TorServiceConstants {
public static final String CMD_UPDATE = "update"; public static final String CMD_UPDATE = "update";
public static final String BINARY_TOR_VERSION = "0.2.5.10-openssl1.0.1i-PIE-bridgepatch-obfs4proxy"; public static final String BINARY_TOR_VERSION = "0.2.6-RC6-PT-UPDATE-2";
public static final String PREF_BINARY_TOR_VERSION_INSTALLED = "BINARY_TOR_VERSION_INSTALLED"; public static final String PREF_BINARY_TOR_VERSION_INSTALLED = "BINARY_TOR_VERSION_INSTALLED";
//obfsproxy //obfsproxy

View File

@ -24,6 +24,7 @@ import org.torproject.android.service.TorServiceConstants;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.VpnService; import android.net.VpnService;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
@ -47,12 +48,10 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
private String mSessionName = "OrbotVPN"; private String mSessionName = "OrbotVPN";
private ParcelFileDescriptor mInterface; private ParcelFileDescriptor mInterface;
private int mSocksProxyPort = 9999; private int mSocksProxyPort = -1;
private ProxyServer mSocksProxyServer; private ProxyServer mSocksProxyServer;
private Thread mThreadProxy; private Thread mThreadProxy;
// private HttpProxy mHttpProxyServer;
private final static int VPN_MTU = 1500; private final static int VPN_MTU = 1500;
@Override @Override
@ -64,6 +63,8 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
{ {
Log.d(TAG,"starting OrbotVPNService service!"); Log.d(TAG,"starting OrbotVPNService service!");
mSocksProxyPort = intent.getIntExtra("proxyPort", 0);
// The handler is only used to show messages. // The handler is only used to show messages.
if (mHandler == null) { if (mHandler == null) {
mHandler = new Handler(this); mHandler = new Handler(this);
@ -72,7 +73,10 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
// Stop the previous session by interrupting the thread. // Stop the previous session by interrupting the thread.
if (mThreadVPN == null || (!mThreadVPN.isAlive())) if (mThreadVPN == null || (!mThreadVPN.isAlive()))
{ {
enableAppRouting (); boolean isLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
if (!isLollipop)
startSocksBypass();
setupTun2Socks(); setupTun2Socks();
} }
} }
@ -87,21 +91,6 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
return START_NOT_STICKY; return START_NOT_STICKY;
} }
private void enableAppRouting ()
{
boolean isLollipop = false;
if (isLollipop)
{
//allow for specific apps to be sent through VPN based on list selection
}
else
{
//do socks bypass trick
startSocksBypass();
}
}
private void startSocksBypass(){ private void startSocksBypass(){
mThreadProxy = new Thread () mThreadProxy = new Thread ()
@ -121,13 +110,6 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
mThreadProxy.start(); mThreadProxy.start();
/**
mHttpProxyServer = new HttpProxy(9998);
HttpProxy.setVpnService(OrbotVpnService.this);
mHttpProxyServer.setDebug(5, System.out);
mHttpProxyServer.start();
*/
} }
@Override @Override
@ -183,6 +165,9 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
// (i.e., Farsi and Arabic).^M // (i.e., Farsi and Arabic).^M
Locale.setDefault(new Locale("en")); Locale.setDefault(new Locale("en"));
boolean isLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
//String localhost = InetAddress.getLocalHost().getHostAddress(); //String localhost = InetAddress.getLocalHost().getHostAddress();
String vpnName = "OrbotVPN"; String vpnName = "OrbotVPN";
@ -201,6 +186,9 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
builder.addRoute("0.0.0.0",0); builder.addRoute("0.0.0.0",0);
// builder.addDnsServer("8.8.8.8"); // builder.addDnsServer("8.8.8.8");
if (isLollipop)
doLollipopAppRouting(builder);
// Create a new interface using the builder and save the parameters. // Create a new interface using the builder and save the parameters.
mInterface = builder.setSession(mSessionName) mInterface = builder.setSession(mSessionName)
.setConfigureIntent(mConfigureIntent) .setConfigureIntent(mConfigureIntent)
@ -220,6 +208,16 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
mThreadVPN.start(); mThreadVPN.start();
} }
@TargetApi(Build.VERSION_CODES.L)
private void doLollipopAppRouting (Builder builder) throws NameNotFoundException
{
builder.addDisallowedApplication("org.torproject.android");
}
@Override @Override
public void onRevoke() { public void onRevoke() {