1 /*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <assert.h>
18 #include <stdbool.h>
19 #include <stdint.h>
20 
21 #include "libknot/attribute.h"
22 #include "libknot/errcode.h"
23 #include "libknot/rrset.h"
24 #include "libknot/rrtype/naptr.h"
25 #include "libknot/rrtype/rrsig.h"
26 #include "contrib/mempattern.h"
27 
28 _public_
knot_rrset_new(const knot_dname_t * owner,uint16_t type,uint16_t rclass,uint32_t ttl,knot_mm_t * mm)29 knot_rrset_t *knot_rrset_new(const knot_dname_t *owner, uint16_t type,
30                              uint16_t rclass, uint32_t ttl, knot_mm_t *mm)
31 {
32 	knot_dname_t *owner_cpy = knot_dname_copy(owner, mm);
33 	if (owner_cpy == NULL) {
34 		return NULL;
35 	}
36 
37 	knot_rrset_t *ret = mm_alloc(mm, sizeof(knot_rrset_t));
38 	if (ret == NULL) {
39 		knot_dname_free(owner_cpy, mm);
40 		return NULL;
41 	}
42 
43 	knot_rrset_init(ret, owner_cpy, type, rclass, ttl);
44 
45 	return ret;
46 }
47 
48 _public_
knot_rrset_copy(const knot_rrset_t * src,knot_mm_t * mm)49 knot_rrset_t *knot_rrset_copy(const knot_rrset_t *src, knot_mm_t *mm)
50 {
51 	if (src == NULL) {
52 		return NULL;
53 	}
54 
55 	knot_rrset_t *rrset = knot_rrset_new(src->owner, src->type,
56 	                                     src->rclass, src->ttl, mm);
57 	if (rrset == NULL) {
58 		return NULL;
59 	}
60 
61 	int ret = knot_rdataset_copy(&rrset->rrs, &src->rrs, mm);
62 	if (ret != KNOT_EOK) {
63 		knot_rrset_free(rrset, mm);
64 		return NULL;
65 	}
66 
67 	return rrset;
68 }
69 
70 _public_
knot_rrset_free(knot_rrset_t * rrset,knot_mm_t * mm)71 void knot_rrset_free(knot_rrset_t *rrset, knot_mm_t *mm)
72 {
73 	if (rrset == NULL) {
74 		return;
75 	}
76 
77 	knot_rrset_clear(rrset, mm);
78 	mm_free(mm, rrset);
79 }
80 
81 _public_
knot_rrset_clear(knot_rrset_t * rrset,knot_mm_t * mm)82 void knot_rrset_clear(knot_rrset_t *rrset, knot_mm_t *mm)
83 {
84 	if (rrset == NULL) {
85 		return;
86 	}
87 
88 	knot_rdataset_clear(&rrset->rrs, mm);
89 	knot_dname_free(rrset->owner, mm);
90 	rrset->owner = NULL;
91 }
92 
93 _public_
knot_rrset_add_rdata(knot_rrset_t * rrset,const uint8_t * data,uint16_t len,knot_mm_t * mm)94 int knot_rrset_add_rdata(knot_rrset_t *rrset, const uint8_t *data, uint16_t len,
95                          knot_mm_t *mm)
96 {
97 	if (rrset == NULL || (data == NULL && len > 0)) {
98 		return KNOT_EINVAL;
99 	}
100 
101 	uint8_t buf[knot_rdata_size(len)];
102 	knot_rdata_t *rdata = (knot_rdata_t *)buf;
103 	knot_rdata_init(rdata, len, data);
104 
105 	return knot_rdataset_add(&rrset->rrs, rdata, mm);
106 }
107 
108 _public_
knot_rrset_equal(const knot_rrset_t * r1,const knot_rrset_t * r2,bool incl_ttl)109 bool knot_rrset_equal(const knot_rrset_t *r1,
110                       const knot_rrset_t *r2,
111                       bool incl_ttl)
112 {
113 	if (r1->type != r2->type ||
114 	    (incl_ttl && r1->ttl != r2->ttl)) {
115 		return false;
116 	}
117 
118 	if ((r1->owner != NULL || r2->owner != NULL) &&
119 	    !knot_dname_is_equal(r1->owner, r2->owner)) {
120 		return false;
121 	}
122 
123 	return knot_rdataset_eq(&r1->rrs, &r2->rrs);
124 }
125 
126 _public_
knot_rrset_is_nsec3rel(const knot_rrset_t * rr)127 bool knot_rrset_is_nsec3rel(const knot_rrset_t *rr)
128 {
129 	if (rr == NULL) {
130 		return false;
131 	}
132 
133 	/* Is NSEC3 or non-empty RRSIG covering NSEC3. */
134 	return ((rr->type == KNOT_RRTYPE_NSEC3) ||
135 	        (rr->type == KNOT_RRTYPE_RRSIG
136 	         && knot_rrsig_type_covered(rr->rrs.rdata) == KNOT_RRTYPE_NSEC3));
137 }
138 
139 _public_
knot_rrset_rr_to_canonical(knot_rrset_t * rrset)140 int knot_rrset_rr_to_canonical(knot_rrset_t *rrset)
141 {
142 	if (rrset == NULL || rrset->rrs.count != 1) {
143 		return KNOT_EINVAL;
144 	}
145 
146 	/* Convert owner for all RRSets. */
147 	knot_dname_to_lower(rrset->owner);
148 
149 	/* Convert DNAMEs in RDATA only for RFC4034 types. */
150 	if (!knot_rrtype_should_be_lowercased(rrset->type)) {
151 		return KNOT_EOK;
152 	}
153 
154 	const knot_rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type);
155 	if (desc->type_name == NULL) {
156 		desc = knot_get_obsolete_rdata_descriptor(rrset->type);
157 	}
158 
159 	uint16_t rdlen = rrset->rrs.rdata->len;
160 	uint8_t *pos = rrset->rrs.rdata->data;
161 	uint8_t *endpos = pos + rdlen;
162 
163 	/* No RDATA */
164 	if (rdlen == 0) {
165 		return KNOT_EOK;
166 	}
167 
168 	/* Otherwise, whole and not malformed RDATA are expected. */
169 	for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; ++i) {
170 		int type = desc->block_types[i];
171 		switch (type) {
172 		case KNOT_RDATA_WF_COMPRESSIBLE_DNAME:
173 		case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME:
174 		case KNOT_RDATA_WF_FIXED_DNAME:
175 			knot_dname_to_lower(pos);
176 			pos += knot_dname_size(pos);
177 			break;
178 		case KNOT_RDATA_WF_NAPTR_HEADER:
179 			; int ret = knot_naptr_header_size(pos, endpos);
180 			if (ret < 0) {
181 				return ret;
182 			}
183 
184 			pos += ret;
185 			break;
186 		case KNOT_RDATA_WF_REMAINDER:
187 			break;
188 		default:
189 			/* Fixed size block */
190 			assert(type > 0);
191 			pos += type;
192 		}
193 	}
194 
195 	return KNOT_EOK;
196 }
197 
198 _public_
knot_rrset_size(const knot_rrset_t * rrset)199 size_t knot_rrset_size(const knot_rrset_t *rrset)
200 {
201 	if (rrset == NULL) {
202 		return 0;
203 	}
204 
205 	uint16_t rr_count = rrset->rrs.count;
206 
207 	size_t total_size = knot_dname_size(rrset->owner) * rr_count;
208 
209 	knot_rdata_t *rr = rrset->rrs.rdata;
210 	for (size_t i = 0; i < rr_count; ++i) {
211 		/* 10B = TYPE + CLASS + TTL + RDLENGTH */
212 		total_size += rr->len + 10;
213 		rr = knot_rdataset_next(rr);
214 	}
215 
216 	return total_size;
217 }
218