resolver.c 111 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Bob Halley's avatar
Bob Halley committed
2
 * Copyright (C) 1999, 2000  Internet Software Consortium.
Michael Graff's avatar
Michael Graff committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */
Bob Halley's avatar
Bob Halley committed
17

18
19
#include <config.h>

Bob Halley's avatar
Bob Halley committed
20
#include <isc/assertions.h>
21
#include <isc/boolean.h>
Bob Halley's avatar
Bob Halley committed
22
#include <isc/error.h>
Bob Halley's avatar
Bob Halley committed
23
#include <isc/result.h>
24
#include <isc/types.h>
Bob Halley's avatar
Bob Halley committed
25
26
27
28
29
#include <isc/timer.h>
#include <isc/mutex.h>
#include <isc/event.h>
#include <isc/task.h>
#include <isc/stdtime.h>
Michael Graff's avatar
Michael Graff committed
30
#include <isc/util.h>
31
#include <isc/netaddr.h>
Bob Halley's avatar
Bob Halley committed
32
33

#include <dns/types.h>
Bob Halley's avatar
Bob Halley committed
34
#include <dns/adb.h>
Bob Halley's avatar
Bob Halley committed
35
36
#include <dns/result.h>
#include <dns/name.h>
Bob Halley's avatar
Bob Halley committed
37
#include <dns/db.h>
Bob Halley's avatar
Bob Halley committed
38
#include <dns/events.h>
Bob Halley's avatar
Bob Halley committed
39
#include <dns/keytable.h>
Bob Halley's avatar
Bob Halley committed
40
#include <dns/message.h>
41
#include <dns/ncache.h>
Bob Halley's avatar
Bob Halley committed
42
43
#include <dns/dispatch.h>
#include <dns/resolver.h>
44
#include <dns/rdata.h>
Bob Halley's avatar
Bob Halley committed
45
#include <dns/rdatalist.h>
Bob Halley's avatar
Bob Halley committed
46
#include <dns/rdataset.h>
47
#include <dns/rdatatype.h>
48
#include <dns/tsig.h>
49
#include <dns/validator.h>
50
#include <dns/view.h>
51
#include <dns/log.h>
Bob Halley's avatar
Bob Halley committed
52

53
#include <dst/dst.h>
54
#include <dns/peer.h>
Bob Halley's avatar
Bob Halley committed
55
56
57

#define DNS_RESOLVER_TRACE
#ifdef DNS_RESOLVER_TRACE
58
59
60
#define RTRACE(m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
61
				      ISC_LOG_DEBUG(3), \
62
63
64
65
				      "res %p: %s", res, (m))
#define RRTRACE(r, m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
66
				      ISC_LOG_DEBUG(3), \
67
68
69
70
				      "res %p: %s", (r), (m))
#define FCTXTRACE(m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
71
				      ISC_LOG_DEBUG(3), \
72
73
74
75
				      "fctx %p: %s", fctx, (m))
#define FTRACE(m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
76
				      ISC_LOG_DEBUG(3), \
77
78
79
80
81
				      "fetch %p (fctx %p): %s", \
				      fetch, fetch->private, (m))
#define QTRACE(m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
82
				      ISC_LOG_DEBUG(3), \
83
84
				      "resquery %p (fctx %p): %s", \
				      query, query->fctx, (m))
Bob Halley's avatar
Bob Halley committed
85
86
87
88
89
#else
#define RTRACE(m)
#define RRTRACE(r, m)
#define FCTXTRACE(m)
#define FTRACE(m)
Bob Halley's avatar
Bob Halley committed
90
#define QTRACE(m)
Bob Halley's avatar
Bob Halley committed
91
92
#endif

Bob Halley's avatar
Bob Halley committed
93
94
95
/*
 * Maximum EDNS0 input packet size.
 */
Bob Halley's avatar
Bob Halley committed
96
#define SEND_BUFFER_SIZE		2048		/* XXXRTH  Constant. */
97

Bob Halley's avatar
Bob Halley committed
98
99
typedef struct fetchctx fetchctx_t;

Bob Halley's avatar
Bob Halley committed
100
typedef struct query {
Bob Halley's avatar
Bob Halley committed
101
	/* Locked by task event serialization. */
Bob Halley's avatar
Bob Halley committed
102
103
104
	unsigned int			magic;
	fetchctx_t *			fctx;
	dns_dispatch_t *		dispatch;
Bob Halley's avatar
Bob Halley committed
105
106
	dns_adbaddrinfo_t *		addrinfo;
	isc_time_t			start;
Bob Halley's avatar
Bob Halley committed
107
	dns_messageid_t			id;
Bob Halley's avatar
Bob Halley committed
108
	dns_dispentry_t *		dispentry;
Bob Halley's avatar
Bob Halley committed
109
	ISC_LINK(struct query)		link;
Bob Halley's avatar
Bob Halley committed
110
	isc_buffer_t			buffer;
111
	dns_rdata_any_tsig_t		*tsig;
112
	dns_tsigkey_t			*tsigkey;
Bob Halley's avatar
Bob Halley committed
113
	unsigned int			options;
114
	unsigned int			attributes;
Bob Halley's avatar
Bob Halley committed
115
	unsigned char			data[512];
Bob Halley's avatar
Bob Halley committed
116
117
} resquery_t;

Bob Halley's avatar
Bob Halley committed
118
119
120
121
#define QUERY_MAGIC			0x51212121U	/* Q!!! */
#define VALID_QUERY(query)		((query) != NULL && \
					 (query)->magic == QUERY_MAGIC)

122
123
124
125
126
127
128
129
#define RESQUERY_ATTR_CONNECTING	0x01
#define RESQUERY_ATTR_CANCELED		0x02

#define RESQUERY_CONNECTING(q)		(((q)->attributes & \
					  RESQUERY_ATTR_CONNECTING) != 0)
#define RESQUERY_CANCELED(q)		(((q)->attributes & \
					  RESQUERY_ATTR_CANCELED) != 0)

Bob Halley's avatar
Bob Halley committed
130
typedef enum {
Bob Halley's avatar
Bob Halley committed
131
	fetchstate_init = 0,		/* Start event has not run yet. */
Bob Halley's avatar
Bob Halley committed
132
	fetchstate_active,
Bob Halley's avatar
Bob Halley committed
133
	fetchstate_done			/* FETCHDONE events posted. */
Bob Halley's avatar
Bob Halley committed
134
135
} fetchstate;

