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