fix resolving IP if SRV violences RFC2782
This commit is contained in:
parent
e2c2ee6507
commit
fdfaae6f59
2 changed files with 69 additions and 25 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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 don’t want this
|
localSocket.setSoTimeout(0); //reset to 0; once the connection is established we don’t 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 {
|
||||||
|
|
Reference in a new issue