diff options
| author | cyberta <cyberta@riseup.net> | 2020-01-21 16:10:59 -0600 | 
|---|---|---|
| committer | cyberta <cyberta@riseup.net> | 2020-01-21 16:10:59 -0600 | 
| commit | 6a015d337d6a786adb319c3f9de7b9b7e9ae80bb (patch) | |
| tree | ae19d8d28d15d3b871d82e804994d810f79ad811 | |
| parent | 14b84f691e369e2a4ef3fe8687688f5ba98fa719 (diff) | |
implement no-dns fallback using okhttp's Dns interface
16 files changed, 270 insertions, 41 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). diff --git a/app/src/normal/assets/urls/pt.demo.bitmask.net.url b/app/src/normal/assets/urls/pt.demo.bitmask.net.url index d6e50462..cd393826 100644 --- a/app/src/normal/assets/urls/pt.demo.bitmask.net.url +++ b/app/src/normal/assets/urls/pt.demo.bitmask.net.url @@ -1,3 +1,4 @@  { -	"main_url" : "https://pt.demo.bitmask.net" +	"main_url" : "https://pt.demo.bitmask.net", +	"provider_ip" : "198.252.153.85"  } diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index 41a63ad7..6f1e3034 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -121,14 +121,13 @@ public class ProviderApiManager extends ProviderApiManagerBase {          Bundle result = new Bundle();          String caCert = provider.getCaCert(); -        JSONObject providerDefinition = provider.getDefinition();          String providerDotJsonString; -        if(providerDefinition.length() == 0 || caCert.isEmpty()) { +        if(provider.getDefinitionString().length() == 0 || caCert.isEmpty()) {              String providerJsonUrl = provider.getMainUrlString() + "/provider.json";              providerDotJsonString = downloadWithCommercialCA(providerJsonUrl, provider);          } else { -            providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition); +            providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, provider);          }          if (ConfigHelper.checkErroneousDownload(providerDotJsonString) || !isValidJson(providerDotJsonString)) { @@ -163,8 +162,7 @@ public class ProviderApiManager extends ProviderApiManagerBase {          Bundle result = new Bundle();          String eipServiceJsonString = "";          try { -            JSONObject providerJson = provider.getDefinition(); -            String eipServiceUrl = providerJson.getString(Provider.API_URL) + "/" + providerJson.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; +            String eipServiceUrl = provider.getApiUrlWithVersion() + "/" + EIP.SERVICE_API_PATH;              eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl);              JSONObject eipServiceJson = new JSONObject(eipServiceJsonString);              if (BuildConfig.DEBUG) { @@ -278,10 +276,10 @@ public class ProviderApiManager extends ProviderApiManagerBase {       *       * @return an empty string if it fails, the response body if not.       */ -    private String downloadFromApiUrlWithProviderCA(String path, String caCert, JSONObject providerDefinition) { +    private String downloadFromApiUrlWithProviderCA(String path, String caCert, Provider provider) {          String responseString;          JSONObject errorJson = new JSONObject(); -        String baseUrl = getApiUrl(providerDefinition); +        String baseUrl = provider.getApiUrlString();          OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson);          if (okHttpClient == null) {              return errorJson.toString(); diff --git a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java index 669abc84..89833393 100644 --- a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java +++ b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java @@ -51,12 +51,15 @@ public class TestSetupHelper {      public static Provider getConfiguredProvider() throws IOException, JSONException { -        return getProvider(null, null, null, null); +        return getProvider(null,  null, null, null, null);      } -    public static Provider getProvider(String domain, String caCertFile, String providerJson, String eipServiceJson) { +    public static Provider getProvider(String domain, String providerIp, String caCertFile, String providerJson, String eipServiceJson) {          if (domain == null)              domain = "https://riseup.net"; +        if (providerIp == null) { +            providerIp = ""; +        }          if (caCertFile == null)              caCertFile = "riseup.net.pem";          if (providerJson == null) @@ -68,6 +71,7 @@ public class TestSetupHelper {          try {              Provider p = new Provider(                      new URL(domain), +                    providerIp,                      getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(caCertFile)),                      getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(providerJson)) diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java index c4b8f65e..bb809a79 100644 --- a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java @@ -53,6 +53,7 @@ public class ProviderTest {                  "https://pt.demo.bitmask.net",                  null,                  null, +                null,                  "ptdemo.bitmask.eip-service.json");          assertTrue(p1.supportsPluggableTransports());      } @@ -63,6 +64,7 @@ public class ProviderTest {                  null,                  null,                  null, +                null,                  "eip-service-two-gateways.json");          assertFalse(p1.supportsPluggableTransports());      } diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java index b37b3474..4d48372c 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java @@ -107,7 +107,7 @@ public class GatewaysManagerTest {      @Test      public void testGatewayManagerFromCurrentProvider_misconfiguredProvider_noGateways() throws IOException, NullPointerException { -        Provider provider = getProvider(null, null, null, "ptdemo_misconfigured_gateway.json"); +        Provider provider = getProvider(null, null, null, null, "ptdemo_misconfigured_gateway.json");          MockHelper.mockProviderObserver(provider);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          assertEquals(0, gatewaysManager.size()); @@ -115,7 +115,7 @@ public class GatewaysManagerTest {      @Test      public void testGatewayManagerFromCurrentProvider_threeGateways() { -        Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, "ptdemo_three_mixed_gateways.json");          MockHelper.mockProviderObserver(provider);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          assertEquals(3, gatewaysManager.size()); @@ -123,7 +123,7 @@ public class GatewaysManagerTest {      @Test      public void TestGetPosition_VpnProfileExtistingObfs4_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, "ptdemo_three_mixed_gateways.json");          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0);          MockHelper.mockProviderObserver(provider); @@ -140,7 +140,7 @@ public class GatewaysManagerTest {      @Test      public void TestGetPosition_VpnProfileExtistingOpenvpn_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, "ptdemo_three_mixed_gateways.json");          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0);          MockHelper.mockProviderObserver(provider); @@ -157,7 +157,7 @@ public class GatewaysManagerTest {      @Test      public void TestGetPosition_VpnProfileDifferentIp_returnMinusOne() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, "ptdemo_three_mixed_gateways.json");          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0);          MockHelper.mockProviderObserver(provider); @@ -174,7 +174,7 @@ public class GatewaysManagerTest {      @Test      public void TestGetPosition_VpnProfileMoscow_returnOne() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, "ptdemo_three_mixed_gateways.json");          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(1);          MockHelper.mockProviderObserver(provider); @@ -191,7 +191,7 @@ public class GatewaysManagerTest {      @Test      public void TestSelectN_selectFirstObfs4Connection_returnThirdGateway() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, "ptdemo_two_openvpn_one_pt_gateways.json"); +        Provider provider = getProvider(null, null, null, null, "ptdemo_two_openvpn_one_pt_gateways.json");          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway3 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(2); diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java index dde0601d..1120c0da 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -25,6 +25,7 @@ import android.os.Bundle;  import android.text.TextUtils;  import org.json.JSONException; +import org.json.JSONObject;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -35,10 +36,13 @@ import org.powermock.core.classloader.annotations.PrepareForTest;  import org.powermock.modules.junit4.PowerMockRunner;  import java.io.IOException; +import java.net.UnknownHostException;  import java.security.NoSuchAlgorithmException;  import java.security.cert.CertificateEncodingException; +import okhttp3.OkHttpClient;  import se.leap.bitmaskclient.BuildConfig; +import se.leap.bitmaskclient.OkHttpClientGenerator;  import se.leap.bitmaskclient.Provider;  import se.leap.bitmaskclient.ProviderAPI;  import se.leap.bitmaskclient.ProviderApiConnector; @@ -48,6 +52,13 @@ import se.leap.bitmaskclient.testutils.MockSharedPreferences;  import se.leap.bitmaskclient.utils.ConfigHelper;  import se.leap.bitmaskclient.utils.PreferenceHelper; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when;  import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;  import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;  import static se.leap.bitmaskclient.ProviderAPI.ERRORS; @@ -56,6 +67,7 @@ import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_FETCH_EIP_SERVICE_CERTIFICATE_INVALID;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_MICONFIGURED_PROVIDER;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_UPDATED_CERTIFICATE; +import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_DNS_RESOLUTION_ERROR;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.NO_ERROR;  import static se.leap.bitmaskclient.testutils.MockHelper.mockBundle;  import static se.leap.bitmaskclient.testutils.MockHelper.mockClientGenerator; @@ -269,7 +281,7 @@ public class ProviderApiManagerTest {      @Test      public void test_handleIntentSetupProvider_preseededProviderAndCA_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { -        Provider provider = getProvider(null ,"outdated_cert.pem", null, null); +        Provider provider = getProvider(null ,null, "outdated_cert.pem", null, null);          mockProviderApiConnector(NO_ERROR);          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); @@ -386,7 +398,7 @@ public class ProviderApiManagerTest {      @Test      public void test_handleIntentSetupProvider_outdatedPreseededProviderAndCA_successfulConfiguration() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { -        Provider provider = getProvider(null, null, "riseup_net_outdated_config.json", null); +        Provider provider = getProvider(null, null, null, "riseup_net_outdated_config.json", null);          mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(NO_ERROR); diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index 481c87cb..7a50b9ce 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -21,6 +21,7 @@ import java.io.File;  import java.io.FileNotFoundException;  import java.io.IOException;  import java.io.InputStream; +import java.net.UnknownHostException;  import java.security.NoSuchAlgorithmException;  import java.security.cert.CertificateEncodingException;  import java.security.cert.X509Certificate; @@ -434,14 +435,23 @@ public class MockHelper {          BackendMockProvider.provideBackendResponsesFor(errorCase);      } -    public static OkHttpClientGenerator mockClientGenerator() { +    public static OkHttpClientGenerator mockClientGenerator(boolean resolveDNS) throws UnknownHostException {          OkHttpClientGenerator mockClientGenerator = mock(OkHttpClientGenerator.class); -        OkHttpClient mockedOkHttpClient = mock(OkHttpClient.class); +        OkHttpClient mockedOkHttpClient = mock(OkHttpClient.class, RETURNS_DEEP_STUBS);          when(mockClientGenerator.initCommercialCAHttpClient(any(JSONObject.class))).thenReturn(mockedOkHttpClient);          when(mockClientGenerator.initSelfSignedCAHttpClient(anyString(), any(JSONObject.class))).thenReturn(mockedOkHttpClient); +        if (resolveDNS) { +            when(mockedOkHttpClient.dns().lookup(anyString())).thenReturn(new ArrayList<>()); +        } else { +            when(mockedOkHttpClient.dns().lookup(anyString())).thenThrow(new UnknownHostException()); +        }          return mockClientGenerator;      } +    public static OkHttpClientGenerator mockClientGenerator() throws UnknownHostException { +        return mockClientGenerator(true); +    } +      public static Resources mockResources(InputStream inputStream) throws IOException, JSONException {          Resources mockedResources = mock(Resources.class, RETURNS_DEEP_STUBS);          JSONObject errorMessages = new JSONObject(TestSetupHelper.getInputAsString(inputStream));  | 