Bob Halley's avatar
Bob Halley committed
136
137
struct fetchctx {
	/* Not locked. */
Bob Halley's avatar
Bob Halley committed
138
139
140
	unsigned int			magic;
	dns_resolver_t *		res;
	dns_name_t			name;
Bob Halley's avatar
Bob Halley committed
141
	dns_rdatatype_t			type;
Bob Halley's avatar
Bob Halley committed
142
	unsigned int			options;
Bob Halley's avatar
Bob Halley committed
143
	unsigned int			bucketnum;
Bob Halley's avatar
Bob Halley committed
144
	/* Locked by appropriate bucket lock. */
Bob Halley's avatar
Bob Halley committed
145
	fetchstate			state;
Bob Halley's avatar
Bob Halley committed
146
	isc_boolean_t			want_shutdown;
Bob Halley's avatar
Bob Halley committed
147
	unsigned int			references;
Bob Halley's avatar
lint    
Bob Halley committed
148
	isc_event_t			control_event;
Bob Halley's avatar
Bob Halley committed
149
150
	ISC_LINK(struct fetchctx)	link;
	ISC_LIST(dns_fetchevent_t)	events;
Bob Halley's avatar
Bob Halley committed
151
	/* Locked by task event serialization. */
Bob Halley's avatar
Bob Halley committed
152
153
	dns_name_t			domain;
	dns_rdataset_t			nameservers;
Bob Halley's avatar
Bob Halley committed
154
	unsigned int			attributes;
Bob Halley's avatar
Bob Halley committed
155
156
157
	isc_timer_t *			timer;
	isc_time_t			expires;
	isc_interval_t			interval;
Bob Halley's avatar
Bob Halley committed
158
159
	dns_message_t *			qmessage;
	dns_message_t *			rmessage;
Bob Halley's avatar
Bob Halley committed
160
	ISC_LIST(resquery_t)		queries;
Bob Halley's avatar
Bob Halley committed
161
	dns_adbfindlist_t		finds;
Bob Halley's avatar
Bob Halley committed
162
	dns_adbfind_t *			find;
163
164
	dns_adbaddrinfolist_t		forwaddrs;
	isc_sockaddrlist_t		forwarders;
Bob Halley's avatar
Bob Halley committed
165
	isc_sockaddrlist_t		bad;
166
	dns_validator_t *		validator;	
Bob Halley's avatar
Bob Halley committed
167
168
169
	/*
	 * # of events we're waiting for.
	 */
Bob Halley's avatar
Bob Halley committed
170
	unsigned int			pending;
171
	unsigned int			validating;
Bob Halley's avatar
Bob Halley committed
172
	unsigned int			restarts;
Bob Halley's avatar
Bob Halley committed
173
};
Bob Halley's avatar
Bob Halley committed
174
175
176
177
178

#define FCTX_MAGIC			0x46212121U	/* F!!! */
#define VALID_FCTX(fctx)		((fctx) != NULL && \
					 (fctx)->magic == FCTX_MAGIC)

Bob Halley's avatar
Bob Halley committed
179
180
#define FCTX_ATTR_HAVEANSWER		0x01
#define FCTX_ATTR_GLUING		0x02
Bob Halley's avatar
Bob Halley committed
181
#define FCTX_ATTR_ADDRWAIT		0x04
Bob Halley's avatar
Bob Halley committed
182
#define FCTX_ATTR_SHUTTINGDOWN		0x08
Bob Halley's avatar
Bob Halley committed
183
184
#define FCTX_ATTR_WANTCACHE		0x10
#define FCTX_ATTR_WANTNCACHE		0x20
185
#define FCTX_ATTR_NEEDEDNS0		0x40
Bob Halley's avatar
Bob Halley committed
186
187
188
189
190

#define HAVE_ANSWER(f)		(((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
				 0)
#define GLUING(f)		(((f)->attributes & FCTX_ATTR_GLUING) != \
				 0)
Bob Halley's avatar
Bob Halley committed
191
192
#define ADDRWAIT(f)		(((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
				 0)
Bob Halley's avatar
Bob Halley committed
193
194
#define SHUTTINGDOWN(f)		(((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
 				 != 0)
Bob Halley's avatar
Bob Halley committed
195
196
#define WANTCACHE(f)		(((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
#define WANTNCACHE(f)		(((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
197
#define NEEDEDNS0(f)		(((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
Bob Halley's avatar
Bob Halley committed
198

Bob Halley's avatar
Bob Halley committed
199
200
201
202
203
204
205
206
207
208
209
210
211
struct dns_fetch {
	unsigned int			magic;
	void *				private;
};

#define DNS_FETCH_MAGIC			0x46746368U	/* Ftch */
#define DNS_FETCH_VALID(fetch)		((fetch) != NULL && \
					 (fetch)->magic == DNS_FETCH_MAGIC)

typedef struct fctxbucket {
	isc_task_t *			task;
	isc_mutex_t			lock;
	ISC_LIST(fetchctx_t)		fctxs;
Bob Halley's avatar
Bob Halley committed
212
	isc_boolean_t			exiting;
Bob Halley's avatar
Bob Halley committed
213
214
} fctxbucket_t;

Bob Halley's avatar
Bob Halley committed
215
struct dns_resolver {
Bob Halley's avatar
Bob Halley committed
216
	/* Unlocked. */
Bob Halley's avatar
Bob Halley committed
217
218
219
220
	unsigned int			magic;
	isc_mem_t *			mctx;
	isc_mutex_t			lock;
	dns_rdataclass_t		rdclass;
Bob Halley's avatar
Bob Halley committed
221
	isc_socketmgr_t *		socketmgr;
Bob Halley's avatar
Bob Halley committed
222
	isc_timermgr_t *		timermgr;
223
	dns_view_t *			view;
224
225
226
	isc_boolean_t			frozen;
	isc_sockaddrlist_t		forwarders;
	dns_fwdpolicy_t			fwdpolicy;
227
228
229
230
231
	unsigned int			options;
	isc_socket_t *			udpsocketv4;
	isc_socket_t *			udpsocketv6;
	dns_dispatch_t *		dispatchv4;
	dns_dispatch_t *		dispatchv6;
Bob Halley's avatar
Bob Halley committed
232
233
	unsigned int			nbuckets;
	fctxbucket_t *			buckets;
234
235
236
237
238
	/* Locked by lock. */
	unsigned int			references;
	isc_boolean_t			exiting;
	isc_eventlist_t			whenshutdown;
	unsigned int			activebuckets;
Bob Halley's avatar
Bob Halley committed
239
240
	isc_boolean_t			priming;
	dns_fetch_t *			primefetch;
Bob Halley's avatar
Bob Halley committed
241
242
243
244
245
246
};

#define RES_MAGIC			0x52657321U	/* Res! */
#define VALID_RESOLVER(res)		((res) != NULL && \
					 (res)->magic == RES_MAGIC)

247
248
249
250
251
252
253
254
255
256
/*
 * Private addrinfo flags.  These must not conflict with DNS_FETCHOPT_NOEDNS0,
 * which we also use as an addrinfo flag.
 */
#define FCTX_ADDRINFO_MARK		0x0001
#define FCTX_ADDRINFO_FORWARDER		0x1000
#define UNMARKED(a)			(((a)->flags & FCTX_ADDRINFO_MARK) \
					 == 0)
