apl_42.c revision 294905
1/*
2 * Copyright (C) 2004, 2005, 2007-2009, 2014  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2002  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: apl_42.c,v 1.16 2009/12/04 22:06:37 tbox Exp $ */
19
20/* RFC3123 */
21
22#ifndef RDATA_IN_1_APL_42_C
23#define RDATA_IN_1_APL_42_C
24
25#define RRTYPE_APL_ATTRIBUTES (0)
26
27static inline isc_result_t
28fromtext_in_apl(ARGS_FROMTEXT) {
29	isc_token_t token;
30	unsigned char addr[16];
31	unsigned long afi;
32	isc_uint8_t prefix;
33	isc_uint8_t len;
34	isc_boolean_t neg;
35	char *cp, *ap, *slash;
36	int n;
37
38	REQUIRE(type == 42);
39	REQUIRE(rdclass == 1);
40
41	UNUSED(type);
42	UNUSED(rdclass);
43	UNUSED(origin);
44	UNUSED(options);
45	UNUSED(callbacks);
46
47	do {
48		RETERR(isc_lex_getmastertoken(lexer, &token,
49					      isc_tokentype_string, ISC_TRUE));
50		if (token.type != isc_tokentype_string)
51			break;
52
53		cp = DNS_AS_STR(token);
54		neg = ISC_TF(*cp == '!');
55		if (neg)
56			cp++;
57		afi = strtoul(cp, &ap, 10);
58		if (*ap++ != ':' || cp == ap)
59			RETTOK(DNS_R_SYNTAX);
60		if (afi > 0xffffU)
61			RETTOK(ISC_R_RANGE);
62		slash = strchr(ap, '/');
63		if (slash == NULL || slash == ap)
64			RETTOK(DNS_R_SYNTAX);
65		RETTOK(isc_parse_uint8(&prefix, slash + 1, 10));
66		switch (afi) {
67		case 1:
68			*slash = '\0';
69			n = inet_pton(AF_INET, ap, addr);
70			*slash = '/';
71			if (n != 1)
72				RETTOK(DNS_R_BADDOTTEDQUAD);
73			if (prefix > 32)
74				RETTOK(ISC_R_RANGE);
75			for (len = 4; len > 0; len--)
76				if (addr[len - 1] != 0)
77					break;
78			break;
79
80		case 2:
81			*slash = '\0';
82			n = inet_pton(AF_INET6, ap, addr);
83			*slash = '/';
84			if (n != 1)
85				RETTOK(DNS_R_BADAAAA);
86			if (prefix > 128)
87				RETTOK(ISC_R_RANGE);
88			for (len = 16; len > 0; len--)
89				if (addr[len - 1] != 0)
90					break;
91			break;
92
93		default:
94			RETTOK(ISC_R_NOTIMPLEMENTED);
95		}
96		RETERR(uint16_tobuffer(afi, target));
97		RETERR(uint8_tobuffer(prefix, target));
98		RETERR(uint8_tobuffer(len | ((neg) ? 0x80 : 0), target));
99		RETERR(mem_tobuffer(target, addr, len));
100	} while (1);
101
102	/*
103	 * Let upper layer handle eol/eof.
104	 */
105	isc_lex_ungettoken(lexer, &token);
106
107	return (ISC_R_SUCCESS);
108}
109
110static inline isc_result_t
111totext_in_apl(ARGS_TOTEXT) {
112	isc_region_t sr;
113	isc_region_t ir;
114	isc_uint16_t afi;
115	isc_uint8_t prefix;
116	isc_uint8_t len;
117	isc_boolean_t neg;
118	unsigned char buf[16];
119	char txt[sizeof(" !64000:")];
120	const char *sep = "";
121	int n;
122
123	REQUIRE(rdata->type == 42);
124	REQUIRE(rdata->rdclass == 1);
125
126	UNUSED(tctx);
127
128	dns_rdata_toregion(rdata, &sr);
129	ir.base = buf;
130	ir.length = sizeof(buf);
131
132	while (sr.length > 0) {
133		INSIST(sr.length >= 4);
134		afi = uint16_fromregion(&sr);
135		isc_region_consume(&sr, 2);
136		prefix = *sr.base;
137		isc_region_consume(&sr, 1);
138		len = (*sr.base & 0x7f);
139		neg = ISC_TF((*sr.base & 0x80) != 0);
140		isc_region_consume(&sr, 1);
141		INSIST(len <= sr.length);
142		n = snprintf(txt, sizeof(txt), "%s%s%u:", sep,
143			     neg ? "!" : "", afi);
144		INSIST(n < (int)sizeof(txt));
145		RETERR(str_totext(txt, target));
146		switch (afi) {
147		case 1:
148			INSIST(len <= 4);
149			INSIST(prefix <= 32);
150			memset(buf, 0, sizeof(buf));
151			memmove(buf, sr.base, len);
152			RETERR(inet_totext(AF_INET, &ir, target));
153			break;
154
155		case 2:
156			INSIST(len <= 16);
157			INSIST(prefix <= 128);
158			memset(buf, 0, sizeof(buf));
159			memmove(buf, sr.base, len);
160			RETERR(inet_totext(AF_INET6, &ir, target));
161			break;
162
163		default:
164			return (ISC_R_NOTIMPLEMENTED);
165		}
166		n = snprintf(txt, sizeof(txt), "/%u", prefix);
167		INSIST(n < (int)sizeof(txt));
168		RETERR(str_totext(txt, target));
169		isc_region_consume(&sr, len);
170		sep = " ";
171	}
172	return (ISC_R_SUCCESS);
173}
174
175static inline isc_result_t
176fromwire_in_apl(ARGS_FROMWIRE) {
177	isc_region_t sr, sr2;
178	isc_region_t tr;
179	isc_uint16_t afi;
180	isc_uint8_t prefix;
181	isc_uint8_t len;
182
183	REQUIRE(type == 42);
184	REQUIRE(rdclass == 1);
185
186	UNUSED(type);
187	UNUSED(dctx);
188	UNUSED(rdclass);
189	UNUSED(options);
190
191	isc_buffer_activeregion(source, &sr);
192	isc_buffer_availableregion(target, &tr);
193	if (sr.length > tr.length)
194		return (ISC_R_NOSPACE);
195	sr2 = sr;
196
197	/* Zero or more items */
198	while (sr.length > 0) {
199		if (sr.length < 4)
200			return (ISC_R_UNEXPECTEDEND);
201		afi = uint16_fromregion(&sr);
202		isc_region_consume(&sr, 2);
203		prefix = *sr.base;
204		isc_region_consume(&sr, 1);
205		len = (*sr.base & 0x7f);
206		isc_region_consume(&sr, 1);
207		if (len > sr.length)
208			return (ISC_R_UNEXPECTEDEND);
209		switch (afi) {
210		case 1:
211			if (prefix > 32 || len > 4)
212				return (ISC_R_RANGE);
213			break;
214		case 2:
215			if (prefix > 128 || len > 16)
216				return (ISC_R_RANGE);
217		}
218		if (len > 0 && sr.base[len - 1] == 0)
219			return (DNS_R_FORMERR);
220		isc_region_consume(&sr, len);
221	}
222	isc_buffer_forward(source, sr2.length);
223	return (mem_tobuffer(target, sr2.base, sr2.length));
224}
225
226static inline isc_result_t
227towire_in_apl(ARGS_TOWIRE) {
228	UNUSED(cctx);
229
230	REQUIRE(rdata->type == 42);
231	REQUIRE(rdata->rdclass == 1);
232
233	return (mem_tobuffer(target, rdata->data, rdata->length));
234}
235
236static inline int
237compare_in_apl(ARGS_COMPARE) {
238	isc_region_t r1;
239	isc_region_t r2;
240
241	REQUIRE(rdata1->type == rdata2->type);
242	REQUIRE(rdata1->rdclass == rdata2->rdclass);
243	REQUIRE(rdata1->type == 42);
244	REQUIRE(rdata1->rdclass == 1);
245
246	dns_rdata_toregion(rdata1, &r1);
247	dns_rdata_toregion(rdata2, &r2);
248	return (isc_region_compare(&r1, &r2));
249}
250
251static inline isc_result_t
252fromstruct_in_apl(ARGS_FROMSTRUCT) {
253	dns_rdata_in_apl_t *apl = source;
254	isc_buffer_t b;
255
256	REQUIRE(type == 42);
257	REQUIRE(rdclass == 1);
258	REQUIRE(source != NULL);
259	REQUIRE(apl->common.rdtype == type);
260	REQUIRE(apl->common.rdclass == rdclass);
261	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
262
263	isc_buffer_init(&b, apl->apl, apl->apl_len);
264	isc_buffer_add(&b, apl->apl_len);
265	isc_buffer_setactive(&b, apl->apl_len);
266	return(fromwire_in_apl(rdclass, type, &b, NULL, ISC_FALSE, target));
267}
268
269static inline isc_result_t
270tostruct_in_apl(ARGS_TOSTRUCT) {
271	dns_rdata_in_apl_t *apl = target;
272	isc_region_t r;
273
274	REQUIRE(rdata->type == 42);
275	REQUIRE(rdata->rdclass == 1);
276
277	apl->common.rdclass = rdata->rdclass;
278	apl->common.rdtype = rdata->type;
279	ISC_LINK_INIT(&apl->common, link);
280
281	dns_rdata_toregion(rdata, &r);
282	apl->apl_len = r.length;
283	apl->apl = mem_maybedup(mctx, r.base, r.length);
284	if (apl->apl == NULL)
285		return (ISC_R_NOMEMORY);
286
287	apl->offset = 0;
288	apl->mctx = mctx;
289	return (ISC_R_SUCCESS);
290}
291
292static inline void
293freestruct_in_apl(ARGS_FREESTRUCT) {
294	dns_rdata_in_apl_t *apl = source;
295
296	REQUIRE(source != NULL);
297	REQUIRE(apl->common.rdtype == 42);
298	REQUIRE(apl->common.rdclass == 1);
299
300	if (apl->mctx == NULL)
301		return;
302	if (apl->apl != NULL)
303		isc_mem_free(apl->mctx, apl->apl);
304	apl->mctx = NULL;
305}
306
307isc_result_t
308dns_rdata_apl_first(dns_rdata_in_apl_t *apl) {
309	isc_uint32_t length;
310
311	REQUIRE(apl != NULL);
312	REQUIRE(apl->common.rdtype == 42);
313	REQUIRE(apl->common.rdclass == 1);
314	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
315
316	/*
317	 * If no APL return ISC_R_NOMORE.
318	 */
319	if (apl->apl == NULL)
320		return (ISC_R_NOMORE);
321
322	/*
323	 * Sanity check data.
324	 */
325	INSIST(apl->apl_len > 3U);
326	length = apl->apl[apl->offset + 3] & 0x7f;
327	INSIST(length <= apl->apl_len);
328
329	apl->offset = 0;
330	return (ISC_R_SUCCESS);
331}
332
333isc_result_t
334dns_rdata_apl_next(dns_rdata_in_apl_t *apl) {
335	isc_uint32_t length;
336
337	REQUIRE(apl != NULL);
338	REQUIRE(apl->common.rdtype == 42);
339	REQUIRE(apl->common.rdclass == 1);
340	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
341
342	/*
343	 * No APL or have already reached the end return ISC_R_NOMORE.
344	 */
345	if (apl->apl == NULL || apl->offset == apl->apl_len)
346		return (ISC_R_NOMORE);
347
348	/*
349	 * Sanity check data.
350	 */
351	INSIST(apl->offset < apl->apl_len);
352	INSIST(apl->apl_len > 3U);
353	INSIST(apl->offset <= apl->apl_len - 4U);
354	length = apl->apl[apl->offset + 3] & 0x7f;
355	/*
356	 * 16 to 32 bits promotion as 'length' is 32 bits so there is
357	 * no overflow problems.
358	 */
359	INSIST(length + apl->offset <= apl->apl_len);
360
361	apl->offset += apl->apl[apl->offset + 3] & 0x7f;
362	return ((apl->offset >= apl->apl_len) ? ISC_R_SUCCESS : ISC_R_NOMORE);
363}
364
365isc_result_t
366dns_rdata_apl_current(dns_rdata_in_apl_t *apl, dns_rdata_apl_ent_t *ent) {
367	isc_uint32_t length;
368
369	REQUIRE(apl != NULL);
370	REQUIRE(apl->common.rdtype == 42);
371	REQUIRE(apl->common.rdclass == 1);
372	REQUIRE(ent != NULL);
373	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
374	REQUIRE(apl->offset <= apl->apl_len);
375
376	if (apl->offset == apl->apl_len)
377		return (ISC_R_NOMORE);
378
379	/*
380	 * Sanity check data.
381	 */
382	INSIST(apl->apl_len > 3U);
383	INSIST(apl->offset <= apl->apl_len - 4U);
384	length = apl->apl[apl->offset + 3] & 0x7f;
385	/*
386	 * 16 to 32 bits promotion as 'length' is 32 bits so there is
387	 * no overflow problems.
388	 */
389	INSIST(length + apl->offset <= apl->apl_len);
390
391	ent->family = (apl->apl[apl->offset] << 8) + apl->apl[apl->offset + 1];
392	ent->prefix = apl->apl[apl->offset + 2];
393	ent->length = apl->apl[apl->offset + 3] & 0x7f;
394	ent->negative = ISC_TF((apl->apl[apl->offset + 3] & 0x80) != 0);
395	if (ent->length != 0)
396		ent->data = &apl->apl[apl->offset + 4];
397	else
398		ent->data = NULL;
399	return (ISC_R_SUCCESS);
400}
401
402static inline isc_result_t
403additionaldata_in_apl(ARGS_ADDLDATA) {
404	REQUIRE(rdata->type == 42);
405	REQUIRE(rdata->rdclass == 1);
406
407	(void)add;
408	(void)arg;
409
410	return (ISC_R_SUCCESS);
411}
412
413static inline isc_result_t
414digest_in_apl(ARGS_DIGEST) {
415	isc_region_t r;
416
417	REQUIRE(rdata->type == 42);
418	REQUIRE(rdata->rdclass == 1);
419
420	dns_rdata_toregion(rdata, &r);
421
422	return ((digest)(arg, &r));
423}
424
425static inline isc_boolean_t
426checkowner_in_apl(ARGS_CHECKOWNER) {
427
428	REQUIRE(type == 42);
429	REQUIRE(rdclass == 1);
430
431	UNUSED(name);
432	UNUSED(type);
433	UNUSED(rdclass);
434	UNUSED(wildcard);
435
436	return (ISC_TRUE);
437}
438
439
440static inline isc_boolean_t
441checknames_in_apl(ARGS_CHECKNAMES) {
442
443	REQUIRE(rdata->type == 42);
444	REQUIRE(rdata->rdclass == 1);
445
446	UNUSED(rdata);
447	UNUSED(owner);
448	UNUSED(bad);
449
450	return (ISC_TRUE);
451}
452
453static inline int
454casecompare_in_apl(ARGS_COMPARE) {
455	return (compare_in_apl(rdata1, rdata2));
456}
457
458#endif	/* RDATA_IN_1_APL_42_C */
459