]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/lib/dns/ncache.c
Fix an off by one which can result in a assertion failure in BIND
[FreeBSD/releng/8.1.git] / contrib / bind9 / lib / dns / ncache.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2008, 2010  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: ncache.c,v 1.43.334.2 2010/02/25 10:57:11 tbox Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <isc/buffer.h>
25 #include <isc/util.h>
26
27 #include <dns/db.h>
28 #include <dns/message.h>
29 #include <dns/ncache.h>
30 #include <dns/rdata.h>
31 #include <dns/rdatalist.h>
32 #include <dns/rdataset.h>
33 #include <dns/rdatastruct.h>
34
35 #define DNS_NCACHE_RDATA 20U
36
37 /*
38  * The format of an ncache rdata is a sequence of one or more records of
39  * the following format:
40  *
41  *      owner name
42  *      type
43  *      rdata count
44  *              rdata length                    These two occur 'rdata count'
45  *              rdata                           times.
46  *
47  */
48
49 static inline isc_result_t
50 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
51         isc_result_t result;
52         unsigned int count;
53         isc_region_t ar, r;
54         dns_rdata_t rdata = DNS_RDATA_INIT;
55
56         /*
57          * Copy the rdataset count to the buffer.
58          */
59         isc_buffer_availableregion(buffer, &ar);
60         if (ar.length < 2)
61                 return (ISC_R_NOSPACE);
62         count = dns_rdataset_count(rdataset);
63         INSIST(count <= 65535);
64         isc_buffer_putuint16(buffer, (isc_uint16_t)count);
65
66         result = dns_rdataset_first(rdataset);
67         while (result == ISC_R_SUCCESS) {
68                 dns_rdataset_current(rdataset, &rdata);
69                 dns_rdata_toregion(&rdata, &r);
70                 INSIST(r.length <= 65535);
71                 isc_buffer_availableregion(buffer, &ar);
72                 if (ar.length < 2)
73                         return (ISC_R_NOSPACE);
74                 /*
75                  * Copy the rdata length to the buffer.
76                  */
77                 isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
78                 /*
79                  * Copy the rdata to the buffer.
80                  */
81                 result = isc_buffer_copyregion(buffer, &r);
82                 if (result != ISC_R_SUCCESS)
83                         return (result);
84                 dns_rdata_reset(&rdata);
85                 result = dns_rdataset_next(rdataset);
86         }
87         if (result != ISC_R_NOMORE)
88                 return (result);
89
90         return (ISC_R_SUCCESS);
91 }
92
93 isc_result_t
94 dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
95                dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
96                dns_rdataset_t *addedrdataset)
97 {
98         return (dns_ncache_addoptout(message, cache, node, covers, now, maxttl,
99                                     ISC_FALSE, addedrdataset));
100 }
101
102 isc_result_t
103 dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
104                      dns_dbnode_t *node, dns_rdatatype_t covers,
105                      isc_stdtime_t now, dns_ttl_t maxttl,
106                      isc_boolean_t optout, dns_rdataset_t *addedrdataset)
107 {
108         isc_result_t result;
109         isc_buffer_t buffer;
110         isc_region_t r;
111         dns_rdataset_t *rdataset;
112         dns_rdatatype_t type;
113         dns_name_t *name;
114         dns_ttl_t ttl;
115         dns_trust_t trust;
116         dns_rdata_t rdata[DNS_NCACHE_RDATA];
117         dns_rdataset_t ncrdataset;
118         dns_rdatalist_t ncrdatalist;
119         unsigned char data[4096];
120         unsigned int next = 0;
121
122         /*
123          * Convert the authority data from 'message' into a negative cache
124          * rdataset, and store it in 'cache' at 'node'.
125          */
126
127         REQUIRE(message != NULL);
128
129         /*
130          * We assume that all data in the authority section has been
131          * validated by the caller.
132          */
133
134         /*
135          * Initialize the list.
136          */
137         ncrdatalist.rdclass = dns_db_class(cache);
138         ncrdatalist.type = 0;
139         ncrdatalist.covers = covers;
140         ncrdatalist.ttl = maxttl;
141         ISC_LIST_INIT(ncrdatalist.rdata);
142         ISC_LINK_INIT(&ncrdatalist, link);
143
144         /*
145          * Build an ncache rdatas into buffer.
146          */
147         ttl = maxttl;
148         trust = 0xffff;
149         isc_buffer_init(&buffer, data, sizeof(data));
150         if (message->counts[DNS_SECTION_AUTHORITY])
151                 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
152         else
153                 result = ISC_R_NOMORE;
154         while (result == ISC_R_SUCCESS) {
155                 name = NULL;
156                 dns_message_currentname(message, DNS_SECTION_AUTHORITY,
157                                         &name);
158                 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
159                         for (rdataset = ISC_LIST_HEAD(name->list);
160                              rdataset != NULL;
161                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
162                                 if ((rdataset->attributes &
163                                      DNS_RDATASETATTR_NCACHE) == 0)
164                                         continue;
165                                 type = rdataset->type;
166                                 if (type == dns_rdatatype_rrsig)
167                                         type = rdataset->covers;
168                                 if (type == dns_rdatatype_soa ||
169                                     type == dns_rdatatype_nsec ||
170                                     type == dns_rdatatype_nsec3) {
171                                         if (ttl > rdataset->ttl)
172                                                 ttl = rdataset->ttl;
173                                         if (trust > rdataset->trust)
174                                                 trust = rdataset->trust;
175                                         /*
176                                          * Copy the owner name to the buffer.
177                                          */
178                                         dns_name_toregion(name, &r);
179                                         result = isc_buffer_copyregion(&buffer,
180                                                                        &r);
181                                         if (result != ISC_R_SUCCESS)
182                                                 return (result);
183                                         /*
184                                          * Copy the type to the buffer.
185                                          */
186                                         isc_buffer_availableregion(&buffer,
187                                                                    &r);
188                                         if (r.length < 3)
189                                                 return (ISC_R_NOSPACE);
190                                         isc_buffer_putuint16(&buffer,
191                                                              rdataset->type);
192                                         /*
193                                          * Copy the rdataset into the buffer.
194                                          */
195                                         result = copy_rdataset(rdataset,
196                                                                &buffer);
197                                         if (result != ISC_R_SUCCESS)
198                                                 return (result);
199
200                                         if (next >= DNS_NCACHE_RDATA)
201                                                 return (ISC_R_NOSPACE);
202                                         dns_rdata_init(&rdata[next]);
203                                         isc_buffer_remainingregion(&buffer, &r);
204                                         rdata[next].data = r.base;
205                                         rdata[next].length = r.length;
206                                         rdata[next].rdclass =
207                                                 ncrdatalist.rdclass;
208                                         rdata[next].type = 0;
209                                         rdata[next].flags = 0;
210                                         ISC_LIST_APPEND(ncrdatalist.rdata,
211                                                         &rdata[next], link);
212                                         isc_buffer_forward(&buffer, r.length);
213                                         next++;
214                                 }
215                         }
216                 }
217                 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
218         }
219         if (result != ISC_R_NOMORE)
220                 return (result);
221
222         if (trust == 0xffff) {
223                 /*
224                  * We didn't find any authority data from which to create a
225                  * negative cache rdataset.  In particular, we have no SOA.
226                  *
227                  * We trust that the caller wants negative caching, so this
228                  * means we have a "type 3 nxdomain" or "type 3 nodata"
229                  * response (see RFC2308 for details).
230                  *
231                  * We will now build a suitable negative cache rdataset that
232                  * will cause zero bytes to be emitted when converted to
233                  * wire format.
234                  */
235
236                 /*
237                  * The ownername must exist, but it doesn't matter what value
238                  * it has.  We use the root name.
239                  */
240                 dns_name_toregion(dns_rootname, &r);
241                 result = isc_buffer_copyregion(&buffer, &r);
242                 if (result != ISC_R_SUCCESS)
243                         return (result);
244                 /*
245                  * Copy the type and a zero rdata count to the buffer.
246                  */
247                 isc_buffer_availableregion(&buffer, &r);
248                 if (r.length < 4)
249                         return (ISC_R_NOSPACE);
250                 isc_buffer_putuint16(&buffer, 0);
251                 isc_buffer_putuint16(&buffer, 0);
252                 /*
253                  * RFC2308, section 5, says that negative answers without
254                  * SOAs should not be cached.
255                  */
256                 ttl = 0;
257                 /*
258                  * Set trust.
259                  */
260                 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
261                     message->counts[DNS_SECTION_ANSWER] == 0) {
262                         /*
263                          * The response has aa set and we haven't followed
264                          * any CNAME or DNAME chains.
265                          */
266                         trust = dns_trust_authauthority;
267                 } else
268                         trust = dns_trust_additional;
269                 /*
270                  * Now add it to the cache.
271                  */
272                 if (next >= DNS_NCACHE_RDATA)
273                         return (ISC_R_NOSPACE);
274                 dns_rdata_init(&rdata[next]);
275                 isc_buffer_remainingregion(&buffer, &r);
276                 rdata[next].data = r.base;
277                 rdata[next].length = r.length;
278                 rdata[next].rdclass = ncrdatalist.rdclass;
279                 rdata[next].type = 0;
280                 rdata[next].flags = 0;
281                 ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link);
282         }
283
284         INSIST(trust != 0xffff);
285
286         ncrdatalist.ttl = ttl;
287
288         dns_rdataset_init(&ncrdataset);
289         RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
290                       == ISC_R_SUCCESS);
291         ncrdataset.trust = trust;
292         if (message->rcode == dns_rcode_nxdomain)
293                 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
294         if (optout)
295                 ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
296
297         return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
298                                    0, addedrdataset));
299 }
300
301 isc_result_t
302 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
303                   isc_buffer_t *target, unsigned int options,
304                   unsigned int *countp)
305 {
306         dns_rdata_t rdata = DNS_RDATA_INIT;
307         isc_result_t result;
308         isc_region_t remaining, tavailable;
309         isc_buffer_t source, savedbuffer, rdlen;
310         dns_name_t name;
311         dns_rdatatype_t type;
312         unsigned int i, rcount, count;
313
314         /*
315          * Convert the negative caching rdataset 'rdataset' to wire format,
316          * compressing names as specified in 'cctx', and storing the result in
317          * 'target'.
318          */
319
320         REQUIRE(rdataset != NULL);
321         REQUIRE(rdataset->type == 0);
322
323         savedbuffer = *target;
324         count = 0;
325
326         result = dns_rdataset_first(rdataset);
327         while (result == ISC_R_SUCCESS) {
328                 dns_rdataset_current(rdataset, &rdata);
329                 isc_buffer_init(&source, rdata.data, rdata.length);
330                 isc_buffer_add(&source, rdata.length);
331                 dns_name_init(&name, NULL);
332                 isc_buffer_remainingregion(&source, &remaining);
333                 dns_name_fromregion(&name, &remaining);
334                 INSIST(remaining.length >= name.length);
335                 isc_buffer_forward(&source, name.length);
336                 remaining.length -= name.length;
337
338                 INSIST(remaining.length >= 4);
339                 type = isc_buffer_getuint16(&source);
340                 rcount = isc_buffer_getuint16(&source);
341
342                 for (i = 0; i < rcount; i++) {
343                         /*
344                          * Get the length of this rdata and set up an
345                          * rdata structure for it.
346                          */
347                         isc_buffer_remainingregion(&source, &remaining);
348                         INSIST(remaining.length >= 2);
349                         dns_rdata_reset(&rdata);
350                         rdata.length = isc_buffer_getuint16(&source);
351                         isc_buffer_remainingregion(&source, &remaining);
352                         rdata.data = remaining.base;
353                         rdata.type = type;
354                         rdata.rdclass = rdataset->rdclass;
355                         INSIST(remaining.length >= rdata.length);
356                         isc_buffer_forward(&source, rdata.length);
357
358                         if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
359                             dns_rdatatype_isdnssec(type))
360                                 continue;
361
362                         /*
363                          * Write the name.
364                          */
365                         dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
366                         result = dns_name_towire(&name, cctx, target);
367                         if (result != ISC_R_SUCCESS)
368                                 goto rollback;
369
370                         /*
371                          * See if we have space for type, class, ttl, and
372                          * rdata length.  Write the type, class, and ttl.
373                          */
374                         isc_buffer_availableregion(target, &tavailable);
375                         if (tavailable.length < 10) {
376                                 result = ISC_R_NOSPACE;
377                                 goto rollback;
378                         }
379                         isc_buffer_putuint16(target, type);
380                         isc_buffer_putuint16(target, rdataset->rdclass);
381                         isc_buffer_putuint32(target, rdataset->ttl);
382
383                         /*
384                          * Save space for rdata length.
385                          */
386                         rdlen = *target;
387                         isc_buffer_add(target, 2);
388
389                         /*
390                          * Write the rdata.
391                          */
392                         result = dns_rdata_towire(&rdata, cctx, target);
393                         if (result != ISC_R_SUCCESS)
394                                 goto rollback;
395
396                         /*
397                          * Set the rdata length field to the compressed
398                          * length.
399                          */
400                         INSIST((target->used >= rdlen.used + 2) &&
401                                (target->used - rdlen.used - 2 < 65536));
402                         isc_buffer_putuint16(&rdlen,
403                                              (isc_uint16_t)(target->used -
404                                                             rdlen.used - 2));
405
406                         count++;
407                 }
408                 INSIST(isc_buffer_remaininglength(&source) == 0);
409                 result = dns_rdataset_next(rdataset);
410                 dns_rdata_reset(&rdata);
411         }
412         if (result != ISC_R_NOMORE)
413                 goto rollback;
414
415         *countp = count;
416
417         return (ISC_R_SUCCESS);
418
419  rollback:
420         INSIST(savedbuffer.used < 65536);
421         dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
422         *countp = 0;
423         *target = savedbuffer;
424
425         return (result);
426 }
427
428 static void
429 rdataset_disassociate(dns_rdataset_t *rdataset) {
430         UNUSED(rdataset);
431 }
432
433 static isc_result_t
434 rdataset_first(dns_rdataset_t *rdataset) {
435         unsigned char *raw = rdataset->private3;
436         unsigned int count;
437
438         count = raw[0] * 256 + raw[1];
439         if (count == 0) {
440                 rdataset->private5 = NULL;
441                 return (ISC_R_NOMORE);
442         }
443         raw += 2;
444         /*
445          * The privateuint4 field is the number of rdata beyond the cursor
446          * position, so we decrement the total count by one before storing
447          * it.
448          */
449         count--;
450         rdataset->privateuint4 = count;
451         rdataset->private5 = raw;
452
453         return (ISC_R_SUCCESS);
454 }
455
456 static isc_result_t
457 rdataset_next(dns_rdataset_t *rdataset) {
458         unsigned int count;
459         unsigned int length;
460         unsigned char *raw;
461
462         count = rdataset->privateuint4;
463         if (count == 0)
464                 return (ISC_R_NOMORE);
465         count--;
466         rdataset->privateuint4 = count;
467         raw = rdataset->private5;
468         length = raw[0] * 256 + raw[1];
469         raw += length + 2;
470         rdataset->private5 = raw;
471
472         return (ISC_R_SUCCESS);
473 }
474
475 static void
476 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
477         unsigned char *raw = rdataset->private5;
478         isc_region_t r;
479
480         REQUIRE(raw != NULL);
481
482         r.length = raw[0] * 256 + raw[1];
483         raw += 2;
484         r.base = raw;
485         dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
486 }
487
488 static void
489 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
490         *target = *source;
491
492         /*
493          * Reset iterator state.
494          */
495         target->privateuint4 = 0;
496         target->private5 = NULL;
497 }
498
499 static unsigned int
500 rdataset_count(dns_rdataset_t *rdataset) {
501         unsigned char *raw = rdataset->private3;
502         unsigned int count;
503
504         count = raw[0] * 256 + raw[1];
505
506         return (count);
507 }
508
509 static dns_rdatasetmethods_t rdataset_methods = {
510         rdataset_disassociate,
511         rdataset_first,
512         rdataset_next,
513         rdataset_current,
514         rdataset_clone,
515         rdataset_count,
516         NULL,
517         NULL,
518         NULL,
519         NULL,
520         NULL,
521         NULL,
522         NULL,
523         NULL,
524         NULL
525 };
526
527 isc_result_t
528 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
529                        dns_rdatatype_t type, dns_rdataset_t *rdataset)
530 {
531         isc_result_t result;
532         dns_rdata_t rdata = DNS_RDATA_INIT;
533         isc_region_t remaining;
534         isc_buffer_t source;
535         dns_name_t tname;
536         dns_rdatatype_t ttype;
537
538         REQUIRE(ncacherdataset != NULL);
539         REQUIRE(ncacherdataset->type == 0);
540         REQUIRE(name != NULL);
541         REQUIRE(!dns_rdataset_isassociated(rdataset));
542         REQUIRE(type != dns_rdatatype_rrsig);
543
544         result = dns_rdataset_first(ncacherdataset);
545         while (result == ISC_R_SUCCESS) {
546                 dns_rdataset_current(ncacherdataset, &rdata);
547                 isc_buffer_init(&source, rdata.data, rdata.length);
548                 isc_buffer_add(&source, rdata.length);
549                 dns_name_init(&tname, NULL);
550                 isc_buffer_remainingregion(&source, &remaining);
551                 dns_name_fromregion(&tname, &remaining);
552                 INSIST(remaining.length >= tname.length);
553                 isc_buffer_forward(&source, tname.length);
554                 remaining.length -= tname.length;
555
556                 INSIST(remaining.length >= 4);
557                 ttype = isc_buffer_getuint16(&source);
558
559                 if (ttype == type && dns_name_equal(&tname, name)) {
560                         isc_buffer_remainingregion(&source, &remaining);
561                         break;
562                 }
563                 result = dns_rdataset_next(ncacherdataset);
564                 dns_rdata_reset(&rdata);
565         }
566         if (result == ISC_R_NOMORE)
567                 return (ISC_R_NOTFOUND);
568         if (result != ISC_R_SUCCESS)
569                 return (result);
570
571         INSIST(remaining.length != 0);
572
573         rdataset->methods = &rdataset_methods;
574         rdataset->rdclass = ncacherdataset->rdclass;
575         rdataset->type = type;
576         rdataset->covers = 0;
577         rdataset->ttl = ncacherdataset->ttl;
578         rdataset->trust = ncacherdataset->trust;
579         rdataset->private1 = NULL;
580         rdataset->private2 = NULL;
581
582         rdataset->private3 = remaining.base;
583
584         /*
585          * Reset iterator state.
586          */
587         rdataset->privateuint4 = 0;
588         rdataset->private5 = NULL;
589         rdataset->private6 = NULL;
590         return (ISC_R_SUCCESS);
591 }
592
593 void
594 dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
595                    dns_rdataset_t *rdataset)
596 {
597         dns_rdata_t rdata = DNS_RDATA_INIT;
598         isc_region_t remaining, sigregion;
599         isc_buffer_t source;
600         dns_name_t tname;
601         dns_rdatatype_t type;
602         unsigned int count;
603         dns_rdata_rrsig_t rrsig;
604         unsigned char *raw;
605
606         REQUIRE(ncacherdataset != NULL);
607         REQUIRE(ncacherdataset->type == 0);
608         REQUIRE(found != NULL);
609         REQUIRE(!dns_rdataset_isassociated(rdataset));
610
611         dns_rdataset_current(ncacherdataset, &rdata);
612         isc_buffer_init(&source, rdata.data, rdata.length);
613         isc_buffer_add(&source, rdata.length);
614
615         dns_name_init(&tname, NULL);
616         isc_buffer_remainingregion(&source, &remaining);
617         dns_name_fromregion(found, &remaining);
618         INSIST(remaining.length >= found->length);
619         isc_buffer_forward(&source, found->length);
620         remaining.length -= found->length;
621
622         INSIST(remaining.length >= 4);
623         type = isc_buffer_getuint16(&source);
624         isc_buffer_remainingregion(&source, &remaining);
625
626         rdataset->methods = &rdataset_methods;
627         rdataset->rdclass = ncacherdataset->rdclass;
628         rdataset->type = type;
629         if (type == dns_rdatatype_rrsig) {
630                 /*
631                  * Extract covers from RRSIG.
632                  */
633                 raw = remaining.base;
634                 count = raw[0] * 256 + raw[1];
635                 INSIST(count > 0);
636                 raw += 2;
637                 sigregion.length = raw[0] * 256 + raw[1];
638                 raw += 2;
639                 sigregion.base = raw;
640                 dns_rdata_reset(&rdata);
641                 dns_rdata_fromregion(&rdata, rdataset->rdclass,
642                                      rdataset->type, &sigregion);
643                 (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
644                 rdataset->covers = rrsig.covered;
645         } else
646                 rdataset->covers = 0;
647         rdataset->ttl = ncacherdataset->ttl;
648         rdataset->trust = ncacherdataset->trust;
649         rdataset->private1 = NULL;
650         rdataset->private2 = NULL;
651
652         rdataset->private3 = remaining.base;
653
654         /*
655          * Reset iterator state.
656          */
657         rdataset->privateuint4 = 0;
658         rdataset->private5 = NULL;
659         rdataset->private6 = NULL;
660 }