#define ISFORWARDER(a)			(((a)->flags & \
					 FCTX_ADDRINFO_FORWARDER) != 0)
Bob Halley's avatar
Bob Halley committed
257
258

static void destroy(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
259
static void empty_bucket(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
260
static isc_result_t resquery_send(resquery_t *query);
Bob Halley's avatar
Bob Halley committed
261
static void resquery_response(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
262
static void resquery_connected(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
263
static void fctx_try(fetchctx_t *fctx);
Bob Halley's avatar
Bob Halley committed
264
static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
Bob Halley's avatar
Bob Halley committed
265

Bob Halley's avatar
Bob Halley committed
266
static inline isc_result_t
Bob Halley's avatar
Bob Halley committed
267
fctx_starttimer(fetchctx_t *fctx) {
268
269
	/*
	 * Start the lifetime timer for fctx.
270
271
272
273
	 *
	 * This is also used for stopping the idle timer; in that
	 * case we must purge events already posted to ensure that
	 * no further idle events are delivered.
274
	 */
Bob Halley's avatar
Bob Halley committed
275
276
	return (isc_timer_reset(fctx->timer, isc_timertype_once,
				&fctx->expires, NULL,
277
				ISC_TRUE));
Bob Halley's avatar
Bob Halley committed
278
279
}

Bob Halley's avatar
Bob Halley committed
280
281
static inline void
fctx_stoptimer(fetchctx_t *fctx) {
Bob Halley's avatar
Bob Halley committed
282
	isc_result_t result;
Bob Halley's avatar
Bob Halley committed
283
284
285
286
287
288
289

	/*
	 * We don't return a result if resetting the timer to inactive fails
	 * since there's nothing to be done about it.  Resetting to inactive
	 * should never fail anyway, since the code as currently written
	 * cannot fail in that case.
	 */
Bob Halley's avatar
Bob Halley committed
290
	result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
Bob Halley's avatar
Bob Halley committed
291
				  NULL, NULL, ISC_TRUE);
Bob Halley's avatar
Bob Halley committed
292
	if (result != ISC_R_SUCCESS) {
Bob Halley's avatar
Bob Halley committed
293
294
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_timer_reset(): %s",
Bob Halley's avatar
Bob Halley committed
295
				 isc_result_totext(result));
Bob Halley's avatar
Bob Halley committed
296
297
298
	}
}

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317

static inline isc_result_t
fctx_startidletimer(fetchctx_t *fctx) {
	/*
	 * Start the idle timer for fctx.  The lifetime timer continues
	 * to be in effect.
	 */
	return (isc_timer_reset(fctx->timer, isc_timertype_once,
				&fctx->expires, &fctx->interval,
				ISC_FALSE));
}

/*
 * Stopping the idle timer is equivalent to calling fctx_starttimer(), but
 * we use fctx_stopidletimer for readability in the code below.
 */
#define fctx_stopidletimer	fctx_starttimer


318
319
320
321
322
323
324
325
326
327
328
329
330
static inline void
resquery_destroy(resquery_t **queryp) {
	resquery_t *query;
	
	REQUIRE(queryp != NULL);
	query = *queryp;
	REQUIRE(!ISC_LINK_LINKED(query, link));

	query->magic = 0;
	isc_mem_put(query->fctx->res->mctx, query, sizeof *query);
	*queryp = NULL;
}

Bob Halley's avatar
Bob Halley committed
331
static void
Bob Halley's avatar
Bob Halley committed
332
fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
333
		 isc_time_t *finish, isc_boolean_t no_response)
Bob Halley's avatar
Bob Halley committed
334
{
Bob Halley's avatar
Bob Halley committed
335
336
	fetchctx_t *fctx;
	resquery_t *query;
Bob Halley's avatar
Bob Halley committed
337
338
	unsigned int rtt;
	unsigned int factor;
339
	isc_socket_t *socket;
Bob Halley's avatar
Bob Halley committed
340

Bob Halley's avatar
Bob Halley committed
341
342
343
	query = *queryp;
	fctx = query->fctx;

Bob Halley's avatar
Bob Halley committed
344
345
	FCTXTRACE("cancelquery");

346
347
348
349
	REQUIRE(!RESQUERY_CANCELED(query));

	query->attributes |= RESQUERY_ATTR_CANCELED;

Bob Halley's avatar
Bob Halley committed
350
	/*
351
	 * Should we update the RTT?
Bob Halley's avatar
Bob Halley committed
352
	 */
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
	if (finish != NULL || no_response) {
		if (finish != NULL) {
			/*
			 * We have both the start and finish times for this
			 * packet, so we can compute a real RTT.
			 */
			rtt = (unsigned int)isc_time_microdiff(finish,
							       &query->start);
			factor = DNS_ADB_RTTADJDEFAULT;
		} else {
			/*
			 * We don't have an RTT for this query.  Maybe the
			 * packet was lost, or maybe this server is very
			 * slow.  We don't know.  Increase the RTT.
			 */
			INSIST(no_response);
			rtt = query->addrinfo->srtt +
				(100000 * fctx->restarts);
			if (rtt > 10000000)
				rtt = 10000000;
			/*
			 * Replace the current RTT with our value.
			 */
			factor = DNS_ADB_RTTADJREPLACE;
		}
		dns_adb_adjustsrtt(fctx->res->view->adb, query->addrinfo, rtt,
				   factor);
Bob Halley's avatar
Bob Halley committed
380
381
	}

Bob Halley's avatar
Bob Halley committed
382
383
384
	if (query->dispentry != NULL)
		dns_dispatch_removeresponse(query->dispatch, &query->dispentry,
					    deventp);
Bob Halley's avatar
Bob Halley committed
385
	ISC_LIST_UNLINK(fctx->queries, query, link);
386
	if (query->tsig != NULL) {
Bob Halley's avatar
Bob Halley committed
387
		dns_rdata_freestruct(query->tsig);
388
389
390
		isc_mem_put(query->fctx->res->mctx, query->tsig,
			    sizeof(*query->tsig));
	}
391
392
393
394
395
396
397
	if (RESQUERY_CONNECTING(query)) {
		/*
		 * Cancel the connect.
		 */
		socket = dns_dispatch_getsocket(query->dispatch);
		isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
	}
Bob Halley's avatar
Bob Halley committed
398
	dns_dispatch_detach(&query->dispatch);
399
400
401
402
403
404
	if (!RESQUERY_CONNECTING(query)) {
		/*
		 * It's safe to destroy the query now.
		 */
		resquery_destroy(&query);
	}
Bob Halley's avatar
Bob Halley committed
405
406
407
}

static void
408
fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
Bob Halley's avatar
Bob Halley committed
409
410
411
412
413
414
415
416
	resquery_t *query, *next_query;

	FCTXTRACE("cancelqueries");

	for (query = ISC_LIST_HEAD(fctx->queries);
	     query != NULL;
	     query = next_query) {
		next_query = ISC_LIST_NEXT(query, link);
417
		fctx_cancelquery(&query, NULL, NULL, no_response);
Bob Halley's avatar
Bob Halley committed
418
419
420
	}
}

