summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java')
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java239
1 files changed, 178 insertions, 61 deletions
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
index 2b6df9af..4f7a5bda 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
@@ -6,16 +6,20 @@
package de.blinkt.openvpn.core;
import android.content.Context;
+import android.content.Intent;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
+import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.support.annotation.NonNull;
-import android.text.TextUtils;
+import android.support.annotation.RequiresApi;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
-
-import junit.framework.Assert;
+import se.leap.bitmaskclient.R;
+import de.blinkt.openvpn.VpnProfile;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -24,19 +28,13 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.Locale;
-import java.util.Vector;
-
-import se.leap.bitmaskclient.BuildConfig;
-import se.leap.bitmaskclient.R;
-import de.blinkt.openvpn.VpnProfile;
+import java.util.*;
public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
+ public static final int ORBOT_TIMEOUT_MS = 20 * 1000;
private static final String TAG = "openvpn";
+ private static final Vector<OpenVpnManagementThread> active = new Vector<>();
private final Handler mResumeHandler;
private LocalSocket mSocket;
private VpnProfile mProfile;
@@ -45,13 +43,55 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
private LocalServerSocket mServerSocket;
private boolean mWaitingForRelease = false;
private long mLastHoldRelease = 0;
-
- private static final Vector<OpenVpnManagementThread> active = new Vector<>();
private LocalSocket mServerSocketLocal;
private pauseReason lastPauseReason = pauseReason.noNetwork;
private PausedStateCallback mPauseCallback;
private boolean mShuttingDown;
+ private Runnable mResumeHoldRunnable = () -> {
+ if (shouldBeRunning()) {
+ releaseHoldCmd();
+ }
+ };
+ private Runnable orbotStatusTimeOutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ sendProxyCMD(Connection.ProxyType.SOCKS5, "127.0.0.1", Integer.toString(OrbotHelper.SOCKS_PROXY_PORT_DEFAULT), false);
+ OrbotHelper.get(mOpenVPNService).removeStatusCallback(statusCallback);
+
+ }
+ };
+ private OrbotHelper.StatusCallback statusCallback = new OrbotHelper.StatusCallback() {
+
+ @Override
+ public void onStatus(Intent statusIntent) {
+ StringBuilder extras = new StringBuilder();
+ for (String key : statusIntent.getExtras().keySet()) {
+ Object val = statusIntent.getExtras().get(key);
+
+ extras.append(String.format(Locale.ENGLISH, "%s - '%s'", key, val == null ? "null" : val.toString()));
+ }
+ VpnStatus.logDebug("Got Orbot status: " + extras);
+ }
+
+ @Override
+ public void onNotYetInstalled() {
+ VpnStatus.logDebug("Orbot not yet installed");
+ }
+
+ @Override
+ public void onOrbotReady(Intent intent, String socksHost, int socksPort) {
+ mResumeHandler.removeCallbacks(orbotStatusTimeOutRunnable);
+ sendProxyCMD(Connection.ProxyType.SOCKS5, socksHost, Integer.toString(socksPort), false);
+ OrbotHelper.get(mOpenVPNService).removeStatusCallback(this);
+ }
+
+ @Override
+ public void onDisabled(Intent intent) {
+ VpnStatus.logWarning("Orbot integration for external applications is disabled. Waiting %ds before connecting to the default port. Enable external app integration in Orbot or use Socks v5 config instead of Orbot to avoid this delay.");
+ }
+ };
+ private transient Connection mCurrentProxyConnection;
public OpenVpnManagementThread(VpnProfile profile, OpenVPNService openVpnService) {
mProfile = profile;
@@ -60,14 +100,21 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
- private Runnable mResumeHoldRunnable = new Runnable() {
- @Override
- public void run() {
- if (shouldBeRunning()) {
- releaseHoldCmd();
+ private static boolean stopOpenVPN() {
+ synchronized (active) {
+ boolean sendCMD = false;
+ for (OpenVpnManagementThread mt : active) {
+ sendCMD = mt.managmentCommand("signal SIGINT\n");
+ try {
+ if (mt.mSocket != null)
+ mt.mSocket.close();
+ } catch (IOException e) {
+ // Ignore close error on already closed socket
+ }
}
+ return sendCMD;
}
- };
+ }
public boolean openManagementInterface(@NonNull Context c) {
// Could take a while to open connection
@@ -122,7 +169,6 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
return false;
}
-
@Override
public void run() {
byte[] buffer = new byte[2048];
@@ -198,9 +244,13 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
//ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(fdint);
//pfd.close();
- NativeUtils.jniclose(fdint);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ fdCloseLollipop(fd);
+ } else {
+ NativeUtils.jniclose(fdint);
+ }
return;
- } catch (NoSuchMethodException | IllegalArgumentException | InvocationTargetException | IllegalAccessException | NullPointerException e) {
+ } catch ( NoSuchMethodException | IllegalArgumentException | InvocationTargetException | IllegalAccessException | NullPointerException e) {
VpnStatus.logException("Failed to retrieve fd from socket (" + fd + ")", e);
}
@@ -208,6 +258,15 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ private void fdCloseLollipop(FileDescriptor fd) {
+ try {
+ Os.close(fd);
+ } catch (Exception e) {
+ VpnStatus.logException("Failed to close fd (" + fd + ")", e);
+ }
+ }
+
private String processInput(String pendingInput) {
@@ -223,11 +282,9 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
return pendingInput;
}
-
private void processCommand(String command) {
//Log.i(TAG, "Line from managment" + command);
-
if (command.startsWith(">") && command.contains(":")) {
String[] parts = command.split(":", 2);
String cmd = parts[0].substring(1);
@@ -263,6 +320,9 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
case "PK_SIGN":
processSignCommand(argument);
break;
+ case "INFOMSG":
+ processInfoMessage(argument);
+ break;
default:
VpnStatus.logWarning("MGMT: Got unrecognized command" + command);
Log.i(TAG, "Got unrecognized command" + command);
@@ -281,6 +341,14 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
}
+ private void processInfoMessage(String info)
+ {
+ if (info.startsWith("OPEN_URL:"))
+ {
+ mOpenVPNService.trigger_url_open(info);
+ }
+ }
+
private void processLogMessage(String argument) {
String[] args = argument.split(",", 4);
// 0 unix time stamp
@@ -367,7 +435,6 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
//managmentCommand("log on all\n");
}
-
public void releaseHold() {
if (mWaitingForRelease)
releaseHoldCmd();
@@ -375,27 +442,81 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
private void processProxyCMD(String argument) {
String[] args = argument.split(",", 3);
- SocketAddress proxyaddr = ProxyDetection.detectProxy(mProfile);
+ Connection.ProxyType proxyType = Connection.ProxyType.NONE;
+
+ int connectionEntryNumber = Integer.parseInt(args[0]) - 1;
+ String proxyport = null;
+ String proxyname = null;
+ boolean proxyUseAuth = false;
+
+ if (mProfile.mConnections.length > connectionEntryNumber) {
+ Connection connection = mProfile.mConnections[connectionEntryNumber];
+ proxyType = connection.mProxyType;
+ proxyname = connection.mProxyName;
+ proxyport = connection.mProxyPort;
+ proxyUseAuth = connection.mUseProxyAuth;
+
+ // Use transient variable to remember http user/password
+ mCurrentProxyConnection = connection;
+
+ } else {
+ VpnStatus.logError(String.format(Locale.ENGLISH, "OpenVPN is asking for a proxy of an unknown connection entry (%d)", connectionEntryNumber));
+ }
- if (args.length >= 2) {
+ // atuo detection of proxy
+ if (proxyType == Connection.ProxyType.NONE) {
+ SocketAddress proxyaddr = ProxyDetection.detectProxy(mProfile);
+ if (proxyaddr instanceof InetSocketAddress) {
+ InetSocketAddress isa = (InetSocketAddress) proxyaddr;
+ proxyType = Connection.ProxyType.HTTP;
+ proxyname = isa.getHostName();
+ proxyport = String.valueOf(isa.getPort());
+ proxyUseAuth = false;
+
+ }
+ }
+
+
+ if (args.length >= 2 && proxyType == Connection.ProxyType.HTTP) {
String proto = args[1];
if (proto.equals("UDP")) {
- proxyaddr = null;
+ proxyname = null;
+ VpnStatus.logInfo("Not using an HTTP proxy since the connection uses UDP");
}
}
- if (proxyaddr instanceof InetSocketAddress) {
- InetSocketAddress isa = (InetSocketAddress) proxyaddr;
- VpnStatus.logInfo(R.string.using_proxy, isa.getHostName(), isa.getPort());
+ if (proxyType == Connection.ProxyType.ORBOT) {
+ VpnStatus.updateStateString("WAIT_ORBOT", "Waiting for Orbot to start", R.string.state_waitorbot, ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET);
+ OrbotHelper orbotHelper = OrbotHelper.get(mOpenVPNService);
+ if (!orbotHelper.checkTorReceier(mOpenVPNService))
+ VpnStatus.logError("Orbot does not seem to be installed!");
+
+ mResumeHandler.postDelayed(orbotStatusTimeOutRunnable, ORBOT_TIMEOUT_MS);
+ orbotHelper.addStatusCallback(mOpenVPNService, statusCallback);
+
+ orbotHelper.sendOrbotStartAndStatusBroadcast();
+
+ } else {
+ sendProxyCMD(proxyType, proxyname, proxyport, proxyUseAuth);
+ }
+ }
+
+ private void sendProxyCMD(Connection.ProxyType proxyType, String proxyname, String proxyport, boolean usePwAuth) {
+ if (proxyType != Connection.ProxyType.NONE && proxyname != null) {
+
+ VpnStatus.logInfo(R.string.using_proxy, proxyname, proxyname);
- String proxycmd = String.format(Locale.ENGLISH, "proxy HTTP %s %d\n", isa.getHostName(), isa.getPort());
+ String pwstr = usePwAuth ? " auto" : "";
+
+ String proxycmd = String.format(Locale.ENGLISH, "proxy %s %s %s%s\n",
+ proxyType == Connection.ProxyType.HTTP ? "HTTP" : "SOCKS",
+ proxyname, proxyport, pwstr);
managmentCommand(proxycmd);
} else {
managmentCommand("proxy NONE\n");
}
-
}
private void processState(String argument) {
@@ -408,7 +529,6 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
VpnStatus.updateStateString(currentstate, args[2]);
}
-
private void processByteCount(String argument) {
// >BYTECOUNT:{BYTES_IN},{BYTES_OUT}
int comma = argument.indexOf(',');
@@ -419,7 +539,6 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
-
private void processNeedCommand(String argument) {
int p1 = argument.indexOf('\'');
int p2 = argument.indexOf('\'', p1 + 1);
@@ -452,7 +571,8 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
*/
if (routeparts.length == 5) {
- if (BuildConfig.DEBUG) Assert.assertEquals("dev", routeparts[3]);
+ //if (BuildConfig.DEBUG)
+ // assertEquals("dev", routeparts[3]);
mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], routeparts[4]);
} else if (routeparts.length >= 3) {
mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], null);
@@ -473,8 +593,10 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
mOpenVPNService.setLocalIP(ifconfigparts[0], ifconfigparts[1], mtu, ifconfigparts[3]);
break;
case "IFCONFIG6":
- mOpenVPNService.setLocalIPv6(extra);
-
+ String[] ifconfig6parts = extra.split(" ");
+ mtu = Integer.parseInt(ifconfig6parts[1]);
+ mOpenVPNService.setMtu(mtu);
+ mOpenVPNService.setLocalIPv6(ifconfig6parts[0]);
break;
case "PERSIST_TUN_ACTION":
// check if tun cfg stayed the same
@@ -546,6 +668,10 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
try {
+ // Ignore Auth token message, already managed by openvpn itself
+ if (argument.startsWith("Auth-Token:")) {
+ return;
+ }
int p1 = argument.indexOf('\'');
int p2 = argument.indexOf('\'', p1 + 1);
@@ -560,17 +686,26 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
String pw = null;
+ String username = null;
if (needed.equals("Private Key")) {
pw = mProfile.getPasswordPrivateKey();
} else if (needed.equals("Auth")) {
pw = mProfile.getPasswordAuth();
+ username = mProfile.mUsername;
- String usercmd = String.format("username '%s' %s\n",
- needed, VpnProfile.openVpnEscape(mProfile.mUsername));
- managmentCommand(usercmd);
+ } else if (needed.equals("HTTP Proxy")) {
+ if( mCurrentProxyConnection != null) {
+ pw = mCurrentProxyConnection.mProxyAuthPassword;
+ username = mCurrentProxyConnection.mProxyAuthUser;
+ }
}
if (pw != null) {
+ if (username !=null) {
+ String usercmd = String.format("username '%s' %s\n",
+ needed, VpnProfile.openVpnEscape(username));
+ managmentCommand(usercmd);
+ }
String cmd = String.format("password '%s' %s\n", needed, VpnProfile.openVpnEscape(pw));
managmentCommand(cmd);
} else {
@@ -580,28 +715,10 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
-
private void proccessPWFailed(String needed, String args) {
VpnStatus.updateStateString("AUTH_FAILED", needed + args, R.string.state_auth_failed, ConnectionStatus.LEVEL_AUTH_FAILED);
}
-
- private static boolean stopOpenVPN() {
- synchronized (active) {
- boolean sendCMD = false;
- for (OpenVpnManagementThread mt : active) {
- sendCMD = mt.managmentCommand("signal SIGINT\n");
- try {
- if (mt.mSocket != null)
- mt.mSocket.close();
- } catch (IOException e) {
- // Ignore close error on already closed socket
- }
- }
- return sendCMD;
- }
- }
-
@Override
public void networkChange(boolean samenetwork) {
if (mWaitingForRelease)
@@ -634,7 +751,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
private void processSignCommand(String b64data) {
- String signed_string = mProfile.getSignedData(b64data);
+ String signed_string = mProfile.getSignedData(mOpenVPNService, b64data, false);
if (signed_string == null) {
managmentCommand("pk-sig\n");