resolver.c 252 KB
Newer Older
Michael Graff's avatar
Michael Graff committed
1
/*
Tinderbox User's avatar
Tinderbox User committed
2
 * Copyright (C) 2004-2014  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

18
/*! \file */
David Lawrence's avatar
David Lawrence committed
19

20
#include <config.h>
Evan Hunt's avatar
Evan Hunt committed
21
#include <ctype.h>
22

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

34
35
36
37
38
39
#ifdef AES_SIT
#include <isc/aes.h>
#else
#include <isc/hmacsha.h>
#endif

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

Bob Halley's avatar
Bob Halley committed
71
72
#define DNS_RESOLVER_TRACE
#ifdef DNS_RESOLVER_TRACE
73
#define RTRACE(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", res, (m))
78
#define RRTRACE(r, m)   isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
79
80
81
82
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "res %p: %s", (r), (m))
83
#define FCTXTRACE(m)    isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
84
85
86
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
87
				      "fctx %p(%s): %s", fctx, fctx->info, (m))
88
#define FCTXTRACE2(m1, m2) \
Mark Andrews's avatar
Mark Andrews committed
89
90
91
92
93
94
			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))
95
#define FTRACE(m)       isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
96
97
98
99
100
101
				      DNS_LOGCATEGORY_RESOLVER, \
				      DNS_LOGMODULE_RESOLVER, \
				      ISC_LOG_DEBUG(3), \
				      "fetch %p (fctx %p(%s)): %s", \
				      fetch, fetch->private, \
				      fetch->private->info, (m))
102
#define QTRACE(m)       isc_log_write(dns_lctx, \
Mark Andrews's avatar
Mark Andrews committed
103
104
105
106
107
108
				      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
109
110
111
112
#else
#define RTRACE(m)
#define RRTRACE(r, m)
#define FCTXTRACE(m)
113
#define FCTXTRACE2(m1, m2)
Bob Halley's avatar
Bob Halley committed
114
#define FTRACE(m)
Bob Halley's avatar
Bob Halley committed
115
#define QTRACE(m)
Bob Halley's avatar
Bob Halley committed
116
117
#endif

118
119
120
121
122
123
124
125
126
127
128
129
130
#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. */
131
#ifndef DEFAULT_QUERY_TIMEOUT
132
#define DEFAULT_QUERY_TIMEOUT MINIMUM_QUERY_TIMEOUT
133
134
135
136
137
138
#endif

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

139
/*%
Bob Halley's avatar
Bob Halley committed
140
141
 * Maximum EDNS0 input packet size.
 */
142
#define RECV_BUFFER_SIZE                4096            /* XXXRTH  Constant. */
143

144
/*%
145
 * This defines the maximum number of timeouts we will permit before we
146
147
 * disable EDNS0 on the query.
 */
148
#define MAX_EDNS0_TIMEOUTS      3
149

Bob Halley's avatar
Bob Halley committed
150
151
typedef struct fetchctx fetchctx_t;

Bob Halley's avatar
Bob Halley committed
152
typedef struct query {
Mark Andrews's avatar
Mark Andrews committed
153
154
155
156
157
158
	/* Locked by task event serialization. */
	unsigned int			magic;
	fetchctx_t *			fctx;
	isc_mem_t *			mctx;
	dns_dispatchmgr_t *		dispatchmgr;
	dns_dispatch_t *		dispatch;
159
	isc_boolean_t			exclusivesocket;
Mark Andrews's avatar
Mark Andrews committed
160
161
162
163
164
165
166
167
168
	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;
169
	isc_socketevent_t		sendevent;
Evan Hunt's avatar
Evan Hunt committed
170
	isc_dscp_t			dscp;
171
	int 				ednsversion;
Mark Andrews's avatar
Mark Andrews committed
172
173
174
175
	unsigned int			options;
	unsigned int			attributes;
	unsigned int			sends;
	unsigned int			connects;
176
	unsigned int			udpsize;
Mark Andrews's avatar
Mark Andrews committed
177
	unsigned char			data[512];
Bob Halley's avatar
Bob Halley committed
178
179
} resquery_t;

180
181
182
183
184
185
struct tried {
	isc_sockaddr_t			addr;
	unsigned int			count;
	ISC_LINK(struct tried)		link;
};

