resolver.c 151 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 1999-2002  Internet Software Consortium.
3
 *
Michael Graff's avatar
Michael Graff committed
4 5 6
 * 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.
7
 *
8 9 10 11 12 13 14 15
 * 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.
Michael Graff's avatar
Michael Graff committed
16
 */
Bob Halley's avatar
Bob Halley committed
17

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id: resolver.c,v 1.270 2003/10/17 03:46:44 marka Exp $ */
David Lawrence's avatar
David Lawrence committed
19

20 21
#include <config.h>

Bob Halley's avatar
Bob Halley committed
22
#include <isc/task.h>
23
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
24
#include <isc/util.h>
Bob Halley's avatar
Bob Halley committed
25

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

Bob Halley's avatar
Bob Halley committed
50 51
#define DNS_RESOLVER_TRACE
#ifdef DNS_RESOLVER_TRACE
52 53 54
#define RTRACE(m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
55
				      ISC_LOG_DEBUG(3), \
56 57 58 59
				      "res %p: %s", res, (m))
#define RRTRACE(r, m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
60
				      ISC_LOG_DEBUG(3), \
61 62 63 64
				      "res %p: %s", (r), (m))
#define FCTXTRACE(m)	isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
65
				      ISC_LOG_DEBUG(3), \
66
				      "fctx %p: %s", fctx, (m))
67 68 69 70 71 72
#define FCTXTRACE2(m1, m2) \
			isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "fctx %p: %s %s", fctx, (m1), (m2))
73 74 75
#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.
 */
96
#define RECV_BUFFER_SIZE		4096		/* XXXRTH  Constant. */
97

98
/*
99
 * This defines the maximum number of timeouts we will permit before we
100 101
 * disable EDNS0 on the query.
 */
102
#define MAX_EDNS0_TIMEOUTS	3
103

Bob Halley's avatar
Bob Halley committed
104 105
typedef struct fetchctx fetchctx_t;

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

129 130
#define QUERY_MAGIC			ISC_MAGIC('Q', '!', '!', '!')
#define VALID_QUERY(query)		ISC_MAGIC_VALID(query, QUERY_MAGIC)
Bob Halley's avatar
Bob Halley committed
131

132 133
#define RESQUERY_ATTR_CANCELED		0x02

134
#define RESQUERY_CONNECTING(q)		((q)->connects > 0)
135 136
#define RESQUERY_CANCELED(q)		(((q)->attributes & \
					  RESQUERY_ATTR_CANCELED) != 0)
137
#define RESQUERY_SENDING(q)		((q)->sends > 0)
138

Bob Halley's avatar
Bob Halley committed
139
typedef enum {
Bob Halley's avatar
Bob Halley committed
140
	fetchstate_init = 0,		/* Start event has not run yet. */
Bob Halley's avatar
Bob Halley committed
141
	fetchstate_active,
Bob Halley's avatar
Bob Halley committed
142
	fetchstate_done			/* FETCHDONE events posted. */
Bob Halley's avatar
Bob Halley committed
143 144
} fetchstate;

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

Bob Halley's avatar
Bob Halley committed
184
	/*
185
	 * The number of events we're waiting for.
Bob Halley's avatar
Bob Halley committed
186
	 */
Bob Halley's avatar
Bob Halley committed
187
	unsigned int			pending;
188

189
	/*
190 191 192 193 194 195
	 * 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".
196
	 */
Bob Halley's avatar
Bob Halley committed
197
	unsigned int			restarts;
198

199
	/*
200 201 202
	 * The number of timeouts that have occurred since we 
	 * last successfully received a response packet.  This
	 * is used for EDNS0 black hole detection.
203 204
	 */
	unsigned int			timeouts;
