source: mainline/uspace/srv/net/dnsres/dns_msg.c@ 7262f89

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7262f89 was 7262f89, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Construct domain names, fix some bugs. Parse answer, print resulting hostname and IP address.

  • Property mode set to 100644
File size: 12.5 KB
RevLine 
[adae30d]1/*
2 * Copyright (c) 2012 Jiri Svoboda
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
29/** @addtogroup dnsres
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <bitops.h>
[08a6382]37#include <byteorder.h>
[adae30d]38#include <errno.h>
[0041cd6d]39#include <macros.h>
[adae30d]40#include <stdint.h>
41#include <stdlib.h>
42#include <str.h>
43
44#include "dns_msg.h"
45#include "dns_std.h"
46
47#define NAME "dnsres"
48
[f1dcf6d]49static uint16_t dns_uint16_t_decode(uint8_t *, size_t);
50
[7262f89]51static int dns_dstr_ext(char **dstr, const char *suff)
52{
53 size_t s1, s2;
54 size_t nsize;
55 char *nstr;
56
57 if (*dstr == NULL) {
58 *dstr = str_dup(suff);
59 if (*dstr == NULL)
60 return ENOMEM;
61 return EOK;
62 }
63
64 s1 = str_size(*dstr);
65 s2 = str_size(suff);
66 nsize = s1 + s2 + 1;
67
68 nstr = realloc(*dstr, nsize);
69 if (nstr == NULL)
70 return ENOMEM;
71
72 str_cpy((*dstr) + s1, nsize - s1, suff);
73
74 *dstr = nstr;
75 return EOK;
76}
77
[f85ed4b]78#include <stdio.h>
[adae30d]79static int dns_name_encode(char *name, uint8_t *buf, size_t buf_size,
80 size_t *act_size)
81{
82 size_t off;
83 wchar_t c;
84 size_t lsize;
85 size_t pi, di;
86
87 pi = 0;
88 di = 1;
[f85ed4b]89 off = 0;
[adae30d]90
[f85ed4b]91 printf("dns_name_encode(name='%s', buf=%p, buf_size=%zu, act_size=%p\n",
92 name, buf, buf_size, act_size);
[adae30d]93 lsize = 0;
94 while (true) {
[f85ed4b]95 printf("off=%zu\n", off);
[adae30d]96 c = str_decode(name, &off, STR_NO_LIMIT);
[f85ed4b]97 printf("c=%d\n", (int)c);
[7262f89]98 if (c >= 127) {
[adae30d]99 /* Non-ASCII character */
[f85ed4b]100 printf("non-ascii character\n");
[adae30d]101 return EINVAL;
102 }
103
104 if (c == '.' || c == '\0') {
105 /* Empty string, starting with period or two consecutive periods. */
[f85ed4b]106 if (lsize == 0) {
107 printf("empty token\n");
[adae30d]108 return EINVAL;
[f85ed4b]109 }
[adae30d]110
111 if (lsize > DNS_LABEL_MAX_SIZE) {
112 /* Label too long */
[f85ed4b]113 printf("label too long\n");
[adae30d]114 return EINVAL;
115 }
116
117 if (buf != NULL && pi < buf_size)
118 buf[pi] = (uint8_t)lsize;
119
[08a6382]120 lsize = 0;
[adae30d]121 pi = di;
122 ++di;
[08a6382]123
124 if (c == '\0')
125 break;
[adae30d]126 } else {
127 if (buf != NULL && di < buf_size)
[08a6382]128 buf[di] = c;
129 ++di;
130 ++lsize;
[adae30d]131 }
132 }
133
134 if (buf != NULL && pi < buf_size)
135 buf[pi] = 0;
136
137 *act_size = di;
138 return EOK;
139}
140
[9d8bd3ac]141static int dns_name_decode(uint8_t *buf, size_t size, size_t boff, char **rname,
142 size_t *eoff)
[0041cd6d]143{
144 uint8_t *bp;
145 size_t bsize;
146 size_t lsize;
147 size_t i;
[f1dcf6d]148 size_t ptr;
149 size_t eptr;
[7262f89]150 char *name;
151 char dbuf[2];
152 int rc;
153 bool first;
154
155 name = NULL;
[0041cd6d]156
[9d8bd3ac]157 if (boff > size)
158 return EINVAL;
159
160 bp = buf + boff;
161 bsize = min(size - boff, DNS_NAME_MAX_SIZE);
[7262f89]162 first = true;
163 *eoff = 0;
[0041cd6d]164
165 while (true) {
166 if (bsize == 0) {
[7262f89]167 rc = EINVAL;
168 goto error;
[0041cd6d]169 }
170
171 lsize = *bp;
172 ++bp;
173 --bsize;
174
175 if (lsize == 0)
176 break;
177
[7262f89]178 if (!first) {
[0041cd6d]179 printf(".");
[7262f89]180 rc = dns_dstr_ext(&name, ".");
181 if (rc != EOK) {
182 rc = ENOMEM;
183 goto error;
184 }
185 }
[0041cd6d]186
187 if ((lsize & 0xc0) == 0xc0) {
[f1dcf6d]188 printf("Pointer\n");
[0041cd6d]189 /* Pointer */
[f1dcf6d]190 if (bsize < 1) {
191 printf("Pointer- bsize < 1\n");
[7262f89]192 rc = EINVAL;
193 goto error;
[f1dcf6d]194 }
195
196 ptr = dns_uint16_t_decode(bp - 1, bsize) & 0x3fff;
[7262f89]197 ++bp;
198 --bsize;
199
[f1dcf6d]200 if (ptr >= (size_t)(bp - buf)) {
201 printf("Pointer- forward ref %u, pos=%u\n",
202 ptr, bp - buf);
203 /* Forward reference */
[7262f89]204 rc = EINVAL;
205 goto error;
[f1dcf6d]206 }
207
208 /*
209 * Make sure we will not decode any byte twice.
210 * XXX Is assumption correct?
211 */
[7262f89]212 eptr = bp - buf;
213 /*
214 * This is where encoded name ends in terms where
215 * the message continues
216 */
217 *eoff = eptr;
[f1dcf6d]218
219 printf("ptr=%u, eptr=%u\n", ptr, eptr);
220 bp = buf + ptr;
221 bsize = eptr - ptr;
222 continue;
[0041cd6d]223 }
224
225 if (lsize > bsize) {
[7262f89]226 rc = EINVAL;
227 goto error;
[0041cd6d]228 }
229
230 for (i = 0; i < lsize; i++) {
231 printf("%c", *bp);
[7262f89]232
233 if (*bp < 32 || *bp >= 127) {
234 rc = EINVAL;
235 goto error;
236 }
237
238 dbuf[0] = *bp;
239 dbuf[1] = '\0';
240
241 rc = dns_dstr_ext(&name, dbuf);
242 if (rc != EOK) {
243 rc = ENOMEM;
244 goto error;
245 }
[0041cd6d]246 ++bp;
247 --bsize;
248 }
[7262f89]249
250 first = false;
[0041cd6d]251 }
252
253 printf("\n");
254
[7262f89]255 *rname = name;
256 if (*eoff == 0)
257 *eoff = bp - buf;
[0041cd6d]258 return EOK;
[7262f89]259error:
260 free(name);
261 return rc;
[0041cd6d]262}
263
264/** Decode unaligned big-endian 16-bit integer */
265static uint16_t dns_uint16_t_decode(uint8_t *buf, size_t buf_size)
266{
267 assert(buf_size >= 2);
268
269 return ((uint16_t)buf[0] << 8) + buf[1];
270}
271
272/** Encode unaligned big-endian 16-bit integer */
[adae30d]273static void dns_uint16_t_encode(uint16_t w, uint8_t *buf, size_t buf_size)
274{
275 if (buf != NULL && buf_size >= 1)
276 buf[0] = w >> 8;
277
278 if (buf != NULL && buf_size >= 2)
279 buf[1] = w & 0xff;
280}
281
[0041cd6d]282/** Decode unaligned big-endian 32-bit integer */
[7262f89]283uint32_t dns_uint32_t_decode(uint8_t *buf, size_t buf_size)
[0041cd6d]284{
[7262f89]285 uint32_t w;
[0041cd6d]286 assert(buf_size >= 4);
287
[7262f89]288 w = ((uint32_t)buf[0] << 24) +
[0041cd6d]289 ((uint32_t)buf[1] << 16) +
290 ((uint32_t)buf[2] << 8) +
[7262f89]291 buf[3];
292
293 printf("dns_uint32_t_decode: %x, %x, %x, %x -> %x\n",
294 buf[0], buf[1], buf[2], buf[3], w);
295 return w;
[0041cd6d]296}
297
[adae30d]298static int dns_question_encode(dns_question_t *question, uint8_t *buf,
299 size_t buf_size, size_t *act_size)
300{
301 size_t name_size;
302 size_t di;
303 int rc;
304
305 rc = dns_name_encode(question->qname, buf, buf_size, &name_size);
306 if (rc != EOK)
307 return rc;
308
[08a6382]309 printf("name_size=%zu\n", name_size);
310
[adae30d]311 *act_size = name_size + sizeof(uint16_t) + sizeof(uint16_t);
[08a6382]312 printf("act_size=%zu\n", *act_size);
[f85ed4b]313 if (buf == NULL)
314 return EOK;
315
[adae30d]316 di = name_size;
317
318 dns_uint16_t_encode(question->qtype, buf + di, buf_size - di);
319 di += sizeof(uint16_t);
320
321 dns_uint16_t_encode(question->qclass, buf + di, buf_size - di);
322 di += sizeof(uint16_t);
323
324 return EOK;
325}
326
[9d8bd3ac]327static int dns_question_decode(uint8_t *buf, size_t buf_size, size_t boff,
328 dns_question_t **rquestion, size_t *eoff)
[0041cd6d]329{
330 dns_question_t *question;
[9d8bd3ac]331 size_t name_eoff;
[0041cd6d]332 int rc;
333
334 question = calloc(1, sizeof (dns_question_t));
335 if (question == NULL)
336 return ENOMEM;
337
338 printf("decode name..\n");
[9d8bd3ac]339 rc = dns_name_decode(buf, buf_size, boff, &question->qname, &name_eoff);
[0041cd6d]340 if (rc != EOK) {
341 printf("error decoding name..\n");
342 free(question);
343 return ENOMEM;
344 }
345
346 printf("ok decoding name..\n");
[9d8bd3ac]347 if (name_eoff + 2 * sizeof(uint16_t) > buf_size) {
348 printf("name_eoff + 2 * 2 = %d > buf_size = %d\n",
349 name_eoff + 2 * sizeof(uint16_t), buf_size);
[0041cd6d]350 free(question);
351 return EINVAL;
352 }
353
[9d8bd3ac]354 question->qtype = dns_uint16_t_decode(buf + name_eoff, buf_size - name_eoff);
355 question->qclass = dns_uint16_t_decode(buf + sizeof(uint16_t) + name_eoff,
356 buf_size - sizeof(uint16_t) - name_eoff);
357 *eoff = name_eoff + 2 * sizeof(uint16_t);
[0041cd6d]358
359 *rquestion = question;
360 return EOK;
361}
362
[9d8bd3ac]363static int dns_rr_decode(uint8_t *buf, size_t buf_size, size_t boff,
364 dns_rr_t **retrr, size_t *eoff)
[0041cd6d]365{
366 dns_rr_t *rr;
[9d8bd3ac]367 size_t name_eoff;
[0041cd6d]368 uint8_t *bp;
369 size_t bsz;
370 size_t rdlength;
371 int rc;
372
373 rr = calloc(1, sizeof (dns_rr_t));
374 if (rr == NULL)
375 return ENOMEM;
376
377 printf("decode name..\n");
[9d8bd3ac]378 rc = dns_name_decode(buf, buf_size, boff, &rr->name, &name_eoff);
[0041cd6d]379 if (rc != EOK) {
380 printf("error decoding name..\n");
381 free(rr);
382 return ENOMEM;
383 }
384
[7262f89]385 printf("ok decoding name.. '%s'\n", rr->name);
[9d8bd3ac]386 if (name_eoff + 2 * sizeof(uint16_t) > buf_size) {
387 printf("name_eoff + 2 * 2 = %d > buf_size = %d\n",
388 name_eoff + 2 * sizeof(uint16_t), buf_size);
[0041cd6d]389 free(rr->name);
390 free(rr);
391 return EINVAL;
392 }
393
[9d8bd3ac]394 bp = buf + name_eoff;
395 bsz = buf_size - name_eoff;
[0041cd6d]396
397 if (bsz < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
398 free(rr->name);
399 free(rr);
400 return EINVAL;
401 }
402
403 rr->rtype = dns_uint16_t_decode(bp, bsz);
404 bp += sizeof(uint16_t); bsz -= sizeof(uint16_t);
[7262f89]405 printf("rtype=%u\n", rr->rtype);
[0041cd6d]406
407 rr->rclass = dns_uint16_t_decode(bp, bsz);
408 bp += sizeof(uint16_t); bsz -= sizeof(uint16_t);
[7262f89]409 printf("rclass=%u\n", rr->rclass);
[0041cd6d]410
411 rr->ttl = dns_uint32_t_decode(bp, bsz);
412 bp += sizeof(uint32_t); bsz -= sizeof(uint32_t);
[7262f89]413 printf("ttl=%u\n", rr->ttl);
[0041cd6d]414
415 rdlength = dns_uint16_t_decode(bp, bsz);
416 bp += sizeof(uint16_t); bsz -= sizeof(uint16_t);
[7262f89]417 printf("rdlength=%u\n", rdlength);
[0041cd6d]418
419 if (rdlength > bsz) {
420 free(rr->name);
421 free(rr);
422 return EINVAL;
423 }
424
425 rr->rdata_size = rdlength;
426 rr->rdata = calloc(1, sizeof(rdlength));
427 if (rr->rdata == NULL) {
428 free(rr->name);
429 free(rr);
430 return ENOMEM;
431 }
432
433 memcpy(rr->rdata, bp, rdlength);
434 bp += rdlength;
435 bsz -= rdlength;
436
[9d8bd3ac]437 *eoff = bp - buf;
[0041cd6d]438 *retrr = rr;
439 return EOK;
440}
441
[adae30d]442int dns_message_encode(dns_message_t *msg, void **rdata, size_t *rsize)
443{
444 uint8_t *data;
445 size_t size;
446 dns_header_t hdr;
447 size_t q_size;
448 size_t di;
449 int rc;
450
[08a6382]451 hdr.id = host2uint16_t_be(msg->id);
[adae30d]452
[08a6382]453 hdr.opbits = host2uint16_t_be(
[adae30d]454 (msg->qr << OPB_QR) |
455 (msg->opcode << OPB_OPCODE_l) |
456 (msg->aa ? BIT_V(uint16_t, OPB_AA) : 0) |
457 (msg->tc ? BIT_V(uint16_t, OPB_TC) : 0) |
458 (msg->rd ? BIT_V(uint16_t, OPB_RD) : 0) |
459 (msg->ra ? BIT_V(uint16_t, OPB_RA) : 0) |
[08a6382]460 msg->rcode
461 );
[adae30d]462
[08a6382]463 hdr.qd_count = host2uint16_t_be(list_count(&msg->question));
[adae30d]464 hdr.an_count = 0;
465 hdr.ns_count = 0;
466 hdr.ar_count = 0;
467
468 size = sizeof(dns_header_t);
[08a6382]469 printf("dns header size=%zu\n", size);
[adae30d]470
471 list_foreach(msg->question, link) {
472 dns_question_t *q = list_get_instance(link, dns_question_t, msg);
473 rc = dns_question_encode(q, NULL, 0, &q_size);
474 if (rc != EOK)
475 return rc;
476
[08a6382]477 printf("q_size=%zu\n", q_size);
[adae30d]478 size += q_size;
479 }
480
481 data = calloc(1, size);
482 if (data == NULL)
483 return ENOMEM;
484
485 memcpy(data, &hdr, sizeof(dns_header_t));
486 di = sizeof(dns_header_t);
487
488 list_foreach(msg->question, link) {
489 dns_question_t *q = list_get_instance(link, dns_question_t, msg);
490 rc = dns_question_encode(q, data + di, size - di, &q_size);
491 assert(rc == EOK);
492
493 di += q_size;
494 }
495
[08a6382]496 printf("-> size=%zu, di=%zu\n", size, di);
[adae30d]497 *rdata = data;
498 *rsize = size;
499 return EOK;
500}
501
[0041cd6d]502int dns_message_decode(void *data, size_t size, dns_message_t **rmsg)
503{
504 dns_message_t *msg;
505 dns_header_t *hdr;
[9d8bd3ac]506 size_t doff;
507 size_t field_eoff;
[0041cd6d]508 dns_question_t *question;
509 dns_rr_t *rr;
510 size_t qd_count;
511 size_t an_count;
512 size_t i;
513 int rc;
514
515 msg = calloc(1, sizeof(dns_message_t));
516 if (msg == NULL)
517 return ENOMEM;
518
519 if (size < sizeof(dns_header_t))
520 return EINVAL;
521
522 hdr = data;
523
524 msg->id = uint16_t_be2host(hdr->id);
525 msg->qr = BIT_RANGE_EXTRACT(uint16_t, OPB_QR, OPB_QR, hdr->opbits);
526 msg->opcode = BIT_RANGE_EXTRACT(uint16_t, OPB_OPCODE_h, OPB_OPCODE_l,
527 hdr->opbits);
528 msg->aa = BIT_RANGE_EXTRACT(uint16_t, OPB_AA, OPB_AA, hdr->opbits);
529 msg->tc = BIT_RANGE_EXTRACT(uint16_t, OPB_TC, OPB_TC, hdr->opbits);
530 msg->rd = BIT_RANGE_EXTRACT(uint16_t, OPB_RD, OPB_RD, hdr->opbits);
531 msg->ra = BIT_RANGE_EXTRACT(uint16_t, OPB_RA, OPB_RA, hdr->opbits);
532 msg->rcode = BIT_RANGE_EXTRACT(uint16_t, OPB_RCODE_h, OPB_RCODE_l,
533 hdr->opbits);
534
535 list_initialize(&msg->question);
536 list_initialize(&msg->answer);
537 list_initialize(&msg->authority);
538 list_initialize(&msg->additional);
539
[9d8bd3ac]540 doff = sizeof(dns_header_t);
[0041cd6d]541
542 qd_count = uint16_t_be2host(hdr->qd_count);
543 printf("qd_count = %d\n", (int)qd_count);
544
545 for (i = 0; i < qd_count; i++) {
546 printf("decode question..\n");
[9d8bd3ac]547 rc = dns_question_decode(data, size, doff, &question, &field_eoff);
[0041cd6d]548 if (rc != EOK) {
549 printf("error decoding question\n");
550 goto error;
551 }
552 printf("ok decoding question\n");
553
[7262f89]554 list_append(&question->msg, &msg->question);
[9d8bd3ac]555 doff = field_eoff;
[0041cd6d]556 }
557
558 an_count = uint16_t_be2host(hdr->an_count);
559 printf("an_count = %d\n", an_count);
560
561 for (i = 0; i < an_count; i++) {
562 printf("decode answer..\n");
[9d8bd3ac]563 rc = dns_rr_decode(data, size, doff, &rr, &field_eoff);
[0041cd6d]564 if (rc != EOK) {
565 printf("error decoding answer\n");
566 goto error;
567 }
568 printf("ok decoding answer\n");
569
[7262f89]570 list_append(&rr->msg, &msg->answer);
[9d8bd3ac]571 doff = field_eoff;
[0041cd6d]572 }
573
574 printf("ns_count = %d\n", uint16_t_be2host(hdr->ns_count));
575 printf("ar_count = %d\n", uint16_t_be2host(hdr->ar_count));
576
577 *rmsg = msg;
578 return EOK;
579error:
580 /* XXX Destroy message */
581 return rc;
582}
583
[adae30d]584/** @}
585 */
Note: See TracBrowser for help on using the repository browser.