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