205 206 207 208 209 210
	/*
	 * 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
211
};
Bob Halley's avatar
Bob Halley committed
212

213 214
#define FCTX_MAGIC			ISC_MAGIC('F', '!', '!', '!')
#define VALID_FCTX(fctx)		ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
Bob Halley's avatar
Bob Halley committed
215

216 217 218 219 220 221 222 223 224
#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
225 226 227 228 229

#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
230 231
#define ADDRWAIT(f)		(((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
				 0)
Bob Halley's avatar
Bob Halley committed
232 233
#define SHUTTINGDOWN(f)		(((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
 				 != 0)
Bob Halley's avatar
Bob Halley committed
234 235
#define WANTCACHE(f)		(((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
#define WANTNCACHE(f)		(((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
236
#define NEEDEDNS0(f)		(((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
Mark Andrews's avatar
Mark Andrews committed
237
#define TRIEDFIND(f)		(((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
238
#define TRIEDALT(f)		(((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
Bob Halley's avatar
Bob Halley committed
239

Bob Halley's avatar
Bob Halley committed
240 241
struct dns_fetch {
	unsigned int			magic;
242
	fetchctx_t *			private;
Bob Halley's avatar
Bob Halley committed
243 244
};

245 246
#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
247 248 249 250 251

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

255 256 257 258 259 260 261 262 263 264 265 266
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
267
struct dns_resolver {
Bob Halley's avatar
Bob Halley committed
268
	/* Unlocked. */
Bob Halley's avatar
Bob Halley committed
269 270 271
	unsigned int			magic;
	isc_mem_t *			mctx;
	isc_mutex_t			lock;
272
	isc_mutex_t			nlock;	
Bob Halley's avatar
Bob Halley committed
273
	dns_rdataclass_t		rdclass;
Bob Halley's avatar
Bob Halley committed
274
	isc_socketmgr_t *		socketmgr;
Bob Halley's avatar
Bob Halley committed
275
	isc_timermgr_t *		timermgr;
276
	isc_taskmgr_t *			taskmgr;
277
	dns_view_t *			view;
278
	isc_boolean_t			frozen;
279
	unsigned int			options;
280
	dns_dispatchmgr_t *		dispatchmgr;
281 282
	dns_dispatch_t *		dispatchv4;
	dns_dispatch_t *		dispatchv6;
Bob Halley's avatar
Bob Halley committed
283 284
	unsigned int			nbuckets;
	fctxbucket_t *			buckets;
Mark Andrews's avatar
Mark Andrews committed
285
	isc_uint32_t			lame_ttl;
286
	ISC_LIST(alternate_t)		alternates;
287
	isc_uint16_t			udpsize;
288 289 290 291 292
	/* Locked by lock. */
	unsigned int			references;
	isc_boolean_t			exiting;
	isc_eventlist_t			whenshutdown;
	unsigned int			activebuckets;
Bob Halley's avatar
Bob Halley committed
293 294
	isc_boolean_t			priming;
	dns_fetch_t *			primefetch;
295
	/* Locked by nlock. */
296
	unsigned int			nfctx;
Bob Halley's avatar
Bob Halley committed
297 298
};

299 300
#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
301

302 303 304 305 306 307 308 309 310 311
/*
 * 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
312

313 314
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)

Bob Halley's avatar
Bob Halley committed
315
static void destroy(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
316
static void empty_bucket(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
317
static isc_result_t resquery_send(resquery_t *query);
Bob Halley's avatar
Bob Halley committed
318
static void resquery_response(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
319
static void resquery_connected(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
320
static void fctx_try(fetchctx_t *fctx);
Bob Halley's avatar
Bob Halley committed
321
static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
322 323 324
static isc_result_t ncache_adderesult(dns_message_t *message,
				      dns_db_t *cache, dns_dbnode_t *node,
				      dns_rdatatype_t covers,
325
				      isc_stdtime_t now, dns_ttl_t maxttl,
326 327
				      dns_rdataset_t *ardataset,
				      isc_result_t *eresultp);
Bob Halley's avatar
Bob Halley committed
328

329
static isc_boolean_t
330
fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
331
	dns_name_t *name;
332
	dns_name_t *domain = &fctx->domain;
333 334 335 336 337 338 339 340
	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);

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
	/*
	 * 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);
		}
	}

368 369 370 371 372 373 374
	/* 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;
375
		dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
376 377 378 379 380 381 382
		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;
383 384
			if (type != dns_rdatatype_ns &&
			    type != dns_rdatatype_soa)
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
				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
403
static inline isc_result_t
Bob Halley's avatar
Bob Halley committed
404
fctx_starttimer(fetchctx_t *fctx) {
405 406
	/*
	 * Start the lifetime timer for fctx.
407 408 409 410
	 *
	 * 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.
411
	 */
