1 /*
2  * Copyright (c) 2018-2021, OARC, Inc.
3  * All rights reserved.
4  *
5  * This file is part of dnsjit.
6  *
7  * dnsjit is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * dnsjit is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with dnsjit.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include "core/object/dns.h"
24 #include "core/object/payload.h"
25 #include "core/assert.h"
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #ifdef HAVE_ENDIAN_H
30 #include <endian.h>
31 #else
32 #ifdef HAVE_SYS_ENDIAN_H
33 #include <sys/endian.h>
34 #else
35 #ifdef HAVE_MACHINE_ENDIAN_H
36 #include <machine/endian.h>
37 #endif
38 #endif
39 #endif
40 #ifdef HAVE_BYTESWAP_H
41 #include <byteswap.h>
42 #endif
43 #ifndef bswap_16
44 #ifndef bswap16
45 #define bswap_16(x) swap16(x)
46 #define bswap_32(x) swap32(x)
47 #define bswap_64(x) swap64(x)
48 #else
49 #define bswap_16(x) bswap16(x)
50 #define bswap_32(x) bswap32(x)
51 #define bswap_64(x) bswap64(x)
52 #endif
53 #endif
54 
55 #define _ERR_MALFORMED -2
56 #define _ERR_NEEDLABELS -3
57 
58 static core_log_t        _log      = LOG_T_INIT("core.object.dns");
59 static core_object_dns_t _defaults = CORE_OBJECT_DNS_INIT(0);
60 
61 static core_object_dns_label_t _defaults_label = { 0 };
62 static core_object_dns_rr_t    _defaults_rr    = { 0 };
63 static core_object_dns_q_t     _defaults_q     = { 0 };
64 
core_object_dns_log()65 core_log_t* core_object_dns_log()
66 {
67     return &_log;
68 }
69 
core_object_dns_new()70 core_object_dns_t* core_object_dns_new()
71 {
72     core_object_dns_t* self;
73 
74     mlfatal_oom(self = malloc(sizeof(core_object_dns_t)));
75     *self = _defaults;
76 
77     return self;
78 }
79 
core_object_dns_copy(const core_object_dns_t * self)80 core_object_dns_t* core_object_dns_copy(const core_object_dns_t* self)
81 {
82     core_object_dns_t* copy;
83     mlassert_self();
84 
85     mlfatal_oom(copy = malloc(sizeof(core_object_dns_t)));
86     memcpy(copy, self, sizeof(core_object_dns_t));
87     copy->obj_prev = 0;
88 
89     return (core_object_dns_t*)copy;
90 }
91 
core_object_dns_free(core_object_dns_t * self)92 void core_object_dns_free(core_object_dns_t* self)
93 {
94     mlassert_self();
95     free(self);
96 }
97 
98 #define need8(v, p, l) \
99     if (l < 1) {       \
100         break;         \
101     }                  \
102     v = *p;            \
103     p += 1;            \
104     l -= 1
105 
_need16(const void * ptr)106 static inline uint16_t _need16(const void* ptr)
107 {
108     uint16_t v;
109     memcpy(&v, ptr, sizeof(v));
110     return be16toh(v);
111 }
112 
113 #define need16(v, p, l) \
114     if (l < 2) {        \
115         break;          \
116     }                   \
117     v = _need16(p);     \
118     p += 2;             \
119     l -= 2
120 
_need32(const void * ptr)121 static inline uint32_t _need32(const void* ptr)
122 {
123     uint32_t v;
124     memcpy(&v, ptr, sizeof(v));
125     return be32toh(v);
126 }
127 
128 #define need32(v, p, l) \
129     if (l < 4) {        \
130         break;          \
131     }                   \
132     v = _need32(p);     \
133     p += 4;             \
134     l -= 4
135 
136 #define needxb(b, x, p, l) \
137     if (l < x) {           \
138         break;             \
139     }                      \
140     memcpy(b, p, x);       \
141     p += x;                \
142     l -= x
143 
144 #define advancexb(x, p, l) \
145     if (l < x) {           \
146         break;             \
147     }                      \
148     p += x;                \
149     l -= x
150 
core_object_dns_parse_header(core_object_dns_t * self)151 int core_object_dns_parse_header(core_object_dns_t* self)
152 {
153     const core_object_payload_t* payload;
154     uint8_t                      byte;
155     mlassert_self();
156 
157     if (!(payload = (core_object_payload_t*)self->obj_prev) || payload->obj_type != CORE_OBJECT_PAYLOAD) {
158         mlfatal("no obj_prev or invalid type");
159     }
160     if (!payload->payload || !payload->len) {
161         mlfatal("no payload set or zero length");
162     }
163 
164     self->payload = self->at = payload->payload;
165     self->len = self->left = payload->len;
166 
167     for (;;) {
168         if (self->includes_dnslen) {
169             need16(self->dnslen, self->at, self->left);
170             self->have_dnslen = 1;
171         }
172         need16(self->id, self->at, self->left);
173         self->have_id = 1;
174 
175         need8(byte, self->at, self->left);
176         self->qr      = byte & (1 << 7) ? 1 : 0;
177         self->opcode  = (byte >> 3) & 0xf;
178         self->aa      = byte & (1 << 2) ? 1 : 0;
179         self->tc      = byte & (1 << 1) ? 1 : 0;
180         self->rd      = byte & (1 << 0) ? 1 : 0;
181         self->have_qr = self->have_opcode = self->have_aa = self->have_tc = self->have_rd = 1;
182 
183         need8(byte, self->at, self->left);
184         self->ra      = byte & (1 << 7) ? 1 : 0;
185         self->z       = byte & (1 << 6) ? 1 : 0;
186         self->ad      = byte & (1 << 5) ? 1 : 0;
187         self->cd      = byte & (1 << 4) ? 1 : 0;
188         self->rcode   = byte & 0xf;
189         self->have_ra = self->have_z = self->have_ad = self->have_cd = self->have_rcode = 1;
190 
191         need16(self->qdcount, self->at, self->left);
192         self->have_qdcount = 1;
193 
194         need16(self->ancount, self->at, self->left);
195         self->have_ancount = 1;
196 
197         need16(self->nscount, self->at, self->left);
198         self->have_nscount = 1;
199 
200         need16(self->arcount, self->at, self->left);
201         self->have_arcount = 1;
202 
203         return 0;
204     }
205 
206     // TODO: error here on malformed/truncated? could be quite spammy
207     return _ERR_MALFORMED;
208 }
209 
_rdata_labels(uint16_t type)210 static inline size_t _rdata_labels(uint16_t type)
211 {
212     switch (type) {
213     case CORE_OBJECT_DNS_TYPE_NS:
214     case CORE_OBJECT_DNS_TYPE_MD:
215     case CORE_OBJECT_DNS_TYPE_MF:
216     case CORE_OBJECT_DNS_TYPE_CNAME:
217     case CORE_OBJECT_DNS_TYPE_MB:
218     case CORE_OBJECT_DNS_TYPE_MG:
219     case CORE_OBJECT_DNS_TYPE_MR:
220     case CORE_OBJECT_DNS_TYPE_PTR:
221     case CORE_OBJECT_DNS_TYPE_NXT:
222     case CORE_OBJECT_DNS_TYPE_DNAME:
223     case CORE_OBJECT_DNS_TYPE_NSEC:
224     case CORE_OBJECT_DNS_TYPE_TKEY:
225     case CORE_OBJECT_DNS_TYPE_TSIG:
226         return 1;
227 
228     case CORE_OBJECT_DNS_TYPE_SOA:
229     case CORE_OBJECT_DNS_TYPE_MINFO:
230     case CORE_OBJECT_DNS_TYPE_RP:
231     case CORE_OBJECT_DNS_TYPE_TALINK:
232         return 2;
233 
234     case CORE_OBJECT_DNS_TYPE_MX:
235     case CORE_OBJECT_DNS_TYPE_AFSDB:
236     case CORE_OBJECT_DNS_TYPE_RT:
237     case CORE_OBJECT_DNS_TYPE_KX:
238     case CORE_OBJECT_DNS_TYPE_LP:
239         return 1;
240 
241     case CORE_OBJECT_DNS_TYPE_PX:
242         return 2;
243 
244     case CORE_OBJECT_DNS_TYPE_SIG:
245     case CORE_OBJECT_DNS_TYPE_RRSIG:
246         return 1;
247 
248     case CORE_OBJECT_DNS_TYPE_SRV:
249         return 1;
250 
251     case CORE_OBJECT_DNS_TYPE_NAPTR:
252         return 1;
253 
254     case CORE_OBJECT_DNS_TYPE_HIP:
255         return 1;
256 
257     default:
258         break;
259     }
260 
261     return 0;
262 }
263 
_label(core_object_dns_t * self,core_object_dns_label_t * label,size_t labels)264 static inline size_t _label(core_object_dns_t* self, core_object_dns_label_t* label, size_t labels)
265 {
266     size_t n;
267 
268     for (n = 0; self->left && n < labels; n++) {
269         core_object_dns_label_t* l = &label[n];
270         *l                         = _defaults_label;
271 
272         need8(l->length, self->at, self->left);
273 
274         if ((l->length & 0xc0) == 0xc0) {
275             need8(l->offset, self->at, self->left);
276             l->offset |= (l->length & 0x3f) << 8;
277             l->have_offset = 1;
278             return n;
279         } else if (l->length & 0xc0) {
280             l->extension_bits      = l->length >> 6;
281             l->have_extension_bits = 1;
282             return n;
283         } else if (l->length) {
284             l->have_length = 1;
285 
286             l->offset = self->at - self->payload - 1;
287             advancexb(l->length, self->at, self->left);
288             l->have_dn = 1;
289         } else {
290             l->is_end = 1;
291             return n;
292         }
293     }
294 
295     return n;
296 }
297 
core_object_dns_parse_q(core_object_dns_t * self,core_object_dns_q_t * q,core_object_dns_label_t * label,size_t labels)298 int core_object_dns_parse_q(core_object_dns_t* self, core_object_dns_q_t* q, core_object_dns_label_t* label, size_t labels)
299 {
300     mlassert_self();
301     mlassert(q, "q is nil");
302     mlassert(label, "label is nil");
303     mlassert(labels, "labels is zero");
304     mlassert(self->at, "at is nil");
305 
306     for (;;) {
307         *q        = _defaults_q;
308         q->labels = _label(self, label, labels);
309         if (q->labels < labels) {
310             core_object_dns_label_t* l = &label[q->labels];
311             if (!(l->have_offset | l->have_extension_bits | l->is_end)) {
312                 // TODO: error here on malformed/truncated? could be quite spammy
313                 return _ERR_MALFORMED;
314             }
315         } else {
316             mlwarning("need more labels, aborting DNS parsing");
317             return _ERR_NEEDLABELS;
318         }
319         q->labels++;
320 
321         need16(q->type, self->at, self->left);
322         q->have_type = 1;
323 
324         need16(q->class, self->at, self->left);
325         q->have_class = 1;
326 
327         return 0;
328     }
329 
330     // TODO: error here on malformed/truncated? could be quite spammy
331     return _ERR_MALFORMED;
332 }
333 
core_object_dns_parse_rr(core_object_dns_t * self,core_object_dns_rr_t * rr,core_object_dns_label_t * label,size_t labels)334 int core_object_dns_parse_rr(core_object_dns_t* self, core_object_dns_rr_t* rr, core_object_dns_label_t* label, size_t labels)
335 {
336     size_t rdata_label_sets;
337     mlassert_self();
338     mlassert(rr, "rr is nil");
339     mlassert(label, "label is nil");
340     mlassert(labels, "labels is zero");
341     mlassert(self->at, "at is nil");
342 
343     for (;;) {
344         *rr        = _defaults_rr;
345         rr->labels = _label(self, label, labels);
346         if (rr->labels < labels) {
347             core_object_dns_label_t* l = &label[rr->labels];
348             if (!(l->have_offset | l->have_extension_bits | l->is_end)) {
349                 // TODO: error here on malformed/truncated? could be quite spammy
350                 return _ERR_MALFORMED;
351             }
352         } else {
353             mlwarning("need more labels, aborting DNS parsing");
354             return _ERR_NEEDLABELS;
355         }
356         rr->labels++;
357 
358         need16(rr->type, self->at, self->left);
359         rr->have_type = 1;
360 
361         need16(rr->class, self->at, self->left);
362         rr->have_class = 1;
363 
364         need32(rr->ttl, self->at, self->left);
365         rr->have_ttl = 1;
366 
367         need16(rr->rdlength, self->at, self->left);
368         rr->have_rdlength = 1;
369 
370         rr->rdata_offset = self->at - self->payload;
371         if (!(rdata_label_sets = _rdata_labels(rr->type))) {
372             advancexb(rr->rdlength, self->at, self->left);
373             rr->have_rdata = 1;
374             return 0;
375         }
376 
377         switch (rr->type) {
378         case CORE_OBJECT_DNS_TYPE_MX:
379         case CORE_OBJECT_DNS_TYPE_AFSDB:
380         case CORE_OBJECT_DNS_TYPE_RT:
381         case CORE_OBJECT_DNS_TYPE_KX:
382         case CORE_OBJECT_DNS_TYPE_LP:
383         case CORE_OBJECT_DNS_TYPE_PX:
384             advancexb(2, self->at, self->left);
385             break;
386 
387         case CORE_OBJECT_DNS_TYPE_SIG:
388         case CORE_OBJECT_DNS_TYPE_RRSIG:
389             advancexb(18, self->at, self->left);
390             break;
391 
392         case CORE_OBJECT_DNS_TYPE_SRV:
393             advancexb(6, self->at, self->left);
394             break;
395 
396         case CORE_OBJECT_DNS_TYPE_NAPTR: {
397             uint8_t naptr_length;
398 
399             advancexb(4, self->at, self->left);
400             need8(naptr_length, self->at, self->left);
401             advancexb(naptr_length, self->at, self->left);
402             need8(naptr_length, self->at, self->left);
403             advancexb(naptr_length, self->at, self->left);
404             need8(naptr_length, self->at, self->left);
405             advancexb(naptr_length, self->at, self->left);
406         } break;
407 
408         case CORE_OBJECT_DNS_TYPE_HIP: {
409             uint8_t  hit_length;
410             uint16_t pk_length;
411 
412             need8(hit_length, self->at, self->left);
413             advancexb(1, self->at, self->left);
414             need16(pk_length, self->at, self->left);
415             advancexb(hit_length, self->at, self->left);
416             advancexb(pk_length, self->at, self->left);
417 
418             if (self->at - self->payload >= rr->rdata_offset + rr->rdlength) {
419                 rdata_label_sets = 0;
420             }
421         } break;
422         }
423 
424         while (rdata_label_sets) {
425             rr->rdata_labels += _label(self, &label[rr->labels + rr->rdata_labels], labels - rr->labels - rr->rdata_labels);
426             if (rr->labels + rr->rdata_labels < labels) {
427                 core_object_dns_label_t* l = &label[rr->labels + rr->rdata_labels];
428                 if (!(l->have_offset | l->have_extension_bits | l->is_end)) {
429                     // TODO: error here on malformed/truncated? could be quite spammy
430                     return _ERR_MALFORMED;
431                 }
432             } else {
433                 mlwarning("need more labels, aborting DNS parsing");
434                 return _ERR_NEEDLABELS;
435             }
436             rr->rdata_labels++;
437 
438             if (rr->type == CORE_OBJECT_DNS_TYPE_HIP && self->at - self->payload < rr->rdata_offset + rr->rdlength) {
439                 continue;
440             }
441 
442             rdata_label_sets--;
443         }
444 
445         if (self->at - self->payload < rr->rdata_offset + rr->rdlength) {
446             rr->padding_offset = self->at - self->payload;
447             rr->padding_length = rr->rdlength - (rr->padding_offset - rr->rdata_offset);
448 
449             advancexb(rr->padding_length, self->at, self->left);
450 
451             /*
452              * TODO:
453              *
454              * This can indicate padding but we do not set that we have padding
455              * yet because we need to fully understand all record types before
456              * that and process valid data after the labels
457              *
458             rr->have_padding = 1;
459              */
460         } else if (self->at - self->payload > rr->rdata_offset + rr->rdlength) {
461             // TODO: error here on malformed/truncated? could be quite spammy
462             return _ERR_MALFORMED;
463         }
464         rr->have_rdata = 1;
465 
466         return 0;
467     }
468 
469     // TODO: error here on malformed/truncated? could be quite spammy
470     return _ERR_MALFORMED;
471 }
472