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