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