upgrade minidns. refactored dns utils

This commit is contained in:
Daniel Gultsch 2017-06-21 23:28:01 +02:00
parent 5d9d725446
commit 2e380ed792
7 changed files with 278 additions and 325 deletions

View file

@ -33,7 +33,7 @@ dependencies {
compile 'org.gnu.inet:libidn:1.15' compile 'org.gnu.inet:libidn:1.15'
compile 'com.google.zxing:core:3.2.1' compile 'com.google.zxing:core:3.2.1'
compile 'com.google.zxing:android-integration:3.2.1' compile 'com.google.zxing:android-integration:3.2.1'
compile 'de.measite.minidns:minidns:0.1.7' compile 'de.measite.minidns:minidns-hla:0.2.1'
compile 'de.timroes.android:EnhancedListView:0.3.4' compile 'de.timroes.android:EnhancedListView:0.3.4'
compile 'me.leolin:ShortcutBadger:1.1.12@aar' compile 'me.leolin:ShortcutBadger:1.1.12@aar'
compile 'com.kyleduo.switchbutton:library:1.2.8' compile 'com.kyleduo.switchbutton:library:1.2.8'

View file

@ -114,6 +114,7 @@ import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PRNGFixes;
import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor; import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
import eu.siacs.conversations.utils.Resolver;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor; import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.utils.XmppUri;
@ -983,6 +984,7 @@ public class XmppConnectionService extends Service {
public void onCreate() { public void onCreate() {
ExceptionHelper.init(getApplicationContext()); ExceptionHelper.init(getApplicationContext());
PRNGFixes.apply(); PRNGFixes.apply();
Resolver.registerLookupMechanism(this);
this.mRandom = new SecureRandom(); this.mRandom = new SecureRandom();
updateMemorizingTrustmanager(); updateMemorizingTrustmanager();
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

View file

@ -0,0 +1,76 @@
package eu.siacs.conversations.utils;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.RouteInfo;
import android.os.Build;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import de.measite.minidns.dnsserverlookup.AbstractDNSServerLookupMechanism;
import de.measite.minidns.dnsserverlookup.AndroidUsingExec;
public class AndroidUsingLinkProperties extends AbstractDNSServerLookupMechanism {
private final Context context;
protected AndroidUsingLinkProperties(Context context) {
super(AndroidUsingLinkProperties.class.getSimpleName(), AndroidUsingExec.PRIORITY - 1);
this.context = context;
}
@Override
public boolean isAvailable() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
@Override
@TargetApi(21)
public String[] getDnsServerAddresses() {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] networks = connectivityManager == null ? null : connectivityManager.getAllNetworks();
if (networks == null) {
return new String[0];
}
List<String> servers = new ArrayList<>();
for(Network network : networks) {
LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
if (linkProperties != null) {
if (hasDefaultRoute(linkProperties)) {
servers.addAll(0, getIPv4First(linkProperties.getDnsServers()));
} else {
servers.addAll(getIPv4First(linkProperties.getDnsServers()));
}
}
}
return servers.toArray(new String[servers.size()]);
}
private static List<String> getIPv4First(List<InetAddress> in) {
List<String> out = new ArrayList<>();
for(InetAddress addr : in) {
if (addr instanceof Inet4Address) {
out.add(0, addr.toString());
} else {
out.add(addr.toString());
}
}
return out;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static boolean hasDefaultRoute(LinkProperties linkProperties) {
for(RouteInfo route: linkProperties.getRoutes()) {
if (route.isDefaultRoute()) {
return true;
}
}
return false;
}
}

View file

@ -1,299 +0,0 @@
package eu.siacs.conversations.utils;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.RouteInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.TreeMap;
import java.util.Map;
import java.util.regex.Pattern;
import de.measite.minidns.Client;
import de.measite.minidns.DNSMessage;
import de.measite.minidns.Record;
import de.measite.minidns.Record.CLASS;
import de.measite.minidns.Record.TYPE;
import de.measite.minidns.record.A;
import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.Data;
import de.measite.minidns.record.SRV;
import de.measite.minidns.util.NameUtil;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.xmpp.jid.Jid;
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();
protected static Context context;
public static Bundle getSRVRecord(final Jid jid, Context context) throws IOException {
DNSHelper.context = context;
final String host = jid.getDomainpart();
final List<InetAddress> servers = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? getDnsServers(context) : getDnsServersPreLollipop();
Bundle b = new Bundle();
boolean interrupted = false;
for(InetAddress server : servers) {
if (Thread.currentThread().isInterrupted()) {
interrupted = true;
break;
}
b = queryDNS(host, server);
if (b.containsKey("values")) {
return b;
}
}
if (!b.containsKey("values")) {
Log.d(Config.LOGTAG,(interrupted ? "Thread interrupted during DNS query" :"all dns queries failed") + ". provide fallback A record");
ArrayList<Parcelable> values = new ArrayList<>();
values.add(createNamePortBundle(host, 5222, false));
b.putParcelableArrayList("values",values);
}
return b;
}
@TargetApi(21)
private static List<InetAddress> getDnsServers(Context context) {
List<InetAddress> servers = new ArrayList<>();
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] networks = connectivityManager == null ? null : connectivityManager.getAllNetworks();
if (networks == null) {
return getDnsServersPreLollipop();
}
for(int i = 0; i < networks.length; ++i) {
LinkProperties linkProperties = connectivityManager.getLinkProperties(networks[i]);
if (linkProperties != null) {
if (hasDefaultRoute(linkProperties)) {
servers.addAll(0, getIPv4First(linkProperties.getDnsServers()));
} else {
servers.addAll(getIPv4First(linkProperties.getDnsServers()));
}
}
}
if (servers.size() > 0) {
Log.d(Config.LOGTAG, "used lollipop variant to discover dns servers in " + networks.length + " networks");
}
return servers.size() > 0 ? servers : getDnsServersPreLollipop();
}
private static List<InetAddress> getIPv4First(List<InetAddress> in) {
List<InetAddress> out = new ArrayList<>();
for(InetAddress addr : in) {
if (addr instanceof Inet4Address) {
out.add(0, addr);
} else {
out.add(addr);
}
}
return out;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static boolean hasDefaultRoute(LinkProperties linkProperties) {
for(RouteInfo route: linkProperties.getRoutes()) {
if (route.isDefaultRoute()) {
return true;
}
}
return false;
}
private static List<InetAddress> getDnsServersPreLollipop() {
List<InetAddress> servers = new ArrayList<>();
String[] dns = client.findDNS();
for(int i = 0; i < dns.length; ++i) {
try {
servers.add(InetAddress.getByName(dns[i]));
} catch (UnknownHostException e) {
//ignore
}
}
return servers;
}
private static class TlsSrv {
private final SRV srv;
private final boolean tls;
public TlsSrv(SRV srv, boolean tls) {
this.srv = srv;
this.tls = tls;
}
}
private static void fillSrvMaps(final String qname, final InetAddress dnsServer, final Map<Integer, List<TlsSrv>> priorities, final Map<String, List<String>> ips4, final Map<String, List<String>> ips6, final boolean tls) throws IOException {
final DNSMessage message = client.query(qname, TYPE.SRV, CLASS.IN, dnsServer.getHostAddress());
for (Record[] rrset : new Record[][] { message.getAnswers(), message.getAdditionalResourceRecords() }) {
for (Record rr : rrset) {
Data d = rr.getPayload();
final String name = rr.getName() != null ? rr.getName().toLowerCase(Locale.US) : null;
if (d instanceof SRV && NameUtil.idnEquals(qname, name)) {
SRV srv = (SRV) d;
if (!priorities.containsKey(srv.getPriority())) {
priorities.put(srv.getPriority(),new ArrayList<TlsSrv>());
}
priorities.get(srv.getPriority()).add(new TlsSrv(srv, tls));
} else if (d instanceof SRV) {
Log.d(Config.LOGTAG,"found unrecognized SRV record with name: "+name);
}
if (d instanceof A) {
A a = (A) d;
if (!ips4.containsKey(name)) {
ips4.put(name, new ArrayList<String>());
}
ips4.get(name).add(a.toString());
}
if (d instanceof AAAA) {
AAAA aaaa = (AAAA) d;
if (!ips6.containsKey(name)) {
ips6.put(name, new ArrayList<String>());
}
ips6.get(name).add("[" + aaaa.toString() + "]");
}
}
}
}
public static Bundle queryDNS(String host, InetAddress dnsServer) {
Bundle bundle = new Bundle();
try {
client.setTimeout(Config.SOCKET_TIMEOUT * 1000);
final String qname = "_xmpp-client._tcp." + host.toLowerCase(Locale.US);
final String tlsQname = "_xmpps-client._tcp." + host.toLowerCase(Locale.US);
Log.d(Config.LOGTAG, "using dns server: " + dnsServer.getHostAddress() + " to look up " + host);
final Map<Integer, List<TlsSrv>> priorities = new TreeMap<>();
final Map<String, List<String>> ips4 = new TreeMap<>();
final Map<String, List<String>> ips6 = new TreeMap<>();
fillSrvMaps(qname, dnsServer, priorities, ips4, ips6, false);
fillSrvMaps(tlsQname, dnsServer, priorities, ips4, ips6, true);
final List<TlsSrv> result = new ArrayList<>();
for (final List<TlsSrv> s : priorities.values()) {
result.addAll(s);
}
final ArrayList<Bundle> values = new ArrayList<>();
if (result.size() == 0) {
DNSMessage response;
try {
response = client.query(host, TYPE.A, CLASS.IN, dnsServer.getHostAddress());
for (int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload(), false));
}
} catch (SocketTimeoutException e) {
Log.d(Config.LOGTAG,"ignoring timeout exception when querying A record on "+dnsServer.getHostAddress());
}
try {
response = client.query(host, TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress());
for (int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(host, 5222, response.getAnswers()[i].getPayload(), false));
}
} catch (SocketTimeoutException e) {
Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress());
}
values.add(createNamePortBundle(host, 5222, false));
bundle.putParcelableArrayList("values", values);
return bundle;
}
for (final TlsSrv tlsSrv : result) {
final SRV srv = tlsSrv.srv;
final String name = srv.getName() != null ? srv.getName().toLowerCase(Locale.US) : null;
if (ips6.containsKey(name)) {
values.add(createNamePortBundle(name,srv.getPort(),ips6, tlsSrv.tls));
} else {
try {
DNSMessage response = client.query(name, TYPE.AAAA, CLASS.IN, dnsServer.getHostAddress());
for (int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(name, srv.getPort(), response.getAnswers()[i].getPayload(), tlsSrv.tls));
}
} catch (SocketTimeoutException e) {
Log.d(Config.LOGTAG,"ignoring timeout exception when querying AAAA record on "+dnsServer.getHostAddress());
}
}
if (ips4.containsKey(name)) {
values.add(createNamePortBundle(name,srv.getPort(),ips4, tlsSrv.tls));
} else {
DNSMessage response = client.query(name, TYPE.A, CLASS.IN, dnsServer.getHostAddress());
for(int i = 0; i < response.getAnswers().length; ++i) {
values.add(createNamePortBundle(name,srv.getPort(),response.getAnswers()[i].getPayload(), tlsSrv.tls));
}
}
values.add(createNamePortBundle(name, srv.getPort(), tlsSrv.tls));
}
bundle.putParcelableArrayList("values", values);
} catch (SocketTimeoutException e) {
bundle.putString("error", "timeout");
} catch (Exception e) {
bundle.putString("error", "unhandled");
}
return bundle;
}
private static Bundle createNamePortBundle(String name, int port, final boolean tls) {
Bundle namePort = new Bundle();
namePort.putString("name", name);
namePort.putBoolean("tls", tls);
namePort.putInt("port", port);
return namePort;
}
private static Bundle createNamePortBundle(String name, int port, Map<String, List<String>> ips, final boolean tls) {
Bundle namePort = new Bundle();
namePort.putString("name", name);
namePort.putBoolean("tls", tls);
namePort.putInt("port", port);
if (ips!=null) {
List<String> ip = ips.get(name);
Collections.shuffle(ip, new Random());
namePort.putString("ip", ip.get(0));
}
return namePort;
}
private static Bundle createNamePortBundle(String name, int port, Data data, final boolean tls) {
Bundle namePort = new Bundle();
namePort.putString("name", name);
namePort.putBoolean("tls", tls);
namePort.putInt("port", port);
if (data instanceof A) {
namePort.putString("ip", data.toString());
} else if (data instanceof AAAA) {
namePort.putString("ip","["+data.toString()+"]");
}
return namePort;
}
public static boolean isIp(final String server) {
return server != null && (
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());
}
}

