resolver.c 236 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
Michael Graff's avatar
Michael Graff committed
6
7
 * 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

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id$ */
19
20

/*! \file */
David Lawrence's avatar
David Lawrence committed
21

22
23
#include <config.h>

24
#include <isc/log.h>
25
#include <isc/platform.h>
26
#include <isc/print.h>
Mark Andrews's avatar
Mark Andrews committed
27
#include <isc/string.h>
28
#include <isc/random.h>
29
#include <isc/socket.h>
30
#include <isc/stats.h>
31
#include <isc/task.h>
32
#include <isc/timer.h>
Michael Graff's avatar
Michael Graff committed
33
#include <isc/util.h>
Bob Halley's avatar
Bob Halley committed
34

35
#include <dns/acl.h>
Bob Halley's avatar
Bob Halley committed
36
#include <dns/adb.h>
37
#include <dns/cache.h>
Bob Halley's avatar
Bob Halley committed
38
#include <dns/db.h>
39
#include <dns/dispatch.h>
40
#include <dns/ds.h>
Bob Halley's avatar
Bob Halley committed
41
#include <dns/events.h>
42
#include <dns/forward.h>
Bob Halley's avatar
Bob Halley committed
43
#include <dns/keytable.h>
44
#include <dns/log.h>
Bob Halley's avatar
Bob Halley committed
45
#include <dns/message.h>
46
#include <dns/ncache.h>
47
48
#include <dns/nsec.h>
#include <dns/nsec3.h>
49
#include <dns/opcode.h>
50
#include <dns/peer.h>
51
#include <dns/rbt.h>
52
#include <dns/rcode.h>
53
#include <dns/rdata.h>
54
#include <dns/rdataclass.h>
Bob Halley's avatar
Bob Halley committed
55
#include <dns/rdatalist.h>
Bob Halley's avatar
Bob Halley committed
56
#include <dns/rdataset.h>
57
#include <dns/rdatastruct.h>
58
#include <dns/rdatatype.h>
59
60
#include <dns/resolver.h>
#include <dns/result.h>
61
#include <dns/rootns.h>
62
#include <dns/stats.h>
63
#include <dns/tsig.h>
64
#include <dns/validator.h>
Bob Halley's avatar
Bob Halley committed
65

Bob Halley's avatar
Bob Halley committed
66
67
#define DNS_RESOLVER_TRACE
#ifdef DNS_RESOLVER_TRACE
68
#define RTRACE(m)       isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
69
70
71
72
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "res %p: %s", res, (m))
73
#define RRTRACE(r, m)   isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
74
75
76
77
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "res %p: %s", (r), (m))
78
#define FCTXTRACE(m)    isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
79
80
81
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
82
				      "fctx %p(%s): %s", fctx, fctx->info, (m))
83
#define FCTXTRACE2(m1, m2) \
Mark Andrews's avatar
Mark Andrews committed
84
85
86
87
88
89
			isc_log_write(dns_lctx, \
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "fctx %p(%s): %s %s", \
				      fctx, fctx->info, (m1), (m2))
90
#define FTRACE(m)       isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
91
92
93
94
95
96
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "fetch %p (fctx %p(%s)): %s", \
				      fetch, fetch->private, \
				      fetch->private->info, (m))
97
#define QTRACE(m)       isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
98
99
100
101
102
103
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "resquery %p (fctx %p(%s)): %s", \
				      query, query->fctx, \
				      query->fctx->info, (m))
Bob Halley's avatar
Bob Halley committed
104
105
106
107
108
#else
#define RTRACE(m)
#define RRTRACE(r, m)
#define FCTXTRACE(m)
#define FTRACE(m)
Bob Halley's avatar
Bob Halley committed
109
#define QTRACE(m)
Bob Halley's avatar
Bob Halley committed
110
111
#endif

112
113
114
115
116
117
118
119
120
121
122
123
124
#define US_PER_SEC 1000000U
/*
 * The maximum time we will wait for a single query.
 */
#define MAX_SINGLE_QUERY_TIMEOUT 9U
#define MAX_SINGLE_QUERY_TIMEOUT_US (MAX_SINGLE_QUERY_TIMEOUT*US_PER_SEC)

/*
 * We need to allow a individual query time to complete / timeout.
 */
#define MINIMUM_QUERY_TIMEOUT (MAX_SINGLE_QUERY_TIMEOUT + 1U)

/* The default time in seconds for the whole query to live. */
125
#ifndef DEFAULT_QUERY_TIMEOUT
126
#define DEFAULT_QUERY_TIMEOUT MINIMUM_QUERY_TIMEOUT
127
128
129
130
131
132
#endif

#ifndef MAXIMUM_QUERY_TIMEOUT
#define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */
#endif

133
/*%
Bob Halley's avatar
Bob Halley committed
134
135
 * Maximum EDNS0 input packet size.
 */
136
#define RECV_BUFFER_SIZE                4096            /* XXXRTH  Constant. */
137

138
/*%
139
 * This defines the maximum number of timeouts we will permit before we
140
141
 * disable EDNS0 on the query.
 */
142
#define MAX_EDNS0_TIMEOUTS      3
143

Bob Halley's avatar
Bob Halley committed
144
145
typedef struct fetchctx fetchctx_t;

Bob Halley's avatar
Bob Halley committed
146
typedef struct query {
Mark Andrews's avatar
Mark Andrews committed
147
148
149
150
151
152
	/* Locked by task event serialization. */
	unsigned int			magic;
	fetchctx_t *			fctx;
	isc_mem_t *			mctx;
	dns_dispatchmgr_t *		dispatchmgr;
	dns_dispatch_t *		dispatch;
153
	isc_boolean_t			exclusivesocket;
Mark Andrews's avatar
Mark Andrews committed
154
155
156
157
158
159
160
161
162
	dns_adbaddrinfo_t *		addrinfo;
	isc_socket_t *			tcpsocket;
	isc_time_t			start;
	dns_messageid_t			id;
	dns_dispentry_t *		dispentry;
	ISC_LINK(struct query)		link;
	isc_buffer_t			buffer;
	isc_buffer_t			*tsig;
	dns_tsigkey_t			*tsigkey;
163
	isc_socketevent_t		sendevent;
Mark Andrews's avatar
Mark Andrews committed
164
165
166
167
168
	unsigned int			options;
	unsigned int			attributes;
	unsigned int			sends;
	unsigned int			connects;
	unsigned char			data[512];
Bob Halley's avatar
Bob Halley committed
169
170
} resquery_t;

Mark Andrews's avatar
Mark Andrews committed
171
172
#define QUERY_MAGIC			ISC_MAGIC('Q', '!', '!', '!')
#define VALID_QUERY(query)		ISC_MAGIC_VALID(query, QUERY_MAGIC)
Bob Halley's avatar
Bob Halley committed
173

174
#define RESQUERY_ATTR_CANCELED          0x02
175

