xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/generic/naptr_35.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: naptr_35.c,v 1.9 2025/01/26 16:25:32 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /* RFC2915 */
17 
18 #ifndef RDATA_GENERIC_NAPTR_35_C
19 #define RDATA_GENERIC_NAPTR_35_C
20 
21 #define RRTYPE_NAPTR_ATTRIBUTES (0)
22 
23 #include <isc/regex.h>
24 
25 /*
26  * Check the wire format of the Regexp field.
27  * Don't allow embedded NUL's.
28  */
29 static isc_result_t
30 txt_valid_regex(const unsigned char *txt) {
31 	unsigned int nsub = 0;
32 	char regex[256];
33 	char *cp;
34 	bool flags = false;
35 	bool replace = false;
36 	unsigned char c;
37 	unsigned char delim;
38 	unsigned int len;
39 	int n;
40 
41 	len = *txt++;
42 	if (len == 0U) {
43 		return ISC_R_SUCCESS;
44 	}
45 
46 	delim = *txt++;
47 	len--;
48 
49 	/*
50 	 * Digits, backslash and flags can't be delimiters.
51 	 */
52 	switch (delim) {
53 	case '0':
54 	case '1':
55 	case '2':
56 	case '3':
57 	case '4':
58 	case '5':
59 	case '6':
60 	case '7':
61 	case '8':
62 	case '9':
63 	case '\\':
64 	case 'i':
65 	case 0:
66 		return DNS_R_SYNTAX;
67 	}
68 
69 	cp = regex;
70 	while (len-- > 0) {
71 		c = *txt++;
72 		if (c == 0) {
73 			return DNS_R_SYNTAX;
74 		}
75 		if (c == delim && !replace) {
76 			replace = true;
77 			continue;
78 		} else if (c == delim && !flags) {
79 			flags = true;
80 			continue;
81 		} else if (c == delim) {
82 			return DNS_R_SYNTAX;
83 		}
84 		/*
85 		 * Flags are not escaped.
86 		 */
87 		if (flags) {
88 			switch (c) {
89 			case 'i':
90 				continue;
91 			default:
92 				return DNS_R_SYNTAX;
93 			}
94 		}
95 		if (!replace) {
96 			*cp++ = c;
97 		}
98 		if (c == '\\') {
99 			if (len == 0) {
100 				return DNS_R_SYNTAX;
101 			}
102 			c = *txt++;
103 			if (c == 0) {
104 				return DNS_R_SYNTAX;
105 			}
106 			len--;
107 			if (replace) {
108 				switch (c) {
109 				case '0':
110 					return DNS_R_SYNTAX;
111 				case '1':
112 					if (nsub < 1) {
113 						nsub = 1;
114 					}
115 					break;
116 				case '2':
117 					if (nsub < 2) {
118 						nsub = 2;
119 					}
120 					break;
121 				case '3':
122 					if (nsub < 3) {
123 						nsub = 3;
124 					}
125 					break;
126 				case '4':
127 					if (nsub < 4) {
128 						nsub = 4;
129 					}
130 					break;
131 				case '5':
132 					if (nsub < 5) {
133 						nsub = 5;
134 					}
135 					break;
136 				case '6':
137 					if (nsub < 6) {
138 						nsub = 6;
139 					}
140 					break;
141 				case '7':
142 					if (nsub < 7) {
143 						nsub = 7;
144 					}
145 					break;
146 				case '8':
147 					if (nsub < 8) {
148 						nsub = 8;
149 					}
150 					break;
151 				case '9':
152 					if (nsub < 9) {
153 						nsub = 9;
154 					}
155 					break;
156 				}
157 			}
158 			if (!replace) {
159 				*cp++ = c;
160 			}
161 		}
162 	}
163 	if (!flags) {
164 		return DNS_R_SYNTAX;
165 	}
166 	*cp = '\0';
167 	n = isc_regex_validate(regex);
168 	if (n < 0 || nsub > (unsigned int)n) {
169 		return DNS_R_SYNTAX;
170 	}
171 	return ISC_R_SUCCESS;
172 }
173 
174 static isc_result_t
175 fromtext_naptr(ARGS_FROMTEXT) {
176 	isc_token_t token;
177 	dns_name_t name;
178 	isc_buffer_t buffer;
179 	unsigned char *regex;
180 
181 	REQUIRE(type == dns_rdatatype_naptr);
182 
183 	UNUSED(type);
184 	UNUSED(rdclass);
185 	UNUSED(callbacks);
186 
187 	/*
188 	 * Order.
189 	 */
190 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
191 				      false));
192 	if (token.value.as_ulong > 0xffffU) {
193 		RETTOK(ISC_R_RANGE);
194 	}
195 	RETERR(uint16_tobuffer(token.value.as_ulong, target));
196 
197 	/*
198 	 * Preference.
199 	 */
200 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
201 				      false));
202 	if (token.value.as_ulong > 0xffffU) {
203 		RETTOK(ISC_R_RANGE);
204 	}
205 	RETERR(uint16_tobuffer(token.value.as_ulong, target));
206 
207 	/*
208 	 * Flags.
209 	 */
210 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
211 				      false));
212 	RETTOK(txt_fromtext(&token.value.as_textregion, target));
213 
214 	/*
215 	 * Service.
216 	 */
217 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
218 				      false));
219 	RETTOK(txt_fromtext(&token.value.as_textregion, target));
220 
221 	/*
222 	 * Regexp.
223 	 */
224 	regex = isc_buffer_used(target);
225 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
226 				      false));
227 	RETTOK(txt_fromtext(&token.value.as_textregion, target));
228 	RETTOK(txt_valid_regex(regex));
229 
230 	/*
231 	 * Replacement.
232 	 */
233 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
234 				      false));
235 	dns_name_init(&name, NULL);
236 	buffer_fromregion(&buffer, &token.value.as_region);
237 	if (origin == NULL) {
238 		origin = dns_rootname;
239 	}
240 	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
241 	return ISC_R_SUCCESS;
242 }
243 
244 static isc_result_t
245 totext_naptr(ARGS_TOTEXT) {
246 	isc_region_t region;
247 	dns_name_t name;
248 	dns_name_t prefix;
249 	unsigned int opts;
250 	char buf[sizeof("64000")];
251 	unsigned short num;
252 
253 	REQUIRE(rdata->type == dns_rdatatype_naptr);
254 	REQUIRE(rdata->length != 0);
255 
256 	dns_name_init(&name, NULL);
257 	dns_name_init(&prefix, NULL);
258 
259 	dns_rdata_toregion(rdata, &region);
260 
261 	/*
262 	 * Order.
263 	 */
264 	num = uint16_fromregion(&region);
265 	isc_region_consume(&region, 2);
266 	snprintf(buf, sizeof(buf), "%u", num);
267 	RETERR(str_totext(buf, target));
268 	RETERR(str_totext(" ", target));
269 
270 	/*
271 	 * Preference.
272 	 */
273 	num = uint16_fromregion(&region);
274 	isc_region_consume(&region, 2);
275 	snprintf(buf, sizeof(buf), "%u", num);
276 	RETERR(str_totext(buf, target));
277 	RETERR(str_totext(" ", target));
278 
279 	/*
280 	 * Flags.
281 	 */
282 	RETERR(txt_totext(&region, true, target));
283 	RETERR(str_totext(" ", target));
284 
285 	/*
286 	 * Service.
287 	 */
288 	RETERR(txt_totext(&region, true, target));
289 	RETERR(str_totext(" ", target));
290 
291 	/*
292 	 * Regexp.
293 	 */
294 	RETERR(txt_totext(&region, true, target));
295 	RETERR(str_totext(" ", target));
296 
297 	/*
298 	 * Replacement.
299 	 */
300 	dns_name_fromregion(&name, &region);
301 	opts = name_prefix(&name, tctx->origin, &prefix) ? DNS_NAME_OMITFINALDOT
302 							 : 0;
303 	return dns_name_totext(&prefix, opts, target);
304 }
305 
306 static isc_result_t
307 fromwire_naptr(ARGS_FROMWIRE) {
308 	dns_name_t name;
309 	isc_region_t sr;
310 	unsigned char *regex;
311 
312 	REQUIRE(type == dns_rdatatype_naptr);
313 
314 	UNUSED(type);
315 	UNUSED(rdclass);
316 
317 	dctx = dns_decompress_setpermitted(dctx, false);
318 
319 	dns_name_init(&name, NULL);
320 
321 	/*
322 	 * Order, preference.
323 	 */
324 	isc_buffer_activeregion(source, &sr);
325 	if (sr.length < 4) {
326 		return ISC_R_UNEXPECTEDEND;
327 	}
328 	RETERR(mem_tobuffer(target, sr.base, 4));
329 	isc_buffer_forward(source, 4);
330 
331 	/*
332 	 * Flags.
333 	 */
334 	RETERR(txt_fromwire(source, target));
335 
336 	/*
337 	 * Service.
338 	 */
339 	RETERR(txt_fromwire(source, target));
340 
341 	/*
342 	 * Regexp.
343 	 */
344 	regex = isc_buffer_used(target);
345 	RETERR(txt_fromwire(source, target));
346 	RETERR(txt_valid_regex(regex));
347 
348 	/*
349 	 * Replacement.
350 	 */
351 	return dns_name_fromwire(&name, source, dctx, target);
352 }
353 
354 static isc_result_t
355 towire_naptr(ARGS_TOWIRE) {
356 	dns_name_t name;
357 	dns_offsets_t offsets;
358 	isc_region_t sr;
359 
360 	REQUIRE(rdata->type == dns_rdatatype_naptr);
361 	REQUIRE(rdata->length != 0);
362 
363 	dns_compress_setpermitted(cctx, false);
364 	/*
365 	 * Order, preference.
366 	 */
367 	dns_rdata_toregion(rdata, &sr);
368 	RETERR(mem_tobuffer(target, sr.base, 4));
369 	isc_region_consume(&sr, 4);
370 
371 	/*
372 	 * Flags.
373 	 */
374 	RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
375 	isc_region_consume(&sr, sr.base[0] + 1);
376 
377 	/*
378 	 * Service.
379 	 */
380 	RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
381 	isc_region_consume(&sr, sr.base[0] + 1);
382 
383 	/*
384 	 * Regexp.
385 	 */
386 	RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
387 	isc_region_consume(&sr, sr.base[0] + 1);
388 
389 	/*
390 	 * Replacement.
391 	 */
392 	dns_name_init(&name, offsets);
393 	dns_name_fromregion(&name, &sr);
394 	return dns_name_towire(&name, cctx, target, NULL);
395 }
396 
397 static int
398 compare_naptr(ARGS_COMPARE) {
399 	dns_name_t name1;
400 	dns_name_t name2;
401 	isc_region_t region1;
402 	isc_region_t region2;
403 	int order, len;
404 
405 	REQUIRE(rdata1->type == rdata2->type);
406 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
407 	REQUIRE(rdata1->type == dns_rdatatype_naptr);
408 	REQUIRE(rdata1->length != 0);
409 	REQUIRE(rdata2->length != 0);
410 
411 	dns_rdata_toregion(rdata1, &region1);
412 	dns_rdata_toregion(rdata2, &region2);
413 
414 	/*
415 	 * Order, preference.
416 	 */
417 	order = memcmp(region1.base, region2.base, 4);
418 	if (order != 0) {
419 		return order < 0 ? -1 : 1;
420 	}
421 	isc_region_consume(&region1, 4);
422 	isc_region_consume(&region2, 4);
423 
424 	/*
425 	 * Flags.
426 	 */
427 	len = ISC_MIN(region1.base[0], region2.base[0]);
428 	order = memcmp(region1.base, region2.base, len + 1);
429 	if (order != 0) {
430 		return order < 0 ? -1 : 1;
431 	}
432 	isc_region_consume(&region1, region1.base[0] + 1);
433 	isc_region_consume(&region2, region2.base[0] + 1);
434 
435 	/*
436 	 * Service.
437 	 */
438 	len = ISC_MIN(region1.base[0], region2.base[0]);
439 	order = memcmp(region1.base, region2.base, len + 1);
440 	if (order != 0) {
441 		return order < 0 ? -1 : 1;
442 	}
443 	isc_region_consume(&region1, region1.base[0] + 1);
444 	isc_region_consume(&region2, region2.base[0] + 1);
445 
446 	/*
447 	 * Regexp.
448 	 */
449 	len = ISC_MIN(region1.base[0], region2.base[0]);
450 	order = memcmp(region1.base, region2.base, len + 1);
451 	if (order != 0) {
452 		return order < 0 ? -1 : 1;
453 	}
454 	isc_region_consume(&region1, region1.base[0] + 1);
455 	isc_region_consume(&region2, region2.base[0] + 1);
456 
457 	/*
458 	 * Replacement.
459 	 */
460 	dns_name_init(&name1, NULL);
461 	dns_name_init(&name2, NULL);
462 
463 	dns_name_fromregion(&name1, &region1);
464 	dns_name_fromregion(&name2, &region2);
465 
466 	return dns_name_rdatacompare(&name1, &name2);
467 }
468 
469 static isc_result_t
470 fromstruct_naptr(ARGS_FROMSTRUCT) {
471 	dns_rdata_naptr_t *naptr = source;
472 	isc_region_t region;
473 
474 	REQUIRE(type == dns_rdatatype_naptr);
475 	REQUIRE(naptr != NULL);
476 	REQUIRE(naptr->common.rdtype == type);
477 	REQUIRE(naptr->common.rdclass == rdclass);
478 	REQUIRE(naptr->flags != NULL || naptr->flags_len == 0);
479 	REQUIRE(naptr->service != NULL || naptr->service_len == 0);
480 	REQUIRE(naptr->regexp != NULL || naptr->regexp_len == 0);
481 
482 	UNUSED(type);
483 	UNUSED(rdclass);
484 
485 	RETERR(uint16_tobuffer(naptr->order, target));
486 	RETERR(uint16_tobuffer(naptr->preference, target));
487 	RETERR(uint8_tobuffer(naptr->flags_len, target));
488 	RETERR(mem_tobuffer(target, naptr->flags, naptr->flags_len));
489 	RETERR(uint8_tobuffer(naptr->service_len, target));
490 	RETERR(mem_tobuffer(target, naptr->service, naptr->service_len));
491 	RETERR(uint8_tobuffer(naptr->regexp_len, target));
492 	RETERR(mem_tobuffer(target, naptr->regexp, naptr->regexp_len));
493 	dns_name_toregion(&naptr->replacement, &region);
494 	return isc_buffer_copyregion(target, &region);
495 }
496 
497 static isc_result_t
498 tostruct_naptr(ARGS_TOSTRUCT) {
499 	dns_rdata_naptr_t *naptr = target;
500 	isc_region_t r;
501 	dns_name_t name;
502 
503 	REQUIRE(rdata->type == dns_rdatatype_naptr);
504 	REQUIRE(naptr != NULL);
505 	REQUIRE(rdata->length != 0);
506 
507 	naptr->common.rdclass = rdata->rdclass;
508 	naptr->common.rdtype = rdata->type;
509 	ISC_LINK_INIT(&naptr->common, link);
510 
511 	naptr->flags = NULL;
512 	naptr->service = NULL;
513 	naptr->regexp = NULL;
514 
515 	dns_rdata_toregion(rdata, &r);
516 
517 	naptr->order = uint16_fromregion(&r);
518 	isc_region_consume(&r, 2);
519 
520 	naptr->preference = uint16_fromregion(&r);
521 	isc_region_consume(&r, 2);
522 
523 	naptr->flags_len = uint8_fromregion(&r);
524 	isc_region_consume(&r, 1);
525 	INSIST(naptr->flags_len <= r.length);
526 	naptr->flags = mem_maybedup(mctx, r.base, naptr->flags_len);
527 	isc_region_consume(&r, naptr->flags_len);
528 
529 	naptr->service_len = uint8_fromregion(&r);
530 	isc_region_consume(&r, 1);
531 	INSIST(naptr->service_len <= r.length);
532 	naptr->service = mem_maybedup(mctx, r.base, naptr->service_len);
533 	isc_region_consume(&r, naptr->service_len);
534 
535 	naptr->regexp_len = uint8_fromregion(&r);
536 	isc_region_consume(&r, 1);
537 	INSIST(naptr->regexp_len <= r.length);
538 	naptr->regexp = mem_maybedup(mctx, r.base, naptr->regexp_len);
539 	isc_region_consume(&r, naptr->regexp_len);
540 
541 	dns_name_init(&name, NULL);
542 	dns_name_fromregion(&name, &r);
543 	dns_name_init(&naptr->replacement, NULL);
544 	name_duporclone(&name, mctx, &naptr->replacement);
545 	naptr->mctx = mctx;
546 	return ISC_R_SUCCESS;
547 }
548 
549 static void
550 freestruct_naptr(ARGS_FREESTRUCT) {
551 	dns_rdata_naptr_t *naptr = source;
552 
553 	REQUIRE(naptr != NULL);
554 	REQUIRE(naptr->common.rdtype == dns_rdatatype_naptr);
555 
556 	if (naptr->mctx == NULL) {
557 		return;
558 	}
559 
560 	if (naptr->flags != NULL) {
561 		isc_mem_free(naptr->mctx, naptr->flags);
562 	}
563 	if (naptr->service != NULL) {
564 		isc_mem_free(naptr->mctx, naptr->service);
565 	}
566 	if (naptr->regexp != NULL) {
567 		isc_mem_free(naptr->mctx, naptr->regexp);
568 	}
569 	dns_name_free(&naptr->replacement, naptr->mctx);
570 	naptr->mctx = NULL;
571 }
572 
573 static isc_result_t
574 additionaldata_naptr(ARGS_ADDLDATA) {
575 	dns_name_t name;
576 	dns_offsets_t offsets;
577 	isc_region_t sr;
578 	dns_rdatatype_t atype;
579 	unsigned int i, flagslen;
580 	char *cp;
581 
582 	REQUIRE(rdata->type == dns_rdatatype_naptr);
583 
584 	UNUSED(owner);
585 
586 	/*
587 	 * Order, preference.
588 	 */
589 	dns_rdata_toregion(rdata, &sr);
590 	isc_region_consume(&sr, 4);
591 
592 	/*
593 	 * Flags.
594 	 */
595 	atype = 0;
596 	flagslen = sr.base[0];
597 	cp = (char *)&sr.base[1];
598 	for (i = 0; i < flagslen; i++, cp++) {
599 		if (*cp == 'S' || *cp == 's') {
600 			atype = dns_rdatatype_srv;
601 			break;
602 		}
603 		if (*cp == 'A' || *cp == 'a') {
604 			atype = dns_rdatatype_a;
605 			break;
606 		}
607 	}
608 	isc_region_consume(&sr, flagslen + 1);
609 
610 	/*
611 	 * Service.
612 	 */
613 	isc_region_consume(&sr, sr.base[0] + 1);
614 
615 	/*
616 	 * Regexp.
617 	 */
618 	isc_region_consume(&sr, sr.base[0] + 1);
619 
620 	/*
621 	 * Replacement.
622 	 */
623 	dns_name_init(&name, offsets);
624 	dns_name_fromregion(&name, &sr);
625 
626 	if (atype != 0) {
627 		return (add)(arg, &name, atype, NULL DNS__DB_FILELINE);
628 	}
629 
630 	return ISC_R_SUCCESS;
631 }
632 
633 static isc_result_t
634 digest_naptr(ARGS_DIGEST) {
635 	isc_region_t r1, r2;
636 	unsigned int length, n;
637 	isc_result_t result;
638 	dns_name_t name;
639 
640 	REQUIRE(rdata->type == dns_rdatatype_naptr);
641 
642 	dns_rdata_toregion(rdata, &r1);
643 	r2 = r1;
644 	length = 0;
645 
646 	/*
647 	 * Order, preference.
648 	 */
649 	length += 4;
650 	isc_region_consume(&r2, 4);
651 
652 	/*
653 	 * Flags.
654 	 */
655 	n = r2.base[0] + 1;
656 	length += n;
657 	isc_region_consume(&r2, n);
658 
659 	/*
660 	 * Service.
661 	 */
662 	n = r2.base[0] + 1;
663 	length += n;
664 	isc_region_consume(&r2, n);
665 
666 	/*
667 	 * Regexp.
668 	 */
669 	n = r2.base[0] + 1;
670 	length += n;
671 	isc_region_consume(&r2, n);
672 
673 	/*
674 	 * Digest the RR up to the replacement name.
675 	 */
676 	r1.length = length;
677 	result = (digest)(arg, &r1);
678 	if (result != ISC_R_SUCCESS) {
679 		return result;
680 	}
681 
682 	/*
683 	 * Replacement.
684 	 */
685 
686 	dns_name_init(&name, NULL);
687 	dns_name_fromregion(&name, &r2);
688 
689 	return dns_name_digest(&name, digest, arg);
690 }
691 
692 static bool
693 checkowner_naptr(ARGS_CHECKOWNER) {
694 	REQUIRE(type == dns_rdatatype_naptr);
695 
696 	UNUSED(name);
697 	UNUSED(type);
698 	UNUSED(rdclass);
699 	UNUSED(wildcard);
700 
701 	return true;
702 }
703 
704 static bool
705 checknames_naptr(ARGS_CHECKNAMES) {
706 	REQUIRE(rdata->type == dns_rdatatype_naptr);
707 
708 	UNUSED(rdata);
709 	UNUSED(owner);
710 	UNUSED(bad);
711 
712 	return true;
713 }
714 
715 static int
716 casecompare_naptr(ARGS_COMPARE) {
717 	return compare_naptr(rdata1, rdata2);
718 }
719 
720 #endif /* RDATA_GENERIC_NAPTR_35_C */
721