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