1135446Strhodes/*
2224092Sdougb * Copyright (C) 2004, 2007-2009, 2011  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2003  Internet Software Consortium.
4135446Strhodes *
5186462Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: nsec_47.c,v 1.15 2011/01/13 04:59:26 tbox Exp $ */
19135446Strhodes
20135446Strhodes/* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */
21135446Strhodes
22186462Sdougb/* RFC 3845 */
23135446Strhodes
24135446Strhodes#ifndef RDATA_GENERIC_NSEC_47_C
25135446Strhodes#define RDATA_GENERIC_NSEC_47_C
26135446Strhodes
27135446Strhodes/*
28135446Strhodes * The attributes do not include DNS_RDATATYPEATTR_SINGLETON
29135446Strhodes * because we must be able to handle a parent/child NSEC pair.
30135446Strhodes */
31135446Strhodes#define RRTYPE_NSEC_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC)
32135446Strhodes
33135446Strhodesstatic inline isc_result_t
34135446Strhodesfromtext_nsec(ARGS_FROMTEXT) {
35135446Strhodes	isc_token_t token;
36135446Strhodes	dns_name_t name;
37135446Strhodes	isc_buffer_t buffer;
38135446Strhodes	unsigned char bm[8*1024]; /* 64k bits */
39135446Strhodes	dns_rdatatype_t covered;
40135446Strhodes	int octet;
41135446Strhodes	int window;
42135446Strhodes
43135446Strhodes	REQUIRE(type == 47);
44135446Strhodes
45135446Strhodes	UNUSED(type);
46135446Strhodes	UNUSED(rdclass);
47135446Strhodes	UNUSED(callbacks);
48135446Strhodes
49135446Strhodes	/*
50135446Strhodes	 * Next domain.
51135446Strhodes	 */
52135446Strhodes	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
53135446Strhodes				      ISC_FALSE));
54135446Strhodes	dns_name_init(&name, NULL);
55135446Strhodes	buffer_fromregion(&buffer, &token.value.as_region);
56135446Strhodes	origin = (origin != NULL) ? origin : dns_rootname;
57135446Strhodes	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
58135446Strhodes
59135446Strhodes	memset(bm, 0, sizeof(bm));
60135446Strhodes	do {
61135446Strhodes		RETERR(isc_lex_getmastertoken(lexer, &token,
62135446Strhodes					      isc_tokentype_string, ISC_TRUE));
63135446Strhodes		if (token.type != isc_tokentype_string)
64135446Strhodes			break;
65135446Strhodes		RETTOK(dns_rdatatype_fromtext(&covered,
66135446Strhodes					      &token.value.as_textregion));
67135446Strhodes		bm[covered/8] |= (0x80>>(covered%8));
68135446Strhodes	} while (1);
69135446Strhodes	isc_lex_ungettoken(lexer, &token);
70135446Strhodes	for (window = 0; window < 256 ; window++) {
71135446Strhodes		/*
72135446Strhodes		 * Find if we have a type in this window.
73135446Strhodes		 */
74135446Strhodes		for (octet = 31; octet >= 0; octet--)
75135446Strhodes			if (bm[window * 32 + octet] != 0)
76135446Strhodes				break;
77135446Strhodes		if (octet < 0)
78135446Strhodes			continue;
79135446Strhodes		RETERR(uint8_tobuffer(window, target));
80135446Strhodes		RETERR(uint8_tobuffer(octet + 1, target));
81135446Strhodes		RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
82135446Strhodes	}
83135446Strhodes	return (ISC_R_SUCCESS);
84135446Strhodes}
85135446Strhodes
86135446Strhodesstatic inline isc_result_t
87135446Strhodestotext_nsec(ARGS_TOTEXT) {
88135446Strhodes	isc_region_t sr;
89135446Strhodes	unsigned int i, j, k;
90135446Strhodes	dns_name_t name;
91135446Strhodes	unsigned int window, len;
92135446Strhodes
93135446Strhodes	REQUIRE(rdata->type == 47);
94135446Strhodes	REQUIRE(rdata->length != 0);
95135446Strhodes
96218384Sdougb	UNUSED(tctx);
97218384Sdougb
98135446Strhodes	dns_name_init(&name, NULL);
99135446Strhodes	dns_rdata_toregion(rdata, &sr);
100135446Strhodes	dns_name_fromregion(&name, &sr);
101135446Strhodes	isc_region_consume(&sr, name_length(&name));
102218384Sdougb	RETERR(dns_name_totext(&name, ISC_FALSE, target));
103135446Strhodes
104135446Strhodes
105135446Strhodes	for (i = 0; i < sr.length; i += len) {
106135446Strhodes		INSIST(i + 2 <= sr.length);
107135446Strhodes		window = sr.base[i];
108135446Strhodes		len = sr.base[i + 1];
109135446Strhodes		INSIST(len > 0 && len <= 32);
110135446Strhodes		i += 2;
111135446Strhodes		INSIST(i + len <= sr.length);
112135446Strhodes		for (j = 0; j < len; j++) {
113135446Strhodes			dns_rdatatype_t t;
114135446Strhodes			if (sr.base[i + j] == 0)
115135446Strhodes				continue;
116135446Strhodes			for (k = 0; k < 8; k++) {
117135446Strhodes				if ((sr.base[i + j] & (0x80 >> k)) == 0)
118135446Strhodes					continue;
119135446Strhodes				t = window * 256 + j * 8 + k;
120135446Strhodes				RETERR(str_totext(" ", target));
121135446Strhodes				if (dns_rdatatype_isknown(t)) {
122135446Strhodes					RETERR(dns_rdatatype_totext(t, target));
123135446Strhodes				} else {
124135446Strhodes					char buf[sizeof("TYPE65535")];
125135446Strhodes					sprintf(buf, "TYPE%u", t);
126135446Strhodes					RETERR(str_totext(buf, target));
127135446Strhodes				}
128135446Strhodes			}
129135446Strhodes		}
130135446Strhodes	}
131135446Strhodes	return (ISC_R_SUCCESS);
132135446Strhodes}
133135446Strhodes
134135446Strhodesstatic /* inline */ isc_result_t
135135446Strhodesfromwire_nsec(ARGS_FROMWIRE) {
136135446Strhodes	isc_region_t sr;
137135446Strhodes	dns_name_t name;
138135446Strhodes	unsigned int window, lastwindow = 0;
139135446Strhodes	unsigned int len;
140135446Strhodes	isc_boolean_t first = ISC_TRUE;
141135446Strhodes	unsigned int i;
142135446Strhodes
143135446Strhodes	REQUIRE(type == 47);
144135446Strhodes
145135446Strhodes	UNUSED(type);
146135446Strhodes	UNUSED(rdclass);
147135446Strhodes
148135446Strhodes	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
149135446Strhodes
150135446Strhodes	dns_name_init(&name, NULL);
151135446Strhodes	RETERR(dns_name_fromwire(&name, source, dctx, options, target));
152135446Strhodes
153135446Strhodes	isc_buffer_activeregion(source, &sr);
154135446Strhodes	for (i = 0; i < sr.length; i += len) {
155135446Strhodes		/*
156135446Strhodes		 * Check for overflow.
157135446Strhodes		 */
158135446Strhodes		if (i + 2 > sr.length)
159135446Strhodes			RETERR(DNS_R_FORMERR);
160135446Strhodes		window = sr.base[i];
161135446Strhodes		len = sr.base[i + 1];
162135446Strhodes		i += 2;
163135446Strhodes		/*
164135446Strhodes		 * Check that bitmap windows are in the correct order.
165135446Strhodes		 */
166135446Strhodes		if (!first && window <= lastwindow)
167135446Strhodes			RETERR(DNS_R_FORMERR);
168135446Strhodes		/*
169135446Strhodes		 * Check for legal lengths.
170135446Strhodes		 */
171135446Strhodes		if (len < 1 || len > 32)
172135446Strhodes			RETERR(DNS_R_FORMERR);
173135446Strhodes		/*
174135446Strhodes		 * Check for overflow.
175135446Strhodes		 */
176135446Strhodes		if (i + len > sr.length)
177135446Strhodes			RETERR(DNS_R_FORMERR);
178135446Strhodes		/*
179135446Strhodes		 * The last octet of the bitmap must be non zero.
180135446Strhodes		 */
181135446Strhodes		if (sr.base[i + len - 1] == 0)
182135446Strhodes			RETERR(DNS_R_FORMERR);
183135446Strhodes		lastwindow = window;
184135446Strhodes		first = ISC_FALSE;
185135446Strhodes	}
186135446Strhodes	if (i != sr.length)
187135446Strhodes		return (DNS_R_EXTRADATA);
188135446Strhodes	if (first)
189135446Strhodes		RETERR(DNS_R_FORMERR);
190135446Strhodes	RETERR(mem_tobuffer(target, sr.base, sr.length));
191135446Strhodes	isc_buffer_forward(source, sr.length);
192135446Strhodes	return (ISC_R_SUCCESS);
193135446Strhodes}
194135446Strhodes
195135446Strhodesstatic inline isc_result_t
196135446Strhodestowire_nsec(ARGS_TOWIRE) {
197135446Strhodes	isc_region_t sr;
198135446Strhodes	dns_name_t name;
199135446Strhodes	dns_offsets_t offsets;
200135446Strhodes
201135446Strhodes	REQUIRE(rdata->type == 47);
202135446Strhodes	REQUIRE(rdata->length != 0);
203135446Strhodes
204135446Strhodes	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
205135446Strhodes	dns_name_init(&name, offsets);
206135446Strhodes	dns_rdata_toregion(rdata, &sr);
207135446Strhodes	dns_name_fromregion(&name, &sr);
208135446Strhodes	isc_region_consume(&sr, name_length(&name));
209135446Strhodes	RETERR(dns_name_towire(&name, cctx, target));
210135446Strhodes
211135446Strhodes	return (mem_tobuffer(target, sr.base, sr.length));
212135446Strhodes}
213135446Strhodes
214135446Strhodesstatic inline int
215135446Strhodescompare_nsec(ARGS_COMPARE) {
216135446Strhodes	isc_region_t r1;
217135446Strhodes	isc_region_t r2;
218135446Strhodes
219135446Strhodes	REQUIRE(rdata1->type == rdata2->type);
220135446Strhodes	REQUIRE(rdata1->rdclass == rdata2->rdclass);
221135446Strhodes	REQUIRE(rdata1->type == 47);
222135446Strhodes	REQUIRE(rdata1->length != 0);
223135446Strhodes	REQUIRE(rdata2->length != 0);
224135446Strhodes
225135446Strhodes	dns_rdata_toregion(rdata1, &r1);
226135446Strhodes	dns_rdata_toregion(rdata2, &r2);
227135446Strhodes	return (isc_region_compare(&r1, &r2));
228135446Strhodes}
229135446Strhodes
230135446Strhodesstatic inline isc_result_t
231135446Strhodesfromstruct_nsec(ARGS_FROMSTRUCT) {
232135446Strhodes	dns_rdata_nsec_t *nsec = source;
233135446Strhodes	isc_region_t region;
234135446Strhodes	unsigned int i, len, window, lastwindow = 0;
235135446Strhodes	isc_boolean_t first = ISC_TRUE;
236135446Strhodes
237135446Strhodes	REQUIRE(type == 47);
238135446Strhodes	REQUIRE(source != NULL);
239135446Strhodes	REQUIRE(nsec->common.rdtype == type);
240135446Strhodes	REQUIRE(nsec->common.rdclass == rdclass);
241135446Strhodes	REQUIRE(nsec->typebits != NULL || nsec->len == 0);
242135446Strhodes
243135446Strhodes	UNUSED(type);
244135446Strhodes	UNUSED(rdclass);
245135446Strhodes
246135446Strhodes	dns_name_toregion(&nsec->next, &region);
247135446Strhodes	RETERR(isc_buffer_copyregion(target, &region));
248135446Strhodes	/*
249135446Strhodes	 * Perform sanity check.
250135446Strhodes	 */
251135446Strhodes	for (i = 0; i < nsec->len ; i += len) {
252135446Strhodes		INSIST(i + 2 <= nsec->len);
253135446Strhodes		window = nsec->typebits[i];
254135446Strhodes		len = nsec->typebits[i+1];
255135446Strhodes		i += 2;
256186462Sdougb		INSIST(first || window > lastwindow);
257135446Strhodes		INSIST(len > 0 && len <= 32);
258135446Strhodes		INSIST(i + len <= nsec->len);
259135446Strhodes		INSIST(nsec->typebits[i + len - 1] != 0);
260135446Strhodes		lastwindow = window;
261135446Strhodes		first = ISC_FALSE;
262135446Strhodes	}
263135446Strhodes	INSIST(!first);
264135446Strhodes	return (mem_tobuffer(target, nsec->typebits, nsec->len));
265135446Strhodes}
266135446Strhodes
267135446Strhodesstatic inline isc_result_t
268135446Strhodestostruct_nsec(ARGS_TOSTRUCT) {
269135446Strhodes	isc_region_t region;
270135446Strhodes	dns_rdata_nsec_t *nsec = target;
271135446Strhodes	dns_name_t name;
272135446Strhodes
273135446Strhodes	REQUIRE(rdata->type == 47);
274135446Strhodes	REQUIRE(target != NULL);
275135446Strhodes	REQUIRE(rdata->length != 0);
276135446Strhodes
277135446Strhodes	nsec->common.rdclass = rdata->rdclass;
278135446Strhodes	nsec->common.rdtype = rdata->type;
279135446Strhodes	ISC_LINK_INIT(&nsec->common, link);
280135446Strhodes
281135446Strhodes	dns_name_init(&name, NULL);
282135446Strhodes	dns_rdata_toregion(rdata, &region);
283135446Strhodes	dns_name_fromregion(&name, &region);
284135446Strhodes	isc_region_consume(&region, name_length(&name));
285135446Strhodes	dns_name_init(&nsec->next, NULL);
286135446Strhodes	RETERR(name_duporclone(&name, mctx, &nsec->next));
287135446Strhodes
288135446Strhodes	nsec->len = region.length;
289135446Strhodes	nsec->typebits = mem_maybedup(mctx, region.base, region.length);
290135446Strhodes	if (nsec->typebits == NULL)
291135446Strhodes		goto cleanup;
292135446Strhodes
293135446Strhodes	nsec->mctx = mctx;
294135446Strhodes	return (ISC_R_SUCCESS);
295135446Strhodes
296135446Strhodes cleanup:
297135446Strhodes	if (mctx != NULL)
298135446Strhodes		dns_name_free(&nsec->next, mctx);
299135446Strhodes	return (ISC_R_NOMEMORY);
300135446Strhodes}
301135446Strhodes
302135446Strhodesstatic inline void
303135446Strhodesfreestruct_nsec(ARGS_FREESTRUCT) {
304135446Strhodes	dns_rdata_nsec_t *nsec = source;
305135446Strhodes
306135446Strhodes	REQUIRE(source != NULL);
307135446Strhodes	REQUIRE(nsec->common.rdtype == 47);
308135446Strhodes
309135446Strhodes	if (nsec->mctx == NULL)
310135446Strhodes		return;
311135446Strhodes
312135446Strhodes	dns_name_free(&nsec->next, nsec->mctx);
313135446Strhodes	if (nsec->typebits != NULL)
314135446Strhodes		isc_mem_free(nsec->mctx, nsec->typebits);
315135446Strhodes	nsec->mctx = NULL;
316135446Strhodes}
317135446Strhodes
318135446Strhodesstatic inline isc_result_t
319135446Strhodesadditionaldata_nsec(ARGS_ADDLDATA) {
320135446Strhodes	REQUIRE(rdata->type == 47);
321135446Strhodes
322135446Strhodes	UNUSED(rdata);
323135446Strhodes	UNUSED(add);
324135446Strhodes	UNUSED(arg);
325135446Strhodes
326135446Strhodes	return (ISC_R_SUCCESS);
327135446Strhodes}
328135446Strhodes
329135446Strhodesstatic inline isc_result_t
330135446Strhodesdigest_nsec(ARGS_DIGEST) {
331135446Strhodes	isc_region_t r;
332135446Strhodes
333135446Strhodes	REQUIRE(rdata->type == 47);
334135446Strhodes
335135446Strhodes	dns_rdata_toregion(rdata, &r);
336135446Strhodes	return ((digest)(arg, &r));
337135446Strhodes}
338135446Strhodes
339135446Strhodesstatic inline isc_boolean_t
340135446Strhodescheckowner_nsec(ARGS_CHECKOWNER) {
341135446Strhodes
342135446Strhodes       REQUIRE(type == 47);
343135446Strhodes
344135446Strhodes       UNUSED(name);
345135446Strhodes       UNUSED(type);
346135446Strhodes       UNUSED(rdclass);
347135446Strhodes       UNUSED(wildcard);
348135446Strhodes
349135446Strhodes       return (ISC_TRUE);
350135446Strhodes}
351135446Strhodes
352135446Strhodesstatic inline isc_boolean_t
353135446Strhodeschecknames_nsec(ARGS_CHECKNAMES) {
354135446Strhodes
355135446Strhodes	REQUIRE(rdata->type == 47);
356135446Strhodes
357135446Strhodes	UNUSED(rdata);
358135446Strhodes	UNUSED(owner);
359135446Strhodes	UNUSED(bad);
360135446Strhodes
361135446Strhodes	return (ISC_TRUE);
362135446Strhodes}
363135446Strhodes
364224092Sdougbstatic inline int
365224092Sdougbcasecompare_nsec(ARGS_COMPARE) {
366224092Sdougb	isc_region_t region1;
367224092Sdougb	isc_region_t region2;
368224092Sdougb	dns_name_t name1;
369224092Sdougb	dns_name_t name2;
370224092Sdougb	int order;
371224092Sdougb
372224092Sdougb	REQUIRE(rdata1->type == rdata2->type);
373224092Sdougb	REQUIRE(rdata1->rdclass == rdata2->rdclass);
374224092Sdougb	REQUIRE(rdata1->type == 47);
375224092Sdougb	REQUIRE(rdata1->length != 0);
376224092Sdougb	REQUIRE(rdata2->length != 0);
377224092Sdougb
378224092Sdougb	dns_name_init(&name1, NULL);
379224092Sdougb	dns_name_init(&name2, NULL);
380224092Sdougb
381224092Sdougb	dns_rdata_toregion(rdata1, &region1);
382224092Sdougb	dns_rdata_toregion(rdata2, &region2);
383224092Sdougb
384224092Sdougb	dns_name_fromregion(&name1, &region1);
385224092Sdougb	dns_name_fromregion(&name2, &region2);
386224092Sdougb
387224092Sdougb	order = dns_name_rdatacompare(&name1, &name2);
388224092Sdougb	if (order != 0)
389224092Sdougb		return (order);
390224092Sdougb
391224092Sdougb	isc_region_consume(&region1, name_length(&name1));
392224092Sdougb	isc_region_consume(&region2, name_length(&name2));
393224092Sdougb
394224092Sdougb	return (isc_region_compare(&region1, &region2));
395224092Sdougb}
396135446Strhodes#endif	/* RDATA_GENERIC_NSEC_47_C */
397