From 1d8fa7e99dc1304ece611bff99d12f52981ab1f9 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Tue, 25 Jun 2019 21:17:32 +0200 Subject: Revert "Networkstack - let OS decide IPv4 or IPv6 (#267)" This reverts commit e6a15597904019f68c02e6fd8f61fb6de0b13324. If there is IPv6 available but the server doesn't listen to it, the connection will not be established --- .../java/de/pixart/messenger/utils/Resolver.java | 123 ++++++++++++++++++--- 1 file changed, 106 insertions(+), 17 deletions(-) (limited to 'src/main/java/de/pixart/messenger/utils/Resolver.java') diff --git a/src/main/java/de/pixart/messenger/utils/Resolver.java b/src/main/java/de/pixart/messenger/utils/Resolver.java index edde83088..2378c429e 100644 --- a/src/main/java/de/pixart/messenger/utils/Resolver.java +++ b/src/main/java/de/pixart/messenger/utils/Resolver.java @@ -7,6 +7,9 @@ import android.util.Log; import java.io.IOException; import java.lang.reflect.Field; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -17,12 +20,16 @@ import de.measite.minidns.DNSName; import de.measite.minidns.Question; import de.measite.minidns.Record; import de.measite.minidns.dnssec.DNSSECResultNotAuthenticException; +import de.measite.minidns.dnsserverlookup.AndroidUsingExec; import de.measite.minidns.hla.DnssecResolverApi; import de.measite.minidns.hla.ResolverApi; import de.measite.minidns.hla.ResolverResult; import de.measite.minidns.iterative.ReliableDNSClient; +import de.measite.minidns.record.A; +import de.measite.minidns.record.AAAA; import de.measite.minidns.record.CNAME; import de.measite.minidns.record.Data; +import de.measite.minidns.record.InternetAddressRR; import de.measite.minidns.record.SRV; import de.pixart.messenger.Config; import de.pixart.messenger.R; @@ -32,13 +39,16 @@ public class Resolver { public static final int DEFAULT_PORT_XMPP = 5222; private static final String DIRECT_TLS_SERVICE = "_xmpps-client"; - private static final String STARTTLS_SERVICE = "_xmpp-client"; + private static final String STARTTLS_SERICE = "_xmpp-client"; private static XmppConnectionService SERVICE = null; public static void init(XmppConnectionService service) { Resolver.SERVICE = service; + DNSClient.removeDNSServerLookupMechanism(AndroidUsingExec.INSTANCE); + DNSClient.addDnsServerLookupMechanism(AndroidUsingExecLowPriority.INSTANCE); + DNSClient.addDnsServerLookupMechanism(new AndroidUsingLinkProperties(service)); final AbstractDNSClient client = ResolverApi.INSTANCE.getClient(); if (client instanceof ReliableDNSClient) { disableHardcodedDnsServers((ReliableDNSClient) client); @@ -138,41 +148,91 @@ public class Resolver { if (!IP.matches(domain)) { return Collections.emptyList(); } - return Collections.singletonList(Result.createDefault(DNSName.from(domain))); + try { + Result result = new Result(); + result.ip = InetAddress.getByName(domain); + result.port = DEFAULT_PORT_XMPP; + return Collections.singletonList(result); + } catch (UnknownHostException e) { + return Collections.emptyList(); + } } private static List resolveSrv(String domain, final boolean directTls) throws IOException { - DNSName dnsName = DNSName.from((directTls ? DIRECT_TLS_SERVICE : STARTTLS_SERVICE) + "._tcp." + domain); + DNSName dnsName = DNSName.from((directTls ? DIRECT_TLS_SERVICE : STARTTLS_SERICE) + "._tcp." + domain); ResolverResult result = resolveWithFallback(dnsName, SRV.class); final List results = new ArrayList<>(); + final List threads = new ArrayList<>(); for (SRV record : result.getAnswersOrEmptySet()) { if (record.name.length() == 0 && record.priority == 0) { continue; } - Result resolverResult = Result.fromRecord(record, directTls); - resolverResult.authenticated = result.isAuthenticData(); - results.add(resolverResult); - } + threads.add(new Thread(() -> { + final List ipv4s = resolveIp(record, A.class, result.isAuthenticData(), directTls); + if (ipv4s.size() == 0) { + Result resolverResult = Result.fromRecord(record, directTls); + resolverResult.authenticated = resolverResult.isAuthenticated(); + ipv4s.add(resolverResult); + } + synchronized (results) { + results.addAll(ipv4s); + } + })); + threads.add(new Thread(() -> { + final List ipv6s = resolveIp(record, AAAA.class, result.isAuthenticData(), directTls); + synchronized (results) { + results.addAll(ipv6s); + } + })); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + try { + thread.join(); + } catch (InterruptedException e) { + return Collections.emptyList(); + } + } return results; } + private static List resolveIp(SRV srv, Class type, boolean authenticated, boolean directTls) { + List list = new ArrayList<>(); + try { + ResolverResult results = resolveWithFallback(srv.name, type, authenticated); + for (D record : results.getAnswersOrEmptySet()) { + Result resolverResult = Result.fromRecord(srv, directTls); + resolverResult.authenticated = results.isAuthenticData() && authenticated; + resolverResult.ip = record.getInetAddress(); + list.add(resolverResult); + } + } catch (Throwable t) { + Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + ": error resolving " + type.getSimpleName() + " " + t.getMessage()); + } + return list; + } + private static List resolveNoSrvRecords(DNSName dnsName, boolean withCnames) { List results = new ArrayList<>(); - Boolean resolveCNAME = false; try { - if (withCnames) { + for (A a : resolveWithFallback(dnsName, A.class, false).getAnswersOrEmptySet()) { + results.add(Result.createDefault(dnsName, a.getInetAddress())); + } + for (AAAA aaaa : resolveWithFallback(dnsName, AAAA.class, false).getAnswersOrEmptySet()) { + results.add(Result.createDefault(dnsName, aaaa.getInetAddress())); + } + if (results.size() == 0 && withCnames) { for (CNAME cname : resolveWithFallback(dnsName, CNAME.class, false).getAnswersOrEmptySet()) { results.addAll(resolveNoSrvRecords(cname.name, false)); - resolveCNAME = true; } } } catch (Throwable throwable) { Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + "error resolving fallback records", throwable); } - if(!resolveCNAME) { - results.add(Result.createDefault(dnsName)); - } + results.add(Result.createDefault(dnsName)); return results; } @@ -203,11 +263,13 @@ public class Resolver { public static class Result implements Comparable { public static final String DOMAIN = "domain"; + public static final String IP = "ip"; public static final String HOSTNAME = "hostname"; public static final String PORT = "port"; public static final String PRIORITY = "priority"; public static final String DIRECT_TLS = "directTls"; public static final String AUTHENTICATED = "authenticated"; + private InetAddress ip; private DNSName hostname; private int port = DEFAULT_PORT_XMPP; private boolean directTls = false; @@ -223,15 +285,25 @@ public class Resolver { return result; } - static Result createDefault(DNSName hostname) { + static Result createDefault(DNSName hostname, InetAddress ip) { Result result = new Result(); result.port = DEFAULT_PORT_XMPP; result.hostname = hostname; + result.ip = ip; return result; } + static Result createDefault(DNSName hostname) { + return createDefault(hostname, null); + } + public static Result fromCursor(Cursor cursor) { final Result result = new Result(); + try { + result.ip = InetAddress.getByAddress(cursor.getBlob(cursor.getColumnIndex(IP))); + } catch (UnknownHostException e) { + result.ip = null; + } final String hostname = cursor.getString(cursor.getColumnIndex(HOSTNAME)); result.hostname = hostname == null ? null : DNSName.from(hostname); result.port = cursor.getInt(cursor.getColumnIndex(PORT)); @@ -252,12 +324,14 @@ public class Resolver { if (directTls != result.directTls) return false; if (authenticated != result.authenticated) return false; if (priority != result.priority) return false; + if (ip != null ? !ip.equals(result.ip) : result.ip != null) return false; return hostname != null ? hostname.equals(result.hostname) : result.hostname == null; } @Override public int hashCode() { - int result = hostname != null ? hostname.hashCode() : 0; + int result = ip != null ? ip.hashCode() : 0; + result = 31 * result + (hostname != null ? hostname.hashCode() : 0); result = 31 * result + port; result = 31 * result + (directTls ? 1 : 0); result = 31 * result + (authenticated ? 1 : 0); @@ -265,6 +339,10 @@ public class Resolver { return result; } + public InetAddress getIp() { + return ip; + } + public int getPort() { return port; } @@ -284,6 +362,7 @@ public class Resolver { @Override public String toString() { return "Result{" + + "ip='" + (ip == null ? null : ip.getHostAddress()) + '\'' + ", hostame='" + hostname.toString() + '\'' + ", port=" + port + ", directTls=" + directTls + @@ -296,7 +375,17 @@ public class Resolver { public int compareTo(@NonNull Result result) { if (result.priority == priority) { if (directTls == result.directTls) { + if (ip == null && result.ip == null) { return 0; + } else if (ip != null && result.ip != null) { + if (ip instanceof Inet4Address && result.ip instanceof Inet4Address) { + return 0; + } else { + return ip instanceof Inet4Address ? -1 : 1; + } + } else { + return ip != null ? -1 : 1; + } } else { return directTls ? -1 : 1; } @@ -307,6 +396,7 @@ public class Resolver { public ContentValues toContentValues() { final ContentValues contentValues = new ContentValues(); + contentValues.put(IP, ip == null ? null : ip.getAddress()); contentValues.put(HOSTNAME, hostname == null ? null : hostname.toString()); contentValues.put(PORT, port); contentValues.put(PRIORITY, priority); @@ -315,5 +405,4 @@ public class Resolver { return contentValues; } } - -} +} \ No newline at end of file -- cgit v1.2.3