Bob Halley's avatar
Bob Halley committed
421
static void
Bob Halley's avatar
Bob Halley committed
422
423
424
fctx_cleanupfinds(fetchctx_t *fctx) {
	dns_adbfind_t *find, *next_find;

Bob Halley's avatar
Bob Halley committed
425
426
	REQUIRE(ISC_LIST_EMPTY(fctx->queries));

Bob Halley's avatar
Bob Halley committed
427
428
429
430
431
432
	for (find = ISC_LIST_HEAD(fctx->finds);
	     find != NULL;
	     find = next_find) {
		next_find = ISC_LIST_NEXT(find, publink);
		ISC_LIST_UNLINK(fctx->finds, find, publink);
		dns_adb_destroyfind(&find);
Bob Halley's avatar
Bob Halley committed
433
	}
Bob Halley's avatar
Bob Halley committed
434
	fctx->find = NULL;
Bob Halley's avatar
Bob Halley committed
435
436
}

437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
static void
fctx_cleanupforwaddrs(fetchctx_t *fctx) {
	dns_adbaddrinfo_t *addr, *next_addr;

	REQUIRE(ISC_LIST_EMPTY(fctx->queries));

	for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
	     addr != NULL;
	     addr = next_addr) {
		next_addr = ISC_LIST_NEXT(addr, publink);
		ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
		dns_adb_freeaddrinfo(fctx->res->view->adb, &addr);
	}
}

Bob Halley's avatar
Bob Halley committed
452
static inline void
453
fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
Bob Halley's avatar
Bob Halley committed
454
	FCTXTRACE("stopeverything");
455
	fctx_cancelqueries(fctx, no_response);
Bob Halley's avatar
Bob Halley committed
456
	fctx_cleanupfinds(fctx);
457
	fctx_cleanupforwaddrs(fctx);
Bob Halley's avatar
Bob Halley committed
458
	fctx_stoptimer(fctx);
Bob Halley's avatar
Bob Halley committed
459
}
Bob Halley's avatar
Bob Halley committed
460

Bob Halley's avatar
Bob Halley committed
461
462
463
464
static inline void
fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
	dns_fetchevent_t *event, *next_event;
	isc_task_t *task;
Bob Halley's avatar
Bob Halley committed
465

Bob Halley's avatar
Bob Halley committed
466
467
468
469
470
471
	/*
	 * Caller must be holding the appropriate bucket lock.
	 */
	REQUIRE(fctx->state == fetchstate_done);

	FCTXTRACE("sendevents");
Bob Halley's avatar
Bob Halley committed
472
473
474
475

	for (event = ISC_LIST_HEAD(fctx->events);
	     event != NULL;
	     event = next_event) {
476
477
478
		next_event = ISC_LIST_NEXT(event, ev_link);
		task = event->ev_sender;
		event->ev_sender = fctx;
Bob Halley's avatar
Bob Halley committed
479
		if (!HAVE_ANSWER(fctx))
480
			event->result = result;
481
		isc_task_sendanddetach(&task, (isc_event_t **)&event);
Bob Halley's avatar
Bob Halley committed
482
483
	}
	ISC_LIST_INIT(fctx->events);
Bob Halley's avatar
Bob Halley committed
484
}
Bob Halley's avatar
Bob Halley committed
485

Bob Halley's avatar
Bob Halley committed
486
487
488
static void
fctx_done(fetchctx_t *fctx, isc_result_t result) {
	dns_resolver_t *res;
489
	isc_boolean_t no_response;
Bob Halley's avatar
Bob Halley committed
490
491
492
493
494

	FCTXTRACE("done");

	res = fctx->res;

495
496
497
498
499
	if (result == ISC_R_SUCCESS)
		no_response = ISC_TRUE;
	else
		no_response = ISC_FALSE;
	fctx_stopeverything(fctx, no_response);
Bob Halley's avatar
Bob Halley committed
500
501
502
503
504

	LOCK(&res->buckets[fctx->bucketnum].lock);

	fctx->state = fetchstate_done;
	fctx_sendevents(fctx, result);
Bob Halley's avatar
Bob Halley committed
505
506

	UNLOCK(&res->buckets[fctx->bucketnum].lock);
Bob Halley's avatar
Bob Halley committed
507
508
}

Bob Halley's avatar
Bob Halley committed
509
static void
Bob Halley's avatar
Bob Halley committed
510
resquery_senddone(isc_task_t *task, isc_event_t *event) {
Bob Halley's avatar
Bob Halley committed
511
	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
512
	resquery_t *query = event->ev_arg;
Bob Halley's avatar
Bob Halley committed
513

514
	REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
Bob Halley's avatar
Bob Halley committed
515

Bob Halley's avatar
Bob Halley committed
516
517
	QTRACE("senddone");

Bob Halley's avatar
Bob Halley committed
518
519
520
521
522
523
524
525
	/*
	 * XXXRTH
	 *
	 * Currently we don't wait for the senddone event before retrying
	 * a query.  This means that if we get really behind, we may end
	 * up doing extra work!
	 */

Andreas Gustafsson's avatar
Andreas Gustafsson committed
526
	UNUSED(task);
Bob Halley's avatar
Bob Halley committed
527

Bob Halley's avatar
Bob Halley committed
528
	if (sevent->result != ISC_R_SUCCESS)
529
		fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
Bob Halley's avatar
Bob Halley committed
530
				 
Bob Halley's avatar
Bob Halley committed
531
532
533
	isc_event_free(&event);
}

