resolver.c 164 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
3
 * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Michael Graff's avatar
Michael Graff committed
5
6
7
 * 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.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9
10
11
12
13
14
15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC 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.
Michael Graff's avatar
Michael Graff committed
16
 */
Bob Halley's avatar
Bob Halley committed
17

18
/* $Id: resolver.c,v 1.300 2005/01/19 23:25:41 marka Exp $ */
David Lawrence's avatar
David Lawrence committed
19

20
21
#include <config.h>

22
#include <isc/print.h>
Mark Andrews's avatar
Mark Andrews committed
23
#include <isc/string.h>
Bob Halley's avatar
Bob Halley committed
24
#include <isc/task.h>
25
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
26
#include <isc/util.h>
Bob Halley's avatar
Bob Halley committed
27

28
#include <dns/acl.h>
Bob Halley's avatar
Bob Halley committed
29
#include <dns/adb.h>
Bob Halley's avatar
Bob Halley committed
30
#include <dns/db.h>
31
#include <dns/dispatch.h>
Bob Halley's avatar
Bob Halley committed
32
#include <dns/events.h>
33
#include <dns/forward.h>
Bob Halley's avatar
Bob Halley committed
34
#include <dns/keytable.h>
35
#include <dns/log.h>
Bob Halley's avatar
Bob Halley committed
36
#include <dns/message.h>
37
#include <dns/ncache.h>
38
#include <dns/opcode.h>
39
#include <dns/peer.h>
40
#include <dns/rbt.h>
41
#include <dns/rcode.h>
42
#include <dns/rdata.h>
43
#include <dns/rdataclass.h>
Bob Halley's avatar
Bob Halley committed
44
#include <dns/rdatalist.h>
Bob Halley's avatar
Bob Halley committed
45
#include <dns/rdataset.h>
46
#include <dns/rdatastruct.h>
47
#include <dns/rdatatype.h>
48
49
#include <dns/resolver.h>
#include <dns/result.h>
50
#include <dns/tsig.h>
51
#include <dns/validator.h>
Bob Halley's avatar
Bob Halley committed
52

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

Bob Halley's avatar
Bob Halley committed
99
100
101
/*
 * Maximum EDNS0 input packet size.
 */
102
#define RECV_BUFFER_SIZE		4096		/* XXXRTH  Constant. */
103

104
/*
105
 * This defines the maximum number of timeouts we will permit before we
106
107
 * disable EDNS0 on the query.
 */
108
#define MAX_EDNS0_TIMEOUTS	3
109

Bob Halley's avatar
Bob Halley committed
110
111
typedef struct fetchctx fetchctx_t;

Bob Halley's avatar
Bob Halley committed
112
typedef struct query {
Bob Halley's avatar
Bob Halley committed
113
	/* Locked by task event serialization. */
Bob Halley's avatar
Bob Halley committed
114
115
	unsigned int			magic;
	fetchctx_t *			fctx;
116
	isc_mem_t *			mctx;
117
	dns_dispatchmgr_t *		dispatchmgr;
Bob Halley's avatar
Bob Halley committed
118
	dns_dispatch_t *		dispatch;
Bob Halley's avatar
Bob Halley committed
119
	dns_adbaddrinfo_t *		addrinfo;
120
	isc_socket_t *			tcpsocket;
Bob Halley's avatar
Bob Halley committed
121
	isc_time_t			start;
Bob Halley's avatar
Bob Halley committed
122
	dns_messageid_t			id;
Bob Halley's avatar
Bob Halley committed
123
	dns_dispentry_t *		dispentry;
Bob Halley's avatar
Bob Halley committed
124
	ISC_LINK(struct query)		link;
Bob Halley's avatar
Bob Halley committed
125
	isc_buffer_t			buffer;
126
	isc_buffer_t			*tsig;
127
	dns_tsigkey_t			*tsigkey;
Bob Halley's avatar
Bob Halley committed
128
	unsigned int			options;
129
	unsigned int			attributes;
130
	unsigned int			sends;
131
	unsigned int			connects;
Bob Halley's avatar
Bob Halley committed
132
	unsigned char			data[512];
Bob Halley's avatar
Bob Halley committed
133
134
} resquery_t;

135
136
#define QUERY_MAGIC			ISC_MAGIC('Q', '!', '!', '!')
#define VALID_QUERY(query)		ISC_MAGIC_VALID(query, QUERY_MAGIC)
Bob Halley's avatar
Bob Halley committed
137

138
139
#define RESQUERY_ATTR_CANCELED		0x02

140
#define RESQUERY_CONNECTING(q)		((q)->connects > 0)
141
142
#define RESQUERY_CANCELED(q)		(((q)->attributes & \
					  RESQUERY_ATTR_CANCELED) != 0)
