/contrib/bind9/lib/dns/rdataslab.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1109 lines · 760 code · 131 blank · 218 comment · 159 complexity · d7233b701e5ac6b8993f3f61d6a441df MD5 · raw file

  1. /*
  2. * Copyright (C) 2004-2012 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. /* $Id$ */
  18. /*! \file */
  19. #include <config.h>
  20. #include <stdlib.h>
  21. #include <isc/mem.h>
  22. #include <isc/region.h>
  23. #include <isc/string.h> /* Required for HP/UX (and others?) */
  24. #include <isc/util.h>
  25. #include <dns/result.h>
  26. #include <dns/rdata.h>
  27. #include <dns/rdataset.h>
  28. #include <dns/rdataslab.h>
  29. /*
  30. * The rdataslab structure allows iteration to occur in both load order
  31. * and DNSSEC order. The structure is as follows:
  32. *
  33. * header (reservelen bytes)
  34. * record count (2 bytes)
  35. * offset table (4 x record count bytes in load order)
  36. * data records
  37. * data length (2 bytes)
  38. * order (2 bytes)
  39. * meta data (1 byte for RRSIG's)
  40. * data (data length bytes)
  41. *
  42. * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a
  43. * rdataslab is as follows:
  44. *
  45. * header (reservelen bytes)
  46. * record count (2 bytes)
  47. * data records
  48. * data length (2 bytes)
  49. * meta data (1 byte for RRSIG's)
  50. * data (data length bytes)
  51. *
  52. * Offsets are from the end of the header.
  53. *
  54. * Load order traversal is performed by walking the offset table to find
  55. * the start of the record (DNS_RDATASET_FIXED = 1).
  56. *
  57. * DNSSEC order traversal is performed by walking the data records.
  58. *
  59. * The order is stored with record to allow for efficient reconstruction
  60. * of the offset table following a merge or subtraction.
  61. *
  62. * The iterator methods here currently only support DNSSEC order iteration.
  63. *
  64. * The iterator methods in rbtdb support both load order and DNSSEC order
  65. * iteration.
  66. *
  67. * WARNING:
  68. * rbtdb.c directly interacts with the slab's raw structures. If the
  69. * structure changes then rbtdb.c also needs to be updated to reflect
  70. * the changes. See the areas tagged with "RDATASLAB".
  71. */
  72. struct xrdata {
  73. dns_rdata_t rdata;
  74. unsigned int order;
  75. };
  76. /*% Note: the "const void *" are just to make qsort happy. */
  77. static int
  78. compare_rdata(const void *p1, const void *p2) {
  79. const struct xrdata *x1 = p1;
  80. const struct xrdata *x2 = p2;
  81. return (dns_rdata_compare(&x1->rdata, &x2->rdata));
  82. }
  83. #if DNS_RDATASET_FIXED
  84. static void
  85. fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
  86. unsigned length)
  87. {
  88. unsigned int i, j;
  89. unsigned char *raw;
  90. for (i = 0, j = 0; i < length; i++) {
  91. if (offsettable[i] == 0)
  92. continue;
  93. /*
  94. * Fill in offset table.
  95. */
  96. raw = &offsetbase[j*4 + 2];
  97. *raw++ = (offsettable[i] & 0xff000000) >> 24;
  98. *raw++ = (offsettable[i] & 0xff0000) >> 16;
  99. *raw++ = (offsettable[i] & 0xff00) >> 8;
  100. *raw = offsettable[i] & 0xff;
  101. /*
  102. * Fill in table index.
  103. */
  104. raw = offsetbase + offsettable[i] + 2;
  105. *raw++ = (j & 0xff00) >> 8;
  106. *raw = j++ & 0xff;
  107. }
  108. }
  109. #endif
  110. isc_result_t
  111. dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
  112. isc_region_t *region, unsigned int reservelen)
  113. {
  114. /*
  115. * Use &removed as a sentinal pointer for duplicate
  116. * rdata as rdata.data == NULL is valid.
  117. */
  118. static unsigned char removed;
  119. struct xrdata *x;
  120. unsigned char *rawbuf;
  121. #if DNS_RDATASET_FIXED
  122. unsigned char *offsetbase;
  123. #endif
  124. unsigned int buflen;
  125. isc_result_t result;
  126. unsigned int nitems;
  127. unsigned int nalloc;
  128. unsigned int i;
  129. #if DNS_RDATASET_FIXED
  130. unsigned int *offsettable;
  131. #endif
  132. unsigned int length;
  133. buflen = reservelen + 2;
  134. nalloc = dns_rdataset_count(rdataset);
  135. nitems = nalloc;
  136. if (nitems == 0 && rdataset->type != 0)
  137. return (ISC_R_FAILURE);
  138. if (nalloc > 0xffff)
  139. return (ISC_R_NOSPACE);
  140. if (nalloc != 0) {
  141. x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata));
  142. if (x == NULL)
  143. return (ISC_R_NOMEMORY);
  144. } else
  145. x = NULL;
  146. /*
  147. * Save all of the rdata members into an array.
  148. */
  149. result = dns_rdataset_first(rdataset);
  150. if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
  151. goto free_rdatas;
  152. for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
  153. INSIST(result == ISC_R_SUCCESS);
  154. dns_rdata_init(&x[i].rdata);
  155. dns_rdataset_current(rdataset, &x[i].rdata);
  156. INSIST(x[i].rdata.data != &removed);
  157. #if DNS_RDATASET_FIXED
  158. x[i].order = i;
  159. #endif
  160. result = dns_rdataset_next(rdataset);
  161. }
  162. if (result != ISC_R_NOMORE)
  163. goto free_rdatas;
  164. if (i != nalloc) {
  165. /*
  166. * Somehow we iterated over fewer rdatas than
  167. * dns_rdataset_count() said there were!
  168. */
  169. result = ISC_R_FAILURE;
  170. goto free_rdatas;
  171. }
  172. /*
  173. * Put into DNSSEC order.
  174. */
  175. qsort(x, nalloc, sizeof(struct xrdata), compare_rdata);
  176. /*
  177. * Remove duplicates and compute the total storage required.
  178. *
  179. * If an rdata is not a duplicate, accumulate the storage size
  180. * required for the rdata. We do not store the class, type, etc,
  181. * just the rdata, so our overhead is 2 bytes for the number of
  182. * records, and 8 for each rdata, (length(2), offset(4) and order(2))
  183. * and then the rdata itself.
  184. */
  185. for (i = 1; i < nalloc; i++) {
  186. if (compare_rdata(&x[i-1].rdata, &x[i].rdata) == 0) {
  187. x[i-1].rdata.data = &removed;
  188. #if DNS_RDATASET_FIXED
  189. /*
  190. * Preserve the least order so A, B, A -> A, B
  191. * after duplicate removal.
  192. */
  193. if (x[i-1].order < x[i].order)
  194. x[i].order = x[i-1].order;
  195. #endif
  196. nitems--;
  197. } else {
  198. #if DNS_RDATASET_FIXED
  199. buflen += (8 + x[i-1].rdata.length);
  200. #else
  201. buflen += (2 + x[i-1].rdata.length);
  202. #endif
  203. /*
  204. * Provide space to store the per RR meta data.
  205. */
  206. if (rdataset->type == dns_rdatatype_rrsig)
  207. buflen++;
  208. }
  209. }
  210. /*
  211. * Don't forget the last item!
  212. */
  213. if (nalloc != 0) {
  214. #if DNS_RDATASET_FIXED
  215. buflen += (8 + x[i-1].rdata.length);
  216. #else
  217. buflen += (2 + x[i-1].rdata.length);
  218. #endif
  219. }
  220. /*
  221. * Provide space to store the per RR meta data.
  222. */
  223. if (rdataset->type == dns_rdatatype_rrsig)
  224. buflen++;
  225. /*
  226. * Ensure that singleton types are actually singletons.
  227. */
  228. if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
  229. /*
  230. * We have a singleton type, but there's more than one
  231. * RR in the rdataset.
  232. */
  233. result = DNS_R_SINGLETON;
  234. goto free_rdatas;
  235. }
  236. /*
  237. * Allocate the memory, set up a buffer, start copying in
  238. * data.
  239. */
  240. rawbuf = isc_mem_get(mctx, buflen);
  241. if (rawbuf == NULL) {
  242. result = ISC_R_NOMEMORY;
  243. goto free_rdatas;
  244. }
  245. #if DNS_RDATASET_FIXED
  246. /* Allocate temporary offset table. */
  247. offsettable = isc_mem_get(mctx, nalloc * sizeof(unsigned int));
  248. if (offsettable == NULL) {
  249. isc_mem_put(mctx, rawbuf, buflen);
  250. result = ISC_R_NOMEMORY;
  251. goto free_rdatas;
  252. }
  253. memset(offsettable, 0, nalloc * sizeof(unsigned int));
  254. #endif
  255. region->base = rawbuf;
  256. region->length = buflen;
  257. rawbuf += reservelen;
  258. #if DNS_RDATASET_FIXED
  259. offsetbase = rawbuf;
  260. #endif
  261. *rawbuf++ = (nitems & 0xff00) >> 8;
  262. *rawbuf++ = (nitems & 0x00ff);
  263. #if DNS_RDATASET_FIXED
  264. /* Skip load order table. Filled in later. */
  265. rawbuf += nitems * 4;
  266. #endif
  267. for (i = 0; i < nalloc; i++) {
  268. if (x[i].rdata.data == &removed)
  269. continue;
  270. #if DNS_RDATASET_FIXED
  271. offsettable[x[i].order] = rawbuf - offsetbase;
  272. #endif
  273. length = x[i].rdata.length;
  274. if (rdataset->type == dns_rdatatype_rrsig)
  275. length++;
  276. INSIST(length <= 0xffff);
  277. *rawbuf++ = (length & 0xff00) >> 8;
  278. *rawbuf++ = (length & 0x00ff);
  279. #if DNS_RDATASET_FIXED
  280. rawbuf += 2; /* filled in later */
  281. #endif
  282. /*
  283. * Store the per RR meta data.
  284. */
  285. if (rdataset->type == dns_rdatatype_rrsig) {
  286. *rawbuf++ |= (x[i].rdata.flags & DNS_RDATA_OFFLINE) ?
  287. DNS_RDATASLAB_OFFLINE : 0;
  288. }
  289. memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length);
  290. rawbuf += x[i].rdata.length;
  291. }
  292. #if DNS_RDATASET_FIXED
  293. fillin_offsets(offsetbase, offsettable, nalloc);
  294. isc_mem_put(mctx, offsettable, nalloc * sizeof(unsigned int));
  295. #endif
  296. result = ISC_R_SUCCESS;
  297. free_rdatas:
  298. if (x != NULL)
  299. isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata));
  300. return (result);
  301. }
  302. static void
  303. rdataset_disassociate(dns_rdataset_t *rdataset) {
  304. UNUSED(rdataset);
  305. }
  306. static isc_result_t
  307. rdataset_first(dns_rdataset_t *rdataset) {
  308. unsigned char *raw = rdataset->private3;
  309. unsigned int count;
  310. count = raw[0] * 256 + raw[1];
  311. if (count == 0) {
  312. rdataset->private5 = NULL;
  313. return (ISC_R_NOMORE);
  314. }
  315. #if DNS_RDATASET_FIXED
  316. raw += 2 + (4 * count);
  317. #else
  318. raw += 2;
  319. #endif
  320. /*
  321. * The privateuint4 field is the number of rdata beyond the cursor
  322. * position, so we decrement the total count by one before storing
  323. * it.
  324. */
  325. count--;
  326. rdataset->privateuint4 = count;
  327. rdataset->private5 = raw;
  328. return (ISC_R_SUCCESS);
  329. }
  330. static isc_result_t
  331. rdataset_next(dns_rdataset_t *rdataset) {
  332. unsigned int count;
  333. unsigned int length;
  334. unsigned char *raw;
  335. count = rdataset->privateuint4;
  336. if (count == 0)
  337. return (ISC_R_NOMORE);
  338. count--;
  339. rdataset->privateuint4 = count;
  340. raw = rdataset->private5;
  341. length = raw[0] * 256 + raw[1];
  342. #if DNS_RDATASET_FIXED
  343. raw += length + 4;
  344. #else
  345. raw += length + 2;
  346. #endif
  347. rdataset->private5 = raw;
  348. return (ISC_R_SUCCESS);
  349. }
  350. static void
  351. rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
  352. unsigned char *raw = rdataset->private5;
  353. isc_region_t r;
  354. unsigned int length;
  355. unsigned int flags = 0;
  356. REQUIRE(raw != NULL);
  357. length = raw[0] * 256 + raw[1];
  358. #if DNS_RDATASET_FIXED
  359. raw += 4;
  360. #else
  361. raw += 2;
  362. #endif
  363. if (rdataset->type == dns_rdatatype_rrsig) {
  364. if (*raw & DNS_RDATASLAB_OFFLINE)
  365. flags |= DNS_RDATA_OFFLINE;
  366. length--;
  367. raw++;
  368. }
  369. r.length = length;
  370. r.base = raw;
  371. dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
  372. rdata->flags |= flags;
  373. }
  374. static void
  375. rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
  376. *target = *source;
  377. /*
  378. * Reset iterator state.
  379. */
  380. target->privateuint4 = 0;
  381. target->private5 = NULL;
  382. }
  383. static unsigned int
  384. rdataset_count(dns_rdataset_t *rdataset) {
  385. unsigned char *raw = rdataset->private3;
  386. unsigned int count;
  387. count = raw[0] * 256 + raw[1];
  388. return (count);
  389. }
  390. static dns_rdatasetmethods_t rdataset_methods = {
  391. rdataset_disassociate,
  392. rdataset_first,
  393. rdataset_next,
  394. rdataset_current,
  395. rdataset_clone,
  396. rdataset_count,
  397. NULL,
  398. NULL,
  399. NULL,
  400. NULL,
  401. NULL,
  402. NULL,
  403. NULL,
  404. NULL,
  405. NULL
  406. };
  407. void
  408. dns_rdataslab_tordataset(unsigned char *slab, unsigned int reservelen,
  409. dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
  410. dns_rdatatype_t covers, dns_ttl_t ttl,
  411. dns_rdataset_t *rdataset)
  412. {
  413. REQUIRE(slab != NULL);
  414. REQUIRE(!dns_rdataset_isassociated(rdataset));
  415. rdataset->methods = &rdataset_methods;
  416. rdataset->rdclass = rdclass;
  417. rdataset->type = rdtype;
  418. rdataset->covers = covers;
  419. rdataset->ttl = ttl;
  420. rdataset->trust = 0;
  421. rdataset->private1 = NULL;
  422. rdataset->private2 = NULL;
  423. rdataset->private3 = slab + reservelen;
  424. /*
  425. * Reset iterator state.
  426. */
  427. rdataset->privateuint4 = 0;
  428. rdataset->private5 = NULL;
  429. }
  430. unsigned int
  431. dns_rdataslab_size(unsigned char *slab, unsigned int reservelen) {
  432. unsigned int count, length;
  433. unsigned char *current;
  434. REQUIRE(slab != NULL);
  435. current = slab + reservelen;
  436. count = *current++ * 256;
  437. count += *current++;
  438. #if DNS_RDATASET_FIXED
  439. current += (4 * count);
  440. #endif
  441. while (count > 0) {
  442. count--;
  443. length = *current++ * 256;
  444. length += *current++;
  445. #if DNS_RDATASET_FIXED
  446. current += length + 2;
  447. #else
  448. current += length;
  449. #endif
  450. }
  451. return ((unsigned int)(current - slab));
  452. }
  453. /*
  454. * Make the dns_rdata_t 'rdata' refer to the slab item
  455. * beginning at '*current', which is part of a slab of type
  456. * 'type' and class 'rdclass', and advance '*current' to
  457. * point to the next item in the slab.
  458. */
  459. static inline void
  460. rdata_from_slab(unsigned char **current,
  461. dns_rdataclass_t rdclass, dns_rdatatype_t type,
  462. dns_rdata_t *rdata)
  463. {
  464. unsigned char *tcurrent = *current;
  465. isc_region_t region;
  466. unsigned int length;
  467. isc_boolean_t offline = ISC_FALSE;
  468. length = *tcurrent++ * 256;
  469. length += *tcurrent++;
  470. if (type == dns_rdatatype_rrsig) {
  471. if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0)
  472. offline = ISC_TRUE;
  473. length--;
  474. tcurrent++;
  475. }
  476. region.length = length;
  477. #if DNS_RDATASET_FIXED
  478. tcurrent += 2;
  479. #endif
  480. region.base = tcurrent;
  481. tcurrent += region.length;
  482. dns_rdata_fromregion(rdata, rdclass, type, &region);
  483. if (offline)
  484. rdata->flags |= DNS_RDATA_OFFLINE;
  485. *current = tcurrent;
  486. }
  487. /*
  488. * Return true iff 'slab' (slab data of type 'type' and class 'rdclass')
  489. * contains an rdata identical to 'rdata'. This does case insensitive
  490. * comparisons per DNSSEC.
  491. */
  492. static inline isc_boolean_t
  493. rdata_in_slab(unsigned char *slab, unsigned int reservelen,
  494. dns_rdataclass_t rdclass, dns_rdatatype_t type,
  495. dns_rdata_t *rdata)
  496. {
  497. unsigned int count, i;
  498. unsigned char *current;
  499. dns_rdata_t trdata = DNS_RDATA_INIT;
  500. int n;
  501. current = slab + reservelen;
  502. count = *current++ * 256;
  503. count += *current++;
  504. #if DNS_RDATASET_FIXED
  505. current += (4 * count);
  506. #endif
  507. for (i = 0; i < count; i++) {
  508. rdata_from_slab(&current, rdclass, type, &trdata);
  509. n = dns_rdata_compare(&trdata, rdata);
  510. if (n == 0)
  511. return (ISC_TRUE);
  512. if (n > 0) /* In DNSSEC order. */
  513. break;
  514. dns_rdata_reset(&trdata);
  515. }
  516. return (ISC_FALSE);
  517. }
  518. isc_result_t
  519. dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
  520. unsigned int reservelen, isc_mem_t *mctx,
  521. dns_rdataclass_t rdclass, dns_rdatatype_t type,
  522. unsigned int flags, unsigned char **tslabp)
  523. {
  524. unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data;
  525. unsigned int ocount, ncount, count, olength, tlength, tcount, length;
  526. dns_rdata_t ordata = DNS_RDATA_INIT;
  527. dns_rdata_t nrdata = DNS_RDATA_INIT;
  528. isc_boolean_t added_something = ISC_FALSE;
  529. unsigned int oadded = 0;
  530. unsigned int nadded = 0;
  531. unsigned int nncount = 0;
  532. #if DNS_RDATASET_FIXED
  533. unsigned int oncount;
  534. unsigned int norder = 0;
  535. unsigned int oorder = 0;
  536. unsigned char *offsetbase;
  537. unsigned int *offsettable;
  538. #endif
  539. /*
  540. * XXX Need parameter to allow "delete rdatasets in nslab" merge,
  541. * or perhaps another merge routine for this purpose.
  542. */
  543. REQUIRE(tslabp != NULL && *tslabp == NULL);
  544. REQUIRE(oslab != NULL && nslab != NULL);
  545. ocurrent = oslab + reservelen;
  546. ocount = *ocurrent++ * 256;
  547. ocount += *ocurrent++;
  548. #if DNS_RDATASET_FIXED
  549. ocurrent += (4 * ocount);
  550. #endif
  551. ostart = ocurrent;
  552. ncurrent = nslab + reservelen;
  553. ncount = *ncurrent++ * 256;
  554. ncount += *ncurrent++;
  555. #if DNS_RDATASET_FIXED
  556. ncurrent += (4 * ncount);
  557. #endif
  558. INSIST(ocount > 0 && ncount > 0);
  559. #if DNS_RDATASET_FIXED
  560. oncount = ncount;
  561. #endif
  562. /*
  563. * Yes, this is inefficient!
  564. */
  565. /*
  566. * Figure out the length of the old slab's data.
  567. */
  568. olength = 0;
  569. for (count = 0; count < ocount; count++) {
  570. length = *ocurrent++ * 256;
  571. length += *ocurrent++;
  572. #if DNS_RDATASET_FIXED
  573. olength += length + 8;
  574. ocurrent += length + 2;
  575. #else
  576. olength += length + 2;
  577. ocurrent += length;
  578. #endif
  579. }
  580. /*
  581. * Start figuring out the target length and count.
  582. */
  583. tlength = reservelen + 2 + olength;
  584. tcount = ocount;
  585. /*
  586. * Add in the length of rdata in the new slab that aren't in
  587. * the old slab.
  588. */
  589. do {
  590. dns_rdata_init(&nrdata);
  591. rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
  592. if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata))
  593. {
  594. /*
  595. * This rdata isn't in the old slab.
  596. */
  597. #if DNS_RDATASET_FIXED
  598. tlength += nrdata.length + 8;
  599. #else
  600. tlength += nrdata.length + 2;
  601. #endif
  602. if (type == dns_rdatatype_rrsig)
  603. tlength++;
  604. tcount++;
  605. nncount++;
  606. added_something = ISC_TRUE;
  607. }
  608. ncount--;
  609. } while (ncount > 0);
  610. ncount = nncount;
  611. if (((flags & DNS_RDATASLAB_EXACT) != 0) &&
  612. (tcount != ncount + ocount))
  613. return (DNS_R_NOTEXACT);
  614. if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0)
  615. return (DNS_R_UNCHANGED);
  616. /*
  617. * Ensure that singleton types are actually singletons.
  618. */
  619. if (tcount > 1 && dns_rdatatype_issingleton(type)) {
  620. /*
  621. * We have a singleton type, but there's more than one
  622. * RR in the rdataset.
  623. */
  624. return (DNS_R_SINGLETON);
  625. }
  626. if (tcount > 0xffff)
  627. return (ISC_R_NOSPACE);
  628. /*
  629. * Copy the reserved area from the new slab.
  630. */
  631. tstart = isc_mem_get(mctx, tlength);
  632. if (tstart == NULL)
  633. return (ISC_R_NOMEMORY);
  634. memcpy(tstart, nslab, reservelen);
  635. tcurrent = tstart + reservelen;
  636. #if DNS_RDATASET_FIXED
  637. offsetbase = tcurrent;
  638. #endif
  639. /*
  640. * Write the new count.
  641. */
  642. *tcurrent++ = (tcount & 0xff00) >> 8;
  643. *tcurrent++ = (tcount & 0x00ff);
  644. #if DNS_RDATASET_FIXED
  645. /*
  646. * Skip offset table.
  647. */
  648. tcurrent += (tcount * 4);
  649. offsettable = isc_mem_get(mctx,
  650. (ocount + oncount) * sizeof(unsigned int));
  651. if (offsettable == NULL) {
  652. isc_mem_put(mctx, tstart, tlength);
  653. return (ISC_R_NOMEMORY);
  654. }
  655. memset(offsettable, 0, (ocount + oncount) * sizeof(unsigned int));
  656. #endif
  657. /*
  658. * Merge the two slabs.
  659. */
  660. ocurrent = ostart;
  661. INSIST(ocount != 0);
  662. #if DNS_RDATASET_FIXED
  663. oorder = ocurrent[2] * 256 + ocurrent[3];
  664. INSIST(oorder < ocount);
  665. #endif
  666. rdata_from_slab(&ocurrent, rdclass, type, &ordata);
  667. ncurrent = nslab + reservelen + 2;
  668. #if DNS_RDATASET_FIXED
  669. ncurrent += (4 * oncount);
  670. #endif
  671. if (ncount > 0) {
  672. do {
  673. dns_rdata_reset(&nrdata);
  674. #if DNS_RDATASET_FIXED
  675. norder = ncurrent[2] * 256 + ncurrent[3];
  676. INSIST(norder < oncount);
  677. #endif
  678. rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
  679. } while (rdata_in_slab(oslab, reservelen, rdclass,
  680. type, &nrdata));
  681. }
  682. while (oadded < ocount || nadded < ncount) {
  683. isc_boolean_t fromold;
  684. if (oadded == ocount)
  685. fromold = ISC_FALSE;
  686. else if (nadded == ncount)
  687. fromold = ISC_TRUE;
  688. else
  689. fromold = ISC_TF(compare_rdata(&ordata, &nrdata) < 0);
  690. if (fromold) {
  691. #if DNS_RDATASET_FIXED
  692. offsettable[oorder] = tcurrent - offsetbase;
  693. #endif
  694. length = ordata.length;
  695. data = ordata.data;
  696. if (type == dns_rdatatype_rrsig) {
  697. length++;
  698. data--;
  699. }
  700. *tcurrent++ = (length & 0xff00) >> 8;
  701. *tcurrent++ = (length & 0x00ff);
  702. #if DNS_RDATASET_FIXED
  703. tcurrent += 2; /* fill in later */
  704. #endif
  705. memcpy(tcurrent, data, length);
  706. tcurrent += length;
  707. oadded++;
  708. if (oadded < ocount) {
  709. dns_rdata_reset(&ordata);
  710. #if DNS_RDATASET_FIXED
  711. oorder = ocurrent[2] * 256 + ocurrent[3];
  712. INSIST(oorder < ocount);
  713. #endif
  714. rdata_from_slab(&ocurrent, rdclass, type,
  715. &ordata);
  716. }
  717. } else {
  718. #if DNS_RDATASET_FIXED
  719. offsettable[ocount + norder] = tcurrent - offsetbase;
  720. #endif
  721. length = nrdata.length;
  722. data = nrdata.data;
  723. if (type == dns_rdatatype_rrsig) {
  724. length++;
  725. data--;
  726. }
  727. *tcurrent++ = (length & 0xff00) >> 8;
  728. *tcurrent++ = (length & 0x00ff);
  729. #if DNS_RDATASET_FIXED
  730. tcurrent += 2; /* fill in later */
  731. #endif
  732. memcpy(tcurrent, data, length);
  733. tcurrent += length;
  734. nadded++;
  735. if (nadded < ncount) {
  736. do {
  737. dns_rdata_reset(&nrdata);
  738. #if DNS_RDATASET_FIXED
  739. norder = ncurrent[2] * 256 + ncurrent[3];
  740. INSIST(norder < oncount);
  741. #endif
  742. rdata_from_slab(&ncurrent, rdclass,
  743. type, &nrdata);
  744. } while (rdata_in_slab(oslab, reservelen,
  745. rdclass, type,
  746. &nrdata));
  747. }
  748. }
  749. }
  750. #if DNS_RDATASET_FIXED
  751. fillin_offsets(offsetbase, offsettable, ocount + oncount);
  752. isc_mem_put(mctx, offsettable,
  753. (ocount + oncount) * sizeof(unsigned int));
  754. #endif
  755. INSIST(tcurrent == tstart + tlength);
  756. *tslabp = tstart;
  757. return (ISC_R_SUCCESS);
  758. }
  759. isc_result_t
  760. dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
  761. unsigned int reservelen, isc_mem_t *mctx,
  762. dns_rdataclass_t rdclass, dns_rdatatype_t type,
  763. unsigned int flags, unsigned char **tslabp)
  764. {
  765. unsigned char *mcurrent, *sstart, *scurrent, *tstart, *tcurrent;
  766. unsigned int mcount, scount, rcount ,count, tlength, tcount, i;
  767. dns_rdata_t srdata = DNS_RDATA_INIT;
  768. dns_rdata_t mrdata = DNS_RDATA_INIT;
  769. #if DNS_RDATASET_FIXED
  770. unsigned char *offsetbase;
  771. unsigned int *offsettable;
  772. unsigned int order;
  773. #endif
  774. REQUIRE(tslabp != NULL && *tslabp == NULL);
  775. REQUIRE(mslab != NULL && sslab != NULL);
  776. mcurrent = mslab + reservelen;
  777. mcount = *mcurrent++ * 256;
  778. mcount += *mcurrent++;
  779. scurrent = sslab + reservelen;
  780. scount = *scurrent++ * 256;
  781. scount += *scurrent++;
  782. INSIST(mcount > 0 && scount > 0);
  783. /*
  784. * Yes, this is inefficient!
  785. */
  786. /*
  787. * Start figuring out the target length and count.
  788. */
  789. tlength = reservelen + 2;
  790. tcount = 0;
  791. rcount = 0;
  792. #if DNS_RDATASET_FIXED
  793. mcurrent += 4 * mcount;
  794. scurrent += 4 * scount;
  795. #endif
  796. sstart = scurrent;
  797. /*
  798. * Add in the length of rdata in the mslab that aren't in
  799. * the sslab.
  800. */
  801. for (i = 0; i < mcount; i++) {
  802. unsigned char *mrdatabegin = mcurrent;
  803. rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
  804. scurrent = sstart;
  805. for (count = 0; count < scount; count++) {
  806. dns_rdata_reset(&srdata);
  807. rdata_from_slab(&scurrent, rdclass, type, &srdata);
  808. if (dns_rdata_compare(&mrdata, &srdata) == 0)
  809. break;
  810. }
  811. if (count == scount) {
  812. /*
  813. * This rdata isn't in the sslab, and thus isn't
  814. * being subtracted.
  815. */
  816. tlength += mcurrent - mrdatabegin;
  817. tcount++;
  818. } else
  819. rcount++;
  820. dns_rdata_reset(&mrdata);
  821. }
  822. #if DNS_RDATASET_FIXED
  823. tlength += (4 * tcount);
  824. #endif
  825. /*
  826. * Check that all the records originally existed. The numeric
  827. * check only works as rdataslabs do not contain duplicates.
  828. */
  829. if (((flags & DNS_RDATASLAB_EXACT) != 0) && (rcount != scount))
  830. return (DNS_R_NOTEXACT);
  831. /*
  832. * Don't continue if the new rdataslab would be empty.
  833. */
  834. if (tcount == 0)
  835. return (DNS_R_NXRRSET);
  836. /*
  837. * If nothing is going to change, we can stop.
  838. */
  839. if (rcount == 0)
  840. return (DNS_R_UNCHANGED);
  841. /*
  842. * Copy the reserved area from the mslab.
  843. */
  844. tstart = isc_mem_get(mctx, tlength);
  845. if (tstart == NULL)
  846. return (ISC_R_NOMEMORY);
  847. memcpy(tstart, mslab, reservelen);
  848. tcurrent = tstart + reservelen;
  849. #if DNS_RDATASET_FIXED
  850. offsetbase = tcurrent;
  851. offsettable = isc_mem_get(mctx, mcount * sizeof(unsigned int));
  852. if (offsettable == NULL) {
  853. isc_mem_put(mctx, tstart, tlength);
  854. return (ISC_R_NOMEMORY);
  855. }
  856. memset(offsettable, 0, mcount * sizeof(unsigned int));
  857. #endif
  858. /*
  859. * Write the new count.
  860. */
  861. *tcurrent++ = (tcount & 0xff00) >> 8;
  862. *tcurrent++ = (tcount & 0x00ff);
  863. #if DNS_RDATASET_FIXED
  864. tcurrent += (4 * tcount);
  865. #endif
  866. /*
  867. * Copy the parts of mslab not in sslab.
  868. */
  869. mcurrent = mslab + reservelen;
  870. mcount = *mcurrent++ * 256;
  871. mcount += *mcurrent++;
  872. #if DNS_RDATASET_FIXED
  873. mcurrent += (4 * mcount);
  874. #endif
  875. for (i = 0; i < mcount; i++) {
  876. unsigned char *mrdatabegin = mcurrent;
  877. #if DNS_RDATASET_FIXED
  878. order = mcurrent[2] * 256 + mcurrent[3];
  879. INSIST(order < mcount);
  880. #endif
  881. rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
  882. scurrent = sstart;
  883. for (count = 0; count < scount; count++) {
  884. dns_rdata_reset(&srdata);
  885. rdata_from_slab(&scurrent, rdclass, type, &srdata);
  886. if (dns_rdata_compare(&mrdata, &srdata) == 0)
  887. break;
  888. }
  889. if (count == scount) {
  890. /*
  891. * This rdata isn't in the sslab, and thus should be
  892. * copied to the tslab.
  893. */
  894. unsigned int length = mcurrent - mrdatabegin;
  895. #if DNS_RDATASET_FIXED
  896. offsettable[order] = tcurrent - offsetbase;
  897. #endif
  898. memcpy(tcurrent, mrdatabegin, length);
  899. tcurrent += length;
  900. }
  901. dns_rdata_reset(&mrdata);
  902. }
  903. #if DNS_RDATASET_FIXED
  904. fillin_offsets(offsetbase, offsettable, mcount);
  905. isc_mem_put(mctx, offsettable, mcount * sizeof(unsigned int));
  906. #endif
  907. INSIST(tcurrent == tstart + tlength);
  908. *tslabp = tstart;
  909. return (ISC_R_SUCCESS);
  910. }
  911. isc_boolean_t
  912. dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2,
  913. unsigned int reservelen)
  914. {
  915. unsigned char *current1, *current2;
  916. unsigned int count1, count2;
  917. unsigned int length1, length2;
  918. current1 = slab1 + reservelen;
  919. count1 = *current1++ * 256;
  920. count1 += *current1++;
  921. current2 = slab2 + reservelen;
  922. count2 = *current2++ * 256;
  923. count2 += *current2++;
  924. if (count1 != count2)
  925. return (ISC_FALSE);
  926. #if DNS_RDATASET_FIXED
  927. current1 += (4 * count1);
  928. current2 += (4 * count2);
  929. #endif
  930. while (count1 > 0) {
  931. length1 = *current1++ * 256;
  932. length1 += *current1++;
  933. length2 = *current2++ * 256;
  934. length2 += *current2++;
  935. #if DNS_RDATASET_FIXED
  936. current1 += 2;
  937. current2 += 2;
  938. #endif
  939. if (length1 != length2 ||
  940. memcmp(current1, current2, length1) != 0)
  941. return (ISC_FALSE);
  942. current1 += length1;
  943. current2 += length1;
  944. count1--;
  945. }
  946. return (ISC_TRUE);
  947. }
  948. isc_boolean_t
  949. dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
  950. unsigned int reservelen, dns_rdataclass_t rdclass,
  951. dns_rdatatype_t type)
  952. {
  953. unsigned char *current1, *current2;
  954. unsigned int count1, count2;
  955. dns_rdata_t rdata1 = DNS_RDATA_INIT;
  956. dns_rdata_t rdata2 = DNS_RDATA_INIT;
  957. current1 = slab1 + reservelen;
  958. count1 = *current1++ * 256;
  959. count1 += *current1++;
  960. current2 = slab2 + reservelen;
  961. count2 = *current2++ * 256;
  962. count2 += *current2++;
  963. if (count1 != count2)
  964. return (ISC_FALSE);
  965. #if DNS_RDATASET_FIXED
  966. current1 += (4 * count1);
  967. current2 += (4 * count2);
  968. #endif
  969. while (count1-- > 0) {
  970. rdata_from_slab(&current1, rdclass, type, &rdata1);
  971. rdata_from_slab(&current2, rdclass, type, &rdata2);
  972. if (dns_rdata_compare(&rdata1, &rdata2) != 0)
  973. return (ISC_FALSE);
  974. dns_rdata_reset(&rdata1);
  975. dns_rdata_reset(&rdata2);
  976. }
  977. return (ISC_TRUE);
  978. }