Mark Andrews's avatar
Mark Andrews committed
186
187
#define QUERY_MAGIC			ISC_MAGIC('Q', '!', '!', '!')
#define VALID_QUERY(query)		ISC_MAGIC_VALID(query, QUERY_MAGIC)
Bob Halley's avatar
Bob Halley committed
188

189
#define RESQUERY_ATTR_CANCELED          0x02
190

191
192
#define RESQUERY_CONNECTING(q)          ((q)->connects > 0)
#define RESQUERY_CANCELED(q)            (((q)->attributes & \
Mark Andrews's avatar
Mark Andrews committed
193
					  RESQUERY_ATTR_CANCELED) != 0)
194
#define RESQUERY_SENDING(q)             ((q)->sends > 0)
195

Bob Halley's avatar
Bob Halley committed
196
typedef enum {
Mark Andrews's avatar
Mark Andrews committed
197
198
199
	fetchstate_init = 0,            /*%< Start event has not run yet. */
	fetchstate_active,
	fetchstate_done                 /*%< FETCHDONE events posted. */
Bob Halley's avatar
Bob Halley committed
200
201
} fetchstate;

202
203
204
205
206
207
typedef enum {
	badns_unreachable = 0,
	badns_response,
	badns_validation
} badnstype_t;

Bob Halley's avatar
Bob Halley committed
208
struct fetchctx {
Mark Andrews's avatar
Mark Andrews committed
209
210
211
212
213
214
215
	/*% Not locked. */
	unsigned int			magic;
	dns_resolver_t *		res;
	dns_name_t			name;
	dns_rdatatype_t			type;
	unsigned int			options;
	unsigned int			bucketnum;
216
217
218
	char *				info;
	isc_mem_t *			mctx;

Mark Andrews's avatar
Mark Andrews committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
	/*% 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;
Evan Hunt's avatar
Evan Hunt committed
244
	dns_forwarderlist_t		forwarders;
Mark Andrews's avatar
Mark Andrews committed
245
246
	dns_fwdpolicy_t			fwdpolicy;
	isc_sockaddrlist_t		bad;
247
248
	ISC_LIST(struct tried)		edns;
	ISC_LIST(struct tried)		edns512;
249
	isc_sockaddrlist_t		bad_edns;
Mark Andrews's avatar
Mark Andrews committed
250
251
252
253
	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
254
255
	isc_boolean_t			ns_ttl_ok;
	isc_uint32_t			ns_ttl;
Mark Andrews's avatar
Mark Andrews committed
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

	/*%
	 * 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;
278

Mark Andrews's avatar
Mark Andrews committed
279
280
281
	/*%
	 * Look aside state for DS lookups.
	 */
282
	dns_name_t 			nsname;
Mark Andrews's avatar
Mark Andrews committed
283
284
285
286
287
288
289
	dns_fetch_t *			nsfetch;
	dns_rdataset_t			nsrrset;

	/*%
	 * Number of queries that reference this context.
	 */
	unsigned int			nqueries;
290
291
292
293
294
295

	/*%
	 * The reason to print when logging a successful
	 * response to a query.
	 */
	const char *			reason;
Evan Hunt's avatar
Evan Hunt committed
296
297
298
299
300
301

	/*%
	 * Random numbers to use for mixing up server addresses.
	 */
	isc_uint32_t                    rand_buf;
	isc_uint32_t                    rand_bits;
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319

