1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.xbill.DNS;
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.*;
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.*;
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.*;
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * An implementation of Resolver that sends one query to one server.
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SimpleResolver handles TCP retries, transaction security (TSIG), and
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * EDNS 0.
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see Resolver
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see TSIG
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see OPTRecord
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Brian Wellington
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class SimpleResolver implements Resolver {
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** The default port to send queries to */
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int DEFAULT_PORT = 53;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** The default EDNS payload size */
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static final int DEFAULT_EDNS_PAYLOADSIZE = 1280;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate InetSocketAddress address;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate InetSocketAddress localAddress;
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate boolean useTCP, ignoreTruncation;
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate OPTRecord queryOPT;
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate TSIG tsig;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate long timeoutValue = 10 * 1000;
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static final short DEFAULT_UDPSIZE = 512;
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static String defaultResolver = "localhost";
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate static int uniqueID = 0;
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a SimpleResolver that will query the specified host
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @exception UnknownHostException Failure occurred while finding the host
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenSimpleResolver(String hostname) throws UnknownHostException {
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (hostname == null) {
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		hostname = ResolverConfig.getCurrentConfig().server();
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (hostname == null)
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			hostname = defaultResolver;
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	InetAddress addr;
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (hostname.equals("0"))
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		addr = InetAddress.getLocalHost();
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	else
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		addr = InetAddress.getByName(hostname);
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	address = new InetSocketAddress(addr, DEFAULT_PORT);
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a SimpleResolver.  The host to query is either found by using
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * ResolverConfig, or the default host is used.
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see ResolverConfig
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @exception UnknownHostException Failure occurred while finding the host
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenSimpleResolver() throws UnknownHostException {
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	this(null);
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Gets the destination address associated with this SimpleResolver.
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Messages sent using this SimpleResolver will be sent to this address.
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The destination address associated with this SimpleResolver.
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenInetSocketAddress
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetAddress() {
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return address;
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** Sets the default host (initially localhost) to query */
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic static void
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetDefaultResolver(String hostname) {
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	defaultResolver = hostname;
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetPort(int port) {
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	address = new InetSocketAddress(address.getAddress(), port);
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sets the address of the server to communicate with.
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param addr The address of the DNS server
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetAddress(InetSocketAddress addr) {
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	address = addr;
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sets the address of the server to communicate with (on the default
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * DNS port)
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param addr The address of the DNS server
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetAddress(InetAddress addr) {
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	address = new InetSocketAddress(addr, address.getPort());
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sets the local address to bind to when sending messages.
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param addr The local address to send messages from.
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetLocalAddress(InetSocketAddress addr) {
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	localAddress = addr;
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sets the local address to bind to when sending messages.  A random port
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * will be used.
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param addr The local address to send messages from.
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetLocalAddress(InetAddress addr) {
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	localAddress = new InetSocketAddress(addr, 0);
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTCP(boolean flag) {
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	this.useTCP = flag;
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetIgnoreTruncation(boolean flag) {
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	this.ignoreTruncation = flag;
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetEDNS(int level, int payloadSize, int flags, List options) {
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (level != 0 && level != -1)
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw new IllegalArgumentException("invalid EDNS level - " +
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						   "must be 0 or -1");
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (payloadSize == 0)
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		payloadSize = DEFAULT_EDNS_PAYLOADSIZE;
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	queryOPT = new OPTRecord(payloadSize, 0, level, flags, options);
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetEDNS(int level) {
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	setEDNS(level, 0, 0, null);
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTSIGKey(TSIG key) {
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	tsig = key;
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenTSIG
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetTSIGKey() {
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return tsig;
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTimeout(int secs, int msecs) {
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	timeoutValue = (long)secs * 1000 + msecs;
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic void
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensetTimeout(int secs) {
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	setTimeout(secs, 0);
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenlong
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChengetTimeout() {
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return timeoutValue;
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate Message
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenparseMessage(byte [] b) throws WireParseException {
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return (new Message(b));
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	catch (IOException e) {
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (Options.check("verbose"))
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			e.printStackTrace();
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (!(e instanceof WireParseException))
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			e = new WireParseException("Error parsing message");
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw (WireParseException) e;
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate void
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenverifyTSIG(Message query, Message response, byte [] b, TSIG tsig) {
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (tsig == null)
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return;
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int error = tsig.verify(response, b, query.getTSIG());
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (Options.check("verbose"))
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		System.err.println("TSIG verify: " + Rcode.TSIGstring(error));
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate void
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenapplyEDNS(Message query) {
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (queryOPT == null || query.getOPT() != null)
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return;
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	query.addRecord(queryOPT, Section.ADDITIONAL);
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate int
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChenmaxUDPSize(Message query) {
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	OPTRecord opt = query.getOPT();
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (opt == null)
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return DEFAULT_UDPSIZE;
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	else
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return opt.getPayloadSize();
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sends a message to a single server and waits for a response.  No checking
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * is done to ensure that the response is associated with the query.
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param query The query to send.
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return The response.
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException An error occurred while sending or receiving.
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Message
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chensend(Message query) throws IOException {
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (Options.check("verbose"))
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		System.err.println("Sending to " +
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				   address.getAddress().getHostAddress() +
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				   ":" + address.getPort());
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (query.getHeader().getOpcode() == Opcode.QUERY) {
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		Record question = query.getQuestion();
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (question != null && question.getType() == Type.AXFR)
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return sendAXFR(query);
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	query = (Message) query.clone();
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	applyEDNS(query);
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (tsig != null)
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		tsig.apply(query, null);
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	byte [] out = query.toWire(Message.MAXLENGTH);
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	int udpSize = maxUDPSize(query);
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	boolean tcp = false;
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	long endTime = System.currentTimeMillis() + timeoutValue;
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	do {
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		byte [] in;
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (useTCP || out.length > udpSize)
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			tcp = true;
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (tcp)
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			in = TCPClient.sendrecv(localAddress, address, out,
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						endTime);
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		else
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			in = UDPClient.sendrecv(localAddress, address, out,
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						udpSize, endTime);
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		/*
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 * Check that the response is long enough.
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 */
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (in.length < Header.LENGTH) {
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw new WireParseException("invalid DNS header - " +
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						     "too short");
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		/*
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 * Check that the response ID matches the query ID.  We want
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 * to check this before actually parsing the message, so that
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 * if there's a malformed response that's not ours, it
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 * doesn't confuse us.
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		 */
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		int id = ((in[0] & 0xFF) << 8) + (in[1] & 0xFF);
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		int qid = query.getHeader().getID();
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (id != qid) {
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			String error = "invalid message id: expected " + qid +
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				       "; got id " + id;
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (tcp) {
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				throw new WireParseException(error);
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			} else {
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (Options.check("verbose")) {
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					System.err.println(error);
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				continue;
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		Message response = parseMessage(in);
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		verifyTSIG(query, response, in, tsig);
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (!tcp && !ignoreTruncation &&
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		    response.getHeader().getFlag(Flags.TC))
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			tcp = true;
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			continue;
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return response;
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	} while (true);
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Asynchronously sends a message to a single server, registering a listener
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to receive a callback on success or exception.  Multiple asynchronous
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * lookups can be performed in parallel.  Since the callback may be invoked
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * before the function returns, external synchronization is necessary.
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param query The query to send
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param listener The object containing the callbacks.
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return An identifier, which is also a parameter in the callback
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic Object
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensendAsync(final Message query, final ResolverListener listener) {
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	final Object id;
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	synchronized (this) {
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		id = new Integer(uniqueID++);
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Record question = query.getQuestion();
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String qname;
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	if (question != null)
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		qname = question.getName().toString();
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	else
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		qname = "(none)";
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	String name = this.getClass() + ": " + qname;
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Thread thread = new ResolveThread(this, query, id, listener);
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	thread.setName(name);
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	thread.setDaemon(true);
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	thread.start();
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return id;
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenprivate Message
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi ChensendAXFR(Message query) throws IOException {
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Name qname = query.getQuestion().getName();
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	ZoneTransferIn xfrin = ZoneTransferIn.newAXFR(qname, address, tsig);
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	xfrin.setTimeout((int)(getTimeout() / 1000));
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	xfrin.setLocalAddress(localAddress);
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	try {
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		xfrin.run();
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	catch (ZoneTransferException e) {
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throw new WireParseException(e.getMessage());
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	List records = xfrin.getAXFR();
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Message response = new Message(query.getHeader().getID());
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	response.getHeader().setFlag(Flags.AA);
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	response.getHeader().setFlag(Flags.QR);
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	response.addRecord(query.getQuestion(), Section.QUESTION);
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Iterator it = records.iterator();
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	while (it.hasNext())
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		response.addRecord((Record)it.next(), Section.ANSWER);
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	return response;
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
352