143
#define RESQUERY_SENDING(q)		((q)->sends > 0)
144

Bob Halley's avatar
Bob Halley committed
145
typedef enum {
Bob Halley's avatar
Bob Halley committed
146
	fetchstate_init = 0,		/* Start event has not run yet. */
Bob Halley's avatar
Bob Halley committed
147
	fetchstate_active,
Bob Halley's avatar
Bob Halley committed
148
	fetchstate_done			/* FETCHDONE events posted. */
Bob Halley's avatar
Bob Halley committed
149
150
} fetchstate;

Bob Halley's avatar
Bob Halley committed
151
152
struct fetchctx {
	/* Not locked. */
Bob Halley's avatar
Bob Halley committed
153
154
155
	unsigned int			magic;
	dns_resolver_t *		res;
	dns_name_t			name;
Bob Halley's avatar
Bob Halley committed
156
	dns_rdatatype_t			type;
Bob Halley's avatar
Bob Halley committed
157
	unsigned int			options;
Bob Halley's avatar
Bob Halley committed
158
	unsigned int			bucketnum;
159
	char *				info;
Bob Halley's avatar
Bob Halley committed
160
	/* Locked by appropriate bucket lock. */
Bob Halley's avatar
Bob Halley committed
161
	fetchstate			state;
Bob Halley's avatar
Bob Halley committed
162
	isc_boolean_t			want_shutdown;
163
	isc_boolean_t			cloned;
Bob Halley's avatar
Bob Halley committed
164
	unsigned int			references;
Bob Halley's avatar
lint    
Bob Halley committed
165
	isc_event_t			control_event;
Bob Halley's avatar
Bob Halley committed
166
167
	ISC_LINK(struct fetchctx)	link;
	ISC_LIST(dns_fetchevent_t)	events;
Bob Halley's avatar
Bob Halley committed
168
	/* Locked by task event serialization. */
Bob Halley's avatar
Bob Halley committed
169
170
	dns_name_t			domain;
	dns_rdataset_t			nameservers;
Bob Halley's avatar
Bob Halley committed
171
	unsigned int			attributes;
Bob Halley's avatar
Bob Halley committed
172
173
174
	isc_timer_t *			timer;
	isc_time_t			expires;
	isc_interval_t			interval;
Bob Halley's avatar
Bob Halley committed
175
176
	dns_message_t *			qmessage;
	dns_message_t *			rmessage;
Bob Halley's avatar
Bob Halley committed
177
	ISC_LIST(resquery_t)		queries;
Bob Halley's avatar
Bob Halley committed
178
	dns_adbfindlist_t		finds;
Bob Halley's avatar
Bob Halley committed
179
	dns_adbfind_t *			find;
180
181
	dns_adbfindlist_t		altfinds;
	dns_adbfind_t *			altfind;
182
	dns_adbaddrinfolist_t		forwaddrs;
183
	dns_adbaddrinfolist_t		altaddrs;
184
	isc_sockaddrlist_t		forwarders;
185
	dns_fwdpolicy_t			fwdpolicy;
Bob Halley's avatar
Bob Halley committed
186
	isc_sockaddrlist_t		bad;
187
	ISC_LIST(dns_validator_t)	validators;
188
189
	dns_db_t *			cache;
	dns_adb_t *			adb;
190

Bob Halley's avatar
Bob Halley committed
191
	/*
192
	 * The number of events we're waiting for.
Bob Halley's avatar
Bob Halley committed
193
	 */
Bob Halley's avatar
Bob Halley committed
194
	unsigned int			pending;
195

196
	/*
197
198
199
200
201
202
	 * The number of times we've "restarted" the current
	 * nameserver set.  This acts as a failsafe to prevent
	 * us from pounding constantly on a particular set of
	 * servers that, for whatever reason, are not giving
	 * us useful responses, but are responding in such a
	 * way that they are not marked "bad".
203
	 */
Bob Halley's avatar
Bob Halley committed
204
	unsigned int			restarts;
205

206
	/*
207
208
209
	 * The number of timeouts that have occurred since we 
	 * last successfully received a response packet.  This
	 * is used for EDNS0 black hole detection.
210
211
	 */
	unsigned int			timeouts;
212
213
214
215
216
217
	/*
	 * Look aside state for DS lookups.
	 */
	dns_name_t 			nsname; 
	dns_fetch_t *			nsfetch;
	dns_rdataset_t			nsrrset;
Bob Halley's avatar
Bob Halley committed
218
};
Bob Halley's avatar
Bob Halley committed
219

220
221
#define FCTX_MAGIC			ISC_MAGIC('F', '!', '!', '!')
#define VALID_FCTX(fctx)		ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
Bob Halley's avatar
Bob Halley committed
222

