Client.java

  1package de.measite.minidns;
  2
  3import java.io.IOException;
  4import java.io.InputStream;
  5import java.io.InputStreamReader;
  6import java.io.LineNumberReader;
  7import java.net.DatagramPacket;
  8import java.net.DatagramSocket;
  9import java.net.InetAddress;
 10import java.security.NoSuchAlgorithmException;
 11import java.security.SecureRandom;
 12import java.util.HashSet;
 13import java.util.Random;
 14
 15import de.measite.minidns.Record.CLASS;
 16import de.measite.minidns.Record.TYPE;
 17
 18/**
 19 * A minimal DNS client for SRV/A/AAAA/NS and CNAME lookups, with IDN support.
 20 * This circumvents the missing javax.naming package on android.
 21 */
 22public class Client {
 23
 24    /**
 25     * The internal random class for sequence generation.
 26     */
 27    protected Random random;
 28
 29    /**
 30     * Create a new DNS client.
 31     */
 32    public Client() {
 33        try {
 34            random = SecureRandom.getInstance("SHA1PRNG");
 35        } catch (NoSuchAlgorithmException e1) {
 36            random = new SecureRandom();
 37        }
 38    }
 39
 40    /**
 41     * Query a nameserver for a single entry.
 42     * @param name The DNS name to request.
 43     * @param type The DNS type to request (SRV, A, AAAA, ...).
 44     * @param clazz The class of the request (usually IN for Internet).
 45     * @param host The DNS server host.
 46     * @return 
 47     * @throws IOException On IO Errors.
 48     */
 49    public DNSMessage query(String name, TYPE type, CLASS clazz, String host)
 50        throws IOException
 51    {
 52        Question q = new Question();
 53        q.setClazz(clazz);
 54        q.setType(type);
 55        q.setName(name);
 56        return query(q, host);
 57    }
 58
 59    /**
 60     * Query the system nameserver for a single entry.
 61     * @param name The DNS name to request.
 62     * @param type The DNS type to request (SRV, A, AAAA, ...).
 63     * @param clazz The class of the request (usually IN for Internet).
 64     * @return The DNSMessage reply or null.
 65     */
 66    public DNSMessage query(String name, TYPE type, CLASS clazz)
 67    {
 68        Question q = new Question();
 69        q.setClazz(clazz);
 70        q.setType(type);
 71        q.setName(name);
 72        return query(q);
 73    }
 74
 75    /**
 76     * Query a specific server for one entry.
 77     * @param q The question section of the DNS query.
 78     * @param host The dns server host.
 79     * @throws IOException On IOErrors.
 80     */
 81    public DNSMessage query(Question q, String host) throws IOException {
 82        DNSMessage message = new DNSMessage();
 83        message.setQuestions(new Question[]{q});
 84        message.setRecursionDesired(true);
 85        message.setId(random.nextInt());
 86        byte[] buf = message.toArray();
 87        DatagramSocket socket = new DatagramSocket();
 88        DatagramPacket packet = new DatagramPacket(
 89                buf, buf.length, InetAddress.getByName(host), 53);
 90        socket.setSoTimeout(5000);
 91        socket.send(packet);
 92        packet = new DatagramPacket(new byte[513], 513);
 93        socket.receive(packet);
 94        DNSMessage dnsMessage = DNSMessage.parse(packet.getData());
 95        if (dnsMessage.getId() != message.getId()) {
 96            return null;
 97        }
 98        return dnsMessage;
 99    }
100
101    /**
102     * Query the system DNS server for one entry.
103     * @param q The question section of the DNS query.
104     */
105    public DNSMessage query(Question q) {
106        String dnsServer[] = findDNS();
107        for (String dns : dnsServer) {
108            try {
109                DNSMessage message = query(q, dns);
110                if (message == null) {
111                    continue;
112                }
113                if (message.getResponseCode() !=
114                    DNSMessage.RESPONSE_CODE.NO_ERROR) {
115                    continue;
116                }
117                for (Record record: message.getAnswers()) {
118                    if (record.isAnswer(q)) {
119                        return message;
120                    }
121                }
122            } catch (IOException ioe) {
123            }
124        }
125        return null;
126    }
127
128    /**
129     * Retrieve a list of currently configured DNS servers.
130     * @return The server array.
131     */
132    public String[] findDNS() {
133        try {
134            Process process = Runtime.getRuntime().exec("getprop");
135            InputStream inputStream = process.getInputStream();
136            LineNumberReader lnr = new LineNumberReader(
137                new InputStreamReader(inputStream));
138            String line = null;
139            HashSet<String> server = new HashSet<String>(6);
140            while ((line = lnr.readLine()) != null) {
141                int split = line.indexOf("]: [");
142                if (split == -1) {
143                    continue;
144                }
145                String property = line.substring(1, split);
146                String value = line.substring(split + 4, line.length() - 1);
147                if (property.endsWith(".dns") || property.endsWith(".dns1") ||
148                    property.endsWith(".dns2") || property.endsWith(".dns3") ||
149		    property.endsWith(".dns4")) {
150                    server.add(value);
151                }
152            }
153            if (server.size() > 0) {
154                return server.toArray(new String[server.size()]);
155            }
156        } catch (IOException e) {
157            e.printStackTrace();
158        }
159        return null;
160    }
161}