Coverage Report

Created: 2025-11-24 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdataslab.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <ctype.h>
17
#include <stdbool.h>
18
#include <stdlib.h>
19
20
#include <isc/ascii.h>
21
#include <isc/atomic.h>
22
#include <isc/mem.h>
23
#include <isc/region.h>
24
#include <isc/result.h>
25
#include <isc/string.h>
26
#include <isc/util.h>
27
28
#include <dns/db.h>
29
#include <dns/rdata.h>
30
#include <dns/rdataset.h>
31
#include <dns/rdataslab.h>
32
#include <dns/stats.h>
33
34
#include "rdataslab_p.h"
35
36
/*
37
 * The memory structure of an rdataslab is as follows:
38
 *
39
 *  header    (dns_slabheader_t)
40
 *  record count  (2 bytes)
41
 *  data records
42
 *    data length (2 bytes)
43
 *    order   (2 bytes)
44
 *    meta data (1 byte for RRSIG, 0 for all other types)
45
 *    data    (data length bytes)
46
 *
47
 * A "bare" rdataslab is everything after "header".
48
 *
49
 * When a slab is created, data records are sorted into DNSSEC order.
50
 */
51
52
static void
53
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
54
static isc_result_t
55
rdataset_first(dns_rdataset_t *rdataset);
56
static isc_result_t
57
rdataset_next(dns_rdataset_t *rdataset);
58
static void
59
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
60
static void
61
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG);
62
static unsigned int
63
rdataset_count(dns_rdataset_t *rdataset);
64
static isc_result_t
65
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
66
        dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
67
static isc_result_t
68
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
69
        dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
70
static void
71
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
72
static void
73
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG);
74
static void
75
rdataset_clearprefetch(dns_rdataset_t *rdataset);
76
static void
77
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
78
static dns_slabheader_t *
79
rdataset_getheader(const dns_rdataset_t *rdataset);
80
81
dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
82
  .disassociate = rdataset_disassociate,
83
  .first = rdataset_first,
84
  .next = rdataset_next,
85
  .current = rdataset_current,
86
  .clone = rdataset_clone,
87
  .count = rdataset_count,
88
  .getnoqname = rdataset_getnoqname,
89
  .getclosest = rdataset_getclosest,
90
  .settrust = rdataset_settrust,
91
  .expire = rdataset_expire,
92
  .clearprefetch = rdataset_clearprefetch,
93
  .getownercase = rdataset_getownercase,
94
  .getheader = rdataset_getheader,
95
};
96
97
/*% Note: the "const void *" are just to make qsort happy.  */
98
static int
99
999k
compare_rdata(const void *p1, const void *p2) {
100
999k
  return dns_rdata_compare(p1, p2);
101
999k
}
102
103
static isc_result_t
104
makeslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
105
6.43M
   uint32_t maxrrperset) {
106
  /*
107
   * Use &removed as a sentinel pointer for duplicate
108
   * rdata as rdata.data == NULL is valid.
109
   */
110
6.43M
  static unsigned char removed;
111
6.43M
  dns_rdata_t *rdata = NULL;
112
6.43M
  unsigned char *rawbuf = NULL;
113
6.43M
  unsigned int headerlen = sizeof(dns_slabheader_t);
114
6.43M
  unsigned int buflen = headerlen + 2;
115
6.43M
  isc_result_t result;
116
6.43M
  unsigned int nitems;
117
6.43M
  unsigned int nalloc;
118
6.43M
  unsigned int length;
119
6.43M
  size_t i;
120
6.43M
  size_t rdatasize;
121
122
  /*
123
   * If the source rdataset is also a slab, we don't need
124
   * to do anything special, just copy the whole slab to a
125
   * new buffer.
126
   */
127
6.43M
  if (rdataset->methods == &dns_rdataslab_rdatasetmethods) {
128
0
    dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
129
0
    buflen = dns_rdataslab_size(header);
130
131
0
    rawbuf = isc_mem_get(mctx, buflen);
132
0
    region->base = rawbuf;
133
0
    region->length = buflen;
134
135
0
    memmove(rawbuf, header, buflen);
136
0
    return ISC_R_SUCCESS;
137
0
  }
138
139
  /*
140
   * If there are no rdata then we just need to allocate a header
141
   * with a zero record count.
142
   */
143
6.43M
  nitems = dns_rdataset_count(rdataset);
144
6.43M
  if (nitems == 0) {
145
0
    if (rdataset->type != 0) {
146
0
      return ISC_R_FAILURE;
147
0
    }
148
0
    rawbuf = isc_mem_get(mctx, buflen);
149
0
    region->base = rawbuf;
150
0
    region->length = buflen;
151
0
    rawbuf += headerlen;
152
0
    put_uint16(rawbuf, 0);
153
0
    return ISC_R_SUCCESS;
154
0
  }
155
156
6.43M
  if (maxrrperset > 0 && nitems > maxrrperset) {
157
0
    return DNS_R_TOOMANYRECORDS;
158
0
  }
159
160
6.43M
  if (nitems > 0xffff) {
161
0
    return ISC_R_NOSPACE;
162
0
  }
163
164
  /*
165
   * Remember the original number of items.
166
   */
167
6.43M
  nalloc = nitems;
168
169
6.43M
  RUNTIME_CHECK(!ckd_mul(&rdatasize, nalloc, sizeof(rdata[0])));
170
6.43M
  rdata = isc_mem_get(mctx, rdatasize);
171
172
  /*
173
   * Save all of the rdata members into an array.
174
   */
175
6.43M
  result = dns_rdataset_first(rdataset);
176
6.43M
  if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
177
0
    goto free_rdatas;
178
0
  }
179
13.0M
  for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
180
6.56M
    INSIST(result == ISC_R_SUCCESS);
181
6.56M
    dns_rdata_init(&rdata[i]);