223
224
225
226
227
228
229
230
231
#define FCTX_ATTR_HAVEANSWER		0x0001
#define FCTX_ATTR_GLUING		0x0002
#define FCTX_ATTR_ADDRWAIT		0x0004
#define FCTX_ATTR_SHUTTINGDOWN		0x0008
#define FCTX_ATTR_WANTCACHE		0x0010
#define FCTX_ATTR_WANTNCACHE		0x0020
#define FCTX_ATTR_NEEDEDNS0		0x0040
#define FCTX_ATTR_TRIEDFIND		0x0080
#define FCTX_ATTR_TRIEDALT		0x0100
Bob Halley's avatar
Bob Halley committed
232
233
234
235
236

#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
237
238
#define ADDRWAIT(f)		(((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
				 0)
Bob Halley's avatar
Bob Halley committed
239
240
#define SHUTTINGDOWN(f)		(((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
 				 != 0)
Bob Halley's avatar
Bob Halley committed
241
242
#define WANTCACHE(f)		(((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
#define WANTNCACHE(f)		(((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
243
#define NEEDEDNS0(f)		(((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
Mark Andrews's avatar
Mark Andrews committed
244
#define TRIEDFIND(f)		(((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
245
#define TRIEDALT(f)		(((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
Bob Halley's avatar
Bob Halley committed
246

Bob Halley's avatar
Bob Halley committed
247
248
struct dns_fetch {
	unsigned int			magic;
249
	fetchctx_t *			private;
Bob Halley's avatar
Bob Halley committed
250
251
};

252
253
#define DNS_FETCH_MAGIC			ISC_MAGIC('F', 't', 'c', 'h')
#define DNS_FETCH_VALID(fetch)		ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
Bob Halley's avatar
Bob Halley committed
254
255
256
257
258

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

262
263
264
265
266
267
268
269
270
271
272
273
typedef struct alternate {
	isc_boolean_t			isaddress;
	union	{
		isc_sockaddr_t		addr;
		struct {
			dns_name_t	name;
			in_port_t	port;
		} _n;
	} _u;
	ISC_LINK(struct alternate)	link;
} alternate_t;

Bob Halley's avatar
Bob Halley committed
274
struct dns_resolver {
Bob Halley's avatar
Bob Halley committed
275
	/* Unlocked. */
Bob Halley's avatar
Bob Halley committed
276
277
278
	unsigned int			magic;
	isc_mem_t *			mctx;
	isc_mutex_t			lock;
279
	isc_mutex_t			nlock;	
280
	isc_mutex_t			primelock;	
Bob Halley's avatar
Bob Halley committed
281
	dns_rdataclass_t		rdclass;
Bob Halley's avatar
Bob Halley committed
282
	isc_socketmgr_t *		socketmgr;
Bob Halley's avatar
Bob Halley committed
283
	isc_timermgr_t *		timermgr;
284
	isc_taskmgr_t *			taskmgr;
285
	dns_view_t *			view;
286
	isc_boolean_t			frozen;
287
	unsigned int			options;
288
	dns_dispatchmgr_t *		dispatchmgr;
289
290
	dns_dispatch_t *		dispatchv4;
	dns_dispatch_t *		dispatchv6;
Bob Halley's avatar
Bob Halley committed
291
292
	unsigned int			nbuckets;
	fctxbucket_t *			buckets;
Mark Andrews's avatar
Mark Andrews committed
293
	isc_uint32_t			lame_ttl;
294
	ISC_LIST(alternate_t)		alternates;
295
	isc_uint16_t			udpsize;
296
#if USE_ALGLOCK
297
298
299
	isc_rwlock_t			alglock;
#endif
	dns_rbt_t *			algorithms;
300
301
302
303
#if USE_MBSLOCK
	isc_rwlock_t			mbslock;
#endif
	dns_rbt_t *			mustbesecure;
304
305
306
307
308
	/* Locked by lock. */
	unsigned int			references;
	isc_boolean_t			exiting;
	isc_eventlist_t			whenshutdown;
	unsigned int			activebuckets;
Bob Halley's avatar
Bob Halley committed
309
	isc_boolean_t			priming;
310
	/* Locked by primelock. */
Bob Halley's avatar
Bob Halley committed
311
	dns_fetch_t *			primefetch;
312
	/* Locked by nlock. */
313
	unsigned int			nfctx;
Bob Halley's avatar
Bob Halley committed
314
315
};

316
317
#define RES_MAGIC			ISC_MAGIC('R', 'e', 's', '!')
#define VALID_RESOLVER(res)		ISC_MAGIC_VALID(res, RES_MAGIC)
Bob Halley's avatar
Bob Halley committed
318

