summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorcyberta <cyberta@riseup.net>2020-01-21 16:10:59 -0600
committercyberta <cyberta@riseup.net>2020-01-21 16:10:59 -0600
commit6a015d337d6a786adb319c3f9de7b9b7e9ae80bb (patch)
treeae19d8d28d15d3b871d82e804994d810f79ad811 /app/src/main/java
parent14b84f691e369e2a4ef3fe8687688f5ba98fa719 (diff)
implement no-dns fallback using okhttp's Dns interface
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/DnsResolver.java33
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java4
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Provider.java41
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderManager.java24
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java12
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java117
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java7
9 files changed, 222 insertions, 20 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java b/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java
new file mode 100644
index 00000000..55cf1123
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java
@@ -0,0 +1,33 @@
+package se.leap.bitmaskclient;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+import okhttp3.Dns;
+
+class DnsResolver implements Dns {
+
+ @Override
+ public List<InetAddress> lookup(String hostname) throws UnknownHostException {
+ try {
+ return Dns.SYSTEM.lookup(hostname);
+ } catch (UnknownHostException e) {
+ ProviderObservable observable = ProviderObservable.getInstance();
+ Provider currentProvider;
+ if (observable.getProviderToSetup() != null) {
+ currentProvider = observable.getProviderToSetup();
+ } else {
+ currentProvider = observable.getCurrentProvider();
+ }
+ if (currentProvider != null && currentProvider.hasProviderIp()) {
+ ArrayList<InetAddress> addresses = new ArrayList<>();
+ addresses.add(InetAddress.getByAddress(hostname, currentProvider.getProviderIpAsBytes()));
+ return addresses;
+ } else {
+ throw new UnknownHostException("Hostname " + hostname + " not found");
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
index eceba0db..486c26bb 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
@@ -47,6 +47,7 @@ import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK;
import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences;
/**
@@ -155,6 +156,9 @@ class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListe
PreferenceHelper.storeProviderInPreferences(preferences, provider);
EipCommand.startVPN(context.getApplicationContext(), true);
break;
+ case PROVIDER_NOK:
+ ProviderObservable.getInstance().setProviderToSetup(null);
+ break;
default:
break;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
index 69270140..9d1168aa 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
@@ -88,6 +88,7 @@ public class OkHttpClientGenerator {
sslCompatFactory.initSSLSocketFactory(clientBuilder);
clientBuilder.cookieJar(getCookieJar())
.connectionSpecs(Collections.singletonList(spec));
+ clientBuilder.dns(new DnsResolver());
return clientBuilder.build();
} catch (IllegalArgumentException e) {
e.printStackTrace();
diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java
index b98c3fd3..3dfee72c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java
@@ -29,6 +29,8 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
+import se.leap.bitmaskclient.utils.IPAddress;
+
import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
import static se.leap.bitmaskclient.Constants.CAPABILITIES;
import static se.leap.bitmaskclient.Constants.GATEWAYS;
@@ -49,6 +51,7 @@ public final class Provider implements Parcelable {
private JSONObject eipServiceJson = new JSONObject();
private DefaultedURL mainUrl = new DefaultedURL();
private DefaultedURL apiUrl = new DefaultedURL();
+ private String providerIp = "";
private String certificatePin = "";
private String certificatePinEncoding = "";
private String caCert = "";
@@ -73,7 +76,8 @@ public final class Provider implements Parcelable {
NAME = "name",
DESCRIPTION = "description",
DOMAIN = "domain",
- MAIN_URL = "main_url";
+ MAIN_URL = "main_url",
+ PROVIDER_IP = "provider_ip";
private static final String API_TERM_NAME = "name";
@@ -87,12 +91,16 @@ public final class Provider implements Parcelable {
}
}
- public Provider(URL mainUrl) {
+ public Provider(URL mainUrl, String providerIp) {
this.mainUrl.setUrl(mainUrl);
+ this.providerIp = providerIp;
}
- public Provider(URL mainUrl, String caCert, String definition) {
+ public Provider(URL mainUrl, String providerIp, String caCert, String definition) {
this.mainUrl.setUrl(mainUrl);
+ if (this.providerIp != null) {
+ this.providerIp = providerIp;
+ }
if (caCert != null) {
this.caCert = caCert;
}
@@ -146,6 +154,18 @@ public final class Provider implements Parcelable {
return false;
}
+ public void setProviderIp(String providerIp) {
+ this.providerIp = providerIp;
+ }
+
+ public String getProviderIp() {
+ return this.providerIp;
+ }
+
+ public byte[] getProviderIpAsBytes() {
+ return IPAddress.asBytes(providerIp);
+ }
+
public void setMainUrl(URL url) {
mainUrl.setUrl(url);
}
@@ -192,7 +212,7 @@ public final class Provider implements Parcelable {
}
- protected String getApiUrlString() {
+ public String getApiUrlString() {
return getApiUrl().toString();
}
@@ -265,6 +285,7 @@ public final class Provider implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(getMainUrlString());
+ parcel.writeString(getProviderIp());
parcel.writeString(getDefinitionString());
parcel.writeString(getCaCert());
parcel.writeString(getEipServiceJsonString());
@@ -281,6 +302,7 @@ public final class Provider implements Parcelable {
definition.toString().equals(p.getDefinition().toString()) &&
eipServiceJson.toString().equals(p.getEipServiceJson().toString())&&
mainUrl.equals(p.getMainUrl()) &&
+ providerIp.equals(p.getProviderIp()) &&
apiUrl.equals(p.getApiUrl()) &&
certificatePin.equals(p.getCertificatePin()) &&
certificatePinEncoding.equals(p.getCertificatePinEncoding()) &&
@@ -298,7 +320,6 @@ public final class Provider implements Parcelable {
JSONObject json = new JSONObject();
try {
json.put(Provider.MAIN_URL, mainUrl);
- //TODO: add other fields here?
} catch (JSONException e) {
e.printStackTrace();
}
@@ -321,6 +342,10 @@ public final class Provider implements Parcelable {
mainUrl.setUrl(new URL(in.readString()));
String tmpString = in.readString();
if (!tmpString.isEmpty()) {
+ providerIp = tmpString;
+ }
+ tmpString = in.readString();
+ if (!tmpString.isEmpty()) {
definition = new JSONObject((tmpString));
parseDefinition(definition);
}
@@ -444,8 +469,12 @@ public final class Provider implements Parcelable {
return getCertificatePinEncoding() + ":" + getCertificatePin();
}
+ public boolean hasProviderIp() {
+ return !providerIp.isEmpty();
+ }
+
/**
- * resets everything except the main url
+ * resets everything except the main url and the providerIp
*/
public void reset() {
definition = new JSONObject();
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
index c8070e18..bae237f6 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
@@ -109,7 +109,7 @@ public abstract class ProviderListBaseActivity extends ProviderSetupBaseActivity
public void showAndSelectProvider(String newURL) {
try {
- provider = new Provider(new URL((newURL)));
+ provider = new Provider(new URL((newURL)), "");
autoSelectProvider();
} catch (MalformedURLException e) {
e.printStackTrace();
@@ -165,6 +165,7 @@ public abstract class ProviderListBaseActivity extends ProviderSetupBaseActivity
if (provider != null && !provider.isDefault()) {
//TODO Code 2 pane view
providerConfigState = SETTING_UP_PROVIDER;
+ ProviderObservable.getInstance().setProviderToSetup(provider);
showProgressBar();
onItemSelectedLogic();
} else {
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
index dd9070af..134e2d76 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java
@@ -21,6 +21,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import static se.leap.bitmaskclient.Provider.MAIN_URL;
+import static se.leap.bitmaskclient.Provider.PROVIDER_IP;
import static se.leap.bitmaskclient.utils.FileHelper.createFile;
import static se.leap.bitmaskclient.utils.FileHelper.persistFile;
import static se.leap.bitmaskclient.utils.InputStreamHelper.getInputStreamFrom;
@@ -84,19 +86,21 @@ public class ProviderManager implements AdapteeCollection<Provider> {
for (String file : relativeFilePaths) {
String mainUrl = null;
+ String providerIp = null;
String certificate = null;
String providerDefinition = null;
try {
String provider = file.substring(0, file.length() - ".url".length());
- InputStream provider_file = assetsManager.open(directory + "/" + file);
- mainUrl = extractMainUrlFromInputStream(provider_file);
+ InputStream providerFile = assetsManager.open(directory + "/" + file);
+ mainUrl = extractKeyFromInputStream(providerFile, MAIN_URL);
+ providerIp = extractKeyFromInputStream(providerFile, PROVIDER_IP);
certificate = loadInputStreamAsString(assetsManager.open(provider + EXT_PEM));
providerDefinition = loadInputStreamAsString(assetsManager.open(provider + EXT_JSON));
} catch (IOException e) {
e.printStackTrace();
}
try {
- providers.add(new Provider(new URL(mainUrl), certificate, providerDefinition));
+ providers.add(new Provider(new URL(mainUrl), providerIp, certificate, providerDefinition));
} catch (MalformedURLException e) {
e.printStackTrace();
}
@@ -118,8 +122,10 @@ public class ProviderManager implements AdapteeCollection<Provider> {
Set<Provider> providers = new HashSet<>();
try {
for (String file : files) {
- String mainUrl = extractMainUrlFromInputStream(getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file));
- providers.add(new Provider(new URL(mainUrl)));
+ InputStream inputStream = getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file);
+ String mainUrl = extractKeyFromInputStream(inputStream, MAIN_URL);
+ String providerIp = extractKeyFromInputStream(inputStream, PROVIDER_IP);
+ providers.add(new Provider(new URL(mainUrl), providerIp));
}
} catch (MalformedURLException | FileNotFoundException | NullPointerException e) {
e.printStackTrace();
@@ -128,13 +134,13 @@ public class ProviderManager implements AdapteeCollection<Provider> {
return providers;
}
- private String extractMainUrlFromInputStream(InputStream inputStream) {
- String mainUrl = "";
+ private String extractKeyFromInputStream(InputStream inputStream, String key) {
+ String value = "";
JSONObject fileContents = inputStreamToJson(inputStream);
if (fileContents != null)
- mainUrl = fileContents.optString(Provider.MAIN_URL);
- return mainUrl;
+ value = fileContents.optString(key);
+ return value;
}
private JSONObject inputStreamToJson(InputStream inputStream) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java b/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java
index 776c0e92..f20599ba 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java
@@ -2,14 +2,13 @@ package se.leap.bitmaskclient;
import java.util.Observable;
-import se.leap.bitmaskclient.utils.PreferenceHelper;
-
/**
* Created by cyberta on 05.12.18.
*/
public class ProviderObservable extends Observable {
private static ProviderObservable instance;
private Provider currentProvider;
+ private Provider providerToSetup;
public static ProviderObservable getInstance() {
if (instance == null) {
@@ -20,6 +19,7 @@ public class ProviderObservable extends Observable {
public synchronized void updateProvider(Provider provider) {
instance.currentProvider = provider;
+ instance.providerToSetup = null;
instance.setChanged();
instance.notifyObservers();
}
@@ -28,4 +28,12 @@ public class ProviderObservable extends Observable {
return instance.currentProvider;
}
+ public void setProviderToSetup(Provider provider) {
+ this.providerToSetup = provider;
+ }
+
+ public Provider getProviderToSetup() {
+ return instance.providerToSetup;
+ }
+
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java b/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java
new file mode 100644
index 00000000..8b419a2c
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java
@@ -0,0 +1,117 @@
+package se.leap.bitmaskclient.utils;
+
+/*
+ * Copyright (C) 2006-2008 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+
+//package net.gqu.utils;
+
+import java.util.StringTokenizer;
+
+/**
+ * TCP/IP Address Utility Class
+ *
+ * @author gkspencer
+ */
+public class IPAddress {
+
+
+ /**
+ * Convert a TCP/IP address string into a byte array
+ *
+ * @param addr String
+ * @return byte[]
+ */
+ public final static byte[] asBytes(String addr) {
+
+ // Convert the TCP/IP address string to an integer value
+
+ int ipInt = parseNumericAddress(addr);
+ if ( ipInt == 0)
+ return null;
+
+ // Convert to bytes
+
+ byte[] ipByts = new byte[4];
+
+ ipByts[3] = (byte) (ipInt & 0xFF);
+ ipByts[2] = (byte) ((ipInt >> 8) & 0xFF);
+ ipByts[1] = (byte) ((ipInt >> 16) & 0xFF);
+ ipByts[0] = (byte) ((ipInt >> 24) & 0xFF);
+
+ // Return the TCP/IP bytes
+
+ return ipByts;
+ }
+ /**
+ * Check if the specified address is a valid numeric TCP/IP address and return as an integer value
+ *
+ * @param ipaddr String
+ * @return int
+ */
+ public final static int parseNumericAddress(String ipaddr) {
+
+ // Check if the string is valid
+
+ if ( ipaddr == null || ipaddr.length() < 7 || ipaddr.length() > 15)
+ return 0;
+
+ // Check the address string, should be n.n.n.n format
+
+ StringTokenizer token = new StringTokenizer(ipaddr,".");
+ if ( token.countTokens() != 4)
+ return 0;
+
+ int ipInt = 0;
+
+ while ( token.hasMoreTokens()) {
+
+ // Get the current token and convert to an integer value
+
+ String ipNum = token.nextToken();
+
+ try {
+
+ // Validate the current address part
+
+ int ipVal = Integer.valueOf(ipNum).intValue();
+ if ( ipVal < 0 || ipVal > 255)
+ return 0;
+
+ // Add to the integer address
+
+ ipInt = (ipInt << 8) + ipVal;
+ }
+ catch (NumberFormatException ex) {
+ return 0;
+ }
+ }
+
+ // Return the integer address
+
+ return ipInt;
+ }
+
+
+} \ No newline at end of file
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
index 40bb2eca..b6e39c50 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
@@ -2,7 +2,6 @@ package se.leap.bitmaskclient.utils;
import android.content.Context;
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -24,6 +23,7 @@ import se.leap.bitmaskclient.Provider;
import static android.content.Context.MODE_PRIVATE;
import static se.leap.bitmaskclient.Constants.ALWAYS_ON_SHOW_DIALOG;
import static se.leap.bitmaskclient.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
+import static se.leap.bitmaskclient.Constants.EXCLUDED_APPS;
import static se.leap.bitmaskclient.Constants.LAST_USED_PROFILE;
import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION;
import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED;
@@ -33,7 +33,6 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.Constants.SU_PERMISSION;
import static se.leap.bitmaskclient.Constants.USE_PLUGGABLE_TRANSPORTS;
-import static se.leap.bitmaskclient.Constants.EXCLUDED_APPS;
/**
* Created by cyberta on 18.03.18.
@@ -48,6 +47,7 @@ public class PreferenceHelper {
Provider provider = new Provider();
try {
provider.setMainUrl(new URL(preferences.getString(Provider.MAIN_URL, "")));
+ provider.setProviderIp(preferences.getString(Provider.PROVIDER_IP, ""));
provider.define(new JSONObject(preferences.getString(Provider.KEY, "")));
provider.setCaCert(preferences.getString(Provider.CA_CERT, ""));
provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, ""));
@@ -131,6 +131,7 @@ public class PreferenceHelper {
//FIXME: don't save private keys in shared preferences! use the keystore
public static void storeProviderInPreferences(SharedPreferences preferences, Provider provider) {
preferences.edit().putBoolean(PROVIDER_CONFIGURED, true).
+ putString(Provider.PROVIDER_IP, provider.getProviderIp()).
putString(Provider.MAIN_URL, provider.getMainUrlString()).
putString(Provider.KEY, provider.getDefinitionString()).
putString(Provider.CA_CERT, provider.getCaCert()).
@@ -141,6 +142,7 @@ public class PreferenceHelper {
String providerDomain = provider.getDomain();
preferences.edit().putBoolean(PROVIDER_CONFIGURED, true).
+ putString(Provider.PROVIDER_IP + "." + providerDomain, provider.getProviderIp()).
putString(Provider.MAIN_URL + "." + providerDomain, provider.getMainUrlString()).
putString(Provider.KEY + "." + providerDomain, provider.getDefinitionString()).
putString(Provider.CA_CERT + "." + providerDomain, provider.getCaCert()).
@@ -206,6 +208,7 @@ public class PreferenceHelper {
remove(Provider.KEY + "." + providerDomain).
remove(Provider.CA_CERT + "." + providerDomain).
remove(Provider.CA_CERT_FINGERPRINT + "." + providerDomain).
+ remove(Provider.PROVIDER_IP + "." + providerDomain).
remove(Provider.MAIN_URL + "." + providerDomain).
remove(Provider.KEY + "." + providerDomain).
remove(Provider.CA_CERT + "." + providerDomain).