182
6.56M
    dns_rdataset_current(rdataset, &rdata[i]);
183
6.56M
    INSIST(rdata[i].data != &removed);
184
6.56M
    result = dns_rdataset_next(rdataset);
185
6.56M
  }
186
6.43M
  if (i != nalloc || result != ISC_R_NOMORE) {
187
    /*
188
     * Somehow we iterated over fewer rdatas than
189
     * dns_rdataset_count() said there were or there
190
     * were more items than dns_rdataset_count said
191
     * there were.
192
     */
193
0
    result = ISC_R_FAILURE;
194
0
    goto free_rdatas;
195
0
  }
196
197
  /*
198
   * Put into DNSSEC order.
199
   */
200
6.43M
  if (nalloc > 1U) {
201
9.10k
    qsort(rdata, nalloc, sizeof(rdata[0]), compare_rdata);
202
9.10k
  }
203
204
  /*
205
   * Remove duplicates and compute the total storage required.
206
   *
207
   * If an rdata is not a duplicate, accumulate the storage size
208
   * required for the rdata.  We do not store the class, type, etc,
209
   * just the rdata, so our overhead is 2 bytes for the number of
210
   * records, and 2 bytes for the length of each rdata, plus the
211
   * rdata itself.
212
   */
213
6.56M
  for (i = 1; i < nalloc; i++) {
214
129k
    if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) {
215
117k
      rdata[i - 1].data = &removed;
216
117k
      nitems--;
217
117k
    } else {
218
12.1k
      buflen += (2 + rdata[i - 1].length);
219
      /*
220
       * Provide space to store the per RR meta data.
221
       */
222
12.1k
      if (rdataset->type == dns_rdatatype_rrsig) {
223
2.55k
        buflen++;
224
2.55k
      }
225
12.1k
    }
226
129k
  }
227
228
  /*
229
   * Don't forget the last item!
230
   */
231
6.43M
  buflen += (2 + rdata[i - 1].length);
232
233
  /*
234
   * Provide space to store the per RR meta data.
235
   */
236
6.43M
  if (rdataset->type == dns_rdatatype_rrsig) {
237
5.57k
    buflen++;
238
5.57k
  }
239
240
  /*
241
   * Ensure that singleton types are actually singletons.
242
   */
243
6.43M
  if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
244
    /*
245
     * We have a singleton type, but there's more than one
246
     * RR in the rdataset.
247
     */
248
54
    result = DNS_R_SINGLETON;
249
54
    goto free_rdatas;
250
54
  }
251
252
  /*
253
   * Allocate the memory, set up a buffer, start copying in
254
   * data.
255
   */
256
6.43M
  rawbuf = isc_mem_get(mctx, buflen);
257
258
6.43M
  region->base = rawbuf;
259
6.43M
  region->length = buflen;
260
6.43M
  rawbuf += headerlen;
261
6.43M
  put_uint16(rawbuf, nitems);
262
263
13.0M
  for (i = 0; i < nalloc; i++) {
264
6.56M
    if (rdata[i].data == &removed) {
265
116k
      continue;
266
116k
    }
267
6.44M
    length = rdata[i].length;
268
6.44M
    if (rdataset->type == dns_rdatatype_rrsig) {
269
8.12k
      length++;
270
8.12k
    }
271
6.44M
    INSIST(length <= 0xffff);
272
273
6.44M
    put_uint16(rawbuf, length);
274
275
    /*
276
     * Store the per RR meta data.
277
     */
278
6.44M
    if (rdataset->type == dns_rdatatype_rrsig) {
279
8.12k
      *rawbuf++ = (rdata[i].flags & DNS_RDATA_OFFLINE)
280
8.12k
              ? DNS_RDATASLAB_OFFLINE
281
8.12k
              : 0;
282
8.12k
    }
283
6.44M
    if (rdata[i].length != 0) {
284
6.44M
      memmove(rawbuf, rdata[i].data, rdata[i].length);
285
6.44M
    }
286
6.44M
    rawbuf += rdata[i].length;
287
6.44M
  }
288
289
6.43M
  result = ISC_R_SUCCESS;
290
291
6.43M
free_rdatas:
292
6.43M
  isc_mem_put(mctx, rdata, rdatasize);
293
6.43M
  return result;
