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