View file

@ -0,0 +1,22 @@
package eu.siacs.conversations.utils;
import java.util.regex.Pattern;
public class IP {
private 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");
private 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");
private 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");
private 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");
private static final Pattern PATTERN_IPV6 = Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");
public static boolean matches(String server) {
return server != null && (
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());
}
}

View file

@ -0,0 +1,163 @@
package eu.siacs.conversations.utils;
import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import de.measite.minidns.DNSClient;
import de.measite.minidns.DNSName;
import de.measite.minidns.Question;
import de.measite.minidns.Record;
import de.measite.minidns.hla.DnssecResolverApi;
import de.measite.minidns.hla.ResolverResult;
import de.measite.minidns.record.A;
import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.Data;
import de.measite.minidns.record.InternetAddressRR;
import de.measite.minidns.record.SRV;
import eu.siacs.conversations.Config;
public class Resolver {
private static final String DIRECT_TLS_SERVICE = "_xmpps-client";
private static final String STARTTLS_SERICE = "_xmpp-client";
public static void registerLookupMechanism(Context context) {
DNSClient.addDnsServerLookupMechanism(new AndroidUsingLinkProperties(context));
}
public static List<Result> resolve(String domain) {
List<Result> results = new ArrayList<>();
try {
results.addAll(resolveSrv(domain,true));
} catch (IOException e) {
//ignore
}
try {
results.addAll(resolveSrv(domain,false));
} catch (IOException e) {
//ignore
}
if (results.size() == 0) {
results.add(Result.createDefault(domain));
}
Collections.sort(results);
return results;
}
private static List<Result> resolveSrv(String domain, final boolean directTls) throws IOException {
Question question = new Question((directTls ? DIRECT_TLS_SERVICE : STARTTLS_SERICE)+"._tcp."+domain,Record.TYPE.SRV);
ResolverResult<Data> result = DnssecResolverApi.INSTANCE.resolve(question);
List<Result> results = new ArrayList<>();
for(Data record : result.getAnswersOrEmptySet()) {
if (record instanceof SRV) {
SRV srvRecord = (SRV) record;
boolean added = results.addAll(resolveIp(srvRecord,A.class,result.isAuthenticData(),directTls));
added |= results.addAll(resolveIp(srvRecord,AAAA.class,result.isAuthenticData(),directTls));
if (!added) {
Result resolverResult = Result.fromRecord(srvRecord, directTls);
resolverResult.authenticated = resolverResult.isAuthenticated();
results.add(resolverResult);
}
}
}
return results;
}
private static <D extends InternetAddressRR> List<Result> resolveIp(SRV srv, Class<D> type, boolean authenticated, boolean directTls) {
List<Result> list = new ArrayList<>();
try {
ResolverResult<D> results = DnssecResolverApi.INSTANCE.resolve(srv.name, type);
for (D record : results.getAnswersOrEmptySet()) {
Result resolverResult = Result.fromRecord(srv, directTls);
resolverResult.authenticated = results.isAuthenticData() && authenticated;
resolverResult.ip = record.getInetAddress();
list.add(resolverResult);
}
} catch (IOException e) {
Log.d(Config.LOGTAG,e.getMessage());
//ignore. will add default record later
}
return list;
}
public static class Result implements Comparable<Result> {
private InetAddress ip;
private DNSName hostname;
private int port = 5222;
private boolean directTls = false;
private boolean authenticated =false;
private int priority;
public InetAddress getIp() {
return ip;
}
public int getPort() {
return port;
}
public DNSName getHostname() {
return hostname;
}
public boolean isDirectTls() {
return directTls;
}
public boolean isAuthenticated() {
return authenticated;
}
@Override
public String toString() {
return "Result{" +
"ip='" + ip + '\'' +
", hostame='" + hostname.toString() + '\'' +
", port=" + port +
", directTls=" + directTls +
", authenticated=" + authenticated +
", priority=" + priority +
'}';
}
@Override
public int compareTo(@NonNull Result result) {
if (result.priority == priority) {
if (directTls == result.directTls) {
return 0;
} else {
return directTls ? 1 : -1;
}
} else {
return priority - result.priority;
}
}
public static Result fromRecord(SRV srv, boolean directTls) {
Result result = new Result();
result.port = srv.port;
result.hostname = srv.name;
result.directTls = directTls;
result.priority = srv.priority;
return result;
}
public static Result createDefault(String domain) {
Result result = new Result();
result.port = 5222;
result.hostname = DNSName.from(domain);
return result;
}
}
}