Bob Halley's avatar
Bob Halley committed
534
535
536
537
538
static inline isc_result_t
fctx_addopt(dns_message_t *message) {
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
	dns_rdata_t *rdata;
Bob Halley's avatar
Bob Halley committed
539
	isc_result_t result;
Bob Halley's avatar
Bob Halley committed
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572

	rdatalist = NULL;
	result = dns_message_gettemprdatalist(message, &rdatalist);
	if (result != ISC_R_SUCCESS)
		return (result);
	rdata = NULL;
	result = dns_message_gettemprdata(message, &rdata);
	if (result != ISC_R_SUCCESS)
		return (result);
	rdataset = NULL;
	result = dns_message_gettemprdataset(message, &rdataset);
	if (result != ISC_R_SUCCESS)
		return (result);
	dns_rdataset_init(rdataset);

	rdatalist->type = dns_rdatatype_opt;
	rdatalist->covers = 0;

	/*
	 * Set Maximum UDP buffer size.
	 */
	rdatalist->rdclass = SEND_BUFFER_SIZE;

	/*
	 * Set EXTENDED-RCODE, VERSION, and Z to 0.
	 */
	rdatalist->ttl = 0;

	/*
	 * No ENDS options.
	 */
	rdata->data = NULL;
	rdata->length = 0;
573
574
	rdata->rdclass = rdatalist->rdclass;
	rdata->type = rdatalist->type;
Bob Halley's avatar
Bob Halley committed
575
576
577
578
579
580
581
582

	ISC_LIST_INIT(rdatalist->rdata);
	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
	dns_rdatalist_tordataset(rdatalist, rdataset);

	return (dns_message_setopt(message, rdataset));
}

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
static inline void
fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
	unsigned int seconds;

	/*
	 * We retry every 2 seconds the first two times through the address
	 * list, and then we do exponential back-off.
	 */
	if (fctx->restarts < 3)
		seconds = 2;
	else
		seconds = (2 << (fctx->restarts - 1));

	/*
	 * Double the round-trip time and convert to seconds.
	 */
	rtt /= 500000;
	
	/*
	 * Always wait for at least the doubled round-trip time.
	 */
	if (seconds < rtt)
		seconds = rtt;

	/*
	 * But don't ever wait for more than 30 seconds.
	 */
	if (seconds > 30)
		seconds = 30;

	isc_interval_set(&fctx->interval, seconds, 0);
}

Bob Halley's avatar
Bob Halley committed
616
617
618
619
static isc_result_t
fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
	   unsigned int options)
{
Bob Halley's avatar
Bob Halley committed
620
621
	dns_resolver_t *res;
	isc_task_t *task;
Bob Halley's avatar
Bob Halley committed
622
623
624
	isc_result_t result;
	resquery_t *query;
	isc_socket_t *socket;
Bob Halley's avatar
Bob Halley committed
625

Bob Halley's avatar
Bob Halley committed
626
	FCTXTRACE("query");
Bob Halley's avatar
Bob Halley committed
627

Bob Halley's avatar
Bob Halley committed
628
629
	res = fctx->res;
	task = res->buckets[fctx->bucketnum].task;
Bob Halley's avatar
Bob Halley committed
630

631
	fctx_setretryinterval(fctx, addrinfo->srtt);
632
	result = fctx_startidletimer(fctx);
Bob Halley's avatar
Bob Halley committed
633
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
634
635
		return (result);

636
	INSIST(fctx->validator == NULL); /* Validator needs rmessage. */
Bob Halley's avatar
Bob Halley committed
637
	dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
Bob Halley's avatar
Bob Halley committed
638

Bob Halley's avatar
Bob Halley committed
639
	query = isc_mem_get(res->mctx, sizeof *query);
Bob Halley's avatar
Bob Halley committed
640
641
	if (query == NULL) {
		result = ISC_R_NOMEMORY; 
642
		goto stop_idle_timer;
Bob Halley's avatar
Bob Halley committed
643
	}
Bob Halley's avatar
Bob Halley committed
644
	query->options = options;
645
	query->attributes = 0;
Bob Halley's avatar
Bob Halley committed
646
647
648
649
650
651
652
653
	/*
	 * Note that the caller MUST guarantee that 'addrinfo' will remain
	 * valid until this query is canceled.
	 */
	query->addrinfo = addrinfo;
	result = isc_time_now(&query->start);
	if (result != ISC_R_SUCCESS)
		goto cleanup_query;
Bob Halley's avatar
Bob Halley committed
654
655
656
657
	
	/*
	 * If this is a TCP query, then we need to make a socket and
	 * a dispatch for it here.  Otherwise we use the resolver's
Bob Halley's avatar
Bob Halley committed
658
659
660
661
662
663
664
665
666
667
668
669
	 * shared dispatch.
	 */
	query->dispatch = NULL;
	if ((query->options & DNS_FETCHOPT_TCP) != 0) {
		socket = NULL;
		result = isc_socket_create(res->socketmgr,
					   isc_sockaddr_pf(addrinfo->sockaddr),
					   isc_sockettype_tcp,
					   &socket);
		if (result != ISC_R_SUCCESS)
			goto cleanup_query;
		result = dns_dispatch_create(res->mctx, socket, task,
670
					     4096, 2, 1, 1, 3, NULL,
671
					     &query->dispatch);
Bob Halley's avatar
Bob Halley committed
672
673
674
675
676
677
678
		/*
		 * Regardless of whether dns_dispatch_create() succeeded or
		 * not, we don't need our reference to the socket anymore.
		 */
		isc_socket_detach(&socket);
		if (result != ISC_R_SUCCESS)
			goto cleanup_dispatch;
Bob Halley's avatar
Bob Halley committed
679
	} else {
Bob Halley's avatar
Bob Halley committed
680
		switch (isc_sockaddr_pf(addrinfo->sockaddr)) {
Bob Halley's avatar
Bob Halley committed
681
		case PF_INET:
682
			dns_dispatch_attach(res->dispatchv4, &query->dispatch);
Bob Halley's avatar
Bob Halley committed
683
			break;
Bob Halley's avatar
Bob Halley committed
684
		case PF_INET6:
685
			dns_dispatch_attach(res->dispatchv6, &query->dispatch);
Bob Halley's avatar
Bob Halley committed
686
687
			break;
		default:
688
			result = ISC_R_NOTIMPLEMENTED;
Bob Halley's avatar
Bob Halley committed
689
			goto cleanup_dispatch;
Bob Halley's avatar
Bob Halley committed
690
691
692
693
694
695
696
697
698
699
		}
		/*
		 * We should always have a valid dispatcher here.  If we
		 * don't support a protocol family, then its dispatcher
		 * will be NULL, but we shouldn't be finding addresses for
		 * protocol types we don't support, so the dispatcher
		 * we found should never be NULL.
		 */
		INSIST(query->dispatch != NULL);
	}
Bob Halley's avatar
Bob Halley committed
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717

	query->dispentry = NULL;
	query->fctx = fctx;
	query->tsig = NULL;
	query->tsigkey = NULL;
	query->magic = QUERY_MAGIC;

	if ((query->options & DNS_FETCHOPT_TCP) != 0) {
		/*
		 * Connect to the remote server.
		 *
		 * XXXRTH  Should we attach to the socket?
		 */
		socket = dns_dispatch_getsocket(query->dispatch);
		result = isc_socket_connect(socket, addrinfo->sockaddr,
					    task, resquery_connected, query);
		if (result != ISC_R_SUCCESS)
			goto cleanup_dispatch;
718
		query->attributes |= RESQUERY_ATTR_CONNECTING;
Bob Halley's avatar
Bob Halley committed
719
720
721
722
723
724
725
		QTRACE("connecting via TCP");
	} else {
		result = resquery_send(query);
		if (result != ISC_R_SUCCESS)
			goto cleanup_dispatch;
	}

726
727
	ISC_LIST_APPEND(fctx->queries, query, link);

Bob Halley's avatar
Bob Halley committed
728
729
730
731
732
733
734
735
736
	return (ISC_R_SUCCESS);

 cleanup_dispatch:
	dns_dispatch_detach(&query->dispatch);

 cleanup_query:
	query->magic = 0;
	isc_mem_put(res->mctx, query, sizeof *query);

737
738
 stop_idle_timer:
	fctx_stopidletimer(fctx);
Bob Halley's avatar
Bob Halley committed
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755

	return (result);
}

