diff options
Diffstat (limited to 'src/main/java/de/pixart/messenger/xmpp/XmppConnection.java')
-rw-r--r-- | src/main/java/de/pixart/messenger/xmpp/XmppConnection.java | 108 |
1 files changed, 40 insertions, 68 deletions
diff --git a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java index cbfdbc365..73cfbab86 100644 --- a/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java +++ b/src/main/java/de/pixart/messenger/xmpp/XmppConnection.java @@ -48,7 +48,6 @@ import java.util.regex.Matcher; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509KeyManager; @@ -77,7 +76,6 @@ import de.pixart.messenger.services.NotificationService; import de.pixart.messenger.services.XmppConnectionService; import de.pixart.messenger.ui.EditAccountActivity; import de.pixart.messenger.utils.CryptoHelper; -import de.pixart.messenger.utils.IP; import de.pixart.messenger.utils.Namespace; import de.pixart.messenger.utils.Patterns; import de.pixart.messenger.utils.Resolver; @@ -210,7 +208,7 @@ public class XmppConnection implements Runnable { } } - protected void changeStatus(final Account.State nextStatus) { + private void changeStatus(final Account.State nextStatus) { synchronized (this) { if (Thread.currentThread().isInterrupted()) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": not changing status to " + nextStatus + " because thread was interrupted"); @@ -304,69 +302,32 @@ public class XmppConnection implements Runnable { } catch (Exception e) { throw new IOException(e.getMessage()); } - } else if (extended && !account.getHostname().isEmpty()) { - - this.verifiedHostname = account.getHostname(); - - try { - InetSocketAddress address = new InetSocketAddress(this.verifiedHostname, account.getPort()); - features.encryptionEnabled = address.getPort() == 5223; - if (features.encryptionEnabled) { - try { - final TlsFactoryVerifier tlsFactoryVerifier = getTlsFactoryVerifier(); - localSocket = tlsFactoryVerifier.factory.createSocket(); - localSocket.connect(address, Config.SOCKET_TIMEOUT * 1000); - final SSLSession session = ((SSLSocket) localSocket).getSession(); - final String domain = account.getJid().getDomain(); - if (!tlsFactoryVerifier.verifier.verify(domain, this.verifiedHostname, session)) { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": TLS certificate verification failed"); - throw new StateChangingException(Account.State.TLS_ERROR); - } - } catch (KeyManagementException e) { - throw new StateChangingException(Account.State.TLS_ERROR); - } - } else { - localSocket = new Socket(); - localSocket.connect(address, Config.SOCKET_TIMEOUT * 1000); - } - } catch (IOException | IllegalArgumentException e) { - throw new UnknownHostException(); + } else { + final String domain = account.getJid().getDomain(); + final List<Resolver.Result> results; + final boolean hardcoded = extended && !account.getHostname().isEmpty(); + if (hardcoded) { + results = Resolver.fromHardCoded(account.getHostname(), account.getPort()); + } else { + results = Resolver.resolve(domain); } - try { - startXmpp(localSocket); - } catch (InterruptedException e) { - Log.d(Config.LOGTAG,account.getJid().asBareJid()+": thread was interrupted before beginning stream"); + if (Thread.currentThread().isInterrupted()) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": Thread was interrupted"); return; - } catch (Exception e) { - throw new IOException(e.getMessage()); } - } else if (IP.matches(account.getServer())) { - localSocket = new Socket(); - try { - localSocket.connect(new InetSocketAddress(account.getServer(), 5222), Config.SOCKET_TIMEOUT * 1000); - } catch (IOException e) { - throw new UnknownHostException(); - } - try { - startXmpp(localSocket); - } catch (InterruptedException e) { - Log.d(Config.LOGTAG,account.getJid().asBareJid()+": thread was interrupted before beginning stream"); + if (results.size() == 0) { + Log.e(Config.LOGTAG, account.getJid().asBareJid() + ": Resolver results were empty"); return; - } catch (Exception e) { - throw new IOException(e.getMessage()); } - } else { - final String domain = account.getJid().getDomain(); - List<Resolver.Result> results = Resolver.resolve(account.getJid().getDomain()); - Resolver.Result storedBackupResult; - if (!Thread.currentThread().isInterrupted()) { + final Resolver.Result storedBackupResult; + if (hardcoded) { + storedBackupResult = null; + } else { storedBackupResult = mXmppConnectionService.databaseBackend.findResolverResult(domain); if (storedBackupResult != null && !results.contains(storedBackupResult)) { results.add(storedBackupResult); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": loaded backup resolver result from db: " + storedBackupResult); } - } else { - storedBackupResult = null; } for (Iterator<Resolver.Result> iterator = results.iterator(); iterator.hasNext(); ) { final Resolver.Result result = iterator.next(); @@ -378,16 +339,17 @@ public class XmppConnection implements Runnable { // if tls is true, encryption is implied and must not be started features.encryptionEnabled = result.isDirectTls(); verifiedHostname = result.isAuthenticated() ? result.getHostname().toString() : null; + Log.d(Config.LOGTAG, "verified hostname " + verifiedHostname); final InetSocketAddress addr; if (result.getIp() != null) { addr = new InetSocketAddress(result.getIp(), result.getPort()); Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() - + ": using values from dns " + result.getHostname().toString() - + "/" + result.getIp().getHostAddress() + ":" + result.getPort() + " tls: " + features.encryptionEnabled); + + ": using values from resolver " + (result.getHostname() == null ? "" : result.getHostname().toString() + + "/") + result.getIp().getHostAddress() + ":" + result.getPort() + " tls: " + features.encryptionEnabled); } else { addr = new InetSocketAddress(IDN.toASCII(result.getHostname().toString()), result.getPort()); Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() - + ": using values from dns " + + ": using values from resolver " + result.getHostname().toString() + ":" + result.getPort() + " tls: " + features.encryptionEnabled); } @@ -403,8 +365,8 @@ public class XmppConnection implements Runnable { } SSLSocketHelper.setSecurity((SSLSocket) localSocket); - SSLSocketHelper.setSNIHost(tlsFactoryVerifier.factory, (SSLSocket) localSocket, account.getServer()); - SSLSocketHelper.setAlpnProtocol(tlsFactoryVerifier.factory, (SSLSocket) localSocket, "xmpp-client"); + SSLSocketHelper.setHostname((SSLSocket) localSocket, account.getServer()); + SSLSocketHelper.setApplicationProtocol((SSLSocket) localSocket, "xmpp-client"); localSocket.connect(addr, Config.SOCKET_TIMEOUT * 1000); @@ -415,14 +377,18 @@ public class XmppConnection implements Runnable { } } } - + localSocket.setSoTimeout(Config.SOCKET_TIMEOUT * 1000); if (startXmpp(localSocket)) { - if (!result.equals(storedBackupResult)) { + localSocket.setSoTimeout(0); //reset to 0; once the connection is established we don’t want this + if (!hardcoded && !result.equals(storedBackupResult)) { mXmppConnectionService.databaseBackend.saveResolverResult(domain, result); } break; // successfully connected to server that speaks xmpp } else { localSocket.close(); + if (!iterator.hasNext()) { + throw new StateChangingException(Account.State.STREAM_OPENING_ERROR); + } } } catch (final StateChangingException e) { throw e; @@ -446,7 +412,7 @@ public class XmppConnection implements Runnable { this.changeStatus(Account.State.SERVER_NOT_FOUND); } catch (final SocksSocketFactory.SocksProxyNotFoundException e) { this.changeStatus(Account.State.TOR_NOT_AVAILABLE); - } catch (final IOException | XmlPullParserException | NoSuchAlgorithmException e) { + } catch (final IOException | XmlPullParserException e) { Log.d(Config.LOGTAG, account.getJid().asBareJid().toString() + ": " + e.getMessage()); this.changeStatus(Account.State.OFFLINE); this.attempt = Math.max(0, this.attempt - 1); @@ -482,6 +448,9 @@ public class XmppConnection implements Runnable { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } + if (socket instanceof SSLSocket) { + SSLSocketHelper.log(account, (SSLSocket) socket); + } return tag != null && tag.isStart("stream"); } @@ -524,7 +493,7 @@ public class XmppConnection implements Runnable { } else if (nextTag.isStart("features")) { processStreamFeatures(nextTag); } else if (nextTag.isStart("proceed")) { - switchOverToTls(nextTag); + switchOverToTls(); } else if (nextTag.isStart("success")) { final String challenge = tagReader.readElement(nextTag).getContent(); try { @@ -542,7 +511,7 @@ public class XmppConnection implements Runnable { if (tag != null && tag.isStart("stream")) { processStream(); } else { - throw new IOException("server didn't restart stream after successful auth"); + throw new StateChangingException(Account.State.STREAM_OPENING_ERROR); } break; } else if (nextTag.isStart("failure")) { @@ -852,7 +821,7 @@ public class XmppConnection implements Runnable { tagWriter.writeTag(startTLS); } - private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException { + private void switchOverToTls() throws XmlPullParserException, IOException { tagReader.readTag(); try { final TlsFactoryVerifier tlsFactoryVerifier = getTlsFactoryVerifier(); @@ -869,6 +838,8 @@ public class XmppConnection implements Runnable { } SSLSocketHelper.setSecurity(sslSocket); + SSLSocketHelper.setHostname(sslSocket, account.getServer()); + SSLSocketHelper.setApplicationProtocol(sslSocket, "xmpp-client"); if (!tlsFactoryVerifier.verifier.verify(account.getServer(), this.verifiedHostname, sslSocket.getSession())) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": TLS certificate verification failed"); @@ -881,9 +852,10 @@ public class XmppConnection implements Runnable { features.encryptionEnabled = true; final Tag tag = tagReader.readTag(); if (tag != null && tag.isStart("stream")) { + SSLSocketHelper.log(account, sslSocket); processStream(); } else { - throw new IOException("server didn't restart stream after STARTTLS"); + throw new StateChangingException(Account.State.STREAM_OPENING_ERROR); } sslSocket.close(); } catch (final NoSuchAlgorithmException | KeyManagementException e1) { |