294
6.43M
}
295
296
isc_result_t
297
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
298
6.43M
         isc_region_t *region, uint32_t maxrrperset) {
299
6.43M
  isc_result_t result;
300
301
6.43M
  if (rdataset->type == dns_rdatatype_none &&
302
0
      rdataset->covers == dns_rdatatype_none)
303
0
  {
304
0
    return DNS_R_DISALLOWED;
305
0
  }
306
307
6.43M
  result = makeslab(rdataset, mctx, region, maxrrperset);
308
6.43M
  if (result == ISC_R_SUCCESS) {
309
6.43M
    dns_slabheader_t *new = (dns_slabheader_t *)region->base;
310
6.43M
    dns_typepair_t typepair;
311
312
6.43M
    if (rdataset->attributes.negative) {
313
0
      INSIST(rdataset->type == dns_rdatatype_none);
314
0
      INSIST(rdataset->covers != dns_rdatatype_none);
315
0
      typepair = DNS_TYPEPAIR_VALUE(rdataset->covers,
316
0
                  dns_rdatatype_none);
317
6.43M
    } else {
318
6.43M
      INSIST(rdataset->type != dns_rdatatype_none);
319
6.43M
      INSIST(dns_rdatatype_issig(rdataset->type) ||
320
6.43M
             rdataset->covers == dns_rdatatype_none);
321
6.43M
      typepair = DNS_TYPEPAIR_VALUE(rdataset->type,
322
6.43M
                  rdataset->covers);
323
6.43M
    }
324
325
6.43M
    *new = (dns_slabheader_t){
326
6.43M
      .headers_link = CDS_LIST_HEAD_INIT(new->headers_link),
327
6.43M
      .typepair = typepair,
328
6.43M
      .trust = rdataset->trust,
329
6.43M
      .ttl = rdataset->ttl,
330
6.43M
    };
331
6.43M
  }
332
333
6.43M
  return result;
334
6.43M
}
335
336
unsigned int
337
12.6M
dns_rdataslab_size(dns_slabheader_t *header) {
338
12.6M
  REQUIRE(header != NULL);
339
340
12.6M
  unsigned char *slab = (unsigned char *)header +
341
12.6M
            sizeof(dns_slabheader_t);
342
12.6M
  INSIST(slab != NULL);
343
344
12.6M
  unsigned char *current = slab;
345
12.6M
  uint16_t count = get_uint16(current);
346
347
293M
  while (count-- > 0) {
348
280M
    uint16_t length = get_uint16(current);
349
280M
    current += length;
350
280M
  }
351
352
12.6M
  return (unsigned int)(current - slab) + sizeof(dns_slabheader_t);
353
12.6M
}
354
355
unsigned int
356
6.08M
dns_rdataslab_count(dns_slabheader_t *header) {
357
6.08M
  REQUIRE(header != NULL);
358
359
6.08M
  unsigned char *current = (unsigned char *)header + sizeof(*header);
360
6.08M
  uint16_t count = get_uint16(current);
361
362
6.08M
  return count;
363
6.08M
}
364
365
/*
366
 * Make the dns_rdata_t 'rdata' refer to the slab item
367
 * beginning at '*current' (which is part of a slab of type
368
 * 'type' and class 'rdclass') and advance '*current' to
369
 * point to the next item in the slab.
370
 */
371
static void
372
rdata_from_slabitem(unsigned char **current, dns_rdataclass_t rdclass,
373
94.6M
        dns_rdatatype_t type, dns_rdata_t *rdata) {
374
94.6M
  unsigned char *tcurrent = *current;
375
94.6M
  isc_region_t region;
376
94.6M
  bool offline = false;
377
94.6M
  uint16_t length = get_uint16(tcurrent);
378
379
94.6M
  if (type == dns_rdatatype_rrsig) {
380
18.8k
    if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0) {
381
0
      offline = true;
382
0
    }
383
18.8k
    length--;
384
18.8k
    tcurrent++;
385
18.8k
  }
386
94.6M
  region.length = length;
387
94.6M
  region.base = tcurrent;
388
94.6M
  tcurrent += region.length;
389
94.6M
  dns_rdata_fromregion(rdata, rdclass, type, &region);
390
94.6M
  if (offline) {
391
0
    rdata->flags |= DNS_RDATA_OFFLINE;
392
0
  }
393
94.6M
  *current = tcurrent;
394
94.6M
}
395
396
static void
397
rdata_to_slabitem(unsigned char **current, dns_rdatatype_t type,
398
89.6M
      dns_rdata_t *rdata) {
399
89.6M
  unsigned int length = rdata->length;
400
89.6M
  unsigned char *data = rdata->data;
401
89.6M
  unsigned char *p = *current;
402
403
89.6M
  if (type == dns_rdatatype_rrsig) {
404
3.50k
    length++;
405
3.50k
    data--;
406
3.50k
  }
407
408
89.6M
  put_uint16(p, length);
409
89.6M
  memmove(p, data, length);
410
89.6M
  p += length;
411
412
89.6M
  *current = p;
413
89.6M
}
414
415
typedef struct slabinfo {
416
  unsigned char *pos;
417
  dns_rdata_t rdata;
418
  bool dup;
419
} slabinfo_t;
420
421
isc_result_t
422
dns_rdataslab_merge(dns_slabheader_t *oheader, dns_slabheader_t *nheader,
423
        isc_mem_t *mctx, dns_rdataclass_t rdclass,
424
        dns_rdatatype_t type, unsigned int flags,
425
582k
        uint32_t maxrrperset, dns_slabheader_t **theaderp) {
426
582k
  isc_result_t result = ISC_R_SUCCESS;
427
582k
  unsigned char *ocurrent = NULL, *ncurrent = NULL, *tcurrent = NULL;
428
582k
  unsigned int ocount, ncount, tlength, tcount = 0;
429
582k
  slabinfo_t *oinfo = NULL, *ninfo = NULL;
430
582k
  size_t o = 0, n = 0;
431
432
582k
  REQUIRE(theaderp != NULL && *theaderp == NULL);
433
582k
  REQUIRE(oheader != NULL && nheader != NULL);
434
435
582k
  ocurrent = (unsigned char *)oheader + sizeof(dns_slabheader_t);
436
582k
  ocount = get_uint16(ocurrent);
437
438
582k
  ncurrent = (unsigned char *)nheader + sizeof(dns_slabheader_t);
439
582k
  ncount = get_uint16(ncurrent);
440
441
582k
  INSIST(ocount > 0 && ncount > 0);
442
443
582k
  if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
444
0
    return DNS_R_TOOMANYRECORDS;
445
0
  }
446
447
  /*
448
   * Figure out the target length. Start with the header,
449
   * plus 2 octets for the count.
450
   */
451
582k
  tlength = sizeof(dns_slabheader_t) + 2;
452
453
  /*
454
   * Gather the rdatas in the old slab and add their lengths to
455
   * the larget length.
456
   */
457
582k
  oinfo = isc_mem_cget(mctx, ocount, sizeof(struct slabinfo));
458
94.5M
  for (size_t i = 0; i < ocount; i++) {
459
94.0M
    oinfo[i].pos = ocurrent;
460
94.0M
    dns_rdata_init(&oinfo[i].rdata);
461
94.0M
    rdata_from_slabitem(&ocurrent, rdclass, type, &oinfo[i].rdata);
462
94.0M
    tlength += ocurrent - oinfo[i].pos;
463
94.0M
  }