static isc_result_t
resquery_send(resquery_t *query) {
	fetchctx_t *fctx;
	isc_result_t result;
	dns_rdataset_t *qrdataset, *trdataset;
	dns_name_t *qname;
	isc_region_t r;
	dns_resolver_t *res;
	isc_task_t *task;
	isc_socket_t *socket;
	isc_buffer_t tcpbuffer;
	isc_sockaddr_t *address;
	isc_buffer_t *buffer;
756
757
758
	dns_peer_t *peer = NULL;
	dns_name_t *keyname = NULL;
	isc_netaddr_t ipaddr;
Bob Halley's avatar
Bob Halley committed
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791

	fctx = query->fctx;
	QTRACE("send");

	res = fctx->res;
	task = res->buckets[fctx->bucketnum].task;
	address = NULL;

	if ((query->options & DNS_FETCHOPT_TCP) != 0) {
		/*
		 * Reserve space for the TCP message length.
		 */
		isc_buffer_init(&tcpbuffer, query->data,
				sizeof query->data, ISC_BUFFERTYPE_BINARY);
		isc_buffer_init(&query->buffer, query->data + 2,
				sizeof query->data - 2,
				ISC_BUFFERTYPE_BINARY);
		buffer = &tcpbuffer;
	} else {
		isc_buffer_init(&query->buffer, query->data,
				sizeof query->data, ISC_BUFFERTYPE_BINARY);
		buffer = &query->buffer;
	}

	qname = NULL;
	result = dns_message_gettempname(fctx->qmessage, &qname);
	if (result != ISC_R_SUCCESS)
		goto cleanup_temps;
	qrdataset = NULL;
	result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
	if (result != ISC_R_SUCCESS)
		goto cleanup_temps;

Bob Halley's avatar
Bob Halley committed
792
	/*
Bob Halley's avatar
Bob Halley committed
793
	 * Get a query id from the dispatch.
Bob Halley's avatar
Bob Halley committed
794
	 */
Bob Halley's avatar
Bob Halley committed
795
	result = dns_dispatch_addresponse(query->dispatch,
Bob Halley's avatar
Bob Halley committed
796
					  query->addrinfo->sockaddr,
Bob Halley's avatar
Bob Halley committed
797
					  task,
Bob Halley's avatar
Bob Halley committed
798
					  resquery_response,
Bob Halley's avatar
Bob Halley committed
799
800
801
					  query,
					  &query->id,
					  &query->dispentry);
Bob Halley's avatar
Bob Halley committed
802
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
803
		goto cleanup_temps;
Bob Halley's avatar
Bob Halley committed
804
805
806
807
808
809

	fctx->qmessage->opcode = dns_opcode_query;

	/*
	 * Set up question.
	 */
Bob Halley's avatar
Bob Halley committed
810
811
812
813
814
815
	dns_name_init(qname, NULL);
	dns_name_clone(&fctx->name, qname);
	dns_rdataset_init(qrdataset);
	dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
	ISC_LIST_APPEND(qname->list, qrdataset, link);
	dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
816
817
	qname = NULL;
	qrdataset = NULL;
818
819
820
821
822
823
824

	/*
	 * Set RD if the client has requested that we do a recursive query,
	 * or if we're sending to a forwarder.
	 */
	if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||
	    ISFORWARDER(query->addrinfo))
Bob Halley's avatar
Bob Halley committed
825
		fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;
826

Bob Halley's avatar
Bob Halley committed
827
828
829
	/*
	 * We don't have to set opcode because it defaults to query.
	 */
Bob Halley's avatar
Bob Halley committed
830
	fctx->qmessage->id = query->id;
Bob Halley's avatar
Bob Halley committed
831

Bob Halley's avatar
Bob Halley committed
832
833
834
	/*
	 * Convert the question to wire format.
	 */
Bob Halley's avatar
Bob Halley committed
835
	result = dns_message_renderbegin(fctx->qmessage, &query->buffer);
Bob Halley's avatar
Bob Halley committed
836
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
837
		goto cleanup_message;
Bob Halley's avatar
Bob Halley committed
838

Bob Halley's avatar
Bob Halley committed
839
	result = dns_message_rendersection(fctx->qmessage,
Michael Graff's avatar
Michael Graff committed
840
					   DNS_SECTION_QUESTION, 0);
Bob Halley's avatar
Bob Halley committed
841
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
842
		goto cleanup_message;
Bob Halley's avatar
Bob Halley committed
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869

	/*
	 * Use EDNS0, unless the caller doesn't want it, or we know that
	 * the remote server doesn't like it.
	 */
	if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
		if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
			trdataset = NULL;
			result = fctx_addopt(fctx->qmessage);
			if (result != ISC_R_SUCCESS) {
				/*
				 * We couldn't add the OPT, but we'll press on.
				 * We're not using EDNS0, so set the NOEDNS0
				 * bit.
				 */
				query->options |= DNS_FETCHOPT_NOEDNS0;
			}
		} else {
			/*
			 * We know this server doesn't like EDNS0, so we
			 * won't use it.  Set the NOEDNS0 bit since we're
			 * not using EDNS0.
			 */
			query->options |= DNS_FETCHOPT_NOEDNS0;
		}
	}

870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
	/*
	 * If we need EDNS0 to do this query and aren't using it, we lose.
	 */
	if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) {
		result = DNS_R_SERVFAIL;
		goto cleanup_message;
	}

	/*
	 * If we're using EDNS, set AD and CD so we'll get DNSSEC data.
	 */
	if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
		fctx->qmessage->flags |=
			(DNS_MESSAGEFLAG_AD|DNS_MESSAGEFLAG_CD);

Bob Halley's avatar
Bob Halley committed
885
	/*
886
	 * Add TSIG record tailored to the current recipient.
Bob Halley's avatar
Bob Halley committed
887
	 */
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
	isc_netaddr_fromsockaddr(&ipaddr, query->addrinfo->sockaddr);
	result = dns_peerlist_peerbyaddr(fctx->res->view->peers,
					 &ipaddr, &peer);

	if (result == ISC_R_SUCCESS &&
	    dns_peer_getkey(peer, &keyname) == ISC_R_SUCCESS)
	{
		result = dns_tsigkey_find(&fctx->qmessage->tsigkey,
					  keyname, NULL,
					  fctx->res->view->statickeys);
		if (result == ISC_R_NOTFOUND)
			result = dns_tsigkey_find(&fctx->qmessage->tsigkey,
						  keyname, NULL,
						  fctx->res->view->dynamickeys);
		if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
			goto cleanup_message;
	}