	/*%
	 * 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;
320
	isc_boolean_t			timeout;
321
322
	dns_adbaddrinfo_t 		*addrinfo;
	isc_sockaddr_t			*client;
Bob Halley's avatar
Bob Halley committed
323
};
Bob Halley's avatar
Bob Halley committed
324

Mark Andrews's avatar
Mark Andrews committed
325
326
#define FCTX_MAGIC			ISC_MAGIC('F', '!', '!', '!')
#define VALID_FCTX(fctx)		ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
327
328
329
330
331
332
333
334
335
336
337
338

#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
339
				 0)
340
#define GLUING(f)               (((f)->attributes & FCTX_ATTR_GLUING) != \
Mark Andrews's avatar
Mark Andrews committed
341
				 0)
342
#define ADDRWAIT(f)             (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
Mark Andrews's avatar
Mark Andrews committed
343
				 0)
344
#define SHUTTINGDOWN(f)         (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
Mark Andrews's avatar
Mark Andrews committed
345
				 != 0)
346
347
348
349
350
#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
351

352
typedef struct {
Mark Andrews's avatar
Mark Andrews committed
353
354
	dns_adbaddrinfo_t *		addrinfo;
	fetchctx_t *			fctx;
355
356
} dns_valarg_t;

Bob Halley's avatar
Bob Halley committed
357
struct dns_fetch {
Mark Andrews's avatar
Mark Andrews committed
358
	unsigned int			magic;
359
	isc_mem_t *			mctx;
Mark Andrews's avatar
Mark Andrews committed
360
	fetchctx_t *			private;
Bob Halley's avatar
Bob Halley committed
361
362
};

Mark Andrews's avatar
Mark Andrews committed
363
364
#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
365
366

typedef struct fctxbucket {
Mark Andrews's avatar
Mark Andrews committed
367
368
369
370
371
	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
372
373
} fctxbucket_t;

374
typedef struct alternate {
Mark Andrews's avatar
Mark Andrews committed
375
376
377
378
379
380
381
382
383
	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;
384
385
} alternate_t;

386
387
388
389
390
391
392
393
394
395
396
397
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
398
struct dns_resolver {
Mark Andrews's avatar
Mark Andrews committed
399
400
401
402
403
404
405
406
407
408
409
410
411
412
	/* 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;
413
	dns_dispatchset_t *		dispatches4;
414
	isc_boolean_t			exclusivev4;
415
	dns_dispatchset_t *		dispatches6;
Evan Hunt's avatar
Evan Hunt committed
416
417
	isc_dscp_t			querydscp4;
	isc_dscp_t			querydscp6;
418
	isc_boolean_t			exclusivev6;
Mark Andrews's avatar
Mark Andrews committed
419
420
421
422
423
	unsigned int			nbuckets;
	fctxbucket_t *			buckets;
	isc_uint32_t			lame_ttl;
	ISC_LIST(alternate_t)		alternates;
	isc_uint16_t			udpsize;
424
#if USE_ALGLOCK
Mark Andrews's avatar
Mark Andrews committed
425
	isc_rwlock_t			alglock;
426
#endif
Mark Andrews's avatar
Mark Andrews committed
427
	dns_rbt_t *			algorithms;
428
	dns_rbt_t *			digests;
429
#if USE_MBSLOCK
Mark Andrews's avatar
Mark Andrews committed
430
	isc_rwlock_t			mbslock;
431
#endif
Mark Andrews's avatar
Mark Andrews committed
432
433
434
435
436
	dns_rbt_t *			mustbesecure;
	unsigned int			spillatmax;
	unsigned int			spillatmin;
	isc_timer_t *			spillattimer;
	isc_boolean_t			zero_no_soa_ttl;
437
	unsigned int			query_timeout;
438

Mark Andrews's avatar
Mark Andrews committed
439
440
441
442
443
444
445
	/* 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 */
446
447
448
449
450
451
452

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

Mark Andrews's avatar
Mark Andrews committed
453
454
455
456
	/* Locked by primelock. */
	dns_fetch_t *			primefetch;
	/* Locked by nlock. */
	unsigned int			nfctx;
Bob Halley's avatar
Bob Halley committed
457
458
};

Mark Andrews's avatar
Mark Andrews committed
459
460
#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
461

462
/*%
463
464
 * Private addrinfo flags.  These must not conflict with DNS_FETCHOPT_NOEDNS0
 * (0x008) which we also use as an addrinfo flag.
465
 */
466
467
#define FCTX_ADDRINFO_MARK              0x0001
#define FCTX_ADDRINFO_FORWARDER         0x1000
Evan Hunt's avatar
Evan Hunt committed
468
#define FCTX_ADDRINFO_TRIED             0x2000
469
#define FCTX_ADDRINFO_EDNSOK            0x4000
470
#define FCTX_ADDRINFO_NOSIT             0x8000
471

472
#define UNMARKED(a)                     (((a)->flags & FCTX_ADDRINFO_MARK) \
Mark Andrews's avatar
Mark Andrews committed
473
					 == 0)
474
#define ISFORWARDER(a)                  (((a)->flags & \
Mark Andrews's avatar
Mark Andrews committed
475
					 FCTX_ADDRINFO_FORWARDER) != 0)