464
465
  /*
466
   * Then add the length of rdatas in the new slab that aren't
467
   * duplicated in the old slab.
468
   */
469
582k
  ninfo = isc_mem_cget(mctx, ncount, sizeof(struct slabinfo));
470
1.17M
  for (size_t i = 0; i < ncount; i++) {
471
589k
    ninfo[i].pos = ncurrent;
472
589k
    dns_rdata_init(&ninfo[i].rdata);
473
589k
    rdata_from_slabitem(&ncurrent, rdclass, type, &ninfo[i].rdata);
474
475
92.1M
    for (size_t j = 0; j < ocount; j++) {
476
92.0M
      if (oinfo[j].dup) {
477
        /*
478
         * This was already found to be
479
         * duplicated; no need to compare
480
         * it again.
481
         */
482
11.7k
        continue;
483
11.7k
      }
484
485
92.0M
      if (dns_rdata_compare(&oinfo[j].rdata,
486
92.0M
                &ninfo[i].rdata) == 0)
487
480k
      {
488
        /*
489
         * Found a dup. Mark the old copy as a
490
         * duplicate so we don't check it again;
491
         * mark the new copy as a duplicate so we
492
         * don't copy it to the target.
493
         */
494
480k
        oinfo[j].dup = ninfo[i].dup = true;
495
480k
        break;
496
480k
      }
497
92.0M
    }
498
499
589k
    if (ninfo[i].dup) {
500
480k
      continue;
501
480k
    }
502
503
    /*
504
     * We will be copying this item to the target, so
505
     * add its length to tlength and increment tcount.
506
     */
507
108k
    tlength += ncurrent - ninfo[i].pos;
508
108k
    tcount++;
509
108k
  }
510
511
  /*
512
   * If the EXACT flag is set, there can't be any rdata in
513
   * the new slab that was also in the old. If tcount is less
514
   * than ncount, then we found such a duplicate.
515
   */
516
582k
  if (((flags & DNS_RDATASLAB_EXACT) != 0) && (tcount < ncount)) {
517
0
    result = DNS_R_NOTEXACT;
518
0
    goto cleanup;
519
0
  }
520
521
  /*
522
   * If nothing's being copied in from the new slab, and the
523
   * FORCE flag isn't set, we're done.
524
   */
525
582k
  if (tcount == 0 && (flags & DNS_RDATASLAB_FORCE) == 0) {
526
469k
    result = DNS_R_UNCHANGED;
527
469k
    goto cleanup;
528
469k
  }
529
530
  /* Add to tcount the total number of items from the old slab. */
531
112k
  tcount += ocount;
532
533
  /* Resposition ncurrent at the first item. */
534
112k
  ncurrent = (unsigned char *)nheader + sizeof(dns_slabheader_t) + 2;
535
536
  /* Single types can't have more than one RR. */
537
112k
  if (tcount > 1 && dns_rdatatype_issingleton(type)) {
538
14
    result = DNS_R_SINGLETON;
539
14
    goto cleanup;
540
14
  }
541
542
112k
  if (tcount > 0xffff) {
543
0
    result = ISC_R_NOSPACE;
544
0
    goto cleanup;
545
0
  }
546
547
  /* Allocate the target buffer and copy the new slab's header */
548
112k
  unsigned char *tstart = isc_mem_get(mctx, tlength);
549
550
112k
  memmove(tstart, nheader, sizeof(dns_slabheader_t));
551
112k
  tcurrent = tstart + sizeof(dns_slabheader_t);
552
553
  /* Write the new count, then start merging the slabs. */
554
112k
  put_uint16(tcurrent, tcount);
555
556
  /*
557
   * Now walk the sets together, adding each item in DNSSEC order,
558
   * and skipping over any more dups in the new slab.
559
   */
560
89.7M
  while (o < ocount || n < ncount) {
561
89.6M
    bool fromold;
562
563
    /* Skip to the next non-duplicate in the new slab. */
564
89.6M
    for (; n < ncount && ninfo[n].dup; n++)
565
7.10k
      ;
566
567
89.6M
    if (o == ocount) {
568
88.3k
      fromold = false;
569
89.5M
    } else if (n == ncount) {
570
2.32M
      fromold = true;
571
87.2M
    } else {
572
87.2M
      fromold = dns_rdata_compare(&oinfo[o].rdata,
573
87.2M
                &ninfo[n].rdata) < 0;
574
87.2M
    }
575
576
89.6M
    if (fromold) {
577
89.5M
      rdata_to_slabitem(&tcurrent, type, &oinfo[o].rdata);
578
89.5M
      if (++o < ocount) {
579
        /* Skip to the next rdata in the old slab */
580
89.3M
        continue;
581
89.3M
      }
582
89.5M
    } else {
583
108k
      rdata_to_slabitem(&tcurrent, type, &ninfo[n++].rdata);
584
108k
    }
585
89.6M
  }
586
587
112k
  INSIST(tcurrent == tstart + tlength);
588
589
112k
  *theaderp = (dns_slabheader_t *)tstart;
590
591
582k
cleanup:
592
582k
  isc_mem_cput(mctx, oinfo, ocount, sizeof(struct slabinfo));
593
582k
  isc_mem_cput(mctx, ninfo, ncount, sizeof(struct slabinfo));
594
595
582k
  return result;