Bob Halley's avatar
Bob Halley committed
905

Bob Halley's avatar
Bob Halley committed
906
	result = dns_message_rendersection(fctx->qmessage,
Michael Graff's avatar
Michael Graff committed
907
					   DNS_SECTION_ADDITIONAL, 0);
Bob Halley's avatar
Bob Halley committed
908
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
909
		goto cleanup_message;
Bob Halley's avatar
Bob Halley committed
910

Bob Halley's avatar
Bob Halley committed
911
	result = dns_message_renderend(fctx->qmessage);
Bob Halley's avatar
Bob Halley committed
912
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
913
914
		goto cleanup_message;

915
916
917
918
	if (fctx->qmessage->tsigkey != NULL) {
		query->tsigkey = fctx->qmessage->tsigkey;
		query->tsig = fctx->qmessage->tsig;
		fctx->qmessage->tsig = NULL;
919
		fctx->qmessage->tsigkey = NULL;
920
921
	}

Bob Halley's avatar
Bob Halley committed
922
923
924
925
926
927
928
929
930
931
	/*
	 * If using TCP, write the length of the message at the beginning
	 * of the buffer.
	 */
	if ((query->options & DNS_FETCHOPT_TCP) != 0) {
		isc_buffer_used(&query->buffer, &r);
		isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
		isc_buffer_add(&tcpbuffer, r.length);
	}

Bob Halley's avatar
Bob Halley committed
932
933
934
935
	/*
	 * We're now done with the query message.
	 */
	dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
Bob Halley's avatar
Bob Halley committed
936

Bob Halley's avatar
Bob Halley committed
937
	socket = dns_dispatch_getsocket(query->dispatch);
Bob Halley's avatar
Bob Halley committed
938
939
940
	/*
	 * Send the query!
	 */
Bob Halley's avatar
Bob Halley committed
941
942
943
	if ((query->options & DNS_FETCHOPT_TCP) == 0)
		address = query->addrinfo->sockaddr;
	isc_buffer_used(buffer, &r);
944
945
946
947
	/*
	 * XXXRTH  Make sure we don't send to ourselves!  We should probably
	 *         prune out these addresses when we get them from the ADB.
	 */
Bob Halley's avatar
Bob Halley committed
948
	result = isc_socket_sendto(socket, &r, task, resquery_senddone,
Michael Graff's avatar
Michael Graff committed
949
				   query, address, NULL);
Bob Halley's avatar
Bob Halley committed
950
951
	if (result != ISC_R_SUCCESS)
		goto cleanup_message;
Bob Halley's avatar
Bob Halley committed
952
	QTRACE("sent");
Bob Halley's avatar
Bob Halley committed
953

Bob Halley's avatar
Bob Halley committed
954
	return (ISC_R_SUCCESS);
Bob Halley's avatar
Bob Halley committed
955
956
957

 cleanup_message:
	dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
Bob Halley's avatar
Bob Halley committed
958

Bob Halley's avatar
Bob Halley committed
959
	/*
Bob Halley's avatar
Bob Halley committed
960
	 * Stop the dispatcher from listening.
Bob Halley's avatar
Bob Halley committed
961
962
963
964
965
	 */
	dns_dispatch_removeresponse(query->dispatch,
				    &query->dispentry,
				    NULL);

Bob Halley's avatar
Bob Halley committed
966
967
968
969
970
 cleanup_temps:
	if (qname != NULL)
		dns_message_puttempname(fctx->qmessage, &qname);
	if (qrdataset != NULL)
		dns_message_puttemprdataset(fctx->qmessage, &qrdataset);
Bob Halley's avatar
Bob Halley committed
971

Bob Halley's avatar
Bob Halley committed
972
	return (result);
Bob Halley's avatar
Bob Halley committed
973
974
}

Bob Halley's avatar
Bob Halley committed
975
976
977
static void
resquery_connected(isc_task_t *task, isc_event_t *event) {
	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
978
	resquery_t *query = event->ev_arg;
Bob Halley's avatar
Bob Halley committed
979
980
	isc_result_t result;

981
	REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
982
	REQUIRE(VALID_QUERY(query));
Bob Halley's avatar
Bob Halley committed
983
984
985

	QTRACE("connected");

Andreas Gustafsson's avatar
Andreas Gustafsson committed
986
	UNUSED(task);
Bob Halley's avatar
Bob Halley committed
987
988
989
990
991
992
993
994
995

	/*
	 * XXXRTH
	 *
	 * Currently we don't wait for the connect event before retrying
	 * a query.  This means that if we get really behind, we may end
	 * up doing extra work!
	 */

996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
	query->attributes &= ~RESQUERY_ATTR_CONNECTING;

	if (RESQUERY_CANCELED(query)) {
		/*
		 * This query was canceled while the connect() was in
		 * progress.
		 */
		resquery_destroy(&query);
	} else {
		if (sevent->result == ISC_R_SUCCESS) {
			/*
			 * We are connected.  Send the query.
			 */
			result = resquery_send(query);
1010
			if (result != ISC_R_SUCCESS) {
1011
1012
				fctx_cancelquery(&query, NULL, NULL,
						 ISC_FALSE);
1013
1014
				fctx_done(query->fctx, result);
			}
1015
1016
1017
		} else
			fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
	}
Bob Halley's avatar
Bob Halley committed
1018
1019
1020
1021
				 
	isc_event_free(&event);
}

1022
1023