176
177
#define RESQUERY_CONNECTING(q)          ((q)->connects > 0)
#define RESQUERY_CANCELED(q)            (((q)->attributes & \
Mark Andrews's avatar
Mark Andrews committed
178
					  RESQUERY_ATTR_CANCELED) != 0)
179
#define RESQUERY_SENDING(q)             ((q)->sends > 0)
180

Bob Halley's avatar
Bob Halley committed
181
typedef enum {
Mark Andrews's avatar
Mark Andrews committed
182
183
184
	fetchstate_init = 0,            /*%< Start event has not run yet. */
	fetchstate_active,
	fetchstate_done                 /*%< FETCHDONE events posted. */
Bob Halley's avatar
Bob Halley committed
185
186
} fetchstate;

187
188
189
190
191
192
typedef enum {
	badns_unreachable = 0,
	badns_response,
	badns_validation
} badnstype_t;

Bob Halley's avatar
Bob Halley committed
193
struct fetchctx {
Mark Andrews's avatar
Mark Andrews committed
194
195
196
197
198
199
200
	/*% Not locked. */
	unsigned int			magic;
	dns_resolver_t *		res;
	dns_name_t			name;
	dns_rdatatype_t			type;
	unsigned int			options;
	unsigned int			bucketnum;
201
202
203
	char *				info;
	isc_mem_t *			mctx;

Mark Andrews's avatar
Mark Andrews committed
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
	/*% Locked by appropriate bucket lock. */
	fetchstate			state;
	isc_boolean_t			want_shutdown;
	isc_boolean_t			cloned;
	isc_boolean_t			spilled;
	unsigned int			references;
	isc_event_t			control_event;
	ISC_LINK(struct fetchctx)       link;
	ISC_LIST(dns_fetchevent_t)      events;
	/*% Locked by task event serialization. */
	dns_name_t			domain;
	dns_rdataset_t			nameservers;
	unsigned int			attributes;
	isc_timer_t *			timer;
	isc_time_t			expires;
	isc_interval_t			interval;
	dns_message_t *			qmessage;
	dns_message_t *			rmessage;
	ISC_LIST(resquery_t)		queries;
	dns_adbfindlist_t		finds;
	dns_adbfind_t *			find;
	dns_adbfindlist_t		altfinds;
	dns_adbfind_t *			altfind;
	dns_adbaddrinfolist_t		forwaddrs;
	dns_adbaddrinfolist_t		altaddrs;
	isc_sockaddrlist_t		forwarders;
	dns_fwdpolicy_t			fwdpolicy;
	isc_sockaddrlist_t		bad;
	isc_sockaddrlist_t		edns;
	isc_sockaddrlist_t		edns512;
234
	isc_sockaddrlist_t		bad_edns;
Mark Andrews's avatar
Mark Andrews committed
235
236
237
238
	dns_validator_t			*validator;
	ISC_LIST(dns_validator_t)       validators;
	dns_db_t *			cache;
	dns_adb_t *			adb;
Mark Andrews's avatar
extend:    
Mark Andrews committed
239
240
	isc_boolean_t			ns_ttl_ok;
	isc_uint32_t			ns_ttl;
Mark Andrews's avatar
Mark Andrews committed
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

	/*%
	 * The number of events we're waiting for.
	 */
	unsigned int			pending;

	/*%
	 * 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".
	 */
	unsigned int			restarts;

	/*%
	 * The number of timeouts that have occurred since we
	 * last successfully received a response packet.  This
	 * is used for EDNS0 black hole detection.
	 */
	unsigned int			timeouts;
263

Mark Andrews's avatar
Mark Andrews committed
264
265
266
	/*%
	 * Look aside state for DS lookups.
	 */
267
	dns_name_t 			nsname;
Mark Andrews's avatar
Mark Andrews committed
268
269
270
271
272
273
274
	dns_fetch_t *			nsfetch;
	dns_rdataset_t			nsrrset;

	/*%
	 * Number of queries that reference this context.
	 */
	unsigned int			nqueries;
275
276
277
278
279
280

	/*%
	 * The reason to print when logging a successful
	 * response to a query.
	 */
	const char *			reason;
Evan Hunt's avatar
Evan Hunt committed
281
282
283
284
285
286

	/*%
	 * Random numbers to use for mixing up server addresses.
	 */
	isc_uint32_t                    rand_buf;
	isc_uint32_t                    rand_bits;
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304

	/*%
	 * Fetch-local statistics for detailed logging.
	 */
	isc_result_t			result; /*%< fetch result  */
	isc_result_t			vresult; /*%< validation result  */
	int				exitline;
	isc_time_t			start;
	isc_uint64_t			duration;
	isc_boolean_t			logged;
	unsigned int			querysent;
	unsigned int			referrals;
	unsigned int			lamecount;
	unsigned int			neterr;
	unsigned int			badresp;
	unsigned int			adberr;
	unsigned int			findfail;
	unsigned int			valfail;
305
	isc_boolean_t			timeout;
306
307
	dns_adbaddrinfo_t 		*addrinfo;
	isc_sockaddr_t			*client;
Bob Halley's avatar
Bob Halley committed
308
};
Bob Halley's avatar
Bob Halley committed
309

Mark Andrews's avatar
Mark Andrews committed
310
311
#define FCTX_MAGIC			ISC_MAGIC('F', '!', '!', '!')
#define VALID_FCTX(fctx)		ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
312
313
314
315
316
317
318
319
320
321
322
323

#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

#define HAVE_ANSWER(f)          (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
Mark Andrews's avatar
Mark Andrews committed
324
				 0)
325
#define GLUING(f)               (((f)->attributes & FCTX_ATTR_GLUING) != \
Mark Andrews's avatar
Mark Andrews committed
326
				 0)
327
#define ADDRWAIT(f)             (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
Mark Andrews's avatar
Mark Andrews committed
328
				 0)
329
#define SHUTTINGDOWN(f)         (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
Mark Andrews's avatar
Mark Andrews committed
330
				 != 0)
331
332
333
334
335
#define WANTCACHE(f)            (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
#define WANTNCACHE(f)           (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
#define NEEDEDNS0(f)            (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
#define TRIEDFIND(f)            (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
#define TRIEDALT(f)             (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
Bob Halley's avatar
Bob Halley committed
336

337
typedef struct {
Mark Andrews's avatar
Mark Andrews committed
338
339
	dns_adbaddrinfo_t *		addrinfo;
	fetchctx_t *			fctx;
340
341
} dns_valarg_t;

Bob Halley's avatar
Bob Halley committed
342
struct dns_fetch {
Mark Andrews's avatar
Mark Andrews committed
343
344
	unsigned int			magic;
	fetchctx_t *			private;
Bob Halley's avatar
Bob Halley committed
345
346
};

Mark Andrews's avatar
Mark Andrews committed
347
348
#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
349
350