Evan Hunt's avatar
Evan Hunt committed
476
477
#define TRIED(a)                        (((a)->flags & \
					 FCTX_ADDRINFO_TRIED) != 0)
478
479
#define NOSIT(a)                        (((a)->flags & \
					 FCTX_ADDRINFO_NOSIT) != 0)
480
481
482
#define EDNSOK(a)                       (((a)->flags & \
					 FCTX_ADDRINFO_EDNSOK) != 0)

Bob Halley's avatar
Bob Halley committed
483

484
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
485
#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
486

Bob Halley's avatar
Bob Halley committed
487
static void destroy(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
488
static void empty_bucket(dns_resolver_t *res);
Bob Halley's avatar
Bob Halley committed
489
static isc_result_t resquery_send(resquery_t *query);
Bob Halley's avatar
Bob Halley committed
490
static void resquery_response(isc_task_t *task, isc_event_t *event);
Bob Halley's avatar
Bob Halley committed
491
static void resquery_connected(isc_task_t *task, isc_event_t *event);
492
493
static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying,
		     isc_boolean_t badcache);
494
495
static void fctx_destroy(fetchctx_t *fctx);
static isc_boolean_t fctx_unlink(fetchctx_t *fctx);
496
static isc_result_t ncache_adderesult(dns_message_t *message,
Mark Andrews's avatar
Mark Andrews committed
497
498
499
				      dns_db_t *cache, dns_dbnode_t *node,
				      dns_rdatatype_t covers,
				      isc_stdtime_t now, dns_ttl_t maxttl,
500
				      isc_boolean_t optout,
501
				      isc_boolean_t secure,
Mark Andrews's avatar
Mark Andrews committed
502
503
				      dns_rdataset_t *ardataset,
				      isc_result_t *eresultp);
504
static void validated(isc_task_t *task, isc_event_t *event);
505
static isc_boolean_t maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked);
506
static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
507
		    isc_result_t reason, badnstype_t badtype);
508
509
510
static inline isc_result_t findnoqname(fetchctx_t *fctx, dns_name_t *name,
				       dns_rdatatype_t type,
				       dns_name_t **noqname);
511

512
513
514
515
/*%
 * Increment resolver-related statistics counters.
 */
static inline void
516
inc_stats(dns_resolver_t *res, isc_statscounter_t counter) {
517
	if (res->view->resstats != NULL)
518
		isc_stats_increment(res->view->resstats, counter);
519
520
}

521
522
523
524
525
526
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);
}

527
528
static isc_result_t
valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
Mark Andrews's avatar
Mark Andrews committed
529
530
531
	  dns_rdatatype_t type, dns_rdataset_t *rdataset,
	  dns_rdataset_t *sigrdataset, unsigned int valoptions,
	  isc_task_t *task)
532
{
Mark Andrews's avatar
Mark Andrews committed
533
534
535
536
	dns_validator_t *validator = NULL;
	dns_valarg_t *valarg;
	isc_result_t result;

537
	valarg = isc_mem_get(fctx->mctx, sizeof(*valarg));
Mark Andrews's avatar
Mark Andrews committed
538
539
540
541
542
543
544
545
546
547
548
549
550
551
	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) {
552
		inc_stats(fctx->res, dns_resstatscounter_val);
Mark Andrews's avatar
Mark Andrews committed
553
554
		if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
			INSIST(fctx->validator == NULL);
555
			fctx->validator = validator;
Mark Andrews's avatar
Mark Andrews committed
556
557
558
		}
		ISC_LIST_APPEND(fctx->validators, validator, link);
	} else
559
		isc_mem_put(fctx->mctx, valarg, sizeof(*valarg));
Mark Andrews's avatar
Mark Andrews committed
560
	return (result);
561
}
Bob Halley's avatar
Bob Halley committed
562

563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
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
579
						&order, &labels);
580
581
582
583
584
585
586
		if (namereln == dns_namereln_subdomain)
			return (ISC_TRUE);
		dns_rdata_reset(&rdata);
	}
	return (ISC_FALSE);
}

587
static isc_boolean_t
588
fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
589
590
591
592
593
594
595
596
597
598
599
	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);

	/*
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
	 * 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
628
	 */
629

