diff --git a/app/build.gradle b/app/build.gradle index 5ac9bd28f0..4bc5742484 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -341,6 +341,7 @@ dependencies { exclude group: 'com.fasterxml.jackson.core' exclude group: 'org.freemarker' } + implementation 'dnsjava:dnsjava:2.1.9' flipperImplementation 'com.facebook.flipper:flipper:0.32.2' flipperImplementation 'com.facebook.soloader:soloader:0.8.2' diff --git a/app/src/main/java/org/thoughtcrime/securesms/giph/net/GiphyLoader.java b/app/src/main/java/org/thoughtcrime/securesms/giph/net/GiphyLoader.java index f85d2ca281..ea6a2e3056 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/giph/net/GiphyLoader.java +++ b/app/src/main/java/org/thoughtcrime/securesms/giph/net/GiphyLoader.java @@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.giph.model.GiphyImage; import org.thoughtcrime.securesms.giph.model.GiphyResponse; import org.thoughtcrime.securesms.net.ContentProxySelector; import org.thoughtcrime.securesms.net.UserAgentInterceptor; +import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.util.AsyncLoader; import org.thoughtcrime.securesms.util.JsonUtils; @@ -43,6 +44,7 @@ public abstract class GiphyLoader extends AsyncLoader> { this.client = new OkHttpClient.Builder() .proxySelector(new ContentProxySelector()) .addInterceptor(new UserAgentInterceptor()) + .dns(SignalServiceNetworkAccess.DNS) .build(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/ChunkedImageUrlLoader.java b/app/src/main/java/org/thoughtcrime/securesms/glide/ChunkedImageUrlLoader.java index 08e9fa1bfb..deb9c0d6cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/ChunkedImageUrlLoader.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/ChunkedImageUrlLoader.java @@ -11,7 +11,9 @@ import com.bumptech.glide.load.model.MultiModelLoaderFactory; import org.thoughtcrime.securesms.giph.model.ChunkedImageUrl; import org.thoughtcrime.securesms.net.ContentProxySafetyInterceptor; import org.thoughtcrime.securesms.net.ContentProxySelector; +import org.thoughtcrime.securesms.net.CustomDns; import org.thoughtcrime.securesms.net.UserAgentInterceptor; +import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import java.io.InputStream; @@ -46,6 +48,7 @@ public class ChunkedImageUrlLoader implements ModelLoader { internalClient = new OkHttpClient.Builder() .proxySelector(new ContentProxySelector()) .addInterceptor(new UserAgentInterceptor()) + .dns(SignalServiceNetworkAccess.DNS) .build(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java b/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java index e5aab21787..49a5ceca90 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/linkpreview/LinkPreviewRepository.java @@ -12,7 +12,6 @@ import com.bumptech.glide.request.FutureTarget; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.UriAttachment; -import org.thoughtcrime.securesms.blurhash.BlurHash; import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.giph.model.ChunkedImageUrl; @@ -23,7 +22,6 @@ import org.thoughtcrime.securesms.net.CompositeRequestController; import org.thoughtcrime.securesms.net.ContentProxySafetyInterceptor; import org.thoughtcrime.securesms.net.ContentProxySelector; import org.thoughtcrime.securesms.net.RequestController; -import org.thoughtcrime.securesms.net.UserAgentInterceptor; import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.stickers.StickerRemoteUri; import org.thoughtcrime.securesms.stickers.StickerUrl; diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/SubmitDebugLogRepository.java b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/SubmitDebugLogRepository.java index b0c8aa6310..8e2f359e22 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/SubmitDebugLogRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/SubmitDebugLogRepository.java @@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logsubmit.util.Scrubber; import org.thoughtcrime.securesms.net.UserAgentInterceptor; +import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; import org.whispersystems.libsignal.util.guava.Optional; @@ -88,7 +89,7 @@ public class SubmitDebugLogRepository { } try { - OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new UserAgentInterceptor()).build(); + OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new UserAgentInterceptor()).dns(SignalServiceNetworkAccess.DNS).build(); Response response = client.newCall(new Request.Builder().url(API_ENDPOINT).get().build()).execute(); ResponseBody body = response.body(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/CustomDns.java b/app/src/main/java/org/thoughtcrime/securesms/net/CustomDns.java new file mode 100644 index 0000000000..d025fba212 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/net/CustomDns.java @@ -0,0 +1,62 @@ +package org.thoughtcrime.securesms.net; + +import androidx.annotation.NonNull; + +import com.annimon.stream.Stream; + +import org.xbill.DNS.ARecord; +import org.xbill.DNS.Lookup; +import org.xbill.DNS.Record; +import org.xbill.DNS.Resolver; +import org.xbill.DNS.SimpleResolver; +import org.xbill.DNS.TextParseException; +import org.xbill.DNS.Type; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; + +import okhttp3.Dns; + +/** + * A {@link Dns} implementation that specifies the hostname of a specific DNS. + */ +public class CustomDns implements Dns { + + private final String dnsHostname; + + public CustomDns(@NonNull String dnsHostname) { + this.dnsHostname = dnsHostname; + } + + @Override + public @NonNull List lookup(@NonNull String hostname) throws UnknownHostException { + Resolver resolver = new SimpleResolver(dnsHostname); + Lookup lookup = doLookup(hostname); + + lookup.setResolver(resolver); + + Record[] records = lookup.run(); + + if (records != null) { + List ipv4Addresses = Stream.of(records) + .filter(r -> r.getType() == Type.A) + .map(r -> (ARecord) r) + .map(ARecord::getAddress) + .toList(); + if (ipv4Addresses.size() > 0) { + return ipv4Addresses; + } + } + + throw new UnknownHostException(hostname); + } + + private static @NonNull Lookup doLookup(@NonNull String hostname) throws UnknownHostException { + try { + return new Lookup(hostname); + } catch (TextParseException e) { + throw new UnknownHostException(); + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/SequentialDns.java b/app/src/main/java/org/thoughtcrime/securesms/net/SequentialDns.java new file mode 100644 index 0000000000..372bf3ce1b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/net/SequentialDns.java @@ -0,0 +1,45 @@ +package org.thoughtcrime.securesms.net; + +import androidx.annotation.NonNull; + +import org.thoughtcrime.securesms.logging.Log; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import okhttp3.Dns; + +/** + * Iterates through an ordered list of {@link Dns}, trying each one in sequence. + */ +public class SequentialDns implements Dns { + + private static final String TAG = Log.tag(SequentialDns.class); + + private List dnsList; + + public SequentialDns(Dns... dns) { + this.dnsList = Arrays.asList(dns); + } + + @Override + public @NonNull List lookup(@NonNull String hostname) throws UnknownHostException { + for (Dns dns : dnsList) { + try { + List addresses = dns.lookup(hostname); + if (addresses.size() > 0) { + return addresses; + } else { + Log.w(TAG, String.format(Locale.ENGLISH, "Didn't find any addresses for %s using %s. Continuing.", hostname, dns.getClass().getSimpleName())); + } + } catch (UnknownHostException e) { + Log.w(TAG, String.format(Locale.ENGLISH, "Failed to resolve %s using %s. Continuing.", hostname, dns.getClass().getSimpleName())); + } + } + Log.w(TAG, "Failed to resolve using any DNS."); + throw new UnknownHostException(hostname); + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/StaticDns.java b/app/src/main/java/org/thoughtcrime/securesms/net/StaticDns.java new file mode 100644 index 0000000000..18d00507fe --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/net/StaticDns.java @@ -0,0 +1,35 @@ +package org.thoughtcrime.securesms.net; + +import androidx.annotation.NonNull; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import okhttp3.Dns; + +/** + * A super simple {@link Dns} implementation that maps hostnames to a static IP addresses. + */ +public class StaticDns implements Dns { + + private final Map hostnameMap; + + public StaticDns(@NonNull Map hostnameMap) { + this.hostnameMap = hostnameMap; + } + + @Override + public @NonNull List lookup(@NonNull String hostname) throws UnknownHostException { + String ip = hostnameMap.get(hostname); + + if (ip != null) { + return Collections.singletonList(InetAddress.getByName(ip)); + } else { + throw new UnknownHostException(hostname); + } + + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java b/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java index 7216c7b17c..85dc9b45a5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java +++ b/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.java @@ -6,9 +6,12 @@ import android.content.Context; import androidx.annotation.Nullable; import org.thoughtcrime.securesms.BuildConfig; +import org.thoughtcrime.securesms.net.CustomDns; +import org.thoughtcrime.securesms.net.SequentialDns; import org.thoughtcrime.securesms.net.UserAgentInterceptor; import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.push.TrustStore; import org.whispersystems.signalservice.internal.configuration.SignalCdnUrl; import org.whispersystems.signalservice.internal.configuration.SignalContactDiscoveryUrl; @@ -25,6 +28,7 @@ import java.util.Map; import okhttp3.CipherSuite; import okhttp3.ConnectionSpec; +import okhttp3.Dns; import okhttp3.Interceptor; import okhttp3.TlsVersion; @@ -33,6 +37,8 @@ public class SignalServiceNetworkAccess { @SuppressWarnings("unused") private static final String TAG = SignalServiceNetworkAccess.class.getSimpleName(); + public static final Dns DNS = new SequentialDns(Dns.SYSTEM, new CustomDns("1.1.1.1")); + private static final String COUNTRY_CODE_EGYPT = "+20"; private static final String COUNTRY_CODE_UAE = "+971"; private static final String COUNTRY_CODE_OMAN = "+968"; @@ -146,6 +152,8 @@ public class SignalServiceNetworkAccess { final SignalStorageUrl qatarGoogleStorage = new SignalStorageUrl("https://www.google.com.qa/storage", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC); final List interceptors = Collections.singletonList(new UserAgentInterceptor()); + final Optional dns = Optional.of(DNS); + final byte[] zkGroupServerPublicParams; try { @@ -161,6 +169,7 @@ public class SignalServiceNetworkAccess { new SignalKeyBackupServiceUrl[] {egyptGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalStorageUrl[] {egyptGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, interceptors, + dns, zkGroupServerPublicParams)); put(COUNTRY_CODE_UAE, new SignalServiceConfiguration(new SignalServiceUrl[] {uaeGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService}, @@ -169,6 +178,7 @@ public class SignalServiceNetworkAccess { new SignalKeyBackupServiceUrl[] {uaeGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalStorageUrl[] {uaeGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, interceptors, + dns, zkGroupServerPublicParams)); put(COUNTRY_CODE_OMAN, new SignalServiceConfiguration(new SignalServiceUrl[] {omanGoogleService, baseAndroidService, baseGoogleService, mapsOneAndroidService, mapsTwoAndroidService, mailAndroidService}, @@ -177,6 +187,7 @@ public class SignalServiceNetworkAccess { new SignalKeyBackupServiceUrl[] {omanGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalStorageUrl[] {omanGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, interceptors, + dns, zkGroupServerPublicParams)); @@ -186,6 +197,7 @@ public class SignalServiceNetworkAccess { new SignalKeyBackupServiceUrl[] {qatarGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs}, new SignalStorageUrl[] {qatarGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage}, interceptors, + dns, zkGroupServerPublicParams)); }}; @@ -195,6 +207,7 @@ public class SignalServiceNetworkAccess { new SignalKeyBackupServiceUrl[] { new SignalKeyBackupServiceUrl(BuildConfig.SIGNAL_KEY_BACKUP_URL, new SignalServiceTrustStore(context)) }, new SignalStorageUrl[] {new SignalStorageUrl(BuildConfig.STORAGE_URL, new SignalServiceTrustStore(context))}, interceptors, + dns, zkGroupServerPublicParams); this.censoredCountries = this.censorshipConfiguration.keySet().toArray(new String[0]); diff --git a/app/witness-verifications.gradle b/app/witness-verifications.gradle index 3a51dd027a..387cf35000 100644 --- a/app/witness-verifications.gradle +++ b/app/witness-verifications.gradle @@ -330,6 +330,9 @@ dependencyVerification { ['com.tomergoldst.android:tooltips:1.0.6', '4c56697dd1ad64b8066535c61f961a6d901e7ae5d97ae27084ba40ad620349b6'], + ['dnsjava:dnsjava:2.1.9', + '072bba34267ffad8907c30a99a6b68f900782f3191454d278e395e289d478446'], + ['me.leolin:ShortcutBadger:1.1.16', 'e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774'], diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java index 74961c334e..6b32a17da5 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java @@ -221,7 +221,8 @@ public class SignalServiceMessageReceiver { urls.getSignalServiceUrls()[0].getTrustStore(), Optional.of(credentialsProvider), signalAgent, connectivityListener, sleepTimer, - urls.getNetworkInterceptors()); + urls.getNetworkInterceptors(), + urls.getDns()); return new SignalServiceMessagePipe(webSocket, Optional.of(credentialsProvider), clientZkProfile); } @@ -231,7 +232,8 @@ public class SignalServiceMessageReceiver { urls.getSignalServiceUrls()[0].getTrustStore(), Optional.absent(), signalAgent, connectivityListener, sleepTimer, - urls.getNetworkInterceptors()); + urls.getNetworkInterceptors(), + urls.getDns()); return new SignalServiceMessagePipe(webSocket, Optional.of(credentialsProvider), clientZkProfile); } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration.java index 97a1cbba44..5d92de9104 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/configuration/SignalServiceConfiguration.java @@ -1,7 +1,10 @@ package org.whispersystems.signalservice.internal.configuration; +import org.whispersystems.libsignal.util.guava.Optional; + import java.util.List; +import okhttp3.Dns; import okhttp3.Interceptor; public final class SignalServiceConfiguration { @@ -12,6 +15,7 @@ public final class SignalServiceConfiguration { private final SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls; private final SignalStorageUrl[] signalStorageUrls; private final List networkInterceptors; + private final Optional dns; private final byte[] zkGroupServerPublicParams; public SignalServiceConfiguration(SignalServiceUrl[] signalServiceUrls, @@ -20,6 +24,7 @@ public final class SignalServiceConfiguration { SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls, SignalStorageUrl[] signalStorageUrls, List networkInterceptors, + Optional dns, byte[] zkGroupServerPublicParams) { this.signalServiceUrls = signalServiceUrls; @@ -28,6 +33,7 @@ public final class SignalServiceConfiguration { this.signalKeyBackupServiceUrls = signalKeyBackupServiceUrls; this.signalStorageUrls = signalStorageUrls; this.networkInterceptors = networkInterceptors; + this.dns = dns; this.zkGroupServerPublicParams = zkGroupServerPublicParams; } @@ -55,6 +61,10 @@ public final class SignalServiceConfiguration { return networkInterceptors; } + public Optional getDns() { + return dns; + } + public byte[] getZkGroupServerPublicParams() { return zkGroupServerPublicParams; } diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java index eaa7e6ea5f..3ef5b477b1 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java @@ -106,6 +106,7 @@ import javax.net.ssl.X509TrustManager; import okhttp3.Call; import okhttp3.ConnectionSpec; import okhttp3.Credentials; +import okhttp3.Dns; import okhttp3.Interceptor; import okhttp3.MediaType; import okhttp3.MultipartBody; @@ -184,16 +185,16 @@ public class PushServiceSocket { private final SecureRandom random; private final ClientZkOperations clientZkOperations; - public PushServiceSocket(SignalServiceConfiguration signalServiceConfiguration, CredentialsProvider credentialsProvider, String signalAgent) { + public PushServiceSocket(SignalServiceConfiguration serviceConfig, CredentialsProvider credentialsProvider, String signalAgent) { this.credentialsProvider = credentialsProvider; this.signalAgent = signalAgent; - this.serviceClients = createServiceConnectionHolders(signalServiceConfiguration.getSignalServiceUrls(), signalServiceConfiguration.getNetworkInterceptors()); - this.cdnClients = createConnectionHolders(signalServiceConfiguration.getSignalCdnUrls(), signalServiceConfiguration.getNetworkInterceptors()); - this.contactDiscoveryClients = createConnectionHolders(signalServiceConfiguration.getSignalContactDiscoveryUrls(), signalServiceConfiguration.getNetworkInterceptors()); - this.keyBackupServiceClients = createConnectionHolders(signalServiceConfiguration.getSignalKeyBackupServiceUrls(), signalServiceConfiguration.getNetworkInterceptors()); - this.storageClients = createConnectionHolders(signalServiceConfiguration.getSignalStorageUrls(), signalServiceConfiguration.getNetworkInterceptors()); + this.serviceClients = createServiceConnectionHolders(serviceConfig.getSignalServiceUrls(), serviceConfig.getNetworkInterceptors(), serviceConfig.getDns()); + this.cdnClients = createConnectionHolders(serviceConfig.getSignalCdnUrls(), serviceConfig.getNetworkInterceptors(), serviceConfig.getDns()); + this.contactDiscoveryClients = createConnectionHolders(serviceConfig.getSignalContactDiscoveryUrls(), serviceConfig.getNetworkInterceptors(), serviceConfig.getDns()); + this.keyBackupServiceClients = createConnectionHolders(serviceConfig.getSignalKeyBackupServiceUrls(), serviceConfig.getNetworkInterceptors(), serviceConfig.getDns()); + this.storageClients = createConnectionHolders(serviceConfig.getSignalStorageUrls(), serviceConfig.getNetworkInterceptors(), serviceConfig.getDns()); this.random = new SecureRandom(); - this.clientZkOperations = FeatureFlags.ZK_GROUPS ? new ClientZkOperations(new ServerPublicParams(signalServiceConfiguration.getZkGroupServerPublicParams())) : null; + this.clientZkOperations = FeatureFlags.ZK_GROUPS ? new ClientZkOperations(new ServerPublicParams(serviceConfig.getZkGroupServerPublicParams())) : null; } public void requestSmsVerificationCode(boolean androidSmsRetriever, Optional captchaToken, Optional challenge) throws IOException { @@ -1349,29 +1350,32 @@ public class PushServiceSocket { throw new NonSuccessfulResponseCodeException("Response: " + response); } - private ServiceConnectionHolder[] createServiceConnectionHolders(SignalUrl[] urls, List interceptors) { + private ServiceConnectionHolder[] createServiceConnectionHolders(SignalUrl[] urls, + List interceptors, + Optional dns) + { List serviceConnectionHolders = new LinkedList<>(); for (SignalUrl url : urls) { - serviceConnectionHolders.add(new ServiceConnectionHolder(createConnectionClient(url, interceptors), - createConnectionClient(url, interceptors), + serviceConnectionHolders.add(new ServiceConnectionHolder(createConnectionClient(url, interceptors, dns), + createConnectionClient(url, interceptors, dns), url.getUrl(), url.getHostHeader())); } return serviceConnectionHolders.toArray(new ServiceConnectionHolder[0]); } - private ConnectionHolder[] createConnectionHolders(SignalUrl[] urls, List interceptors) { + private ConnectionHolder[] createConnectionHolders(SignalUrl[] urls, List interceptors, Optional dns) { List connectionHolders = new LinkedList<>(); for (SignalUrl url : urls) { - connectionHolders.add(new ConnectionHolder(createConnectionClient(url, interceptors), url.getUrl(), url.getHostHeader())); + connectionHolders.add(new ConnectionHolder(createConnectionClient(url, interceptors, dns), url.getUrl(), url.getHostHeader())); } return connectionHolders.toArray(new ConnectionHolder[0]); } - private OkHttpClient createConnectionClient(SignalUrl url, List interceptors) { + private OkHttpClient createConnectionClient(SignalUrl url, List interceptors, Optional dns) { try { TrustManager[] trustManagers = BlacklistingTrustManager.createFor(url.getTrustStore()); @@ -1380,7 +1384,8 @@ public class PushServiceSocket { OkHttpClient.Builder builder = new OkHttpClient.Builder() .sslSocketFactory(new Tls12SocketFactory(context.getSocketFactory()), (X509TrustManager)trustManagers[0]) - .connectionSpecs(url.getConnectionSpecs().or(Util.immutableList(ConnectionSpec.RESTRICTED_TLS))); + .connectionSpecs(url.getConnectionSpecs().or(Util.immutableList(ConnectionSpec.RESTRICTED_TLS))) + .dns(dns.or(Dns.SYSTEM)); for (Interceptor interceptor : interceptors) { builder.addInterceptor(interceptor); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/websocket/WebSocketConnection.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/websocket/WebSocketConnection.java index b61099557f..d32f1247cc 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/websocket/WebSocketConnection.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/websocket/WebSocketConnection.java @@ -33,6 +33,7 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import okhttp3.ConnectionSpec; +import okhttp3.Dns; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -60,6 +61,7 @@ public class WebSocketConnection extends WebSocketListener { private final ConnectivityListener listener; private final SleepTimer sleepTimer; private final List interceptors; + private final Optional dns; private WebSocket client; private KeepAliveSender keepAliveSender; @@ -72,7 +74,8 @@ public class WebSocketConnection extends WebSocketListener { String signalAgent, ConnectivityListener listener, SleepTimer timer, - List interceptors) + List interceptors, + Optional dns) { this.trustStore = trustStore; this.credentialsProvider = credentialsProvider; @@ -80,6 +83,7 @@ public class WebSocketConnection extends WebSocketListener { this.listener = listener; this.sleepTimer = timer; this.interceptors = interceptors; + this.dns = dns; this.attempts = 0; this.connected = false; @@ -108,6 +112,7 @@ public class WebSocketConnection extends WebSocketListener { .sslSocketFactory(new Tls12SocketFactory(socketFactory.first()), socketFactory.second()) .connectionSpecs(Util.immutableList(ConnectionSpec.RESTRICTED_TLS)) .readTimeout(KEEPALIVE_TIMEOUT_SECONDS + 10, TimeUnit.SECONDS) + .dns(dns.or(Dns.SYSTEM)) .connectTimeout(KEEPALIVE_TIMEOUT_SECONDS + 10, TimeUnit.SECONDS); for (Interceptor interceptor : interceptors) {