1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 #include "dnscore/dnscore-config.h"
36
37 #include <fcntl.h>
38 #include <stddef.h>
39 #include <arpa/inet.h>
40
41 #include <dnscore/parser.h>
42
43 #include <dnscore/logger.h>
44 #include <dnscore/file_input_stream.h>
45 #include <dnscore/bytearray_output_stream.h>
46 #include <dnscore/bytearray_input_stream.h>
47 #include <dnscore/buffer_input_stream.h>
48
49 #include <dnscore/typebitmap.h>
50 #include <dnscore/base16.h>
51 #include <dnscore/base32hex.h>
52 #include <dnscore/base64.h>
53 #include <dnscore/fdtools.h>
54
55 #include "dnscore/zone_reader_text.h"
56
57 #define ZFREADER_TAG 0x524544414552465a
58 #define ZFERRMSG_TAG 0x47534d525245465a
59 #define ZONE_FILE_READER_INCLUDE_DEPTH_MAX 16
60
61 #define DOT_SYMBOL '.'
62
63 #if !DNSCORE_HAS_FULL_ASCII7
64 #define AT_SYMBOL '@'
65 #define VAR_SYMBOL '$'
66 #else
67 #define AT_SYMBOL ((char)0xff)
68 #define VAR_SYMBOL ((char)0xfe)
69 //#define DOT_SYMBOL ((char)0xfd)
70 #endif
71
72 logger_handle *g_zone_logger = LOGGER_HANDLE_SINK;
73 #define MODULE_MSG_HANDLE g_zone_logger
74
75 #define DEBUG_BENCH_TEXT_ZONE_PARSE 1
76 #if !DEBUG
77 #undef DEBUG_BENCH_TEXT_ZONE_PARSE
78 #define DEBUG_BENCH_TEXT_ZONE_PARSE 0
79 #endif
80
81 static bool zone_reader_text_init_error_codes_done = FALSE;
82
83 static const char * const zfr_string_delimiters = "\"\"";
84 static const char * const zfr_multiline_delimiters = "()";
85 static const char * const zrf_comment_markers = ";";
86 static const char * const zrf_blank_makers = "\040\t\r";
87 static const char * const zfr_escape_characters = "\\";
88
89 #define ZONE_FILE_READER_MESSAGE_STATIC 0
90 #define ZONE_FILE_READER_MESSAGE_ALLOCATED 1
91
92 typedef struct zone_reader_text zone_reader_text;
93 struct zone_reader_text
94 {
95 parser_s parser;
96 resource_record* unread_next;
97 s32 rttl_default; // $TTL
98 s32 rttl_current;
99 u32 dot_origin_size; // with the CHR0 sentinel
100 s32 origin_stack_size;
101 u16 rclass_current;
102 u16 rdata_size;
103 bool soa_found;
104 bool template_source;
105 bool rttl_default_defined;
106 bool rttl_current_defined;
107
108 u8 domain[MAX_DOMAIN_LENGTH + 1];
109 u8 origin[MAX_DOMAIN_LENGTH + 1];
110 char dot_origin[MAX_DOMAIN_LENGTH + 1];
111 u8 *origin_stack[PARSER_INCLUDE_DEPTH_MAX];
112
113 u8 rdata[RDATA_MAX_LENGTH];
114
115 input_stream includes[ZONE_FILE_READER_INCLUDE_DEPTH_MAX];
116 char *file_name[ZONE_FILE_READER_INCLUDE_DEPTH_MAX];
117
118 u8 includes_count;
119 //
120 ya_result error_message_code;
121 u8 error_message_allocated; // 0: static 1: malloc
122 char *error_message_buffer; // It's not aligned but this is an exception :
123 // _ This is a rarely used structure (don't care too much about a hole)
124 // _ This is an hopefully rarely used field (best case: "never" (besides setting it up to NULL))
125 // _ Putting it among the more popular fields will likely increase misses
126 };
127
128 static void
zone_reader_text_free_error_message(zone_reader_text * zfr)129 zone_reader_text_free_error_message(zone_reader_text *zfr)
130 {
131 if(zfr->error_message_allocated == ZONE_FILE_READER_MESSAGE_ALLOCATED)
132 {
133 free(zfr->error_message_buffer);
134 }
135 }
136 /*
137 static void
138 zone_reader_text_clear_error_message(zone_reader_text *zfr)
139 {
140 zone_reader_text_free_error_message(zfr);
141 zfr->error_message_buffer = NULL;
142 }
143 */
144
145 static ya_result
zone_reader_text_cstr_to_locase_dnsname_with_check_len_with_origin(u8 * name_parm,const char * text,u32 text_len,const u8 * origin,parser_s * p)146 zone_reader_text_cstr_to_locase_dnsname_with_check_len_with_origin(u8* name_parm, const char* text, u32 text_len, const u8 *origin, parser_s *p)
147 {
148 ya_result ret;
149 if(FAIL(ret = cstr_to_locase_dnsname_with_check_len_with_origin(name_parm, text, text_len, origin)))
150 {
151 bool retry = FALSE;
152 char retry_text[MAX_DOMAIN_LENGTH];
153
154 if(text_len <= MAX_DOMAIN_LENGTH)
155 {
156 for(u32 i = 0; i < text_len; ++i)
157 {
158 char c = text[i];
159 switch(c)
160 {
161 case VAR_SYMBOL:
162 {
163 retry_text[i] = '$';
164 retry = TRUE;
165 break;
166 }
167 case AT_SYMBOL:
168 {
169 retry_text[i] = '@';
170 retry = TRUE;
171 break;
172 }
173 default:
174 {
175 retry_text[i] = c;
176 break;
177 }
178 }
179 }
180 }
181
182 if(retry)
183 {
184 if(ISOK(ret = cstr_to_locase_dnsname_with_check_len_with_origin(name_parm, retry_text, text_len, origin)))
185 {
186 // an escape is probably missing
187 /*
188 char *file_name = "?";
189 if((p->includes_count > 0) && (p->includes_count < ZONE_FILE_READER_INCLUDE_DEPTH_MAX))
190 {
191 if(p->file_name[p->includes_count - 1] != NULL)
192 {
193 file_name = p->file_name[p->includes_count - 1];
194 }
195 }
196
197 log_warn("zone parse: there is probably an escape missing in front of a '$' or a '@' in file '%s' at line %u for %{dnsname}", file_name, p->line_number, domain);
198 */
199 log_warn("zone parse: there is probably an escape missing in front of a '$' or a '@' at line %u for %{dnsname}", p->line_number, name_parm);
200 }
201 }
202 }
203
204 return ret;
205 }
206
207 static inline ya_result
zone_reader_text_copy_rdata_inline(parser_s * p,u16 rtype,u8 * rdata,u32 rdata_size,const u8 * origin)208 zone_reader_text_copy_rdata_inline(parser_s *p, u16 rtype, u8 *rdata, u32 rdata_size, const u8 *origin)
209 {
210 const char *text;
211 u32 text_len;
212 ya_result return_code;
213 char text_buffer[1024];
214 type_bit_maps_context tbmctx;
215 if(FAIL(return_code = parser_copy_next_word(p, text_buffer, sizeof(text_buffer))))
216 {
217 return return_code;
218 }
219
220 text = text_buffer;
221 text_len = return_code;
222
223 if(!((text_len >= 1) && (text[0] == '#')))
224 {
225 switch(rtype)
226 {
227 case TYPE_A:
228 {
229 if(inet_pton(AF_INET, text, rdata))
230 {
231 return_code = 4;
232 }
233 else
234 {
235 return_code = INCORRECT_IPADDRESS;
236 }
237
238 break;
239 }
240 case TYPE_AAAA:
241 {
242 if(inet_pton(AF_INET6, text, rdata))
243 {
244 return_code = 16;
245 }
246 else
247 {
248 return_code = INCORRECT_IPADDRESS;
249 }
250 break;
251 }
252 case TYPE_SOA:
253 {
254 s32 total_size;
255
256 if(FAIL(return_code = zone_reader_text_cstr_to_locase_dnsname_with_check_len_with_origin(rdata, text, text_len, origin, p)))
257 {
258 break;
259 }
260
261 total_size = return_code;
262
263 rdata += return_code;
264
265 if(FAIL(return_code = parser_copy_next_fqdn_locase_with_origin(p, rdata, origin)))
266 {
267 break;
268 }
269
270 total_size += return_code + 20;
271
272 rdata += return_code;
273 return_code = total_size;
274
275 for(u8 i = 5; i > 0; i--)
276 {
277 s32 tmp_int32;
278 ya_result err;
279 if(FAIL(err = parser_copy_next_ttl(p, &tmp_int32)))
280 {
281 return_code = err;
282 break;
283 }
284 tmp_int32 = htonl(tmp_int32);
285 SET_U32_AT_P(rdata, tmp_int32);
286 rdata += 4;
287 }
288
289 break;
290 }
291 case TYPE_NS:
292 case TYPE_CNAME:
293 case TYPE_PTR:
294 #if !HAS_NOOBSOLETETYPES
295 case TYPE_MD: /** @NOTE: obsolete */
296 case TYPE_MF: /** NOTE: obsolete */
297 case TYPE_MB: /** NOTE: obsolete */
298 case TYPE_MG: /** NOTE: obsolete */
299 case TYPE_MR: /** NOTE: obsolete */
300 #endif
301 {
302 return_code = zone_reader_text_cstr_to_locase_dnsname_with_check_len_with_origin(rdata, text, text_len, origin, p);
303
304 break;
305 }
306 #if !HAS_NOOBSOLETETYPES
307 case TYPE_WKS:
308 {
309 // ip address
310 if(!inet_pton(AF_INET, text, rdata))
311 {
312 return_code = INCORRECT_IPADDRESS;
313 break;
314 }
315 rdata += 4;
316
317 int protocol;
318 if(FAIL(return_code = parser_get_network_protocol_from_next_word(p, &protocol)))
319 {
320 break;
321 }
322
323 rdata[0] = (u8) protocol;
324 rdata++;
325
326 ZEROMEMORY(rdata, rdata_size - 1);
327 int port_limit = (rdata_size - 5) << 3;
328 int max_index = -1;
329
330 for(;;)
331 {
332 int service_port;
333 if(FAIL(return_code = parser_get_network_service_port_from_next_word(p, &service_port)))
334 {
335 break;
336 }
337
338 if(service_port > port_limit)
339 {
340 return_code = MAKE_ERRNO_ERROR(ERANGE); /// @todo 20181018 edf -- consider having a value/parameter "out of range" error code
341 break;
342 }
343
344 int index = service_port >> 3;
345
346 rdata[index] |= 0x80 >> (service_port & 7);
347
348 if(index > max_index)
349 {
350 max_index = index;
351 }
352 }
353
354 if(FAIL(return_code))
355 {
356 break;
357 }
358
359 if(max_index < 0) // @todo 20150608 timh -- is this the right way to do it?
360 {
361 return_code = INVALID_RECORD;
362 break;
363 }
364
365 return_code = max_index + 6; // ipv4 + proto + index=>+1
366
367 parser_set_eol(p); // @todo 20150608 timh -- is this necessary?
368 break;
369 }
370 #endif
371 case TYPE_MX:
372 case TYPE_KX:
373 case TYPE_LP:
374 case TYPE_AFSDB:
375 {
376 u16 preference;
377
378 if(FAIL(return_code = parser_get_u16(text, text_len, &preference)))
379 {
380 break;
381 }
382 preference = htons(preference);
383 SET_U16_AT_P(rdata, preference);
384 rdata += 2;
385
386 if(FAIL(return_code = parser_copy_next_fqdn_locase_with_origin(p, rdata, origin)))
387 {
388 break;
389 }
390
391 return_code += 2;
392
393 break;
394 }
395
396 case TYPE_RRSIG:
397 {
398 u16 rtype;
399
400 if(FAIL(return_code = dns_type_from_case_name_length(text, text_len, &rtype)))
401 {
402 break;
403 }
404 SET_U16_AT_P(rdata, rtype);
405 rdata += 2;
406
407 // algorithm (8 bits integer)
408
409 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
410 {
411 break;
412 }
413
414 rdata++;
415
416 // labels (8 bits integer)
417
418 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
419 {
420 break;
421 }
422
423 rdata++;
424
425 // original TTL (32 bits integer)
426
427 s32 ttl;
428
429 if(FAIL(return_code = parser_copy_next_ttl(p, &ttl)))
430 {
431 break;
432 }
433
434 ttl = htonl(ttl);
435 SET_U32_AT_P(rdata, ttl);
436 rdata += 4;
437
438 // signature expiration (YYYYMMDDHHMMSS epoch -> 32 bits)
439
440 u32 epoch;
441
442 if(FAIL(return_code = parser_copy_next_yyyymmddhhmmss(p, &epoch)))
443 {
444 break;
445 }
446
447 epoch = htonl(epoch);
448 SET_U32_AT_P(rdata, epoch);
449 rdata += 4;
450
451 // signature inception (YYYYMMDDHHMMSS epoch -> 32 bits)
452
453 if(FAIL(return_code = parser_copy_next_yyyymmddhhmmss(p, &epoch)))
454 {
455 break;
456 }
457
458 epoch = htonl(epoch);
459 SET_U32_AT_P(rdata, epoch);
460 rdata += 4;
461
462 // key tag (16 bits integer)
463
464 u16 tag;
465
466 if(FAIL(return_code = parser_copy_next_u16(p, &tag)))
467 {
468 break;
469 }
470
471 tag = htons(tag);
472 SET_U16_AT_P(rdata, tag);
473 rdata += 2;
474
475 // signer's name (fqdn)
476
477 if(FAIL(return_code = parser_copy_next_fqdn_with_origin(p, rdata, origin)))
478 {
479 break;
480 }
481
482 rdata += return_code;
483
484 u32 signer_len = return_code;
485
486 // signature (base64)
487
488 if(FAIL(return_code = parser_concat_next_tokens_nospace(p)))
489 {
490 break;
491 }
492
493 if(FAIL(return_code = base64_decode(parser_text(p), parser_text_length(p), rdata)))
494 {
495 break;
496 }
497
498 return_code += 18 + signer_len;
499
500 break;
501 }
502
503 case TYPE_DNSKEY:
504 case TYPE_CDNSKEY:
505 {
506 // flags
507
508 u16 flags;
509
510 if(FAIL(return_code = parser_get_u16(text, text_len, &flags)))
511 {
512 break;
513 }
514
515 flags = htons(flags);
516 SET_U16_AT_P(rdata, flags);
517 rdata += 2;
518
519 // protocol (8 bits integer)
520
521 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
522 {
523 break;
524 }
525
526 rdata++;
527
528 // algorithm (8 bits integer)
529
530 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
531 {
532 if(ISOK(return_code = parser_copy_word(p, text_buffer, sizeof(text_buffer))))
533 {
534 if(FAIL(return_code = dns_encryption_algorithm_from_name(text_buffer, rdata)))
535 {
536 break;
537 }
538 }
539 else
540 {
541 break;
542 }
543 }
544
545 rdata++;
546
547 // key (base64)
548
549 if(FAIL(return_code = parser_concat_next_tokens_nospace(p)))
550 {
551 break;
552 }
553
554 if(FAIL(return_code = base64_decode(parser_text(p), parser_text_length(p), rdata)))
555 {
556 break;
557 }
558
559 return_code += 4;
560
561 break;
562 }
563
564 case TYPE_OPENPGPKEY:
565 {
566 if(FAIL(return_code = parser_concat_current_and_next_tokens_nospace(p)))
567 {
568 break;
569 }
570
571 return_code = base64_decode(parser_text(p), parser_text_length(p), rdata);
572 break;
573 }
574
575 case TYPE_NSEC3PARAM:
576 {
577 // hash algorithm
578
579 if(FAIL(return_code = parser_get_u8(text, text_len, rdata)))
580 {
581 break;
582 }
583
584 rdata++;
585
586 // flags
587
588 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
589 {
590 break;
591 }
592
593 rdata++;
594
595 // iterations
596
597 u16 iterations;
598
599 if(FAIL(return_code = parser_copy_next_u16(p, &iterations)))
600 {
601 break;
602 }
603
604 iterations = htons(iterations);
605 SET_U16_AT_P(rdata, iterations);
606 rdata += 2;
607
608 // salt
609
610 if(FAIL(return_code = parser_next_token(p)))
611 {
612 break;
613 }
614
615 if(! ((parser_text_length(p) == 1) && (parser_text(p)[0] == '-')) )
616 {
617 if(FAIL(return_code = base16_decode(parser_text(p), parser_text_length(p), rdata + 1)))
618 {
619 break;
620 }
621
622 if(return_code > 255)
623 {
624 return_code = ZONEFILE_SALT_TOO_BIG; // parse error ...
625 break;
626 }
627 }
628 else
629 {
630 // no salt
631 return_code = 0;
632 }
633
634 rdata[0] = (u8)return_code;
635 return_code += 5;
636
637 break;
638 }
639
640 case TYPE_NSEC3:
641 {
642 u8 *rdata_start = rdata;
643 // hash algorithm
644
645 if(FAIL(return_code = parser_get_u8(text, text_len, rdata)))
646 {
647 break;
648 }
649
650 rdata++;
651
652 // flags
653
654 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
655 {
656 break;
657 }
658
659 rdata++;
660
661 // iterations
662
663 u16 iterations;
664
665 if(FAIL(return_code = parser_copy_next_u16(p, &iterations)))
666 {
667 break;
668 }
669
670 iterations = htons(iterations);
671 SET_U16_AT_P(rdata, iterations);
672 rdata += 2;
673
674 // salt
675
676 if(FAIL(return_code = parser_next_token(p)))
677 {
678 break;
679 }
680
681 if(! ((parser_text_length(p) == 1) && (parser_text(p)[0] == '-')) )
682 {
683 if(FAIL(return_code = base16_decode(parser_text(p), parser_text_length(p), rdata + 1)))
684 {
685 break;
686 }
687
688 if(return_code > 255)
689 {
690 return_code = ZONEFILE_SALT_TOO_BIG; // parse error ...
691 break;
692 }
693 }
694 else
695 {
696 return_code = 0;
697 }
698
699 rdata[0] = (u8)return_code;
700 rdata += return_code + 1;
701
702 // digest
703
704 if(FAIL(return_code = parser_next_token(p)))
705 {
706 break;
707 }
708
709 if(FAIL(return_code = base32hex_decode(parser_text(p), parser_text_length(p), rdata + 1)))
710 {
711 break;
712 }
713
714 rdata[0] = (u8)return_code;
715 rdata += return_code + 1;
716
717 // type bitmap
718
719 if(FAIL(return_code = parser_type_bit_maps_initialise(p, &tbmctx)))
720 {
721 break;
722 }
723
724 if(return_code > 0)
725 {
726 type_bit_maps_write(&tbmctx, rdata);
727 rdata += return_code;
728 }
729
730 return_code = rdata - rdata_start;
731
732 parser_set_eol(p);
733
734 break;
735 }
736
737 case TYPE_NSEC:
738 {
739 u8 *rdata_start = rdata;
740
741 if(FAIL(return_code = zone_reader_text_cstr_to_locase_dnsname_with_check_len_with_origin(rdata, text, text_len, origin, p)))
742 {
743 break;
744 }
745
746 rdata += return_code;
747
748 // type bitmap
749
750 if(FAIL(return_code = parser_type_bit_maps_initialise(p, &tbmctx)))
751 {
752 break;
753 }
754
755 type_bit_maps_write(&tbmctx, rdata);
756
757 rdata += return_code;
758
759 return_code = rdata - rdata_start;
760
761 parser_set_eol(p);
762
763 break;
764 }
765
766 case TYPE_DS:
767 case TYPE_CDS:
768 case TYPE_DLV:
769 {
770 // keytag
771
772 u16 keytag;
773
774 if(FAIL(return_code = parser_get_u16(text, text_len, &keytag)))
775 {
776 break;
777 }
778 keytag = htons(keytag);
779 SET_U16_AT_P(rdata, keytag);
780 rdata += 2;
781
782 // algorithm
783
784 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
785 {
786 break;
787 }
788
789 rdata++;
790
791 // digest type
792
793 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
794 {
795 break;
796 }
797
798 rdata++;
799
800 // digest
801
802 if(FAIL(return_code = parser_concat_next_tokens_nospace(p)))
803 {
804 break;
805 }
806
807 if(FAIL(return_code = base16_decode(parser_text(p), parser_text_length(p), rdata)))
808 {
809 break;
810 }
811
812 return_code += 4;
813
814 break;
815 }
816
817 case TYPE_TXT:
818 case TYPE_SPF: // discontinued
819 {
820 u8 *rdata_start = rdata;
821
822 for(;;)
823 {
824 if(text_len > 255)
825 {
826 return_code = ZONEFILE_TEXT_TOO_BIG;
827 break;
828 }
829
830 *rdata++ = (u8)text_len;
831 memcpy(rdata, text, text_len);
832 rdata += text_len;
833
834 if(FAIL(return_code = parser_next_token(p)))
835 {
836 break;
837 }
838
839 if((return_code & (PARSER_COMMENT|PARSER_EOL|PARSER_EOF)) != 0)
840 {
841 // stop
842
843 break;
844 }
845 text = parser_text(p);
846 text_len = parser_text_length(p);
847 }
848
849 if(ISOK(return_code))
850 {
851 return_code = rdata - rdata_start;
852 parser_set_eol(p);
853 }
854
855 break;
856 }
857
858 case TYPE_SSHFP:
859 {
860 // algorithm
861
862 if(FAIL(return_code = parser_get_u8(text, text_len, rdata)))
863 {
864 break;
865 }
866
867 rdata++;
868
869 // fp type
870
871 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
872 {
873 break;
874 }
875
876 rdata++;
877
878 // fingerprint
879
880 if(FAIL(return_code = parser_concat_next_tokens_nospace(p)))
881 {
882 break;
883 }
884
885 if(FAIL(return_code = base16_decode(parser_text(p), parser_text_length(p), rdata)))
886 {
887 break;
888 }
889
890 return_code += 2;
891
892 break;
893 }
894 case TYPE_TLSA:
895 {
896 // ?
897
898 if(FAIL(return_code = parser_get_u8(text, text_len, rdata)))
899 {
900 break;
901 }
902
903 rdata++;
904
905 // ?
906
907 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
908 {
909 break;
910 }
911
912 rdata++;
913
914 // ?
915
916 if(FAIL(return_code = parser_copy_next_u8(p, rdata)))
917 {
918 break;
919 }
920
921 rdata++;
922
923 // ?
924
925 if(FAIL(return_code = parser_concat_next_tokens_nospace(p)))
926 {
927 break;
928 }
929
930 if(FAIL(return_code = base16_decode(parser_text(p), parser_text_length(p), rdata)))
931 {
932 break;
933 }
934
935 return_code += 3;
936
937 break;
938 }
939
940 case TYPE_SRV:
941 {
942 u16 tmp16;
943
944 // ?
945
946 if(FAIL(return_code = parser_get_u16(text, text_len, &tmp16)))
947 {
948 break;
949 }
950 tmp16 = htons(tmp16);
951 SET_U16_AT_P(rdata, tmp16);
952 rdata += 2;
953
954 // ?
955
956 if(FAIL(return_code = parser_copy_next_u16(p, &tmp16)))
957 {
958 break;
959 }
960 tmp16 = htons(tmp16);
961 SET_U16_AT_P(rdata, tmp16);
962 rdata += 2;
963
964 // ?
965
966 if(FAIL(return_code = parser_copy_next_u16(p, &tmp16)))
967 {
968 break;
969 }
970 tmp16 = htons(tmp16);
971 SET_U16_AT_P(rdata, tmp16);
972 rdata += 2;
973
974 if(FAIL(return_code = parser_copy_next_fqdn_with_origin(p, rdata, origin)))
975 {
976 break;
977 }
978
979 return_code += 6;
980 break;
981 }
982
983 case TYPE_NAPTR:
984 {
985 u8 *rdata_start = rdata;
986 u16 tmp16;
987
988 // order
989
990 if(FAIL(return_code = parser_get_u16(text, text_len, &tmp16)))
991 {
992 break;
993 }
994 tmp16 = htons(tmp16);
995 SET_U16_AT_P(rdata, tmp16);
996 rdata += 2;
997
998 // preference
999
1000 if(FAIL(return_code = parser_copy_next_u16(p, &tmp16)))
1001 {
1002 break;
1003 }
1004 tmp16 = htons(tmp16);
1005 SET_U16_AT_P(rdata, tmp16);
1006 rdata += 2;
1007
1008 // flags
1009
1010 if(FAIL(return_code = parser_next_token(p)))
1011 {
1012 break;
1013 }
1014
1015 if((return_code & (PARSER_COMMENT|PARSER_EOL|PARSER_EOF)) != 0)
1016 {
1017 // stop
1018
1019 break;
1020 }
1021 text = parser_text(p);
1022 text_len = parser_text_length(p);
1023
1024 if(text_len > 255)
1025 {
1026 return_code = ZONEFILE_FLAGS_TOO_BIG;
1027 break;
1028 }
1029
1030 *rdata++ = (u8)text_len;
1031 memcpy(rdata, text, text_len);
1032 rdata += text_len;
1033
1034 // service
1035
1036 if(FAIL(return_code = parser_next_token(p)))
1037 {
1038 break;
1039 }
1040
1041 if((return_code & (PARSER_COMMENT|PARSER_EOL|PARSER_EOF)) != 0)
1042 {
1043 // stop
1044
1045 break;
1046 }
1047 text = parser_text(p);
1048 text_len = parser_text_length(p);
1049
1050 if(text_len > 255)
1051 {
1052 return_code = ZONEFILE_SERVICE_TOO_BIG;
1053 break;
1054 }
1055
1056 *rdata++ = (u8)text_len;
1057 memcpy(rdata, text, text_len);
1058 rdata += text_len;
1059
1060 // regex
1061
1062 if(FAIL(return_code = parser_next_token(p)))
1063 {
1064 break;
1065 }
1066
1067 if((return_code & (PARSER_COMMENT|PARSER_EOL|PARSER_EOF)) != 0)
1068 {
1069 // stop
1070
1071 break;
1072 }
1073 text = parser_text(p);
1074 text_len = parser_text_length(p);
1075
1076 if(text_len > 255)
1077 {
1078 return_code = ZONEFILE_REGEX_TOO_BIG;
1079 break;
1080 }
1081
1082 *rdata++ = (u8)text_len;
1083 memcpy(rdata, text, text_len);
1084 rdata += text_len;
1085
1086 if(FAIL(return_code = parser_copy_next_fqdn_with_origin(p, rdata, origin)))
1087 {
1088 break;
1089 }
1090
1091 return_code += rdata - rdata_start;
1092 break;
1093 }
1094
1095 // exist out of two parts
1096 // 1. mbox-dname
1097 // 2. txt-dname
1098 case TYPE_RP:
1099 {
1100 u8 *rdata_start = rdata;
1101
1102 // 1.mbox-name1
1103 //s32 total_size;
1104
1105 // return_code = "length" or "error code"
1106 if(FAIL(return_code = zone_reader_text_cstr_to_locase_dnsname_with_check_len_with_origin(rdata, text, text_len, origin, p)))
1107 {
1108 break;
1109 }
1110
1111 // set rdata to the next chunk
1112 rdata += return_code;
1113
1114 if(FAIL(return_code = parser_copy_next_fqdn_locase_with_origin(p, rdata, origin)))
1115 {
1116 break;
1117 }
1118
1119 return_code = rdata - rdata_start + return_code;
1120 break;
1121 }
1122
1123 case TYPE_HINFO: // should not be supported anymore
1124 {
1125 u8 *rdata_start = rdata;
1126
1127 if(text_len > 255)
1128 {
1129 return_code = ZONEFILE_TEXT_TOO_BIG;
1130 break;
1131 }
1132
1133 *rdata++ = (u8)text_len;
1134 memcpy(rdata, text, text_len);
1135 rdata += text_len;
1136
1137 if(FAIL(return_code = parser_next_token(p)))
1138 {
1139 break;
1140 }
1141
1142 if((return_code & (PARSER_COMMENT|PARSER_EOL|PARSER_EOF)) != 0)
1143 {
1144 // stop
1145
1146 break;
1147 }
1148 text = parser_text(p);
1149 text_len = parser_text_length(p);
1150
1151 if(text_len > 255)
1152 {
1153 return_code = ZONEFILE_TEXT_TOO_BIG;
1154 break;
1155 }
1156
1157 *rdata++ = (u8)text_len;
1158 memcpy(rdata, text, text_len);
1159 rdata += text_len;
1160
1161 if(FAIL(return_code = parser_copy_next_fqdn_with_origin(p, rdata, origin)))
1162 {
1163 break;
1164 }
1165
1166 return_code += rdata - rdata_start;
1167
1168 break;
1169 }
1170
1171 case TYPE_NID:
1172 case TYPE_L64:
1173 {
1174 u16 preference;
1175
1176 if(FAIL(return_code = parser_get_u16(text, text_len, &preference)))
1177 {
1178 break;
1179 }
1180 preference = htons(preference);
1181 SET_U16_AT_P(rdata, preference);
1182
1183 if(FAIL(return_code = parser_next_token(p)))
1184 {
1185 break;
1186 }
1187
1188 memcpy(text_buffer, parser_text(p), parser_text_length(p));
1189 text_buffer[parser_text_length(p)] = '\0';
1190
1191 // hex:hex:hex:hex
1192
1193 unsigned int a,b,c,d;
1194 if(sscanf(text_buffer, "%x:%x:%x:%x", &a,&b,&c,&d) != 4)
1195 {
1196 return_code = PARSEB16_ERROR;
1197 break;
1198 }
1199
1200 if((a|b|c|d) > 65535)
1201 {
1202 return_code = PARSEB16_ERROR;
1203 break;
1204 }
1205
1206 SET_U16_AT(rdata[2], htons((u16)a));
1207 SET_U16_AT(rdata[4], htons((u16)b));
1208 SET_U16_AT(rdata[6], htons((u16)c));
1209 SET_U16_AT(rdata[8], htons((u16)d));
1210
1211 return_code = 10;
1212
1213 break;
1214 }
1215 case TYPE_L32:
1216 {
1217 u16 preference;
1218
1219 if(FAIL(return_code = parser_get_u16(text, text_len, &preference)))
1220 {
1221 break;
1222 }
1223 preference = htons(preference);
1224 SET_U16_AT_P(rdata, preference);
1225 if(FAIL(return_code = parser_next_token(p)))
1226 {
1227 break;
1228 }
1229
1230 memcpy(text_buffer, parser_text(p), parser_text_length(p));
1231 text_buffer[parser_text_length(p)] = '\0';
1232
1233 // hex:hex:hex:hex
1234
1235 unsigned int a,b,c,d;
1236 if(sscanf(text_buffer, "%u.%u.%u.%u", &a,&b,&c,&d) != 4)
1237 {
1238 return_code = PARSEB16_ERROR;
1239 break;
1240 }
1241
1242 if((a|b|c|d) > 255)
1243 {
1244 return_code = PARSEB16_ERROR;
1245 break;
1246 }
1247
1248 rdata[2] = (u8)a;
1249 rdata[3] = (u8)b;
1250 rdata[4] = (u8)c;
1251 rdata[5] = (u8)d;
1252
1253 return_code = 6;
1254
1255 break;
1256 }
1257
1258 case TYPE_EUI48:
1259 {
1260 text_buffer[parser_text_length(p)] = '\0';
1261
1262 unsigned int a,b,c,d,e,f;
1263 if(sscanf(text_buffer, "%x-%x-%x-%x-%x-%x", &a,&b,&c,&d,&e,&f) != 6)
1264 {
1265 return_code = PARSEB16_ERROR;
1266 break;
1267 }
1268
1269 if((a|b|c|d|e|f) > 255)
1270 {
1271 return_code = PARSEB16_ERROR;
1272 break;
1273 }
1274
1275 rdata[0] = (u8)a;
1276 rdata[1] = (u8)b;
1277 rdata[2] = (u8)c;
1278 rdata[3] = (u8)d;
1279 rdata[4] = (u8)e;
1280 rdata[5] = (u8)f;
1281
1282 return_code = 6;
1283 break;
1284 }
1285
1286 case TYPE_EUI64:
1287 {
1288 text_buffer[parser_text_length(p)] = '\0';
1289
1290 unsigned int a,b,c,d,e,f,g,h;
1291 if(sscanf(text_buffer, "%x-%x-%x-%x-%x-%x-%x-%x", &a,&b,&c,&d,&e,&f,&g,&h) != 8)
1292 {
1293 return_code = PARSEB16_ERROR;
1294 break;
1295 }
1296
1297 if((a|b|c|d|e|f|g|h) > 255)
1298 {
1299 return_code = PARSEB16_ERROR;
1300 break;
1301 }
1302
1303 rdata[0] = (u8)a;
1304 rdata[1] = (u8)b;
1305 rdata[2] = (u8)c;
1306 rdata[3] = (u8)d;
1307 rdata[4] = (u8)e;
1308 rdata[5] = (u8)f;
1309 rdata[6] = (u8)g;
1310 rdata[7] = (u8)h;
1311
1312 return_code = 8;
1313 break;
1314 }
1315 case TYPE_TSIG:
1316 for(;;)
1317 {
1318 return_code = parser_next_token(p);
1319 if((return_code == PARSER_CHAR_TYPE_EOL) || (return_code == PARSER_EOL) || (return_code == PARSER_EOF))
1320 {
1321 break;
1322 }
1323 }
1324 case TYPE_OPT:
1325 case TYPE_IXFR:
1326 case TYPE_AXFR:
1327 case TYPE_ANY:
1328 {
1329 return_code = ZONEFILE_INVALID_TYPE;
1330 break;
1331 }
1332 default:
1333 {
1334 return_code = UNSUPPORTED_RECORD;
1335 log_err("zone file: %{dnsname}: %{dnstype}: %r", origin, &rtype, return_code);
1336 break;
1337 }
1338 } // end switch
1339 }
1340 else
1341 {
1342 // hex
1343
1344 return_code = ZONEFILE_RDATA_PARSE_ERROR; /// parse error
1345
1346 if((text_len == 1) && (text[0] == '#'))
1347 {
1348 u16 unknown_rdata_len;
1349
1350 if(ISOK(return_code = parser_copy_next_u16(p, &unknown_rdata_len)))
1351 {
1352 return_code = ZONEFILE_RDATA_BUFFER_TOO_SMALL; /// buffer too small
1353
1354 if(unknown_rdata_len <= rdata_size)
1355 {
1356 if(ISOK(return_code = parser_concat_next_tokens_nospace(p)))
1357 {
1358 if(((u32)return_code << 1) <= rdata_size)
1359 {
1360 if(ISOK(return_code = base16_decode(parser_text(p), parser_text_length(p), rdata)))
1361 {
1362 if(return_code != unknown_rdata_len)
1363 {
1364 return_code = ZONEFILE_RDATA_SIZE_MISMATCH; /// unexpected size
1365 }
1366 }
1367 }
1368 else
1369 {
1370 return_code = ZONEFILE_RDATA_BUFFER_TOO_SMALL; /// buffer too small
1371 }
1372 }
1373 }
1374 }
1375 }
1376 } // if(!((text_len >= 1) && (text[0] == '#')))
1377
1378 if(ISOK(return_code))
1379 {
1380 // expect to find EOL
1381 ya_result got_eol = parser_expect_eol(p);
1382
1383 if(FAIL(got_eol))
1384 {
1385 return_code = got_eol;
1386
1387 log_err("zone file: %{dnsname}: %{dnstype}: expected end of line: %r", origin, &rtype, return_code);
1388 }
1389 }
1390
1391 return return_code;
1392 }
1393
1394 static ya_result
zone_reader_text_unread_record(zone_reader * zr,resource_record * entry)1395 zone_reader_text_unread_record(zone_reader *zr, resource_record *entry)
1396 {
1397 zone_reader_text *zfr = (zone_reader_text*)zr->data;
1398 resource_record *rr;
1399 u32 required = offsetof(resource_record,rdata) + entry->rdata_size;
1400 MALLOC_OR_DIE(resource_record*, rr, required, DNSRR_TAG);
1401 memcpy(rr, entry, required);
1402 rr->next = zfr->unread_next;
1403 zfr->unread_next = rr;
1404
1405 return SUCCESS;
1406 }
1407
1408 static void
zone_reader_text_escaped_string_format(const void * value,output_stream * os,s32 padding,char pad_char,bool left_justified,void * reserved_for_method_parameters)1409 zone_reader_text_escaped_string_format(const void *value, output_stream *os, s32 padding, char pad_char,
1410 bool left_justified, void *reserved_for_method_parameters)
1411 {
1412 (void)padding;
1413 (void)pad_char;
1414 (void)left_justified;
1415 (void)reserved_for_method_parameters;
1416
1417 #if !DNSCORE_HAS_FULL_ASCII7
1418 output_stream_write(os, value, strlen((const char*)value));
1419 #else
1420 const char *text = (const char*)value;
1421
1422 for(;;)
1423 {
1424 char c = *text;
1425
1426 switch(c)
1427 {
1428 case '\0':
1429 {
1430 return;
1431 }
1432 case VAR_SYMBOL:
1433 {
1434 output_stream_write_u8(os, '$');
1435 break;
1436 }
1437 case AT_SYMBOL:
1438 {
1439 output_stream_write_u8(os, '@');
1440 break;
1441 }
1442 case '$':
1443 {
1444 output_stream_write_u8(os, '\\');
1445 output_stream_write_u8(os, '$');
1446 break;
1447 }
1448 case '@':
1449 {
1450 output_stream_write_u8(os, '\\');
1451 output_stream_write_u8(os, '@');
1452 break;
1453 }
1454 default:
1455 {
1456 output_stream_write_u8(os, c);
1457 break;
1458 }
1459 }
1460
1461 ++text;
1462 }
1463 #endif
1464 }
1465
1466 static ya_result
zone_reader_text_read_record(zone_reader * zr,resource_record * entry)1467 zone_reader_text_read_record(zone_reader *zr, resource_record *entry)
1468 {
1469 yassert((zr != NULL) && (entry != NULL));
1470
1471 zone_reader_text *zfr = (zone_reader_text*)zr->data;
1472
1473 if(zfr->unread_next != NULL)
1474 {
1475 resource_record *top = zfr->unread_next;
1476 u32 required = offsetof(resource_record,rdata) + top->rdata_size;
1477 memcpy(entry, top, required);
1478 zfr->unread_next = top->next;
1479 free(top);
1480
1481 return 0;
1482 }
1483
1484 parser_s *p = &zfr->parser;
1485 ya_result return_code;
1486
1487 for(;;)
1488 {
1489 if(ISOK(return_code = parser_next_token(p)))
1490 {
1491 if(!(return_code & PARSER_WORD))
1492 {
1493 if(return_code & PARSER_COMMENT)
1494 {
1495 #if DO_PRINT
1496 print("[COMMENT]");
1497 #endif
1498 continue;
1499 }
1500
1501 if(return_code & PARSER_EOL)
1502 {
1503 #if DO_PRINT
1504 println("[EOL]");
1505 #endif
1506 continue;
1507 }
1508
1509 if(return_code & PARSER_EOF)
1510 {
1511 #if DO_PRINT
1512 println("[EOF]");
1513 #endif
1514 if(zfr->origin_stack[--zfr->origin_stack_size] != NULL)
1515 {
1516 dnsname_copy(zfr->origin, zfr->origin_stack[zfr->origin_stack_size]);
1517 zfr->dot_origin_size = dnsname_to_cstr(&zfr->dot_origin[1], zfr->origin) + 1;
1518
1519 dnsname_zfree(zfr->origin_stack[zfr->origin_stack_size]);
1520 }
1521
1522 input_stream *completed_stream = parser_pop_stream(p);
1523 #if DEBUG
1524 if(zfr->includes_count <= 0)
1525 {
1526 abort();
1527 }
1528 #endif
1529 --zfr->includes_count;
1530 #if DEBUG
1531 if(zfr->file_name[zfr->includes_count] == NULL)
1532 {
1533 abort();
1534 }
1535 #endif
1536
1537 free(zfr->file_name[zfr->includes_count]);
1538
1539 input_stream_close(completed_stream);
1540
1541 if(parser_stream_count(p) > 0)
1542 {
1543 continue;
1544 }
1545 else
1546 {
1547 break;
1548 }
1549 }
1550
1551 continue;
1552 }
1553
1554 p->needle_mark = p->text;
1555
1556 // keywords or new domain
1557
1558 u32 text_len = parser_text_length(p);
1559 const char *text = parser_text(p);
1560
1561 if(text_len > 0)
1562 {
1563 if(text[0] == VAR_SYMBOL)
1564 {
1565 // keyword match
1566
1567 if(parse_word_case_match(&text[1], text_len - 1, "ORIGIN", 6))
1568 {
1569 if(FAIL(return_code = parser_next_word(p)))
1570 {
1571 entry->name[0] = '\0';
1572 entry->type = TYPE_NONE;
1573 entry->class = CLASS_NONE;
1574 entry->rdata_size = 0;
1575 //
1576 zone_reader_text_free_error_message(zfr);
1577 zfr->error_message_code = return_code;
1578
1579
1580 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
1581 if(ISOK(asformat(&zfr->error_message_buffer, "failed to parse $ORIGIN from line \"%w\"", &escaped_text)))
1582 {
1583 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1584 }
1585 return return_code;
1586 }
1587
1588 text_len = parser_text_length(p);
1589 text = parser_text(p);
1590
1591 memcpy(&zfr->dot_origin[1], text, text_len);
1592 zfr->dot_origin_size = text_len + 1; // +1 for the dot
1593
1594 if(FAIL(return_code = cstr_to_locase_dnsname_with_check_len(zfr->origin, &zfr->dot_origin[1], zfr->dot_origin_size - 1)))
1595 {
1596 entry->name[0] = '\0';
1597 entry->type = TYPE_NONE;
1598 entry->class = CLASS_NONE;
1599 entry->rdata_size = 0;
1600 //
1601 zone_reader_text_free_error_message(zfr);
1602 zfr->error_message_code = return_code;
1603
1604 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
1605 if(ISOK(asformat(&zfr->error_message_buffer, "failed to parse $ORIGIN from line \"%w\"", &escaped_text)))
1606 {
1607 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1608 }
1609 return return_code;
1610 }
1611 }
1612 else if(parse_word_case_match(&text[1], text_len - 1, "TTL", 3))
1613 {
1614 if(FAIL(return_code = parser_copy_next_ttl(p, &zfr->rttl_default)))
1615 {
1616 entry->name[0] = '\0';
1617 entry->type = TYPE_NONE;
1618 entry->class = CLASS_NONE;
1619 entry->rdata_size = 0;
1620 //
1621 zone_reader_text_free_error_message(zfr);
1622 zfr->error_message_code = return_code;
1623
1624 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
1625 if(ISOK(asformat(&zfr->error_message_buffer, "failed to parse $TTL from line \"%w\"", &escaped_text)))
1626 {
1627 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1628 }
1629 return return_code;
1630 }
1631
1632 zfr->rttl_current = zfr->rttl_default;
1633 zfr->rttl_default_defined = TRUE;
1634 }
1635 else if(parse_word_case_match(&text[1], text_len - 1, "INCLUDE", 7))
1636 {
1637 char file_name[PATH_MAX];
1638
1639 if(FAIL(return_code = parser_copy_next_word(p, file_name, sizeof(file_name))))
1640 {
1641 entry->name[0] = '\0';
1642 entry->type = TYPE_NONE;
1643 entry->class = CLASS_NONE;
1644 entry->rdata_size = 0;
1645 //
1646 zone_reader_text_free_error_message(zfr);
1647 zfr->error_message_code = ZONEFILE_EXPECTED_FILE_PATH;
1648
1649 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
1650 if(ISOK(asformat(&zfr->error_message_buffer, "failed to parse $INCLUDE from line \"%w\"", &escaped_text)))
1651 {
1652 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1653 }
1654 return return_code;
1655 }
1656
1657 if(file_name[0] != '/')
1658 {
1659 // prepend the path of current file
1660 // path + current = zfr->file_name[zfr->includes_count - 1];
1661 char *current = zfr->file_name[zfr->includes_count - 1];
1662 char *path_end = strrchr(current, '/');
1663
1664 if(path_end != NULL)
1665 {
1666 size_t path_len = path_end - current + 1;
1667 size_t file_name_len = strlen(file_name) + 1;
1668 if(path_len + file_name_len < sizeof(file_name))
1669 {
1670 memmove(&file_name[path_len], file_name, file_name_len);
1671 memcpy(file_name, current, path_len);
1672 }
1673 else
1674 {
1675 entry->name[0] = '\0';
1676 entry->type = TYPE_NONE;
1677 entry->class = CLASS_NONE;
1678 entry->rdata_size = 0;
1679 //
1680 zone_reader_text_free_error_message(zfr);
1681 zfr->error_message_code = BUFFER_WOULD_OVERFLOW;
1682
1683 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
1684 if(ISOK(asformat(&zfr->error_message_buffer, "$INCLUDE absolute path of file is too big, from line \"%w\"", &escaped_text)))
1685 {
1686 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1687 }
1688
1689 return BUFFER_WOULD_OVERFLOW;
1690 }
1691 }
1692 }
1693
1694 u8 new_origin[MAX_DOMAIN_LENGTH];
1695
1696 if(ISOK(return_code = parser_copy_next_fqdn(p, new_origin)))
1697 {
1698 if((return_code & PARSER_WORD) != 0)
1699 {
1700 // push current origin and replace
1701
1702 zfr->origin_stack[zfr->origin_stack_size++] = dnsname_zdup(zfr->origin);
1703 dnsname_copy(zfr->origin, new_origin);
1704 zfr->dot_origin_size = dnsname_to_cstr(&zfr->dot_origin[1], new_origin) + 1;
1705 }
1706 else
1707 {
1708 zfr->origin_stack[zfr->origin_stack_size++] = NULL;
1709 }
1710 }
1711 else
1712 {
1713 zfr->origin_stack[zfr->origin_stack_size++] = NULL;
1714 }
1715
1716
1717 ya_result err;
1718
1719 if(ISOK(err = file_input_stream_open(&zfr->includes[zfr->includes_count], file_name)))
1720 {
1721 zfr->file_name[zfr->includes_count] = strdup(file_name);
1722 parser_push_stream(&zfr->parser, &zfr->includes[zfr->includes_count++]);
1723 }
1724 else
1725 {
1726 entry->name[0] = '\0';
1727 entry->type = TYPE_NONE;
1728 entry->class = CLASS_NONE;
1729 entry->rdata_size = 0;
1730 //
1731 zone_reader_text_free_error_message(zfr);
1732 zfr->error_message_code = err;
1733
1734 if(ISOK(asformat(&zfr->error_message_buffer, "failed to open file %s", file_name)))
1735 {
1736 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1737 }
1738
1739 return err;
1740 }
1741 }
1742 else if(parse_word_match(&text[1], text_len - 1, "GENERATE", 8))
1743 {
1744 entry->name[0] = '\0';
1745 entry->type = TYPE_NONE;
1746 entry->class = CLASS_NONE;
1747 entry->rdata_size = 0;
1748 //
1749 zone_reader_text_free_error_message(zfr);
1750 zfr->error_message_code = ZONEFILE_FEATURE_NOT_SUPPORTED;
1751 zfr->error_message_buffer = "$GENERATE not supported";
1752 return ZONEFILE_FEATURE_NOT_SUPPORTED;
1753 }
1754 else if(parse_word_match(&text[1], text_len - 1, "CLASS", 5))
1755 {
1756 }
1757 else if(parse_word_match(&text[1], text_len - 1, "RETURN", 6))
1758 {
1759 if(zfr->origin_stack[--zfr->origin_stack_size] != NULL)
1760 {
1761 dnsname_copy(zfr->origin, zfr->origin_stack[zfr->origin_stack_size]);
1762 zfr->dot_origin_size = dnsname_to_cstr(&zfr->dot_origin[1], zfr->origin) + 1;
1763
1764 dnsname_zfree(zfr->origin_stack[zfr->origin_stack_size]);
1765 }
1766
1767 input_stream *completed_stream = parser_pop_stream(p);
1768 free(zfr->file_name[zfr->includes_count]);
1769
1770 input_stream_close(completed_stream);
1771
1772 if(parser_stream_count(p) > 0)
1773 {
1774 continue;
1775 }
1776 else
1777 {
1778 break;
1779 }
1780 }
1781 else if(parse_word_match(&text[1], text_len - 1, "END", 3))
1782 {
1783 break;
1784 }
1785 }
1786 else // parse record
1787 {
1788 // domain
1789 if((return_code & PARSER_BLANK_START) == 0)
1790 {
1791 // new domain
1792
1793 u8 *domain = entry->name;
1794
1795 if(!((text_len == 1) && (text[0] == AT_SYMBOL)))
1796 {
1797 if(text[text_len - 1] != DOT_SYMBOL)
1798 {
1799 if(FAIL(return_code = charp_to_locase_dnsname_with_check(domain, text, text_len)))
1800 {
1801 bool retry = FALSE;
1802 char retry_text[MAX_DOMAIN_LENGTH];
1803
1804 if(text_len <= MAX_DOMAIN_LENGTH)
1805 {
1806 for(u32 i = 0; i < text_len; ++i)
1807 {
1808 char c = text[i];
1809 switch(c)
1810 {
1811 case VAR_SYMBOL:
1812 {
1813 retry_text[i] = '$';
1814 retry = TRUE;
1815 break;
1816 }
1817 case AT_SYMBOL:
1818 {
1819 retry_text[i] = '@';
1820 retry = TRUE;
1821 break;
1822 }
1823 default:
1824 {
1825 retry_text[i] = c;
1826 break;
1827 }
1828 }
1829 }
1830 }
1831
1832 if(retry)
1833 {
1834 if(ISOK(return_code = charp_to_locase_dnsname_with_check(domain, retry_text, text_len)))
1835 {
1836 // an escape is probably missing
1837 char *file_name = "?";
1838 if((zfr->includes_count > 0) && (zfr->includes_count < ZONE_FILE_READER_INCLUDE_DEPTH_MAX))
1839 {
1840 if(zfr->file_name[zfr->includes_count - 1] != NULL)
1841 {
1842 file_name = zfr->file_name[zfr->includes_count - 1];
1843 }
1844 }
1845
1846 log_warn("zone parse: there is probably an escape missing in front of a '$' or a '@' in file '%s' at line %u for %{dnsname}", file_name, p->line_number, domain);
1847 }
1848 }
1849
1850 if(FAIL(return_code))
1851 {
1852 entry->type = TYPE_NONE;
1853 entry->class = CLASS_NONE;
1854 entry->rdata_size = 0;
1855 //
1856 zone_reader_text_free_error_message(zfr);
1857 zfr->error_message_code = return_code;
1858 MALLOC_OR_DIE(char*, zfr->error_message_buffer, text_len + 1, ZFERRMSG_TAG);
1859 memcpy(zfr->error_message_buffer, text, text_len);
1860 zfr->error_message_buffer[text_len] = '\0';
1861 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1862
1863
1864 return return_code;
1865 }
1866 }
1867
1868 /*return_code =*/ dnsname_copy(&domain[return_code - 1], zfr->origin); /// @note: cannot fail
1869 }
1870 else
1871 {
1872 if(FAIL(return_code = charp_to_locase_dnsname(domain, text, text_len)))
1873 {
1874 entry->type = TYPE_NONE;
1875 entry->class = CLASS_NONE;
1876 entry->rdata_size = 0;
1877 //
1878 zone_reader_text_free_error_message(zfr);
1879 zfr->error_message_code = return_code;
1880 MALLOC_OR_DIE(char*, zfr->error_message_buffer, text_len + 1, ZFERRMSG_TAG);
1881 memcpy(zfr->error_message_buffer, text, text_len);
1882 zfr->error_message_buffer[text_len] = '\0';
1883 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1884
1885 return return_code;
1886 }
1887 }
1888 }
1889 else // label is @
1890 {
1891 dnsname_copy(domain, zfr->origin); /// @note: cannot fail
1892 dnsname_to_cstr(&zfr->dot_origin[1], zfr->origin); /// @note: cannot fail
1893
1894 zfr->dot_origin_size = return_code + 1;
1895 zfr->template_source = TRUE;
1896 }
1897 }
1898 else
1899 {
1900 parser_rewind(p);
1901 }
1902
1903 // TTL CLASS TYPE RDATA
1904 // CLASS TTL TYPE RDATA
1905
1906 parser_mark(p);
1907
1908 if(ISOK(parser_copy_next_ttl(p, &zfr->rttl_current))) // parses as an int ?
1909 {
1910 entry->ttl = zfr->rttl_current;
1911 zfr->rttl_current_defined = TRUE;
1912
1913 parser_mark(p);
1914
1915 if(FAIL(parser_copy_next_class(p, &zfr->rclass_current))) // TTL no CLASS
1916 {
1917 parser_rewind(p);
1918 }
1919 // else TTL + CLASS
1920 }
1921 else
1922 {
1923 parser_rewind(p);
1924
1925 if(ISOK(parser_copy_next_class(p, &zfr->rclass_current)))
1926 {
1927 parser_mark(p);
1928
1929 if(ISOK(parser_copy_next_ttl(p, &zfr->rttl_current))) // parses as an int ? // CLASS + TTL
1930 {
1931 entry->ttl = zfr->rttl_current;
1932 zfr->rttl_current_defined = TRUE;
1933 }
1934 else
1935 {
1936 if(!zfr->rttl_default_defined) // CLASS no TTL, no $TTL
1937 {
1938 if(zfr->rttl_current_defined)
1939 {
1940 entry->ttl = zfr->rttl_current;
1941 }
1942 else
1943 {
1944 // this will be handled with the SOA case
1945 }
1946 }
1947
1948 parser_rewind(p); // CLASS no TTL, + $TTL
1949
1950 entry->ttl = zfr->rttl_default;
1951 }
1952 }
1953 else // no CLASS, no TTL, $TTL ?
1954 {
1955 parser_rewind(p);
1956
1957 if(zfr->rttl_default_defined)
1958 {
1959 entry->ttl = zfr->rttl_default;
1960 }
1961 else
1962 {
1963 entry->ttl = zfr->rttl_current;
1964 }
1965 }
1966 }
1967
1968 entry->class = zfr->rclass_current;
1969
1970 u16 rtype;
1971
1972 if(FAIL(return_code = parser_copy_next_type(p, &rtype)))
1973 {
1974 entry->type = TYPE_NONE;
1975 entry->class = CLASS_NONE;
1976 entry->rdata_size = 0;
1977 //
1978 zone_reader_text_free_error_message(zfr);
1979 zfr->error_message_code = return_code;
1980
1981 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
1982
1983 if(ISOK(asformat(&zfr->error_message_buffer, "could not parse type for %{dnsname} from line %i: \"%w\"", entry->name, parser_get_line_number(p), &escaped_text)))
1984 {
1985 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
1986 }
1987 return return_code;
1988 }
1989
1990 entry->type = rtype;
1991
1992 #if DNSCORE_HAS_FULL_ASCII7
1993 parser_del_translation(&zfr->parser, '@');
1994 parser_del_translation(&zfr->parser, '$');
1995 #endif
1996 if(rtype != TYPE_SOA)
1997 {
1998 if(FAIL(return_code = zone_reader_text_copy_rdata_inline(p, rtype, entry->rdata, sizeof(entry->rdata), zfr->origin)))
1999 {
2000 entry->rdata_size = 0;
2001 //
2002 zone_reader_text_free_error_message(zfr);
2003 zfr->error_message_code = return_code;
2004
2005 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
2006 if(ISOK(asformat(&zfr->error_message_buffer, "could not parse rdata for %{dnsname} %{dnsclass} %{dnstype} from line \"%w\"", entry->name, &entry->class, &entry->type, &escaped_text)))
2007 {
2008 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
2009 }
2010 return return_code;
2011 }
2012
2013 entry->rdata_size = return_code;
2014 }
2015 else // SOA
2016 {
2017 if(entry->class == CLASS_NONE)
2018 {
2019 entry->rdata_size = 0;
2020 //
2021 zone_reader_text_free_error_message(zfr);
2022 zfr->error_message_code = ZONEFILE_SOA_WITHOUT_CLASS;
2023 zfr->error_message_buffer = "no class set on the SOA record";
2024 return ZONEFILE_SOA_WITHOUT_CLASS;
2025 }
2026
2027 if(FAIL(return_code = zone_reader_text_copy_rdata_inline(p, rtype, entry->rdata, sizeof(entry->rdata), zfr->origin)))
2028 {
2029 entry->rdata_size = 0;
2030 //
2031 zone_reader_text_free_error_message(zfr);
2032 zfr->error_message_code = return_code;
2033
2034 format_writer escaped_text = {zone_reader_text_escaped_string_format, text};
2035 if(ISOK(asformat(&zfr->error_message_buffer, "could not parse rdata for %{dnsname} %{dnsclass} %{dnstype} from line \"%w\"", entry->name, &entry->class, &entry->type, &escaped_text)))
2036 {
2037 zfr->error_message_allocated = ZONE_FILE_READER_MESSAGE_ALLOCATED;
2038 }
2039 return return_code;
2040 }
2041
2042 entry->rdata_size = return_code;
2043
2044 // FULL RECORD READY
2045
2046 if(!(zfr->rttl_default_defined || zfr->rttl_current_defined))
2047 {
2048 u8 *p = entry->rdata;
2049 p += entry->rdata_size - 4;
2050
2051 zfr->rttl_default = zfr->rttl_current = ntohl(GET_U32_AT_P(p));
2052 zfr->rttl_default_defined = zfr->rttl_current_defined = TRUE;
2053 entry->ttl = zfr->rttl_default;
2054 }
2055 }
2056
2057 #if DNSCORE_HAS_FULL_ASCII7
2058 parser_add_translation(&zfr->parser, '@', AT_SYMBOL);
2059 parser_add_translation(&zfr->parser, '$', VAR_SYMBOL);
2060 #endif
2061
2062 return SUCCESS;
2063 }
2064 }
2065
2066 #if DO_PRINT
2067 flushout();
2068 #endif
2069 }
2070 else
2071 {
2072 #if DO_PRINT
2073 formatln("[ERROR %r]", return_code);
2074 #endif
2075 break;
2076 }
2077 }
2078
2079 if(ISOK(return_code))
2080 {
2081 return_code = 1;
2082 }
2083
2084 return return_code;
2085 }
2086
2087
2088 static ya_result
zone_reader_text_free_record(zone_reader * zr,resource_record * entry)2089 zone_reader_text_free_record(zone_reader *zr, resource_record *entry)
2090 {
2091 (void)zr;
2092 (void)entry;
2093 return OK;
2094 }
2095
2096 /** @brief Closes a zone file entry
2097 *
2098 * Closes a zone file entry. The function will do nothing if the zonefile has already been closed
2099 *
2100 * @param[in] zonefile a pointer to a valid (zone_file_open'ed) zone-file structure
2101 *
2102 */
2103 static void
zone_reader_text_close(zone_reader * zr)2104 zone_reader_text_close(zone_reader *zr)
2105 {
2106 yassert(zr != NULL);
2107
2108 zone_reader_text *zfr = (zone_reader_text*)zr->data;
2109
2110 parser_finalize(&zfr->parser);
2111
2112 u8 n = zfr->includes_count;
2113 while(n-- > 0)
2114 {
2115 free(zfr->file_name[n]);
2116 /*
2117 Warning C6001 Using uninitialized memory '**zr[BYTE:268944]'. yadifa
2118 zone_reader_text.c 2411
2119 */
2120 }
2121
2122 resource_record *rr = zfr->unread_next;
2123 while(rr != NULL)
2124 {
2125 resource_record *tmp = rr;
2126 rr = rr->next;
2127 free(tmp);
2128 }
2129
2130 zone_reader_text_free_error_message(zfr);
2131
2132 free(zfr);
2133
2134 zr->data = NULL;
2135 zr->vtbl = NULL;
2136 }
2137
2138 static bool
zone_reader_text_canwriteback(zone_reader * zr)2139 zone_reader_text_canwriteback(zone_reader *zr)
2140 {
2141 yassert(zr != NULL);
2142
2143 zone_reader_text *zfr = (zone_reader_text*)zr->data;
2144 return !zfr->template_source;
2145 }
2146
2147 static void
zone_reader_text_handle_error(zone_reader * zr,ya_result error_code)2148 zone_reader_text_handle_error(zone_reader *zr, ya_result error_code)
2149 {
2150 /* nop */
2151 (void)zr;
2152 (void)error_code;
2153 }
2154
2155 static const char*
zone_reader_text_get_last_error_message(zone_reader * zr)2156 zone_reader_text_get_last_error_message(zone_reader *zr)
2157 {
2158 zone_reader_text *zfr = (zone_reader_text*)zr->data;
2159 return zfr->error_message_buffer;
2160 }
2161
2162 static const zone_reader_vtbl zone_reader_text_vtbl =
2163 {
2164 zone_reader_text_read_record,
2165 zone_reader_text_unread_record,
2166 zone_reader_text_free_record,
2167 zone_reader_text_close,
2168 zone_reader_text_handle_error,
2169 zone_reader_text_canwriteback,
2170 zone_reader_text_get_last_error_message,
2171 "zone_reader_text_v2"
2172 };
2173
2174
2175 void
zone_reader_text_init_error_codes()2176 zone_reader_text_init_error_codes()
2177 {
2178 if(zone_reader_text_init_error_codes_done)
2179 {
2180 return;
2181 }
2182
2183 zone_reader_text_init_error_codes_done = TRUE;
2184
2185 error_register(ZONEFILE_FEATURE_NOT_SUPPORTED, "ZONEFILE_FEATURE_NOT_SUPPORTED");
2186 error_register(ZONEFILE_EXPECTED_FILE_PATH, "ZONEFILE_EXPECTED_FILE_PATH");
2187 error_register(ZONEFILE_SOA_WITHOUT_CLASS, "ZONEFILE_SOA_WITHOUT_CLASS");
2188 error_register(ZONEFILE_SALT_TOO_BIG, "ZONEFILE_SALT_TOO_BIG");
2189 error_register(ZONEFILE_TEXT_TOO_BIG, "ZONEFILE_TEXT_TOO_BIG");
2190 error_register(ZONEFILE_FLAGS_TOO_BIG, "ZONEFILE_FLAGS_TOO_BIG");
2191 error_register(ZONEFILE_SERVICE_TOO_BIG, "ZONEFILE_SERVICE_TOO_BIG");
2192 error_register(ZONEFILE_REGEX_TOO_BIG, "ZONEFILE_REGEX_TOO_BIG");
2193 error_register(ZONEFILE_RDATA_PARSE_ERROR, "ZONEFILE_RDATA_PARSE_ERROR");
2194 error_register(ZONEFILE_RDATA_BUFFER_TOO_SMALL, "ZONEFILE_RDATA_BUFFER_TOO_SMALL");
2195 error_register(ZONEFILE_RDATA_SIZE_MISMATCH, "ZONEFILE_RDATA_SIZE_MISMATCH");
2196 }
2197
2198 static ya_result
zone_reader_text_init(zone_reader * zr)2199 zone_reader_text_init(zone_reader *zr)
2200 {
2201 ya_result error_code;
2202 zone_reader_text *zfr;
2203
2204 /* ------------------------------------------------------------ */
2205
2206 MALLOC_OBJECT_OR_DIE(zfr, zone_reader_text, ZFREADER_TAG);
2207
2208 ZEROMEMORY(zfr, sizeof(zone_reader_text));
2209
2210 if(ISOK(error_code = parser_init(&zfr->parser,
2211 zfr_string_delimiters, // by 2
2212 zfr_multiline_delimiters, // by 2
2213 zrf_comment_markers, // by 1
2214 zrf_blank_makers, // by 1
2215 zfr_escape_characters))) // by 1
2216 {
2217 zfr->rttl_default = 86400;
2218 zfr->rttl_current = 86400;
2219 zfr->dot_origin_size = 2; // with the CHR0 sentinel
2220 zfr->rclass_current = CLASS_IN;
2221 zfr->rdata_size = 0;
2222 zfr->soa_found = FALSE;
2223 zfr->domain[0] = (u8)'\0';
2224 zfr->dot_origin[0] = '.';
2225 zfr->dot_origin[1] = '\0';
2226 }
2227
2228 #if DNSCORE_HAS_FULL_ASCII7
2229 parser_add_translation(&zfr->parser, '@', AT_SYMBOL);
2230 parser_add_translation(&zfr->parser, '$', VAR_SYMBOL);
2231 //parser_add_translation(&zfr->parser, '.', DOT_SYMBOL);
2232 #endif
2233
2234 zr->data = zfr;
2235 zr->vtbl = &zone_reader_text_vtbl;
2236
2237 return error_code;
2238 }
2239
2240 #if DEBUG_BENCH_TEXT_ZONE_PARSE
2241
2242 static debug_bench_s zone_reader_text_parse;
2243 static bool zone_reader_text_parse_done = FALSE;
2244
zone_reader_text_bench_register()2245 static inline void zone_reader_text_bench_register()
2246 {
2247 if(!zone_reader_text_parse_done)
2248 {
2249 zone_reader_text_parse_done = TRUE;
2250 debug_bench_register(&zone_reader_text_parse, "text parse");
2251 }
2252 }
2253
2254 #endif
2255
2256 ya_result
zone_reader_text_parse_stream(input_stream * ins,zone_reader * zr)2257 zone_reader_text_parse_stream(input_stream *ins, zone_reader *zr)
2258 {
2259 #if DEBUG_BENCH_TEXT_ZONE_PARSE
2260 zone_reader_text_bench_register();
2261 u64 bench = debug_bench_start(&zone_reader_text_parse);
2262 #endif
2263
2264 ya_result ret;
2265
2266 if(ISOK(ret = zone_reader_text_init(zr)))
2267 {
2268 zone_reader_text *zfr = (zone_reader_text*)zr->data;
2269
2270 // push the stream
2271
2272 parser_push_stream(&zfr->parser, ins);
2273 }
2274 else
2275 {
2276 zone_reader_text_close(zr);
2277 }
2278
2279 #if DEBUG_BENCH_TEXT_ZONE_PARSE
2280 zone_reader_text_bench_register();
2281 debug_bench_stop(&zone_reader_text_parse, bench);
2282 #endif
2283
2284 return ret;
2285 }
2286
2287 /** @brief Opens a zone file
2288 *
2289 * Opens a zone file
2290 *
2291 * @param[in] fullpath the path and name of the file to open
2292 * @param[out] zone a pointer to a structure that will be used by the function
2293 * to hold the zone-file information
2294 *
2295 * @return A result code
2296 * @retval OK : the file has been opened successfully
2297 * @retval else : an error occurred
2298 */
2299 ya_result
zone_reader_text_open(const char * fullpath,zone_reader * zr)2300 zone_reader_text_open(const char* fullpath, zone_reader *zr)
2301 {
2302 ya_result return_value;
2303
2304 #if DEBUG_BENCH_TEXT_ZONE_PARSE
2305 zone_reader_text_bench_register();
2306 u64 bench = debug_bench_start(&zone_reader_text_parse);
2307 #endif
2308
2309 if(ISOK(return_value = zone_reader_text_init(zr)))
2310 {
2311 // push the stream
2312
2313 zone_reader_text *zfr = (zone_reader_text*)zr->data;
2314
2315 if(ISOK(return_value = file_input_stream_open(&zfr->includes[0], fullpath)))
2316 {
2317 /*
2318 #if (DNSDB_USE_POSIX_ADVISE != 0) && (_XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L)
2319 int fd = fd_input_stream_get_filedescriptor(&zfr->includes[0]);
2320 fdatasync_ex(fd);
2321 posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
2322 #endif
2323 */
2324 zfr->file_name[zfr->includes_count] = strdup(fullpath);
2325 parser_push_stream(&zfr->parser, &zfr->includes[zfr->includes_count++]);
2326 }
2327 else
2328 {
2329 log_debug("zone file: cannot open: '%s': %r", fullpath, return_value);
2330
2331 zone_reader_text_close(zr);
2332
2333 return return_value;
2334 }
2335
2336 #if DEBUG_BENCH_TEXT_ZONE_PARSE
2337 zone_reader_text_bench_register();
2338 debug_bench_stop(&zone_reader_text_parse, bench);
2339 #endif
2340 }
2341
2342 return return_value;
2343 }
2344
2345 void
zone_reader_text_ignore_missing_soa(zone_reader * zr)2346 zone_reader_text_ignore_missing_soa(zone_reader *zr)
2347 {
2348 zone_reader_text *zfr = (zone_reader_text*)zr->data;
2349 zfr->soa_found = TRUE;
2350 }
2351
2352 ya_result
zone_reader_text_set_origin(zone_reader * zr,const u8 * origin)2353 zone_reader_text_set_origin(zone_reader *zr, const u8* origin)
2354 {
2355 zone_reader_text *zfr = (zone_reader_text*)zr->data;
2356 ya_result return_code = dnsname_copy(zfr->origin, origin);
2357 return return_code;
2358 }
2359
2360 ya_result
zone_reader_text_copy_rdata(const char * text,u16 rtype,u8 * rdata,u32 rdata_size,const u8 * origin)2361 zone_reader_text_copy_rdata(const char *text, u16 rtype, u8 *rdata, u32 rdata_size, const u8 *origin)
2362 {
2363 parser_s parser;
2364
2365 ya_result return_code;
2366
2367 char buffer[4096];
2368
2369 int n = strlen(text);
2370
2371 if(n > (int)(sizeof(buffer) - 2))
2372 {
2373 return -1;
2374 }
2375
2376 if(text[n - 1] != '\n')
2377 {
2378 memcpy(buffer, text, n);
2379 buffer[n] = '\n';
2380 buffer[n + 1] = '\0';
2381 n++;
2382 text = buffer;
2383 }
2384
2385 if(ISOK(return_code = parser_init(&parser,
2386 zfr_string_delimiters, // by 2
2387 zfr_multiline_delimiters, // by 2
2388 zrf_comment_markers, // by 1
2389 zrf_blank_makers, // by 1
2390 zfr_escape_characters))) // by 1
2391 {
2392 input_stream text_is;
2393
2394 bytearray_input_stream_init_const(&text_is, (const u8*)text, n);
2395
2396 if(ISOK(return_code = parser_push_stream(&parser, &text_is)))
2397 {
2398 return_code = zone_reader_text_copy_rdata_inline(&parser, rtype, rdata, rdata_size, origin);
2399 }
2400
2401 // will be closed by the parser
2402 // input_stream_close(&text_is);
2403
2404 parser_finalize(&parser);
2405 }
2406
2407 return return_code;
2408 }
2409
2410 ya_result
zone_reader_text_len_copy_rdata(const char * text,u32 n,u16 rtype,u8 * rdata,u32 rdata_size,const u8 * origin)2411 zone_reader_text_len_copy_rdata(const char *text, u32 n, u16 rtype, u8 *rdata, u32 rdata_size, const u8 *origin)
2412 {
2413 parser_s parser;
2414
2415 ya_result return_code;
2416
2417 if(ISOK(return_code = parser_init(&parser,
2418 zfr_string_delimiters, // by 2
2419 zfr_multiline_delimiters, // by 2
2420 zrf_comment_markers, // by 1
2421 zrf_blank_makers, // by 1
2422 zfr_escape_characters))) // by 1
2423 {
2424 input_stream text_is;
2425
2426 bytearray_input_stream_init_const(&text_is, (const u8*)text, n);
2427
2428 if(ISOK(return_code = parser_push_stream(&parser, &text_is)))
2429 {
2430 return_code = zone_reader_text_copy_rdata_inline(&parser, rtype, rdata, rdata_size, origin);
2431 }
2432
2433 // will be closed by the parser
2434 // input_stream_close(&text_is);
2435
2436 parser_finalize(&parser);
2437 }
2438
2439 return return_code;
2440 }
2441
2442
2443 /** @} */
2444