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}