Mark Andrews's avatar
Mark Andrews committed
630
631
	if (message->counts[DNS_SECTION_ANSWER] != 0 &&
	    (fctx->type == dns_rdatatype_ns ||
632
633
634
635
636
	     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
637
638
639
640
641
642
643
644
		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
645
				if (!dns_name_equal(name, &fctx->name))
Mark Andrews's avatar
Mark Andrews committed
646
					continue;
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
				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
671
672
673
674
675
676
677
					return (ISC_FALSE);
			}
			result = dns_message_nextname(message,
						      DNS_SECTION_ANSWER);
		}
	}

678
679
680
681
682
683
684
685
	/*
	 * 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
686
687
688
689
690
691
692
693
694
695
696
697
698
699
	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;
700

Mark Andrews's avatar
Mark Andrews committed
701
			if (type != dns_rdatatype_ns &&
702
703
			    type != dns_rdatatype_soa &&
			    type != dns_rdatatype_rrsig)
Mark Andrews's avatar
Mark Andrews committed
704
				continue;
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728

			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
729
				return (ISC_FALSE);
730
			}
Mark Andrews's avatar
Mark Andrews committed
731
732
733
		}
		result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
	}
734
735

 munge:
Mark Andrews's avatar
Mark Andrews committed
736
737
738
739
740
741
	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);
742
743
}

Bob Halley's avatar
Bob Halley committed
744
static inline isc_result_t
Bob Halley's avatar
Bob Halley committed
745
fctx_starttimer(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
746
747
748
749
750
751
752
753
754
	/*
	 * 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
755
756
}

Bob Halley's avatar
Bob Halley committed
757
758
static inline void
fctx_stoptimer(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
	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
774
775
}

776
777

static inline isc_result_t
778
fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) {
Mark Andrews's avatar
Mark Andrews committed
779
780
781
782
783
	/*
	 * Start the idle timer for fctx.  The lifetime timer continues
	 * to be in effect.
	 */
	return (isc_timer_reset(fctx->timer, isc_timertype_once,
784
				&fctx->expires, interval, ISC_FALSE));
785
786
787
788
789
790
}

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


794
795
static inline void
resquery_destroy(resquery_t **queryp) {
Mark Andrews's avatar
Mark Andrews committed
796
	resquery_t *query;
797

Mark Andrews's avatar
Mark Andrews committed
798
799
800
	REQUIRE(queryp != NULL);
	query = *queryp;
	REQUIRE(!ISC_LINK_LINKED(query, link));
801

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

Mark Andrews's avatar
Mark Andrews committed
804
	query->fctx->nqueries--;
805
806
807
808
809
	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
810
811
812
	query->magic = 0;
	isc_mem_put(query->mctx, query, sizeof(*query));
	*queryp = NULL;
813
814
}

Bob Halley's avatar
Bob Halley committed
815
static void
Bob Halley's avatar
Bob Halley committed
816
fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
Mark Andrews's avatar
Mark Andrews committed
817
		 isc_time_t *finish, isc_boolean_t no_response)
Bob Halley's avatar
Bob Halley committed
818
{
819
	char addrbuf[ISC_SOCKADDR_FORMATSIZE];
Mark Andrews's avatar
Mark Andrews committed
820
821
	fetchctx_t *fctx;
	resquery_t *query;
822
	unsigned int rtt, rttms;
Mark Andrews's avatar
Mark Andrews committed
823
824
825
	unsigned int factor;
	dns_adbfind_t *find;
	dns_adbaddrinfo_t *addrinfo;
826
	isc_socket_t *socket;
827
	isc_stdtime_t now;
Mark Andrews's avatar
Mark Andrews committed
828
829
830
831
832
833
834
835
836
837

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

	FCTXTRACE("cancelquery");

	REQUIRE(!RESQUERY_CANCELED(query));

	query->attributes |= RESQUERY_ATTR_CANCELED;

838
839
840
	isc_sockaddr_format(&query->addrinfo->sockaddr,
			    addrbuf, sizeof(addrbuf));

Mark Andrews's avatar
Mark Andrews committed
841
842
843
844
845
846
847
848
849
850
851
852
	/*
	 * 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;
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873

			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);
			}
Tinderbox User's avatar
Tinderbox User committed
874
		} else {
875
876
			isc_uint32_t value;
			isc_uint32_t mask;
Mark Andrews's avatar
Mark Andrews committed
877
878
879
880
881
882
			/*
			 * 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);
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
			isc_random_get(&value);
			if (query->addrinfo->srtt > 800000)
				mask = 0x3fff;
			else if (query->addrinfo->srtt > 400000)
				mask = 0x7fff;
			else if (query->addrinfo->srtt > 200000)
				mask = 0xffff;
			else if (query->addrinfo->srtt > 100000)
				mask = 0x1ffff;
			else if (query->addrinfo->srtt > 50000)
				mask = 0x3ffff;
			else if (query->addrinfo->srtt > 25000)
				mask = 0x7ffff;
			else
				mask = 0xfffff;
			if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
				dns_adb_ednsto(fctx->adb, query->addrinfo,
					       query->udpsize);
			else
				dns_adb_timeout(fctx->adb, query->addrinfo);

			/*
			 * Don't adjust timeout on EDNS queries unless we have
			 * seen a EDNS response.
			 */
			if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
Mark Andrews's avatar
Mark Andrews committed
909
			    !EDNSOK(query->addrinfo)) {
910
911
912
				mask >>= 2;
			}
			rtt = query->addrinfo->srtt + (value & mask);