typedef struct fctxbucket {
Mark Andrews's avatar
Mark Andrews committed
351
352
353
354
355
	isc_task_t *			task;
	isc_mutex_t			lock;
	ISC_LIST(fetchctx_t)		fctxs;
	isc_boolean_t			exiting;
	isc_mem_t *			mctx;
Bob Halley's avatar
Bob Halley committed
356
357
} fctxbucket_t;

358
typedef struct alternate {
Mark Andrews's avatar
Mark Andrews committed
359
360
361
362
363
364
365
366
367
	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;
368
369
} alternate_t;

370
371
372
373
374
375
376
377
378
379
380
381
typedef struct dns_badcache dns_badcache_t;
struct dns_badcache {
	dns_badcache_t *	next;
	dns_rdatatype_t 	type;
	isc_time_t		expire;
	unsigned int		hashval;
	dns_name_t		name;
};
#define DNS_BADCACHE_SIZE 1021
#define DNS_BADCACHE_TTL(fctx) \
	(((fctx)->res->lame_ttl > 30 ) ? (fctx)->res->lame_ttl : 30)

Bob Halley's avatar
Bob Halley committed
382
struct dns_resolver {
Mark Andrews's avatar
Mark Andrews committed
383
384
385
386
387
388
389
390
391
392
393
394
395
396
	/* Unlocked. */
	unsigned int			magic;
	isc_mem_t *			mctx;
	isc_mutex_t			lock;
	isc_mutex_t			nlock;
	isc_mutex_t			primelock;
	dns_rdataclass_t		rdclass;
	isc_socketmgr_t *		socketmgr;
	isc_timermgr_t *		timermgr;
	isc_taskmgr_t *			taskmgr;
	dns_view_t *			view;
	isc_boolean_t			frozen;
	unsigned int			options;
	dns_dispatchmgr_t *		dispatchmgr;
397
	dns_dispatchset_t *		dispatches4;
398
	isc_boolean_t			exclusivev4;
399
	dns_dispatchset_t *		dispatches6;
400
	isc_boolean_t			exclusivev6;
Mark Andrews's avatar
Mark Andrews committed
401
402
403
404
405
	unsigned int			nbuckets;
	fctxbucket_t *			buckets;
	isc_uint32_t			lame_ttl;
	ISC_LIST(alternate_t)		alternates;
	isc_uint16_t			udpsize;
406
#if USE_ALGLOCK
Mark Andrews's avatar
Mark Andrews committed
407
	isc_rwlock_t			alglock;
408
#endif
Mark Andrews's avatar
Mark Andrews committed
409
	dns_rbt_t *			algorithms;
410
	dns_rbt_t *			digests;
411
#if USE_MBSLOCK
Mark Andrews's avatar
Mark Andrews committed
412
	isc_rwlock_t			mbslock;
413
#endif
Mark Andrews's avatar
Mark Andrews committed
414
415
416
417
418
	dns_rbt_t *			mustbesecure;
	unsigned int			spillatmax;
	unsigned int			spillatmin;
	isc_timer_t *			spillattimer;
	isc_boolean_t			zero_no_soa_ttl;
419
	unsigned int			query_timeout;
420

Mark Andrews's avatar
Mark Andrews committed
421
422
423
424
425
426
427
	/* Locked by lock. */
	unsigned int			references;
	isc_boolean_t			exiting;
	isc_eventlist_t			whenshutdown;
	unsigned int			activebuckets;
	isc_boolean_t			priming;
	unsigned int			spillat;	/* clients-per-query */
428
429
430
431
432
433
434

	/* Bad cache. */
	dns_badcache_t  ** 		badcache;
	unsigned int 			badcount;
	unsigned int 			badhash;
	unsigned int 			badsweep;

Mark Andrews's avatar
Mark Andrews committed
435
436
437
438
	/* Locked by primelock. */
	dns_fetch_t *			primefetch;
	/* Locked by nlock. */
	unsigned int			nfctx;
Bob Halley's avatar
Bob Halley committed
439
440
};

Mark Andrews's avatar
Mark Andrews committed
441
442
#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
443

444
/*%
445
446
447
 * Private addrinfo flags.  These must not conflict with DNS_FETCHOPT_NOEDNS0,
 * which we also use as an addrinfo flag.
 */
448
449
#define FCTX_ADDRINFO_MARK              0x0001
#define FCTX_ADDRINFO_FORWARDER         0x1000
Evan Hunt's avatar
Evan Hunt committed
450
#define FCTX_ADDRINFO_TRIED             0x2000
451
#define UNMARKED(a)                     (((a)->flags & FCTX_ADDRINFO_MARK) \
Mark Andrews's avatar
Mark Andrews committed
452
					 == 0)
453
#define ISFORWARDER(a)                  (((a)->flags & \
Mark Andrews's avatar
Mark Andrews committed
454
					 FCTX_ADDRINFO_FORWARDER) != 0)
Evan Hunt's avatar
Evan Hunt committed
455
456
#define TRIED(a)                        (((a)->flags & \
					 FCTX_ADDRINFO_TRIED) != 0)
Bob Halley's avatar
Bob Halley committed
457

458
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
459
#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
460

Bob Halley's avatar
Bob Halley committed
461
static void destroy(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
462
static void empty_bucket(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
463
static isc_result_t resquery_send(resquery_t *query);
Bob Halley's avatar
Bob Halley committed
464
static void resquery_response(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
465
static void resquery_connected(isc_task_t *task, isc_event_t *event);
466
467
static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying,
		     isc_boolean_t badcache);
468
469
static void fctx_destroy(fetchctx_t *fctx);
static isc_boolean_t fctx_unlink(fetchctx_t *fctx);
470
static isc_result_t ncache_adderesult(dns_message_t *message,
Mark Andrews's avatar
Mark Andrews committed
471
472
473
				      dns_db_t *cache, dns_dbnode_t *node,
				      dns_rdatatype_t covers,
				      isc_stdtime_t now, dns_ttl_t maxttl,
474
				      isc_boolean_t optout,
Mark Andrews's avatar
Mark Andrews committed
475
476
				      dns_rdataset_t *ardataset,
				      isc_result_t *eresultp);
477
static void validated(isc_task_t *task, isc_event_t *event);
478
static isc_boolean_t maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked);
479
static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
480
		    isc_result_t reason, badnstype_t badtype);
481
482
483
static inline isc_result_t findnoqname(fetchctx_t *fctx, dns_name_t *name,
				       dns_rdatatype_t type,
				       dns_name_t **noqname);
484

485
486
487
488
/*%
 * Increment resolver-related statistics counters.
 */
static inline void
489
inc_stats(dns_resolver_t *res, isc_statscounter_t counter) {
490
	if (res->view->resstats != NULL)
491
		isc_stats_increment(res->view->resstats, counter);
492
493
}

494
495
496
497
498
499
static inline void
dec_stats(dns_resolver_t *res, isc_statscounter_t counter) {
	if (res->view->resstats != NULL)
		isc_stats_decrement(res->view->resstats, counter);
}

