1 /*
2  * Copyright (C) 2004, 2005, 2007-2009, 2014, 2015  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 
27 static inline isc_result_t
fromtext_in_apl(ARGS_FROMTEXT)28 fromtext_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 == dns_rdatatype_apl);
39 	REQUIRE(rdclass == dns_rdataclass_in);
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 
110 static inline isc_result_t
totext_in_apl(ARGS_TOTEXT)111 totext_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 == dns_rdatatype_apl);
124 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
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 
175 static inline isc_result_t
fromwire_in_apl(ARGS_FROMWIRE)176 fromwire_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 == dns_rdatatype_apl);
184 	REQUIRE(rdclass == dns_rdataclass_in);
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 
226 static inline isc_result_t
towire_in_apl(ARGS_TOWIRE)227 towire_in_apl(ARGS_TOWIRE) {
228 	UNUSED(cctx);
229 
230 	REQUIRE(rdata->type == dns_rdatatype_apl);
231 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
232 
233 	return (mem_tobuffer(target, rdata->data, rdata->length));
234 }
235 
236 static inline int
compare_in_apl(ARGS_COMPARE)237 compare_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 == dns_rdatatype_apl);
244 	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
245 
246 	dns_rdata_toregion(rdata1, &r1);
247 	dns_rdata_toregion(rdata2, &r2);
248 	return (isc_region_compare(&r1, &r2));
249 }
250 
251 static inline isc_result_t
fromstruct_in_apl(ARGS_FROMSTRUCT)252 fromstruct_in_apl(ARGS_FROMSTRUCT) {
253 	dns_rdata_in_apl_t *apl = source;
254 	isc_buffer_t b;
255 
256 	REQUIRE(type == dns_rdatatype_apl);
257 	REQUIRE(rdclass == dns_rdataclass_in);
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 
269 static inline isc_result_t
tostruct_in_apl(ARGS_TOSTRUCT)270 tostruct_in_apl(ARGS_TOSTRUCT) {
271 	dns_rdata_in_apl_t *apl = target;
272 	isc_region_t r;
273 
274 	REQUIRE(rdata->type == dns_rdatatype_apl);
275 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
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 
292 static inline void
freestruct_in_apl(ARGS_FREESTRUCT)293 freestruct_in_apl(ARGS_FREESTRUCT) {
294 	dns_rdata_in_apl_t *apl = source;
295 
296 	REQUIRE(source != NULL);
297 	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
298 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
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 
307 isc_result_t
dns_rdata_apl_first(dns_rdata_in_apl_t * apl)308 dns_rdata_apl_first(dns_rdata_in_apl_t *apl) {
309 	isc_uint32_t length;
310 
311 	REQUIRE(apl != NULL);
312 	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
313 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
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 
333 isc_result_t
dns_rdata_apl_next(dns_rdata_in_apl_t * apl)334 dns_rdata_apl_next(dns_rdata_in_apl_t *apl) {
335 	isc_uint32_t length;
336 
337 	REQUIRE(apl != NULL);
338 	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
339 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
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 
365 isc_result_t
dns_rdata_apl_current(dns_rdata_in_apl_t * apl,dns_rdata_apl_ent_t * ent)366 dns_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 == dns_rdatatype_apl);
371 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
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 
402 static inline isc_result_t
additionaldata_in_apl(ARGS_ADDLDATA)403 additionaldata_in_apl(ARGS_ADDLDATA) {
404 	REQUIRE(rdata->type == dns_rdatatype_apl);
405 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
406 
407 	(void)add;
408 	(void)arg;
409 
410 	return (ISC_R_SUCCESS);
411 }
412 
413 static inline isc_result_t
digest_in_apl(ARGS_DIGEST)414 digest_in_apl(ARGS_DIGEST) {
415 	isc_region_t r;
416 
417 	REQUIRE(rdata->type == dns_rdatatype_apl);
418 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
419 
420 	dns_rdata_toregion(rdata, &r);
421 
422 	return ((digest)(arg, &r));
423 }
424 
425 static inline isc_boolean_t
checkowner_in_apl(ARGS_CHECKOWNER)426 checkowner_in_apl(ARGS_CHECKOWNER) {
427 
428 	REQUIRE(type == dns_rdatatype_apl);
429 	REQUIRE(rdclass == dns_rdataclass_in);
430 
431 	UNUSED(name);
432 	UNUSED(type);
433 	UNUSED(rdclass);
434 	UNUSED(wildcard);
435 
436 	return (ISC_TRUE);
437 }
438 
439 
440 static inline isc_boolean_t
checknames_in_apl(ARGS_CHECKNAMES)441 checknames_in_apl(ARGS_CHECKNAMES) {
442 
443 	REQUIRE(rdata->type == dns_rdatatype_apl);
444 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
445 
446 	UNUSED(rdata);
447 	UNUSED(owner);
448 	UNUSED(bad);
449 
450 	return (ISC_TRUE);
451 }
452 
453 static inline int
casecompare_in_apl(ARGS_COMPARE)454 casecompare_in_apl(ARGS_COMPARE) {
455 	return (compare_in_apl(rdata1, rdata2));
456 }
457 
458 #endif	/* RDATA_IN_1_APL_42_C */
459