Add fallback static DNS resolver.
This commit is contained in:
parent
2483a92975
commit
56a8451d07
12 changed files with 198 additions and 39 deletions
|
@ -7,6 +7,7 @@ apply from: 'translations.gradle'
|
|||
apply plugin: 'org.jetbrains.kotlin.android'
|
||||
apply plugin: 'app.cash.exhaustive'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply from: 'static-ips.gradle'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
|
@ -186,6 +187,14 @@ android {
|
|||
buildConfigField "String[]", "SIGNAL_SFU_INTERNAL_URLS", "new String[]{\"https://sfu.test.voip.signal.org\", \"https://sfu.staging.voip.signal.org\"}"
|
||||
buildConfigField "String", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\""
|
||||
buildConfigField "int", "CONTENT_PROXY_PORT", "443"
|
||||
buildConfigField "String[]", "SIGNAL_SERVICE_IPS", service_ips
|
||||
buildConfigField "String[]", "SIGNAL_STORAGE_IPS", storage_ips
|
||||
buildConfigField "String[]", "SIGNAL_CDN_IPS", cdn_ips
|
||||
buildConfigField "String[]", "SIGNAL_CDN2_IPS", cdn2_ips
|
||||
buildConfigField "String[]", "SIGNAL_CDS_IPS", cds_ips
|
||||
buildConfigField "String[]", "SIGNAL_KBS_IPS", kbs_ips
|
||||
buildConfigField "String[]", "SIGNAL_SFU_IPS", sfu_ips
|
||||
buildConfigField "String[]", "SIGNAL_CONTENT_PROXY_IPS", content_proxy_ips
|
||||
buildConfigField "String", "SIGNAL_AGENT", "\"OWA\""
|
||||
buildConfigField "String", "CDSH_PUBLIC_KEY", "\"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74\""
|
||||
buildConfigField "String", "CDSH_CODE_HASH", "\"2f79dc6c1599b71c70fc2d14f3ea2e3bc65134436eb87011c88845b137af673a\""
|
||||
|
|
|
@ -5,6 +5,8 @@ import androidx.annotation.NonNull;
|
|||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.util.NetworkUtil;
|
||||
import org.xbill.DNS.ARecord;
|
||||
import org.xbill.DNS.Lookup;
|
||||
import org.xbill.DNS.Record;
|
||||
|
@ -14,6 +16,7 @@ import org.xbill.DNS.Type;
|
|||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import okhttp3.Dns;
|
||||
|
|
|
@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.net;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.util.NetworkUtil;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
@ -36,10 +38,10 @@ public class SequentialDns implements Dns {
|
|||
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, String.format(Locale.ENGLISH, "Failed to resolve %s using %s. Continuing. Network Type: %s", hostname, dns.getClass().getSimpleName(), NetworkUtil.getNetworkTypeDescriptor(ApplicationDependencies.getApplication())));
|
||||
}
|
||||
}
|
||||
Log.w(TAG, "Failed to resolve using any DNS.");
|
||||
Log.w(TAG, "Failed to resolve using any DNS. Network Type: " + NetworkUtil.getNetworkTypeDescriptor(ApplicationDependencies.getApplication()));
|
||||
throw new UnknownHostException(hostname);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.thoughtcrime.securesms.net
|
||||
|
||||
import okhttp3.Dns
|
||||
import java.net.InetAddress
|
||||
import java.net.UnknownHostException
|
||||
|
||||
/**
|
||||
* A super simple [Dns] implementation that maps hostnames to a static IP addresses.
|
||||
*/
|
||||
class StaticDns(private val hostnameMap: Map<String, Set<String>>) : Dns {
|
||||
|
||||
@Throws(UnknownHostException::class)
|
||||
override fun lookup(hostname: String): List<InetAddress> {
|
||||
val ips = hostnameMap[hostname]
|
||||
|
||||
return if (ips != null && ips.isNotEmpty()) {
|
||||
listOf(InetAddress.getByName(ips.random()))
|
||||
} else {
|
||||
throw UnknownHostException(hostname)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor
|
|||
import org.thoughtcrime.securesms.net.RemoteDeprecationDetectorInterceptor
|
||||
import org.thoughtcrime.securesms.net.SequentialDns
|
||||
import org.thoughtcrime.securesms.net.StandardUserAgentInterceptor
|
||||
import org.thoughtcrime.securesms.net.StaticDns
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
import org.whispersystems.libsignal.util.guava.Optional
|
||||
|
@ -38,7 +39,26 @@ class SignalServiceNetworkAccess(context: Context) {
|
|||
private val TAG = Log.tag(SignalServiceNetworkAccess::class.java)
|
||||
|
||||
@JvmField
|
||||
val DNS: Dns = SequentialDns(Dns.SYSTEM, CustomDns("1.1.1.1"))
|
||||
val DNS: Dns = SequentialDns(
|
||||
Dns.SYSTEM,
|
||||
CustomDns("1.1.1.1"),
|
||||
StaticDns(
|
||||
mapOf(
|
||||
BuildConfig.SIGNAL_URL.stripProtocol() to BuildConfig.SIGNAL_SERVICE_IPS.toSet(),
|
||||
BuildConfig.STORAGE_URL.stripProtocol() to BuildConfig.SIGNAL_STORAGE_IPS.toSet(),
|
||||
BuildConfig.SIGNAL_CDN_URL.stripProtocol() to BuildConfig.SIGNAL_CDN_IPS.toSet(),
|
||||
BuildConfig.SIGNAL_CDN2_URL.stripProtocol() to BuildConfig.SIGNAL_CDN2_IPS.toSet(),
|
||||
BuildConfig.SIGNAL_CONTACT_DISCOVERY_URL.stripProtocol() to BuildConfig.SIGNAL_CDS_IPS.toSet(),
|
||||
BuildConfig.SIGNAL_KEY_BACKUP_URL.stripProtocol() to BuildConfig.SIGNAL_KBS_IPS.toSet(),
|
||||
BuildConfig.SIGNAL_SFU_URL.stripProtocol() to BuildConfig.SIGNAL_SFU_IPS.toSet(),
|
||||
BuildConfig.CONTENT_PROXY_HOST.stripProtocol() to BuildConfig.SIGNAL_CONTENT_PROXY_IPS.toSet(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private fun String.stripProtocol(): String {
|
||||
return this.removePrefix("https://")
|
||||
}
|
||||
|
||||
private const val COUNTRY_CODE_EGYPT = 20
|
||||
private const val COUNTRY_CODE_UAE = 971
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.util;
|
|||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
@ -37,6 +38,42 @@ public final class NetworkUtil {
|
|||
return useLowBandwidthCalling(context, networkAdapter) ? CallManager.BandwidthMode.LOW : CallManager.BandwidthMode.NORMAL;
|
||||
}
|
||||
|
||||
public static String getNetworkTypeDescriptor(@NonNull Context context) {
|
||||
NetworkInfo info = getNetworkInfo(context);
|
||||
if (info == null || !info.isConnected()) {
|
||||
return "NOT CONNECTED";
|
||||
} else if (info.getType() == ConnectivityManager.TYPE_WIFI) {
|
||||
return "WIFI";
|
||||
} else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
|
||||
int networkType = info.getSubtype();
|
||||
switch (networkType) {
|
||||
case TelephonyManager.NETWORK_TYPE_GPRS: return "MOBILE - GPRS";
|
||||
case TelephonyManager.NETWORK_TYPE_EDGE: return "MOBILE - EDGE";
|
||||
case TelephonyManager.NETWORK_TYPE_CDMA: return "MOBILE - CDMA";
|
||||
case TelephonyManager.NETWORK_TYPE_1xRTT: return "MOBILE - 1xRTT";
|
||||
case TelephonyManager.NETWORK_TYPE_IDEN: return "MOBILE - IDEN";
|
||||
case TelephonyManager.NETWORK_TYPE_GSM: return "MOBILE - GSM";
|
||||
case TelephonyManager.NETWORK_TYPE_UMTS: return "MOBILE - UMTS";
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_0: return "MOBILE - EVDO_0";
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_A: return "MOBILE - EVDO_A";
|
||||
case TelephonyManager.NETWORK_TYPE_HSDPA: return "MOBILE - HSDPA";
|
||||
case TelephonyManager.NETWORK_TYPE_HSUPA: return "MOBILE - HSUPA";
|
||||
case TelephonyManager.NETWORK_TYPE_HSPA: return "MOBILE - HSPA";
|
||||
case TelephonyManager.NETWORK_TYPE_EVDO_B: return "MOBILE - EVDO_B";
|
||||
case TelephonyManager.NETWORK_TYPE_EHRPD: return "MOBILE - EHRDP";
|
||||
case TelephonyManager.NETWORK_TYPE_HSPAP: return "MOBILE - HSPAP";
|
||||
case TelephonyManager.NETWORK_TYPE_TD_SCDMA: return "MOBILE - TD_SCDMA";
|
||||
case TelephonyManager.NETWORK_TYPE_LTE: return "MOBILE - LTE";
|
||||
case TelephonyManager.NETWORK_TYPE_IWLAN: return "MOBILE - IWLAN";
|
||||
case 19: return "MOBILE - LTE_CA";
|
||||
case TelephonyManager.NETWORK_TYPE_NR: return "MOBILE - NR";
|
||||
default: return "MOBILE - OTHER";
|
||||
}
|
||||
} else {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean useLowBandwidthCalling(@NonNull Context context, @NonNull PeerConnection.AdapterType networkAdapter) {
|
||||
switch (SignalStore.settings().getCallBandwidthMode()) {
|
||||
case HIGH_ON_WIFI:
|
||||
|
|
8
app/static-ips.gradle
Normal file
8
app/static-ips.gradle
Normal file
|
@ -0,0 +1,8 @@
|
|||
ext.service_ips='new String[]{"76.223.92.165","13.248.212.111"}'
|
||||
ext.storage_ips='new String[]{"142.251.40.179"}'
|
||||
ext.cdn_ips='new String[]{"65.8.198.46","65.8.198.39","65.8.198.54","65.8.198.118"}'
|
||||
ext.cdn2_ips='new String[]{"104.18.28.74","104.18.29.74"}'
|
||||
ext.cds_ips='new String[]{"20.62.208.25"}'
|
||||
ext.kbs_ips='new String[]{"20.85.156.233"}'
|
||||
ext.sfu_ips='new String[]{"54.152.177.76","52.6.24.145"}'
|
||||
ext.content_proxy_ips='new String[]{"107.178.250.75"}'
|
|
@ -1,6 +1,7 @@
|
|||
import groovy.io.FileType
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.SimpleType
|
||||
import org.signal.StaticIpResolver
|
||||
|
||||
ext {
|
||||
autoResConfig = this.&autoResConfig
|
||||
|
@ -129,8 +130,25 @@ task postTranslateQa {
|
|||
mustRunAfter excludeNonTranslatables
|
||||
}
|
||||
|
||||
task postTranslateIpFetch {
|
||||
group 'Translate'
|
||||
description 'Fetches static IPs for core hosts and writes them to static-ips.gradle'
|
||||
doLast {
|
||||
new File(projectDir, "static-ips.gradle").text = """
|
||||
ext.service_ips='${StaticIpResolver.resolveToBuildConfig("chat.signal.org")}'
|
||||
ext.storage_ips='${StaticIpResolver.resolveToBuildConfig("storage.signal.org")}'
|
||||
ext.cdn_ips='${StaticIpResolver.resolveToBuildConfig("cdn.signal.org")}'
|
||||
ext.cdn2_ips='${StaticIpResolver.resolveToBuildConfig("cdn2.signal.org")}'
|
||||
ext.cds_ips='${StaticIpResolver.resolveToBuildConfig("api.directory.signal.org")}'
|
||||
ext.kbs_ips='${StaticIpResolver.resolveToBuildConfig("api.backup.signal.org")}'
|
||||
ext.sfu_ips='${StaticIpResolver.resolveToBuildConfig("sfu.voip.signal.org")}'
|
||||
ext.content_proxy_ips='${StaticIpResolver.resolveToBuildConfig("contentproxy.signal.org")}'
|
||||
""".stripIndent().trim()
|
||||
}
|
||||
}
|
||||
|
||||
task translate {
|
||||
group 'Translate'
|
||||
description 'Pull translations and post-process for ellipsis, apostrophes and non-translatables.'
|
||||
dependsOn pullTranslations, replaceEllipsis, cleanApostropheErrors, excludeNonTranslatables, postTranslateQa
|
||||
dependsOn pullTranslations, replaceEllipsis, cleanApostropheErrors, excludeNonTranslatables, postTranslateIpFetch, postTranslateQa
|
||||
}
|
||||
|
|
10
buildSrc/build.gradle
Normal file
10
buildSrc/build.gradle
Normal file
|
@ -0,0 +1,10 @@
|
|||
apply plugin: 'java-gradle-plugin'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation libs.dnsjava
|
||||
}
|
2
buildSrc/settings.gradle
Normal file
2
buildSrc/settings.gradle
Normal file
|
@ -0,0 +1,2 @@
|
|||
enableFeaturePreview('VERSION_CATALOGS')
|
||||
apply from: '../dependencies.gradle'
|
63
buildSrc/src/main/java/org/signal/StaticIpResolver.java
Normal file
63
buildSrc/src/main/java/org/signal/StaticIpResolver.java
Normal file
|
@ -0,0 +1,63 @@
|
|||
package org.signal;
|
||||
|
||||
import org.gradle.internal.impldep.org.eclipse.jgit.annotations.NonNull;
|
||||
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.Type;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class StaticIpResolver {
|
||||
|
||||
private StaticIpResolver() {}
|
||||
|
||||
public static String resolveToBuildConfig(String hostName) {
|
||||
String[] ips = resolve(hostName);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("new String[]{");
|
||||
for (int i = 0; i < ips.length; i++) {
|
||||
builder.append("\"").append(ips[i]).append("\"");
|
||||
if (i < ips.length - 1) {
|
||||
builder.append(",");
|
||||
}
|
||||
}
|
||||
return builder.append("}").toString();
|
||||
}
|
||||
|
||||
private static String[] resolve(String hostName) {
|
||||
try {
|
||||
Resolver resolver = new SimpleResolver("1.1.1.1");
|
||||
Lookup lookup = doLookup(hostName);
|
||||
|
||||
lookup.setResolver(resolver);
|
||||
|
||||
Record[] records = lookup.run();
|
||||
|
||||
if (records != null) {
|
||||
return Arrays.stream(records)
|
||||
.filter(r -> r.getType() == Type.A)
|
||||
.map(r -> (ARecord) r)
|
||||
.map(ARecord::getAddress)
|
||||
.map(InetAddress::getHostAddress)
|
||||
.toArray(String[]::new);
|
||||
} else {
|
||||
throw new IllegalStateException("Failed to resolve host! " + hostName);
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
throw new IllegalStateException("Failed to resolve host! " + hostName);
|
||||
}
|
||||
}
|
||||
|
||||
private static @NonNull Lookup doLookup(@NonNull String hostname) throws UnknownHostException {
|
||||
try {
|
||||
return new Lookup(hostname);
|
||||
} catch (Throwable e) {
|
||||
throw new UnknownHostException();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue