xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/generic/naptr_35.c (revision 70f7362772ba52b749c976fb5e86e39a8b2c9afc)
1 /*	$NetBSD: naptr_35.c,v 1.8 2024/02/21 22:52:13 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 	bool sub;
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 	sub = name_prefix(&name, tctx->origin, &prefix);
302 	return (dns_name_totext(&prefix, sub, target));
303 }
304 
305 static isc_result_t
306 fromwire_naptr(ARGS_FROMWIRE) {
307 	dns_name_t name;
308 	isc_region_t sr;
309 	unsigned char *regex;
310 
311 	REQUIRE(type == dns_rdatatype_naptr);
312 
313 	UNUSED(type);
314 	UNUSED(rdclass);
315 
316 	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
317 
318 	dns_name_init(&name, NULL);
319 
320 	/*
321 	 * Order, preference.
322 	 */
323 	isc_buffer_activeregion(source, &sr);
324 	if (sr.length < 4) {
325 		return (ISC_R_UNEXPECTEDEND);
326 	}
327 	RETERR(mem_tobuffer(target, sr.base, 4));
328 	isc_buffer_forward(source, 4);
329 
330 	/*
331 	 * Flags.
332 	 */
333 	RETERR(txt_fromwire(source, target));
334 
335 	/*
336 	 * Service.
337 	 */
338 	RETERR(txt_fromwire(source, target));
339 
340 	/*
341 	 * Regexp.
342 	 */
343 	regex = isc_buffer_used(target);
344 	RETERR(txt_fromwire(source, target));
345 	RETERR(txt_valid_regex(regex));
346 
347 	/*
348 	 * Replacement.
349 	 */
350 	return (dns_name_fromwire(&name, source, dctx, options, target));
351 }
352 
353 static isc_result_t
354 towire_naptr(ARGS_TOWIRE) {
355 	dns_name_t name;
356 	dns_offsets_t offsets;
357 	isc_region_t sr;
358 
359 	REQUIRE(rdata->type == dns_rdatatype_naptr);
360 	REQUIRE(rdata->length != 0);
361 
362 	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
363 	/*
364 	 * Order, preference.
365 	 */
366 	dns_rdata_toregion(rdata, &sr);
367 	RETERR(mem_tobuffer(target, sr.base, 4));
368 	isc_region_consume(&sr, 4);
369 
370 	/*
371 	 * Flags.
372 	 */
373 	RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
374 	isc_region_consume(&sr, sr.base[0] + 1);
375 
376 	/*
377 	 * Service.
378 	 */
379 	RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
380 	isc_region_consume(&sr, sr.base[0] + 1);
381 
382 	/*
383 	 * Regexp.
384 	 */
385 	RETERR(mem_tobuffer(target, sr.base, sr.base[0] + 1));
386 	isc_region_consume(&sr, sr.base[0] + 1);
387 
388 	/*
389 	 * Replacement.
390 	 */
391 	dns_name_init(&name, offsets);
392 	dns_name_fromregion(&name, &sr);
393 	return (dns_name_towire(&name, cctx, target));
394 }
395 
396 static int
397 compare_naptr(ARGS_COMPARE) {
398 	dns_name_t name1;
399 	dns_name_t name2;
400 	isc_region_t region1;
401 	isc_region_t region2;
402 	int order, len;
403 
404 	REQUIRE(rdata1->type == rdata2->type);
405 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
406 	REQUIRE(rdata1->type == dns_rdatatype_naptr);
407 	REQUIRE(rdata1->length != 0);
408 	REQUIRE(rdata2->length != 0);
409 
410 	dns_rdata_toregion(rdata1, &region1);
411 	dns_rdata_toregion(rdata2, &region2);
412 
413 	/*
414 	 * Order, preference.
415 	 */
416 	order = memcmp(region1.base, region2.base, 4);
417 	if (order != 0) {
418 		return (order < 0 ? -1 : 1);
419 	}
420 	isc_region_consume(&region1, 4);
421 	isc_region_consume(&region2, 4);
422 
423 	/*
424 	 * Flags.
425 	 */
426 	len = ISC_MIN(region1.base[0], region2.base[0]);
427 	order = memcmp(region1.base, region2.base, len + 1);
428 	if (order != 0) {
429 		return (order < 0 ? -1 : 1);
430 	}
431 	isc_region_consume(&region1, region1.base[0] + 1);
432 	isc_region_consume(&region2, region2.base[0] + 1);
433 
434 	/*
435 	 * Service.
436 	 */
437 	len = ISC_MIN(region1.base[0], region2.base[0]);
438 	order = memcmp(region1.base, region2.base, len + 1);
439 	if (order != 0) {
440 		return (order < 0 ? -1 : 1);
441 	}
442 	isc_region_consume(&region1, region1.base[0] + 1);
443 	isc_region_consume(&region2, region2.base[0] + 1);
444 
445 	/*
446 	 * Regexp.
447 	 */
448 	len = ISC_MIN(region1.base[0], region2.base[0]);
449 	order = memcmp(region1.base, region2.base, len + 1);
450 	if (order != 0) {
451 		return (order < 0 ? -1 : 1);
452 	}
453 	isc_region_consume(&region1, region1.base[0] + 1);
454 	isc_region_consume(&region2, region2.base[0] + 1);
455 
456 	/*
457 	 * Replacement.
458 	 */
459 	dns_name_init(&name1, NULL);
460 	dns_name_init(&name2, NULL);
461 
462 	dns_name_fromregion(&name1, &region1);
463 	dns_name_fromregion(&name2, &region2);
464 
465 	return (dns_name_rdatacompare(&name1, &name2));
466 }
467 
468 static isc_result_t
469 fromstruct_naptr(ARGS_FROMSTRUCT) {
470 	dns_rdata_naptr_t *naptr = source;
471 	isc_region_t region;
472 
473 	REQUIRE(type == dns_rdatatype_naptr);
474 	REQUIRE(naptr != NULL);
475 	REQUIRE(naptr->common.rdtype == type);
476 	REQUIRE(naptr->common.rdclass == rdclass);
477 	REQUIRE(naptr->flags != NULL || naptr->flags_len == 0);
478 	REQUIRE(naptr->service != NULL || naptr->service_len == 0);
479 	REQUIRE(naptr->regexp != NULL || naptr->regexp_len == 0);
480 
481 	UNUSED(type);
482 	UNUSED(rdclass);
483 
484 	RETERR(uint16_tobuffer(naptr->order, target));
485 	RETERR(uint16_tobuffer(naptr->preference, target));
486 	RETERR(uint8_tobuffer(naptr->flags_len, target));
487 	RETERR(mem_tobuffer(target, naptr->flags, naptr->flags_len));
488 	RETERR(uint8_tobuffer(naptr->service_len, target));
489 	RETERR(mem_tobuffer(target, naptr->service, naptr->service_len));
490 	RETERR(uint8_tobuffer(naptr->regexp_len, target));
491 	RETERR(mem_tobuffer(target, naptr->regexp, naptr->regexp_len));
492 	dns_name_toregion(&naptr->replacement, &region);
493 	return (isc_buffer_copyregion(target, &region));
494 }
495 
496 static isc_result_t
497 tostruct_naptr(ARGS_TOSTRUCT) {
498 	dns_rdata_naptr_t *naptr = target;
499 	isc_region_t r;
500 	dns_name_t name;
501 
502 	REQUIRE(rdata->type == dns_rdatatype_naptr);
503 	REQUIRE(naptr != NULL);
504 	REQUIRE(rdata->length != 0);
505 
506 	naptr->common.rdclass = rdata->rdclass;
507 	naptr->common.rdtype = rdata->type;
508 	ISC_LINK_INIT(&naptr->common, link);
509 
510 	naptr->flags = NULL;
511 	naptr->service = NULL;
512 	naptr->regexp = NULL;
513 
514 	dns_rdata_toregion(rdata, &r);
515 
516 	naptr->order = uint16_fromregion(&r);
517 	isc_region_consume(&r, 2);
518 
519 	naptr->preference = uint16_fromregion(&r);
520 	isc_region_consume(&r, 2);
521 
522 	naptr->flags_len = uint8_fromregion(&r);
523 	isc_region_consume(&r, 1);
524 	INSIST(naptr->flags_len <= r.length);
525 	naptr->flags = mem_maybedup(mctx, r.base, naptr->flags_len);
526 	if (naptr->flags == NULL) {
527 		goto cleanup;
528 	}
529 	isc_region_consume(&r, naptr->flags_len);
530 
531 	naptr->service_len = uint8_fromregion(&r);
532 	isc_region_consume(&r, 1);
533 	INSIST(naptr->service_len <= r.length);
534 	naptr->service = mem_maybedup(mctx, r.base, naptr->service_len);
535 	if (naptr->service == NULL) {
536 		goto cleanup;
537 	}
538 	isc_region_consume(&r, naptr->service_len);
539 
540 	naptr->regexp_len = uint8_fromregion(&r);
541 	isc_region_consume(&r, 1);
542 	INSIST(naptr->regexp_len <= r.length);
543 	naptr->regexp = mem_maybedup(mctx, r.base, naptr->regexp_len);
544 	if (naptr->regexp == NULL) {
545 		goto cleanup;
546 	}
547 	isc_region_consume(&r, naptr->regexp_len);
548 
549 	dns_name_init(&name, NULL);
550 	dns_name_fromregion(&name, &r);
551 	dns_name_init(&naptr->replacement, NULL);
552 	name_duporclone(&name, mctx, &naptr->replacement);
553 	naptr->mctx = mctx;
554 	return (ISC_R_SUCCESS);
555 
556 cleanup:
557 	if (mctx != NULL && naptr->flags != NULL) {
558 		isc_mem_free(mctx, naptr->flags);
559 	}
560 	if (mctx != NULL && naptr->service != NULL) {
561 		isc_mem_free(mctx, naptr->service);
562 	}
563 	if (mctx != NULL && naptr->regexp != NULL) {
564 		isc_mem_free(mctx, naptr->regexp);
565 	}
566 	return (ISC_R_NOMEMORY);
567 }
568 
569 static void
570 freestruct_naptr(ARGS_FREESTRUCT) {
571 	dns_rdata_naptr_t *naptr = source;
572 
573 	REQUIRE(naptr != NULL);
574 	REQUIRE(naptr->common.rdtype == dns_rdatatype_naptr);
575 
576 	if (naptr->mctx == NULL) {
577 		return;
578 	}
579 
580 	if (naptr->flags != NULL) {
581 		isc_mem_free(naptr->mctx, naptr->flags);
582 	}
583 	if (naptr->service != NULL) {
584 		isc_mem_free(naptr->mctx, naptr->service);
585 	}
586 	if (naptr->regexp != NULL) {
587 		isc_mem_free(naptr->mctx, naptr->regexp);
588 	}
589 	dns_name_free(&naptr->replacement, naptr->mctx);
590 	naptr->mctx = NULL;
591 }
592 
593 static isc_result_t
594 additionaldata_naptr(ARGS_ADDLDATA) {
595 	dns_name_t name;
596 	dns_offsets_t offsets;
597 	isc_region_t sr;
598 	dns_rdatatype_t atype;
599 	unsigned int i, flagslen;
600 	char *cp;
601 
602 	REQUIRE(rdata->type == dns_rdatatype_naptr);
603 
604 	UNUSED(owner);
605 
606 	/*
607 	 * Order, preference.
608 	 */
609 	dns_rdata_toregion(rdata, &sr);
610 	isc_region_consume(&sr, 4);
611 
612 	/*
613 	 * Flags.
614 	 */
615 	atype = 0;
616 	flagslen = sr.base[0];
617 	cp = (char *)&sr.base[1];
618 	for (i = 0; i < flagslen; i++, cp++) {
619 		if (*cp == 'S' || *cp == 's') {
620 			atype = dns_rdatatype_srv;
621 			break;
622 		}
623 		if (*cp == 'A' || *cp == 'a') {
624 			atype = dns_rdatatype_a;
625 			break;
626 		}
627 	}
628 	isc_region_consume(&sr, flagslen + 1);
629 
630 	/*
631 	 * Service.
632 	 */
633 	isc_region_consume(&sr, sr.base[0] + 1);
634 
635 	/*
636 	 * Regexp.
637 	 */
638 	isc_region_consume(&sr, sr.base[0] + 1);
639 
640 	/*
641 	 * Replacement.
642 	 */
643 	dns_name_init(&name, offsets);
644 	dns_name_fromregion(&name, &sr);
645 
646 	if (atype != 0) {
647 		return ((add)(arg, &name, atype, NULL));
648 	}
649 
650 	return (ISC_R_SUCCESS);
651 }
652 
653 static isc_result_t
654 digest_naptr(ARGS_DIGEST) {
655 	isc_region_t r1, r2;
656 	unsigned int length, n;
657 	isc_result_t result;
658 	dns_name_t name;
659 
660 	REQUIRE(rdata->type == dns_rdatatype_naptr);
661 
662 	dns_rdata_toregion(rdata, &r1);
663 	r2 = r1;
664 	length = 0;
665 
666 	/*
667 	 * Order, preference.
668 	 */
669 	length += 4;
670 	isc_region_consume(&r2, 4);
671 
672 	/*
673 	 * Flags.
674 	 */
675 	n = r2.base[0] + 1;
676 	length += n;
677 	isc_region_consume(&r2, n);
678 
679 	/*
680 	 * Service.
681 	 */
682 	n = r2.base[0] + 1;
683 	length += n;
684 	isc_region_consume(&r2, n);
685 
686 	/*
687 	 * Regexp.
688 	 */
689 	n = r2.base[0] + 1;
690 	length += n;
691 	isc_region_consume(&r2, n);
692 
693 	/*
694 	 * Digest the RR up to the replacement name.
695 	 */
696 	r1.length = length;
697 	result = (digest)(arg, &r1);
698 	if (result != ISC_R_SUCCESS) {
699 		return (result);
700 	}
701 
702 	/*
703 	 * Replacement.
704 	 */
705 
706 	dns_name_init(&name, NULL);
707 	dns_name_fromregion(&name, &r2);
708 
709 	return (dns_name_digest(&name, digest, arg));
710 }
711 
712 static bool
713 checkowner_naptr(ARGS_CHECKOWNER) {
714 	REQUIRE(type == dns_rdatatype_naptr);
715 
716 	UNUSED(name);
717 	UNUSED(type);
718 	UNUSED(rdclass);
719 	UNUSED(wildcard);
720 
721 	return (true);
722 }
723 
724 static bool
725 checknames_naptr(ARGS_CHECKNAMES) {
726 	REQUIRE(rdata->type == dns_rdatatype_naptr);
727 
728 	UNUSED(rdata);
729 	UNUSED(owner);
730 	UNUSED(bad);
731 
732 	return (true);
733 }
734 
735 static int
736 casecompare_naptr(ARGS_COMPARE) {
737 	return (compare_naptr(rdata1, rdata2));
738 }
739 
740 #endif /* RDATA_GENERIC_NAPTR_35_C */
741