Bob Halley's avatar
Bob Halley committed
412 413
	return (isc_timer_reset(fctx->timer, isc_timertype_once,
				&fctx->expires, NULL,
414
				ISC_TRUE));
Bob Halley's avatar
Bob Halley committed
415 416
}

Bob Halley's avatar
Bob Halley committed
417 418
static inline void
fctx_stoptimer(fetchctx_t *fctx) {
Bob Halley's avatar
Bob Halley committed
419
	isc_result_t result;
Bob Halley's avatar
Bob Halley committed
420 421 422 423 424 425 426

	/*
	 * 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
427
	result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
Bob Halley's avatar
Bob Halley committed
428
				  NULL, NULL, ISC_TRUE);
Bob Halley's avatar
Bob Halley committed
429
	if (result != ISC_R_SUCCESS) {
Bob Halley's avatar
Bob Halley committed
430 431
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_timer_reset(): %s",
Bob Halley's avatar
Bob Halley committed
432
				 isc_result_totext(result));
Bob Halley's avatar
Bob Halley committed
433 434 435
	}
}

436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454

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


455 456 457
static inline void
resquery_destroy(resquery_t **queryp) {
	resquery_t *query;
458

459 460 461 462
	REQUIRE(queryp != NULL);
	query = *queryp;
	REQUIRE(!ISC_LINK_LINKED(query, link));

463
	INSIST(query->tcpsocket == NULL);
464

465
	query->magic = 0;
466
	isc_mem_put(query->mctx, query, sizeof(*query));
467 468 469
	*queryp = NULL;
}

Bob Halley's avatar
Bob Halley committed
470
static void
Bob Halley's avatar
Bob Halley committed
471
fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
472
		 isc_time_t *finish, isc_boolean_t no_response)
Bob Halley's avatar
Bob Halley committed
473
{
Bob Halley's avatar
Bob Halley committed
474 475
	fetchctx_t *fctx;
	resquery_t *query;
Bob Halley's avatar
Bob Halley committed
476 477
	unsigned int rtt;
	unsigned int factor;
Mark Andrews's avatar
Mark Andrews committed
478 479
	dns_adbfind_t *find;
	dns_adbaddrinfo_t *addrinfo;
Bob Halley's avatar
Bob Halley committed
480

Bob Halley's avatar
Bob Halley committed
481 482 483
	query = *queryp;
	fctx = query->fctx;

Bob Halley's avatar
Bob Halley committed
484 485
	FCTXTRACE("cancelquery");

486 487 488 489
	REQUIRE(!RESQUERY_CANCELED(query));

	query->attributes |= RESQUERY_ATTR_CANCELED;

Bob Halley's avatar
Bob Halley committed
490
	/*
491
	 * Should we update the RTT?
Bob Halley's avatar
Bob Halley committed
492
	 */
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
	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;
		}
518
		dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
Bob Halley's avatar
Bob Halley committed
519 520
	}

521 522 523
	/*
	 * Age RTTs of servers not tried.
	 */
Mark Andrews's avatar
Mark Andrews committed
524 525 526 527 528 529 530 531
	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);
532

Mark Andrews's avatar
Mark Andrews committed
533
	if (finish != NULL && TRIEDFIND(fctx))
534 535 536 537 538 539 540 541 542 543
                for (find = ISC_LIST_HEAD(fctx->finds);
		     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);

544 545 546 547 548 549 550
	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
551
		for (find = ISC_LIST_HEAD(fctx->altfinds);
552 553 554 555 556 557 558 559 560 561
		     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
562
	if (query->dispentry != NULL)
563
		dns_dispatch_removeresponse(&query->dispentry, deventp);
564

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

567 568
	if (query->tsig != NULL)
		isc_buffer_free(&query->tsig);
569

570 571 572
	if (query->tsigkey != NULL)
		dns_tsigkey_detach(&query->tsigkey);

573 574 575 576 577 578 579
	/*
	 * 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))
580 581 582
		/*
		 * Cancel the connect.
		 */
583 584
		isc_socket_cancel(query->tcpsocket, NULL,
				  ISC_SOCKCANCEL_CONNECT);
585 586 587 588 589 590
	else if (RESQUERY_SENDING(query))
		/*
		 * Cancel the pending send.
		 */
		isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
				  NULL, ISC_SOCKCANCEL_SEND);