596
112k
}
597
598
isc_result_t
599
dns_rdataslab_subtract(dns_slabheader_t *oheader, dns_slabheader_t *sheader,
600
           isc_mem_t *mctx, dns_rdataclass_t rdclass,
601
           dns_rdatatype_t type, unsigned int flags,
602
0
           dns_slabheader_t **theaderp) {
603
0
  isc_result_t result = ISC_R_SUCCESS;
604
0
  unsigned char *ocurrent = NULL, *scurrent = NULL;
605
0
  unsigned char *tstart = NULL, *tcurrent = NULL;
606
0
  unsigned int ocount, scount, tlength;
607
0
  unsigned int tcount = 0, rcount = 0;
608
0
  slabinfo_t *oinfo = NULL, *sinfo = NULL;
609
610
0
  REQUIRE(theaderp != NULL && *theaderp == NULL);
611
0
  REQUIRE(oheader != NULL && sheader != NULL);
612
613
0
  ocurrent = (unsigned char *)oheader + sizeof(dns_slabheader_t);
614
0
  ocount = get_uint16(ocurrent);
615
616
0
  scurrent = (unsigned char *)sheader + sizeof(dns_slabheader_t);
617
0
  scount = get_uint16(scurrent);
618
619
0
  INSIST(ocount > 0 && scount > 0);
620
621
  /* Get info about the rdatas being subtracted */
622
0
  sinfo = isc_mem_cget(mctx, scount, sizeof(struct slabinfo));
623
0
  for (size_t i = 0; i < scount; i++) {
624
0
    sinfo[i].pos = scurrent;
625
0
    dns_rdata_init(&sinfo[i].rdata);
626
0
    rdata_from_slabitem(&scurrent, rdclass, type, &sinfo[i].rdata);
627
0
  }
628
629
  /*
630
   * Figure out the target length. Start with the header,
631
   * plus 2 octets for the count.
632
   */
633
0
  tlength = sizeof(dns_slabheader_t) + 2;
634
635
  /*
636
   * Add the length of the rdatas in the old slab that
637
   * aren't being subtracted.
638
   */
639
0
  oinfo = isc_mem_cget(mctx, ocount, sizeof(struct slabinfo));
640
0
  for (size_t i = 0; i < ocount; i++) {
641
0
    bool matched = false;
642
643
0
    oinfo[i].pos = ocurrent;
644
0
    dns_rdata_init(&oinfo[i].rdata);
645
0
    rdata_from_slabitem(&ocurrent, rdclass, type, &oinfo[i].rdata);
646
647
0
    for (size_t j = 0; j < scount; j++) {
648
0
      if (sinfo[j].dup) {
649
0
        continue;
650
0
      } else if (dns_rdata_compare(&oinfo[i].rdata,
651
0
                 &sinfo[j].rdata) == 0)
652
0
      {
653
0
        matched = true;
654
0
        oinfo[i].dup = sinfo[j].dup = true;
655
0
        break;
656
0
      }
657
0
    }
658
659
0
    if (matched) {
660
      /* This item will be subtracted. */
661
0
      rcount++;
662
0
    } else {
663
      /*
664
       * This rdata wasn't in the slab to be subtracted,
665
       * so copy it to the target.  Add its length to
666
       * tlength and increment tcount.
667
       */
668
0
      tlength += ocurrent - oinfo[i].pos;
669
0
      tcount++;
670
0
    }
671
0
  }
672
673
  /*
674
   * If the EXACT flag wasn't set, check that all the records that
675
   * were to be subtracted actually did exist in the original slab.
676
   * (The numeric check works here because rdataslabs do not contain
677
   * duplicates.)
678
   */
679
0
  if ((flags & DNS_RDATASLAB_EXACT) != 0 && rcount != scount) {
680
0
    result = DNS_R_NOTEXACT;
681
0
    goto cleanup;
682
0
  }
683
684
  /*
685
   * If the resulting rdataslab would be empty, don't bother to
686
   * create a new buffer, just return.
687
   */
688
0
  if (tcount == 0) {
689
0
    result = DNS_R_NXRRSET;
690
0
    goto cleanup;
691
0
  }
692
693
  /*
694
   * If nothing is going to change, stop.
695
   */
696
0
  if (rcount == 0) {
697
0
    result = DNS_R_UNCHANGED;
698
0
    goto cleanup;
699
0
  }
700
701
  /*
702
   * Allocate the target buffer and copy the old slab's header.
703
   */
704
0
  tstart = isc_mem_get(mctx, tlength);
705
0
  memmove(tstart, oheader, sizeof(dns_slabheader_t));
706
0
  tcurrent = tstart + sizeof(dns_slabheader_t);
707
708
  /*
709
   * Write the new count.
710
   */
711
0
  put_uint16(tcurrent, tcount);
712
713
  /*
714
   * Copy the parts of the old slab that didn't have duplicates.
715
   */
716
0
  for (size_t i = 0; i < ocount; i++) {
717
0
    if (!oinfo[i].dup) {
718
0
      rdata_to_slabitem(&tcurrent, type, &oinfo[i].rdata);
719
0
    }
720
0
  }
721
722
0
  INSIST(tcurrent == tstart + tlength);
723
724
0
  *theaderp = (dns_slabheader_t *)tstart;
725
726
0
cleanup:
727
0
  isc_mem_cput(mctx, oinfo, ocount, sizeof(struct slabinfo));
728
0
  isc_mem_cput(mctx, sinfo, scount, sizeof(struct slabinfo));
729
730
0
  return result;
731
0
}
732
733
bool
734
0
dns_rdataslab_equal(dns_slabheader_t *slab1, dns_slabheader_t *slab2) {
735
0
  unsigned char *current1 = NULL, *current2 = NULL;
736
0
  unsigned int count1, count2;
737
738
0
  current1 = (unsigned char *)slab1 + sizeof(dns_slabheader_t);
739
0
  count1 = get_uint16(current1);
740
741
0
  current2 = (unsigned char *)slab2 + sizeof(dns_slabheader_t);
742
0
  count2 = get_uint16(current2);
743
744
0
  if (count1 != count2) {
745
0
    return false;
746
0
  } else if (count1 == 0) {
747
0
    return true;
748
0
  }
749
750
0
  while (count1-- > 0) {
751
0
    unsigned int length1 = get_uint16(current1);
752
0
    unsigned int length2 = get_uint16(current2);
753
754
0
    if (length1 != length2 ||
755
0
        memcmp(current1, current2, length1) != 0)
756
0
    {
757
0
      return false;
758
0
    }
759
760
0
    current1 += length1;
761
0
    current2 += length1;
762
0
  }
763
0
  return true;
764
0
}
765
766
bool
767
dns_rdataslab_equalx(dns_slabheader_t *slab1, dns_slabheader_t *slab2,
768
0
         dns_rdataclass_t rdclass, dns_rdatatype_t type) {
769
0
  unsigned char *current1 = NULL, *current2 = NULL;
770
0
  unsigned int count1, count2;
771
772
0
  current1 = (unsigned char *)slab1 + sizeof(dns_slabheader_t);
773
0
  count1 = get_uint16(current1);
774
775
0
  current2 = (unsigned char *)slab2 + sizeof(dns_slabheader_t);
776
0
  count2 = get_uint16(current2);
777
778
0
  if (count1 != count2) {
779
0
    return false;
780
0
  } else if (count1 == 0) {
781
0
    return true;
782
0
  }
783
784
0
  while (count1-- > 0) {
785
0
    dns_rdata_t rdata1 = DNS_RDATA_INIT;
786
0
    dns_rdata_t rdata2 = DNS_RDATA_INIT;
787
788
0
    rdata_from_slabitem(&current1, rdclass, type, &rdata1);
789
0
    rdata_from_slabitem(&current2, rdclass, type, &rdata2);
790
0
    if (dns_rdata_compare(&rdata1, &rdata2) != 0) {
791
0
      return false;
792
0
    }
793
0
  }
794
0
  return true;
795
0
}
796
797
void
798
6.43M
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) {
799
6.43M
  REQUIRE(!CASESET(header));
800
801
6.43M
  bool casefullylower = true;
802
803
  /*
804
   * We do not need to worry about label lengths as they are all
805
   * less than or equal to 63.
806
   */
807
6.43M
  memset(header->upper, 0, sizeof(header->upper));
808
86.2M
  for (size_t i = 0; i < name->length; i++) {
809
79.7M
    if (isupper(name->ndata[i])) {
810
3.60M
      header->upper[i / 8] |= 1 << (i % 8);
811
3.60M
      casefullylower = false;
812
3.60M
    }
813
79.7M
  }
814
6.43M
  if (casefullylower) {
815
4.88M
    DNS_SLABHEADER_SETATTR(header,
816
4.88M
               DNS_SLABHEADERATTR_CASEFULLYLOWER);
817
4.88M
  }
818
6.43M
  DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_CASESET);