319
320
321
322
323
324
325
326
327
328
/*
 * 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
329

330
331
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)

Bob Halley's avatar
Bob Halley committed
332
static void destroy(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
333
static void empty_bucket(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
334
static isc_result_t resquery_send(resquery_t *query);
Bob Halley's avatar
Bob Halley committed
335
static void resquery_response(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
336
static void resquery_connected(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
337
static void fctx_try(fetchctx_t *fctx);
Bob Halley's avatar
Bob Halley committed
338
static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
339
340
341
static isc_result_t ncache_adderesult(dns_message_t *message,
				      dns_db_t *cache, dns_dbnode_t *node,
				      dns_rdatatype_t covers,
342
				      isc_stdtime_t now, dns_ttl_t maxttl,
343
344
				      dns_rdataset_t *ardataset,
				      isc_result_t *eresultp);
Bob Halley's avatar
Bob Halley committed
345

346
static isc_boolean_t
347
fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
348
	dns_name_t *name;
349
	dns_name_t *domain = &fctx->domain;
350
351
352
353
354
355
356
357
	dns_rdataset_t *rdataset;
	dns_rdatatype_t type;
	isc_result_t result;
	isc_boolean_t keep_auth = ISC_FALSE;

	if (message->rcode == dns_rcode_nxdomain)
		return (ISC_FALSE);

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
	/*
	 * Look for BIND 8 style delegations.
	 * Also look for answers to ANY queries where the duplicate NS RRset
	 * may have been stripped from the authority section.
	 */
	if (message->counts[DNS_SECTION_ANSWER] != 0 &&
	    (fctx->type == dns_rdatatype_ns ||
	     fctx->type == dns_rdatatype_any)) {
		result = dns_message_firstname(message, DNS_SECTION_ANSWER);
		while (result == ISC_R_SUCCESS) {
			name = NULL;
			dns_message_currentname(message, DNS_SECTION_ANSWER,
						&name);
			for (rdataset = ISC_LIST_HEAD(name->list);
			     rdataset != NULL;
			     rdataset = ISC_LIST_NEXT(rdataset, link)) {
				type = rdataset->type;
				if (type != dns_rdatatype_ns)
					continue;
				if (dns_name_issubdomain(name, domain))
					return (ISC_FALSE);
			}
			result = dns_message_nextname(message,
						      DNS_SECTION_ANSWER);
		}
	}

385
386
387
388
389
390
391
	/* Look for referral. */
	if (message->counts[DNS_SECTION_AUTHORITY] == 0)
		goto munge;

	result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
	while (result == ISC_R_SUCCESS) {
		name = NULL;
392
		dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
393
394
395
396
397
398
399
		for (rdataset = ISC_LIST_HEAD(name->list);
		     rdataset != NULL;
		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
			type = rdataset->type;
			if (type == dns_rdatatype_soa &&
			    dns_name_equal(name, domain))
				keep_auth = ISC_TRUE;
400
401
			if (type != dns_rdatatype_ns &&
			    type != dns_rdatatype_soa)
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
				continue;
			if (dns_name_equal(name, domain))
				goto munge;
			if (dns_name_issubdomain(name, domain))
				return (ISC_FALSE);
		}
		result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
	}

 munge:
	message->rcode = dns_rcode_nxdomain;
	message->counts[DNS_SECTION_ANSWER] = 0;
	if (!keep_auth)
		message->counts[DNS_SECTION_AUTHORITY] = 0;
	message->counts[DNS_SECTION_ADDITIONAL] = 0;
	return (ISC_TRUE);
}

Bob Halley's avatar
Bob Halley committed
420
static inline isc_result_t
Bob Halley's avatar
Bob Halley committed
421
fctx_starttimer(fetchctx_t *fctx) {
422
423
	/*
	 * Start the lifetime timer for fctx.
424
425
426
427
	 *
	 * 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.
428
	 */
Bob Halley's avatar
Bob Halley committed
429
430
	return (isc_timer_reset(fctx->timer, isc_timertype_once,
				&fctx->expires, NULL,
431
				ISC_TRUE));
Bob Halley's avatar
Bob Halley committed
432
433
}

