From 36d2ce3d1c02f3a2e522203b92cc6e98b562650f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 29 Dec 2022 22:31:02 +0100 Subject: draft DoH for bootstrapping --- .../providersetup/connectivity/DnsResolver.java | 94 +++++++++++++++++++--- .../connectivity/OkHttpClientGenerator.java | 29 ++++--- 2 files changed, 97 insertions(+), 26 deletions(-) (limited to 'app') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/DnsResolver.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/DnsResolver.java index 5655e7b7..b50c480d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/DnsResolver.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/DnsResolver.java @@ -1,25 +1,63 @@ -package se.leap.bitmaskclient.providersetup.connectivity; + package se.leap.bitmaskclient.providersetup.connectivity; -import androidx.annotation.NonNull; + import static java.net.InetAddress.getByName; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; + import android.util.Log; -import de.blinkt.openvpn.core.VpnStatus; -import okhttp3.Dns; -import se.leap.bitmaskclient.base.models.Provider; -import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.base.utils.IPAddress; + import androidx.annotation.NonNull; + + import java.net.InetAddress; + import java.net.UnknownHostException; + import java.util.ArrayList; + import java.util.List; + + import de.blinkt.openvpn.core.VpnStatus; + import okhttp3.Dns; + import okhttp3.HttpUrl; + import okhttp3.OkHttpClient; + import okhttp3.dnsoverhttps.DnsOverHttps; + import se.leap.bitmaskclient.base.models.Provider; + import se.leap.bitmaskclient.base.models.ProviderObservable; + import se.leap.bitmaskclient.base.utils.IPAddress; class DnsResolver implements Dns { + OkHttpClient dohHttpClient; + boolean forceDoH; + public DnsResolver(OkHttpClient dohHttpClient, boolean forceDoH) { + this.dohHttpClient = dohHttpClient; + this.forceDoH = forceDoH; + } + + @NonNull @Override public List lookup(@NonNull String hostname) throws UnknownHostException { + Log.d("DNS", "trying to resolve DNS for " + hostname); + try { + if (forceDoH) { + List list = lookupDoH(hostname); + for (InetAddress address : list) { + Log.d("DNS", "DoH ---> " + address.toString()); + } + return list; + } return Dns.SYSTEM.lookup(hostname); } catch (UnknownHostException e) { + e.printStackTrace(); + Log.e("DNS", "DoH via cloudflare failed"); + + // if not yet tried, do DNS over Https after normal DNS failed + if (!forceDoH) { + try { + return lookupDoH(hostname); + } catch (RuntimeException uhe) { + uhe.printStackTrace(); + } + } + + Log.d("DNS", "try hard coded IPs"); + // let's check if there's an hard-coded IP we can use ProviderObservable observable = ProviderObservable.getInstance(); Provider currentProvider; if (observable.getProviderForDns() != null) { @@ -39,4 +77,38 @@ class DnsResolver implements Dns { } } } + + private List lookupDoH(@NonNull String hostname) throws RuntimeException, UnknownHostException { + DnsOverHttps ahablitzDoHClient = new DnsOverHttps.Builder().client(dohHttpClient) + .url(HttpUrl.get("https://blitz.ahadns.com")) + .build(); + try { + Log.d("DNS", "DoH via blitz.ahadns.com"); + return ahablitzDoHClient.lookup(hostname); + } catch (UnknownHostException e) { + e.printStackTrace(); + Log.e("DNS", "DoH via blitz.ahadns.com failed"); + } + + DnsOverHttps googleDoHClient = new DnsOverHttps.Builder().client(dohHttpClient) + .url(HttpUrl.get("https://dns.google/dns-query")) + .bootstrapDnsHosts(getByName("8.8.4.4"), getByName("8.8.8.8")) + .build(); + try { + Log.d("DNS", "DoH via dns.google"); + return googleDoHClient.lookup(hostname); + } catch (UnknownHostException e) { + e.printStackTrace(); + Log.e("DNS", "DoH via dns.google failed"); + + } + + DnsOverHttps cloudFlareDoHClient = new DnsOverHttps.Builder().client(dohHttpClient) + .url(HttpUrl.get("https://1.1.1.1/dns-query")) + .bootstrapDnsHosts(getByName("1.1.1.1"), getByName("1.0.0.1")) + .build(); + + Log.d("DNS", "DoH via cloudflare 1.1.1.1"); + return cloudFlareDoHClient.lookup(hostname); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java index ea619263..97393551 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/connectivity/OkHttpClientGenerator.java @@ -17,8 +17,16 @@ package se.leap.bitmaskclient.providersetup.connectivity; +import static android.text.TextUtils.isEmpty; +import static se.leap.bitmaskclient.R.string.certificate_error; +import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; +import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message; +import static se.leap.bitmaskclient.R.string.keyChainAccessError; +import static se.leap.bitmaskclient.R.string.server_unreachable_message; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString; +import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; + import android.content.res.Resources; -import android.net.LocalSocketAddress; import android.os.Build; import androidx.annotation.NonNull; @@ -29,7 +37,6 @@ import org.json.JSONObject; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; -import java.net.SocketAddress; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStoreException; @@ -49,16 +56,6 @@ import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.TlsVersion; -import static android.text.TextUtils.isEmpty; -import static se.leap.bitmaskclient.R.string.certificate_error; -import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; -import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message; -import static se.leap.bitmaskclient.R.string.keyChainAccessError; -import static se.leap.bitmaskclient.R.string.proxy; -import static se.leap.bitmaskclient.R.string.server_unreachable_message; -import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString; - /** * Created by cyberta on 08.01.18. */ @@ -68,7 +65,7 @@ public class OkHttpClientGenerator { Resources resources; private final static String PROXY_HOST = "127.0.0.1"; - public OkHttpClientGenerator(/*SharedPreferences preferences,*/ Resources resources) { + public OkHttpClientGenerator(Resources resources) { this.resources = resources; } @@ -133,13 +130,15 @@ public class OkHttpClientGenerator { } else { sslCompatFactory = new TLSCompatSocketFactory(); } - sslCompatFactory.initSSLSocketFactory(clientBuilder); clientBuilder.cookieJar(getCookieJar()) .connectionSpecs(Collections.singletonList(spec)); - clientBuilder.dns(new DnsResolver()); + if (proxyPort != -1) { clientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, proxyPort))); } + + clientBuilder.dns(new DnsResolver(clientBuilder.build(), true)); + sslCompatFactory.initSSLSocketFactory(clientBuilder); return clientBuilder.build(); } -- cgit v1.2.3