819
6.43M
}
820
821
void
822
112k
dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) {
823
112k
  REQUIRE(!CASESET(dest));
824
112k
  if (CASESET(src)) {
825
112k
    memmove(dest->upper, src->upper, sizeof(src->upper));
826
112k
    if (CASEFULLYLOWER(src)) {
827
85.3k
      DNS_SLABHEADER_SETATTR(
828
85.3k
        dest, DNS_SLABHEADERATTR_CASEFULLYLOWER);
829
85.3k
    }
830
112k
    DNS_SLABHEADER_SETATTR(dest, DNS_SLABHEADERATTR_CASESET);
831
112k
  }
832
112k
}
833
834
void
835
6.55M
dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) {
836
6.55M
  h->heap_index = 0;
837
6.55M
  h->heap = NULL;
838
6.55M
  h->node = node;
839
840
6.55M
  atomic_init(&h->attributes, 0);
841
6.55M
  atomic_init(&h->last_refresh_fail_ts, 0);
842
843
6.55M
  STATIC_ASSERT(sizeof(h->attributes) == 2,
844
6.55M
          "The .attributes field of dns_slabheader_t needs to be "
845
6.55M
          "16-bit int type exactly.");
846
6.55M
}
847
848
dns_slabheader_t *
849
0
dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) {
850
0
  dns_slabheader_t *h = NULL;
851
852
0
  h = isc_mem_get(mctx, sizeof(*h));
853
0
  *h = (dns_slabheader_t){
854
0
    .node = node,
855
0
  };
856
0
  return h;
857
0
}
858
859
void
860
6.54M
dns_slabheader_destroy(dns_slabheader_t **headerp) {
861
6.54M
  unsigned int size;
862
6.54M
  dns_slabheader_t *header = *headerp;
863
864
6.54M
  *headerp = NULL;
865
866
6.54M
  isc_mem_t *mctx = header->node->mctx;
867
6.54M
  dns_db_deletedata(header->node, header);
868
869
6.54M
  if (EXISTS(header)) {
870
6.54M
    size = dns_rdataslab_size(header);
871
18.4E
  } else {
872
18.4E
    size = sizeof(*header);
873
18.4E
  }
874
875
6.54M
  isc_mem_put(mctx, header, size);
876
6.54M
}
877
878
void
879
0
dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) {
880
0
  unsigned int buflen;
881
0
  uint8_t *rawbuf;
882
0
  dns_slabheader_proof_t *proof = *proofp;
883
0
  *proofp = NULL;
884
885
0
  if (dns_name_dynamic(&proof->name)) {
886
0
    dns_name_free(&proof->name, mctx);
887
0
  }
888
0
  if (proof->neg != NULL) {
889
0
    rawbuf = proof->neg;
890
0
    rawbuf -= sizeof(dns_slabheader_t);
891
0
    buflen = dns_rdataslab_size((dns_slabheader_t *)rawbuf);
892
893
0
    isc_mem_put(mctx, rawbuf, buflen);
894
0
  }
895
0
  if (proof->negsig != NULL) {
896
0
    rawbuf = proof->negsig;
897
0
    rawbuf -= sizeof(dns_slabheader_t);
898
0
    buflen = dns_rdataslab_size((dns_slabheader_t *)rawbuf);
899
900
0
    isc_mem_put(mctx, rawbuf, buflen);
901
0
  }
902
0
  isc_mem_put(mctx, proof, sizeof(*proof));
903
0
}
904
905
/* Fixed RRSet helper macros */
906
907
static void
908
179
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
909
179
  dns_dbnode_t *node = rdataset->slab.node;