Bob Halley's avatar
Bob Halley committed
434
435
static inline void
fctx_stoptimer(fetchctx_t *fctx) {
Bob Halley's avatar
Bob Halley committed
436
	isc_result_t result;
Bob Halley's avatar
Bob Halley committed
437
438
439
440
441
442
443

	/*
	 * 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
444
	result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
Bob Halley's avatar
Bob Halley committed
445
				  NULL, NULL, ISC_TRUE);
Bob Halley's avatar
Bob Halley committed
446
	if (result != ISC_R_SUCCESS) {
Bob Halley's avatar
Bob Halley committed
447
448
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_timer_reset(): %s",
Bob Halley's avatar
Bob Halley committed
449
				 isc_result_totext(result));
Bob Halley's avatar
Bob Halley committed
450
451
452
	}
}

453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471

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


472
473
474
static inline void
resquery_destroy(resquery_t **queryp) {
	resquery_t *query;
475

476
477
478
479
	REQUIRE(queryp != NULL);
	query = *queryp;
	REQUIRE(!ISC_LINK_LINKED(query, link));

480
	INSIST(query->tcpsocket == NULL);
481

482
	query->magic = 0;
483
	isc_mem_put(query->mctx, query, sizeof(*query));
484
485
486
	*queryp = NULL;
}

Bob Halley's avatar
Bob Halley committed
487
static void
Bob Halley's avatar
Bob Halley committed
488
fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
489
		 isc_time_t *finish, isc_boolean_t no_response)
Bob Halley's avatar
Bob Halley committed
490
{
Bob Halley's avatar
Bob Halley committed
491
492
	fetchctx_t *fctx;
	resquery_t *query;
Bob Halley's avatar
Bob Halley committed
493
494
	unsigned int rtt;
	unsigned int factor;
Mark Andrews's avatar
Mark Andrews committed
495
496
	dns_adbfind_t *find;
	dns_adbaddrinfo_t *addrinfo;
Bob Halley's avatar
Bob Halley committed
497

Bob Halley's avatar
Bob Halley committed
498
499
500
	query = *queryp;
	fctx = query->fctx;

Bob Halley's avatar
Bob Halley committed
501
502
	FCTXTRACE("cancelquery");

503
504
505
506
	REQUIRE(!RESQUERY_CANCELED(query));

	query->attributes |= RESQUERY_ATTR_CANCELED;

Bob Halley's avatar
Bob Halley committed
507
	/*
508
	 * Should we update the RTT?
Bob Halley's avatar
Bob Halley committed
509
	 */
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
	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 +
527
				(200000 * fctx->restarts);
528
529
530
531
532
533
534
			if (rtt > 10000000)
				rtt = 10000000;
			/*
			 * Replace the current RTT with our value.
			 */
			factor = DNS_ADB_RTTADJREPLACE;
		}
535
		dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
Bob Halley's avatar
Bob Halley committed
536
537
	}

538
539
540
	/*
	 * Age RTTs of servers not tried.
	 */
Mark Andrews's avatar
Mark Andrews committed
541
542
543
544
545
546
547
548
	factor = DNS_ADB_RTTADJAGE;
	if (finish != NULL)
		for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
		     addrinfo != NULL;
		     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
			if (UNMARKED(addrinfo))
				dns_adb_adjustsrtt(fctx->adb, addrinfo,
						   0, factor);
549

Mark Andrews's avatar
Mark Andrews committed
550
	if (finish != NULL && TRIEDFIND(fctx))
Mark Andrews's avatar
Mark Andrews committed
551
		for (find = ISC_LIST_HEAD(fctx->finds);
552
553
554
555
556
557
558
559
560
		     find != NULL;
		     find = ISC_LIST_NEXT(find, publink))
			for (addrinfo = ISC_LIST_HEAD(find->list);
			     addrinfo != NULL;
			     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
				if (UNMARKED(addrinfo))
					dns_adb_adjustsrtt(fctx->adb, addrinfo,
							   0, factor);

561
562
563
564
565
566
567
	if (finish != NULL && TRIEDALT(fctx)) {
		for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
		     addrinfo != NULL;
		     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
			if (UNMARKED(addrinfo))
				dns_adb_adjustsrtt(fctx->adb, addrinfo,
						   0, factor);
Mark Andrews's avatar
Mark Andrews committed
568
		for (find = ISC_LIST_HEAD(fctx->altfinds);
569
570
571
572
573
574
575
576
577
578
		     find != NULL;
		     find = ISC_LIST_NEXT(find, publink))
			for (addrinfo = ISC_LIST_HEAD(find->list);
			     addrinfo != NULL;
			     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
				if (UNMARKED(addrinfo))
					dns_adb_adjustsrtt(fctx->adb, addrinfo,
							   0, factor);
	}

Bob Halley's avatar
Bob Halley committed
579
	if (query->dispentry != NULL)
580
		dns_dispatch_removeresponse(&query->dispentry, deventp);
581

Bob Halley's avatar
Bob Halley committed
582
	ISC_LIST_UNLINK(fctx->queries, query, link);
583

584
585
	if (query->tsig != NULL)
		isc_buffer_free(&query->tsig);
586

587
588
589
	if (query->tsigkey != NULL)
		dns_tsigkey_detach(&query->tsigkey);

590
591
592
593
594
595
596
	/*
	 * Check for any outstanding socket events.  If they exist, cancel
	 * them and let the event handlers finish the cleanup.  The resolver
	 * only needs to worry about managing the connect and send events;
	 * the dispatcher manages the recv events.
	 */
	if (RESQUERY_CONNECTING(query))
597
598
599
		/*
		 * Cancel the connect.
		 */
600
601
		isc_socket_cancel(query->tcpsocket, NULL,
				  ISC_SOCKCANCEL_CONNECT);
602
603
604
605
606
607
	else if (RESQUERY_SENDING(query))
		/*
		 * Cancel the pending send.
		 */
		isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
				  NULL, ISC_SOCKCANCEL_SEND);
608
609
610

	if (query->dispatch != NULL)
		dns_dispatch_detach(&query->dispatch);
611

612
	if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
613
614
615
616
		/*
		 * It's safe to destroy the query now.
		 */
		resquery_destroy(&query);
Bob Halley's avatar
Bob Halley committed
617
618
619
}

