fix resolving IP if SRV violences RFC2782

This commit is contained in:
Christian Schneppe 2020-04-07 20:08:25 +02:00
parent e2c2ee6507
commit fdfaae6f59
No known key found for this signature in database
GPG key ID: F30B8D686B44D87E
2 changed files with 69 additions and 25 deletions

View file

@ -128,10 +128,14 @@ public class Resolver {
} }
}); });
threads[2] = new Thread(() -> { threads[2] = new Thread(() -> {
List<Result> list = resolveNoSrvRecords(DNSName.from(domain), DEFAULT_PORT_XMPP, true); try {
final List<Result> list = resolveNoSrvRecords(DNSName.from(domain), DEFAULT_PORT_XMPP, true);
synchronized (fallbackResults) { synchronized (fallbackResults) {
fallbackResults.addAll(list); fallbackResults.addAll(list);
} }
} catch (Throwable throwable) {
Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + ": resolving no SRV record (STARTTLS)", throwable);
}
}); });
for (Thread thread : threads) { for (Thread thread : threads) {
thread.start(); thread.start();
@ -187,7 +191,7 @@ public class Resolver {
final List<Thread> fallbackThreads = new ArrayList<>(); final List<Thread> fallbackThreads = new ArrayList<>();
for (SRV record : result.getAnswersOrEmptySet()) { for (SRV record : result.getAnswersOrEmptySet()) {
if (record.name.length() == 0) { if (record.name.length() == 0 && record.priority == 0) {
continue; continue;
} }
threads.add(new Thread(() -> { threads.add(new Thread(() -> {
@ -198,6 +202,11 @@ public class Resolver {
})); }));
threads.add(new Thread(() -> { threads.add(new Thread(() -> {
final List<Result> ipv4s = resolveIp(record, A.class, result.isAuthenticData(), directTls); final List<Result> ipv4s = resolveIp(record, A.class, result.isAuthenticData(), directTls);
if (ipv4s.size() == 0) {
Result resolverResult = Result.fromRecord(record, directTls);
resolverResult.authenticated = result.isAuthenticData();
ipv4s.add(resolverResult);
}
synchronized (results) { synchronized (results) {
results.addAll(ipv4s); results.addAll(ipv4s);
} }
@ -211,13 +220,13 @@ public class Resolver {
fallbackResults.addAll(ipv6s); fallbackResults.addAll(ipv6s);
} }
final List<Result> ipv4s = resolveIp(record, cname.name, A.class, cnames.isAuthenticData(), directTls); final List<Result> ipv4s = resolveIp(record, cname.name, A.class, cnames.isAuthenticData(), directTls);
synchronized (results) { synchronized (fallbackResults) {
fallbackResults.addAll(ipv4s); fallbackResults.addAll(ipv4s);
} }
} }
Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + "cname in srv (agains RFC2782) - run slow fallback"); Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + " cname in srv (against RFC2782) - run slow fallback");
} catch (Throwable throwable) { } catch (Throwable throwable) {
Log.i(Config.LOGTAG, Resolver.class.getSimpleName() + "error resolving srv cname-fallback records", throwable); Log.i(Config.LOGTAG, Resolver.class.getSimpleName() + " error resolving srv cname-fallback records", throwable);
} }
})); }));
} }
@ -285,6 +294,7 @@ public class Resolver {
} catch (Throwable throwable) { } catch (Throwable throwable) {
Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + "error resolving fallback records", throwable); Log.d(Config.LOGTAG, Resolver.class.getSimpleName() + "error resolving fallback records", throwable);
} }
results.add(Result.createDefault(dnsName, port));
return results; return results;
} }
@ -315,7 +325,7 @@ public class Resolver {
if (r.size() == 0) return null; if (r.size() == 0) return null;
Result result; Result result;
if (r.size() == 1) { if (r.size() == 1 && r.get(0).ip != null) {
result = r.get(0); result = r.get(0);
result.setLogID(logID); result.setLogID(logID);
result.connect(); result.connect();
@ -387,11 +397,27 @@ public class Resolver {
result.timeRequested = System.currentTimeMillis(); result.timeRequested = System.currentTimeMillis();
result.port = srv.port; result.port = srv.port;
result.hostname = srv.name; result.hostname = srv.name;
try {
result.ip = InetAddress.getByName(result.hostname.toString());
} catch (UnknownHostException e) {
result.ip = null;
e.printStackTrace();
}
result.directTls = directTls; result.directTls = directTls;
result.priority = srv.priority; result.priority = srv.priority;
return result; return result;
} }
static Result createDefault(final DNSName hostname, final int port) {
InetAddress ip = null;
try {
ip = InetAddress.getByName(hostname.toString());
} catch (UnknownHostException e) {
e.printStackTrace();
}
return createDefault(hostname, ip, port);
}
static Result createDefault(final DNSName hostname, final InetAddress ip, final int port) { static Result createDefault(final DNSName hostname, final InetAddress ip, final int port) {
Result result = new Result(); Result result = new Result();
result.timeRequested = System.currentTimeMillis(); result.timeRequested = System.currentTimeMillis();
@ -464,6 +490,10 @@ public class Resolver {
if (this.socket != null) { if (this.socket != null) {
this.disconnect(); this.disconnect();
} }
if (this.ip == null || this.port == 0) {
Log.d(Config.LOGTAG, "Resolver did not get IP:port (" + this.ip + ":" + this.port + ")");
return;
}
final InetSocketAddress addr = new InetSocketAddress(this.ip, this.port); final InetSocketAddress addr = new InetSocketAddress(this.ip, this.port);
this.socket = new Socket(); this.socket = new Socket();
try { try {

View file

@ -18,7 +18,6 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.IDN;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.MalformedURLException; import java.net.MalformedURLException;
@ -317,20 +316,35 @@ public class XmppConnection implements Runnable {
} }
} else { } else {
final String domain = account.getJid().getDomain(); final String domain = account.getJid().getDomain();
final Resolver.Result storedBackupResult = mXmppConnectionService.databaseBackend.findResolverResult(domain); Resolver.Result results;
Resolver.Result result = null;
final boolean hardcoded = extended && !account.getHostname().isEmpty(); final boolean hardcoded = extended && !account.getHostname().isEmpty();
if (hardcoded) { if (hardcoded) {
result = Resolver.fromHardCoded(account.getHostname(), account.getPort()); results = Resolver.fromHardCoded(account.getHostname(), account.getPort());
} else if (storedBackupResult != null && !storedBackupResult.isOutdated()) { } else {
storedBackupResult.connect(); results = Resolver.resolve(domain);
result = storedBackupResult; }
if (Thread.currentThread().isInterrupted()) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": Thread was interrupted");
return;
}
if (results == null) {
Log.e(Config.LOGTAG,account.getJid().asBareJid()+": Resolver results were empty");
return;
}
final Resolver.Result storedBackupResult;
if (hardcoded) {
storedBackupResult = null;
} else {
storedBackupResult = mXmppConnectionService.databaseBackend.findResolverResult(domain);
if (storedBackupResult != null && results != storedBackupResult && !storedBackupResult.isOutdated()) {
results = storedBackupResult;
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": loaded backup resolver result from db: " + storedBackupResult); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": loaded backup resolver result from db: " + storedBackupResult);
} }
if (result == null || result.getSocket() == null) {
result = Resolver.resolve(domain);
} }
if (result == null) { if (results == null || results.getSocket() == null) {
results = Resolver.resolve(domain);
}
if (results == null) {
throw new UnknownHostException(); throw new UnknownHostException();
} }
if (Thread.currentThread().isInterrupted()) { if (Thread.currentThread().isInterrupted()) {
@ -339,13 +353,13 @@ public class XmppConnection implements Runnable {
} }
try { try {
// if tls is true, encryption is implied and must not be started // if tls is true, encryption is implied and must not be started
features.encryptionEnabled = result.isDirectTls(); features.encryptionEnabled = results.isDirectTls();
verifiedHostname = result.isAuthenticated() ? result.getHostname().toString() : null; verifiedHostname = results.isAuthenticated() ? results.getHostname().toString() : null;
Log.d(Config.LOGTAG,"verified hostname " + verifiedHostname); Log.d(Config.LOGTAG,"verified hostname " + verifiedHostname);
Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() Log.d(Config.LOGTAG, account.getJid().asBareJid().toString()
+ ": using values from resolver " + result.toString()); + ": using values from resolver " + results.toString());
localSocket = result.getSocket(); localSocket = results.getSocket();
if (features.encryptionEnabled) { if (features.encryptionEnabled) {
localSocket = upgradeSocketToTls(localSocket); localSocket = upgradeSocketToTls(localSocket);
@ -354,8 +368,8 @@ public class XmppConnection implements Runnable {
localSocket.setSoTimeout(Config.SOCKET_TIMEOUT * 1000); localSocket.setSoTimeout(Config.SOCKET_TIMEOUT * 1000);
if (startXmpp(localSocket)) { if (startXmpp(localSocket)) {
localSocket.setSoTimeout(0); //reset to 0; once the connection is established we dont want this localSocket.setSoTimeout(0); //reset to 0; once the connection is established we dont want this
if (!hardcoded && !result.equals(storedBackupResult)) { if (!hardcoded && !results.equals(storedBackupResult)) {
mXmppConnectionService.databaseBackend.saveResolverResult(domain, result); mXmppConnectionService.databaseBackend.saveResolverResult(domain, results);
} }
// successfully connected to server that speaks xmpp // successfully connected to server that speaks xmpp
} else { } else {