1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup dnscore
36 * @ingroup dnscore
37 * @brief Wire resource record reader
38 *
39 * Wire resource record reader
40 *
41 * @{
42 */
43
44 #include "dnscore/dnscore-config.h"
45 #include "dnscore/dnscore-config.h"
46
47 #include <arpa/inet.h>
48 #include <dnscore/dns_resource_record.h>
49 #include <dnscore/dnskey-signature.h>
50
51 #define RRRDATA_TAG 0x0041544144525252
52
53 void
dns_resource_record_init(dns_resource_record * rr)54 dns_resource_record_init(dns_resource_record *rr)
55 {
56 #if DEBUG
57 memset(rr, 0xf1, sizeof(dns_resource_record));
58 #endif
59
60 rr->rdata = NULL;
61 rr->rdata_size = 0;
62 rr->rdata_buffer_size = 0;
63 }
64
65 void
dns_resource_record_clear(dns_resource_record * rr)66 dns_resource_record_clear(dns_resource_record *rr)
67 {
68 if(rr->rdata != NULL)
69 {
70 #if DEBUG
71 memset(rr->rdata, 0xfe, rr->rdata_size);
72 #endif
73 yassert(rr->rdata_buffer_size > 0);
74 free(rr->rdata);
75 rr->rdata = NULL;
76 rr->rdata_size = 0;
77 rr->rdata_buffer_size = 0;
78 }
79 }
80
81 ya_result
dns_resource_record_set_fqdn(dns_resource_record * rr,const u8 * fqdn)82 dns_resource_record_set_fqdn(dns_resource_record *rr, const u8* fqdn)
83 {
84 u32 len = dnsname_len(fqdn);
85 if(len <= sizeof(rr->name))
86 {
87 memcpy(rr->name, fqdn, len);
88 rr->name_len = len;
89 return len;
90 }
91 else
92 {
93 return DOMAIN_TOO_LONG;
94 }
95 }
96
97 ya_result
dns_resource_record_set_record(dns_resource_record * rr,const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,u16 rdata_size,const u8 * rdata)98 dns_resource_record_set_record(dns_resource_record *rr, const u8* fqdn, u16 rtype, u16 rclass, s32 ttl, u16 rdata_size, const u8 *rdata)
99 {
100 ya_result ret;
101 if(ISOK(ret = dns_resource_record_set_fqdn(rr, fqdn)))
102 {
103 rr->tctr.qtype = rtype;
104 rr->tctr.qclass = rclass;
105 rr->tctr.rdlen = htons(rdata_size);
106 rr->tctr.ttl = htonl(ttl);
107 rr->rdata_size = rdata_size;
108
109 if(rr->rdata_size > 0)
110 {
111 if(rr->rdata_buffer_size < rdata_size)
112 {
113 u8 *tmp;
114
115 // do the computations into 32 bits words
116
117 u32 rdata_size_32 = rr->rdata_size;
118 u32 buffer_size_32 = MIN((rdata_size_32 + 15) & 0xfff0, 0xffff);
119 #if DEBUG
120 if(rr->rdata != NULL)
121 {
122 memset(rr->rdata, 0xfe, rr->rdata_buffer_size);
123 }
124 #endif
125 rr->rdata_buffer_size = buffer_size_32;
126
127 MALLOC_OR_DIE(u8*, tmp, rr->rdata_buffer_size, RRRDATA_TAG);
128
129 free(rr->rdata);
130 rr->rdata = tmp;
131 }
132
133 memcpy(rr->rdata, rdata, rdata_size); // rdata_size != 0 => rdata != 0 && rr->rdata != NULL ; also: VS false positive (nonsense)
134 }
135 }
136
137 return ret;
138 }
139
140 ya_result
dns_resource_record_init_record(dns_resource_record * rr,const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,u16 rdata_size,const u8 * rdata)141 dns_resource_record_init_record(dns_resource_record *rr, const u8* fqdn, u16 rtype, u16 rclass, s32 ttl, u16 rdata_size, const u8 *rdata)
142 {
143 yassert((rdata != NULL) && (rdata_size > 0));
144 ya_result ret;
145 dns_resource_record_init(rr);
146 ret = dns_resource_record_set_record(rr, fqdn, rtype, rclass, ttl, rdata_size, rdata);
147 return ret;
148 }
149
150 ya_result
dns_resource_init_from_record(dns_resource_record * rr,const dns_resource_record * src)151 dns_resource_init_from_record(dns_resource_record *rr, const dns_resource_record *src)
152 {
153 yassert((src != NULL) && (src->rdata != NULL) && (src->rdata_size > 0));
154 ya_result ret;
155 ret = dns_resource_record_init_record(rr, src->name, src->tctr.qtype, src->tctr.qclass, ntohl(src->tctr.ttl), src->rdata_size, src->rdata);
156 return ret;
157 }
158
159 ya_result
dns_resource_set_from_record(dns_resource_record * rr,const dns_resource_record * src)160 dns_resource_set_from_record(dns_resource_record *rr, const dns_resource_record *src)
161 {
162 ya_result ret;
163 ret = dns_resource_record_set_record(rr, src->name, src->tctr.qtype, src->tctr.qclass, ntohl(src->tctr.ttl), src->rdata_size, src->rdata);
164 return ret;
165 }
166
167 /**
168 *
169 * This utility function reads an uncompressed record from a stream.
170 * Compression has to be handled by the underlying input_stream
171 * If an error code is returned, then most likely the stream is broken.
172 *
173 * @param is
174 * @param rr
175 *
176 * @return an error code or the number of bytes read
177 */
178
179 ya_result
dns_resource_record_read(dns_resource_record * rr,input_stream * is)180 dns_resource_record_read(dns_resource_record *rr, input_stream *is)
181 {
182 ya_result ret;
183
184 if(FAIL(ret = input_stream_read_dnsname(is, &rr->name[0])))
185 {
186 return ret;
187 }
188
189 if(ret == 0)
190 {
191 return 0;
192 }
193
194 rr->name_len = ret;
195
196 if(FAIL(ret = input_stream_read_fully(is, &rr->tctr, 10))) /* cannot use sizeof(tctr) */
197 {
198 return ret;
199 }
200
201 rr->rdata_size = htons(rr->tctr.rdlen);
202
203 if(rr->rdata_buffer_size < rr->rdata_size)
204 {
205 u8 *tmp;
206
207 // do the computations into 32 bits words
208
209 u32 rdata_size = rr->rdata_size;
210 u32 buffer_size = MIN((rdata_size + 255) & 0xff00, 0xffff);
211
212 #if DEBUG
213 memset(rr->rdata, 0xfe, rr->rdata_buffer_size);
214 #endif
215
216 rr->rdata_buffer_size = buffer_size;
217
218 MALLOC_OR_DIE(u8*, tmp, rr->rdata_buffer_size, RRRDATA_TAG);
219
220 free(rr->rdata);
221 rr->rdata = tmp;
222 }
223
224 if(FAIL(ret = input_stream_read_fully(is, rr->rdata, rr->rdata_size)))
225 {
226 return ret;
227 }
228
229 #if DEBUG
230 memset(&rr->rdata[rr->rdata_size], 0xee, rr->rdata_buffer_size - rr->rdata_size);
231 #endif
232
233 return rr->name_len + 10 + rr->rdata_size; /* total bytes read */
234 }
235
236 /**
237 *
238 * This utility function writes an uncompressed record to a stream.
239 * Compression has to be handled by the underlying output_stream
240 * If an error code is returned, then most likely the stream is broken.
241 *
242 * @param os
243 * @param rr
244 *
245 * @return an error code or the number of bytes written
246 */
247
248 ya_result
dns_resource_record_write(const dns_resource_record * rr,output_stream * os)249 dns_resource_record_write(const dns_resource_record *rr, output_stream *os)
250 {
251 ya_result return_value;
252
253 if(FAIL(return_value = output_stream_write(os, rr->name, rr->name_len)))
254 {
255 return return_value;
256 }
257
258 if(FAIL(return_value = output_stream_write(os, (u8*)&rr->tctr, 10)))
259 {
260 return return_value;
261 }
262
263 if(FAIL(return_value = output_stream_write(os, rr->rdata, rr->rdata_size)))
264 {
265 return return_value;
266 }
267
268 return rr->name_len + 10 + rr->rdata_size; /* total bytes read */
269 }
270
271 bool
dns_resource_record_equals(const dns_resource_record * a,const dns_resource_record * b)272 dns_resource_record_equals(const dns_resource_record *a, const dns_resource_record *b)
273 {
274 if((a->rdata_size == b->rdata_size) && (a->name_len == b->name_len))
275 {
276 if(memcmp(&a->tctr, &b->tctr, sizeof(a->tctr)) == 0)
277 {
278 if(dnsname_equals(a->name, b->name))
279 {
280 if(memcmp(a->rdata, b->rdata, a->rdata_size) == 0)
281 {
282 return TRUE;
283 }
284 }
285 }
286 }
287
288 return FALSE;
289 }
290
291 bool
dns_resource_record_match(const dns_resource_record * a,const dns_resource_record * b)292 dns_resource_record_match(const dns_resource_record *a, const dns_resource_record *b)
293 {
294 if((a->rdata_size == b->rdata_size) && (a->name_len == b->name_len))
295 {
296 if((a->tctr.qtype == b->tctr.qtype) && (a->tctr.qclass == b->tctr.qclass) && (a->tctr.rdlen == b->tctr.rdlen))
297 {
298 if(dnsname_equals(a->name, b->name))
299 {
300 if(memcmp(a->rdata, b->rdata, a->rdata_size) == 0)
301 {
302 return TRUE;
303 }
304 }
305 }
306 }
307
308 return FALSE;
309 }
310
311 int
dns_resource_record_compare(const dns_resource_record * a,const dns_resource_record * b)312 dns_resource_record_compare(const dns_resource_record *a, const dns_resource_record *b)
313 {
314 int d;
315
316 d = dnsname_compare(a->name, b->name);
317
318 if(d == 0)
319 {
320 d = a->tctr.qclass;
321 d -= b->tctr.qclass;
322
323 if(d == 0)
324 {
325 d = a->tctr.qtype;
326 d -= b->tctr.qtype;
327
328 if(d == 0)
329 {
330 d = a->tctr.ttl;
331 d -= b->tctr.ttl;
332
333 if(d == 0)
334 {
335 d = a->rdata_size;
336 d -= b->rdata_size;
337
338 if(d == 0)
339 {
340 d = memcmp(a->rdata, b->rdata, a->rdata_size);
341 }
342 }
343 }
344 }
345 }
346
347 return d;
348 }
349
350 int
ptr_set_dns_resource_record_node_compare(const void * node_a,const void * node_b)351 ptr_set_dns_resource_record_node_compare(const void *node_a, const void *node_b)
352 {
353 if(node_a != NULL)
354 {
355 if(node_b != NULL)
356 {
357 return dns_resource_record_compare((const dns_resource_record*)node_a, (const dns_resource_record*)node_b);
358 }
359 else
360 {
361 return -1;
362 }
363 }
364 else
365 {
366 return (node_b == NULL)?0:1;
367 }
368 }
369
dns_resource_record_view_get_fqdn(void * data,const void * rr_)370 static const u8* dns_resource_record_view_get_fqdn(void *data, const void *rr_)
371 {
372 (void)data;
373 const dns_resource_record* rr = (const dns_resource_record*)rr_;
374 return rr->name;
375 }
376
dns_resource_record_view_get_type(void * data,const void * rr_)377 static u16 dns_resource_record_view_get_type(void *data, const void *rr_)
378 {
379 (void)data;
380 const dns_resource_record* rr = (const dns_resource_record*)rr_;
381 return rr->tctr.qtype;
382 }
383
dns_resource_record_view_get_class(void * data,const void * rr_)384 static u16 dns_resource_record_view_get_class(void *data, const void *rr_)
385 {
386 (void)data;
387 const dns_resource_record* rr = (const dns_resource_record*)rr_;
388 return rr->tctr.qclass;
389 }
390
dns_resource_record_view_get_ttl(void * data,const void * rr_)391 static s32 dns_resource_record_view_get_ttl(void *data, const void *rr_)
392 {
393 (void)data;
394 const dns_resource_record* rr = (const dns_resource_record*)rr_;
395 return ntohl(rr->tctr.ttl);
396 }
397
dns_resource_record_view_get_rdata_size(void * data,const void * rr_)398 static u16 dns_resource_record_view_get_rdata_size(void *data, const void *rr_)
399 {
400 (void)data;
401 const dns_resource_record* rr = (const dns_resource_record*)rr_;
402 return rr->rdata_size;
403 }
404
dns_resource_record_view_get_rdata(void * data,const void * rr_)405 static const u8* dns_resource_record_view_get_rdata(void *data, const void *rr_)
406 {
407 (void)data;
408 const dns_resource_record* rr = (const dns_resource_record*)rr_;
409 return rr->rdata;
410 }
411
412 /// @todo 20190820 edf -- replace the malloc by a zalloc, check for usage first.
dns_resource_record_view_new_instance(void * data,const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,u16 rdata_size,const u8 * rdata)413 static void *dns_resource_record_view_new_instance(void *data, const u8 *fqdn, u16 rtype, u16 rclass, s32 ttl, u16 rdata_size, const u8 *rdata)
414 {
415 (void)data;
416 dns_resource_record* rr;
417 ZALLOC_OBJECT_OR_DIE(rr, dns_resource_record, DNSRREC_TAG);
418 dns_resource_record_init_record(rr, fqdn, rtype, rclass, ttl, rdata_size, rdata);
419 return rr;
420 }
421
422 static resource_record_view_vtbl dns_resource_record_view_vtbl =
423 {
424 dns_resource_record_view_get_fqdn,
425 dns_resource_record_view_get_type,
426 dns_resource_record_view_get_class,
427 dns_resource_record_view_get_ttl,
428 dns_resource_record_view_get_rdata_size,
429 dns_resource_record_view_get_rdata,
430 dns_resource_record_view_new_instance
431 };
432
433 void
dns_resource_record_resource_record_view_init(struct resource_record_view * rrv)434 dns_resource_record_resource_record_view_init(struct resource_record_view *rrv)
435 {
436 rrv->data = NULL;
437 rrv->vtbl = &dns_resource_record_view_vtbl;
438 }
439
440 void
dns_resource_record_resource_record_view_finalise(struct resource_record_view * rrv)441 dns_resource_record_resource_record_view_finalise(struct resource_record_view *rrv)
442 {
443 rrv->vtbl = NULL;
444 }
445
446 /** @} */
447