Resolver.java

  1package eu.siacs.conversations.utils;
  2
  3import android.content.Context;
  4import android.support.annotation.NonNull;
  5import android.util.Log;
  6
  7import java.io.IOException;
  8import java.net.InetAddress;
  9import java.util.ArrayList;
 10import java.util.Collections;
 11import java.util.List;
 12
 13import de.measite.minidns.DNSClient;
 14import de.measite.minidns.DNSName;
 15import de.measite.minidns.hla.DnssecResolverApi;
 16import de.measite.minidns.hla.ResolverResult;
 17import de.measite.minidns.record.A;
 18import de.measite.minidns.record.AAAA;
 19import de.measite.minidns.record.InternetAddressRR;
 20import de.measite.minidns.record.SRV;
 21import eu.siacs.conversations.Config;
 22
 23public class Resolver {
 24
 25    private static final String DIRECT_TLS_SERVICE = "_xmpps-client";
 26    private static final String STARTTLS_SERICE = "_xmpp-client";
 27
 28
 29
 30
 31    public static void registerLookupMechanism(Context context) {
 32        DNSClient.addDnsServerLookupMechanism(new AndroidUsingLinkProperties(context));
 33    }
 34
 35    public static List<Result> resolve(String domain) {
 36        List<Result> results = new ArrayList<>();
 37        try {
 38            results.addAll(resolveSrv(domain,true));
 39        } catch (Throwable t) {
 40            Log.d(Config.LOGTAG,Resolver.class.getSimpleName()+": "+t.getMessage());
 41        }
 42        try {
 43            results.addAll(resolveSrv(domain,false));
 44        } catch (Throwable t) {
 45            Log.d(Config.LOGTAG,Resolver.class.getSimpleName()+": "+t.getMessage());
 46        }
 47        if (results.size() == 0) {
 48            results.add(Result.createDefault(domain));
 49        }
 50        Collections.sort(results);
 51        return results;
 52    }
 53
 54    private static List<Result> resolveSrv(String domain, final boolean directTls) throws IOException {
 55        DNSName dnsName = DNSName.from((directTls ? DIRECT_TLS_SERVICE : STARTTLS_SERICE)+"._tcp."+domain);
 56        ResolverResult<SRV> result = DnssecResolverApi.INSTANCE.resolveDnssecReliable(dnsName,SRV.class);
 57        List<Result> results = new ArrayList<>();
 58        for(SRV record : result.getAnswersOrEmptySet()) {
 59            boolean added = results.addAll(resolveIp(record,A.class,result.isAuthenticData(),directTls));
 60            added |= results.addAll(resolveIp(record,AAAA.class,result.isAuthenticData(),directTls));
 61            if (!added) {
 62                Result resolverResult = Result.fromRecord(record, directTls);
 63                resolverResult.authenticated = resolverResult.isAuthenticated();
 64                results.add(resolverResult);
 65            }
 66        }
 67        return results;
 68    }
 69
 70    private static <D extends InternetAddressRR> List<Result> resolveIp(SRV srv, Class<D> type, boolean authenticated, boolean directTls) {
 71        List<Result> list = new ArrayList<>();
 72        try {
 73            ResolverResult<D> results = DnssecResolverApi.INSTANCE.resolveDnssecReliable(srv.name, type);
 74            for (D record : results.getAnswersOrEmptySet()) {
 75                Result resolverResult = Result.fromRecord(srv, directTls);
 76                resolverResult.authenticated = results.isAuthenticData() && authenticated;
 77                resolverResult.ip = record.getInetAddress();
 78                list.add(resolverResult);
 79            }
 80        } catch (Throwable t) {
 81            Log.d(Config.LOGTAG,Resolver.class.getSimpleName()+": error resolving "+type.getSimpleName()+" "+t.getMessage());
 82        }
 83        return list;
 84    }
 85
 86    public static class Result implements Comparable<Result> {
 87        private InetAddress ip;
 88        private DNSName hostname;
 89        private int port = 5222;
 90        private boolean directTls = false;
 91        private boolean authenticated =false;
 92        private int priority;
 93
 94        public InetAddress getIp() {
 95            return ip;
 96        }
 97
 98        public int getPort() {
 99            return port;
100        }
101
102        public DNSName getHostname() {
103            return hostname;
104        }
105
106        public boolean isDirectTls() {
107            return directTls;
108        }
109
110        public boolean isAuthenticated() {
111            return authenticated;
112        }
113
114        @Override
115        public String toString() {
116            return "Result{" +
117                    "ip='" + (ip==null?null:ip.getHostAddress()) + '\'' +
118                    ", hostame='" + hostname.toString() + '\'' +
119                    ", port=" + port +
120                    ", directTls=" + directTls +
121                    ", authenticated=" + authenticated +
122                    ", priority=" + priority +
123                    '}';
124        }
125
126        @Override
127        public int compareTo(@NonNull Result result) {
128            if (result.priority == priority) {
129                if (directTls == result.directTls) {
130                    return 0;
131                } else {
132                    return directTls ? 1 : -1;
133                }
134            } else {
135                return priority - result.priority;
136            }
137        }
138
139        public static Result fromRecord(SRV srv, boolean directTls) {
140            Result result = new Result();
141            result.port = srv.port;
142            result.hostname = srv.name;
143            result.directTls = directTls;
144            result.priority = srv.priority;
145            return result;
146        }
147
148        public static Result createDefault(String domain) {
149            Result result = new Result();
150            result.port = 5222;
151            result.hostname = DNSName.from(domain);
152            return result;
153        }
154    }
155
156}