591 592 593

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

595
	if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
596 597 598 599
		/*
		 * It's safe to destroy the query now.
		 */
		resquery_destroy(&query);
Bob Halley's avatar
Bob Halley committed
600 601 602
}

static void
603
fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
Bob Halley's avatar
Bob Halley committed
604 605 606 607 608 609 610 611
	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);
612
		fctx_cancelquery(&query, NULL, NULL, no_response);
Bob Halley's avatar
Bob Halley committed
613 614 615
	}
}

Bob Halley's avatar
Bob Halley committed
616
static void
Bob Halley's avatar
Bob Halley committed
617 618 619
fctx_cleanupfinds(fetchctx_t *fctx) {
	dns_adbfind_t *find, *next_find;

Bob Halley's avatar
Bob Halley committed
620 621
	REQUIRE(ISC_LIST_EMPTY(fctx->queries));

Bob Halley's avatar
Bob Halley committed
622 623 624 625 626 627
	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
628
	}
Bob Halley's avatar
Bob Halley committed
629
	fctx->find = NULL;
Bob Halley's avatar
Bob Halley committed
630 631
}

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
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;
}

648 649 650 651 652 653 654 655 656 657 658
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);
659
		dns_adb_freeaddrinfo(fctx->adb, &addr);
660 661 662
	}
}

663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
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
678
static inline void
679
fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
Bob Halley's avatar
Bob Halley committed
680
	FCTXTRACE("stopeverything");
681
	fctx_cancelqueries(fctx, no_response);
Bob Halley's avatar
Bob Halley committed
682
	fctx_cleanupfinds(fctx);
683
	fctx_cleanupaltfinds(fctx);
684
	fctx_cleanupforwaddrs(fctx);
685
	fctx_cleanupaltaddrs(fctx);
Bob Halley's avatar
Bob Halley committed
686
	fctx_stoptimer(fctx);
Bob Halley's avatar
Bob Halley committed
687
}
Bob Halley's avatar
Bob Halley committed
688

Bob Halley's avatar
Bob Halley committed
689 690 691 692
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
693

Bob Halley's avatar
Bob Halley committed
694 695 696 697 698 699
	/*
	 * Caller must be holding the appropriate bucket lock.
	 */
	REQUIRE(fctx->state == fetchstate_done);

	FCTXTRACE("sendevents");
Bob Halley's avatar
Bob Halley committed
700 701 702 703

	for (event = ISC_LIST_HEAD(fctx->events);
	     event != NULL;
	     event = next_event) {
704
		next_event = ISC_LIST_NEXT(event, ev_link);
705
		ISC_LIST_UNLINK(fctx->events, event, ev_link);
706 707
		task = event->ev_sender;
		event->ev_sender = fctx;
Bob Halley's avatar
Bob Halley committed
708
		if (!HAVE_ANSWER(fctx))
709
			event->result = result;
710 711 712 713

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

716
		isc_task_sendanddetach(&task, (isc_event_t **)&event);
Bob Halley's avatar
Bob Halley committed
717
	}
Bob Halley's avatar
Bob Halley committed
718
}
Bob Halley's avatar
Bob Halley committed
719

