VECTOR_GENERATE(u16buf,uint16_t)1 VECTOR_GENERATE(u16buf, uint16_t)
2
3 static size_t
4 rdata_from_str_string(const uint8_t *src, ubuf *u) {
5 const uint8_t *ptr = src;
6 size_t u_orig_size = ubuf_size(u);
7 bool is_quoted;
8
9 if (*ptr == '"') {
10 is_quoted = true;
11 ptr++;
12 } else {
13 is_quoted = false;
14 }
15
16 while (*ptr) {
17 if (is_quoted && *ptr == '"') {
18 ptr++;
19 return ptr-src;
20 } else if ((!is_quoted) && isspace(*ptr)) {
21 break;
22 } else if (*ptr == '\\') {
23 ptr++;
24 if (*ptr == 0) {
25 goto err;
26 } else if (*ptr == '"' || *ptr == '\\') {
27 ubuf_append(u, ptr++, 1);
28 } else if (isdigit(*ptr)) {
29 char dstr[4] = { 0, 0, 0, 0 };
30 uint8_t c;
31 uint16_t c_in;
32 strncpy(dstr, (const char *)ptr, sizeof(dstr)-1);
33 if (! (isdigit(dstr[1]) && isdigit(dstr[2]))) {
34 goto err;
35 }
36 if (sscanf(dstr, "%hu", &c_in) == 0) {
37 goto err;
38 }
39 c = (uint8_t) c_in;
40 if (c != c_in) {
41 goto err;
42 }
43 ubuf_append(u, &c, 1);
44 ptr += 3;
45 } else {
46 goto err;
47 }
48 } else if (*ptr >= ' ' && *ptr <= '~') {
49 ubuf_append(u, ptr++, 1);
50 } else {
51 goto err;
52 }
53 }
54
55 if (!is_quoted) {
56 return ptr-src;
57 }
58
59 err:
60 ubuf_clip(u, u_orig_size);
61 return 0;
62 }
63
64 static int
cmp_u16(const void * a,const void * b)65 cmp_u16(const void *a, const void *b) {
66 uint16_t u1 = *(uint16_t *)a;
67 uint16_t u2 = *(uint16_t *)b;
68 return u1 == u2 ? 0 : u1 > u2 ? 1 : -1;
69 }
70
71 wdns_res
_wdns_str_to_rdata_ubuf(ubuf * u,const char * str,uint16_t rrtype,uint16_t rrclass)72 _wdns_str_to_rdata_ubuf(ubuf *u, const char *str,
73 uint16_t rrtype, uint16_t rrclass) {
74 wdns_res res;
75 const record_descr *descr = NULL;
76 size_t u_orig_size = ubuf_size(u);
77
78 if (rrtype < record_descr_len)
79 descr = &record_descr_array[rrtype];
80
81 if (rrtype >= record_descr_len ||
82 (descr != NULL && descr->types[0] == rdf_unknown))
83 {
84 /* generic encoding */
85
86 if (strncmp(str, "\\#", 2)) {
87 res = wdns_res_parse_error;
88 goto err;
89 }
90 str += 2;
91 if (!isspace(*str)) {
92 res = wdns_res_parse_error;
93 goto err;
94 }
95 while (*str && isspace(*str)) {
96 str++;
97 }
98
99 const char * ptr = str;
100 while (*ptr && !isspace(*ptr)) {
101 if (!isdigit(*ptr)) {
102 res = wdns_res_parse_error;
103 goto err;
104 }
105 ptr++;
106 }
107
108 uint16_t rdlen;
109 if (sscanf(str, "%hu", &rdlen) == 0) {
110 res = wdns_res_parse_error;
111 goto err;
112 }
113 str = ptr;
114
115 size_t len = 0;
116 while (*str) {
117 uint8_t c;
118
119 if (isspace(*str)) {
120 str++;
121 continue;
122 }
123
124 if (*(str+1) == 0) {
125 res = wdns_res_parse_error;
126 goto err;
127 }
128 if (!sscanf(str, "%02hhx", &c)) {
129 res = wdns_res_parse_error;
130 goto err;
131 }
132 ubuf_append(u, &c, 1);
133 len++;
134 str += 2;
135 }
136 if (len != rdlen) {
137 res = wdns_res_parse_error;
138 goto err;
139 }
140
141 return (wdns_res_success);
142 } else if (descr != NULL && !(descr->record_class == class_un ||
143 descr->record_class == rrclass))
144 {
145 return (wdns_res_success);
146 }
147
148 for (const uint8_t *t = &descr->types[0]; *t != rdf_end; t++) {
149 if (str == NULL) {
150 break;
151 }
152
153 while (isspace(*str)) {
154 str++;
155 }
156
157 if (*str == 0) {
158 break;
159 }
160
161 switch (*t) {
162 case rdf_name:
163 case rdf_uname: {
164 wdns_name_t *name;
165 char * s;
166 const char *end = strpbrk(str, " \t\r\n");
167
168 if (end != NULL) {
169 s = strndup(str, end-str);
170 } else {
171 s = strdup(str);
172 }
173 name = calloc(1, sizeof(*name));
174
175 res = wdns_str_to_name_case(s, name);
176 if (res != wdns_res_success) {
177 free(s);
178 free(name);
179 goto err;
180 }
181
182 ubuf_append(u, name->data, name->len);
183 str = end;
184
185 free(s);
186 if(name->data) {
187 free (name->data);
188 }
189 free(name);
190
191 break;
192 }
193
194 case rdf_bytes:
195 while (*str) {
196 uint8_t c;
197 if (*(str+1) == 0) {
198 res = wdns_res_parse_error;
199 goto err;
200 }
201 if (!sscanf(str, "%02hhx", &c)) {
202 res = wdns_res_parse_error;
203 goto err;
204 }
205 ubuf_append(u, &c, 1);
206 str += 2;
207 }
208 break;
209
210 case rdf_bytes_b64: {
211 base64_decodestate b64;
212 char *buf;
213 size_t str_len = strlen(str);
214 size_t buf_len;
215
216 base64_init_decodestate(&b64);
217 buf = malloc(str_len+1);
218 buf_len = base64_decode_block((const char *) str, str_len, buf, &b64);
219 ubuf_append(u, (uint8_t *) buf, buf_len);
220 free(buf);
221 str += str_len;
222 break;
223 }
224
225 case rdf_bytes_str: {
226 size_t str_len = strlen(str);
227
228 if (str_len >= 3 && str[0] == '"' && str[str_len - 1] == '"') {
229 if (rdata_from_str_string((const uint8_t *)str, u) == 0) {
230 res = wdns_res_parse_error;
231 goto err;
232 }
233 str += str_len;
234 } else {
235 res = wdns_res_parse_error;
236 goto err;
237 }
238 break;
239 }
240
241 case rdf_ipv6prefix: {
242 uint8_t prefix_len;
243 const char *end = strpbrk(str, " \t\r\n");
244 const char *ptr = str;
245
246 if (end == NULL) {
247 end = str + strlen(str);
248 }
249
250 while (ptr < end) {
251 if (!isdigit(*ptr++)) {
252 res = wdns_res_parse_error;
253 goto err;
254 }
255 }
256
257 if (sscanf(str, "%hhu", &prefix_len) == 0) {
258 res = wdns_res_parse_error;
259 goto err;
260 }
261
262 if (prefix_len > 128) {
263 res = wdns_res_parse_error;
264 goto err;
265 }
266
267 ubuf_append(u, &prefix_len, sizeof(prefix_len));
268
269 str = end;
270 if (str) {
271 while (isspace(*str)) {
272 str++;
273 }
274 }
275
276 if (prefix_len > 0) {
277 if (str == NULL || *str == 0) {
278 res = wdns_res_parse_error;
279 goto err;
280 }
281
282 end = strpbrk(str, " \t\r\n");
283
284 uint8_t oclen = prefix_len / 8;
285 if (prefix_len % 8 > 0) {
286 oclen++;
287 }
288
289 uint8_t addr[16];
290 char * pres;
291
292 if (end != NULL) {
293 pres = strndup(str, end-str);
294 } else {
295 pres = strdup(str);
296 }
297
298 int pton_res = inet_pton(AF_INET6, pres, addr);
299 free(pres);
300
301 if (pton_res == 1) {
302 ubuf_append(u, addr, oclen);
303 } else {
304 res = wdns_res_parse_error;
305 goto err;
306 }
307
308 str = end;
309 }
310
311 break;
312 }
313
314 case rdf_salt: {
315 const char *end = strpbrk(str, " \t\r\n");
316 if (end == NULL) {
317 end = str + strlen(str);
318 }
319
320 if (*str == '-' && (end-str) == 1) {
321 uint8_t c = 0;
322 ubuf_append(u, &c, 1);
323 str++;
324 } else {
325 if (end-str > (2*UINT8_MAX) || (end-str) % 2 == 1) {
326 res = wdns_res_parse_error;
327 goto err;
328 }
329 uint8_t oclen = (uint8_t)(end-str)/2;
330 ubuf_append(u, &oclen, 1);
331
332 while (oclen > 0) {
333 uint8_t c;
334 if (!sscanf(str, "%02hhx", &c)) {
335 res = wdns_res_parse_error;
336 goto err;
337 }
338 ubuf_append(u, &c, 1);
339 str += 2;
340 oclen--;
341 }
342 }
343 break;
344 }
345
346 case rdf_hash: {
347 char *buf;
348 size_t buf_len;
349 const char *end = strpbrk(str, " \t\r\n");
350
351 if (end == NULL) {
352 end = str + strlen(str);
353 }
354
355 size_t str_len = end-str;
356
357 /*
358 * The hashed owner name is presented as one base32 digit.
359 * A single byte would be two base32 digits, therefore we
360 * we can conclude the original data was zero bytes long.
361 */
362 if (str_len == 1) {
363 uint8_t c = 0;
364 ubuf_append(u, &c, 1);
365 str++;
366 break;
367 }
368
369 buf = malloc(str_len);
370 buf_len = base32_decode(buf, str_len, str, str_len);
371
372 uint8_t oclen = (uint8_t)buf_len;
373 if (oclen != buf_len) {
374 free(buf);
375 res = wdns_res_parse_error;
376 goto err;
377 }
378 ubuf_append(u, &oclen, 1);
379 ubuf_append(u, (uint8_t *) buf, oclen);
380 free(buf);
381 str = end;
382 break;
383 }
384
385 case rdf_int8: {
386 uint64_t s_val;
387 uint8_t val;
388 const char *ptr = str;
389 const char *end = strpbrk(str, " \t\r\n");
390
391 if (end == NULL) {
392 end = str + strlen(str);
393 }
394
395 while (ptr < end) {
396 if (!isdigit(*ptr++)) {
397 res = wdns_res_parse_error;
398 goto err;
399 }
400 }
401
402 if (sscanf(str, "%" PRIu64, &s_val)) {
403 val = (uint8_t)s_val;
404 if (val != s_val) {
405 res = wdns_res_parse_error;
406 goto err;
407 }
408 ubuf_append(u, &val, sizeof(val));
409 }
410 str = end;
411 break;
412 }
413
414 case rdf_int16: {
415 uint64_t s_val;
416 uint16_t val;
417 const char *ptr = str;
418 const char *end = strpbrk(str, " \t\r\n");
419
420 if (end == NULL) {
421 end = str + strlen(str);
422 }
423
424 while (ptr < end) {
425 if (!isdigit(*ptr++)) {
426 res = wdns_res_parse_error;
427 goto err;
428 }
429 }
430
431 if (sscanf(str, "%" PRIu64, &s_val)) {
432 val = (uint16_t)s_val;
433 if (val != s_val) {
434 res = wdns_res_parse_error;
435 goto err;
436 }
437 val = htons(val);
438 ubuf_append(u, (uint8_t*)&val, sizeof(val));
439 }
440 str = end;
441 break;
442 }
443
444 case rdf_int32: {
445 uint64_t s_val;
446 uint32_t val;
447 const char *ptr = str;
448 const char *end = strpbrk(str, " \t\r\n");
449
450 if (end == NULL) {
451 end = str + strlen(str);
452 }
453
454 while (ptr < end) {
455 if (!isdigit(*ptr++)) {
456 res = wdns_res_parse_error;
457 goto err;
458 }
459 }
460
461 if (sscanf(str, "%" PRIu64, &s_val)) {
462 val = (uint32_t)s_val;
463 if (val != s_val) {
464 res = wdns_res_parse_error;
465 goto err;
466 }
467 val = htonl(val);
468 ubuf_append(u, (uint8_t*)&val, sizeof(val));
469 }
470 str = end;
471 break;
472 }
473
474 case rdf_ipv4: {
475 uint8_t addr[4];
476 char * pres;
477 int pton_res;
478 const char *end = strpbrk(str, " \t\r\n");
479
480 if (end == NULL) {
481 end = str + strlen(str);
482 }
483
484 pres = strdup(str);
485 pres[end-str] = 0;
486 pton_res = inet_pton(AF_INET, pres, addr);
487 free(pres);
488
489 if (pton_res == 1) {
490 ubuf_append(u, addr, sizeof(addr));
491 } else {
492 res = wdns_res_parse_error;
493 goto err;
494 }
495
496 str = end;
497 break;
498 }
499
500 case rdf_ipv6: {
501 uint8_t addr[16];
502 char * pres;
503 int pton_res;
504 const char *end = strpbrk(str, " \t\r\n");
505
506 if (end != NULL) {
507 pres = strndup(str, end-str);
508 } else {
509 pres = strdup(str);
510 }
511 pton_res = inet_pton(AF_INET6, pres, addr);
512 free(pres);
513
514 if (pton_res == 1) {
515 ubuf_append(u, addr, sizeof(addr));
516 } else {
517 res = wdns_res_parse_error;
518 goto err;
519 }
520
521 str = end;
522 break;
523 }
524
525 case rdf_eui48: {
526 uint8_t a[6] = {0};
527 int ret;
528
529 if (strlen(str) != strlen("01-02-03-04-05-06")) {
530 res = wdns_res_parse_error;
531 goto err;
532 }
533 for (int i = 0; i < 6; i++) {
534 if (!isxdigit(str[3*i]) ||
535 !isxdigit(str[3*i + 1]) ||
536 (i < 5 && str[3*i + 2] != '-'))
537 {
538 res = wdns_res_parse_error;
539 goto err;
540 }
541 }
542 ret = sscanf(str, "%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx",
543 &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);
544 if (ret != 6) {
545 res = wdns_res_parse_error;
546 goto err;
547 }
548 ubuf_append(u, a, 6);
549 str += strlen(str);
550 break;
551 }
552
553 case rdf_eui64: {
554 uint8_t a[8] = {0};
555 int ret;
556
557 if (strlen(str) != strlen("01-02-03-04-05-06-07-08")) {
558 res = wdns_res_parse_error;
559 goto err;
560 }
561 for (int i = 0; i < 8; i++) {
562 if (!isxdigit(str[3*i]) ||
563 !isxdigit(str[3*i + 1]) ||
564 (i < 7 && str[3*i + 2] != '-'))
565 {
566 res = wdns_res_parse_error;
567 goto err;
568 }
569 }
570 ret = sscanf(str, "%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx",
571 &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);
572 if (ret != 8) {
573 res = wdns_res_parse_error;
574 goto err;
575 }
576 ubuf_append(u, a, 8);
577 str += strlen(str);
578 break;
579 }
580
581 case rdf_string: {
582 const char * end = str;
583 size_t u_oclen_offset;
584 size_t str_len;
585 uint8_t oclen = 0;
586
587 u_oclen_offset = ubuf_size(u);
588 ubuf_append(u, &oclen, sizeof(oclen));
589
590 end += rdata_from_str_string((const uint8_t*)str, u);
591 if (end == str) {
592 res = wdns_res_parse_error;
593 goto err;
594 }
595 str_len = ubuf_size(u) - u_oclen_offset - 1;
596
597 oclen = (uint8_t)str_len;
598 if (oclen != str_len) {
599 res = wdns_res_parse_error;
600 goto err;
601 }
602 ubuf_data(u)[u_oclen_offset] = oclen;
603
604 str = end;
605 break;
606 }
607
608 case rdf_repstring: {
609 const char * end;
610 size_t u_oclen_offset;
611 size_t str_len;
612 uint8_t oclen = 0;
613
614 while (*str) {
615 if (isspace(*str)) {
616 str++;
617 continue;
618 }
619
620 end = str;
621 oclen = 0;
622
623 u_oclen_offset = ubuf_size(u);
624 ubuf_append(u, &oclen, sizeof(oclen));
625
626 end += rdata_from_str_string((const uint8_t*)str, u);
627 if (end == str) {
628 res = wdns_res_parse_error;
629 goto err;
630 }
631 str_len = ubuf_size(u) - u_oclen_offset - 1;
632
633 oclen = (uint8_t)str_len;
634 if (oclen != str_len) {
635 res = wdns_res_parse_error;
636 goto err;
637 }
638 ubuf_data(u)[u_oclen_offset] = oclen;
639
640 str = end;
641 }
642
643 break;
644 }
645
646 case rdf_rrtype: {
647 char * s_rrtype;
648 uint16_t my_rrtype;
649 const char *end = strpbrk(str, " \t\r\n");
650
651 if (end != NULL) {
652 s_rrtype = strndup(str, end-str);
653 } else {
654 s_rrtype = strdup(str);
655 }
656 my_rrtype = htons(wdns_str_to_rrtype(s_rrtype));
657 free(s_rrtype);
658
659 if (my_rrtype > 0) {
660 ubuf_append(u, (const uint8_t*)&my_rrtype, sizeof(my_rrtype));
661 } else {
662 res = wdns_res_parse_error;
663 goto err;
664 }
665
666 str = end;
667 break;
668 }
669
670 case rdf_type_bitmap: {
671 const char *end;
672 char *s_rrtype;
673 u16buf *rrtypes;
674 uint16_t my_rrtype, last_rrtype;
675 size_t n;
676 uint8_t window_block, bitmap_len;
677 uint8_t bitmap[32];
678
679 rrtypes = u16buf_init(16);
680 if (! rrtypes) {
681 res = wdns_res_malloc;
682 goto err;
683 }
684
685 while (str != NULL && *str) {
686 if (isspace(*str)) {
687 str++;
688 continue;
689 }
690
691 end = strpbrk(str, " \t\r\n");
692 if (end != NULL) {
693 s_rrtype = strndup(str, end-str);
694 } else {
695 s_rrtype = strdup(str);
696 }
697
698 my_rrtype = wdns_str_to_rrtype(s_rrtype);
699 free(s_rrtype);
700
701 if (my_rrtype == 0 || (rrtype >= 128 && rrtype < 256) || rrtype == 65535) {
702 u16buf_destroy(&rrtypes);
703 res = wdns_res_parse_error;
704 goto err;
705 }
706
707 u16buf_add(rrtypes, my_rrtype);
708 str = end;
709 }
710 qsort(u16buf_data(rrtypes), u16buf_size(rrtypes), sizeof(uint16_t), cmp_u16);
711
712 memset(bitmap, 0, sizeof(bitmap));
713 window_block = 0;
714 bitmap_len = 0;
715 last_rrtype = 0;
716
717 for (n = 0; n < u16buf_size(rrtypes); n++) {
718 my_rrtype = u16buf_value(rrtypes, n);
719 if (my_rrtype == last_rrtype) {
720 continue;
721 }
722 last_rrtype = my_rrtype;
723
724 uint8_t cur_window = my_rrtype / 256;
725
726 if (cur_window != window_block) {
727 ubuf_append(u, (const uint8_t*)&window_block, sizeof(window_block));
728 ubuf_append(u, (const uint8_t*)&bitmap_len, sizeof(bitmap_len));
729 ubuf_append(u, (const uint8_t*)bitmap, bitmap_len);
730 memset(bitmap, 0, sizeof(bitmap));
731 window_block = cur_window;
732 }
733
734 uint8_t offset = my_rrtype % 256;
735 uint8_t byte = offset / 8;
736 uint8_t bit = offset % 8;
737
738 bitmap[byte] |= 0x80 >> bit;
739 bitmap_len = 1 + byte;
740 }
741 ubuf_append(u, (const uint8_t*)&window_block, sizeof(window_block));
742 ubuf_append(u, (const uint8_t*)&bitmap_len, sizeof(bitmap_len));
743 ubuf_append(u, (const uint8_t*)bitmap, bitmap_len);
744
745 u16buf_destroy(&rrtypes);
746 break;
747 }
748 default: {
749 res = wdns_res_failure;
750 goto err;
751 }
752 } /* switch */
753 }
754
755 return wdns_res_success;
756
757 err:
758 ubuf_clip(u, u_orig_size);
759 return res;
760 }
761