source: mainline/uspace/srv/net/dnsrsrv/dns_msg.c

Last change on this file was 28a5ebd, checked in by Martin Decky <martin@…>, 5 years ago

Use char32_t instead of wchat_t to represent UTF-32 strings

The intention of the native HelenOS string API has been always to
support Unicode in the UTF-8 and UTF-32 encodings as the sole character
representations and ignore the obsolete mess of older single-byte and
multibyte character encodings. Before C11, the wchar_t type has been
slightly misused for the purpose of the UTF-32 strings. The newer
char32_t type is obviously a much more suitable option. The standard
defines char32_t as uint_least32_t, thus we can take the liberty to fix
it to uint32_t.

To maintain compatilibity with the C Standard, the putwchar(wchar_t)
functions has been replaced by our custom putuchar(char32_t) functions
where appropriate.

  • Property mode set to 100644
File size: 16.1 KB
RevLine 
[adae30d]1/*
[dc95342]2 * Copyright (c) 2013 Jiri Svoboda
[adae30d]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[a63966d]29/** @addtogroup dnsrsrv
[adae30d]30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <bitops.h>
[08a6382]37#include <byteorder.h>
[adae30d]38#include <errno.h>
[ef904895]39#include <io/log.h>
[0041cd6d]40#include <macros.h>
[adae30d]41#include <stdint.h>
42#include <stdlib.h>
43#include <str.h>
44
45#include "dns_msg.h"
46#include "dns_std.h"
47
48#define NAME "dnsres"
49
[f1dcf6d]50static uint16_t dns_uint16_t_decode(uint8_t *, size_t);
51
[9f029aa]52/** Extend dynamically allocated string with suffix.
53 *
[c477c80]54 * @a *dstr points to a dynamically allocated buffer containing a string.
[9f029aa]55 * Reallocate this buffer so that concatenation of @a *dstr and @a suff can
56 * fit in and append @a suff.
57 */
[b7fd2a0]58static errno_t dns_dstr_ext(char **dstr, const char *suff)
[7262f89]59{
60 size_t s1, s2;
61 size_t nsize;
62 char *nstr;
63
64 if (*dstr == NULL) {
65 *dstr = str_dup(suff);
66 if (*dstr == NULL)
67 return ENOMEM;
68 return EOK;
69 }
70
71 s1 = str_size(*dstr);
72 s2 = str_size(suff);
73 nsize = s1 + s2 + 1;
74
75 nstr = realloc(*dstr, nsize);
76 if (nstr == NULL)
77 return ENOMEM;
78
[20c82e3]79 str_cpy(nstr + s1, nsize - s1, suff);
[7262f89]80
81 *dstr = nstr;
82 return EOK;
83}
84
[9f029aa]85/** Encode DNS name.
86 *
87 * Encode DNS name or measure the size of encoded name (with @a buf NULL,
88 * and @a buf_size 0).
89 *
90 * @param name String to encode
91 * @param buf Buffer or NULL
92 * @param buf_size Buffer size or 0 if @a buf is NULL
93 * @param act_size Place to store actual encoded size
94 */
[b7fd2a0]95static errno_t dns_name_encode(char *name, uint8_t *buf, size_t buf_size,
[adae30d]96 size_t *act_size)
97{
98 size_t off;
[28a5ebd]99 char32_t c;
[adae30d]100 size_t lsize;
101 size_t pi, di;
102
103 pi = 0;
104 di = 1;
[f85ed4b]105 off = 0;
[adae30d]106
107 lsize = 0;
108 while (true) {
109 c = str_decode(name, &off, STR_NO_LIMIT);
[7262f89]110 if (c >= 127) {
[adae30d]111 /* Non-ASCII character */
[ef904895]112 log_msg(LOG_DEFAULT, LVL_DEBUG, "Non-ascii character");
[adae30d]113 return EINVAL;
114 }
115
116 if (c == '.' || c == '\0') {
117 /* Empty string, starting with period or two consecutive periods. */
[f85ed4b]118 if (lsize == 0) {
[ef904895]119 log_msg(LOG_DEFAULT, LVL_DEBUG, "Empty token");
[adae30d]120 return EINVAL;
[f85ed4b]121 }
[adae30d]122
123 if (lsize > DNS_LABEL_MAX_SIZE) {
124 /* Label too long */
[ef904895]125 log_msg(LOG_DEFAULT, LVL_DEBUG, "Label too long");
[adae30d]126 return EINVAL;
127 }
128
129 if (buf != NULL && pi < buf_size)
130 buf[pi] = (uint8_t)lsize;
131
[08a6382]132 lsize = 0;
[adae30d]133 pi = di;
134 ++di;
[08a6382]135
136 if (c == '\0')
137 break;
[adae30d]138 } else {
139 if (buf != NULL && di < buf_size)
[08a6382]140 buf[di] = c;
141 ++di;
142 ++lsize;
[adae30d]143 }
144 }
145
146 if (buf != NULL && pi < buf_size)
147 buf[pi] = 0;
148
149 *act_size = di;
150 return EOK;
151}
152
[9f029aa]153/** Decode DNS name.
154 *
155 * @param pdu PDU from which we are decoding
156 * @param boff Starting offset within PDU
157 * @param rname Place to return dynamically allocated string
158 * @param eoff Place to store end offset (offset after last decoded byte)
159 */
[b7fd2a0]160errno_t dns_name_decode(dns_pdu_t *pdu, size_t boff, char **rname,
[9d8bd3ac]161 size_t *eoff)
[0041cd6d]162{
163 uint8_t *bp;
164 size_t bsize;
165 size_t lsize;
166 size_t i;
[f1dcf6d]167 size_t ptr;
168 size_t eptr;
[7262f89]169 char *name;
170 char dbuf[2];
[b7fd2a0]171 errno_t rc;
[7262f89]172 bool first;
173
174 name = NULL;
[0041cd6d]175
[9f029aa]176 if (boff > pdu->size)
[9d8bd3ac]177 return EINVAL;
178
[9f029aa]179 bp = pdu->data + boff;
180 bsize = min(pdu->size - boff, DNS_NAME_MAX_SIZE);
[7262f89]181 first = true;
182 *eoff = 0;
[0041cd6d]183
184 while (true) {
185 if (bsize == 0) {
[7262f89]186 rc = EINVAL;
187 goto error;
[0041cd6d]188 }
189
190 lsize = *bp;
191 ++bp;
192 --bsize;
193
194 if (lsize == 0)
195 break;
196
197 if ((lsize & 0xc0) == 0xc0) {
198 /* Pointer */
[f1dcf6d]199 if (bsize < 1) {
[ef904895]200 log_msg(LOG_DEFAULT, LVL_DEBUG, "Pointer- bsize < 1");
[7262f89]201 rc = EINVAL;
202 goto error;
[f1dcf6d]203 }
204
205 ptr = dns_uint16_t_decode(bp - 1, bsize) & 0x3fff;
[7262f89]206 ++bp;
207 --bsize;
208
[9f029aa]209 if (ptr >= (size_t)(bp - pdu->data)) {
[ef904895]210 log_msg(LOG_DEFAULT, LVL_DEBUG,
[716357f]211 "Pointer- forward ref %zu, pos=%zu",
[9f029aa]212 ptr, (size_t)(bp - pdu->data));
[f1dcf6d]213 /* Forward reference */
[7262f89]214 rc = EINVAL;
215 goto error;
[f1dcf6d]216 }
217
218 /*
219 * Make sure we will not decode any byte twice.
220 * XXX Is assumption correct?
221 */
[9f029aa]222 eptr = bp - pdu->data;
[7262f89]223 /*
224 * This is where encoded name ends in terms where
225 * the message continues
226 */
[20c82e3]227 if (*eoff == 0)
228 *eoff = eptr;
[f1dcf6d]229
[9f029aa]230 bp = pdu->data + ptr;
[f1dcf6d]231 bsize = eptr - ptr;
232 continue;
[0041cd6d]233 }
234
235 if (lsize > bsize) {
[7262f89]236 rc = EINVAL;
237 goto error;
[0041cd6d]238 }
239
[20c82e3]240 if (!first) {
241 rc = dns_dstr_ext(&name, ".");
242 if (rc != EOK) {
243 rc = ENOMEM;
244 goto error;
245 }
246 }
247
[0041cd6d]248 for (i = 0; i < lsize; i++) {
[7262f89]249 if (*bp < 32 || *bp >= 127) {
250 rc = EINVAL;
251 goto error;
252 }
253
254 dbuf[0] = *bp;
255 dbuf[1] = '\0';
256
257 rc = dns_dstr_ext(&name, dbuf);
258 if (rc != EOK) {
259 rc = ENOMEM;
260 goto error;
261 }
[0041cd6d]262 ++bp;
263 --bsize;
264 }
[7262f89]265
266 first = false;
[0041cd6d]267 }
268
[7262f89]269 *rname = name;
270 if (*eoff == 0)
[9f029aa]271 *eoff = bp - pdu->data;
[0041cd6d]272 return EOK;
[7262f89]273error:
274 free(name);
275 return rc;
[0041cd6d]276}
277
278/** Decode unaligned big-endian 16-bit integer */
279static uint16_t dns_uint16_t_decode(uint8_t *buf, size_t buf_size)
280{
281 assert(buf_size >= 2);
282
283 return ((uint16_t)buf[0] << 8) + buf[1];
284}
285
286/** Encode unaligned big-endian 16-bit integer */
[adae30d]287static void dns_uint16_t_encode(uint16_t w, uint8_t *buf, size_t buf_size)
288{
289 if (buf != NULL && buf_size >= 1)
290 buf[0] = w >> 8;
291
292 if (buf != NULL && buf_size >= 2)
293 buf[1] = w & 0xff;
294}
295
[0041cd6d]296/** Decode unaligned big-endian 32-bit integer */
[7262f89]297uint32_t dns_uint32_t_decode(uint8_t *buf, size_t buf_size)
[0041cd6d]298{
299 assert(buf_size >= 4);
[a35b458]300
[0aa70f4]301 uint32_t w = ((uint32_t) buf[0] << 24) +
[3e66428]302 ((uint32_t) buf[1] << 16) +
303 ((uint32_t) buf[2] << 8) +
[7262f89]304 buf[3];
[a35b458]305
[7262f89]306 return w;
[0041cd6d]307}
308
[0aa70f4]309/** Decode unaligned big-endian 128-bit integer */
310void dns_addr128_t_decode(uint8_t *buf, size_t buf_size, addr128_t addr)
311{
312 assert(buf_size >= 16);
[a35b458]313
[0aa70f4]314 addr128_t_be2host(buf, addr);
315}
316
[9f029aa]317/** Encode DNS question.
318 *
319 * Encode DNS question or measure the size of encoded question (with @a buf NULL,
320 * and @a buf_size 0).
321 *
322 * @param question Question to encode
323 * @param buf Buffer or NULL
324 * @param buf_size Buffer size or 0 if @a buf is NULL
325 * @param act_size Place to store actual encoded size
326 */
[b7fd2a0]327static errno_t dns_question_encode(dns_question_t *question, uint8_t *buf,
[adae30d]328 size_t buf_size, size_t *act_size)
329{
330 size_t name_size;
331 size_t di;
[b7fd2a0]332 errno_t rc;
[adae30d]333
334 rc = dns_name_encode(question->qname, buf, buf_size, &name_size);
335 if (rc != EOK)
336 return rc;
337
338 *act_size = name_size + sizeof(uint16_t) + sizeof(uint16_t);
[f85ed4b]339 if (buf == NULL)
340 return EOK;
341
[adae30d]342 di = name_size;
343
344 dns_uint16_t_encode(question->qtype, buf + di, buf_size - di);
345 di += sizeof(uint16_t);
346
347 dns_uint16_t_encode(question->qclass, buf + di, buf_size - di);
348 di += sizeof(uint16_t);
349
350 return EOK;
351}
352
[9f029aa]353/** Decode DNS question.
354 *
355 * @param pdu PDU from which we are decoding
356 * @param boff Starting offset within PDU
357 * @param rquestion Place to return dynamically allocated question
358 * @param eoff Place to store end offset (offset after last decoded byte)
359 */
[b7fd2a0]360static errno_t dns_question_decode(dns_pdu_t *pdu, size_t boff,
[9d8bd3ac]361 dns_question_t **rquestion, size_t *eoff)
[0041cd6d]362{
363 dns_question_t *question;
[9d8bd3ac]364 size_t name_eoff;
[b7fd2a0]365 errno_t rc;
[0041cd6d]366
367 question = calloc(1, sizeof (dns_question_t));
368 if (question == NULL)
369 return ENOMEM;
370
[9f029aa]371 rc = dns_name_decode(pdu, boff, &question->qname, &name_eoff);
[0041cd6d]372 if (rc != EOK) {
[ef904895]373 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error decoding name");
[0041cd6d]374 free(question);
375 return ENOMEM;
376 }
377
[9f029aa]378 if (name_eoff + 2 * sizeof(uint16_t) > pdu->size) {
[0041cd6d]379 free(question);
380 return EINVAL;
381 }
382
[9f029aa]383 question->qtype = dns_uint16_t_decode(pdu->data + name_eoff,
384 pdu->size - name_eoff);
[3bacee1]385 question->qclass = dns_uint16_t_decode(pdu->data + sizeof(uint16_t) +
386 name_eoff, pdu->size - sizeof(uint16_t) - name_eoff);
[9d8bd3ac]387 *eoff = name_eoff + 2 * sizeof(uint16_t);
[0041cd6d]388
389 *rquestion = question;
390 return EOK;
391}
392
[9f029aa]393/** Decode DNS resource record.
394 *
395 * @param pdu PDU from which we are decoding
396 * @param boff Starting offset within PDU
397 * @param retrr Place to return dynamically allocated resource record
398 * @param eoff Place to store end offset (offset after last decoded byte)
399 */
[b7fd2a0]400static errno_t dns_rr_decode(dns_pdu_t *pdu, size_t boff, dns_rr_t **retrr,
[9f029aa]401 size_t *eoff)
[0041cd6d]402{
403 dns_rr_t *rr;
[9d8bd3ac]404 size_t name_eoff;
[0041cd6d]405 uint8_t *bp;
406 size_t bsz;
407 size_t rdlength;
[b7fd2a0]408 errno_t rc;
[0041cd6d]409
[0aa70f4]410 rr = calloc(1, sizeof(dns_rr_t));
[0041cd6d]411 if (rr == NULL)
412 return ENOMEM;
413
[9f029aa]414 rc = dns_name_decode(pdu, boff, &rr->name, &name_eoff);
[0041cd6d]415 if (rc != EOK) {
[20c82e3]416 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_rr_decode: error decoding name");
[0041cd6d]417 free(rr);
418 return ENOMEM;
419 }
420
[9f029aa]421 if (name_eoff + 2 * sizeof(uint16_t) > pdu->size) {
[0041cd6d]422 free(rr->name);
423 free(rr);
[20c82e3]424 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_rr_decode: error name_off");
[0041cd6d]425 return EINVAL;
426 }
427
[9f029aa]428 bp = pdu->data + name_eoff;
429 bsz = pdu->size - name_eoff;
[0041cd6d]430
431 if (bsz < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
432 free(rr->name);
433 free(rr);
[20c82e3]434 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_rr_decode: error bsz");
[0041cd6d]435 return EINVAL;
436 }
437
438 rr->rtype = dns_uint16_t_decode(bp, bsz);
[0aa70f4]439 bp += sizeof(uint16_t);
440 bsz -= sizeof(uint16_t);
[0041cd6d]441
442 rr->rclass = dns_uint16_t_decode(bp, bsz);
[0aa70f4]443 bp += sizeof(uint16_t);
444 bsz -= sizeof(uint16_t);
[0041cd6d]445
446 rr->ttl = dns_uint32_t_decode(bp, bsz);
[0aa70f4]447 bp += sizeof(uint32_t);
448 bsz -= sizeof(uint32_t);
[0041cd6d]449
[20c82e3]450 log_msg(LOG_DEFAULT, LVL_DEBUG2, "dns_rr_decode: rtype=0x%x, rclass=0x%x, ttl=0x%x",
[3bacee1]451 rr->rtype, rr->rclass, rr->ttl);
[20c82e3]452
[0041cd6d]453 rdlength = dns_uint16_t_decode(bp, bsz);
[0aa70f4]454 bp += sizeof(uint16_t);
455 bsz -= sizeof(uint16_t);
[0041cd6d]456
457 if (rdlength > bsz) {
458 free(rr->name);
459 free(rr);
[20c82e3]460 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_rr_decode: Error rdlength %zu > bsz %zu", rdlength, bsz);
[0041cd6d]461 return EINVAL;
462 }
463
464 rr->rdata_size = rdlength;
[20c82e3]465 log_msg(LOG_DEFAULT, LVL_DEBUG2, "dns_rr_decode: rdlength=%zu", rdlength);
466 rr->rdata = calloc(1, rdlength);
[0041cd6d]467 if (rr->rdata == NULL) {
468 free(rr->name);
469 free(rr);
[20c82e3]470 log_msg(LOG_DEFAULT, LVL_DEBUG, "dns_rr_decode: Error memory");
[0041cd6d]471 return ENOMEM;
472 }
473
474 memcpy(rr->rdata, bp, rdlength);
[9f029aa]475 rr->roff = bp - pdu->data;
[0041cd6d]476 bp += rdlength;
477 bsz -= rdlength;
478
[9f029aa]479 *eoff = bp - pdu->data;
[0041cd6d]480 *retrr = rr;
[20c82e3]481 log_msg(LOG_DEFAULT, LVL_DEBUG2, "dns_rr_decode: done");
[0041cd6d]482 return EOK;
483}
484
[9f029aa]485/** Encode DNS message.
486 *
487 * @param msg Message
488 * @param rdata Place to store encoded data pointer
489 * @param rsize Place to store encoded data size
490 *
491 * @return EOK on success, EINVAL if message contains invalid data,
492 * ENOMEM if out of memory
493 */
[b7fd2a0]494errno_t dns_message_encode(dns_message_t *msg, void **rdata, size_t *rsize)
[adae30d]495{
496 uint8_t *data;
497 size_t size;
498 dns_header_t hdr;
[b5f716b]499 size_t q_size = 0;
[adae30d]500 size_t di;
[b7fd2a0]501 errno_t rc;
[adae30d]502
[08a6382]503 hdr.id = host2uint16_t_be(msg->id);
[adae30d]504
[08a6382]505 hdr.opbits = host2uint16_t_be(
[adae30d]506 (msg->qr << OPB_QR) |
507 (msg->opcode << OPB_OPCODE_l) |
508 (msg->aa ? BIT_V(uint16_t, OPB_AA) : 0) |
509 (msg->tc ? BIT_V(uint16_t, OPB_TC) : 0) |
510 (msg->rd ? BIT_V(uint16_t, OPB_RD) : 0) |
511 (msg->ra ? BIT_V(uint16_t, OPB_RA) : 0) |
[3bacee1]512 msg->rcode);
[adae30d]513
[08a6382]514 hdr.qd_count = host2uint16_t_be(list_count(&msg->question));
[adae30d]515 hdr.an_count = 0;
516 hdr.ns_count = 0;
517 hdr.ar_count = 0;
518
519 size = sizeof(dns_header_t);
520
[feeac0d]521 list_foreach(msg->question, msg, dns_question_t, q) {
[adae30d]522 rc = dns_question_encode(q, NULL, 0, &q_size);
523 if (rc != EOK)
524 return rc;
525
[b5f716b]526 assert(q_size > 0);
527
[adae30d]528 size += q_size;
529 }
530
531 data = calloc(1, size);
532 if (data == NULL)
533 return ENOMEM;
534
535 memcpy(data, &hdr, sizeof(dns_header_t));
536 di = sizeof(dns_header_t);
537
[feeac0d]538 list_foreach(msg->question, msg, dns_question_t, q) {
[adae30d]539 rc = dns_question_encode(q, data + di, size - di, &q_size);
[dc95342]540 if (rc != EOK) {
541 assert(rc == ENOMEM || rc == EINVAL);
542 free(data);
543 return rc;
544 }
[adae30d]545
[b5f716b]546 assert(q_size > 0);
547
[adae30d]548 di += q_size;
549 }
550
551 *rdata = data;
552 *rsize = size;
553 return EOK;
554}
555
[9f029aa]556/** Decode DNS message.
557 *
558 * @param data Encoded PDU data
559 * @param size Encoded PDU size
560 * @param rmsg Place to store pointer to decoded message
561 *
562 * @return EOK on success, EINVAL if message contains invalid data,
563 * ENOMEM if out of memory
564 */
[b7fd2a0]565errno_t dns_message_decode(void *data, size_t size, dns_message_t **rmsg)
[0041cd6d]566{
567 dns_message_t *msg;
568 dns_header_t *hdr;
[9d8bd3ac]569 size_t doff;
570 size_t field_eoff;
[0041cd6d]571 dns_question_t *question;
572 dns_rr_t *rr;
573 size_t qd_count;
574 size_t an_count;
575 size_t i;
[b7fd2a0]576 errno_t rc;
[0041cd6d]577
[a0d97f83]578 msg = dns_message_new();
[0041cd6d]579 if (msg == NULL)
580 return ENOMEM;
581
[d531bd6]582 if (size < sizeof(dns_header_t)) {
583 rc = EINVAL;
584 goto error;
585 }
586
587 /* Store a copy of raw message data for string decompression */
588
[9f029aa]589 msg->pdu.data = malloc(size);
590 if (msg->pdu.data == NULL) {
591 rc = ENOMEM;
[d531bd6]592 goto error;
593 }
594
[9f029aa]595 memcpy(msg->pdu.data, data, size);
596 msg->pdu.size = size;
[20c82e3]597 log_msg(LOG_DEFAULT, LVL_DEBUG2, "dns_message_decode: pdu->data = %p, "
[9f029aa]598 "pdu->size=%zu", msg->pdu.data, msg->pdu.size);
[0041cd6d]599
600 hdr = data;
601
602 msg->id = uint16_t_be2host(hdr->id);
603 msg->qr = BIT_RANGE_EXTRACT(uint16_t, OPB_QR, OPB_QR, hdr->opbits);
604 msg->opcode = BIT_RANGE_EXTRACT(uint16_t, OPB_OPCODE_h, OPB_OPCODE_l,
605 hdr->opbits);
606 msg->aa = BIT_RANGE_EXTRACT(uint16_t, OPB_AA, OPB_AA, hdr->opbits);
607 msg->tc = BIT_RANGE_EXTRACT(uint16_t, OPB_TC, OPB_TC, hdr->opbits);
608 msg->rd = BIT_RANGE_EXTRACT(uint16_t, OPB_RD, OPB_RD, hdr->opbits);
609 msg->ra = BIT_RANGE_EXTRACT(uint16_t, OPB_RA, OPB_RA, hdr->opbits);
610 msg->rcode = BIT_RANGE_EXTRACT(uint16_t, OPB_RCODE_h, OPB_RCODE_l,
611 hdr->opbits);
612
[9d8bd3ac]613 doff = sizeof(dns_header_t);
[0041cd6d]614
615 qd_count = uint16_t_be2host(hdr->qd_count);
[20c82e3]616 log_msg(LOG_DEFAULT, LVL_DEBUG2, "qd_count=%zu", qd_count);
617
[0041cd6d]618 for (i = 0; i < qd_count; i++) {
[9f029aa]619 rc = dns_question_decode(&msg->pdu, doff, &question, &field_eoff);
[0041cd6d]620 if (rc != EOK) {
[ef904895]621 log_msg(LOG_DEFAULT, LVL_DEBUG, "error decoding question");
[0041cd6d]622 goto error;
623 }
624
[7262f89]625 list_append(&question->msg, &msg->question);
[9d8bd3ac]626 doff = field_eoff;
[0041cd6d]627 }
628
629 an_count = uint16_t_be2host(hdr->an_count);
[20c82e3]630 log_msg(LOG_DEFAULT, LVL_DEBUG2, "an_count=%zu", an_count);
[0041cd6d]631
632 for (i = 0; i < an_count; i++) {
[9f029aa]633 rc = dns_rr_decode(&msg->pdu, doff, &rr, &field_eoff);
[0041cd6d]634 if (rc != EOK) {
[ef904895]635 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error decoding answer");
[0041cd6d]636 goto error;
637 }
638
[7262f89]639 list_append(&rr->msg, &msg->answer);
[9d8bd3ac]640 doff = field_eoff;
[0041cd6d]641 }
642
643 *rmsg = msg;
644 return EOK;
645error:
[dc95342]646 dns_message_destroy(msg);
[0041cd6d]647 return rc;
648}
649
[9f029aa]650/** Destroy question. */
[dc95342]651static void dns_question_destroy(dns_question_t *question)
652{
653 free(question->qname);
654 free(question);
655}
656
[9f029aa]657/** Destroy resource record. */
[dc95342]658static void dns_rr_destroy(dns_rr_t *rr)
659{
660 free(rr->name);
661 free(rr->rdata);
662 free(rr);
663}
664
[9f029aa]665/** Create new empty message. */
[a0d97f83]666dns_message_t *dns_message_new(void)
667{
668 dns_message_t *msg;
669
670 msg = calloc(1, sizeof(dns_message_t));
671 if (msg == NULL)
672 return NULL;
673
674 list_initialize(&msg->question);
675 list_initialize(&msg->answer);
676 list_initialize(&msg->authority);
677 list_initialize(&msg->additional);
678
679 return msg;
680}
681
[9f029aa]682/** Destroy message. */
[dc95342]683void dns_message_destroy(dns_message_t *msg)
684{
685 link_t *link;
686 dns_question_t *question;
687 dns_rr_t *rr;
688
689 while (!list_empty(&msg->question)) {
690 link = list_first(&msg->question);
691 question = list_get_instance(link, dns_question_t, msg);
692 list_remove(&question->msg);
693 dns_question_destroy(question);
694 }
695
696 while (!list_empty(&msg->answer)) {
697 link = list_first(&msg->answer);
698 rr = list_get_instance(link, dns_rr_t, msg);
699 list_remove(&rr->msg);
700 dns_rr_destroy(rr);
701 }
702
703 while (!list_empty(&msg->authority)) {
704 link = list_first(&msg->authority);
705 rr = list_get_instance(link, dns_rr_t, msg);
706 list_remove(&rr->msg);
707 dns_rr_destroy(rr);
708 }
709
710 while (!list_empty(&msg->additional)) {
711 link = list_first(&msg->additional);
712 rr = list_get_instance(link, dns_rr_t, msg);
713 list_remove(&rr->msg);
714 dns_rr_destroy(rr);
715 }
716
[9f029aa]717 free(msg->pdu.data);
[dc95342]718 free(msg);
719}
720
[adae30d]721/** @}
722 */
Note: See TracBrowser for help on using the repository browser.