913
914
			if (rtt > MAX_SINGLE_QUERY_TIMEOUT_US)
				rtt = MAX_SINGLE_QUERY_TIMEOUT_US;
Mark Andrews's avatar
Mark Andrews committed
915
916
917
918
919
920
921
922
			/*
			 * 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
923
924
925
926
927
928
	/* 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
929
930
931
	/*
	 * Age RTTs of servers not tried.
	 */
932
	isc_stdtime_get(&now);
Mark Andrews's avatar
Mark Andrews committed
933
934
935
936
937
	if (finish != NULL)
		for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
		     addrinfo != NULL;
		     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
			if (UNMARKED(addrinfo))
938
				dns_adb_agesrtt(fctx->adb, addrinfo, now);
Mark Andrews's avatar
Mark Andrews committed
939
940
941
942
943
944
945
946
947

	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))
948
949
					dns_adb_agesrtt(fctx->adb, addrinfo,
							now);
Mark Andrews's avatar
Mark Andrews committed
950
951
952
953
954
955

	if (finish != NULL && TRIEDALT(fctx)) {
		for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
		     addrinfo != NULL;
		     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
			if (UNMARKED(addrinfo))
956
				dns_adb_agesrtt(fctx->adb, addrinfo, now);
Mark Andrews's avatar
Mark Andrews committed
957
958
959
960
961
962
963
		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))
964
965
					dns_adb_agesrtt(fctx->adb, addrinfo,
							now);
Mark Andrews's avatar
Mark Andrews committed
966
967
968
969
970
971
972
973
	}

	/*
	 * 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.
	 */
974
	if (RESQUERY_CONNECTING(query)) {
Mark Andrews's avatar
Mark Andrews committed
975
976
977
		/*
		 * Cancel the connect.
		 */
978
979
980
981
982
983
984
985
986
987
988
		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
989
990
991
		/*
		 * Cancel the pending send.
		 */
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
		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
1010
1011
1012
1013
1014
1015
1016
1017
1018

	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
1019
1020
1021
}

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

Mark Andrews's avatar
Mark Andrews committed
1025
	FCTXTRACE("cancelqueries");
Bob Halley's avatar
Bob Halley committed
1026

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

Bob Halley's avatar
Bob Halley committed
1035
static void
Bob Halley's avatar
Bob Halley committed
1036
fctx_cleanupfinds(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
	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
1049
1050
}

1051
1052
static void
fctx_cleanupaltfinds(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
	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;
1065
1066
}

1067
1068
static void
fctx_cleanupforwaddrs(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
1069
	dns_adbaddrinfo_t *addr, *next_addr;
1070

Mark Andrews's avatar
Mark Andrews committed
1071
	REQUIRE(ISC_LIST_EMPTY(fctx->queries));
1072

Mark Andrews's avatar
Mark Andrews committed
1073
1074
1075
1076
1077
1078
1079
	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);
	}
1080
1081
}

