1 /* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 * SPDX-License-Identifier: GPL-3.0-or-later
3 */
4
5 /** @file
6 * Implementation of preparing knot_pkt_t for filling with RRs.
7 * Prototypes in ./impl.h
8 */
9
10 #include "lib/cache/impl.h"
11
pkt_renew(knot_pkt_t * pkt,const knot_dname_t * name,uint16_t type)12 int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type)
13 {
14 /* Update packet question if needed. */
15 if (!knot_dname_is_equal(knot_pkt_qname(pkt), name)
16 || knot_pkt_qtype(pkt) != type || knot_pkt_qclass(pkt) != KNOT_CLASS_IN) {
17 int ret = kr_pkt_recycle(pkt);
18 if (ret) return kr_error(ret);
19 ret = knot_pkt_put_question(pkt, name, KNOT_CLASS_IN, type);
20 if (ret) return kr_error(ret);
21 }
22
23 pkt->parsed = pkt->size = PKT_SIZE_NOWIRE;
24 knot_wire_set_qr(pkt->wire);
25 knot_wire_set_aa(pkt->wire);
26 return kr_ok();
27 }
28
29 /** Reserve space for additional `count` RRsets.
30 * \note pkt->rr_info gets correct length but is always zeroed
31 */
pkt_alloc_space(knot_pkt_t * pkt,int count)32 static int pkt_alloc_space(knot_pkt_t *pkt, int count)
33 {
34 size_t allocd_orig = pkt->rrset_allocd;
35 if (pkt->rrset_count + count <= allocd_orig) {
36 return kr_ok();
37 }
38 /* A simple growth strategy, amortized O(count). */
39 pkt->rrset_allocd = MAX(
40 pkt->rrset_count + count,
41 pkt->rrset_count + allocd_orig);
42
43 pkt->rr = mm_realloc(&pkt->mm, pkt->rr,
44 sizeof(pkt->rr[0]) * pkt->rrset_allocd,
45 sizeof(pkt->rr[0]) * allocd_orig);
46 if (!pkt->rr) {
47 return kr_error(ENOMEM);
48 }
49 /* Allocate pkt->rr_info to be certain, but just leave it zeroed. */
50 mm_free(&pkt->mm, pkt->rr_info);
51 pkt->rr_info = mm_calloc(&pkt->mm, pkt->rrset_allocd, sizeof(pkt->rr_info[0]));
52 if (!pkt->rr_info) {
53 return kr_error(ENOMEM);
54 }
55 return kr_ok();
56 }
57
pkt_append(knot_pkt_t * pkt,const struct answer_rrset * rrset,uint8_t rank)58 int pkt_append(knot_pkt_t *pkt, const struct answer_rrset *rrset, uint8_t rank)
59 {
60 /* allocate space, to be sure */
61 int rrset_cnt = (rrset->set.rr->rrs.count > 0) + (rrset->sig_rds.count > 0);
62 int ret = pkt_alloc_space(pkt, rrset_cnt);
63 if (ret) return kr_error(ret);
64 /* write both sets */
65 const knot_rdataset_t *rdss[2] = { &rrset->set.rr->rrs, &rrset->sig_rds };
66 for (int i = 0; i < rrset_cnt; ++i) {
67 if (kr_fails_assert(rdss[i]->count))
68 return kr_error(EINVAL);
69 /* allocate rank */
70 uint8_t *rr_rank = mm_alloc(&pkt->mm, sizeof(*rr_rank));
71 if (!rr_rank) return kr_error(ENOMEM);
72 *rr_rank = (i == 0) ? rank : (KR_RANK_OMIT | KR_RANK_AUTH);
73 /* rank for RRSIGs isn't really useful: ^^ */
74 if (i == 0) {
75 pkt->rr[pkt->rrset_count] = *rrset->set.rr;
76 pkt->rr[pkt->rrset_count].additional = rr_rank;
77 } else {
78 /* append the RR array */
79 pkt->rr[pkt->rrset_count] = (knot_rrset_t){
80 .owner = knot_dname_copy(rrset->set.rr->owner, &pkt->mm),
81 /* ^^ well, another copy isn't really needed */
82 .ttl = rrset->set.rr->ttl,
83 .type = KNOT_RRTYPE_RRSIG,
84 .rclass = KNOT_CLASS_IN,
85 .rrs = *rdss[i],
86 .additional = rr_rank,
87 };
88 }
89 ++pkt->rrset_count;
90 ++(pkt->sections[pkt->current].count);
91 }
92 return kr_ok();
93 }
94
95