static void
620
fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
Bob Halley's avatar
Bob Halley committed
621
622
623
624
625
626
627
628
	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);
629
		fctx_cancelquery(&query, NULL, NULL, no_response);
Bob Halley's avatar
Bob Halley committed
630
631
632
	}
}

Bob Halley's avatar
Bob Halley committed
633
static void
Bob Halley's avatar
Bob Halley committed
634
635
636
fctx_cleanupfinds(fetchctx_t *fctx) {
	dns_adbfind_t *find, *next_find;

Bob Halley's avatar
Bob Halley committed
637
638
	REQUIRE(ISC_LIST_EMPTY(fctx->queries));

Bob Halley's avatar
Bob Halley committed
639
640
641
642
643
644
	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
645
	}
Bob Halley's avatar
Bob Halley committed
646
	fctx->find = NULL;
Bob Halley's avatar
Bob Halley committed
647
648
}

649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
static void
fctx_cleanupaltfinds(fetchctx_t *fctx) {
	dns_adbfind_t *find, *next_find;

	REQUIRE(ISC_LIST_EMPTY(fctx->queries));

	for (find = ISC_LIST_HEAD(fctx->altfinds);
	     find != NULL;
	     find = next_find) {
		next_find = ISC_LIST_NEXT(find, publink);
		ISC_LIST_UNLINK(fctx->altfinds, find, publink);
		dns_adb_destroyfind(&find);
	}
	fctx->altfind = NULL;
}

665
666
667
668
669
670
671
672
673
674
675
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);
676
		dns_adb_freeaddrinfo(fctx->adb, &addr);
677
678
679
	}
}

680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
static void
fctx_cleanupaltaddrs(fetchctx_t *fctx) {
	dns_adbaddrinfo_t *addr, *next_addr;

	REQUIRE(ISC_LIST_EMPTY(fctx->queries));

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

Bob Halley's avatar
Bob Halley committed
695
static inline void
696
fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
Bob Halley's avatar
Bob Halley committed
697
	FCTXTRACE("stopeverything");
698
	fctx_cancelqueries(fctx, no_response);
Bob Halley's avatar
Bob Halley committed
699
	fctx_cleanupfinds(fctx);
700
	fctx_cleanupaltfinds(fctx);
701
	fctx_cleanupforwaddrs(fctx);
702
	fctx_cleanupaltaddrs(fctx);
Bob Halley's avatar
Bob Halley committed
703
	fctx_stoptimer(fctx);
Bob Halley's avatar
Bob Halley committed
704
}
Bob Halley's avatar
Bob Halley committed
705

Bob Halley's avatar
Bob Halley committed
706
707
708
709
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
710

Bob Halley's avatar
Bob Halley committed
711
712
713
714
715
716
	/*
	 * Caller must be holding the appropriate bucket lock.
	 */
	REQUIRE(fctx->state == fetchstate_done);

	FCTXTRACE("sendevents");
Bob Halley's avatar
Bob Halley committed
717
718
719
720

	for (event = ISC_LIST_HEAD(fctx->events);
	     event != NULL;
	     event = next_event) {
721
		next_event = ISC_LIST_NEXT(event, ev_link);
722
		ISC_LIST_UNLINK(fctx->events, event, ev_link);
723
724
		task = event->ev_sender;
		event->ev_sender = fctx;
Bob Halley's avatar
Bob Halley committed
725
		if (!HAVE_ANSWER(fctx))
726
			event->result = result;
727
728
729
730

		INSIST(result != ISC_R_SUCCESS ||
		       dns_rdataset_isassociated(event->rdataset) ||
		       fctx->type == dns_rdatatype_any ||
731
		       fctx->type == dns_rdatatype_rrsig);
732

733
		isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
Bob Halley's avatar
Bob Halley committed
734
	}
Bob Halley's avatar
Bob Halley committed
735
}
Bob Halley's avatar
Bob Halley committed
736

