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