1/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3    This program is free software: you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation, either version 3 of the License, or
6    (at your option) any later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <https://www.gnu.org/licenses/>.
15 */
16
17%%{
18	machine zone_scanner;
19
20	# Comeback function to calling state machine.
21	action _ret {
22		fhold; fret;
23	}
24
25	# BEGIN - Blank space processing
26	action _newline {
27		s->line_counter++;
28	}
29
30	action _check_multiline_begin {
31		if (s->multiline == true) {
32			ERR(ZS_LEFT_PARENTHESIS);
33			fhold; fgoto err_line;
34		}
35		s->multiline = true;
36	}
37	action _check_multiline_end {
38		if (s->multiline == false) {
39			ERR(ZS_RIGHT_PARENTHESIS);
40			fhold; fgoto err_line;
41		}
42		s->multiline = false;
43	}
44
45	action _comment_init {
46		s->buffer_length = 0;
47	}
48	action _comment {
49		if (s->buffer_length < sizeof(s->buffer) - 1) {
50			s->buffer[s->buffer_length++] = fc;
51		}
52	}
53	action _comment_exit {
54		s->buffer[s->buffer_length++] = 0;
55
56		// Execute the comment callback.
57		if (s->process.automatic && s->process.comment != NULL) {
58			s->process.comment(s);
59
60			// Stop if required from the callback.
61			if (s->state == ZS_STATE_STOP) {
62				fbreak;
63			}
64		}
65	}
66
67	action _rest_init {
68		s->buffer[0] = 0;
69		s->buffer_length = 0;
70	}
71	action _rest_error {
72		WARN(ZS_BAD_REST);
73		fhold; fgoto err_line;
74	}
75
76	newline = '\n' $_newline;
77	comment = (';' . (^newline)* $_comment) >_comment_init %_comment_exit;
78
79	# White space separation. With respect to parentheses and included comments.
80	sep = ( [ \t]                                       # Blank characters.
81	      | (comment? . newline) when { s->multiline }  # Comment in multiline.
82	      | '(' $_check_multiline_begin                 # Start of multiline.
83	      | ')' $_check_multiline_end                   # End of multiline.
84	      )+;                                           # Apply more times.
85
86	rest = (sep? :> comment?) >_rest_init $!_rest_error; # Comments.
87
88	# Artificial machines which are used for next state transition only!
89	all_wchar = [ \t\n;()];
90	end_wchar = [\n;] when { !s->multiline }; # For noncontinuous ending tokens.
91	# END
92
93	# BEGIN - Error line processing
94	action _err_line_init {
95		s->buffer_length = 0;
96	}
97	action _err_line {
98		if (fc == '\r') {
99			ERR(ZS_DOS_NEWLINE);
100		}
101
102		if (s->buffer_length < sizeof(s->buffer) - 1) {
103			s->buffer[s->buffer_length++] = fc;
104		}
105	}
106	action _err_line_exit {
107		// Terminate the error context string.
108		s->buffer[s->buffer_length++] = 0;
109
110		// Error counter incrementation.
111		s->error.counter++;
112
113		// Initialize the fcall stack.
114		top = 0;
115
116		// Reset per-record contexts.
117		s->long_string = false;
118		s->comma_list = false;
119
120		s->state = ZS_STATE_ERROR;
121
122		// Execute the error callback.
123		if (s->process.automatic) {
124			fhold;
125			if (s->process.error != NULL) {
126				s->process.error(s);
127
128				// Stop if required from the callback.
129				if (s->state == ZS_STATE_STOP) {
130					fbreak;
131				}
132			}
133
134			// Stop the scanner if fatal error.
135			if (s->error.fatal) {
136				fbreak;
137			}
138			fgoto err_rest;
139		} else {
140			// Return if external processing.
141			fhold; fnext err_rest; fbreak;
142		}
143	}
144
145	# Consume rest lines of defective multiline record.
146	err_rest := ( (any - newline - ')')
147	            | newline when { s->multiline }
148	            | ')'     when { s->multiline } $_check_multiline_end
149	            )* %{ fhold; fcall main; } <: newline;
150
151	# Fill rest of the line to buffer and skip to main loop.
152	err_line := (^newline $_err_line)* >_err_line_init
153	            %_err_line_exit . newline;
154	# END
155
156	# BEGIN - Domain name labels processing
157	action _label_init {
158		s->item_length = 0;
159		s->item_length_position = s->dname_tmp_length++;
160	}
161	action _label_char {
162		// Check for maximum dname label length.
163		if (s->item_length < ZS_MAX_LABEL_LENGTH) {
164			(s->dname)[s->dname_tmp_length++] = fc;
165			s->item_length++;
166		} else {
167			WARN(ZS_LABEL_OVERFLOW);
168			fhold; fgoto err_line;
169		}
170	}
171	action _label_exit {
172		// Check for maximum dname length overflow after each label.
173		// (at least the next label length must follow).
174		if (s->dname_tmp_length < ZS_MAX_DNAME_LENGTH) {
175			(s->dname)[s->item_length_position] =
176				(uint8_t)(s->item_length);
177		} else {
178			WARN(ZS_DNAME_OVERFLOW);
179			fhold; fgoto err_line;
180		}
181	}
182
183	action _label_dec_init {
184		if (s->item_length < ZS_MAX_LABEL_LENGTH) {
185			(s->dname)[s->dname_tmp_length] = 0;
186			s->item_length++;
187		} else {
188			WARN(ZS_LABEL_OVERFLOW);
189			fhold; fgoto err_line;
190		}
191	}
192	action _label_dec {
193		(s->dname)[s->dname_tmp_length] *= 10;
194		(s->dname)[s->dname_tmp_length] += digit_to_num[(uint8_t)fc];
195	}
196	action _label_dec_exit {
197		s->dname_tmp_length++;
198	}
199	action _label_dec_error {
200		WARN(ZS_BAD_NUMBER);
201		fhold; fgoto err_line;
202	}
203
204	label_char =
205	    ( (alnum | [*\-_/]) $_label_char                 # One common char.
206	    | ('\\' . ^digit)   @_label_char                 # One "\x" char.
207	    | ('\\'             %_label_dec_init             # Initial "\" char.
208	       . digit {3}      $_label_dec %_label_dec_exit # "DDD" rest.
209	                        $!_label_dec_error
210	      )
211	    );
212
213	label  = label_char+ >_label_init %_label_exit;
214	labels = (label . '.')* . label;
215	# END
216
217	# BEGIN - Domain name processing.
218	action _absolute_dname_exit {
219		// Enough room for the terminal label is guaranteed (_label_exit).
220		(s->dname)[s->dname_tmp_length++] = 0;
221	}
222	action _relative_dname_exit {
223		// Check for (relative + origin) dname length overflow.
224		if (s->dname_tmp_length + s->zone_origin_length <= ZS_MAX_DNAME_LENGTH) {
225			memcpy(s->dname + s->dname_tmp_length,
226			       s->zone_origin,
227			       s->zone_origin_length);
228
229			s->dname_tmp_length += s->zone_origin_length;
230		} else {
231			WARN(ZS_DNAME_OVERFLOW);
232			fhold; fgoto err_line;
233		}
234	}
235	action _origin_dname_exit {
236		// Copy already verified zone origin.
237		memcpy(s->dname,
238		       s->zone_origin,
239		       s->zone_origin_length);
240
241		s->dname_tmp_length = s->zone_origin_length;
242	}
243
244	action _dname_init {
245		s->item_length_position = 0;
246		s->dname_tmp_length = 0;
247	}
248	action _dname_error {
249		WARN(ZS_BAD_DNAME_CHAR);
250		fhold; fgoto err_line;
251	}
252
253	relative_dname = (labels       ) >_dname_init %_relative_dname_exit;
254	absolute_dname = (labels? . '.') >_dname_init %_absolute_dname_exit;
255
256	dname_ := ( relative_dname
257	          | absolute_dname
258	          | '@' %_origin_dname_exit
259	          ) $!_dname_error %_ret . all_wchar;
260	dname = (alnum | [\-_/\\] | [*.@]) ${ fhold; fcall dname_; };
261	# END
262
263	# BEGIN - Common r_data item processing
264	action _item_length_init {
265		if (rdata_tail <= rdata_stop) {
266			s->item_length_location = rdata_tail++;
267		} else {
268			WARN(ZS_RDATA_OVERFLOW);
269			fhold; fgoto err_line;
270		}
271	}
272	action _item_length_exit {
273		s->item_length = rdata_tail - s->item_length_location - 1;
274		if (s->comma_list && s->item_length == 0) {
275			WARN(ZS_EMPTY_LIST_ITEM);
276			fhold; fgoto err_line;
277		}
278		if (s->item_length <= MAX_ITEM_LENGTH) {
279			*(s->item_length_location) = (uint8_t)(s->item_length);
280		} else {
281			WARN(ZS_ITEM_OVERFLOW);
282			fhold; fgoto err_line;
283		}
284	}
285	action _item_length2_init {
286		if (rdata_tail < rdata_stop) {
287			s->item_length2_location = rdata_tail;
288			rdata_tail += 2;
289		} else {
290			WARN(ZS_RDATA_OVERFLOW);
291			fhold; fgoto err_line;
292		}
293	}
294	action _item_length2_exit {
295		s->item_length = rdata_tail - s->item_length2_location - 2;
296
297		if (s->item_length <= MAX_ITEM_LENGTH2) {
298			uint16_t val = htons((uint16_t)(s->item_length));
299			memcpy(s->item_length2_location, &val, 2);
300		} else {
301			WARN(ZS_ITEM_OVERFLOW);
302			fhold; fgoto err_line;
303		}
304	}
305	# END
306
307	# BEGIN - Owner processing
308	action _r_owner_init {
309		s->dname = s->r_owner;
310		s->r_owner_length = 0;
311	}
312	action _r_owner_exit {
313		s->r_owner_length = s->dname_tmp_length;
314	}
315	action _r_owner_empty_exit {
316		if (s->r_owner_length == 0) {
317			WARN(ZS_BAD_PREVIOUS_OWNER);
318			fhold; fgoto err_line;
319		}
320	}
321	action _r_owner_error {
322		s->r_owner_length = 0;
323		WARN(ZS_BAD_OWNER);
324		fhold; fgoto err_line;
325	}
326
327	r_owner = ( dname >_r_owner_init %_r_owner_exit
328	          | zlen  %_r_owner_empty_exit # Empty owner - use the previous one.
329	          ) $!_r_owner_error;
330	# END
331
332	# BEGIN - domain name in record data processing
333	action _r_dname_init {
334		s->dname = rdata_tail;
335	}
336	action _r_dname_exit {
337		rdata_tail += s->dname_tmp_length;
338	}
339
340	r_dname = dname >_r_dname_init %_r_dname_exit;
341	# END
342
343	# BEGIN - Number processing
344	action _number_digit {
345		// Overflow check: 10*(s->number64) + fc - '0' <= UINT64_MAX
346		if ((s->number64 < (UINT64_MAX / 10)) ||   // Dominant fast check.
347			((s->number64 == (UINT64_MAX / 10)) && // Marginal case.
348			 ((uint8_t)fc <= (UINT64_MAX % 10) + '0')
349			)
350		   ) {
351			s->number64 *= 10;
352			s->number64 += digit_to_num[(uint8_t)fc];
353		} else {
354			WARN(ZS_NUMBER64_OVERFLOW);
355			fhold; fgoto err_line;
356		}
357	}
358
359	number_digit = [0-9] $_number_digit;
360
361	action _number_init {
362		s->number64 = 0;
363	}
364	action _number_error {
365		WARN(ZS_BAD_NUMBER);
366		fhold; fgoto err_line;
367	}
368
369	# General integer number that cover all necessary integer ranges.
370	number = number_digit+ >_number_init;
371
372	action _float_init {
373		s->decimal_counter = 0;
374	}
375	action _decimal_init {
376		s->number64_tmp = s->number64;
377	}
378	action _decimal_digit {
379		s->decimal_counter++;
380	}
381
382	action _float_exit {
383		if (s->decimal_counter == 0 && s->number64 < UINT32_MAX) {
384			s->number64 *= pow(10, s->decimals);
385		} else if (s->decimal_counter <= s->decimals &&
386				 s->number64_tmp < UINT32_MAX) {
387			s->number64 *= pow(10, s->decimals - s->decimal_counter);
388			s->number64 += s->number64_tmp * pow(10, s->decimals);
389		} else {
390			WARN(ZS_FLOAT_OVERFLOW);
391			fhold; fgoto err_line;
392		}
393	}
394
395	# Next float can't be used directly (doesn't contain decimals init)!
396	float = (number . ('.' . number? >_decimal_init $_decimal_digit)?)
397			>_float_init %_float_exit;
398
399	action _float2_init {
400		s->decimals = 2;
401	}
402	action _float3_init {
403		s->decimals = 3;
404	}
405
406	# Float number (in hundredths)with 2 possible decimal digits.
407	float2  = float >_float2_init;
408	# Float number (in thousandths) with 3 possible decimal digits.
409	float3  = float >_float3_init;
410
411	action _num8_write {
412		if (s->number64 <= UINT8_MAX) {
413			*rdata_tail = (uint8_t)(s->number64);
414			rdata_tail += 1;
415		} else {
416			WARN(ZS_NUMBER8_OVERFLOW);
417			fhold; fgoto err_line;
418		}
419	}
420	action _num16_write {
421		if (s->number64 <= UINT16_MAX) {
422			uint16_t num16 = htons((uint16_t)s->number64);
423			memcpy(rdata_tail, &num16, 2);
424			rdata_tail += 2;
425		} else {
426			WARN(ZS_NUMBER16_OVERFLOW);
427			fhold; fgoto err_line;
428		}
429	}
430	action _num32_write {
431		if (s->number64 <= UINT32_MAX) {
432			uint32_t num32 = htonl((uint32_t)s->number64);
433			memcpy(rdata_tail, &num32, 4);
434			rdata_tail += 4;
435		} else {
436			WARN(ZS_NUMBER32_OVERFLOW);
437			fhold; fgoto err_line;
438		}
439	}
440
441	action _type_number_exit {
442		if (s->number64 <= UINT16_MAX) {
443			s->r_type = (uint16_t)(s->number64);
444		} else {
445			WARN(ZS_NUMBER16_OVERFLOW);
446			fhold; fgoto err_line;
447		}
448	}
449
450	action _length_number_exit {
451		if (s->number64 <= UINT16_MAX) {
452			s->r_data_length = (uint16_t)(s->number64);
453		} else {
454			WARN(ZS_NUMBER16_OVERFLOW);
455			fhold; fgoto err_line;
456		}
457	}
458	num8  = number %_num8_write  $!_number_error;
459	num16 = number %_num16_write $!_number_error;
460	num32 = number %_num32_write $!_number_error;
461
462	type_number   = number %_type_number_exit $!_number_error;
463	length_number = number %_length_number_exit $!_number_error;
464	# END
465
466	# BEGIN - Time processing
467	action _time_unit_error {
468		WARN(ZS_BAD_TIME_UNIT);
469		fhold; fgoto err_line;
470	}
471
472	time_unit =
473	    ( 's'i
474	    | 'm'i ${ if (s->number64 <= (UINT32_MAX / 60)) {
475	                  s->number64 *= 60;
476	              } else {
477	                  WARN(ZS_NUMBER32_OVERFLOW);
478	                  fhold; fgoto err_line;
479	              }
480	            }
481	    | 'h'i ${ if (s->number64 <= (UINT32_MAX / 3600)) {
482	                  s->number64 *= 3600;
483	              } else {
484	                  WARN(ZS_NUMBER32_OVERFLOW);
485	                  fhold; fgoto err_line;
486	              }
487	            }
488	    | 'd'i ${ if (s->number64 <= (UINT32_MAX / 86400)) {
489	                  s->number64 *= 86400;
490	              } else {
491	                  WARN(ZS_NUMBER32_OVERFLOW);
492	                  fhold; fgoto err_line;
493	              }
494	            }
495	    | 'w'i ${ if (s->number64 <= (UINT32_MAX / 604800)) {
496	                  s->number64 *= 604800;
497	              } else {
498	                  WARN(ZS_NUMBER32_OVERFLOW);
499	                  fhold; fgoto err_line;
500	              }
501	            }
502	    ) $!_time_unit_error;
503
504
505	action _time_block_init {
506		s->number64_tmp = s->number64;
507	}
508	action _time_block_exit {
509		if (s->number64 + s->number64_tmp < UINT32_MAX) {
510			s->number64 += s->number64_tmp;
511		} else {
512			WARN(ZS_NUMBER32_OVERFLOW);
513			fhold; fgoto err_line;
514		}
515	}
516
517	time_block = (number . time_unit) >_time_block_init %_time_block_exit;
518
519	# Time is either a number or a sequence of time blocks (1w1h1m).
520	time = (number . (time_unit . (time_block)*)?) $!_number_error;
521
522	time32 = time %_num32_write;
523	# END
524
525	# BEGIN - Timestamp processing
526	action _timestamp_init {
527		s->buffer_length = 0;
528	}
529	action _timestamp {
530		if (s->buffer_length < sizeof(s->buffer) - 1) {
531			s->buffer[s->buffer_length++] = fc;
532		} else {
533			WARN(ZS_RDATA_OVERFLOW);
534			fhold; fgoto err_line;
535		}
536	}
537	action _timestamp_exit {
538		s->buffer[s->buffer_length] = 0;
539
540		if (s->buffer_length == 14) { // Date; 14 = len("YYYYMMDDHHmmSS").
541			uint32_t timestamp;
542			int ret = date_to_timestamp(s->buffer, &timestamp);
543
544			if (ret == ZS_OK) {
545				*((uint32_t *)rdata_tail) = htonl(timestamp);
546				rdata_tail += 4;
547			} else {
548				WARN(ret);
549				fhold; fgoto err_line;
550			}
551		} else if (s->buffer_length <= 10) { // Timestamp format.
552			char *end;
553
554			s->number64 = strtoull((char *)(s->buffer), &end,  10);
555
556			if (end == (char *)(s->buffer) || *end != '\0') {
557				WARN(ZS_BAD_TIMESTAMP);
558				fhold; fgoto err_line;
559			}
560
561			if (s->number64 <= UINT32_MAX) {
562				*((uint32_t *)rdata_tail) = htonl((uint32_t)s->number64);
563				rdata_tail += 4;
564			} else {
565				WARN(ZS_NUMBER32_OVERFLOW);
566				fhold; fgoto err_line;
567			}
568		} else {
569			WARN(ZS_BAD_TIMESTAMP_LENGTH);
570			fhold; fgoto err_line;
571		}
572	}
573	action _timestamp_error {
574		WARN(ZS_BAD_TIMESTAMP_CHAR);
575		fhold; fgoto err_line;
576	}
577
578	timestamp = digit+ >_timestamp_init $_timestamp
579	            %_timestamp_exit $!_timestamp_error;
580	# END
581
582	# BEGIN - Text processing
583	action _text_char {
584		if (rdata_tail <= rdata_stop) {
585			// Split long string.
586			if (s->long_string &&
587			    rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
588				// _item_length_exit equivalent.
589				*(s->item_length_location) = MAX_ITEM_LENGTH;
590				// _item_length_init equivalent.
591				s->item_length_location = rdata_tail++;
592
593				if (rdata_tail > rdata_stop) {
594					WARN(ZS_TEXT_OVERFLOW);
595					fhold; fgoto err_line;
596				}
597			}
598
599			*(rdata_tail++) = fc;
600		} else {
601			WARN(ZS_TEXT_OVERFLOW);
602			fhold; fgoto err_line;
603		}
604	}
605	action _text_char_error {
606		WARN(ZS_BAD_TEXT_CHAR);
607		fhold; fgoto err_line;
608	}
609	action _text_error {
610		WARN(ZS_BAD_TEXT);
611		fhold; fgoto err_line;
612	}
613
614	action _text_dec_init {
615		if (rdata_tail <= rdata_stop) {
616			// Split long string.
617			if (s->long_string &&
618			    rdata_tail - s->item_length_location == 1 + MAX_ITEM_LENGTH) {
619				// _item_length_exit equivalent.
620				*(s->item_length_location) = MAX_ITEM_LENGTH;
621				// _item_length_init equivalent.
622				s->item_length_location = rdata_tail++;
623
624				if (rdata_tail > rdata_stop) {
625					WARN(ZS_TEXT_OVERFLOW);
626					fhold; fgoto err_line;
627				}
628			}
629
630			*rdata_tail = 0;
631			s->item_length++;
632		} else {
633			WARN(ZS_TEXT_OVERFLOW);
634			fhold; fgoto err_line;
635		}
636	}
637	action _text_dec {
638		if ((*rdata_tail < (UINT8_MAX / 10)) ||   // Dominant fast check.
639			((*rdata_tail == (UINT8_MAX / 10)) && // Marginal case.
640			 (fc <= (UINT8_MAX % 10) + '0')
641			)
642		   ) {
643			*rdata_tail *= 10;
644			*rdata_tail += digit_to_num[(uint8_t)fc];
645		} else {
646			WARN(ZS_NUMBER8_OVERFLOW);
647			fhold; fgoto err_line;
648		}
649	}
650	action _text_dec_exit {
651		rdata_tail++;
652	}
653	action _text_dec_error {
654		WARN(ZS_BAD_NUMBER);
655		fhold; fgoto err_line;
656	}
657
658	action _comma_list {
659		uint8_t *last_two = rdata_tail - 2;
660		uint16_t current_len = rdata_tail - s->item_length_location - 2;
661		if (s->comma_list) {
662			if (last_two[1] == ',') {
663				if (current_len <= 1) {
664					WARN(ZS_EMPTY_LIST_ITEM);
665					fhold; fgoto err_line;
666				} else if (last_two[0] != '\\') { // Start a new item.
667					*(s->item_length_location) = current_len;
668					s->item_length_location = rdata_tail - 1;
669				} else { // Remove backslash.
670					last_two[0] = ',';
671					rdata_tail--;
672				}
673			} else if (current_len > 1 && last_two[1] == '\\') {
674				if (last_two[0] == '\\') { // Remove backslash.
675					rdata_tail--;
676				}
677			}
678		}
679	}
680
681	text_char =
682		( (33..126 - [\\;\"])        $_text_char       # One printable char.
683		| ('\\' . (32..126 - digit)) @_text_char       # One "\x" char.
684		| ('\\'                      %_text_dec_init   # Initial "\" char.
685		   . digit {3}               $_text_dec %_text_dec_exit # "DDD" rest.
686		                             $!_text_dec_error
687		  )
688		) %_comma_list $!_text_char_error;
689
690	quoted_text_char =
691		( text_char
692		| ([ \t;] | [\n] when { s->multiline }) $_text_char
693		) $!_text_char_error;
694
695	# Text string machine instantiation (for smaller code).
696	text_ := (('\"' . quoted_text_char* . '\"') | text_char+)
697		 $!_text_error %_ret . all_wchar;
698	text = ^all_wchar ${ fhold; fcall text_; };
699
700	# Text string with forward 1-byte length.
701	text_string = text >_item_length_init %_item_length_exit;
702
703	action _text_array_init {
704		s->long_string = true;
705	}
706	action _text_array_exit {
707		s->long_string = false;
708	}
709
710	# Text string array as one rdata item.
711	text_array =
712		( (text_string . (sep . text_string)* . sep?)
713		) >_text_array_init %_text_array_exit $!_text_array_exit;
714	# END
715
716	# BEGIN - TTL directive processing
717	action _default_ttl_exit {
718		if (s->number64 <= UINT32_MAX) {
719			s->default_ttl = (uint32_t)(s->number64);
720		} else {
721			ERR(ZS_NUMBER32_OVERFLOW);
722			fhold; fgoto err_line;
723		}
724	}
725	action _default_ttl_error {
726		ERR(ZS_BAD_TTL);
727		fhold; fgoto err_line;
728	}
729
730	default_ttl_ := (sep . time . rest) $!_default_ttl_error
731	                %_default_ttl_exit %_ret . newline;
732	default_ttl = all_wchar ${ fhold; fcall default_ttl_; };
733	# END
734
735	# BEGIN - ORIGIN directive processing
736	action _zone_origin_init {
737		s->dname = s->zone_origin;
738	}
739	action _zone_origin_exit {
740		s->zone_origin_length = s->dname_tmp_length;
741	}
742	action _zone_origin_error {
743		ERR(ZS_BAD_ORIGIN);
744		fhold; fgoto err_line;
745	}
746
747	zone_origin_ := (sep . absolute_dname >_zone_origin_init . rest)
748	                $!_zone_origin_error %_zone_origin_exit %_ret . newline;
749	zone_origin = all_wchar ${ fhold; fcall zone_origin_; };
750	# END
751
752	# BEGIN - INCLUDE directive processing
753	action _incl_filename_init {
754		rdata_tail = s->r_data;
755	}
756	action _incl_filename_exit {
757		size_t len = rdata_tail - s->r_data;
758		if (len >= sizeof(s->include_filename)) {
759			ERR(ZS_BAD_INCLUDE_FILENAME);
760			fhold; fgoto err_line;
761		}
762
763		// Store zero terminated include filename.
764		memcpy(s->include_filename, s->r_data, len);
765		s->include_filename[len] = '\0';
766
767		// For detection whether origin is not present.
768		s->dname = NULL;
769	}
770	action _incl_filename_error {
771		ERR(ZS_BAD_INCLUDE_FILENAME);
772		fhold; fgoto err_line;
773	}
774
775	action _incl_origin_init {
776		s->dname = s->r_data;
777	}
778	action _incl_origin_exit {
779		s->r_data_length = s->dname_tmp_length;
780	}
781	action _incl_origin_error {
782		ERR(ZS_BAD_INCLUDE_ORIGIN);
783		fhold; fgoto err_line;
784	}
785
786	action _include_exit {
787		// Extend relative file path.
788		if (s->include_filename[0] != '/') {
789			int ret = snprintf((char *)(s->buffer), sizeof(s->buffer),
790			                   "%s/%s", s->path, s->include_filename);
791			if (ret <= 0 || ret >= sizeof(s->buffer)) {
792				ERR(ZS_BAD_INCLUDE_FILENAME);
793				fhold; fgoto err_line;
794			}
795			memcpy(s->include_filename, s->buffer, ret + 1);
796		}
797
798		// Origin conversion from wire to text form in \DDD notation.
799		if (s->dname == NULL) { // Use current origin.
800			wire_dname_to_str(s->zone_origin,
801			                  s->zone_origin_length,
802			                  (char *)s->buffer);
803		} else { // Use specified origin.
804			wire_dname_to_str(s->r_data,
805			                  s->r_data_length,
806			                  (char *)s->buffer);
807		}
808
809		// Let the caller to solve the include.
810		if (s->process.automatic) {
811			// Create new scanner for included zone file.
812			zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
813			if (ss == NULL) {
814				ERR(ZS_UNPROCESSED_INCLUDE);
815				fhold; fgoto err_line;
816			}
817
818			// Parse included zone file.
819			if (zs_init(ss, (char *)s->buffer, s->default_class,
820			            s->default_ttl) != 0 ||
821			    zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
822			    zs_set_processing(ss, s->process.record, s->process.error,
823			                      s->process.data) != 0 ||
824			    zs_parse_all(ss) != 0) {
825				// File internal errors are handled by error callback.
826				if (ss->error.counter > 0) {
827					s->error.counter += ss->error.counter;
828					ERR(ZS_UNPROCESSED_INCLUDE);
829				// General include file error.
830				} else {
831					ERR(ss->error.code);
832				}
833				zs_deinit(ss);
834				free(ss);
835				fhold; fgoto err_line;
836			}
837			zs_deinit(ss);
838			free(ss);
839		} else {
840			s->state = ZS_STATE_INCLUDE;
841			fhold; fnext main; fbreak;
842		}
843	}
844
845	include_file_ :=
846		(sep . text >_incl_filename_init %_incl_filename_exit
847		 $!_incl_filename_error .
848		 (sep . absolute_dname >_incl_origin_init %_incl_origin_exit
849		  $!_incl_origin_error
850		 )? . rest
851		) %_include_exit %_ret newline;
852	include_file = all_wchar ${ fhold; fcall include_file_; };
853	# END
854
855	# BEGIN - Directive switch
856	# Each error/warning in directive should stop processing.
857	# Some internal errors cause warning only. This causes stop processing.
858	action _directive_init {
859		ERR(ZS_OK);
860	}
861	# Remove stop processing flag.
862	action _directive_exit {
863		NOERR;
864	}
865	action _directive_error {
866		ERR(ZS_BAD_DIRECTIVE);
867		fhold; fgoto err_line;
868	}
869
870	directive = '$' . ( ("TTL"i     . default_ttl)
871	                  | ("ORIGIN"i  . zone_origin)
872	                  | ("INCLUDE"i . include_file)
873	                  ) >_directive_init %_directive_exit $!_directive_error;
874	# END
875
876	# BEGIN - RRecord class and ttl processing
877	action _default_r_class_exit {
878		s->r_class = s->default_class;
879	}
880
881	action _default_r_ttl_exit {
882		s->r_ttl = s->default_ttl;
883	}
884
885	action _r_class_in_exit {
886		s->r_class = KNOT_CLASS_IN;
887	}
888
889	action _r_ttl_exit {
890		if (s->number64 <= UINT32_MAX) {
891			s->r_ttl = (uint32_t)(s->number64);
892		} else {
893			WARN(ZS_NUMBER32_OVERFLOW);
894			fhold; fgoto err_line;
895		}
896	}
897
898	r_class = "IN"i %_r_class_in_exit;
899
900	r_ttl = time %_r_ttl_exit;
901	# END
902
903	# BEGIN - IPv4 and IPv6 address processing
904	action _addr_init {
905		s->buffer_length = 0;
906	}
907	action _addr {
908		if (s->buffer_length < sizeof(s->buffer) - 1) {
909			s->buffer[s->buffer_length++] = fc;
910		} else {
911			WARN(ZS_RDATA_OVERFLOW);
912			fhold; fgoto err_line;
913		}
914	}
915	action _addr_error {
916		WARN(ZS_BAD_ADDRESS_CHAR);
917		fhold; fgoto err_line;
918	}
919
920	action _ipv4_addr_exit {
921		s->buffer[s->buffer_length] = 0;
922
923		if (inet_pton(AF_INET, (char *)s->buffer, s->addr) <= 0) {
924			WARN(ZS_BAD_IPV4);
925			fhold; fgoto err_line;
926		}
927	}
928	action _ipv4_addr_write {
929		if (rdata_tail + ZS_INET4_ADDR_LENGTH > rdata_stop + 1) {
930			WARN(ZS_RDATA_OVERFLOW);
931			fhold; fgoto err_line;
932		}
933		memcpy(rdata_tail, s->addr, ZS_INET4_ADDR_LENGTH);
934		rdata_tail += ZS_INET4_ADDR_LENGTH;
935	}
936
937	action _ipv6_addr_exit {
938		s->buffer[s->buffer_length] = 0;
939
940		if (inet_pton(AF_INET6, (char *)s->buffer, s->addr) <= 0) {
941			WARN(ZS_BAD_IPV6);
942			fhold; fgoto err_line;
943		}
944	}
945	action _ipv6_addr_write {
946		if (rdata_tail + ZS_INET6_ADDR_LENGTH > rdata_stop + 1) {
947			WARN(ZS_RDATA_OVERFLOW);
948			fhold; fgoto err_line;
949		}
950		memcpy(rdata_tail, s->addr, ZS_INET6_ADDR_LENGTH);
951		rdata_tail += ZS_INET6_ADDR_LENGTH;
952	}
953
954	# Address parsers only.
955	ipv4_addr = (digit  | '.')+  >_addr_init $_addr %_ipv4_addr_exit
956	            $!_addr_error;
957	ipv6_addr = (xdigit | [.:])+ >_addr_init $_addr %_ipv6_addr_exit
958	            $!_addr_error;
959
960	# Write parsed address to r_data.
961	ipv4_addr_write = ipv4_addr %_ipv4_addr_write;
962	ipv6_addr_write = ipv6_addr %_ipv6_addr_write;
963	# END
964
965	# BEGIN - apl record processing
966	action _apl_init {
967		memset(&(s->apl), 0, sizeof(s->apl));
968	}
969	action _apl_excl_flag {
970		s->apl.excl_flag = 128; // dec 128  = bin 10000000.
971	}
972	action _apl_addr_1 {
973		s->apl.addr_family = 1;
974	}
975	action _apl_addr_2 {
976		s->apl.addr_family = 2;
977	}
978	action _apl_prefix_length {
979		if ((s->apl.addr_family == 1 && s->number64 <= 32) ||
980		    (s->apl.addr_family == 2 && s->number64 <= 128)) {
981			s->apl.prefix_length = (uint8_t)(s->number64);
982		} else {
983			WARN(ZS_BAD_APL);
984			fhold; fgoto err_line;
985		}
986	}
987	action _apl_exit {
988		// Copy address to buffer.
989		uint8_t len;
990		switch (s->apl.addr_family) {
991		case 1:
992			len = ZS_INET4_ADDR_LENGTH;
993			memcpy(s->buffer, s->addr, len);
994			break;
995		case 2:
996			len = ZS_INET6_ADDR_LENGTH;
997			memcpy(s->buffer, s->addr, len);
998			break;
999		default:
1000			WARN(ZS_BAD_APL);
1001			fhold; fgoto err_line;
1002		}
1003		// Find prefix without trailing zeroes.
1004		while (len > 0) {
1005			if ((s->buffer[len - 1] & 255) != 0) {
1006				break;
1007			}
1008			len--;
1009		}
1010		// Check for rdata overflow.
1011		if (rdata_tail + 4 + len > rdata_stop + 1) {
1012			WARN(ZS_RDATA_OVERFLOW);
1013			fhold; fgoto err_line;
1014		}
1015		// Write address family.
1016		uint16_t af = htons(s->apl.addr_family);
1017		memcpy(rdata_tail, &af, sizeof(af));
1018		rdata_tail += 2;
1019		// Write prefix length in bits.
1020		*(rdata_tail) = s->apl.prefix_length;
1021		rdata_tail += 1;
1022		// Write negation flag + prefix length in bytes.
1023		*(rdata_tail) = len + s->apl.excl_flag;
1024		rdata_tail += 1;
1025		// Write address prefix non-null data.
1026		memcpy(rdata_tail, s->buffer, len);
1027		rdata_tail += len;
1028	}
1029	action _apl_error {
1030		WARN(ZS_BAD_APL);
1031		fhold; fgoto err_line;
1032	}
1033
1034	apl = ('!'? $_apl_excl_flag .
1035	       ( ('1' $_apl_addr_1 . ':' . ipv4_addr . '/' . number
1036	          %_apl_prefix_length)
1037	       | ('2' $_apl_addr_2 . ':' . ipv6_addr . '/' . number
1038	          %_apl_prefix_length)
1039	       )
1040	      ) >_apl_init %_apl_exit $!_apl_error;
1041
1042	# Array of APL records (can be empty).
1043	apl_array = apl? . (sep . apl)* . sep?;
1044	# END
1045
1046	# BEGIN - Hexadecimal string array processing
1047	action _first_hex_char {
1048		if (rdata_tail <= rdata_stop) {
1049			*rdata_tail = first_hex_to_num[(uint8_t)fc];
1050		} else {
1051			WARN(ZS_RDATA_OVERFLOW);
1052			fhold; fgoto err_line;
1053		}
1054	}
1055	action _second_hex_char {
1056		*rdata_tail += second_hex_to_num[(uint8_t)fc];
1057		rdata_tail++;
1058	}
1059	action _hex_char_error {
1060		WARN(ZS_BAD_HEX_CHAR);
1061		fhold; fgoto err_line;
1062	}
1063
1064	hex_char  = (xdigit $_first_hex_char . xdigit $_second_hex_char);
1065
1066	# Hex array with possibility of inside white spaces and multiline.
1067	hex_array = (hex_char+ . sep?)+ $!_hex_char_error;
1068
1069	# Continuous hex array (or "-") with forward length processing.
1070	salt = (hex_char+ | '-') >_item_length_init %_item_length_exit
1071	       $!_hex_char_error;
1072
1073	action _type_data_exit {
1074		if ((rdata_tail - s->r_data) != s->r_data_length) {
1075			WARN(ZS_BAD_RDATA_LENGTH);
1076			fhold; fgoto err_line;
1077		}
1078	}
1079
1080	action _type_data_error {
1081		WARN(ZS_BAD_HEX_RDATA);
1082		fhold; fgoto err_line;
1083	}
1084
1085	# Hex array with control to forward length statement.
1086	type_data = hex_array %_type_data_exit $!_type_data_error;
1087	# END
1088
1089	# BEGIN - Base64 processing (RFC 4648)
1090	action _first_base64_char {
1091		if (rdata_tail <= rdata_stop) {
1092			*rdata_tail = first_base64_to_num[(uint8_t)fc];
1093		} else {
1094			WARN(ZS_RDATA_OVERFLOW);
1095			fhold; fgoto err_line;
1096		}
1097	}
1098	action _second_base64_char {
1099		*(rdata_tail++) += second_left_base64_to_num[(uint8_t)fc];
1100
1101		if (rdata_tail <= rdata_stop) {
1102			*rdata_tail = second_right_base64_to_num[(uint8_t)fc];
1103		} else {
1104			WARN(ZS_RDATA_OVERFLOW);
1105			fhold; fgoto err_line;
1106		}
1107	}
1108	action _third_base64_char {
1109		*(rdata_tail++) += third_left_base64_to_num[(uint8_t)fc];
1110
1111		if (rdata_tail <= rdata_stop) {
1112			*rdata_tail = third_right_base64_to_num[(uint8_t)fc];
1113		} else {
1114			WARN(ZS_RDATA_OVERFLOW);
1115			fhold; fgoto err_line;
1116		}
1117	}
1118	action _fourth_base64_char {
1119		*(rdata_tail++) += fourth_base64_to_num[(uint8_t)fc];
1120	}
1121
1122	action _base64_char_error {
1123		WARN(ZS_BAD_BASE64_CHAR);
1124		fhold; fgoto err_line;
1125	}
1126
1127	base64_char = alnum | [+/];
1128	base64_padd = '=';
1129	base64_quartet =
1130	    ( base64_char          $_first_base64_char  . # A
1131	      base64_char          $_second_base64_char . # AB
1132	      ( ( base64_char      $_third_base64_char  . # ABC
1133	          ( base64_char    $_fourth_base64_char   # ABCD
1134	          | base64_padd{1}                        # ABC=
1135	          )
1136	        )
1137	      | base64_padd{2}                            # AB==
1138	      )
1139	    );
1140
1141	# Base64 array with possibility of inside white spaces and multiline.
1142	base64_ := (base64_quartet+ . sep?)+ $!_base64_char_error
1143	           %_ret . end_wchar;
1144	base64 = base64_char ${ fhold; fcall base64_; };
1145	# END
1146
1147	# BEGIN - Base32hex processing (RFC 4648)
1148	action _first_base32hex_char {
1149		if (rdata_tail <= rdata_stop) {
1150			*rdata_tail = first_base32hex_to_num[(uint8_t)fc];
1151		} else {
1152			WARN(ZS_RDATA_OVERFLOW);
1153			fhold; fgoto err_line;
1154		}
1155	}
1156	action _second_base32hex_char {
1157		*(rdata_tail++) += second_left_base32hex_to_num[(uint8_t)fc];
1158
1159		if (rdata_tail <= rdata_stop) {
1160			*rdata_tail = second_right_base32hex_to_num[(uint8_t)fc];
1161		} else {
1162			WARN(ZS_RDATA_OVERFLOW);
1163			fhold; fgoto err_line;
1164		}
1165	}
1166	action _third_base32hex_char {
1167		*rdata_tail += third_base32hex_to_num[(uint8_t)fc];
1168	}
1169	action _fourth_base32hex_char {
1170		*(rdata_tail++) += fourth_left_base32hex_to_num[(uint8_t)fc];
1171
1172		if (rdata_tail <= rdata_stop) {
1173			*rdata_tail = fourth_right_base32hex_to_num[(uint8_t)fc];
1174		} else {
1175			WARN(ZS_RDATA_OVERFLOW);
1176			fhold; fgoto err_line;
1177		}
1178	}
1179	action _fifth_base32hex_char {
1180		*(rdata_tail++) += fifth_left_base32hex_to_num[(uint8_t)fc];
1181
1182		if (rdata_tail <= rdata_stop) {
1183			*rdata_tail = fifth_right_base32hex_to_num[(uint8_t)fc];
1184		} else {
1185			WARN(ZS_RDATA_OVERFLOW);
1186			fhold; fgoto err_line;
1187		}
1188	}
1189	action _sixth_base32hex_char {
1190		*rdata_tail += sixth_base32hex_to_num[(uint8_t)fc];
1191	}
1192	action _seventh_base32hex_char {
1193		*(rdata_tail++) += seventh_left_base32hex_to_num[(uint8_t)fc];
1194
1195		if (rdata_tail <= rdata_stop) {
1196			*rdata_tail = seventh_right_base32hex_to_num[(uint8_t)fc];
1197		} else {
1198			WARN(ZS_RDATA_OVERFLOW);
1199			fhold; fgoto err_line;
1200		}
1201	}
1202	action _eighth_base32hex_char {
1203		*(rdata_tail++) += eighth_base32hex_to_num[(uint8_t)fc];
1204	}
1205
1206	action _base32hex_char_error {
1207		WARN(ZS_BAD_BASE32HEX_CHAR);
1208		fhold; fgoto err_line;
1209	}
1210
1211	base32hex_char = [0-9a-vA-V];
1212	base32hex_padd = '=';
1213	base32hex_octet =
1214	    ( base32hex_char                  $_first_base32hex_char   . # A
1215	      base32hex_char                  $_second_base32hex_char  . # AB
1216	      ( ( base32hex_char              $_third_base32hex_char   . # ABC
1217	          base32hex_char              $_fourth_base32hex_char  . # ABCD
1218	          ( ( base32hex_char          $_fifth_base32hex_char   . # ABCDE
1219	              ( ( base32hex_char      $_sixth_base32hex_char   . # ABCDEF
1220	                  base32hex_char      $_seventh_base32hex_char . # ABCDEFG
1221	                  ( base32hex_char    $_eighth_base32hex_char    # ABCDEFGH
1222	                  | base32hex_padd{1}                            # ABCDEFG=
1223	                  )
1224	                )
1225	              | base32hex_padd{3}                                # ABCDE===
1226	              )
1227	            )
1228	          | base32hex_padd{4}                                    # ABCD====
1229	          )
1230	        )
1231	      | base32hex_padd{6}                                        # AB======
1232	      )
1233	    );
1234
1235	# Continuous base32hex (with padding!) array with forward length processing.
1236	hash = base32hex_octet+ >_item_length_init %_item_length_exit
1237	       $!_base32hex_char_error;
1238	# END
1239
1240	# BEGIN - Simple number write functions.
1241	action _write8_0 {
1242		*(rdata_tail++) = 0;
1243	}
1244	action _write8_1 {
1245		*(rdata_tail++) = 1;
1246	}
1247	action _write8_2 {
1248		*(rdata_tail++) = 2;
1249	}
1250	action _write8_3 {
1251		*(rdata_tail++) = 3;
1252	}
1253	action _write8_5 {
1254		*(rdata_tail++) = 5;
1255	}
1256	action _write8_6 {
1257		*(rdata_tail++) = 6;
1258	}
1259	action _write8_7 {
1260		*(rdata_tail++) = 7;
1261	}
1262	action _write8_8 {
1263		*(rdata_tail++) = 8;
1264	}
1265	action _write8_10 {
1266		*(rdata_tail++) = 10;
1267	}
1268	action _write8_12 {
1269		*(rdata_tail++) = 12;
1270	}
1271	action _write8_13 {
1272		*(rdata_tail++) = 13;
1273	}
1274	action _write8_14 {
1275		*(rdata_tail++) = 14;
1276	}
1277	action _write8_15 {
1278		*(rdata_tail++) = 15;
1279	}
1280	action _write8_16 {
1281		*(rdata_tail++) = 16;
1282	}
1283	action _write8_252 {
1284		*(rdata_tail++) = 252;
1285	}
1286	action _write8_253 {
1287		*(rdata_tail++) = 253;
1288	}
1289	action _write8_254 {
1290		*(rdata_tail++) = 254;
1291	}
1292
1293	action _write16_0 {
1294		uint16_t val = htons(0);
1295		memcpy(rdata_tail, &val, 2);
1296		rdata_tail += 2;
1297	}
1298	action _write16_1 {
1299		uint16_t val = htons(1);
1300		memcpy(rdata_tail, &val, 2);
1301		rdata_tail += 2;
1302	}
1303	action _write16_2 {
1304		uint16_t val = htons(2);
1305		memcpy(rdata_tail, &val, 2);
1306		rdata_tail += 2;
1307	}
1308	action _write16_3 {
1309		uint16_t val = htons(3);
1310		memcpy(rdata_tail, &val, 2);
1311		rdata_tail += 2;
1312	}
1313	action _write16_4 {
1314		uint16_t val = htons(4);
1315		memcpy(rdata_tail, &val, 2);
1316		rdata_tail += 2;
1317	}
1318	action _write16_5 {
1319		uint16_t val = htons(5);
1320		memcpy(rdata_tail, &val, 2);
1321		rdata_tail += 2;
1322	}
1323	action _write16_6 {
1324		uint16_t val = htons(6);
1325		memcpy(rdata_tail, &val, 2);
1326		rdata_tail += 2;
1327	}
1328	action _write16_7 {
1329		uint16_t val = htons(7);
1330		memcpy(rdata_tail, &val, 2);
1331		rdata_tail += 2;
1332	}
1333	action _write16_8 {
1334		uint16_t val = htons(8);
1335		memcpy(rdata_tail, &val, 2);
1336		rdata_tail += 2;
1337	}
1338	action _write16_253 {
1339		uint16_t val = htons(253);
1340		memcpy(rdata_tail, &val, 2);
1341		rdata_tail += 2;
1342	}
1343	action _write16_254 {
1344		uint16_t val = htons(254);
1345		memcpy(rdata_tail, &val, 2);
1346		rdata_tail += 2;
1347	}
1348	# END
1349
1350	# BEGIN - Gateway
1351	action _gateway_error {
1352		WARN(ZS_BAD_GATEWAY);
1353		fhold; fgoto err_line;
1354	}
1355	action _gateway_key_error {
1356		WARN(ZS_BAD_GATEWAY_KEY);
1357		fhold; fgoto err_line;
1358	}
1359
1360	gateway = (( ('0' $_write8_0 . sep . num8 . sep . '.')
1361	           | ('1' $_write8_1 . sep . num8 . sep . ipv4_addr_write)
1362	           | ('2' $_write8_2 . sep . num8 . sep . ipv6_addr_write)
1363	           | ('3' $_write8_3 . sep . num8 . sep . r_dname)
1364	           ) $!_gateway_error .
1365	           # If algorithm is 0 then key isn't present and vice versa.
1366	           ( ((sep . base64) when { s->number64 != 0 })
1367	           | ((sep?)         when { s->number64 == 0 }) # remove blank space
1368	           ) $!_gateway_key_error
1369	          );
1370	# END
1371
1372	# BEGIN - Type processing
1373	action _type_error {
1374		WARN(ZS_UNSUPPORTED_TYPE);
1375		fhold; fgoto err_line;
1376	}
1377
1378	type_num =
1379	    ( "A"i          %{ type_num(KNOT_RRTYPE_A, &rdata_tail); }
1380	    | "NS"i         %{ type_num(KNOT_RRTYPE_NS, &rdata_tail); }
1381	    | "CNAME"i      %{ type_num(KNOT_RRTYPE_CNAME, &rdata_tail); }
1382	    | "SOA"i        %{ type_num(KNOT_RRTYPE_SOA, &rdata_tail); }
1383	    | "PTR"i        %{ type_num(KNOT_RRTYPE_PTR, &rdata_tail); }
1384	    | "HINFO"i      %{ type_num(KNOT_RRTYPE_HINFO, &rdata_tail); }
1385	    | "MINFO"i      %{ type_num(KNOT_RRTYPE_MINFO, &rdata_tail); }
1386	    | "MX"i         %{ type_num(KNOT_RRTYPE_MX, &rdata_tail); }
1387	    | "TXT"i        %{ type_num(KNOT_RRTYPE_TXT, &rdata_tail); }
1388	    | "RP"i         %{ type_num(KNOT_RRTYPE_RP, &rdata_tail); }
1389	    | "AFSDB"i      %{ type_num(KNOT_RRTYPE_AFSDB, &rdata_tail); }
1390	    | "RT"i         %{ type_num(KNOT_RRTYPE_RT, &rdata_tail); }
1391	    | "KEY"i        %{ type_num(KNOT_RRTYPE_KEY, &rdata_tail); }
1392	    | "AAAA"i       %{ type_num(KNOT_RRTYPE_AAAA, &rdata_tail); }
1393	    | "LOC"i        %{ type_num(KNOT_RRTYPE_LOC, &rdata_tail); }
1394	    | "SRV"i        %{ type_num(KNOT_RRTYPE_SRV, &rdata_tail); }
1395	    | "NAPTR"i      %{ type_num(KNOT_RRTYPE_NAPTR, &rdata_tail); }
1396	    | "KX"i         %{ type_num(KNOT_RRTYPE_KX, &rdata_tail); }
1397	    | "CERT"i       %{ type_num(KNOT_RRTYPE_CERT, &rdata_tail); }
1398	    | "DNAME"i      %{ type_num(KNOT_RRTYPE_DNAME, &rdata_tail); }
1399	    | "APL"i        %{ type_num(KNOT_RRTYPE_APL, &rdata_tail); }
1400	    | "DS"i         %{ type_num(KNOT_RRTYPE_DS, &rdata_tail); }
1401	    | "SSHFP"i      %{ type_num(KNOT_RRTYPE_SSHFP, &rdata_tail); }
1402	    | "IPSECKEY"i   %{ type_num(KNOT_RRTYPE_IPSECKEY, &rdata_tail); }
1403	    | "RRSIG"i      %{ type_num(KNOT_RRTYPE_RRSIG, &rdata_tail); }
1404	    | "NSEC"i       %{ type_num(KNOT_RRTYPE_NSEC, &rdata_tail); }
1405	    | "DNSKEY"i     %{ type_num(KNOT_RRTYPE_DNSKEY, &rdata_tail); }
1406	    | "DHCID"i      %{ type_num(KNOT_RRTYPE_DHCID, &rdata_tail); }
1407	    | "NSEC3"i      %{ type_num(KNOT_RRTYPE_NSEC3, &rdata_tail); }
1408	    | "NSEC3PARAM"i %{ type_num(KNOT_RRTYPE_NSEC3PARAM, &rdata_tail); }
1409	    | "TLSA"i       %{ type_num(KNOT_RRTYPE_TLSA, &rdata_tail); }
1410	    | "SMIMEA"i     %{ type_num(KNOT_RRTYPE_SMIMEA, &rdata_tail); }
1411	    | "CDS"i        %{ type_num(KNOT_RRTYPE_CDS, &rdata_tail); }
1412	    | "CDNSKEY"i    %{ type_num(KNOT_RRTYPE_CDNSKEY, &rdata_tail); }
1413	    | "OPENPGPKEY"i %{ type_num(KNOT_RRTYPE_OPENPGPKEY, &rdata_tail); }
1414	    | "CSYNC"i      %{ type_num(KNOT_RRTYPE_CSYNC, &rdata_tail); }
1415	    | "ZONEMD"i     %{ type_num(KNOT_RRTYPE_ZONEMD, &rdata_tail); }
1416	    | "SPF"i        %{ type_num(KNOT_RRTYPE_SPF, &rdata_tail); }
1417	    | "NID"i        %{ type_num(KNOT_RRTYPE_NID, &rdata_tail); }
1418	    | "L32"i        %{ type_num(KNOT_RRTYPE_L32, &rdata_tail); }
1419	    | "L64"i        %{ type_num(KNOT_RRTYPE_L64, &rdata_tail); }
1420	    | "LP"i         %{ type_num(KNOT_RRTYPE_LP, &rdata_tail); }
1421	    | "EUI48"i      %{ type_num(KNOT_RRTYPE_EUI48, &rdata_tail); }
1422	    | "EUI64"i      %{ type_num(KNOT_RRTYPE_EUI64, &rdata_tail); }
1423	    | "URI"i        %{ type_num(KNOT_RRTYPE_URI, &rdata_tail); }
1424	    | "CAA"i        %{ type_num(KNOT_RRTYPE_CAA, &rdata_tail); }
1425	    | "SVCB"i       %{ type_num(KNOT_RRTYPE_SVCB, &rdata_tail); }
1426	    | "HTTPS"i      %{ type_num(KNOT_RRTYPE_HTTPS, &rdata_tail); }
1427	    | "TYPE"i      . num16 # TYPE0-TYPE65535.
1428	    ) $!_type_error;
1429	# END
1430
1431	# BEGIN - Bitmap processing
1432	action _type_bitmap_exit {
1433		if (s->number64 <= UINT16_MAX) {
1434			window_add_bit(s->number64, s);
1435		} else {
1436			WARN(ZS_NUMBER16_OVERFLOW);
1437			fhold; fgoto err_line;
1438		}
1439	}
1440
1441	# TYPE0-TYPE65535.
1442	type_bitmap = number %_type_bitmap_exit;
1443
1444	type_bit =
1445	    ( "A"i          %{ window_add_bit(KNOT_RRTYPE_A, s); }
1446	    | "NS"i         %{ window_add_bit(KNOT_RRTYPE_NS, s); }
1447	    | "CNAME"i      %{ window_add_bit(KNOT_RRTYPE_CNAME, s); }
1448	    | "SOA"i        %{ window_add_bit(KNOT_RRTYPE_SOA, s); }
1449	    | "PTR"i        %{ window_add_bit(KNOT_RRTYPE_PTR, s); }
1450	    | "HINFO"i      %{ window_add_bit(KNOT_RRTYPE_HINFO, s); }
1451	    | "MINFO"i      %{ window_add_bit(KNOT_RRTYPE_MINFO, s); }
1452	    | "MX"i         %{ window_add_bit(KNOT_RRTYPE_MX, s); }
1453	    | "TXT"i        %{ window_add_bit(KNOT_RRTYPE_TXT, s); }
1454	    | "RP"i         %{ window_add_bit(KNOT_RRTYPE_RP, s); }
1455	    | "AFSDB"i      %{ window_add_bit(KNOT_RRTYPE_AFSDB, s); }
1456	    | "RT"i         %{ window_add_bit(KNOT_RRTYPE_RT, s); }
1457	    | "KEY"i        %{ window_add_bit(KNOT_RRTYPE_KEY, s); }
1458	    | "AAAA"i       %{ window_add_bit(KNOT_RRTYPE_AAAA, s); }
1459	    | "LOC"i        %{ window_add_bit(KNOT_RRTYPE_LOC, s); }
1460	    | "SRV"i        %{ window_add_bit(KNOT_RRTYPE_SRV, s); }
1461	    | "NAPTR"i      %{ window_add_bit(KNOT_RRTYPE_NAPTR, s); }
1462	    | "KX"i         %{ window_add_bit(KNOT_RRTYPE_KX, s); }
1463	    | "CERT"i       %{ window_add_bit(KNOT_RRTYPE_CERT, s); }
1464	    | "DNAME"i      %{ window_add_bit(KNOT_RRTYPE_DNAME, s); }
1465	    | "APL"i        %{ window_add_bit(KNOT_RRTYPE_APL, s); }
1466	    | "DS"i         %{ window_add_bit(KNOT_RRTYPE_DS, s); }
1467	    | "SSHFP"i      %{ window_add_bit(KNOT_RRTYPE_SSHFP, s); }
1468	    | "IPSECKEY"i   %{ window_add_bit(KNOT_RRTYPE_IPSECKEY, s); }
1469	    | "RRSIG"i      %{ window_add_bit(KNOT_RRTYPE_RRSIG, s); }
1470	    | "NSEC"i       %{ window_add_bit(KNOT_RRTYPE_NSEC, s); }
1471	    | "DNSKEY"i     %{ window_add_bit(KNOT_RRTYPE_DNSKEY, s); }
1472	    | "DHCID"i      %{ window_add_bit(KNOT_RRTYPE_DHCID, s); }
1473	    | "NSEC3"i      %{ window_add_bit(KNOT_RRTYPE_NSEC3, s); }
1474	    | "NSEC3PARAM"i %{ window_add_bit(KNOT_RRTYPE_NSEC3PARAM, s); }
1475	    | "TLSA"i       %{ window_add_bit(KNOT_RRTYPE_TLSA, s); }
1476	    | "SMIMEA"i     %{ window_add_bit(KNOT_RRTYPE_SMIMEA, s); }
1477	    | "CDS"i        %{ window_add_bit(KNOT_RRTYPE_CDS, s); }
1478	    | "CDNSKEY"i    %{ window_add_bit(KNOT_RRTYPE_CDNSKEY, s); }
1479	    | "OPENPGPKEY"i %{ window_add_bit(KNOT_RRTYPE_OPENPGPKEY, s); }
1480	    | "CSYNC"i      %{ window_add_bit(KNOT_RRTYPE_CSYNC, s); }
1481	    | "ZONEMD"i     %{ window_add_bit(KNOT_RRTYPE_ZONEMD, s); }
1482	    | "SPF"i        %{ window_add_bit(KNOT_RRTYPE_SPF, s); }
1483	    | "NID"i        %{ window_add_bit(KNOT_RRTYPE_NID, s); }
1484	    | "L32"i        %{ window_add_bit(KNOT_RRTYPE_L32, s); }
1485	    | "L64"i        %{ window_add_bit(KNOT_RRTYPE_L64, s); }
1486	    | "LP"i         %{ window_add_bit(KNOT_RRTYPE_LP, s); }
1487	    | "EUI48"i      %{ window_add_bit(KNOT_RRTYPE_EUI48, s); }
1488	    | "EUI64"i      %{ window_add_bit(KNOT_RRTYPE_EUI64, s); }
1489	    | "URI"i        %{ window_add_bit(KNOT_RRTYPE_URI, s); }
1490	    | "CAA"i        %{ window_add_bit(KNOT_RRTYPE_CAA, s); }
1491	    | "SVCB"i       %{ window_add_bit(KNOT_RRTYPE_SVCB, s); }
1492	    | "HTTPS"i      %{ window_add_bit(KNOT_RRTYPE_HTTPS, s); }
1493	    | "TYPE"i      . type_bitmap # TYPE0-TYPE65535.
1494	    );
1495
1496	action _bitmap_init {
1497		memset(s->windows, 0, sizeof(s->windows));
1498		s->last_window = -1;
1499	}
1500	action _bitmap_exit {
1501		for (uint16_t window = 0; window <= s->last_window; window++) {
1502			if ((s->windows[window]).length > 0) {
1503				if (rdata_tail + 2 + (s->windows[window]).length <= rdata_stop)
1504				{
1505					// Window number.
1506					*rdata_tail = (uint8_t)window;
1507					rdata_tail += 1;
1508					// Bitmap length.
1509					*rdata_tail = (s->windows[window]).length;
1510					rdata_tail += 1;
1511					// Copying bitmap.
1512					memcpy(rdata_tail,
1513					       (s->windows[window]).bitmap,
1514					       (s->windows[window]).length);
1515					rdata_tail += (s->windows[window]).length;
1516				} else {
1517					WARN(ZS_RDATA_OVERFLOW);
1518					fhold; fgoto err_line;
1519				}
1520			}
1521		}
1522	}
1523	action _bitmap_error {
1524		WARN(ZS_BAD_BITMAP);
1525		fhold; fgoto err_line;
1526	}
1527
1528	# Blank bitmap is allowed too.
1529	bitmap_ := ((sep . type_bit)* . sep?) >_bitmap_init
1530	           %_bitmap_exit %_ret $!_bitmap_error . end_wchar;
1531	bitmap = all_wchar ${ fhold; fcall bitmap_; };
1532	# END
1533
1534	# BEGIN - Location processing
1535	action _d1_exit {
1536		if (s->number64 <= 90) {
1537			s->loc.d1 = (uint32_t)(s->number64);
1538		} else {
1539			WARN(ZS_BAD_NUMBER);
1540			fhold; fgoto err_line;
1541		}
1542	}
1543	action _d2_exit {
1544		if (s->number64 <= 180) {
1545			s->loc.d2 = (uint32_t)(s->number64);
1546		} else {
1547			WARN(ZS_BAD_NUMBER);
1548			fhold; fgoto err_line;
1549		}
1550	}
1551	action _m1_exit {
1552		if (s->number64 <= 59) {
1553			s->loc.m1 = (uint32_t)(s->number64);
1554		} else {
1555			WARN(ZS_BAD_NUMBER);
1556			fhold; fgoto err_line;
1557		}
1558	}
1559	action _m2_exit {
1560		if (s->number64 <= 59) {
1561			s->loc.m2 = (uint32_t)(s->number64);
1562		} else {
1563			WARN(ZS_BAD_NUMBER);
1564			fhold; fgoto err_line;
1565		}
1566	}
1567	action _s1_exit {
1568		if (s->number64 <= 59999) {
1569			s->loc.s1 = (uint32_t)(s->number64);
1570		} else {
1571			WARN(ZS_BAD_NUMBER);
1572			fhold; fgoto err_line;
1573		}
1574	}
1575	action _s2_exit {
1576		if (s->number64 <= 59999) {
1577			s->loc.s2 = (uint32_t)(s->number64);
1578		} else {
1579			WARN(ZS_BAD_NUMBER);
1580			fhold; fgoto err_line;
1581		}
1582	}
1583	action _alt_exit {
1584		if ((s->loc.alt_sign ==  1 && s->number64 <= 4284967295) ||
1585		    (s->loc.alt_sign == -1 && s->number64 <=   10000000))
1586		{
1587			s->loc.alt = (uint32_t)(s->number64);
1588		} else {
1589			WARN(ZS_BAD_NUMBER);
1590			fhold; fgoto err_line;
1591		}
1592	}
1593	action _siz_exit {
1594		if (s->number64 <= 9000000000ULL) {
1595			s->loc.siz = s->number64;
1596		} else {
1597			WARN(ZS_BAD_NUMBER);
1598			fhold; fgoto err_line;
1599		}
1600	}
1601	action _hp_exit {
1602		if (s->number64 <= 9000000000ULL) {
1603			s->loc.hp = s->number64;
1604		} else {
1605			WARN(ZS_BAD_NUMBER);
1606			fhold; fgoto err_line;
1607		}
1608	}
1609	action _vp_exit {
1610		if (s->number64 <= 9000000000ULL) {
1611			s->loc.vp = s->number64;
1612		} else {
1613			WARN(ZS_BAD_NUMBER);
1614			fhold; fgoto err_line;
1615		}
1616	}
1617	action _lat_sign {
1618		s->loc.lat_sign = -1;
1619	}
1620	action _long_sign {
1621		s->loc.long_sign = -1;
1622	}
1623	action _alt_sign {
1624		s->loc.alt_sign = -1;
1625	}
1626
1627	d1  = number %_d1_exit;
1628	d2  = number %_d2_exit;
1629	m1  = number %_m1_exit;
1630	m2  = number %_m2_exit;
1631	s1  = float3 %_s1_exit;
1632	s2  = float3 %_s2_exit;
1633	siz = float2 %_siz_exit;
1634	hp  = float2 %_hp_exit;
1635	vp  = float2 %_vp_exit;
1636	alt = ('-' %_alt_sign)? . float2 %_alt_exit;
1637	lat_sign  = 'N' | 'S' %_lat_sign;
1638	long_sign = 'E' | 'W' %_long_sign;
1639
1640	action _loc_init {
1641		memset(&(s->loc), 0, sizeof(s->loc));
1642		// Defaults.
1643		s->loc.siz = 100;
1644		s->loc.vp  = 1000;
1645		s->loc.hp  = 1000000;
1646		s->loc.lat_sign  = 1;
1647		s->loc.long_sign = 1;
1648		s->loc.alt_sign  = 1;
1649	}
1650	action _loc_exit {
1651		// Write version.
1652		*(rdata_tail) = 0;
1653		rdata_tail += 1;
1654		// Write size.
1655		*(rdata_tail) = loc64to8(s->loc.siz);
1656		rdata_tail += 1;
1657		// Write horizontal precision.
1658		*(rdata_tail) = loc64to8(s->loc.hp);
1659		rdata_tail += 1;
1660		// Write vertical precision.
1661		*(rdata_tail) = loc64to8(s->loc.vp);
1662		rdata_tail += 1;
1663		// Write latitude.
1664		*((uint32_t *)rdata_tail) = htonl(LOC_LAT_ZERO + s->loc.lat_sign *
1665			(3600000 * s->loc.d1 + 60000 * s->loc.m1 + s->loc.s1));
1666		rdata_tail += 4;
1667		// Write longitude.
1668		*((uint32_t *)rdata_tail) = htonl(LOC_LONG_ZERO + s->loc.long_sign *
1669			(3600000 * s->loc.d2 + 60000 * s->loc.m2 + s->loc.s2));
1670		rdata_tail += 4;
1671		// Write altitude.
1672		*((uint32_t *)rdata_tail) = htonl(LOC_ALT_ZERO + s->loc.alt_sign *
1673			(s->loc.alt));
1674		rdata_tail += 4;
1675	}
1676	action _loc_error {
1677		WARN(ZS_BAD_LOC_DATA);
1678		fhold; fgoto err_line;
1679	}
1680
1681	loc = (d1 . sep . (m1 . sep . (s1 . sep)?)? . lat_sign  . sep .
1682	       d2 . sep . (m2 . sep . (s2 . sep)?)? . long_sign . sep .
1683	       alt 'm'? . (sep . siz 'm'? . (sep . hp 'm'? . (sep . vp 'm'?)?)?)? .
1684	       sep?
1685	      ) >_loc_init %_loc_exit $!_loc_error;
1686	# END
1687
1688	# BEGIN - Hexadecimal rdata processing
1689	action _hex_r_data_error {
1690		WARN(ZS_BAD_HEX_RDATA);
1691		fhold; fgoto err_line;
1692	}
1693
1694	nonempty_hex_r_data :=
1695		(sep . length_number . sep . type_data)
1696		$!_hex_r_data_error %_ret . end_wchar;
1697
1698	hex_r_data :=
1699		(sep .
1700		 ( ('0'                             %_ret . all_wchar)
1701		 | (length_number . sep . type_data %_ret . end_wchar)
1702		 )
1703		) $!_hex_r_data_error;
1704	# END
1705
1706	# BEGIN - EUI processing
1707	action _eui_init {
1708		s->item_length = 0;
1709	}
1710	action _eui_count {
1711		s->item_length++;
1712	}
1713	action _eui48_exit {
1714		if (s->item_length != 6) {
1715			WARN(ZS_BAD_EUI_LENGTH);
1716			fhold; fgoto err_line;
1717		}
1718	}
1719	action _eui64_exit {
1720		if (s->item_length != 8) {
1721			WARN(ZS_BAD_EUI_LENGTH);
1722			fhold; fgoto err_line;
1723		}
1724	}
1725	action _eui_sep_error {
1726		WARN(ZS_BAD_CHAR_DASH);
1727		fhold; fgoto err_line;
1728	}
1729
1730	eui48 = (hex_char %_eui_count .
1731	         ('-' >!_eui_sep_error . hex_char %_eui_count)+
1732		) $!_hex_char_error >_eui_init %_eui48_exit;
1733
1734	eui64 = (hex_char %_eui_count .
1735	         ('-' >!_eui_sep_error . hex_char %_eui_count)+
1736		) $!_hex_char_error >_eui_init %_eui64_exit;
1737	# END
1738
1739	# BEGIN - ILNP processing
1740	action _l64_init {
1741		s->item_length = 0;
1742	}
1743	action _l64_count {
1744		s->item_length++;
1745	}
1746	action _l64_exit {
1747		if (s->item_length != 4) {
1748			WARN(ZS_BAD_L64_LENGTH);
1749			fhold; fgoto err_line;
1750		}
1751	}
1752	action _l64_sep_error {
1753		WARN(ZS_BAD_CHAR_COLON);
1754		fhold; fgoto err_line;
1755	}
1756
1757	l64_label = (hex_char . hex_char) $!_hex_char_error %_l64_count;
1758	l64 = (l64_label . (':' >!_l64_sep_error . l64_label)+
1759	      ) $!_hex_char_error >_l64_init %_l64_exit;
1760
1761	l32 = ipv4_addr %_ipv4_addr_write;
1762	# END
1763
1764	# BEGIN - SvcParams processing (SVCB/HTTPS records)
1765	action _svcb_params_init {
1766		s->svcb.params_position = rdata_tail;
1767		s->svcb.last_key = -1;
1768	}
1769	action _svcb_params_exit {
1770		int ret = svcb_check(s, rdata_tail);
1771		if (ret != ZS_OK) {
1772			WARN(ret);
1773			fhold; fgoto err_line;
1774		}
1775	}
1776	action _svcb_params_error {
1777		WARN(ZS_BAD_SVCB_PARAM);
1778		fhold; fgoto err_line;
1779	}
1780
1781	action _mandat_value_error {
1782		WARN(ZS_BAD_SVCB_MANDATORY);
1783		fhold; fgoto err_line;
1784	}
1785
1786	action _svcb_param_init {
1787		if (rdata_tail + 4 > rdata_stop + 1) { // key_len + val_len
1788			WARN(ZS_RDATA_OVERFLOW);
1789			fhold; fgoto err_line;
1790		}
1791		s->svcb.param_position = rdata_tail;
1792	}
1793	action _svcb_param_exit {
1794		int ret = svcb_sort(s, rdata_tail);
1795		if (ret != ZS_OK) {
1796			WARN(ret);
1797			fhold; fgoto err_line;
1798		}
1799	}
1800
1801	action _alpnl_init {
1802		s->comma_list = true;
1803	}
1804	action _alpnl_exit {
1805		s->comma_list = false;
1806	}
1807
1808	action _mandatory_init {
1809		s->svcb.mandatory_position = rdata_tail + 2; // Skip 2-B prefix.
1810	}
1811	action _mandatory_exit {
1812		svcb_mandatory_sort(s->svcb.mandatory_position, rdata_tail);
1813	}
1814
1815	action _rdata_2B_check {
1816		if (rdata_tail + 2 > rdata_stop + 1) {
1817			WARN(ZS_RDATA_OVERFLOW);
1818			fhold; fgoto err_line;
1819		}
1820	}
1821
1822	svcb_key_generic   = ("key"             . num16);
1823	svcb_key_mandatory = ("mandatory"       %_write16_0);
1824	svcb_key_alpn      = ("alpn"            %_write16_1);
1825	svcb_key_ndalpn    = ("no-default-alpn" %_write16_2);
1826	svcb_key_port      = ("port"            %_write16_3);
1827	svcb_key_ipv4hint  = ("ipv4hint"        %_write16_4);
1828	svcb_key_ech       = ("ech"             %_write16_5);
1829	svcb_key_ipv6hint  = ("ipv6hint"        %_write16_6);
1830
1831	mandat_value_ :=
1832		(svcb_key_generic | svcb_key_alpn | svcb_key_ndalpn | svcb_key_port |
1833		 svcb_key_ipv4hint | svcb_key_ech | svcb_key_ipv6hint
1834		) >_rdata_2B_check $!_mandat_value_error %_ret . ([,\"] | all_wchar);
1835	mandat_value = alpha ${ fhold; fcall mandat_value_; };
1836
1837	svcb_empty    = zlen %_write16_0;
1838	svcb_generic_ = (text                                         >_item_length2_init %_item_length2_exit);
1839	svcb_generic  = ("=" .  svcb_generic_) | svcb_empty;
1840	svcb_mandat_  = ((mandat_value    . ("," . mandat_value)*)    >_item_length2_init %_item_length2_exit);
1841	svcb_mandat   = svcb_mandat_ >_mandatory_init %_mandatory_exit;
1842	svcb_alpn     = (text_string >_alpnl_init %_alpnl_exit        >_item_length2_init %_item_length2_exit);
1843	svcb_port     = num16 >_write16_2 >_rdata_2B_check;
1844	svcb_ipv4     = ((ipv4_addr_write . ("," . ipv4_addr_write)*) >_item_length2_init %_item_length2_exit);
1845	svcb_ech      = (base64_quartet+                              >_item_length2_init %_item_length2_exit);
1846	svcb_ipv6     = ((ipv6_addr_write . ("," . ipv6_addr_write)*) >_item_length2_init %_item_length2_exit);
1847
1848	svcb_param_generic   = (svcb_key_generic   . svcb_generic);
1849	svcb_param_mandatory = (svcb_key_mandatory . "=" . (svcb_mandat | ('\"' . svcb_mandat . '\"')));
1850	svcb_param_alpn      = (svcb_key_alpn      . "=" . (svcb_alpn   | ('\"' . svcb_alpn   . '\"')));
1851	svcb_param_ndalpn    = (svcb_key_ndalpn    . svcb_empty);
1852	svcb_param_port      = (svcb_key_port      . "=" . (svcb_port   | ('\"' . svcb_port   . '\"')));
1853	svcb_param_ipv4hint  = (svcb_key_ipv4hint  . "=" . (svcb_ipv4   | ('\"' . svcb_ipv4   . '\"')));
1854	svcb_param_ech       = (svcb_key_ech       . "=" . (svcb_ech    | ('\"' . svcb_ech    . '\"')));
1855	svcb_param_ipv6hint  = (svcb_key_ipv6hint  . "=" . (svcb_ipv6   | ('\"' . svcb_ipv6   . '\"')));
1856
1857	svcb_param_any =
1858		(svcb_param_generic | svcb_param_mandatory | svcb_param_alpn |
1859		 svcb_param_ndalpn | svcb_param_port | svcb_param_ipv4hint |
1860		 svcb_param_ech | svcb_param_ipv6hint
1861		) >_svcb_param_init %_svcb_param_exit;
1862	svcb_params_ :=
1863		((sep . svcb_param_any)* . sep?) >_svcb_params_init
1864		%_svcb_params_exit $!_svcb_params_error %_ret . end_wchar;
1865	svcb_params = all_wchar ${ fhold; fcall svcb_params_; };
1866	# END
1867
1868	# BEGIN - Mnemomic names processing
1869	action _dns_alg_error {
1870		WARN(ZS_BAD_ALGORITHM);
1871		fhold; fgoto err_line;
1872	}
1873	action _cert_type_error {
1874		WARN(ZS_BAD_CERT_TYPE);
1875		fhold; fgoto err_line;
1876	}
1877
1878	dns_alg_ :=
1879		( number                %_num8_write
1880		| "RSAMD5"i             %_write8_1
1881		| "DH"i                 %_write8_2
1882		| "DSA"i                %_write8_3
1883		| "RSASHA1"i            %_write8_5
1884		| "DSA-NSEC3-SHA1"i     %_write8_6
1885		| "RSASHA1-NSEC3-SHA1"i %_write8_7
1886		| "RSASHA256"i          %_write8_8
1887		| "RSASHA512"i          %_write8_10
1888		| "ECC-GOST"i           %_write8_12
1889		| "ECDSAP256SHA256"i    %_write8_13
1890		| "ECDSAP384SHA384"i    %_write8_14
1891		| "ED25519"i            %_write8_15
1892		| "ED448"i              %_write8_16
1893		| "INDIRECT"i           %_write8_252
1894		| "PRIVATEDNS"i         %_write8_253
1895		| "PRIVATEOID"i         %_write8_254
1896		) $!_dns_alg_error %_ret . all_wchar;
1897	dns_alg = alnum ${ fhold; fcall dns_alg_; };
1898
1899	cert_type_ :=
1900		( number     %_num16_write
1901		| "PKIX"i    %_write16_1
1902		| "SPKI"i    %_write16_2
1903		| "PGP"i     %_write16_3
1904		| "IPKIX"i   %_write16_4
1905		| "ISPKI"i   %_write16_5
1906		| "IPGP"i    %_write16_6
1907		| "ACPKIX"i  %_write16_7
1908		| "IACPKIX"i %_write16_8
1909		| "URI"i     %_write16_253
1910		| "OID"i     %_write16_254
1911		) $!_cert_type_error %_ret . all_wchar;
1912	cert_type = alnum ${ fhold; fcall cert_type_; };
1913	# END
1914
1915	# BEGIN - Rdata processing
1916	action _r_data_init {
1917		rdata_tail = s->r_data;
1918	}
1919	action _r_data_error {
1920		WARN(ZS_BAD_RDATA);
1921		fhold; fgoto err_line;
1922	}
1923
1924	r_data_a :=
1925		(ipv4_addr_write)
1926		$!_r_data_error %_ret . all_wchar;
1927
1928	r_data_ns :=
1929		(r_dname)
1930		$!_r_data_error %_ret . all_wchar;
1931
1932	r_data_soa :=
1933		(r_dname . sep . r_dname . sep . num32 . sep . time32 .
1934		 sep . time32 . sep . time32 . sep . time32)
1935		$!_r_data_error %_ret . all_wchar;
1936
1937	r_data_hinfo :=
1938		(text_string . sep . text_string)
1939		$!_r_data_error %_ret . all_wchar;
1940
1941	r_data_minfo :=
1942		(r_dname . sep . r_dname)
1943		$!_r_data_error %_ret . all_wchar;
1944
1945	r_data_mx :=
1946		(num16 . sep . r_dname)
1947		$!_r_data_error %_ret . all_wchar;
1948
1949	r_data_txt :=
1950		(text_array)
1951		$!_r_data_error %_ret . end_wchar;
1952
1953	r_data_aaaa :=
1954		(ipv6_addr_write)
1955		$!_r_data_error %_ret . all_wchar;
1956
1957	r_data_loc :=
1958		(loc)
1959		$!_r_data_error %_ret . end_wchar;
1960
1961	r_data_srv :=
1962		(num16 . sep . num16 . sep . num16 . sep . r_dname)
1963		$!_r_data_error %_ret . all_wchar;
1964
1965	r_data_naptr :=
1966		(num16 . sep . num16 . sep . text_string . sep . text_string .
1967		 sep . text_string . sep . r_dname)
1968		$!_r_data_error %_ret . all_wchar;
1969
1970	r_data_cert :=
1971		(cert_type . sep . num16 . sep . dns_alg . sep . base64)
1972		$!_r_data_error %_ret . end_wchar;
1973
1974	r_data_apl :=
1975		(apl_array)
1976		$!_r_data_error %_ret . end_wchar;
1977
1978	r_data_ds :=
1979		(num16 . sep . dns_alg . sep . num8 . sep . hex_array)
1980		$!_r_data_error %_ret . end_wchar;
1981
1982	r_data_sshfp :=
1983		(num8 . sep . num8 . sep . hex_array)
1984		$!_r_data_error %_ret . end_wchar;
1985
1986	r_data_ipseckey :=
1987		(num8 . sep . gateway)
1988		$!_r_data_error %_ret . end_wchar;
1989
1990	r_data_rrsig :=
1991		(type_num . sep . dns_alg . sep . num8 . sep . num32 . sep .
1992		 timestamp . sep . timestamp . sep . num16 . sep . r_dname .
1993		 sep . base64)
1994		$!_r_data_error %_ret . end_wchar;
1995
1996	r_data_nsec :=
1997		(r_dname . bitmap)
1998		$!_r_data_error %_ret . all_wchar;
1999
2000	r_data_dnskey :=
2001		(num16 . sep . num8 . sep . dns_alg . sep . base64)
2002		$!_r_data_error %_ret . end_wchar;
2003
2004	r_data_dhcid :=
2005		(base64)
2006		$!_r_data_error %_ret . end_wchar;
2007
2008	r_data_nsec3 :=
2009		(num8 . sep . num8 . sep . num16 . sep . salt . sep .
2010		 hash . bitmap)
2011		$!_r_data_error %_ret . all_wchar;
2012
2013	r_data_nsec3param :=
2014		(num8 . sep . num8 . sep . num16 . sep . salt)
2015		$!_r_data_error %_ret . all_wchar;
2016
2017	r_data_tlsa :=
2018		(num8 . sep . num8 . sep . num8 . sep . hex_array)
2019		$!_r_data_error %_ret . end_wchar;
2020
2021	r_data_csync :=
2022		(num32 . sep . num16 . bitmap)
2023		$!_r_data_error %_ret . all_wchar;
2024
2025	r_data_zonemd :=
2026		(num32 . sep . num8 . sep . num8 . sep . hex_array)
2027		$!_r_data_error %_ret . end_wchar;
2028
2029	r_data_l32 :=
2030		(num16 . sep . l32)
2031		$!_r_data_error %_ret . all_wchar;
2032
2033	r_data_l64 :=
2034		(num16 . sep . l64)
2035		$!_r_data_error %_ret . all_wchar;
2036
2037	r_data_eui48 :=
2038		(eui48)
2039		$!_r_data_error %_ret . all_wchar;
2040
2041	r_data_eui64 :=
2042		(eui64)
2043		$!_r_data_error %_ret . all_wchar;
2044
2045	r_data_uri :=
2046		(num16 . sep . num16 . sep . text)
2047		$!_r_data_error %_ret . all_wchar;
2048
2049	r_data_caa :=
2050		(num8 . sep . text_string . sep . text)
2051		$!_r_data_error %_ret . all_wchar;
2052
2053	r_data_svcb :=
2054		(num16 . sep . r_dname . svcb_params)
2055		$!_r_data_error %_ret . all_wchar;
2056
2057	action _text_r_data {
2058		fhold;
2059		switch (s->r_type) {
2060		case KNOT_RRTYPE_A:
2061			fcall r_data_a;
2062		case KNOT_RRTYPE_NS:
2063		case KNOT_RRTYPE_CNAME:
2064		case KNOT_RRTYPE_PTR:
2065		case KNOT_RRTYPE_DNAME:
2066			fcall r_data_ns;
2067		case KNOT_RRTYPE_SOA:
2068			fcall r_data_soa;
2069		case KNOT_RRTYPE_HINFO:
2070			fcall r_data_hinfo;
2071		case KNOT_RRTYPE_MINFO:
2072		case KNOT_RRTYPE_RP:
2073			fcall r_data_minfo;
2074		case KNOT_RRTYPE_MX:
2075		case KNOT_RRTYPE_AFSDB:
2076		case KNOT_RRTYPE_RT:
2077		case KNOT_RRTYPE_KX:
2078		case KNOT_RRTYPE_LP:
2079			fcall r_data_mx;
2080		case KNOT_RRTYPE_TXT:
2081		case KNOT_RRTYPE_SPF:
2082			fcall r_data_txt;
2083		case KNOT_RRTYPE_AAAA:
2084			fcall r_data_aaaa;
2085		case KNOT_RRTYPE_LOC:
2086			fcall r_data_loc;
2087		case KNOT_RRTYPE_SRV:
2088			fcall r_data_srv;
2089		case KNOT_RRTYPE_NAPTR:
2090			fcall r_data_naptr;
2091		case KNOT_RRTYPE_CERT:
2092			fcall r_data_cert;
2093		case KNOT_RRTYPE_APL:
2094			fcall r_data_apl;
2095		case KNOT_RRTYPE_DS:
2096		case KNOT_RRTYPE_CDS:
2097			fcall r_data_ds;
2098		case KNOT_RRTYPE_SSHFP:
2099			fcall r_data_sshfp;
2100		case KNOT_RRTYPE_IPSECKEY:
2101			fcall r_data_ipseckey;
2102		case KNOT_RRTYPE_RRSIG:
2103			fcall r_data_rrsig;
2104		case KNOT_RRTYPE_NSEC:
2105			fcall r_data_nsec;
2106		case KNOT_RRTYPE_KEY:
2107		case KNOT_RRTYPE_DNSKEY:
2108		case KNOT_RRTYPE_CDNSKEY:
2109			fcall r_data_dnskey;
2110		case KNOT_RRTYPE_DHCID:
2111		case KNOT_RRTYPE_OPENPGPKEY:
2112			fcall r_data_dhcid;
2113		case KNOT_RRTYPE_NSEC3:
2114			fcall r_data_nsec3;
2115		case KNOT_RRTYPE_NSEC3PARAM:
2116			fcall r_data_nsec3param;
2117		case KNOT_RRTYPE_TLSA:
2118		case KNOT_RRTYPE_SMIMEA:
2119			fcall r_data_tlsa;
2120		case KNOT_RRTYPE_CSYNC:
2121			fcall r_data_csync;
2122		case KNOT_RRTYPE_ZONEMD:
2123			fcall r_data_zonemd;
2124		case KNOT_RRTYPE_NID:
2125		case KNOT_RRTYPE_L64:
2126			fcall r_data_l64;
2127		case KNOT_RRTYPE_L32:
2128			fcall r_data_l32;
2129		case KNOT_RRTYPE_EUI48:
2130			fcall r_data_eui48;
2131		case KNOT_RRTYPE_EUI64:
2132			fcall r_data_eui64;
2133		case KNOT_RRTYPE_URI:
2134			fcall r_data_uri;
2135		case KNOT_RRTYPE_CAA:
2136			fcall r_data_caa;
2137		case KNOT_RRTYPE_SVCB:
2138		case KNOT_RRTYPE_HTTPS:
2139			fcall r_data_svcb;
2140		default:
2141			WARN(ZS_CANNOT_TEXT_DATA);
2142			fgoto err_line;
2143		}
2144	}
2145	action _hex_r_data {
2146		switch (s->r_type) {
2147		// Next types must not have empty rdata.
2148		case KNOT_RRTYPE_A:
2149		case KNOT_RRTYPE_NS:
2150		case KNOT_RRTYPE_CNAME:
2151		case KNOT_RRTYPE_PTR:
2152		case KNOT_RRTYPE_DNAME:
2153		case KNOT_RRTYPE_SOA:
2154		case KNOT_RRTYPE_HINFO:
2155		case KNOT_RRTYPE_MINFO:
2156		case KNOT_RRTYPE_MX:
2157		case KNOT_RRTYPE_AFSDB:
2158		case KNOT_RRTYPE_RT:
2159		case KNOT_RRTYPE_KX:
2160		case KNOT_RRTYPE_TXT:
2161		case KNOT_RRTYPE_SPF:
2162		case KNOT_RRTYPE_RP:
2163		case KNOT_RRTYPE_AAAA:
2164		case KNOT_RRTYPE_LOC:
2165		case KNOT_RRTYPE_SRV:
2166		case KNOT_RRTYPE_NAPTR:
2167		case KNOT_RRTYPE_CERT:
2168		case KNOT_RRTYPE_DS:
2169		case KNOT_RRTYPE_SSHFP:
2170		case KNOT_RRTYPE_IPSECKEY:
2171		case KNOT_RRTYPE_RRSIG:
2172		case KNOT_RRTYPE_NSEC:
2173		case KNOT_RRTYPE_KEY:
2174		case KNOT_RRTYPE_DNSKEY:
2175		case KNOT_RRTYPE_DHCID:
2176		case KNOT_RRTYPE_NSEC3:
2177		case KNOT_RRTYPE_NSEC3PARAM:
2178		case KNOT_RRTYPE_TLSA:
2179		case KNOT_RRTYPE_SMIMEA:
2180		case KNOT_RRTYPE_CDS:
2181		case KNOT_RRTYPE_CDNSKEY:
2182		case KNOT_RRTYPE_OPENPGPKEY:
2183		case KNOT_RRTYPE_CSYNC:
2184		case KNOT_RRTYPE_ZONEMD:
2185		case KNOT_RRTYPE_NID:
2186		case KNOT_RRTYPE_L32:
2187		case KNOT_RRTYPE_L64:
2188		case KNOT_RRTYPE_LP:
2189		case KNOT_RRTYPE_EUI48:
2190		case KNOT_RRTYPE_EUI64:
2191		case KNOT_RRTYPE_URI:
2192		case KNOT_RRTYPE_CAA:
2193		case KNOT_RRTYPE_SVCB:
2194		case KNOT_RRTYPE_HTTPS:
2195			fcall nonempty_hex_r_data;
2196		// Next types can have empty rdata.
2197		case KNOT_RRTYPE_APL:
2198		default:
2199			fcall hex_r_data;
2200		}
2201	}
2202
2203	# Avoidance of multiple fhold at the input block end.
2204	action _wrap_in {
2205		if (pe - p == 1) {
2206			*wrap = WRAP_DETECTED;
2207		}
2208	}
2209	action _wrap_out {
2210		if (*wrap == WRAP_NONE) {
2211			fhold;
2212		}
2213	}
2214
2215	# rdata can be in text or hex format with leading "\#" string.
2216	r_data =
2217		( sep  . ^('\\' | all_wchar)              $_text_r_data
2218		| sep  . '\\' $_wrap_in . ^'#' $_wrap_out $_text_r_data
2219		| sep  . '\\'           .  '#'            $_hex_r_data   # Hex format.
2220		| sep? . end_wchar                        $_text_r_data  # Empty rdata.
2221		) >_r_data_init $!_r_data_error;
2222	# END
2223
2224	# BEGIN - Record type processing
2225	action _r_type_error {
2226		WARN(ZS_UNSUPPORTED_TYPE);
2227		fhold; fgoto err_line;
2228	}
2229
2230	r_type =
2231		( "A"i          %{ s->r_type = KNOT_RRTYPE_A; }
2232		| "NS"i         %{ s->r_type = KNOT_RRTYPE_NS; }
2233		| "CNAME"i      %{ s->r_type = KNOT_RRTYPE_CNAME; }
2234		| "SOA"i        %{ s->r_type = KNOT_RRTYPE_SOA; }
2235		| "PTR"i        %{ s->r_type = KNOT_RRTYPE_PTR; }
2236		| "HINFO"i      %{ s->r_type = KNOT_RRTYPE_HINFO; }
2237		| "MINFO"i      %{ s->r_type = KNOT_RRTYPE_MINFO; }
2238		| "MX"i         %{ s->r_type = KNOT_RRTYPE_MX; }
2239		| "TXT"i        %{ s->r_type = KNOT_RRTYPE_TXT; }
2240		| "RP"i         %{ s->r_type = KNOT_RRTYPE_RP; }
2241		| "AFSDB"i      %{ s->r_type = KNOT_RRTYPE_AFSDB; }
2242		| "RT"i         %{ s->r_type = KNOT_RRTYPE_RT; }
2243		| "KEY"i        %{ s->r_type = KNOT_RRTYPE_KEY; }
2244		| "AAAA"i       %{ s->r_type = KNOT_RRTYPE_AAAA; }
2245		| "LOC"i        %{ s->r_type = KNOT_RRTYPE_LOC; }
2246		| "SRV"i        %{ s->r_type = KNOT_RRTYPE_SRV; }
2247		| "NAPTR"i      %{ s->r_type = KNOT_RRTYPE_NAPTR; }
2248		| "KX"i         %{ s->r_type = KNOT_RRTYPE_KX; }
2249		| "CERT"i       %{ s->r_type = KNOT_RRTYPE_CERT; }
2250		| "DNAME"i      %{ s->r_type = KNOT_RRTYPE_DNAME; }
2251		| "APL"i        %{ s->r_type = KNOT_RRTYPE_APL; }
2252		| "DS"i         %{ s->r_type = KNOT_RRTYPE_DS; }
2253		| "SSHFP"i      %{ s->r_type = KNOT_RRTYPE_SSHFP; }
2254		| "IPSECKEY"i   %{ s->r_type = KNOT_RRTYPE_IPSECKEY; }
2255		| "RRSIG"i      %{ s->r_type = KNOT_RRTYPE_RRSIG; }
2256		| "NSEC"i       %{ s->r_type = KNOT_RRTYPE_NSEC; }
2257		| "DNSKEY"i     %{ s->r_type = KNOT_RRTYPE_DNSKEY; }
2258		| "DHCID"i      %{ s->r_type = KNOT_RRTYPE_DHCID; }
2259		| "NSEC3"i      %{ s->r_type = KNOT_RRTYPE_NSEC3; }
2260		| "NSEC3PARAM"i %{ s->r_type = KNOT_RRTYPE_NSEC3PARAM; }
2261		| "TLSA"i       %{ s->r_type = KNOT_RRTYPE_TLSA; }
2262		| "SMIMEA"i     %{ s->r_type = KNOT_RRTYPE_SMIMEA; }
2263		| "CDS"i        %{ s->r_type = KNOT_RRTYPE_CDS; }
2264		| "CDNSKEY"i    %{ s->r_type = KNOT_RRTYPE_CDNSKEY; }
2265		| "OPENPGPKEY"i %{ s->r_type = KNOT_RRTYPE_OPENPGPKEY; }
2266		| "CSYNC"i      %{ s->r_type = KNOT_RRTYPE_CSYNC; }
2267		| "ZONEMD"i     %{ s->r_type = KNOT_RRTYPE_ZONEMD; }
2268		| "SPF"i        %{ s->r_type = KNOT_RRTYPE_SPF; }
2269		| "NID"i        %{ s->r_type = KNOT_RRTYPE_NID; }
2270		| "L32"i        %{ s->r_type = KNOT_RRTYPE_L32; }
2271		| "L64"i        %{ s->r_type = KNOT_RRTYPE_L64; }
2272		| "LP"i         %{ s->r_type = KNOT_RRTYPE_LP; }
2273		| "EUI48"i      %{ s->r_type = KNOT_RRTYPE_EUI48; }
2274		| "EUI64"i      %{ s->r_type = KNOT_RRTYPE_EUI64; }
2275		| "URI"i        %{ s->r_type = KNOT_RRTYPE_URI; }
2276		| "CAA"i        %{ s->r_type = KNOT_RRTYPE_CAA; }
2277		| "SVCB"i       %{ s->r_type = KNOT_RRTYPE_SVCB; }
2278		| "HTTPS"i      %{ s->r_type = KNOT_RRTYPE_HTTPS; }
2279		| "TYPE"i      . type_number
2280		) $!_r_type_error;
2281	# END
2282
2283	# BEGIN - The highest level processing
2284	action _record_exit {
2285		if (rdata_tail - s->r_data > UINT16_MAX) {
2286			WARN(ZS_RDATA_OVERFLOW);
2287			fhold; fgoto err_line;
2288		}
2289		s->r_data_length = rdata_tail - s->r_data;
2290
2291		s->state = ZS_STATE_DATA;
2292
2293		// Execute the record callback.
2294		if (s->process.automatic) {
2295			if (s->process.record != NULL) {
2296				s->process.record(s);
2297
2298				// Stop if required from the callback.
2299				if (s->state == ZS_STATE_STOP) {
2300					fbreak;
2301				}
2302			}
2303		} else {
2304			// Return if external processing.
2305			fhold; fbreak;
2306		}
2307	}
2308
2309	# Resource record.
2310	record =
2311		r_owner . sep .
2312		( (r_class . sep . ((r_ttl   . sep) | (zlen %_default_r_ttl_exit  )))
2313		| (r_ttl   . sep . ((r_class . sep) | (zlen %_default_r_class_exit)))
2314		| zlen %_default_r_class_exit %_default_r_ttl_exit
2315		) $!_r_type_error .
2316		r_type . r_data .
2317		rest %_record_exit .
2318		newline;
2319
2320	# Blank spaces with comments.
2321	blank = rest . newline;
2322
2323	# Main processing loop.
2324	main := (record | directive | blank)*;
2325	# END
2326}%%
2327