Bob Halley's avatar
Bob Halley committed
720 721 722
static void
fctx_done(fetchctx_t *fctx, isc_result_t result) {
	dns_resolver_t *res;
723
	isc_boolean_t no_response;
Bob Halley's avatar
Bob Halley committed
724 725 726 727 728

	FCTXTRACE("done");

	res = fctx->res;

729 730 731 732 733
	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
734 735 736 737

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

	fctx->state = fetchstate_done;
738
	fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
Bob Halley's avatar
Bob Halley committed
739
	fctx_sendevents(fctx, result);
Bob Halley's avatar
Bob Halley committed
740 741

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

Bob Halley's avatar
Bob Halley committed
744
static void
Bob Halley's avatar
Bob Halley committed
745
resquery_senddone(isc_task_t *task, isc_event_t *event) {
Bob Halley's avatar
Bob Halley committed
746
	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
747
	resquery_t *query = event->ev_arg;
Bob Halley's avatar
Bob Halley committed
748

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

Bob Halley's avatar
Bob Halley committed
751 752
	QTRACE("senddone");

Bob Halley's avatar
Bob Halley committed
753 754 755 756 757 758 759 760
	/*
	 * 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
761
	UNUSED(task);
Bob Halley's avatar
Bob Halley committed
762

763 764 765 766
	INSIST(RESQUERY_SENDING(query));

	query->sends--;

767 768 769 770 771 772 773 774 775 776 777 778
	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);
		}
	} else if (sevent->result != ISC_R_SUCCESS)
		fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
779

Bob Halley's avatar
Bob Halley committed
780 781 782
	isc_event_free(&event);
}

Bob Halley's avatar
Bob Halley committed
783
static inline isc_result_t
784
fctx_addopt(dns_message_t *message, dns_resolver_t *res) {
Bob Halley's avatar
Bob Halley committed
785 786 787
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
	dns_rdata_t *rdata;
Bob Halley's avatar
Bob Halley committed
788
	isc_result_t result;
Bob Halley's avatar
Bob Halley committed
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809

	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.
	 */
810
	rdatalist->rdclass = res->udpsize;
Bob Halley's avatar
Bob Halley committed
811 812

	/*
813
	 * Set EXTENDED-RCODE, VERSION, and Z to 0, and the DO bit to 1.
Bob Halley's avatar
Bob Halley committed
814
	 */
815
	rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO;
Bob Halley's avatar
Bob Halley committed
816 817

	/*
818
	 * No EDNS options.
Bob Halley's avatar
Bob Halley committed
819 820 821
	 */
	rdata->data = NULL;
	rdata->length = 0;
822 823
	rdata->rdclass = rdatalist->rdclass;
	rdata->type = rdatalist->type;
824
	rdata->flags = 0;
Bob Halley's avatar
Bob Halley committed
825 826 827

	ISC_LIST_INIT(rdatalist->rdata);
	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
828
	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
Bob Halley's avatar
Bob Halley committed
829 830 831 832

	return (dns_message_setopt(message, rdataset));
}

833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
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;
850

851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
	/*
	 * 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
866 867 868 869
static isc_result_t
fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
	   unsigned int options)
{
Bob Halley's avatar
Bob Halley committed
870 871
	dns_resolver_t *res;
	isc_task_t *task;
Bob Halley's avatar
Bob Halley committed
872 873
	isc_result_t result;
	resquery_t *query;
Bob Halley's avatar
Bob Halley committed
874

Bob Halley's avatar
Bob Halley committed
875
	FCTXTRACE("query");
Bob Halley's avatar
Bob Halley committed
876

Bob Halley's avatar
Bob Halley committed
877 878
	res = fctx->res;
	task = res->buckets[fctx->bucketnum].task;
Bob Halley's avatar
Bob Halley committed
879

880
	fctx_setretryinterval(fctx, addrinfo->srtt);
881
	result = fctx_startidletimer(fctx);
Bob Halley's avatar
Bob Halley committed
882
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
883 884
		return (result);

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

Andreas Gustafsson's avatar
Andreas Gustafsson committed
887
	query = isc_mem_get(res->mctx, sizeof(*query));
Bob Halley's avatar
Bob Halley committed
888
	if (query == NULL) {
889
		result = ISC_R_NOMEMORY;
890
		goto stop_idle_timer;
Bob Halley's avatar
Bob Halley committed
891
	}
892
	query->mctx = res->mctx;
Bob Halley's avatar
Bob Halley committed
893
	query->options = options;
894
	query->attributes = 0;
895
	query->sends = 0;
896
	query->connects = 0;
Bob Halley's avatar
Bob Halley committed
897 898 899 900 901
	/*
	 * Note that the caller MUST guarantee that 'addrinfo' will remain
	 * valid until this query is canceled.
	 */
	query->addrinfo = addrinfo;
902
	TIME_NOW(&query->start);
903

Bob Halley's avatar
Bob Halley committed
904 905 906
	/*
	 * 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
907 908
	 * shared dispatch.
	 */
909
	query->dispatchmgr = res->dispatchmgr;