don't perform dns lookups on domain parts that obviously look like ip addresses

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/utils/DNSHelper.java     | 24 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java | 96 ++--
2 files changed, 67 insertions(+), 53 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/utils/DNSHelper.java 🔗

@@ -20,11 +20,19 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Random;
 import java.util.TreeMap;
+import java.util.regex.Pattern;
 
 import android.os.Bundle;
 import android.util.Log;
 
 public class DNSHelper {
+
+	public static final Pattern PATTERN_IPV4 = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
+	public static final Pattern PATTERN_IPV6_HEX4DECCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::((?:[0-9A-Fa-f]{1,4}:)*)(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
+	public static final Pattern PATTERN_IPV6_6HEX4DEC = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}:){6,6})(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
+	public static final Pattern PATTERN_IPV6_HEXCOMPRESSED = Pattern.compile("\\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)\\z");
+	public static final Pattern PATTERN_IPV6 = Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");
+
 	protected static Client client = new Client();
 
 	public static Bundle getSRVRecord(final Jid jid) throws IOException {
@@ -160,15 +168,11 @@ public class DNSHelper {
 		return namePort;
 	}
 
-	final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
-
-	public static String bytesToHex(byte[] bytes) {
-		char[] hexChars = new char[bytes.length * 2];
-		for (int j = 0; j < bytes.length; j++) {
-			int v = bytes[j] & 0xFF;
-			hexChars[j * 2] = hexArray[v >>> 4];
-			hexChars[j * 2 + 1] = hexArray[v & 0x0F];
-		}
-		return new String(hexChars);
+	public static boolean isIp(final String server) {
+		return PATTERN_IPV4.matcher(server).matches()
+				|| PATTERN_IPV6.matcher(server).matches()
+				|| PATTERN_IPV6_6HEX4DEC.matcher(server).matches()
+				|| PATTERN_IPV6_HEX4DECCOMPRESSED.matcher(server).matches()
+				|| PATTERN_IPV6_HEXCOMPRESSED.matcher(server).matches();
 	}
 }

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -26,6 +26,7 @@ import java.net.IDN;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.net.SocketAddress;
 import java.net.UnknownHostException;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
@@ -155,53 +156,62 @@ public class XmppConnection implements Runnable {
 			tagWriter = new TagWriter();
 			packetCallbacks.clear();
 			this.changeStatus(Account.State.CONNECTING);
-			final Bundle result = DNSHelper.getSRVRecord(account.getServer());
-			final ArrayList<Parcelable> values = result.getParcelableArrayList("values");
-			if ("timeout".equals(result.getString("error"))) {
-				throw new IOException("timeout in dns");
-			} else if (values != null) {
-				int i = 0;
-				boolean socketError = true;
-				while (socketError && values.size() > i) {
-					final Bundle namePort = (Bundle) values.get(i);
-					try {
-						String srvRecordServer;
+			if (DNSHelper.isIp(account.getServer().toString())) {
+				socket = new Socket();
+				try {
+					socket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);
+				} catch (IOException e) {
+					throw new UnknownHostException();
+				}
+			} else {
+				final Bundle result = DNSHelper.getSRVRecord(account.getServer());
+				final ArrayList<Parcelable> values = result.getParcelableArrayList("values");
+				if ("timeout".equals(result.getString("error"))) {
+					throw new IOException("timeout in dns");
+				} else if (values != null) {
+					int i = 0;
+					boolean socketError = true;
+					while (socketError && values.size() > i) {
+						final Bundle namePort = (Bundle) values.get(i);
 						try {
-							srvRecordServer = IDN.toASCII(namePort.getString("name"));
-						} catch (final IllegalArgumentException e) {
-							// TODO: Handle me?`
-							srvRecordServer = "";
-						}
-						final int srvRecordPort = namePort.getInt("port");
-						final String srvIpServer = namePort.getString("ip");
-						final InetSocketAddress addr;
-						if (srvIpServer != null) {
-							addr = new InetSocketAddress(srvIpServer, srvRecordPort);
-							Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
-									+ ": using values from dns " + srvRecordServer
-									+ "[" + srvIpServer + "]:" + srvRecordPort);
-						} else {
-							addr = new InetSocketAddress(srvRecordServer, srvRecordPort);
-							Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
-									+ ": using values from dns "
-									+ srvRecordServer + ":" + srvRecordPort);
+							String srvRecordServer;
+							try {
+								srvRecordServer = IDN.toASCII(namePort.getString("name"));
+							} catch (final IllegalArgumentException e) {
+								// TODO: Handle me?`
+								srvRecordServer = "";
+							}
+							final int srvRecordPort = namePort.getInt("port");
+							final String srvIpServer = namePort.getString("ip");
+							final InetSocketAddress addr;
+							if (srvIpServer != null) {
+								addr = new InetSocketAddress(srvIpServer, srvRecordPort);
+								Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+										+ ": using values from dns " + srvRecordServer
+										+ "[" + srvIpServer + "]:" + srvRecordPort);
+							} else {
+								addr = new InetSocketAddress(srvRecordServer, srvRecordPort);
+								Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+										+ ": using values from dns "
+										+ srvRecordServer + ":" + srvRecordPort);
+							}
+							socket = new Socket();
+							socket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
+							socketError = false;
+						} catch (final UnknownHostException e) {
+							Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
+							i++;
+						} catch (final IOException e) {
+							Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
+							i++;
 						}
-						socket = new Socket();
-						socket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
-						socketError = false;
-					} catch (final UnknownHostException e) {
-						Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
-						i++;
-					} catch (final IOException e) {
-						Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage());
-						i++;
 					}
+					if (socketError) {
+						throw new UnknownHostException();
+					}
+				} else {
+					throw new IOException("unhandled exception in DNS resolver");
 				}
-				if (socketError) {
-					throw new UnknownHostException();
-				}
-			} else {
-				throw new IOException("unhandled exception in DNS resolver");
 			}
 			final OutputStream out = socket.getOutputStream();
 			tagWriter.setOutputStream(out);