1/*
2 * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-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: nxt_30.c,v 1.65 2009/12/04 22:06:37 tbox Exp $ */
19
20/* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */
21
22/* RFC2535 */
23
24#ifndef RDATA_GENERIC_NXT_30_C
25#define RDATA_GENERIC_NXT_30_C
26
27/*
28 * The attributes do not include DNS_RDATATYPEATTR_SINGLETON
29 * because we must be able to handle a parent/child NXT pair.
30 */
31#define RRTYPE_NXT_ATTRIBUTES (0)
32
33static inline isc_result_t
34fromtext_nxt(ARGS_FROMTEXT) {
35	isc_token_t token;
36	dns_name_t name;
37	isc_buffer_t buffer;
38	char *e;
39	unsigned char bm[8*1024]; /* 64k bits */
40	dns_rdatatype_t covered;
41	dns_rdatatype_t maxcovered = 0;
42	isc_boolean_t first = ISC_TRUE;
43	long n;
44
45	REQUIRE(type == 30);
46
47	UNUSED(type);
48	UNUSED(rdclass);
49	UNUSED(callbacks);
50
51	/*
52	 * Next domain.
53	 */
54	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
55				      ISC_FALSE));
56	dns_name_init(&name, NULL);
57	buffer_fromregion(&buffer, &token.value.as_region);
58	origin = (origin != NULL) ? origin : dns_rootname;
59	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
60
61	memset(bm, 0, sizeof(bm));
62	do {
63		RETERR(isc_lex_getmastertoken(lexer, &token,
64					      isc_tokentype_string, ISC_TRUE));
65		if (token.type != isc_tokentype_string)
66			break;
67		n = strtol(DNS_AS_STR(token), &e, 10);
68		if (e != DNS_AS_STR(token) && *e == '\0') {
69			covered = (dns_rdatatype_t)n;
70		} else if (dns_rdatatype_fromtext(&covered,
71				&token.value.as_textregion) == DNS_R_UNKNOWN)
72			RETTOK(DNS_R_UNKNOWN);
73		/*
74		 * NXT is only specified for types 1..127.
75		 */
76		if (covered < 1 || covered > 127)
77			return (ISC_R_RANGE);
78		if (first || covered > maxcovered)
79			maxcovered = covered;
80		first = ISC_FALSE;
81		bm[covered/8] |= (0x80>>(covered%8));
82	} while (1);
83	isc_lex_ungettoken(lexer, &token);
84	if (first)
85		return (ISC_R_SUCCESS);
86	n = (maxcovered + 8) / 8;
87	return (mem_tobuffer(target, bm, n));
88}
89
90static inline isc_result_t
91totext_nxt(ARGS_TOTEXT) {
92	isc_region_t sr;
93	unsigned int i, j;
94	dns_name_t name;
95	dns_name_t prefix;
96	isc_boolean_t sub;
97
98	REQUIRE(rdata->type == 30);
99	REQUIRE(rdata->length != 0);
100
101	dns_name_init(&name, NULL);
102	dns_name_init(&prefix, NULL);
103	dns_rdata_toregion(rdata, &sr);
104	dns_name_fromregion(&name, &sr);
105	isc_region_consume(&sr, name_length(&name));
106	sub = name_prefix(&name, tctx->origin, &prefix);
107	RETERR(dns_name_totext(&prefix, sub, target));
108
109	for (i = 0; i < sr.length; i++) {
110		if (sr.base[i] != 0)
111			for (j = 0; j < 8; j++)
112				if ((sr.base[i] & (0x80 >> j)) != 0) {
113					dns_rdatatype_t t = i * 8 + j;
114					RETERR(str_totext(" ", target));
115					if (dns_rdatatype_isknown(t)) {
116						RETERR(dns_rdatatype_totext(t,
117								      target));
118					} else {
119						char buf[sizeof("65535")];
120						sprintf(buf, "%u", t);
121						RETERR(str_totext(buf,
122								  target));
123					}
124				}
125	}
126	return (ISC_R_SUCCESS);
127}
128
129static inline isc_result_t
130fromwire_nxt(ARGS_FROMWIRE) {
131	isc_region_t sr;
132	dns_name_t name;
133
134	REQUIRE(type == 30);
135
136	UNUSED(type);
137	UNUSED(rdclass);
138
139	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
140
141	dns_name_init(&name, NULL);
142	RETERR(dns_name_fromwire(&name, source, dctx, options, target));
143
144	isc_buffer_activeregion(source, &sr);
145	if (sr.length > 0 && (sr.base[0] & 0x80) == 0 &&
146	    ((sr.length > 16) || sr.base[sr.length - 1] == 0))
147		return (DNS_R_BADBITMAP);
148	RETERR(mem_tobuffer(target, sr.base, sr.length));
149	isc_buffer_forward(source, sr.length);
150	return (ISC_R_SUCCESS);
151}
152
153static inline isc_result_t
154towire_nxt(ARGS_TOWIRE) {
155	isc_region_t sr;
156	dns_name_t name;
157	dns_offsets_t offsets;
158
159	REQUIRE(rdata->type == 30);
160	REQUIRE(rdata->length != 0);
161
162	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
163	dns_name_init(&name, offsets);
164	dns_rdata_toregion(rdata, &sr);
165	dns_name_fromregion(&name, &sr);
166	isc_region_consume(&sr, name_length(&name));
167	RETERR(dns_name_towire(&name, cctx, target));
168
169	return (mem_tobuffer(target, sr.base, sr.length));
170}
171
172static inline int
173compare_nxt(ARGS_COMPARE) {
174	isc_region_t r1;
175	isc_region_t r2;
176	dns_name_t name1;
177	dns_name_t name2;
178	int order;
179
180	REQUIRE(rdata1->type == rdata2->type);
181	REQUIRE(rdata1->rdclass == rdata2->rdclass);
182	REQUIRE(rdata1->type == 30);
183	REQUIRE(rdata1->length != 0);
184	REQUIRE(rdata2->length != 0);
185
186	dns_name_init(&name1, NULL);
187	dns_name_init(&name2, NULL);
188	dns_rdata_toregion(rdata1, &r1);
189	dns_rdata_toregion(rdata2, &r2);
190	dns_name_fromregion(&name1, &r1);
191	dns_name_fromregion(&name2, &r2);
192	order = dns_name_rdatacompare(&name1, &name2);
193	if (order != 0)
194		return (order);
195
196	return (isc_region_compare(&r1, &r2));
197}
198
199static inline isc_result_t
200fromstruct_nxt(ARGS_FROMSTRUCT) {
201	dns_rdata_nxt_t *nxt = source;
202	isc_region_t region;
203
204	REQUIRE(type == 30);
205	REQUIRE(source != NULL);
206	REQUIRE(nxt->common.rdtype == type);
207	REQUIRE(nxt->common.rdclass == rdclass);
208	REQUIRE(nxt->typebits != NULL || nxt->len == 0);
209	if (nxt->typebits != NULL && (nxt->typebits[0] & 0x80) == 0) {
210		REQUIRE(nxt->len <= 16);
211		REQUIRE(nxt->typebits[nxt->len - 1] != 0);
212	}
213
214	UNUSED(type);
215	UNUSED(rdclass);
216
217	dns_name_toregion(&nxt->next, &region);
218	RETERR(isc_buffer_copyregion(target, &region));
219
220	return (mem_tobuffer(target, nxt->typebits, nxt->len));
221}
222
223static inline isc_result_t
224tostruct_nxt(ARGS_TOSTRUCT) {
225	isc_region_t region;
226	dns_rdata_nxt_t *nxt = target;
227	dns_name_t name;
228
229	REQUIRE(rdata->type == 30);
230	REQUIRE(target != NULL);
231	REQUIRE(rdata->length != 0);
232
233	nxt->common.rdclass = rdata->rdclass;
234	nxt->common.rdtype = rdata->type;
235	ISC_LINK_INIT(&nxt->common, link);
236
237	dns_name_init(&name, NULL);
238	dns_rdata_toregion(rdata, &region);
239	dns_name_fromregion(&name, &region);
240	isc_region_consume(&region, name_length(&name));
241	dns_name_init(&nxt->next, NULL);
242	RETERR(name_duporclone(&name, mctx, &nxt->next));
243
244	nxt->len = region.length;
245	nxt->typebits = mem_maybedup(mctx, region.base, region.length);
246	if (nxt->typebits == NULL)
247		goto cleanup;
248
249	nxt->mctx = mctx;
250	return (ISC_R_SUCCESS);
251
252 cleanup:
253	if (mctx != NULL)
254		dns_name_free(&nxt->next, mctx);
255	return (ISC_R_NOMEMORY);
256}
257
258static inline void
259freestruct_nxt(ARGS_FREESTRUCT) {
260	dns_rdata_nxt_t *nxt = source;
261
262	REQUIRE(source != NULL);
263	REQUIRE(nxt->common.rdtype == 30);
264
265	if (nxt->mctx == NULL)
266		return;
267
268	dns_name_free(&nxt->next, nxt->mctx);
269	if (nxt->typebits != NULL)
270		isc_mem_free(nxt->mctx, nxt->typebits);
271	nxt->mctx = NULL;
272}
273
274static inline isc_result_t
275additionaldata_nxt(ARGS_ADDLDATA) {
276	REQUIRE(rdata->type == 30);
277
278	UNUSED(rdata);
279	UNUSED(add);
280	UNUSED(arg);
281
282	return (ISC_R_SUCCESS);
283}
284
285static inline isc_result_t
286digest_nxt(ARGS_DIGEST) {
287	isc_region_t r;
288	dns_name_t name;
289	isc_result_t result;
290
291	REQUIRE(rdata->type == 30);
292
293	dns_rdata_toregion(rdata, &r);
294	dns_name_init(&name, NULL);
295	dns_name_fromregion(&name, &r);
296	result = dns_name_digest(&name, digest, arg);
297	if (result != ISC_R_SUCCESS)
298		return (result);
299	isc_region_consume(&r, name_length(&name));
300
301	return ((digest)(arg, &r));
302}
303
304static inline isc_boolean_t
305checkowner_nxt(ARGS_CHECKOWNER) {
306
307	REQUIRE(type == 30);
308
309	UNUSED(name);
310	UNUSED(type);
311	UNUSED(rdclass);
312	UNUSED(wildcard);
313
314	return (ISC_TRUE);
315}
316
317static inline isc_boolean_t
318checknames_nxt(ARGS_CHECKNAMES) {
319
320	REQUIRE(rdata->type == 30);
321
322	UNUSED(rdata);
323	UNUSED(owner);
324	UNUSED(bad);
325
326	return (ISC_TRUE);
327}
328
329static inline int
330casecompare_nxt(ARGS_COMPARE) {
331	return (compare_nxt(rdata1, rdata2));
332}
333#endif	/* RDATA_GENERIC_NXT_30_C */
334