910
911
179
  dns__db_detachnode(&node DNS__DB_FLARG_PASS);
912
179
}
913
914
static isc_result_t
915
166
rdataset_first(dns_rdataset_t *rdataset) {
916
166
  unsigned char *raw = rdataset->slab.raw;
917
166
  uint16_t count = peek_uint16(raw);
918
166
  if (count == 0) {
919
0
    rdataset->slab.iter_pos = NULL;
920
0
    rdataset->slab.iter_count = 0;
921
0
    return ISC_R_NOMORE;
922
0
  }
923
924
  /*
925
   * iter_count is the number of rdata beyond the cursor
926
   * position, so we decrement the total count by one before
927
   * storing it.
928
   *
929
   * 'raw' points to the first record.
930
   */
931
166
  rdataset->slab.iter_pos = raw + sizeof(uint16_t);
932
166
  rdataset->slab.iter_count = count - 1;
933
934
166
  return ISC_R_SUCCESS;
935
166
}
936
937
static isc_result_t
938
182
rdataset_next(dns_rdataset_t *rdataset) {
939
182
  uint16_t count = rdataset->slab.iter_count;
940
182
  if (count == 0) {
941
136
    rdataset->slab.iter_pos = NULL;
942
136
    return ISC_R_NOMORE;
943
136
  }
944
46
  rdataset->slab.iter_count = count - 1;
945
946
  /*
947
   * Skip forward one record (length + 4) or one offset (4).
948
   */
949
46
  unsigned char *raw = rdataset->slab.iter_pos;
950
46
  uint16_t length = peek_uint16(raw);
951
46
  raw += length;
952
46
  rdataset->slab.iter_pos = raw + sizeof(uint16_t);
953
954
46
  return ISC_R_SUCCESS;
955
182
}
956
957
static void
958
212
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
959
212
  unsigned char *raw = NULL;
960
212
  unsigned int length;
961
212
  isc_region_t r;
962
212
  unsigned int flags = 0;
963
964
212
  raw = rdataset->slab.iter_pos;
965
212
  REQUIRE(raw != NULL);
966
967
  /*
968
   * Find the start of the record if not already in iter_pos
969
   * then skip the length and order fields.
970
   */
971
212
  length = get_uint16(raw);
972
973
212
  if (rdataset->type == dns_rdatatype_rrsig) {
974
0
    if (*raw & DNS_RDATASLAB_OFFLINE) {
975
0
      flags |= DNS_RDATA_OFFLINE;
976
0
    }
977
0
    length--;
978
0
    raw++;
979
0
  }
980
212
  r.length = length;
981
212
  r.base = raw;
982
212
  dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
983
212
  rdata->flags |= flags;
984
212
}
985
986
static void
987
0
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
988
0
  dns_dbnode_t *node = source->slab.node;
989
0
  dns_dbnode_t *cloned_node = NULL;
990
991
0
  dns__db_attachnode(node, &cloned_node DNS__DB_FLARG_PASS);
992
0
  INSIST(!ISC_LINK_LINKED(target, link));
993
0
  *target = *source;
994
0
  ISC_LINK_INIT(target, link);
995
996
0
  target->slab.iter_pos = NULL;
997
0
  target->slab.iter_count = 0;
998
0
}
999
1000
static unsigned int
1001
0
rdataset_count(dns_rdataset_t *rdataset) {
1002
0
  unsigned char *raw = NULL;
1003
0
  unsigned int count;
1004
1005
0
  raw = rdataset->slab.raw;
1006
0
  count = get_uint16(raw);
1007
1008
0
  return count;
1009
0
}
1010
1011
static isc_result_t
1012
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
1013
        dns_rdataset_t *nsec,
1014
0
        dns_rdataset_t *nsecsig DNS__DB_FLARG) {
1015
0
  dns_db_t *db = rdataset->slab.db;
1016
0
  dns_dbnode_t *node = rdataset->slab.node;
1017
0
  const dns_slabheader_proof_t *noqname = rdataset->slab.noqname;
1018
1019
  /*
1020
   * Normally, rdataset->slab.raw points to the data immediately
1021
   * following a dns_slabheader in memory. Here, though, it will
1022
   * point to a bare rdataslab, a pointer to which is stored in
1023
   * the dns_slabheader's `noqname` field.
1024
   *
1025
   * The 'keepcase' attribute is set to prevent setownercase and
1026
   * getownercase methods from affecting the case of NSEC/NSEC3
1027
   * owner names.
1028
   */
1029
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1030
0
  *nsec = (dns_rdataset_t){
1031
0
    .methods = &dns_rdataslab_rdatasetmethods,
1032
0
    .rdclass = db->rdclass,
1033
0
    .type = noqname->type,
1034
0
    .ttl = rdataset->ttl,
1035
0
    .trust = rdataset->trust,
1036
0
    .slab.db = db,
1037
0
    .slab.node = node,
1038
0
    .slab.raw = noqname->neg,
1039
0
    .link = nsec->link,
1040
0
    .attributes = nsec->attributes,
1041
0
    .magic = nsec->magic,
1042
0
  };
1043
0
  nsec->attributes.keepcase = true;
1044
1045
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1046
0
  *nsecsig = (dns_rdataset_t){
1047
0
    .methods = &dns_rdataslab_rdatasetmethods,
1048
0
    .rdclass = db->rdclass,
1049
0
    .type = dns_rdatatype_rrsig,
1050
0
    .covers = noqname->type,
1051
0
    .ttl = rdataset->ttl,
1052
0
    .trust = rdataset->trust,
1053
0
    .slab.db = db,
1054
0
    .slab.node = node,
1055
0
    .slab.raw = noqname->negsig,
1056
0
    .link = nsecsig->link,
1057
0
    .attributes = nsecsig->attributes,
1058
0
    .magic = nsecsig->magic,
1059
0
  };
1060
0
  nsecsig->attributes.keepcase = true;
1061
1062
0
  dns_name_clone(&noqname->name, name);
1063
1064
0
  return ISC_R_SUCCESS;
1065
0
}
1066
1067
static isc_result_t
1068
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
1069
        dns_rdataset_t *nsec,