Bob Halley's avatar
Bob Halley committed
737
738
739
static void
fctx_done(fetchctx_t *fctx, isc_result_t result) {
	dns_resolver_t *res;
740
	isc_boolean_t no_response;
Bob Halley's avatar
Bob Halley committed
741
742
743
744
745

	FCTXTRACE("done");

	res = fctx->res;

746
747
748
749
750
	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
751
752
753
754

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

	fctx->state = fetchstate_done;
755
	fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
Bob Halley's avatar
Bob Halley committed
756
	fctx_sendevents(fctx, result);
Bob Halley's avatar
Bob Halley committed
757
758

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

Bob Halley's avatar
Bob Halley committed
761
static void
Bob Halley's avatar
Bob Halley committed
762
resquery_senddone(isc_task_t *task, isc_event_t *event) {
Bob Halley's avatar
Bob Halley committed
763
	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
764
	resquery_t *query = event->ev_arg;
765
766
767
	isc_boolean_t retry = ISC_FALSE;
	isc_result_t result;
	fetchctx_t *fctx;
Bob Halley's avatar
Bob Halley committed
768

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

Bob Halley's avatar
Bob Halley committed
771
772
	QTRACE("senddone");

Bob Halley's avatar
Bob Halley committed
773
774
775
776
777
778
779
780
	/*
	 * 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
781
	UNUSED(task);
Bob Halley's avatar
Bob Halley committed
782

783
784
785
	INSIST(RESQUERY_SENDING(query));

	query->sends--;
786
	fctx = query->fctx;
787

788
789
790
791
792
793
794
795
796
797
	if (RESQUERY_CANCELED(query)) {
		if (query->sends == 0) {
			/*
			 * This query was canceled while the
			 * isc_socket_sendto() was in progress.
			 */
			if (query->tcpsocket != NULL)
				isc_socket_detach(&query->tcpsocket);
			resquery_destroy(&query);
		}
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
	} else 
		switch (sevent->result) {
		case ISC_R_SUCCESS:
			break;

		case ISC_R_HOSTUNREACH:
		case ISC_R_NETUNREACH:
		case ISC_R_NOPERM:
		case ISC_R_ADDRNOTAVAIL:
		case ISC_R_CONNREFUSED:

			/*
			 * No route to remote.
			 */
			fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
			retry = ISC_TRUE;
			break;

		default:
			fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
			break;
		}
820

Bob Halley's avatar
Bob Halley committed
821
	isc_event_free(&event);
822
823
824
825
826
827
828
829
830
831
832
833
834

	if (retry) {
		/*
		 * Behave as if the idle timer has expired.  For TCP
		 * this may not actually reflect the latest timer.
		 */
		fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
		result = fctx_stopidletimer(fctx);
		if (result != ISC_R_SUCCESS)
			fctx_done(fctx, result);
		else
			fctx_try(fctx);
	}
Bob Halley's avatar
Bob Halley committed
835
836
}

Bob Halley's avatar
Bob Halley committed
837
static inline isc_result_t
838
fctx_addopt(dns_message_t *message, dns_resolver_t *res) {
Bob Halley's avatar
Bob Halley committed
839
840
841
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
	dns_rdata_t *rdata;
Bob Halley's avatar
Bob Halley committed
842
	isc_result_t result;
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

	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.
	 */
864
	rdatalist->rdclass = res->udpsize;
Bob Halley's avatar
Bob Halley committed
865
866

	/*
867
	 * Set EXTENDED-RCODE, VERSION, and Z to 0, and the DO bit to 1.
Bob Halley's avatar
Bob Halley committed
868
	 */
869
	rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO;
Bob Halley's avatar
Bob Halley committed
870
871

	/*
872
	 * No EDNS options.
Bob Halley's avatar
Bob Halley committed
873
874
875
	 */
	rdata->data = NULL;
	rdata->length = 0;
876
877
	rdata->rdclass = rdatalist->rdclass;
	rdata->type = rdatalist->type;
878
	rdata->flags = 0;
Bob Halley's avatar
Bob Halley committed
879
880
881

	ISC_LIST_INIT(rdatalist->rdata);
	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
882
	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
Bob Halley's avatar
Bob Halley committed
883
884
885
886

	return (dns_message_setopt(message, rdataset));
}

887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
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;
904

