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