1 /**
2 * Insert an RR into an RRset array.
3 *
4 * This function is destructive. No copying is performed; instead the RR's name
5 * and/or rdata fields are detached from the RR and given to an RRset in the
6 * RRset array. wdns_clear_rr() is called on the RR object.
7 *
8 * \return wdns_res_success
9 * \return wdns_res_malloc
10 */
11
12 wdns_res
_wdns_insert_rr_rrset_array(wdns_rrset_array_t * a,wdns_rr_t * rr,unsigned sec)13 _wdns_insert_rr_rrset_array(wdns_rrset_array_t *a, wdns_rr_t *rr, unsigned sec)
14 {
15 bool found_rrset = false;
16 wdns_rdata_t *rdata;
17 wdns_rr_t *new_rr;
18 wdns_rrset_t *rrset;
19
20 /* add to RR array */
21 a->n_rrs += 1;
22 a->rrs = my_realloc(a->rrs, a->n_rrs * sizeof(wdns_rr_t));
23 new_rr = &a->rrs[a->n_rrs - 1];
24 new_rr->rrttl = rr->rrttl;
25 new_rr->rrtype = rr->rrtype;
26 new_rr->rrclass = rr->rrclass;
27 new_rr->name.len = rr->name.len;
28
29 /* copy the owner name */
30 new_rr->name.data = my_malloc(rr->name.len);
31 memcpy(new_rr->name.data, rr->name.data, rr->name.len);
32
33 /* copy the rdata */
34 if (sec != WDNS_MSG_SEC_QUESTION) {
35 new_rr->rdata = my_malloc(sizeof(wdns_rdata_t) + rr->rdata->len);
36 new_rr->rdata->len = rr->rdata->len;
37 memcpy(new_rr->rdata->data, rr->rdata->data, rr->rdata->len);
38 } else {
39 new_rr->rdata = NULL;
40 }
41
42 /* iterate over RRset array backwards */
43 for (unsigned i = a->n_rrsets; i > 0; i--) {
44 if (sec == WDNS_MSG_SEC_QUESTION)
45 break;
46
47 rrset = &a->rrsets[i - 1];
48
49 if (wdns_compare_rr_rrset(rr, rrset)) {
50 /* this RR is part of the RRset */
51 rrset->n_rdatas += 1;
52 rrset->rdatas = my_realloc(rrset->rdatas,
53 rrset->n_rdatas * sizeof(*(rrset->rdatas)));
54
55 /* detach the rdata from the RR and give it to the RRset */
56 rdata = rr->rdata;
57 rr->rdata = NULL;
58 rrset->rdatas[rrset->n_rdatas - 1] = rdata;
59
60 /* use the lowest TTL out of the RRs for the RRset itself */
61 if (rr->rrttl < rrset->rrttl)
62 rrset->rrttl = rr->rrttl;
63
64 found_rrset = true;
65 break;
66 }
67 }
68
69 if (found_rrset == false) {
70 /* create a new RRset */
71 a->n_rrsets += 1;
72 a->rrsets = my_realloc(a->rrsets, a->n_rrsets * sizeof(wdns_rrset_t));
73 rrset = &a->rrsets[a->n_rrsets - 1];
74 memset(rrset, 0, sizeof(*rrset));
75
76 /* copy fields from the RR */
77 rrset->rrttl = rr->rrttl;
78 rrset->rrtype = rr->rrtype;
79 rrset->rrclass = rr->rrclass;
80
81 /* add rdata */
82 if (sec != WDNS_MSG_SEC_QUESTION) {
83 rrset->n_rdatas = 1;
84 rrset->rdatas = my_malloc(sizeof(*(rrset->rdatas)));
85 }
86
87 /* detach the owner name from the RR and give it to the RRset */
88 rrset->name.len = rr->name.len;
89 rrset->name.data = rr->name.data;
90 rr->name.len = 0;
91 rr->name.data = NULL;
92
93 /* detach the rdata from the RR and give it to the RRset */
94 if (sec != WDNS_MSG_SEC_QUESTION) {
95 rdata = rr->rdata;
96 rr->rdata = NULL;
97 rrset->rdatas[0] = rdata;
98 }
99 }
100
101 wdns_clear_rr(rr);
102 return (wdns_res_success);
103 }
104