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

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

Pointer decoding.

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