500
501
static isc_result_t
valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
Mark Andrews's avatar
Mark Andrews committed
502
503
504
	  dns_rdatatype_t type, dns_rdataset_t *rdataset,
	  dns_rdataset_t *sigrdataset, unsigned int valoptions,
	  isc_task_t *task)
505
{
Mark Andrews's avatar
Mark Andrews committed
506
507
508
509
	dns_validator_t *validator = NULL;
	dns_valarg_t *valarg;
	isc_result_t result;

510
	valarg = isc_mem_get(fctx->mctx, sizeof(*valarg));
Mark Andrews's avatar
Mark Andrews committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
	if (valarg == NULL)
		return (ISC_R_NOMEMORY);

	valarg->fctx = fctx;
	valarg->addrinfo = addrinfo;

	if (!ISC_LIST_EMPTY(fctx->validators))
		INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0);

	result = dns_validator_create(fctx->res->view, name, type, rdataset,
				      sigrdataset, fctx->rmessage,
				      valoptions, task, validated, valarg,
				      &validator);
	if (result == ISC_R_SUCCESS) {
525
		inc_stats(fctx->res, dns_resstatscounter_val);
Mark Andrews's avatar
Mark Andrews committed
526
527
		if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
			INSIST(fctx->validator == NULL);
528
			fctx->validator = validator;
Mark Andrews's avatar
Mark Andrews committed
529
530
531
		}
		ISC_LIST_APPEND(fctx->validators, validator, link);
	} else
532
		isc_mem_put(fctx->mctx, valarg, sizeof(*valarg));
Mark Andrews's avatar
Mark Andrews committed
533
	return (result);
534
}
Bob Halley's avatar
Bob Halley committed
535

536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
static isc_boolean_t
rrsig_fromchildzone(fetchctx_t *fctx, dns_rdataset_t *rdataset) {
	dns_namereln_t namereln;
	dns_rdata_rrsig_t rrsig;
	dns_rdata_t rdata = DNS_RDATA_INIT;
	int order;
	isc_result_t result;
	unsigned int labels;

	for (result = dns_rdataset_first(rdataset);
	     result == ISC_R_SUCCESS;
	     result = dns_rdataset_next(rdataset)) {
		dns_rdataset_current(rdataset, &rdata);
		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
		RUNTIME_CHECK(result == ISC_R_SUCCESS);
		namereln = dns_name_fullcompare(&rrsig.signer, &fctx->domain,
Automatic Updater's avatar
Automatic Updater committed
552
						&order, &labels);
553
554
555
556
557
558
559
		if (namereln == dns_namereln_subdomain)
			return (ISC_TRUE);
		dns_rdata_reset(&rdata);
	}
	return (ISC_FALSE);
}

560
static isc_boolean_t
561
fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
562
563
564
565
566
567
568
569
570
571
572
	dns_name_t *name;
	dns_name_t *domain = &fctx->domain;
	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);

	/*
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
	 * A DS RRset can appear anywhere in a zone, even for a delegation-only
	 * zone.  So a response to an explicit query for this type should be
	 * excluded from delegation-only fixup.
	 *
	 * SOA, NS, and DNSKEY can only exist at a zone apex, so a postive
	 * response to a query for these types can never violate the
	 * delegation-only assumption: if the query name is below a
	 * zone cut, the response should normally be a referral, which should
	 * be accepted; if the query name is below a zone cut but the server
	 * happens to have authority for the zone of the query name, the
	 * response is a (non-referral) answer.  But this does not violate
	 * delegation-only because the query name must be in a different zone
	 * due to the "apex-only" nature of these types.  Note that if the
	 * remote server happens to have authority for a child zone of a
	 * delegation-only zone, we may still incorrectly "fix" the response
	 * with NXDOMAIN for queries for other types.  Unfortunately it's
	 * generally impossible to differentiate this case from violation of
	 * the delegation-only assumption.  Once the resolver learns the
	 * correct zone cut, possibly via a separate query for an "apex-only"
	 * type, queries for other types will be resolved correctly.
	 *
	 * A query for type ANY will be accepted if it hits an exceptional
	 * type above in the answer section as it should be from a child
	 * zone.
	 *
	 * Also accept answers with RRSIG records from the child zone.
	 * Direct queries for RRSIG records should not be answered from
	 * the parent zone.
Mark Andrews's avatar
Mark Andrews committed
601
	 */
602

Mark Andrews's avatar
Mark Andrews committed
603
604
	if (message->counts[DNS_SECTION_ANSWER] != 0 &&
	    (fctx->type == dns_rdatatype_ns ||
605
606
607
608
609
	     fctx->type == dns_rdatatype_ds ||
	     fctx->type == dns_rdatatype_soa ||
	     fctx->type == dns_rdatatype_any ||
	     fctx->type == dns_rdatatype_rrsig ||
	     fctx->type == dns_rdatatype_dnskey)) {
Mark Andrews's avatar
Mark Andrews committed
610
611
612
613
614
615
616
617
		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)) {
Automatic Updater's avatar
Automatic Updater committed
618
				if (!dns_name_equal(name, &fctx->name))
Mark Andrews's avatar
Mark Andrews committed
619
					continue;
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
				type = rdataset->type;
				/*
				 * RRsig from child?
				 */
				if (type == dns_rdatatype_rrsig &&
				    rrsig_fromchildzone(fctx, rdataset))
					return (ISC_FALSE);
				/*
				 * Direct query for apex records or DS.
				 */
				if (fctx->type == type &&
				    (type == dns_rdatatype_ds ||
				     type == dns_rdatatype_ns ||
				     type == dns_rdatatype_soa ||
				     type == dns_rdatatype_dnskey))
					return (ISC_FALSE);
				/*
				 * Indirect query for apex records or DS.
				 */
				if (fctx->type == dns_rdatatype_any &&
				    (type == dns_rdatatype_ns ||
				     type == dns_rdatatype_ds ||
				     type == dns_rdatatype_soa ||
				     type == dns_rdatatype_dnskey))
Mark Andrews's avatar
Mark Andrews committed
644
645
646
647
648
649
650
					return (ISC_FALSE);
			}
			result = dns_message_nextname(message,
						      DNS_SECTION_ANSWER);
		}
	}

651
652
653
654
655
656
657
658
	/*
	 * A NODATA response to a DS query?
	 */
	if (fctx->type == dns_rdatatype_ds &&
	    message->counts[DNS_SECTION_ANSWER] == 0)
		return (ISC_FALSE);

	/* Look for referral or indication of answer from child zone? */
