Skip to content

Commit

Permalink
Add DNS fallback system.
Browse files Browse the repository at this point in the history
  • Loading branch information
greyson-signal committed Apr 3, 2020
1 parent d6000af commit 711715c
Show file tree
Hide file tree
Showing 15 changed files with 207 additions and 20 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
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;

Expand Down Expand Up @@ -43,6 +44,7 @@ protected GiphyLoader(@NonNull Context context, @Nullable String searchString) {
this.client = new OkHttpClient.Builder()
.proxySelector(new ContentProxySelector())
.addInterceptor(new UserAgentInterceptor())
.dns(SignalServiceNetworkAccess.DNS)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
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;

Expand Down Expand Up @@ -46,6 +48,7 @@ public Factory() {
.addInterceptor(new UserAgentInterceptor())
.addNetworkInterceptor(new ContentProxySafetyInterceptor())
.addNetworkInterceptor(new PaddedHeadersInterceptor())
.dns(SignalServiceNetworkAccess.DNS)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import org.thoughtcrime.securesms.net.ContentProxySelector;
import org.thoughtcrime.securesms.net.UserAgentInterceptor;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;

import java.io.InputStream;

Expand Down Expand Up @@ -48,6 +49,7 @@ private static OkHttpClient getInternalClient() {
internalClient = new OkHttpClient.Builder()
.proxySelector(new ContentProxySelector())
.addInterceptor(new UserAgentInterceptor())
.dns(SignalServiceNetworkAccess.DNS)
.build();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

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;
Expand All @@ -23,7 +22,6 @@
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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;

Expand Down Expand Up @@ -88,7 +89,7 @@ public void submitLog(@NonNull List<LogLine> lines, Callback<Optional<String>> c
}

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();

Expand Down
62 changes: 62 additions & 0 deletions app/src/main/java/org/thoughtcrime/securesms/net/CustomDns.java
Original file line number Diff line number Diff line change
@@ -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<InetAddress> 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<InetAddress> 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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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<Dns> dnsList;

public SequentialDns(Dns... dns) {
this.dnsList = Arrays.asList(dns);
}

@Override
public @NonNull List<InetAddress> lookup(@NonNull String hostname) throws UnknownHostException {
for (Dns dns : dnsList) {
try {
List<InetAddress> 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);
}
}
35 changes: 35 additions & 0 deletions app/src/main/java/org/thoughtcrime/securesms/net/StaticDns.java
Original file line number Diff line number Diff line change
@@ -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<String, String> hostnameMap;

public StaticDns(@NonNull Map<String, String> hostnameMap) {
this.hostnameMap = hostnameMap;
}

@Override
public @NonNull List<InetAddress> 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);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
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;
Expand All @@ -25,6 +28,7 @@

import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec;
import okhttp3.Dns;
import okhttp3.Interceptor;
import okhttp3.TlsVersion;

Expand All @@ -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";
Expand Down Expand Up @@ -146,6 +152,8 @@ public SignalServiceNetworkAccess(Context context) {
final SignalStorageUrl qatarGoogleStorage = new SignalStorageUrl("https://www.google.com.qa/storage", SERVICE_REFLECTOR_HOST, trustStore, GMAIL_CONNECTION_SPEC);

final List<Interceptor> interceptors = Collections.singletonList(new UserAgentInterceptor());
final Optional<Dns> dns = Optional.of(DNS);

final byte[] zkGroupServerPublicParams;

try {
Expand All @@ -161,6 +169,7 @@ public SignalServiceNetworkAccess(Context context) {
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},
Expand All @@ -169,6 +178,7 @@ public SignalServiceNetworkAccess(Context context) {
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},
Expand All @@ -177,6 +187,7 @@ public SignalServiceNetworkAccess(Context context) {
new SignalKeyBackupServiceUrl[] {omanGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs},
new SignalStorageUrl[] {omanGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage},
interceptors,
dns,
zkGroupServerPublicParams));


Expand All @@ -186,6 +197,7 @@ public SignalServiceNetworkAccess(Context context) {
new SignalKeyBackupServiceUrl[] {qatarGoogleKbs, baseGoogleKbs, baseAndroidKbs, mapsOneAndroidKbs, mapsTwoAndroidKbs, mailAndroidKbs},
new SignalStorageUrl[] {qatarGoogleStorage, baseGoogleStorage, baseAndroidStorage, mapsOneAndroidStorage, mapsTwoAndroidStorage, mailAndroidStorage},
interceptors,
dns,
zkGroupServerPublicParams));
}};

Expand All @@ -195,6 +207,7 @@ public SignalServiceNetworkAccess(Context context) {
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]);
Expand Down
3 changes: 3 additions & 0 deletions app/witness-verifications.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'],

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ public SignalServiceMessagePipe createMessagePipe() {
urls.getSignalServiceUrls()[0].getTrustStore(),
Optional.of(credentialsProvider), signalAgent, connectivityListener,
sleepTimer,
urls.getNetworkInterceptors());
urls.getNetworkInterceptors(),
urls.getDns());

return new SignalServiceMessagePipe(webSocket, Optional.of(credentialsProvider), clientZkProfile);
}
Expand All @@ -231,7 +232,8 @@ public SignalServiceMessagePipe createUnidentifiedMessagePipe() {
urls.getSignalServiceUrls()[0].getTrustStore(),
Optional.<CredentialsProvider>absent(), signalAgent, connectivityListener,
sleepTimer,
urls.getNetworkInterceptors());
urls.getNetworkInterceptors(),
urls.getDns());

return new SignalServiceMessagePipe(webSocket, Optional.of(credentialsProvider), clientZkProfile);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -12,6 +15,7 @@ public final class SignalServiceConfiguration {
private final SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls;
private final SignalStorageUrl[] signalStorageUrls;
private final List<Interceptor> networkInterceptors;
private final Optional<Dns> dns;
private final byte[] zkGroupServerPublicParams;

public SignalServiceConfiguration(SignalServiceUrl[] signalServiceUrls,
Expand All @@ -20,6 +24,7 @@ public SignalServiceConfiguration(SignalServiceUrl[] signalServiceUrls,
SignalKeyBackupServiceUrl[] signalKeyBackupServiceUrls,
SignalStorageUrl[] signalStorageUrls,
List<Interceptor> networkInterceptors,
Optional<Dns> dns,
byte[] zkGroupServerPublicParams)
{
this.signalServiceUrls = signalServiceUrls;
Expand All @@ -28,6 +33,7 @@ public SignalServiceConfiguration(SignalServiceUrl[] signalServiceUrls,
this.signalKeyBackupServiceUrls = signalKeyBackupServiceUrls;
this.signalStorageUrls = signalStorageUrls;
this.networkInterceptors = networkInterceptors;
this.dns = dns;
this.zkGroupServerPublicParams = zkGroupServerPublicParams;
}

Expand Down Expand Up @@ -55,6 +61,10 @@ public List<Interceptor> getNetworkInterceptors() {
return networkInterceptors;
}

public Optional<Dns> getDns() {
return dns;
}

public byte[] getZkGroupServerPublicParams() {
return zkGroupServerPublicParams;
}
Expand Down

0 comments on commit 711715c

Please sign in to comment.