|
1 This patch was obtained from ISC for 9.6-ESV-R11-P1. The patch can |
|
2 only be obtained from [email protected] on an as needed |
|
3 basis. |
|
4 |
|
5 diff --git a/CHANGES b/CHANGES |
|
6 index 178f73d..8ace4fb 100644 |
|
7 --- a/CHANGES |
|
8 +++ b/CHANGES |
|
9 @@ -1,3 +1,17 @@ |
|
10 + --- 9.6-ESV-R11-P1 released --- |
|
11 + |
|
12 +4006. [security] A flaw in delegation handling could be exploited |
|
13 + to put named into an infinite loop. This has |
|
14 + been addressed by placing limits on the number |
|
15 + of levels of recursion named will allow (default 7), |
|
16 + and the number of iterative queries that it will |
|
17 + send (default 50) before terminating a recursive |
|
18 + query (CVE-2014-8500). |
|
19 + |
|
20 + The recursion depth limit is configured via the |
|
21 + "max-recursion-depth" option, and the query limit |
|
22 + via the "max-recursion-queries" option. [RT #37580] |
|
23 + |
|
24 --- 9.6-ESV-R11 released --- |
|
25 |
|
26 --- 9.6-ESV-R11rc2 released --- |
|
27 diff --git a/bin/named/config.c b/bin/named/config.c |
|
28 index d85afa7..823d101 100644 |
|
29 --- a/bin/named/config.c |
|
30 +++ b/bin/named/config.c |
|
31 @@ -15,8 +15,6 @@ |
|
32 * PERFORMANCE OF THIS SOFTWARE. |
|
33 */ |
|
34 |
|
35 -/* $Id$ */ |
|
36 - |
|
37 /*! \file */ |
|
38 |
|
39 #include <config.h> |
|
40 @@ -145,6 +143,8 @@ options {\n\ |
|
41 dnssec-accept-expired no;\n\ |
|
42 clients-per-query 10;\n\ |
|
43 max-clients-per-query 100;\n\ |
|
44 + max-recursion-depth 7;\n\ |
|
45 + max-recursion-queries 50;\n\ |
|
46 zero-no-soa-ttl-cache no;\n\ |
|
47 nsec3-test-zone no;\n\ |
|
48 " |
|
49 diff --git a/bin/named/include/named/query.h b/bin/named/include/named/query.h |
|
50 index 20aff40..771345e 100644 |
|
51 --- a/bin/named/include/named/query.h |
|
52 +++ b/bin/named/include/named/query.h |
|
53 @@ -1,5 +1,5 @@ |
|
54 /* |
|
55 - * Copyright (C) 2004, 2005, 2007, 2010, 2012 Internet Systems Consortium, Inc. ("ISC") |
|
56 + * Copyright (C) 2004, 2005, 2007, 2010, 2011, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") |
|
57 * Copyright (C) 1999-2002 Internet Software Consortium. |
|
58 * |
|
59 * Permission to use, copy, modify, and/or distribute this software for any |
|
60 @@ -15,8 +15,6 @@ |
|
61 * PERFORMANCE OF THIS SOFTWARE. |
|
62 */ |
|
63 |
|
64 -/* $Id$ */ |
|
65 - |
|
66 #ifndef NAMED_QUERY_H |
|
67 #define NAMED_QUERY_H 1 |
|
68 |
|
69 diff --git a/bin/named/query.c b/bin/named/query.c |
|
70 index 10a7d9a..48e4822 100644 |
|
71 --- a/bin/named/query.c |
|
72 +++ b/bin/named/query.c |
|
73 @@ -3343,13 +3343,12 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, |
|
74 peeraddr = &client->peeraddr; |
|
75 else |
|
76 peeraddr = NULL; |
|
77 - result = dns_resolver_createfetch2(client->view->resolver, |
|
78 + result = dns_resolver_createfetch3(client->view->resolver, |
|
79 client->query.qname, |
|
80 qtype, qdomain, nameservers, |
|
81 NULL, peeraddr, client->message->id, |
|
82 - client->query.fetchoptions, |
|
83 - client->task, |
|
84 - query_resume, client, |
|
85 + client->query.fetchoptions, 0, NULL, |
|
86 + client->task, query_resume, client, |
|
87 rdataset, sigrdataset, |
|
88 &client->query.fetch); |
|
89 |
|
90 diff --git a/bin/named/server.c b/bin/named/server.c |
|
91 index af53b48..4d48074 100644 |
|
92 --- a/bin/named/server.c |
|
93 +++ b/bin/named/server.c |
|
94 @@ -15,8 +15,6 @@ |
|
95 * PERFORMANCE OF THIS SOFTWARE. |
|
96 */ |
|
97 |
|
98 -/* $Id$ */ |
|
99 - |
|
100 /*! \file */ |
|
101 |
|
102 #include <config.h> |
|
103 @@ -2048,6 +2046,16 @@ configure_view(dns_view_t *view, const cfg_obj_t *config, |
|
104 max_clients_per_query); |
|
105 |
|
106 obj = NULL; |
|
107 + result = ns_config_get(maps, "max-recursion-depth", &obj); |
|
108 + INSIST(result == ISC_R_SUCCESS); |
|
109 + dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj)); |
|
110 + |
|
111 + obj = NULL; |
|
112 + result = ns_config_get(maps, "max-recursion-queries", &obj); |
|
113 + INSIST(result == ISC_R_SUCCESS); |
|
114 + dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj)); |
|
115 + |
|
116 + obj = NULL; |
|
117 result = ns_config_get(maps, "dnssec-enable", &obj); |
|
118 INSIST(result == ISC_R_SUCCESS); |
|
119 view->enablednssec = cfg_obj_asboolean(obj); |
|
120 diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml |
|
121 index f894aab..b823dc4 100644 |
|
122 --- a/doc/arm/Bv9ARM-book.xml |
|
123 +++ b/doc/arm/Bv9ARM-book.xml |
|
124 @@ -4652,6 +4652,8 @@ category notify { null; }; |
|
125 <optional> max-acache-size <replaceable>size_spec</replaceable> ; </optional> |
|
126 <optional> clients-per-query <replaceable>number</replaceable> ; </optional> |
|
127 <optional> max-clients-per-query <replaceable>number</replaceable> ; </optional> |
|
128 + <optional> max-recursion-depth <replaceable>number</replaceable> ; </optional> |
|
129 + <optional> max-recursion-queries <replaceable>number</replaceable> ; </optional> |
|
130 <optional> masterfile-format (<constant>text</constant>|<constant>raw</constant>) ; </optional> |
|
131 <optional> empty-server <replaceable>name</replaceable> ; </optional> |
|
132 <optional> empty-contact <replaceable>name</replaceable> ; </optional> |
|
133 @@ -4729,6 +4731,35 @@ category notify { null; }; |
|
134 </listitem> |
|
135 </varlistentry> |
|
136 |
|
137 + <varlistentry id="max-recursion-depth"> |
|
138 + <term><command>max-recursion-depth</command></term> |
|
139 + <listitem> |
|
140 + <para> |
|
141 + Sets the maximum number of levels of recursion |
|
142 + that are permitted at any one time while servicing |
|
143 + a recursive query. Resolving a name may require |
|
144 + looking up a name server address, which in turn |
|
145 + requires resolving another name, etc; if the number |
|
146 + of indirections exceeds this value, the recursive |
|
147 + query is terminated and returns SERVFAIL. The |
|
148 + default is 7. |
|
149 + </para> |
|
150 + </listitem> |
|
151 + </varlistentry> |
|
152 + |
|
153 + <varlistentry id="max-recursion-queries"> |
|
154 + <term><command>max-recursion-queries</command></term> |
|
155 + <listitem> |
|
156 + <para> |
|
157 + Sets the maximum number of iterative queries that |
|
158 + may be sent while servicing a recursive query. |
|
159 + If more queries are sent, the recursive query |
|
160 + is terminated and returns SERVFAIL. The default |
|
161 + is 50. |
|
162 + </para> |
|
163 + </listitem> |
|
164 + </varlistentry> |
|
165 + |
|
166 <varlistentry> |
|
167 <term><command>tkey-gssapi-credential</command></term> |
|
168 <listitem> |
|
169 diff --git a/lib/dns/adb.c b/lib/dns/adb.c |
|
170 index 2d7b904..422e59c 100644 |
|
171 --- a/lib/dns/adb.c |
|
172 +++ b/lib/dns/adb.c |
|
173 @@ -200,6 +200,7 @@ struct dns_adbfetch { |
|
174 unsigned int magic; |
|
175 dns_fetch_t *fetch; |
|
176 dns_rdataset_t rdataset; |
|
177 + unsigned int depth; |
|
178 }; |
|
179 |
|
180 /*% |
|
181 @@ -298,8 +299,7 @@ static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t, |
|
182 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *); |
|
183 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *); |
|
184 static void clean_target(dns_adb_t *, dns_name_t *); |
|
185 -static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, |
|
186 - unsigned int); |
|
187 +static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int); |
|
188 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t); |
|
189 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **, |
|
190 isc_stdtime_t); |
|
191 @@ -307,6 +307,7 @@ static void cancel_fetches_at_name(dns_adbname_t *); |
|
192 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, |
|
193 dns_rdatatype_t); |
|
194 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, |
|
195 + unsigned int, isc_counter_t *qc, |
|
196 dns_rdatatype_t); |
|
197 static inline void check_exit(dns_adb_t *); |
|
198 static void destroy(dns_adb_t *); |
|
199 @@ -2282,6 +2283,19 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, |
|
200 isc_stdtime_t now, dns_name_t *target, |
|
201 in_port_t port, dns_adbfind_t **findp) |
|
202 { |
|
203 + return (dns_adb_createfind2(adb, task, action, arg, name, |
|
204 + qname, qtype, options, now, |
|
205 + target, port, 0, NULL, findp)); |
|
206 +} |
|
207 + |
|
208 +isc_result_t |
|
209 +dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, |
|
210 + void *arg, dns_name_t *name, dns_name_t *qname, |
|
211 + dns_rdatatype_t qtype, unsigned int options, |
|
212 + isc_stdtime_t now, dns_name_t *target, |
|
213 + in_port_t port, unsigned int depth, isc_counter_t *qc, |
|
214 + dns_adbfind_t **findp) |
|
215 +{ |
|
216 dns_adbfind_t *find; |
|
217 dns_adbname_t *adbname; |
|
218 int bucket; |
|
219 @@ -2512,7 +2526,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, |
|
220 * Start V4. |
|
221 */ |
|
222 if (WANT_INET(wanted_fetches) && |
|
223 - fetch_name(adbname, start_at_zone, |
|
224 + fetch_name(adbname, start_at_zone, depth, qc, |
|
225 dns_rdatatype_a) == ISC_R_SUCCESS) { |
|
226 DP(DEF_LEVEL, |
|
227 "dns_adb_createfind: started A fetch for name %p", |
|
228 @@ -2523,7 +2537,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, |
|
229 * Start V6. |
|
230 */ |
|
231 if (WANT_INET6(wanted_fetches) && |
|
232 - fetch_name(adbname, start_at_zone, |
|
233 + fetch_name(adbname, start_at_zone, depth, qc, |
|
234 dns_rdatatype_aaaa) == ISC_R_SUCCESS) { |
|
235 DP(DEF_LEVEL, |
|
236 "dns_adb_createfind: " |
|
237 @@ -3256,6 +3270,12 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { |
|
238 DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s", |
|
239 buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA", |
|
240 dns_result_totext(dev->result)); |
|
241 + /* |
|
242 + * Don't record a failure unless this is the initial |
|
243 + * fetch of a chain. |
|
244 + */ |
|
245 + if (fetch->depth > 1) |
|
246 + goto out; |
|
247 /* XXXMLG Don't pound on bad servers. */ |
|
248 if (address_type == DNS_ADBFIND_INET) { |
|
249 name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); |
|
250 @@ -3293,9 +3313,8 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { |
|
251 } |
|
252 |
|
253 static isc_result_t |
|
254 -fetch_name(dns_adbname_t *adbname, |
|
255 - isc_boolean_t start_at_zone, |
|
256 - dns_rdatatype_t type) |
|
257 +fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone, |
|
258 + unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type) |
|
259 { |
|
260 isc_result_t result; |
|
261 dns_adbfetch_t *fetch = NULL; |
|
262 @@ -3340,12 +3359,14 @@ fetch_name(dns_adbname_t *adbname, |
|
263 result = ISC_R_NOMEMORY; |
|
264 goto cleanup; |
|
265 } |
|
266 + fetch->depth = depth; |
|
267 |
|
268 - result = dns_resolver_createfetch(adb->view->resolver, &adbname->name, |
|
269 - type, name, nameservers, NULL, |
|
270 - options, adb->task, fetch_callback, |
|
271 - adbname, &fetch->rdataset, NULL, |
|
272 - &fetch->fetch); |
|
273 + result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name, |
|
274 + type, name, nameservers, NULL, |
|
275 + NULL, 0, options, depth, qc, |
|
276 + adb->task, fetch_callback, adbname, |
|
277 + &fetch->rdataset, NULL, |
|
278 + &fetch->fetch); |
|
279 if (result != ISC_R_SUCCESS) |
|
280 goto cleanup; |
|
281 |
|
282 diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h |
|
283 index d4d1b05..556fcc2 100644 |
|
284 --- a/lib/dns/include/dns/adb.h |
|
285 +++ b/lib/dns/include/dns/adb.h |
|
286 @@ -334,6 +334,13 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, |
|
287 dns_rdatatype_t qtype, unsigned int options, |
|
288 isc_stdtime_t now, dns_name_t *target, |
|
289 in_port_t port, dns_adbfind_t **find); |
|
290 +isc_result_t |
|
291 +dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, |
|
292 + void *arg, dns_name_t *name, dns_name_t *qname, |
|
293 + dns_rdatatype_t qtype, unsigned int options, |
|
294 + isc_stdtime_t now, dns_name_t *target, in_port_t port, |
|
295 + unsigned int depth, isc_counter_t *qc, |
|
296 + dns_adbfind_t **find); |
|
297 /*%< |
|
298 * Main interface for clients. The adb will look up the name given in |
|
299 * "name" and will build up a list of found addresses, and perhaps start |
|
300 diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h |
|
301 index d293daa..10c3a3a 100644 |
|
302 --- a/lib/dns/include/dns/resolver.h |
|
303 +++ b/lib/dns/include/dns/resolver.h |
|
304 @@ -270,6 +270,18 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, |
|
305 dns_rdataset_t *rdataset, |
|
306 dns_rdataset_t *sigrdataset, |
|
307 dns_fetch_t **fetchp); |
|
308 +isc_result_t |
|
309 +dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name, |
|
310 + dns_rdatatype_t type, |
|
311 + dns_name_t *domain, dns_rdataset_t *nameservers, |
|
312 + dns_forwarders_t *forwarders, |
|
313 + isc_sockaddr_t *client, isc_uint16_t id, |
|
314 + unsigned int options, unsigned int depth, |
|
315 + isc_counter_t *qc, isc_task_t *task, |
|
316 + isc_taskaction_t action, void *arg, |
|
317 + dns_rdataset_t *rdataset, |
|
318 + dns_rdataset_t *sigrdataset, |
|
319 + dns_fetch_t **fetchp); |
|
320 /*%< |
|
321 * Recurse to answer a question. |
|
322 * |
|
323 @@ -550,6 +562,30 @@ dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp); |
|
324 * \li resolver to be valid. |
|
325 */ |
|
326 |
|
327 +void |
|
328 +dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth); |
|
329 +unsigned int |
|
330 +dns_resolver_getmaxdepth(dns_resolver_t *resolver); |
|
331 +/*% |
|
332 + * Get and set how many NS indirections will be followed when looking for |
|
333 + * nameserver addresses. |
|
334 + * |
|
335 + * Requires: |
|
336 + * \li resolver to be valid. |
|
337 + */ |
|
338 + |
|
339 +void |
|
340 +dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries); |
|
341 +unsigned int |
|
342 +dns_resolver_getmaxqueries(dns_resolver_t *resolver); |
|
343 +/*% |
|
344 + * Get and set how many iterative queries will be allowed before |
|
345 + * terminating a recursive query. |
|
346 + * |
|
347 + * Requires: |
|
348 + * \li resolver to be valid. |
|
349 + */ |
|
350 + |
|
351 ISC_LANG_ENDDECLS |
|
352 |
|
353 #endif /* DNS_RESOLVER_H */ |
|
354 diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c |
|
355 index 7dcea6d..bd3d9fd 100644 |
|
356 --- a/lib/dns/resolver.c |
|
357 +++ b/lib/dns/resolver.c |
|
358 @@ -21,6 +21,7 @@ |
|
359 |
|
360 #include <config.h> |
|
361 |
|
362 +#include <isc/counter.h> |
|
363 #include <isc/log.h> |
|
364 #include <isc/platform.h> |
|
365 #include <isc/print.h> |
|
366 @@ -109,6 +110,16 @@ |
|
367 #define QTRACE(m) |
|
368 #endif |
|
369 |
|
370 +/* The default maximum number of recursions to follow before giving up. */ |
|
371 +#ifndef DEFAULT_RECURSION_DEPTH |
|
372 +#define DEFAULT_RECURSION_DEPTH 7 |
|
373 +#endif |
|
374 + |
|
375 +/* The default maximum number of iterative queries to allow before giving up. */ |
|
376 +#ifndef DEFAULT_MAX_QUERIES |
|
377 +#define DEFAULT_MAX_QUERIES 50 |
|
378 +#endif |
|
379 + |
|
380 /*% |
|
381 * Maximum EDNS0 input packet size. |
|
382 */ |
|
383 @@ -211,12 +222,13 @@ struct fetchctx { |
|
384 isc_sockaddrlist_t edns; |
|
385 isc_sockaddrlist_t edns512; |
|
386 isc_sockaddrlist_t bad_edns; |
|
387 - dns_validator_t *validator; |
|
388 + dns_validator_t * validator; |
|
389 ISC_LIST(dns_validator_t) validators; |
|
390 dns_db_t * cache; |
|
391 dns_adb_t * adb; |
|
392 isc_boolean_t ns_ttl_ok; |
|
393 isc_uint32_t ns_ttl; |
|
394 + isc_counter_t * qc; |
|
395 |
|
396 /*% |
|
397 * The number of events we're waiting for. |
|
398 @@ -283,6 +295,7 @@ struct fetchctx { |
|
399 unsigned int valfail; |
|
400 isc_boolean_t timeout; |
|
401 dns_adbaddrinfo_t *addrinfo; |
|
402 + unsigned int depth; |
|
403 }; |
|
404 |
|
405 #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!') |
|
406 @@ -394,6 +407,8 @@ struct dns_resolver { |
|
407 unsigned int spillatmin; |
|
408 isc_timer_t * spillattimer; |
|
409 isc_boolean_t zero_no_soa_ttl; |
|
410 + unsigned int maxdepth; |
|
411 + unsigned int maxqueries; |
|
412 |
|
413 /* Locked by lock. */ |
|
414 unsigned int references; |
|
415 @@ -1495,6 +1510,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, |
|
416 if (result != ISC_R_SUCCESS) |
|
417 goto cleanup_dispatch; |
|
418 } |
|
419 + |
|
420 fctx->querysent++; |
|
421 |
|
422 ISC_LIST_APPEND(fctx->queries, query, link); |
|
423 @@ -2146,9 +2162,9 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { |
|
424 */ |
|
425 INSIST(!SHUTTINGDOWN(fctx)); |
|
426 fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; |
|
427 - if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) |
|
428 + if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) { |
|
429 want_try = ISC_TRUE; |
|
430 - else { |
|
431 + } else { |
|
432 fctx->findfail++; |
|
433 if (fctx->pending == 0) { |
|
434 /* |
|
435 @@ -2177,7 +2193,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { |
|
436 else if (want_done) |
|
437 fctx_done(fctx, ISC_R_FAILURE, __LINE__); |
|
438 else if (destroy) { |
|
439 - fctx_destroy(fctx); |
|
440 + fctx_destroy(fctx); |
|
441 if (bucket_empty) |
|
442 empty_bucket(res); |
|
443 } |
|
444 @@ -2499,12 +2515,13 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, |
|
445 * See what we know about this address. |
|
446 */ |
|
447 find = NULL; |
|
448 - result = dns_adb_createfind(fctx->adb, |
|
449 - res->buckets[fctx->bucketnum].task, |
|
450 - fctx_finddone, fctx, name, |
|
451 - &fctx->name, fctx->type, |
|
452 - options, now, NULL, |
|
453 - res->view->dstport, &find); |
|
454 + result = dns_adb_createfind2(fctx->adb, |
|
455 + res->buckets[fctx->bucketnum].task, |
|
456 + fctx_finddone, fctx, name, |
|
457 + &fctx->name, fctx->type, |
|
458 + options, now, NULL, |
|
459 + res->view->dstport, |
|
460 + fctx->depth + 1, fctx->qc, &find); |
|
461 if (result != ISC_R_SUCCESS) { |
|
462 if (result == DNS_R_ALIAS) { |
|
463 /* |
|
464 @@ -2612,6 +2629,14 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { |
|
465 |
|
466 res = fctx->res; |
|
467 |
|
468 + if (fctx->depth > res->maxdepth) { |
|
469 + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, |
|
470 + DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), |
|
471 + "too much NS indirection resolving '%s'", |
|
472 + fctx->info); |
|
473 + return (DNS_R_SERVFAIL); |
|
474 + } |
|
475 + |
|
476 /* |
|
477 * Forwarders. |
|
478 */ |
|
479 @@ -3087,6 +3112,16 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) { |
|
480 } |
|
481 } |
|
482 |
|
483 + result = isc_counter_increment(fctx->qc); |
|
484 + if (result != ISC_R_SUCCESS) { |
|
485 + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, |
|
486 + DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), |
|
487 + "exceeded max queries resolving '%s'", |
|
488 + fctx->info); |
|
489 + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); |
|
490 + return; |
|
491 + } |
|
492 + |
|
493 result = fctx_query(fctx, addrinfo, fctx->options); |
|
494 if (result != ISC_R_SUCCESS) |
|
495 fctx_done(fctx, result, __LINE__); |
|
496 @@ -3185,6 +3220,7 @@ fctx_destroy(fetchctx_t *fctx) { |
|
497 isc_mem_put(fctx->mctx, sa, sizeof(*sa)); |
|
498 } |
|
499 |
|
500 + isc_counter_detach(&fctx->qc); |
|
501 isc_timer_detach(&fctx->timer); |
|
502 dns_message_destroy(&fctx->rmessage); |
|
503 dns_message_destroy(&fctx->qmessage); |
|
504 @@ -3512,7 +3548,8 @@ log_ns_ttl(fetchctx_t *fctx, const char *where) { |
|
505 static isc_result_t |
|
506 fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, |
|
507 dns_name_t *domain, dns_rdataset_t *nameservers, |
|
508 - unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp) |
|
509 + unsigned int options, unsigned int bucketnum, unsigned int depth, |
|
510 + isc_counter_t *qc, fetchctx_t **fctxp) |
|
511 { |
|
512 fetchctx_t *fctx; |
|
513 isc_result_t result; |
|
514 @@ -3534,6 +3571,21 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, |
|
515 fctx = isc_mem_get(mctx, sizeof(*fctx)); |
|
516 if (fctx == NULL) |
|
517 return (ISC_R_NOMEMORY); |
|
518 + |
|
519 + fctx->qc = NULL; |
|
520 + if (qc != NULL) { |
|
521 + isc_counter_attach(qc, &fctx->qc); |
|
522 + } else { |
|
523 + result = isc_counter_create(res->mctx, |
|
524 + res->maxqueries, &fctx->qc); |
|
525 + if (result != ISC_R_SUCCESS) |
|
526 + goto cleanup_fetch; |
|
527 + } |
|
528 + |
|
529 + /* |
|
530 + * Make fctx->info point to a copy of a formatted string |
|
531 + * "name/type". |
|
532 + */ |
|
533 dns_name_format(name, buf, sizeof(buf)); |
|
534 dns_rdatatype_format(type, typebuf, sizeof(typebuf)); |
|
535 strcat(buf, "/"); /* checked */ |
|
536 @@ -3541,7 +3593,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, |
|
537 fctx->info = isc_mem_strdup(mctx, buf); |
|
538 if (fctx->info == NULL) { |
|
539 result = ISC_R_NOMEMORY; |
|
540 - goto cleanup_fetch; |
|
541 + goto cleanup_counter; |
|
542 } |
|
543 FCTXTRACE("create"); |
|
544 dns_name_init(&fctx->name, NULL); |
|
545 @@ -3564,6 +3616,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, |
|
546 fctx->state = fetchstate_init; |
|
547 fctx->want_shutdown = ISC_FALSE; |
|
548 fctx->cloned = ISC_FALSE; |
|
549 + fctx->depth = depth; |
|
550 ISC_LIST_INIT(fctx->queries); |
|
551 ISC_LIST_INIT(fctx->finds); |
|
552 ISC_LIST_INIT(fctx->altfinds); |
|
553 @@ -3768,6 +3821,9 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, |
|
554 cleanup_info: |
|
555 isc_mem_free(mctx, fctx->info); |
|
556 |
|
557 + cleanup_counter: |
|
558 + isc_counter_detach(&fctx->qc); |
|
559 + |
|
560 cleanup_fetch: |
|
561 isc_mem_put(mctx, fctx, sizeof(*fctx)); |
|
562 |
|
563 @@ -7339,6 +7395,8 @@ dns_resolver_create(dns_view_t *view, |
|
564 res->zero_no_soa_ttl = ISC_FALSE; |
|
565 res->ndisps = 0; |
|
566 res->nextdisp = 0; /* meaningless at this point, but init it */ |
|
567 + res->maxdepth = DEFAULT_RECURSION_DEPTH; |
|
568 + res->maxqueries = DEFAULT_MAX_QUERIES; |
|
569 res->nbuckets = ntasks; |
|
570 res->activebuckets = ntasks; |
|
571 res->buckets = isc_mem_get(view->mctx, |
|
572 @@ -7778,9 +7836,9 @@ dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name, |
|
573 dns_rdataset_t *sigrdataset, |
|
574 dns_fetch_t **fetchp) |
|
575 { |
|
576 - return (dns_resolver_createfetch2(res, name, type, domain, |
|
577 + return (dns_resolver_createfetch3(res, name, type, domain, |
|
578 nameservers, forwarders, NULL, 0, |
|
579 - options, task, action, arg, |
|
580 + options, 0, NULL, task, action, arg, |
|
581 rdataset, sigrdataset, fetchp)); |
|
582 } |
|
583 |
|
584 @@ -7796,6 +7854,25 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, |
|
585 dns_rdataset_t *sigrdataset, |
|
586 dns_fetch_t **fetchp) |
|
587 { |
|
588 + return (dns_resolver_createfetch3(res, name, type, domain, |
|
589 + nameservers, forwarders, client, id, |
|
590 + options, 0, NULL, task, action, arg, |
|
591 + rdataset, sigrdataset, fetchp)); |
|
592 +} |
|
593 + |
|
594 +isc_result_t |
|
595 +dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name, |
|
596 + dns_rdatatype_t type, |
|
597 + dns_name_t *domain, dns_rdataset_t *nameservers, |
|
598 + dns_forwarders_t *forwarders, |
|
599 + isc_sockaddr_t *client, dns_messageid_t id, |
|
600 + unsigned int options, unsigned int depth, |
|
601 + isc_counter_t *qc, isc_task_t *task, |
|
602 + isc_taskaction_t action, void *arg, |
|
603 + dns_rdataset_t *rdataset, |
|
604 + dns_rdataset_t *sigrdataset, |
|
605 + dns_fetch_t **fetchp) |
|
606 +{ |
|
607 dns_fetch_t *fetch; |
|
608 fetchctx_t *fctx = NULL; |
|
609 isc_result_t result = ISC_R_SUCCESS; |
|
610 @@ -7882,11 +7959,12 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, |
|
611 |
|
612 if (fctx == NULL) { |
|
613 result = fctx_create(res, name, type, domain, nameservers, |
|
614 - options, bucketnum, &fctx); |
|
615 + options, bucketnum, depth, qc, &fctx); |
|
616 if (result != ISC_R_SUCCESS) |
|
617 goto unlock; |
|
618 new_fctx = ISC_TRUE; |
|
619 - } |
|
620 + } else if (fctx->depth > depth) |
|
621 + fctx->depth = depth; |
|
622 |
|
623 result = fctx_join(fctx, task, client, id, action, arg, |
|
624 rdataset, sigrdataset, fetch); |
|
625 @@ -8637,3 +8715,27 @@ dns_resolver_getoptions(dns_resolver_t *resolver) { |
|
626 |
|
627 return (resolver->options); |
|
628 } |
|
629 + |
|
630 +void |
|
631 +dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth) { |
|
632 + REQUIRE(VALID_RESOLVER(resolver)); |
|
633 + resolver->maxdepth = maxdepth; |
|
634 +} |
|
635 + |
|
636 +unsigned int |
|
637 +dns_resolver_getmaxdepth(dns_resolver_t *resolver) { |
|
638 + REQUIRE(VALID_RESOLVER(resolver)); |
|
639 + return (resolver->maxdepth); |
|
640 +} |
|
641 + |
|
642 +void |
|
643 +dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries) { |
|
644 + REQUIRE(VALID_RESOLVER(resolver)); |
|
645 + resolver->maxqueries = queries; |
|
646 +} |
|
647 + |
|
648 +unsigned int |
|
649 +dns_resolver_getmaxqueries(dns_resolver_t *resolver) { |
|
650 + REQUIRE(VALID_RESOLVER(resolver)); |
|
651 + return (resolver->maxqueries); |
|
652 +} |
|
653 diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in |
|
654 index 0b4020b..afc19ee 100644 |
|
655 --- a/lib/isc/Makefile.in |
|
656 +++ b/lib/isc/Makefile.in |
|
657 @@ -13,8 +13,6 @@ |
|
658 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
659 # PERFORMANCE OF THIS SOFTWARE. |
|
660 |
|
661 -# $Id$ |
|
662 - |
|
663 srcdir = @srcdir@ |
|
664 VPATH = @srcdir@ |
|
665 top_srcdir = @top_srcdir@ |
|
666 @@ -53,7 +51,7 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ |
|
667 # Alphabetically |
|
668 OBJS = @ISC_EXTRA_OBJS@ \ |
|
669 assertions.@O@ base32.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \ |
|
670 - bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \ |
|
671 + bufferlist.@O@ commandline.@O@ counter.@O@ error.@O@ event.@O@ \ |
|
672 hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \ |
|
673 httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \ |
|
674 lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \ |
|
675 @@ -68,7 +66,7 @@ OBJS = @ISC_EXTRA_OBJS@ \ |
|
676 # Alphabetically |
|
677 SRCS = @ISC_EXTRA_SRCS@ \ |
|
678 assertions.c base32.c base64.c bitstring.c buffer.c \ |
|
679 - bufferlist.c commandline.c error.c event.c \ |
|
680 + bufferlist.c commandline.c counter.c error.c event.c \ |
|
681 heap.c hex.c hmacmd5.c hmacsha.c \ |
|
682 httpd.c inet_aton.c iterated_hash.c \ |
|
683 lex.c lfsr.c lib.c log.c \ |
|
684 diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in |
|
685 index 9adca3e..1cfbbd1 100644 |
|
686 --- a/lib/isc/include/isc/Makefile.in |
|
687 +++ b/lib/isc/include/isc/Makefile.in |
|
688 @@ -13,8 +13,6 @@ |
|
689 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
690 # PERFORMANCE OF THIS SOFTWARE. |
|
691 |
|
692 -# $Id$ |
|
693 - |
|
694 srcdir = @srcdir@ |
|
695 VPATH = @srcdir@ |
|
696 top_srcdir = @top_srcdir@ |
|
697 @@ -27,7 +25,7 @@ top_srcdir = @top_srcdir@ |
|
698 # install target below. |
|
699 # |
|
700 HEADERS = app.h assertions.h base64.h bitstring.h boolean.h buffer.h \ |
|
701 - bufferlist.h commandline.h entropy.h error.h event.h \ |
|
702 + bufferlist.h commandline.h counter.h entropy.h error.h event.h \ |
|
703 eventclass.h file.h formatcheck.h fsaccess.h \ |
|
704 hash.h heap.h hex.h hmacmd5.h hmacsha.h \ |
|
705 httpd.h \ |
|
706 diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h |
|
707 index 8e8b08f..a646b8b 100644 |
|
708 --- a/lib/isc/include/isc/types.h |
|
709 +++ b/lib/isc/include/isc/types.h |
|
710 @@ -45,6 +45,7 @@ typedef struct isc_buffer isc_buffer_t; /*%< Buffer */ |
|
711 typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */ |
|
712 typedef struct isc_constregion isc_constregion_t; /*%< Const region */ |
|
713 typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region */ |
|
714 +typedef struct isc_counter isc_counter_t; /*%< Counter */ |
|
715 typedef struct isc_entropy isc_entropy_t; /*%< Entropy */ |
|
716 typedef struct isc_entropysource isc_entropysource_t; /*%< Entropy Source */ |
|
717 typedef struct isc_event isc_event_t; /*%< Event */ |
|
718 diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c |
|
719 index fac2633..3023dcc 100644 |
|
720 --- a/lib/isccfg/namedconf.c |
|
721 +++ b/lib/isccfg/namedconf.c |
|
722 @@ -15,8 +15,6 @@ |
|
723 * PERFORMANCE OF THIS SOFTWARE. |
|
724 */ |
|
725 |
|
726 -/* $Id$ */ |
|
727 - |
|
728 /*! \file */ |
|
729 |
|
730 #include <config.h> |
|
731 @@ -830,6 +828,8 @@ view_clauses[] = { |
|
732 { "max-cache-ttl", &cfg_type_uint32, 0 }, |
|
733 { "max-clients-per-query", &cfg_type_uint32, 0 }, |
|
734 { "max-ncache-ttl", &cfg_type_uint32, 0 }, |
|
735 + { "max-recursion-depth", &cfg_type_uint32, 0 }, |
|
736 + { "max-recursion-queries", &cfg_type_uint32, 0 }, |
|
737 { "max-udp-size", &cfg_type_uint32, 0 }, |
|
738 { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, |
|
739 { "minimal-responses", &cfg_type_boolean, 0 }, |
|
740 diff --git a/version b/version |
|
741 index 1be3c16..2058444 100644 |
|
742 --- a/version |
|
743 +++ b/version |
|
744 @@ -10,4 +10,4 @@ MINORVER=6 |
|
745 PATCHVER= |
|
746 RELEASETYPE=-ESV |
|
747 RELEASEVER=-R11 |
|
748 -EXTENSIONS= |
|
749 +EXTENSIONS=-P1 |
|
750 diff --git a/lib/isc/counter.c b/lib/isc/counter.c |
|
751 new file mode 100644 |
|
752 index 0000000..d7d187b |
|
753 --- /dev/null |
|
754 +++ b/lib/isc/counter.c |
|
755 @@ -0,0 +1,138 @@ |
|
756 +/* |
|
757 + * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") |
|
758 + * |
|
759 + * Permission to use, copy, modify, and/or distribute this software for any |
|
760 + * purpose with or without fee is hereby granted, provided that the above |
|
761 + * copyright notice and this permission notice appear in all copies. |
|
762 + * |
|
763 + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH |
|
764 + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
|
765 + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, |
|
766 + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
|
767 + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
|
768 + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
769 + * PERFORMANCE OF THIS SOFTWARE. |
|
770 + */ |
|
771 + |
|
772 +/*! \file */ |
|
773 + |
|
774 +#include <config.h> |
|
775 + |
|
776 +#include <stddef.h> |
|
777 + |
|
778 +#include <isc/counter.h> |
|
779 +#include <isc/magic.h> |
|
780 +#include <isc/mem.h> |
|
781 +#include <isc/util.h> |
|
782 + |
|
783 +#define COUNTER_MAGIC ISC_MAGIC('C', 'n', 't', 'r') |
|
784 +#define VALID_COUNTER(r) ISC_MAGIC_VALID(r, COUNTER_MAGIC) |
|
785 + |
|
786 +struct isc_counter { |
|
787 + unsigned int magic; |
|
788 + isc_mem_t *mctx; |
|
789 + isc_mutex_t lock; |
|
790 + unsigned int references; |
|
791 + unsigned int limit; |
|
792 + unsigned int used; |
|
793 +}; |
|
794 + |
|
795 +isc_result_t |
|
796 +isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) { |
|
797 + isc_result_t result; |
|
798 + isc_counter_t *counter; |
|
799 + |
|
800 + REQUIRE(counterp != NULL && *counterp == NULL); |
|
801 + |
|
802 + counter = isc_mem_get(mctx, sizeof(*counter)); |
|
803 + if (counter == NULL) |
|
804 + return (ISC_R_NOMEMORY); |
|
805 + |
|
806 + result = isc_mutex_init(&counter->lock); |
|
807 + if (result != ISC_R_SUCCESS) { |
|
808 + isc_mem_put(mctx, counter, sizeof(*counter)); |
|
809 + return (result); |
|
810 + } |
|
811 + |
|
812 + counter->mctx = NULL; |
|
813 + isc_mem_attach(mctx, &counter->mctx); |
|
814 + |
|
815 + counter->references = 1; |
|
816 + counter->limit = limit; |
|
817 + counter->used = 0; |
|
818 + |
|
819 + counter->magic = COUNTER_MAGIC; |
|
820 + *counterp = counter; |
|
821 + return (ISC_R_SUCCESS); |
|
822 +} |
|
823 + |
|
824 +isc_result_t |
|
825 +isc_counter_increment(isc_counter_t *counter) { |
|
826 + isc_result_t result = ISC_R_SUCCESS; |
|
827 + |
|
828 + LOCK(&counter->lock); |
|
829 + counter->used++; |
|
830 + if (counter->limit != 0 && counter->used >= counter->limit) |
|
831 + result = ISC_R_QUOTA; |
|
832 + UNLOCK(&counter->lock); |
|
833 + |
|
834 + return (result); |
|
835 +} |
|
836 + |
|
837 +unsigned int |
|
838 +isc_counter_used(isc_counter_t *counter) { |
|
839 + REQUIRE(VALID_COUNTER(counter)); |
|
840 + |
|
841 + return (counter->used); |
|
842 +} |
|
843 + |
|
844 +void |
|
845 +isc_counter_setlimit(isc_counter_t *counter, int limit) { |
|
846 + REQUIRE(VALID_COUNTER(counter)); |
|
847 + |
|
848 + LOCK(&counter->lock); |
|
849 + counter->limit = limit; |
|
850 + UNLOCK(&counter->lock); |
|
851 +} |
|
852 + |
|
853 +void |
|
854 +isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) { |
|
855 + REQUIRE(VALID_COUNTER(source)); |
|
856 + REQUIRE(targetp != NULL && *targetp == NULL); |
|
857 + |
|
858 + LOCK(&source->lock); |
|
859 + source->references++; |
|
860 + INSIST(source->references > 0); |
|
861 + UNLOCK(&source->lock); |
|
862 + |
|
863 + *targetp = source; |
|
864 +} |
|
865 + |
|
866 +static void |
|
867 +destroy(isc_counter_t *counter) { |
|
868 + counter->magic = 0; |
|
869 + isc_mutex_destroy(&counter->lock); |
|
870 + isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter)); |
|
871 +} |
|
872 + |
|
873 +void |
|
874 +isc_counter_detach(isc_counter_t **counterp) { |
|
875 + isc_counter_t *counter; |
|
876 + isc_boolean_t want_destroy = ISC_FALSE; |
|
877 + |
|
878 + REQUIRE(counterp != NULL && *counterp != NULL); |
|
879 + counter = *counterp; |
|
880 + REQUIRE(VALID_COUNTER(counter)); |
|
881 + |
|
882 + *counterp = NULL; |
|
883 + |
|
884 + LOCK(&counter->lock); |
|
885 + INSIST(counter->references > 0); |
|
886 + counter->references--; |
|
887 + if (counter->references == 0) |
|
888 + want_destroy = ISC_TRUE; |
|
889 + UNLOCK(&counter->lock); |
|
890 + |
|
891 + if (want_destroy) |
|
892 + destroy(counter); |
|
893 +} |
|
894 diff --git a/lib/isc/include/isc/counter.h b/lib/isc/include/isc/counter.h |
|
895 new file mode 100644 |
|
896 index 0000000..e7ebd25 |
|
897 --- /dev/null |
|
898 +++ b/lib/isc/include/isc/counter.h |
|
899 @@ -0,0 +1,90 @@ |
|
900 +/* |
|
901 + * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") |
|
902 + * |
|
903 + * Permission to use, copy, modify, and/or distribute this software for any |
|
904 + * purpose with or without fee is hereby granted, provided that the above |
|
905 + * copyright notice and this permission notice appear in all copies. |
|
906 + * |
|
907 + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH |
|
908 + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
|
909 + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, |
|
910 + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
|
911 + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
|
912 + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
913 + * PERFORMANCE OF THIS SOFTWARE. |
|
914 + */ |
|
915 + |
|
916 +#ifndef ISC_COUNTER_H |
|
917 +#define ISC_COUNTER_H 1 |
|
918 + |
|
919 +/***** |
|
920 + ***** Module Info |
|
921 + *****/ |
|
922 + |
|
923 +/*! \file isc/counter.h |
|
924 + * |
|
925 + * \brief The isc_counter_t object is a simplified version of the |
|
926 + * isc_quota_t object; it tracks the consumption of limited |
|
927 + * resources, returning an error condition when the quota is |
|
928 + * exceeded. However, unlike isc_quota_t, attaching and detaching |
|
929 + * from a counter object does not increment or decrement the counter. |
|
930 + */ |
|
931 + |
|
932 +/*** |
|
933 + *** Imports. |
|
934 + ***/ |
|
935 + |
|
936 +#include <isc/lang.h> |
|
937 +#include <isc/mutex.h> |
|
938 +#include <isc/types.h> |
|
939 + |
|
940 +/***** |
|
941 + ***** Types. |
|
942 + *****/ |
|
943 + |
|
944 +ISC_LANG_BEGINDECLS |
|
945 + |
|
946 +isc_result_t |
|
947 +isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp); |
|
948 +/*%< |
|
949 + * Allocate and initialize a counter object. |
|
950 + */ |
|
951 + |
|
952 +isc_result_t |
|
953 +isc_counter_increment(isc_counter_t *counter); |
|
954 +/*%< |
|
955 + * Increment the counter. |
|
956 + * |
|
957 + * If the counter limit is nonzero and has been reached, then |
|
958 + * return ISC_R_QUOTA, otherwise ISC_R_SUCCESS. (The counter is |
|
959 + * incremented regardless of return value.) |
|
960 + */ |
|
961 + |
|
962 +unsigned int |
|
963 +isc_counter_used(isc_counter_t *counter); |
|
964 +/*%< |
|
965 + * Return the current counter value. |
|
966 + */ |
|
967 + |
|
968 +void |
|
969 +isc_counter_setlimit(isc_counter_t *counter, int limit); |
|
970 +/*%< |
|
971 + * Set the counter limit. |
|
972 + */ |
|
973 + |
|
974 +void |
|
975 +isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp); |
|
976 +/*%< |
|
977 + * Attach to a counter object, increasing its reference counter. |
|
978 + */ |
|
979 + |
|
980 +void |
|
981 +isc_counter_detach(isc_counter_t **counterp); |
|
982 +/*%< |
|
983 + * Detach (and destroy if reference counter has dropped to zero) |
|
984 + * a counter object. |
|
985 + */ |
|
986 + |
|
987 +ISC_LANG_ENDDECLS |
|
988 + |
|
989 +#endif /* ISC_COUNTER_H */ |
|
990 diff --git a/lib/isc/tests/counter_test.c b/lib/isc/tests/counter_test.c |
|
991 new file mode 100644 |
|
992 index 0000000..a7a1997 |
|
993 --- /dev/null |
|
994 +++ b/lib/isc/tests/counter_test.c |
|
995 @@ -0,0 +1,69 @@ |
|
996 +/* |
|
997 + * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") |
|
998 + * |
|
999 + * Permission to use, copy, modify, and/or distribute this software for any |
|
1000 + * purpose with or without fee is hereby granted, provided that the above |
|
1001 + * copyright notice and this permission notice appear in all copies. |
|
1002 + * |
|
1003 + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH |
|
1004 + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
|
1005 + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, |
|
1006 + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
|
1007 + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
|
1008 + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
|
1009 + * PERFORMANCE OF THIS SOFTWARE. |
|
1010 + */ |
|
1011 + |
|
1012 +#include <config.h> |
|
1013 +#include <stdlib.h> |
|
1014 + |
|
1015 +#include <atf-c.h> |
|
1016 + |
|
1017 +#include <isc/counter.h> |
|
1018 +#include <isc/result.h> |
|
1019 + |
|
1020 +#include "isctest.h" |
|
1021 + |
|
1022 +ATF_TC(isc_counter); |
|
1023 +ATF_TC_HEAD(isc_counter, tc) { |
|
1024 + atf_tc_set_md_var(tc, "descr", "isc counter object"); |
|
1025 +} |
|
1026 +ATF_TC_BODY(isc_counter, tc) { |
|
1027 + isc_result_t result; |
|
1028 + isc_counter_t *counter = NULL; |
|
1029 + int i; |
|
1030 + |
|
1031 + result = isc_test_begin(NULL, ISC_TRUE); |
|
1032 + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); |
|
1033 + |
|
1034 + result = isc_counter_create(mctx, 0, &counter); |
|
1035 + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); |
|
1036 + |
|
1037 + for (i = 0; i < 10; i++) { |
|
1038 + result = isc_counter_increment(counter); |
|
1039 + ATF_CHECK_EQ(result, ISC_R_SUCCESS); |
|
1040 + } |
|
1041 + |
|
1042 + ATF_CHECK_EQ(isc_counter_used(counter), 10); |
|
1043 + |
|
1044 + isc_counter_setlimit(counter, 15); |
|
1045 + for (i = 0; i < 10; i++) { |
|
1046 + result = isc_counter_increment(counter); |
|
1047 + if (result != ISC_R_SUCCESS) |
|
1048 + break; |
|
1049 + } |
|
1050 + |
|
1051 + ATF_CHECK_EQ(isc_counter_used(counter), 15); |
|
1052 + |
|
1053 + isc_counter_detach(&counter); |
|
1054 + isc_test_end(); |
|
1055 +} |
|
1056 + |
|
1057 +/* |
|
1058 + * Main |
|
1059 + */ |
|
1060 +ATF_TP_ADD_TCS(tp) { |
|
1061 + ATF_TP_ADD_TC(tp, isc_counter); |
|
1062 + return (atf_no_error()); |
|
1063 +} |
|
1064 + |