Mark Andrews's avatar
Mark Andrews committed
659
660
661
662
663
664
665
666
667
668
669
670
671
672
	if (message->counts[DNS_SECTION_AUTHORITY] == 0)
		goto munge;

	result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
	while (result == ISC_R_SUCCESS) {
		name = NULL;
		dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
		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;
673

Mark Andrews's avatar
Mark Andrews committed
674
			if (type != dns_rdatatype_ns &&
675
676
			    type != dns_rdatatype_soa &&
			    type != dns_rdatatype_rrsig)
Mark Andrews's avatar
Mark Andrews committed
677
				continue;
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701

			if (type == dns_rdatatype_rrsig) {
				if (rrsig_fromchildzone(fctx, rdataset))
					return (ISC_FALSE);
				else
					continue;
			}

			/* NS or SOA records. */
			if (dns_name_equal(name, domain)) {
				/*
				 * If a query for ANY causes a negative
				 * response, we can be sure that this is
				 * an empty node.  For other type of queries
				 * we cannot differentiate an empty node
				 * from a node that just doesn't have that
				 * type of record.  We only accept the former
				 * case.
				 */
				if (message->counts[DNS_SECTION_ANSWER] == 0 &&
				    fctx->type == dns_rdatatype_any)
					return (ISC_FALSE);
			} else if (dns_name_issubdomain(name, domain)) {
				/* Referral or answer from child zone. */
Mark Andrews's avatar
Mark Andrews committed
702
				return (ISC_FALSE);
703
			}
Mark Andrews's avatar
Mark Andrews committed
704
705
706
		}
		result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
	}
707
708

 munge:
Mark Andrews's avatar
Mark Andrews committed
709
710
711
712
713
714
	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);
715
716
}

Bob Halley's avatar
Bob Halley committed
717
static inline isc_result_t
Bob Halley's avatar
Bob Halley committed
718
fctx_starttimer(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
719
720
721
722
723
724
725
726
727
	/*
	 * Start the lifetime timer for fctx.
	 *
	 * 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.
	 */
	return (isc_timer_reset(fctx->timer, isc_timertype_once,
				&fctx->expires, NULL, ISC_TRUE));
Bob Halley's avatar
Bob Halley committed
728
729
}

Bob Halley's avatar
Bob Halley committed
730
731
static inline void
fctx_stoptimer(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
	isc_result_t result;

	/*
	 * 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.
	 */
	result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
				  NULL, NULL, ISC_TRUE);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_timer_reset(): %s",
				 isc_result_totext(result));
	}
Bob Halley's avatar
Bob Halley committed
747
748
}

749
750

static inline isc_result_t
751
fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) {
Mark Andrews's avatar
Mark Andrews committed
752
753
754
755
756
	/*
	 * Start the idle timer for fctx.  The lifetime timer continues
	 * to be in effect.
	 */
	return (isc_timer_reset(fctx->timer, isc_timertype_once,
757
				&fctx->expires, interval, ISC_FALSE));
758
759
760
761
762
763
}

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


767
768
static inline void
resquery_destroy(resquery_t **queryp) {
Mark Andrews's avatar
Mark Andrews committed
769
	resquery_t *query;
770

Mark Andrews's avatar
Mark Andrews committed
771
772
773
	REQUIRE(queryp != NULL);
	query = *queryp;
	REQUIRE(!ISC_LINK_LINKED(query, link));
774

Mark Andrews's avatar
Mark Andrews committed
775
	INSIST(query->tcpsocket == NULL);
776

Mark Andrews's avatar
Mark Andrews committed
777
	query->fctx->nqueries--;
778
779
780
781
782
	if (SHUTTINGDOWN(query->fctx)) {
		dns_resolver_t *res = query->fctx->res;
		if (maybe_destroy(query->fctx, ISC_FALSE))
			empty_bucket(res);
	}
Mark Andrews's avatar
Mark Andrews committed
783
784
785
	query->magic = 0;
	isc_mem_put(query->mctx, query, sizeof(*query));
	*queryp = NULL;
786
787
}

Bob Halley's avatar
Bob Halley committed
788
static void
Bob Halley's avatar
Bob Halley committed
789
fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
Mark Andrews's avatar
Mark Andrews committed
790
		 isc_time_t *finish, isc_boolean_t no_response)
Bob Halley's avatar
Bob Halley committed
791
{
Mark Andrews's avatar
Mark Andrews committed
792
793
	fetchctx_t *fctx;
	resquery_t *query;
794
	unsigned int rtt, rttms;
Mark Andrews's avatar
Mark Andrews committed
795
796
797
	unsigned int factor;
	dns_adbfind_t *find;
	dns_adbaddrinfo_t *addrinfo;
798
	isc_socket_t *socket;
Mark Andrews's avatar
Mark Andrews committed
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820

	query = *queryp;
	fctx = query->fctx;

	FCTXTRACE("cancelquery");

	REQUIRE(!RESQUERY_CANCELED(query));

	query->attributes |= RESQUERY_ATTR_CANCELED;

	/*
	 * Should we update the RTT?
	 */
	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;
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841

			rttms = rtt / 1000;
			if (rttms < DNS_RESOLVER_QRYRTTCLASS0) {
				inc_stats(fctx->res,
					  dns_resstatscounter_queryrtt0);
			} else if (rttms < DNS_RESOLVER_QRYRTTCLASS1) {
				inc_stats(fctx->res,
					  dns_resstatscounter_queryrtt1);
			} else if (rttms < DNS_RESOLVER_QRYRTTCLASS2) {
				inc_stats(fctx->res,
					  dns_resstatscounter_queryrtt2);
			} else if (rttms < DNS_RESOLVER_QRYRTTCLASS3) {
				inc_stats(fctx->res,
					  dns_resstatscounter_queryrtt3);
			} else if (rttms < DNS_RESOLVER_QRYRTTCLASS4) {
				inc_stats(fctx->res,
					  dns_resstatscounter_queryrtt4);
			} else {
				inc_stats(fctx->res,
					  dns_resstatscounter_queryrtt5);
			}
Mark Andrews's avatar
Mark Andrews committed
842
843
844
845
846
847
848
849
		} 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 + 200000;
850
851
			if (rtt > MAX_SINGLE_QUERY_TIMEOUT_US)
				rtt = MAX_SINGLE_QUERY_TIMEOUT_US;
Mark Andrews's avatar
Mark Andrews committed
852
853
854
855
856
857
858
859
			/*
			 * Replace the current RTT with our value.
			 */
			factor = DNS_ADB_RTTADJREPLACE;
		}
		dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
	}

Evan Hunt's avatar
Evan Hunt committed
860
861
862
863
864
865
	/* Remember that the server has been tried. */
	if (!TRIED(query->addrinfo)) {
		dns_adb_changeflags(fctx->adb, query->addrinfo,
				    FCTX_ADDRINFO_TRIED, FCTX_ADDRINFO_TRIED);
	}

Mark Andrews's avatar
Mark Andrews committed
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
	/*
	 * Age RTTs of servers not tried.
	 */
	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);

	if (finish != NULL && TRIEDFIND(fctx))
		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);

	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);
		for (find = ISC_LIST_HEAD(fctx->altfinds);
		     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);
	}

	/*
	 * 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.
	 */