1070
0
        dns_rdataset_t *nsecsig DNS__DB_FLARG) {
1071
0
  dns_db_t *db = rdataset->slab.db;
1072
0
  dns_dbnode_t *node = rdataset->slab.node;
1073
0
  const dns_slabheader_proof_t *closest = rdataset->slab.closest;
1074
1075
  /*
1076
   * Normally, rdataset->slab.raw points to the data immediately
1077
   * following a dns_slabheader in memory. Here, though, it will
1078
   * point to a bare rdataslab, a pointer to which is stored in
1079
   * the dns_slabheader's `closest` field.
1080
   *
1081
   * The 'keepcase' attribute is set to prevent setownercase and
1082
   * getownercase methods from affecting the case of NSEC/NSEC3
1083
   * owner names.
1084
   */
1085
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1086
0
  *nsec = (dns_rdataset_t){
1087
0
    .methods = &dns_rdataslab_rdatasetmethods,
1088
0
    .rdclass = db->rdclass,
1089
0
    .type = closest->type,
1090
0
    .ttl = rdataset->ttl,
1091
0
    .trust = rdataset->trust,
1092
0
    .slab.db = db,
1093
0
    .slab.node = node,
1094
0
    .slab.raw = closest->neg,
1095
0
    .link = nsec->link,
1096
0
    .attributes = nsec->attributes,
1097
0
    .magic = nsec->magic,
1098
0
  };
1099
0
  nsec->attributes.keepcase = true;
1100
1101
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1102
0
  *nsecsig = (dns_rdataset_t){
1103
0
    .methods = &dns_rdataslab_rdatasetmethods,
1104
0
    .rdclass = db->rdclass,
1105
0
    .type = dns_rdatatype_rrsig,
1106
0
    .covers = closest->type,
1107
0
    .ttl = rdataset->ttl,
1108
0
    .trust = rdataset->trust,
1109
0
    .slab.db = db,
1110
0
    .slab.node = node,
1111
0
    .slab.raw = closest->negsig,
1112
0
    .link = nsecsig->link,
1113
0
    .attributes = nsecsig->attributes,
1114
0
    .magic = nsecsig->magic,
1115
0
  };
1116
0
  nsecsig->attributes.keepcase = true;
1117
1118
0
  dns_name_clone(&closest->name, name);
1119
1120
0
  return ISC_R_SUCCESS;
1121
0
}
1122
1123
static void
1124
0
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
1125
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1126
1127
0
  rdataset->trust = trust;
1128
0
  atomic_store(&header->trust, trust);
1129
0
}
1130
1131
static void
1132
0
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) {
1133
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1134
1135
0
  dns_db_expiredata(header->node, header);
1136
0
}
1137
1138
static void
1139
0
rdataset_clearprefetch(dns_rdataset_t *rdataset) {
1140
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1141
1142
0
  DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_PREFETCH);
1143
0
}
1144
1145
static void
1146
0
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
1147
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1148
0
  uint8_t mask = (1 << 7);
1149
0
  uint8_t bits = 0;
1150
1151
0
  if (!CASESET(header)) {
1152
0
    return;
1153
0
  }
1154
1155
0
  if (CASEFULLYLOWER(header)) {
1156
0
    isc_ascii_lowercopy(name->ndata, name->ndata, name->length);
1157
0
    return;
1158
0
  }
1159
1160
0
  uint8_t *nd = name->ndata;
1161
0
  for (size_t i = 0; i < name->length; i++) {
1162
0
    if (mask == (1 << 7)) {
1163
0
      bits = header->upper[i / 8];
1164
0
      mask = 1;
1165
0
    } else {
1166
0
      mask <<= 1;
1167
0
    }
1168
0
    nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i])
1169
0
              : isc_ascii_tolower(nd[i]);
1170
0
  }
1171
0
}
1172
1173
static dns_slabheader_t *
1174
0
rdataset_getheader(const dns_rdataset_t *rdataset) {
1175
0
  dns_slabheader_t *header = (dns_slabheader_t *)rdataset->slab.raw;
1176
0
  return header - 1;
1177
0
}
1178
1179
dns_slabtop_t *
1180
5.85M
dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair) {
1181
5.85M
  dns_slabtop_t *top = isc_mem_get(mctx, sizeof(*top));
1182
5.85M
  *top = (dns_slabtop_t){
1183
5.85M
    .types_link = CDS_LIST_HEAD_INIT(top->types_link),
1184
5.85M
    .headers = CDS_LIST_HEAD_INIT(top->headers),
1185
5.85M
    .typepair = typepair,
1186
5.85M
    .link = ISC_LINK_INITIALIZER,
1187
5.85M
  };
1188
1189
5.85M
  return top;
1190
5.85M
}
1191
1192
void
1193
5.85M
dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp) {
1194
5.85M
  REQUIRE(topp != NULL && *topp != NULL);
1195
5.85M
  dns_slabtop_t *top = *topp;
1196
5.85M
  *topp = NULL;
1197
  isc_mem_put(mctx, top, sizeof(*top));
1198
5.85M
}