1082
1083
static void
fctx_cleanupaltaddrs(fetchctx_t *fctx) {
Mark Andrews's avatar
Mark Andrews committed
1084
	dns_adbaddrinfo_t *addr, *next_addr;
1085

Mark Andrews's avatar
Mark Andrews committed
1086
	REQUIRE(ISC_LIST_EMPTY(fctx->queries));
1087

Mark Andrews's avatar
Mark Andrews committed
1088
1089
1090
1091
1092
1093
1094
	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);
	}
1095
1096
}

Bob Halley's avatar
Bob Halley committed
1097
static inline void
1098
fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
Mark Andrews's avatar
Mark Andrews committed
1099
1100
1101
1102
1103
1104
1105
	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
1106
}
Bob Halley's avatar
Bob Halley committed
1107

Bob Halley's avatar
Bob Halley committed
1108
static inline void
1109
fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) {
Mark Andrews's avatar
Mark Andrews committed
1110
1111
1112
1113
1114
	dns_fetchevent_t *event, *next_event;
	isc_task_t *task;
	unsigned int count = 0;
	isc_interval_t i;
	isc_boolean_t logit = ISC_FALSE;
1115
	isc_time_t now;
1116
	unsigned int old_spillat;
Automatic Updater's avatar
Automatic Updater committed
1117
	unsigned int new_spillat = 0;	/* initialized to silence
1118
					   compiler warnings */
1119

Mark Andrews's avatar
Mark Andrews committed
1120
1121
1122
1123
1124
1125
1126
	/*
	 * Caller must be holding the appropriate bucket lock.
	 */
	REQUIRE(fctx->state == fetchstate_done);

	FCTXTRACE("sendevents");

1127
	/*
Automatic Updater's avatar
Automatic Updater committed
1128
	 * Keep some record of fetch result for logging later (if required).
1129
1130
1131
1132
1133
1134
	 */
	fctx->result = result;
	fctx->exitline = line;
	TIME_NOW(&now);
	fctx->duration = isc_time_microdiff(&now, &fctx->start);

Mark Andrews's avatar
Mark Andrews committed
1135
1136
1137
1138
1139
1140
1141
	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;
1142
		event->vresult = fctx->vresult;
Mark Andrews's avatar
Mark Andrews committed
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
		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) &&
1156
		    NEGATIVE(event->rdataset)) {
Mark Andrews's avatar
Mark Andrews committed
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
			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) {
1170
			old_spillat = fctx->res->spillat;
Mark Andrews's avatar
Mark Andrews committed
1171
1172
1173
1174
			fctx->res->spillat += 5;
			if (fctx->res->spillat > fctx->res->spillatmax &&
			    fctx->res->spillatmax != 0)
				fctx->res->spillat = fctx->res->spillatmax;
1175
1176
			new_spillat = fctx->res->spillat;
			if (new_spillat != old_spillat) {
Mark Andrews's avatar
Mark Andrews committed
1177
				logit = ISC_TRUE;
1178
			}
Mark Andrews's avatar
Mark Andrews committed
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
			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
1192
}
Bob Halley's avatar
Bob Halley committed
1193