913
	if (RESQUERY_CONNECTING(query)) {
Mark Andrews's avatar
Mark Andrews committed
914
915
916
		/*
		 * Cancel the connect.
		 */
917
918
919
920
921
922
923
924
925
926
927
		if (query->tcpsocket != NULL) {
			isc_socket_cancel(query->tcpsocket, NULL,
					  ISC_SOCKCANCEL_CONNECT);
		} else if (query->dispentry != NULL) {
			INSIST(query->exclusivesocket);
			socket = dns_dispatch_getentrysocket(query->dispentry);
			if (socket != NULL)
				isc_socket_cancel(socket, NULL,
						  ISC_SOCKCANCEL_CONNECT);
		}
	} else if (RESQUERY_SENDING(query)) {
Mark Andrews's avatar
Mark Andrews committed
928
929
930
		/*
		 * Cancel the pending send.
		 */
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
		if (query->exclusivesocket && query->dispentry != NULL)
			socket = dns_dispatch_getentrysocket(query->dispentry);
		else
			socket = dns_dispatch_getsocket(query->dispatch);
		if (socket != NULL)
			isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
	}

	if (query->dispentry != NULL)
		dns_dispatch_removeresponse(&query->dispentry, deventp);

	ISC_LIST_UNLINK(fctx->queries, query, link);

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

	if (query->tsigkey != NULL)
		dns_tsigkey_detach(&query->tsigkey);
Mark Andrews's avatar
Mark Andrews committed
949
950
951
952
953
954
955
956
957

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

	if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
		/*
		 * It's safe to destroy the query now.
		 */
		resquery_destroy(&query);
Bob Halley's avatar
Bob Halley committed
958
959
960
}

static void
961
fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
Mark Andrews's avatar
Mark Andrews committed
962
	resquery_t *query, *next_query;
Bob Halley's avatar
Bob Halley committed
963

Mark Andrews's avatar
Mark Andrews committed
964
	FCTXTRACE("cancelqueries");
Bob Halley's avatar
Bob Halley committed
965

Mark Andrews's avatar
Mark Andrews committed
966
967
968
969
970
971
	for (query = ISC_LIST_HEAD(fctx->queries);
	     query != NULL;
	     query = next_query) {
		next_query = ISC_LIST_NEXT(query, link);
		fctx_cancelquery(&query, NULL, NULL, no_response);
	}
Bob Halley's avatar
Bob Halley committed
972
973
}

Bob Halley's avatar
Bob Halley committed
974
static void
Bob Halley's avatar
Bob Halley committed
975
fctx_cleanupfinds(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
976
977
978
979
980
981
982
983
984
985
986
987
	dns_adbfind_t *find, *next_find;

	REQUIRE(ISC_LIST_EMPTY(fctx->queries));

	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);
	}
	fctx->find = NULL;
Bob Halley's avatar
Bob Halley committed
988
989
}

990
991
static void
fctx_cleanupaltfinds(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
992
993
994
995
996
997
998
999
1000
1001
1002
1003
	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;
1004
1005
}

1006
1007
static void
fctx_cleanupforwaddrs(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
1008
	dns_adbaddrinfo_t *addr, *next_addr;
1009

Mark Andrews's avatar
Mark Andrews committed
1010
	REQUIRE(ISC_LIST_EMPTY(fctx->queries));
1011

Mark Andrews's avatar
Mark Andrews committed
1012
1013
1014
1015
1016
1017
1018
	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->adb, &addr);
	}
1019
1020
}

1021
1022
static void
fctx_cleanupaltaddrs(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
1023
	dns_adbaddrinfo_t *addr, *next_addr;
1024

Mark Andrews's avatar
Mark Andrews committed
1025
	REQUIRE(ISC_LIST_EMPTY(fctx->queries));
1026

Mark Andrews's avatar
Mark Andrews committed
1027
1028
1029
1030
1031
1032
1033
	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);
	}
1034
1035
}

Bob Halley's avatar
Bob Halley committed
1036
static inline void
1037
fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
Mark Andrews's avatar
Mark Andrews committed
1038
1039
1040
1041
1042
1043
1044
	FCTXTRACE("stopeverything");
	fctx_cancelqueries(fctx, no_response);
	fctx_cleanupfinds(fctx);
	fctx_cleanupaltfinds(fctx);
	fctx_cleanupforwaddrs(fctx);
	fctx_cleanupaltaddrs(fctx);
	fctx_stoptimer(fctx);
Bob Halley's avatar
Bob Halley committed
1045
}
Bob Halley's avatar
Bob Halley committed
1046

Bob Halley's avatar
Bob Halley committed
1047
static inline void
1048
fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) {
Mark Andrews's avatar
Mark Andrews committed
1049
1050
1051
1052
1053
	dns_fetchevent_t *event, *next_event;
	isc_task_t *task;
	unsigned int count = 0;
	isc_interval_t i;
	isc_boolean_t logit = ISC_FALSE;
1054
	isc_time_t now;
1055
	unsigned int old_spillat;
Automatic Updater's avatar
Automatic Updater committed
1056
	unsigned int new_spillat = 0;	/* initialized to silence
1057
					   compiler warnings */
1058

Mark Andrews's avatar
Mark Andrews committed
1059
1060
1061
1062
1063
1064
1065
	/*
	 * Caller must be holding the appropriate bucket lock.
	 */
	REQUIRE(fctx->state == fetchstate_done);

	FCTXTRACE("sendevents");

1066
	/*
Automatic Updater's avatar
Automatic Updater committed
1067
	 * Keep some record of fetch result for logging later (if required).
1068
1069
1070
1071
1072
1073
	 */
	fctx->result = result;
	fctx->exitline = line;
	TIME_NOW(&now);
	fctx->duration = isc_time_microdiff(&now, &fctx->start);

Mark Andrews's avatar
Mark Andrews committed
1074
1075
1076
1077
1078
1079
1080
	for (event = ISC_LIST_HEAD(fctx->events);
	     event != NULL;
	     event = next_event) {
		next_event = ISC_LIST_NEXT(event, ev_link);
		ISC_LIST_UNLINK(fctx->events, event, ev_link);
		task = event->ev_sender;
		event->ev_sender = fctx;
1081
		event->vresult = fctx->vresult;
Mark Andrews's avatar
Mark Andrews committed
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
		if (!HAVE_ANSWER(fctx))
			event->result = result;

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

		/*
		 * Negative results must be indicated in event->result.
		 */
		if (dns_rdataset_isassociated(event->rdataset) &&
1095
		    NEGATIVE(event->rdataset)) {
Mark Andrews's avatar
Mark Andrews committed
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
			INSIST(event->result == DNS_R_NCACHENXDOMAIN ||
			       event->result == DNS_R_NCACHENXRRSET);
		}

		isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
		count++;
	}

	if ((fctx->attributes & FCTX_ATTR_HAVEANSWER) != 0 &&
	    fctx->spilled &&
	    (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) {
		LOCK(&fctx->res->lock);
		if (count == fctx->res->spillat && !fctx->res->exiting) {
1109
			old_spillat = fctx->res->spillat;
Mark Andrews's avatar
Mark Andrews committed
1110
1111
1112
1113
			fctx->res->spillat += 5;
			if (fctx->res->spillat > fctx->res->spillatmax &&
			    fctx->res->spillatmax != 0)
				fctx->res->spillat = fctx->res->spillatmax;
1114
1115
			new_spillat = fctx->res->spillat;
			if (new_spillat != old_spillat) {
Mark Andrews's avatar
Mark Andrews committed
1116
				logit = ISC_TRUE;
1117
			}
Mark Andrews's avatar
Mark Andrews committed
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
			isc_interval_set(&i, 20 * 60, 0);
			result = isc_timer_reset(fctx->res->spillattimer,
						 isc_timertype_ticker, NULL,
						 &i, ISC_TRUE);
			RUNTIME_CHECK(result == ISC_R_SUCCESS);
		}
		UNLOCK(&fctx->res->lock);
		if (logit)
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
				      DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
				      "clients-per-query increased to %u",
				      new_spillat);
	}
Bob Halley's avatar
Bob Halley committed
1131
}
Bob Halley's avatar
Bob Halley committed
1132

