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