Bob Halley's avatar
Bob Halley committed
1024
static void
Bob Halley's avatar
Bob Halley committed
1025
fctx_finddone(isc_task_t *task, isc_event_t *event) {
Bob Halley's avatar
Bob Halley committed
1026
	fetchctx_t *fctx;
Bob Halley's avatar
Bob Halley committed
1027
1028
	dns_adbfind_t *find;
	dns_resolver_t *res;
Bob Halley's avatar
Bob Halley committed
1029
1030
	isc_boolean_t want_try = ISC_FALSE;
	isc_boolean_t want_done = ISC_FALSE;
Bob Halley's avatar
Bob Halley committed
1031
1032
	isc_boolean_t bucket_empty = ISC_FALSE;
	unsigned int bucketnum;
Bob Halley's avatar
Bob Halley committed
1033

1034
1035
	find = event->ev_sender;
	fctx = event->ev_arg;
Bob Halley's avatar
Bob Halley committed
1036
	REQUIRE(VALID_FCTX(fctx));
Bob Halley's avatar
Bob Halley committed
1037
	res = fctx->res;
Bob Halley's avatar
Bob Halley committed
1038

Andreas Gustafsson's avatar
Andreas Gustafsson committed
1039
	UNUSED(task);
Bob Halley's avatar
Bob Halley committed
1040

Bob Halley's avatar
Bob Halley committed
1041
1042
1043
1044
	FCTXTRACE("finddone");

	INSIST(fctx->pending > 0);
	fctx->pending--;
Bob Halley's avatar
Bob Halley committed
1045
1046

	if (ADDRWAIT(fctx)) {
Bob Halley's avatar
Bob Halley committed
1047
1048
1049
		/*
		 * The fetch is waiting for a name to be found.
		 */
1050
		INSIST(!SHUTTINGDOWN(fctx));
Bob Halley's avatar
Bob Halley committed
1051
		fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1052
		if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
Bob Halley's avatar
Bob Halley committed
1053
			want_try = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
1054
1055
1056
1057
1058
1059
		else if (fctx->pending == 0) {
			/*
			 * We've got nothing else to wait for and don't
			 * know the answer.  There's nothing to do but
			 * fail the fctx.
			 */
Bob Halley's avatar
Bob Halley committed
1060
			want_done = ISC_TRUE;
Bob Halley's avatar
Bob Halley committed
1061
		}
1062
1063
	} else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
		   fctx->validating == 0) {
Bob Halley's avatar
Bob Halley committed
1064
1065
		bucketnum = fctx->bucketnum;
		LOCK(&res->buckets[bucketnum].lock);
1066
1067
1068
1069
1070
1071
		/*
		 * Note that we had to wait until we had the lock before
		 * looking at fctx->references.
		 */
		if (fctx->references == 0)
			bucket_empty = fctx_destroy(fctx);
Bob Halley's avatar
Bob Halley committed
1072
		UNLOCK(&res->buckets[bucketnum].lock);
Bob Halley's avatar
Bob Halley committed
1073
	}
Bob Halley's avatar
Bob Halley committed
1074

Bob Halley's avatar
Bob Halley committed
1075
	isc_event_free(&event);
Bob Halley's avatar
Bob Halley committed
1076
	dns_adb_destroyfind(&find);
Bob Halley's avatar
Bob Halley committed
1077
1078
1079
1080

	if (want_try)
		fctx_try(fctx);
	else if (want_done)
Bob Halley's avatar
Bob Halley committed
1081
1082
1083
		fctx_done(fctx, ISC_R_FAILURE);
	else if (bucket_empty)
		empty_bucket(res);
Bob Halley's avatar
Bob Halley committed
1084
1085
}

Bob Halley's avatar
Bob Halley committed
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163

static inline isc_boolean_t
bad_server(fetchctx_t *fctx, isc_sockaddr_t *address) {
	isc_sockaddr_t *sa;

	for (sa = ISC_LIST_HEAD(fctx->bad);
	     sa != NULL;
	     sa = ISC_LIST_NEXT(sa, link)) {
		if (isc_sockaddr_equal(sa, address))
			return (ISC_TRUE);
	}
	
	return (ISC_FALSE);
}

static inline isc_boolean_t
mark_bad(fetchctx_t *fctx) {
	dns_adbfind_t *curr;
	dns_adbaddrinfo_t *addrinfo;
	isc_boolean_t all_bad = ISC_TRUE;

	/*
	 * Mark all known bad servers, so we don't try to talk to them
	 * again.
	 */

	/*
	 * Mark any bad nameservers.
	 */
	for (curr = ISC_LIST_HEAD(fctx->finds);
	     curr != NULL;
	     curr = ISC_LIST_NEXT(curr, publink)) {
		for (addrinfo = ISC_LIST_HEAD(curr->list);
		     addrinfo != NULL;
		     addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
			if (bad_server(fctx, addrinfo->sockaddr))
				addrinfo->flags |= FCTX_ADDRINFO_MARK;
			else
				all_bad = ISC_FALSE;
		}
	}

	/*
	 * Mark any bad forwarders.
	 */
	for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
	     addrinfo != NULL;
	     addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
		if (bad_server(fctx, addrinfo->sockaddr))
			addrinfo->flags |= FCTX_ADDRINFO_MARK;
		else
			all_bad = ISC_FALSE;
	}
	
	return (all_bad);
}

static void
add_bad(fetchctx_t *fctx, isc_sockaddr_t *address) {
	isc_sockaddr_t *sa;

	if (bad_server(fctx, address)) {
		/*
		 * We already know this server is bad.
		 */
		return;
	}

	FCTXTRACE("add_bad");

	sa = isc_mem_get(fctx->res->mctx, sizeof *sa);
	if (sa == NULL)
		return;
	*sa = *address;
	ISC_LINK_INIT(sa, link);
	ISC_LIST_APPEND(fctx->bad, sa, link);
}

Bob Halley's avatar
Bob Halley committed
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
static void
sort_adbfind(dns_adbfind_t *find) {
	dns_adbaddrinfo_t *best, *curr;
	dns_adbaddrinfolist_t sorted;

	/*
	 * Lame N^2 bubble sort.
	 */

	ISC_LIST_INIT(sorted);
	while (!ISC_LIST_EMPTY(find->list)) {
		best = ISC_LIST_HEAD(find->list);
		curr = ISC_LIST_NEXT(best, publink);
		while (curr != NULL) {
			if (curr->srtt < best->srtt)
				best = curr;
			curr = ISC_LIST_NEXT(curr, publink);
		}
		ISC_LIST_UNLINK(find->list, best, publink);
		ISC_LIST_APPEND(sorted, best, publink);
	} 
	find->list = sorted;
}

static void
sort_finds(fetchctx_t *fctx) {
	dns_adbfind_t *best, *curr;
	dns_adbfindlist_t sorted;
	dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;

	/*
	 * Lame N^2 bubble sort.
	 */

	ISC_LIST_INIT(sorted);
	while (!ISC_LIST_EMPTY(fctx->finds)) {
		best = ISC_LIST_HEAD(fctx->finds);
		bestaddrinfo = ISC_LIST_HEAD(best->list);
		INSIST(bestaddrinfo != NULL);
		curr = ISC_LIST_NEXT(best, publink);
		while (curr != NULL) {
			addrinfo = ISC_LIST_HEAD(curr->list);
			INSIST(addrinfo != NULL);
			if (addrinfo->srtt < bestaddrinfo->srtt) {
				best = curr;
				bestaddrinfo = addrinfo;
			}
			curr = ISC_LIST_NEXT(curr, publink);
		}
		ISC_LIST_UNLINK(fctx->finds, best, publink);
		ISC_LIST_APPEND(sorted, best, publink);
	}
	fctx->finds = sorted;
}

Bob Halley's avatar
Bob Halley committed
1219
static isc_result_t
Bob Halley's avatar
Bob Halley committed
1220
fctx_getaddresses(fetchctx_t *fctx) {
Bob Halley's avatar
Bob Halley committed
1221
1222
1223
1224
	dns_rdata_t rdata;
	isc_region_t r;
	dns_name_t name;
	isc_result_t result;
Bob Halley's avatar
Bob Halley committed
1225
1226
	dns_resolver_t *res;
	isc_stdtime_t now;