View file

@ -2,8 +2,6 @@ package eu.siacs.conversations.xmpp;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManager.WakeLock; import android.os.PowerManager.WakeLock;
import android.os.SystemClock; import android.os.SystemClock;
@ -20,7 +18,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigInteger; import java.math.BigInteger;
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.Socket; import java.net.Socket;
@ -67,8 +64,9 @@ import eu.siacs.conversations.entities.ServiceDiscoveryResult;
import eu.siacs.conversations.generator.IqGenerator; import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.services.NotificationService; import eu.siacs.conversations.services.NotificationService;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.DNSHelper; import eu.siacs.conversations.utils.IP;
import eu.siacs.conversations.utils.Patterns; import eu.siacs.conversations.utils.Patterns;
import eu.siacs.conversations.utils.Resolver;
import eu.siacs.conversations.utils.SSLSocketHelper; import eu.siacs.conversations.utils.SSLSocketHelper;
import eu.siacs.conversations.utils.SocksSocketFactory; import eu.siacs.conversations.utils.SocksSocketFactory;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
@ -329,7 +327,7 @@ public class XmppConnection implements Runnable {
} catch (Exception e) { } catch (Exception e) {
throw new IOException(e.getMessage()); throw new IOException(e.getMessage());
} }
} else if (DNSHelper.isIp(account.getServer().toString())) { } else if (IP.matches(account.getServer().toString())) {
localSocket = new Socket(); localSocket = new Socket();
try { try {
localSocket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000); localSocket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);
@ -345,37 +343,28 @@ public class XmppConnection implements Runnable {
throw new IOException(e.getMessage()); throw new IOException(e.getMessage());
} }
} else { } else {
final Bundle result = DNSHelper.getSRVRecord(account.getServer(), mXmppConnectionService); List<Resolver.Result> results = Resolver.resolve(account.getJid().getDomainpart());
final ArrayList<Parcelable> values = result.getParcelableArrayList("values"); Log.d(Config.LOGTAG,"results: "+results);
for (Iterator<Parcelable> iterator = values.iterator(); iterator.hasNext(); ) { for (Iterator<Resolver.Result> iterator = results.iterator(); iterator.hasNext(); ) {
final Resolver.Result result = iterator.next();
if (Thread.currentThread().isInterrupted()) { if (Thread.currentThread().isInterrupted()) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": Thread was interrupted"); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": Thread was interrupted");
return; return;
} }
final Bundle namePort = (Bundle) iterator.next();
try { try {
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");
// 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 = namePort.getBoolean("tls"); features.encryptionEnabled = result.isDirectTls();
final InetSocketAddress addr; final InetSocketAddress addr;
if (srvIpServer != null) { if (result.getIp() != null) {
addr = new InetSocketAddress(srvIpServer, srvRecordPort); addr = new InetSocketAddress(result.getIp(), result.getPort());
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+ ": using values from dns " + srvRecordServer + ": using values from dns " + result.getHostname().toString()
+ "[" + srvIpServer + "]:" + srvRecordPort + " tls: " + features.encryptionEnabled); + "[" + result.getIp().toString() + "]:" + result.getPort() + " tls: " + features.encryptionEnabled);
} else { } else {
addr = new InetSocketAddress(srvRecordServer, srvRecordPort); addr = new InetSocketAddress(result.getHostname().toString(), result.getPort());
Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() Log.d(Config.LOGTAG, account.getJid().toBareJid().toString()
+ ": using values from dns " + ": using values from dns "
+ srvRecordServer + ":" + srvRecordPort + " tls: " + features.encryptionEnabled); + result.getHostname().toString() + ":" + result.getPort() + " tls: " + features.encryptionEnabled);
} }
if (!features.encryptionEnabled) { if (!features.encryptionEnabled) {