1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
static inline void
log_edns(fetchctx_t *fctx) {
	char domainbuf[DNS_NAME_FORMATSIZE];

	if (fctx->reason == NULL)
		return;

	dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_EDNS_DISABLED,
		      DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
		      "success resolving '%s' (in '%s'?) after %s",
		      fctx->info, domainbuf, fctx->reason);

	fctx->reason = NULL;
}

Bob Halley's avatar
Bob Halley committed
1149
static void
1150
fctx_done(fetchctx_t *fctx, isc_result_t result, int line) {
Mark Andrews's avatar
Mark Andrews committed
1151
1152
	dns_resolver_t *res;
	isc_boolean_t no_response;
Bob Halley's avatar
Bob Halley committed
1153

1154
1155
	REQUIRE(line >= 0);

Mark Andrews's avatar
Mark Andrews committed
1156
	FCTXTRACE("done");
Bob Halley's avatar
Bob Halley committed
1157

Mark Andrews's avatar
Mark Andrews committed
1158
	res = fctx->res;
Bob Halley's avatar
Bob Halley committed
1159

1160
1161
1162
1163
1164
	if (result == ISC_R_SUCCESS) {
		/*%
		 * Log any deferred EDNS timeout messages.
		 */
		log_edns(fctx);
Mark Andrews's avatar
Mark Andrews committed
1165
		no_response = ISC_TRUE;
1166
	 } else
Mark Andrews's avatar
Mark Andrews committed
1167
		no_response = ISC_FALSE;
1168
1169

	fctx->reason = NULL;
Mark Andrews's avatar
Mark Andrews committed
1170
	fctx_stopeverything(fctx, no_response);
Bob Halley's avatar
Bob Halley committed
1171

Mark Andrews's avatar
Mark Andrews committed
1172
	LOCK(&res->buckets[fctx->bucketnum].lock);
Bob Halley's avatar
Bob Halley committed
1173

Mark Andrews's avatar
Mark Andrews committed
1174
1175
	fctx->state = fetchstate_done;
	fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1176
	fctx_sendevents(fctx, result, line);
Bob Halley's avatar
Bob Halley committed
1177

Mark Andrews's avatar
Mark Andrews committed
1178
	UNLOCK(&res->buckets[fctx->bucketnum].lock);
Bob Halley's avatar
Bob Halley committed
1179
1180
}

Bob Halley's avatar
Bob Halley committed
1181
static void
1182
process_sendevent(resquery_t *query, isc_event_t *event) {
Mark Andrews's avatar
Mark Andrews committed
1183
1184
1185
1186
1187
1188
1189
1190
	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
	isc_boolean_t retry = ISC_FALSE;
	isc_result_t result;
	fetchctx_t *fctx;

	fctx = query->fctx;

	if (RESQUERY_CANCELED(query)) {
1191
		if (query->sends == 0 && query->connects == 0) {
Mark Andrews's avatar
Mark Andrews committed
1192
1193
			/*
			 * This query was canceled while the
1194
			 * isc_socket_sendto/connect() was in progress.
Mark Andrews's avatar
Mark Andrews committed
1195
1196
1197
1198
1199
			 */
			if (query->tcpsocket != NULL)
				isc_socket_detach(&query->tcpsocket);
			resquery_destroy(&query);
		}
1200
	} else {
Mark Andrews's avatar
Mark Andrews committed
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
		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.
			 */
1214
1215
			add_bad(fctx, query->addrinfo, sevent->result,
				badns_unreachable);
Mark Andrews's avatar
Mark Andrews committed
1216
1217
1218
1219
1220
1221
1222
1223
			fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
			retry = ISC_TRUE;
			break;

		default:
			fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
			break;
		}
1224
	}
Mark Andrews's avatar
Mark Andrews committed
1225

1226
1227
	if (event->ev_type == ISC_SOCKEVENT_CONNECT)
		isc_event_free(&event);
Mark Andrews's avatar
Mark Andrews committed
1228
1229
1230
1231
1232
1233
1234
1235
1236

	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)
1237
			fctx_done(fctx, result, __LINE__);
Mark Andrews's avatar
Mark Andrews committed
1238
		else
1239
			fctx_try(fctx, ISC_TRUE, ISC_FALSE);
Mark Andrews's avatar
Mark Andrews committed
1240
	}
Bob Halley's avatar
Bob Halley committed
1241
1242
}

1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
static void
resquery_udpconnected(isc_task_t *task, isc_event_t *event) {
	resquery_t *query = event->ev_arg;

	REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);

	QTRACE("udpconnected");

	UNUSED(task);

	INSIST(RESQUERY_CONNECTING(query));

	query->connects--;

	process_sendevent(query, event);
}

static void
resquery_senddone(isc_task_t *task, isc_event_t *event) {
	resquery_t *query = event->ev_arg;

	REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);

	QTRACE("senddone");

	/*
	 * 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!
	 */

	UNUSED(task);

	INSIST(RESQUERY_SENDING(query));

	query->sends--;

	process_sendevent(query, event);
}

Bob Halley's avatar
Bob Halley committed
1285
static inline isc_result_t
1286
1287
fctx_addopt(dns_message_t *message, unsigned int version,
	    isc_uint16_t udpsize, isc_boolean_t request_nsid)
