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