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