1 /* $NetBSD: naptr_35.c,v 1.7 2022/09/23 12:15:31 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
txt_valid_regex(const unsigned char * txt)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
fromtext_naptr(ARGS_FROMTEXT)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
totext_naptr(ARGS_TOTEXT)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, ®ion);
260
261 /*
262 * Order.
263 */
264 num = uint16_fromregion(®ion);
265 isc_region_consume(®ion, 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(®ion);
274 isc_region_consume(®ion, 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(®ion, true, target));
283 RETERR(str_totext(" ", target));
284
285 /*
286 * Service.
287 */
288 RETERR(txt_totext(®ion, true, target));
289 RETERR(str_totext(" ", target));
290
291 /*
292 * Regexp.
293 */
294 RETERR(txt_totext(®ion, true, target));
295 RETERR(str_totext(" ", target));
296
297 /*
298 * Replacement.
299 */
300 dns_name_fromregion(&name, ®ion);
301 sub = name_prefix(&name, tctx->origin, &prefix);
302 return (dns_name_totext(&prefix, sub, target));
303 }
304
305 static isc_result_t
fromwire_naptr(ARGS_FROMWIRE)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
towire_naptr(ARGS_TOWIRE)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
compare_naptr(ARGS_COMPARE)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, ®ion1);
411 dns_rdata_toregion(rdata2, ®ion2);
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(®ion1, 4);
421 isc_region_consume(®ion2, 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(®ion1, region1.base[0] + 1);
432 isc_region_consume(®ion2, 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(®ion1, region1.base[0] + 1);
443 isc_region_consume(®ion2, 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(®ion1, region1.base[0] + 1);
454 isc_region_consume(®ion2, 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, ®ion1);
463 dns_name_fromregion(&name2, ®ion2);
464
465 return (dns_name_rdatacompare(&name1, &name2));
466 }
467
468 static isc_result_t
fromstruct_naptr(ARGS_FROMSTRUCT)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, ®ion);
493 return (isc_buffer_copyregion(target, ®ion));
494 }
495
496 static isc_result_t
tostruct_naptr(ARGS_TOSTRUCT)497 tostruct_naptr(ARGS_TOSTRUCT) {
498 dns_rdata_naptr_t *naptr = target;
499 isc_region_t r;
500 isc_result_t result;
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 if (naptr->flags == NULL) {
528 goto cleanup;
529 }
530 isc_region_consume(&r, naptr->flags_len);
531
532 naptr->service_len = uint8_fromregion(&r);
533 isc_region_consume(&r, 1);
534 INSIST(naptr->service_len <= r.length);
535 naptr->service = mem_maybedup(mctx, r.base, naptr->service_len);
536 if (naptr->service == NULL) {
537 goto cleanup;
538 }
539 isc_region_consume(&r, naptr->service_len);
540
541 naptr->regexp_len = uint8_fromregion(&r);
542 isc_region_consume(&r, 1);
543 INSIST(naptr->regexp_len <= r.length);
544 naptr->regexp = mem_maybedup(mctx, r.base, naptr->regexp_len);
545 if (naptr->regexp == NULL) {
546 goto cleanup;
547 }
548 isc_region_consume(&r, naptr->regexp_len);
549
550 dns_name_init(&name, NULL);
551 dns_name_fromregion(&name, &r);
552 dns_name_init(&naptr->replacement, NULL);
553 result = name_duporclone(&name, mctx, &naptr->replacement);
554 if (result != ISC_R_SUCCESS) {
555 goto cleanup;
556 }
557 naptr->mctx = mctx;
558 return (ISC_R_SUCCESS);
559
560 cleanup:
561 if (mctx != NULL && naptr->flags != NULL) {
562 isc_mem_free(mctx, naptr->flags);
563 }
564 if (mctx != NULL && naptr->service != NULL) {
565 isc_mem_free(mctx, naptr->service);
566 }
567 if (mctx != NULL && naptr->regexp != NULL) {
568 isc_mem_free(mctx, naptr->regexp);
569 }
570 return (ISC_R_NOMEMORY);
571 }
572
573 static void
freestruct_naptr(ARGS_FREESTRUCT)574 freestruct_naptr(ARGS_FREESTRUCT) {
575 dns_rdata_naptr_t *naptr = source;
576
577 REQUIRE(naptr != NULL);
578 REQUIRE(naptr->common.rdtype == dns_rdatatype_naptr);
579
580 if (naptr->mctx == NULL) {
581 return;
582 }
583
584 if (naptr->flags != NULL) {
585 isc_mem_free(naptr->mctx, naptr->flags);
586 }
587 if (naptr->service != NULL) {
588 isc_mem_free(naptr->mctx, naptr->service);
589 }
590 if (naptr->regexp != NULL) {
591 isc_mem_free(naptr->mctx, naptr->regexp);
592 }
593 dns_name_free(&naptr->replacement, naptr->mctx);
594 naptr->mctx = NULL;
595 }
596
597 static isc_result_t
additionaldata_naptr(ARGS_ADDLDATA)598 additionaldata_naptr(ARGS_ADDLDATA) {
599 dns_name_t name;
600 dns_offsets_t offsets;
601 isc_region_t sr;
602 dns_rdatatype_t atype;
603 unsigned int i, flagslen;
604 char *cp;
605
606 REQUIRE(rdata->type == dns_rdatatype_naptr);
607
608 /*
609 * Order, preference.
610 */
611 dns_rdata_toregion(rdata, &sr);
612 isc_region_consume(&sr, 4);
613
614 /*
615 * Flags.
616 */
617 atype = 0;
618 flagslen = sr.base[0];
619 cp = (char *)&sr.base[1];
620 for (i = 0; i < flagslen; i++, cp++) {
621 if (*cp == 'S' || *cp == 's') {
622 atype = dns_rdatatype_srv;
623 break;
624 }
625 if (*cp == 'A' || *cp == 'a') {
626 atype = dns_rdatatype_a;
627 break;
628 }
629 }
630 isc_region_consume(&sr, flagslen + 1);
631
632 /*
633 * Service.
634 */
635 isc_region_consume(&sr, sr.base[0] + 1);
636
637 /*
638 * Regexp.
639 */
640 isc_region_consume(&sr, sr.base[0] + 1);
641
642 /*
643 * Replacement.
644 */
645 dns_name_init(&name, offsets);
646 dns_name_fromregion(&name, &sr);
647
648 if (atype != 0) {
649 return ((add)(arg, &name, atype));
650 }
651
652 return (ISC_R_SUCCESS);
653 }
654
655 static isc_result_t
digest_naptr(ARGS_DIGEST)656 digest_naptr(ARGS_DIGEST) {
657 isc_region_t r1, r2;
658 unsigned int length, n;
659 isc_result_t result;
660 dns_name_t name;
661
662 REQUIRE(rdata->type == dns_rdatatype_naptr);
663
664 dns_rdata_toregion(rdata, &r1);
665 r2 = r1;
666 length = 0;
667
668 /*
669 * Order, preference.
670 */
671 length += 4;
672 isc_region_consume(&r2, 4);
673
674 /*
675 * Flags.
676 */
677 n = r2.base[0] + 1;
678 length += n;
679 isc_region_consume(&r2, n);
680
681 /*
682 * Service.
683 */
684 n = r2.base[0] + 1;
685 length += n;
686 isc_region_consume(&r2, n);
687
688 /*
689 * Regexp.
690 */
691 n = r2.base[0] + 1;
692 length += n;
693 isc_region_consume(&r2, n);
694
695 /*
696 * Digest the RR up to the replacement name.
697 */
698 r1.length = length;
699 result = (digest)(arg, &r1);
700 if (result != ISC_R_SUCCESS) {
701 return (result);
702 }
703
704 /*
705 * Replacement.
706 */
707
708 dns_name_init(&name, NULL);
709 dns_name_fromregion(&name, &r2);
710
711 return (dns_name_digest(&name, digest, arg));
712 }
713
714 static bool
checkowner_naptr(ARGS_CHECKOWNER)715 checkowner_naptr(ARGS_CHECKOWNER) {
716 REQUIRE(type == dns_rdatatype_naptr);
717
718 UNUSED(name);
719 UNUSED(type);
720 UNUSED(rdclass);
721 UNUSED(wildcard);
722
723 return (true);
724 }
725
726 static bool
checknames_naptr(ARGS_CHECKNAMES)727 checknames_naptr(ARGS_CHECKNAMES) {
728 REQUIRE(rdata->type == dns_rdatatype_naptr);
729
730 UNUSED(rdata);
731 UNUSED(owner);
732 UNUSED(bad);
733
734 return (true);
735 }
736
737 static int
casecompare_naptr(ARGS_COMPARE)738 casecompare_naptr(ARGS_COMPARE) {
739 return (compare_naptr(rdata1, rdata2));
740 }
741
742 #endif /* RDATA_GENERIC_NAPTR_35_C */
743