1194
1195
1196
1197
1198
1199
1200
static inline void
log_edns(fetchctx_t *fctx) {
	char domainbuf[DNS_NAME_FORMATSIZE];

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

Mark Andrews's avatar
Mark Andrews committed
1201
1202
1203
1204
	/*
	 * We do not know if fctx->domain is the actual domain the record
	 * lives in or a parent domain so we have a '?' after it.
	 */
1205
1206
1207
1208
1209
1210
1211
1212
1213
	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
1214
static void
1215
fctx_done(fetchctx_t *fctx, isc_result_t result, int line) {
Mark Andrews's avatar
Mark Andrews committed
1216
1217
	dns_resolver_t *res;
	isc_boolean_t no_response;
Bob Halley's avatar
Bob Halley committed
1218

1219
1220
	REQUIRE(line >= 0);

Mark Andrews's avatar
Mark Andrews committed
1221
	FCTXTRACE("done");
Bob Halley's avatar
Bob Halley committed
1222

Mark Andrews's avatar
Mark Andrews committed
1223
	res = fctx->res;
Bob Halley's avatar
Bob Halley committed
1224

1225
1226
1227
1228
1229
	if (result == ISC_R_SUCCESS) {
		/*%
		 * Log any deferred EDNS timeout messages.
		 */
		log_edns(fctx);
Mark Andrews's avatar
Mark Andrews committed
1230
		no_response = ISC_TRUE;
1231
	 } else
Mark Andrews's avatar
Mark Andrews committed
1232
		no_response = ISC_FALSE;
1233
1234

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

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

Mark Andrews's avatar
Mark Andrews committed
1239
1240
	fctx->state = fetchstate_done;
	fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
1241
	fctx_sendevents(fctx, result, line);
Bob Halley's avatar
Bob Halley committed
1242

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

Bob Halley's avatar
Bob Halley committed
1246
static void
1247
process_sendevent(resquery_t *query, isc_event_t *event) {
Mark Andrews's avatar
Mark Andrews committed
1248
1249
1250
1251
1252
1253
1254
1255
	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)) {
1256
		if (query->sends == 0 && query->connects == 0) {
Mark Andrews's avatar
Mark Andrews committed
1257
1258
			/*
			 * This query was canceled while the
1259
			 * isc_socket_sendto/connect() was in progress.
Mark Andrews's avatar
Mark Andrews committed
1260
1261
1262
1263
1264
			 */
			if (query->tcpsocket != NULL)
				isc_socket_detach(&query->tcpsocket);
			resquery_destroy(&query);
		}
1265
	} else {
Mark Andrews's avatar
Mark Andrews committed
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
		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.
			 */
1279
1280
			add_bad(fctx, query->addrinfo, sevent->result,
				badns_unreachable);
Mark Andrews's avatar
Mark Andrews committed
1281
1282
1283
1284
1285
1286
1287
1288
			fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
			retry = ISC_TRUE;
			break;

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

1291
1292
	if (event->ev_type == ISC_SOCKEVENT_CONNECT)
		isc_event_free(&event);
Mark Andrews's avatar
Mark Andrews committed
1293
1294
1295
1296
1297
1298
1299
1300
1301

	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)
1302
			fctx_done(fctx, result, __LINE__);
Mark Andrews's avatar
Mark Andrews committed
1303
		else
1304
			fctx_try(fctx, ISC_TRUE, ISC_FALSE);
Mark Andrews's avatar
Mark Andrews committed
1305
	}
Bob Halley's avatar
Bob Halley committed
1306
1307
}

1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
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
1350
static inline isc_result_t
1351
fctx_addopt(dns_message_t *message, unsigned int version,
1352
	    isc_uint16_t udpsize, dns_ednsopt_t *ednsopts, size_t count)
1353
{
1354
	dns_rdataset_t *rdataset = NULL;
Mark Andrews's avatar
Mark Andrews committed
1355
1356
	isc_result_t result;

1357
1358
	result = dns_message_buildopt(message, &rdataset, version, udpsize,
				      DNS_MESSAGEEXTFLAG_DO, ednsopts, count);
Mark Andrews's avatar
Mark Andrews committed
1359
1360
1361
	if (result != ISC_R_SUCCESS)
		return (result);
	return (dns_message_setopt(message, rdataset));
Bob Halley's avatar
Bob Halley committed
1362
1363
}

1364
1365
static inline void
fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
Mark Andrews's avatar
Mark Andrews committed
1366
1367
1368
1369
	unsigned int seconds;
	unsigned int us;

	/*
1370
	 * We retry every .8 seconds the first two times through the address
Mark Andrews's avatar
Mark Andrews committed
1371
1372
	 * list, and then we do exponential back-off.
	 */
Evan Hunt's avatar
Evan Hunt committed
1373
	if (fctx->restarts < 3)
1374
		us = 800000;
Mark Andrews's avatar
Mark Andrews committed
1375
	else
1376
		us = (800000 << (fctx->restarts - 2));
Mark Andrews's avatar
Mark Andrews committed
1377
1378

	/*
1379
1380
	 * Add a fudge factor to the expected rtt based on the current
	 * estimate.
Mark Andrews's avatar
Mark Andrews committed
1381
	 */
1382
1383
1384
1385
1386
1387
	if (rtt < 50000)
		rtt += 50000;
	else if (rtt < 100000)
		rtt += 100000;
	else
		rtt += 200000;
Mark Andrews's avatar
Mark Andrews committed
1388
1389

	/*
1390
	 * Always wait for at least the expected rtt.
Mark Andrews's avatar
Mark Andrews committed
1391
1392
1393
1394
1395
1396
1397
	 */
	if (us < rtt)
		us = rtt;

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