905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
	/*
	 * 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
920
921
922
923
static isc_result_t
fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
	   unsigned int options)
{
Bob Halley's avatar
Bob Halley committed
924
925
	dns_resolver_t *res;
	isc_task_t *task;
Bob Halley's avatar
Bob Halley committed
926
927
	isc_result_t result;
	resquery_t *query;
Bob Halley's avatar
Bob Halley committed
928

Bob Halley's avatar
Bob Halley committed
929
	FCTXTRACE("query");
Bob Halley's avatar
Bob Halley committed
930

Bob Halley's avatar
Bob Halley committed
931
932
	res = fctx->res;
	task = res->buckets[fctx->bucketnum].task;
Bob Halley's avatar
Bob Halley committed
933

934
	fctx_setretryinterval(fctx, addrinfo->srtt);
935
	result = fctx_startidletimer(fctx);
Bob Halley's avatar
Bob Halley committed
936
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
937
938
		return (result);

Bob Halley's avatar
Bob Halley committed
939
	dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
Bob Halley's avatar
Bob Halley committed
940

Andreas Gustafsson's avatar
Andreas Gustafsson committed
941
	query = isc_mem_get(res->mctx, sizeof(*query));
Bob Halley's avatar
Bob Halley committed
942
	if (query == NULL) {
943
		result = ISC_R_NOMEMORY;
944
		goto stop_idle_timer;
Bob Halley's avatar
Bob Halley committed
945
	}
946
	query->mctx = res->mctx;
Bob Halley's avatar
Bob Halley committed
947
	query->options = options;
948
	query->attributes = 0;
949
	query->sends = 0;
950
	query->connects = 0;
Bob Halley's avatar
Bob Halley committed
951
952
953
954
955
	/*
	 * Note that the caller MUST guarantee that 'addrinfo' will remain
	 * valid until this query is canceled.
	 */
	query->addrinfo = addrinfo;
956
	TIME_NOW(&query->start);
957

Bob Halley's avatar
Bob Halley committed
958
959
960
	/*
	 * 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
961
962
	 * shared dispatch.
	 */
963
	query->dispatchmgr = res->dispatchmgr;
Bob Halley's avatar
Bob Halley committed
964
	query->dispatch = NULL;
965
	query->tcpsocket = NULL;
Bob Halley's avatar
Bob Halley committed
966
	if ((query->options & DNS_FETCHOPT_TCP) != 0) {
967
		isc_sockaddr_t addr;
968
		int pf;
969

970
971
		pf = isc_sockaddr_pf(&addrinfo->sockaddr);

972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
		switch (pf) {
		case PF_INET:
			result = dns_dispatch_getlocaladdress(res->dispatchv4,
							      &addr);
			break;
		case PF_INET6:
			result = dns_dispatch_getlocaladdress(res->dispatchv6,
							      &addr);
			break;
		default:
			result = ISC_R_NOTIMPLEMENTED;
			break;
		}
		if (result != ISC_R_SUCCESS)
			goto cleanup_query;

		isc_sockaddr_setport(&addr, 0);

990
		result = isc_socket_create(res->socketmgr, pf,
Bob Halley's avatar
Bob Halley committed
991
					   isc_sockettype_tcp,
992
					   &query->tcpsocket);
Bob Halley's avatar
Bob Halley committed
993
994
		if (result != ISC_R_SUCCESS)
			goto cleanup_query;
995

996
		result = isc_socket_bind(query->tcpsocket, &addr);
997
998
		if (result != ISC_R_SUCCESS)
			goto cleanup_socket;
999

Bob Halley's avatar
Bob Halley committed
1000
		/*
1001
		 * A dispatch will be created once the connect succeeds.
Bob Halley's avatar
Bob Halley committed
1002
		 */
Bob Halley's avatar
Bob Halley committed
1003
	} else {
1004
		switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
Bob Halley's avatar
Bob Halley committed
1005
		case PF_INET:
1006
			dns_dispatch_attach(res->dispatchv4, &query->dispatch);
Bob Halley's avatar
Bob Halley committed
1007
			break;
Bob Halley's avatar
Bob Halley committed
1008
		case PF_INET6:
1009
			dns_dispatch_attach(res->dispatchv6, &query->dispatch);
Bob Halley's avatar
Bob Halley committed
1010
1011
			break;
		default:
1012
			result = ISC_R_NOTIMPLEMENTED;
1013
			goto cleanup_query;
Bob Halley's avatar
Bob Halley committed
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
		}
		/*
		 * 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
1024
1025
1026
1027
1028

	query->dispentry = NULL;
	query->fctx = fctx;
	query->tsig = NULL;
	query->tsigkey = NULL;
1029
	ISC_LINK_INIT(query, link);
Bob Halley's avatar
Bob Halley committed
1030
1031
1032
1033
1034
1035
1036
1037
	query->magic = QUERY_MAGIC;

	if ((query->options & DNS_FETCHOPT_TCP) != 0) {
		/*
		 * Connect to the remote server.
		 *
		 * XXXRTH  Should we attach to the socket?
		 */
David Lawrence's avatar
David Lawrence committed
1038
		result = isc_socket_connect(query->tcpsocket,
1039
					    &addrinfo->sockaddr, task,
David Lawrence's avatar