1288
{
Mark Andrews's avatar
Mark Andrews committed
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
	dns_rdataset_t *rdataset;
	dns_rdatalist_t *rdatalist;
	dns_rdata_t *rdata;
	isc_result_t result;

	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 = udpsize;

	/*
	 * Set EXTENDED-RCODE and Z to 0, DO to 1.
	 */
	rdatalist->ttl = (version << 16);
	rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO;

	/*
1323
	 * Set EDNS options if applicable
Mark Andrews's avatar
Mark Andrews committed
1324
	 */
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
	if (request_nsid) {
		/* Send empty NSID option (RFC5001) */
		unsigned char data[4];
		isc_buffer_t buf;

		isc_buffer_init(&buf, data, sizeof(data));
		isc_buffer_putuint16(&buf, DNS_OPT_NSID);
		isc_buffer_putuint16(&buf, 0);
		rdata->data = data;
		rdata->length = sizeof(data);
	} else {
		rdata->data = NULL;
		rdata->length = 0;
	}

Mark Andrews's avatar
Mark Andrews committed
1340
1341
1342
1343
1344
1345
1346
1347
1348
	rdata->rdclass = rdatalist->rdclass;
	rdata->type = rdatalist->type;
	rdata->flags = 0;

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

	return (dns_message_setopt(message, rdataset));
Bob Halley's avatar
Bob Halley committed
1349
1350
}

1351
1352
static inline void
fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
Mark Andrews's avatar
Mark Andrews committed
1353
1354
1355
1356
	unsigned int seconds;
	unsigned int us;

	/*
1357
	 * We retry every .8 seconds the first two times through the address
Mark Andrews's avatar
Mark Andrews committed
1358
1359
	 * list, and then we do exponential back-off.
	 */
Evan Hunt's avatar
Evan Hunt committed
1360
	if (fctx->restarts < 3)
1361
		us = 800000;
Mark Andrews's avatar
Mark Andrews committed
1362
	else
1363
		us = (800000 << (fctx->restarts - 2));
Mark Andrews's avatar
Mark Andrews committed
1364
1365

	/*
1366
1367
	 * Add a fudge factor to the expected rtt based on the current
	 * estimate.
Mark Andrews's avatar
Mark Andrews committed
1368
	 */
1369
1370
1371
1372
1373
1374
	if (rtt < 50000)
		rtt += 50000;
	else if (rtt < 100000)
		rtt += 100000;
	else
		rtt += 200000;
Mark Andrews's avatar
Mark Andrews committed
1375
1376

	/*
1377
	 * Always wait for at least the expected rtt.
Mark Andrews's avatar
Mark Andrews committed
1378
1379
1380
1381
1382
1383
1384
	 */
	if (us < rtt)
		us = rtt;

	/*
	 * But don't ever wait for more than 10 seconds.
	 */
1385
1386
	if (us > MAX_SINGLE_QUERY_TIMEOUT_US)
		us = MAX_SINGLE_QUERY_TIMEOUT_US;
Mark Andrews's avatar
Mark Andrews committed
1387

1388
1389
	seconds = us / US_PER_SEC;
	us -= seconds * US_PER_SEC;
Mark Andrews's avatar
Mark Andrews committed
1390
	isc_interval_set(&fctx->interval, seconds, us * 1000);
1391
1392
}

Bob Halley's avatar
Bob Halley committed
1393
1394
static isc_result_t
fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
Mark Andrews's avatar
Mark Andrews committed
1395
	   unsigned int options)
Bob Halley's avatar
Bob Halley committed
1396
{
Mark Andrews's avatar
Mark Andrews committed
1397
1398
1399
1400
1401
1402
	dns_resolver_t *res;
	isc_task_t *task;
	isc_result_t result;
	resquery_t *query;
	isc_sockaddr_t addr;
	isc_boolean_t have_addr = ISC_FALSE;
1403
	unsigned int srtt;
Mark Andrews's avatar
Mark Andrews committed
1404
1405
1406
1407
1408
1409

	FCTXTRACE("query");

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

1410
	srtt = addrinfo->srtt;
1411
1412
1413
1414
1415

	/*
	 * A forwarder needs to make multiple queries. Give it at least
	 * a second to do these in.
	 */
1416
1417
1418
1419
	if (ISFORWARDER(addrinfo) && srtt < 1000000)
		srtt = 1000000;

	fctx_setretryinterval(fctx, srtt);
1420
	result = fctx_startidletimer(fctx, &fctx->interval);
Mark Andrews's avatar
Mark Andrews committed
1421
1422
1423
1424
1425
1426
1427
	if (result != ISC_R_SUCCESS)
		return (result);

	INSIST(ISC_LIST_EMPTY(fctx->validators));

	dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);

1428
	query = isc_mem_get(fctx->mctx, sizeof(*query));
Mark Andrews's avatar
Mark Andrews committed
1429
1430
1431
1432
	if (query == NULL) {
		result = ISC_R_NOMEMORY;
		goto stop_idle_timer;
	}
1433
	query->mctx = fctx->mctx;
Mark Andrews's avatar
Mark Andrews committed
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
	query->options = options;
	query->attributes = 0;
	query->sends = 0;
	query->connects = 0;
	/*
	 * Note that the caller MUST guarantee that 'addrinfo' will remain
	 * valid until this query is canceled.
	 */
	query->addrinfo = addrinfo;
	TIME_NOW(&query->start);

	/*
	 * 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
	 * shared dispatch.
	 */
	query->dispatchmgr = res->dispatchmgr;
	query->dispatch = NULL;
1452
	query->exclusivesocket = ISC_FALSE;
Mark Andrews's avatar
Mark Andrews committed
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
	query->tcpsocket = NULL;
	if (res->view->peers != NULL) {
		dns_peer_t *peer = NULL;
		isc_netaddr_t dstip;
		isc_netaddr_fromsockaddr(&dstip, &addrinfo->sockaddr);
		result = dns_peerlist_peerbyaddr(res->view->peers,
						 &dstip, &peer);
		if (result == ISC_R_SUCCESS) {
			result = dns_peer_getquerysource(peer, &addr);
			if (result == ISC_R_SUCCESS)
				have_addr = ISC_TRUE;
		}
	}

	if ((query->options & DNS_FETCHOPT_TCP) != 0) {
		int pf;

		pf = isc_sockaddr_pf(&addrinfo->sockaddr);
		if (!have_addr) {
			switch (pf) {
			case PF_INET:
1474
1475
1476
				result = dns_dispatch_getlocaladdress(
					      res->dispatches4->dispatches[0],
					      &addr);
Mark Andrews's avatar
Mark Andrews committed
1477
1478
				break;
			case PF_INET6:
1479
1480
1481
				result = dns_dispatch_getlocaladdress(
					      res->dispatches6->dispatches[0],
					      &addr);
Mark Andrews's avatar
Mark Andrews committed
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
				break;
			default:
				result = ISC_R_NOTIMPLEMENTED;
				break;
			}
			if (result != ISC_R_SUCCESS)
				goto cleanup_query;
		}
		isc_sockaddr_setport(&addr, 0);

		result = isc_socket_create(res->socketmgr, pf,
					   isc_sockettype_tcp,
					   &query->tcpsocket);
		if (result != ISC_R_SUCCESS)
			goto cleanup_query;
1497

1498
#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
1499
		result = isc_socket_bind(query->tcpsocket, &addr, 0);