xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/in_1/apl_42.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: apl_42.c,v 1.10 2025/01/26 16:25:34 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
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
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
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 
199 	isc_buffer_activeregion(source, &sr);
200 	isc_buffer_availableregion(target, &tr);
201 	if (sr.length > tr.length) {
202 		return ISC_R_NOSPACE;
203 	}
204 	sr2 = sr;
205 
206 	/* Zero or more items */
207 	while (sr.length > 0) {
208 		if (sr.length < 4) {
209 			return ISC_R_UNEXPECTEDEND;
210 		}
211 		afi = uint16_fromregion(&sr);
212 		isc_region_consume(&sr, 2);
213 		prefix = *sr.base;
214 		isc_region_consume(&sr, 1);
215 		len = (*sr.base & 0x7f);
216 		isc_region_consume(&sr, 1);
217 		if (len > sr.length) {
218 			return ISC_R_UNEXPECTEDEND;
219 		}
220 		switch (afi) {
221 		case 1:
222 			if (prefix > 32 || len > 4) {
223 				return ISC_R_RANGE;
224 			}
225 			break;
226 		case 2:
227 			if (prefix > 128 || len > 16) {
228 				return ISC_R_RANGE;
229 			}
230 		}
231 		if (len > 0 && sr.base[len - 1] == 0) {
232 			return DNS_R_FORMERR;
233 		}
234 		isc_region_consume(&sr, len);
235 	}
236 	isc_buffer_forward(source, sr2.length);
237 	return mem_tobuffer(target, sr2.base, sr2.length);
238 }
239 
240 static isc_result_t
241 towire_in_apl(ARGS_TOWIRE) {
242 	UNUSED(cctx);
243 
244 	REQUIRE(rdata->type == dns_rdatatype_apl);
245 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
246 
247 	return mem_tobuffer(target, rdata->data, rdata->length);
248 }
249 
250 static int
251 compare_in_apl(ARGS_COMPARE) {
252 	isc_region_t r1;
253 	isc_region_t r2;
254 
255 	REQUIRE(rdata1->type == rdata2->type);
256 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
257 	REQUIRE(rdata1->type == dns_rdatatype_apl);
258 	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
259 
260 	dns_rdata_toregion(rdata1, &r1);
261 	dns_rdata_toregion(rdata2, &r2);
262 	return isc_region_compare(&r1, &r2);
263 }
264 
265 static isc_result_t
266 fromstruct_in_apl(ARGS_FROMSTRUCT) {
267 	dns_rdata_in_apl_t *apl = source;
268 	isc_buffer_t b;
269 
270 	REQUIRE(type == dns_rdatatype_apl);
271 	REQUIRE(rdclass == dns_rdataclass_in);
272 	REQUIRE(apl != NULL);
273 	REQUIRE(apl->common.rdtype == type);
274 	REQUIRE(apl->common.rdclass == rdclass);
275 	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
276 
277 	isc_buffer_init(&b, apl->apl, apl->apl_len);
278 	isc_buffer_add(&b, apl->apl_len);
279 	isc_buffer_setactive(&b, apl->apl_len);
280 	return fromwire_in_apl(rdclass, type, &b, DNS_DECOMPRESS_DEFAULT,
281 			       target);
282 }
283 
284 static isc_result_t
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 	apl->offset = 0;
301 	apl->mctx = mctx;
302 	return ISC_R_SUCCESS;
303 }
304 
305 static void
306 freestruct_in_apl(ARGS_FREESTRUCT) {
307 	dns_rdata_in_apl_t *apl = source;
308 
309 	REQUIRE(apl != NULL);
310 	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
311 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
312 
313 	if (apl->mctx == NULL) {
314 		return;
315 	}
316 	if (apl->apl != NULL) {
317 		isc_mem_free(apl->mctx, apl->apl);
318 	}
319 	apl->mctx = NULL;
320 }
321 
322 isc_result_t
323 dns_rdata_apl_first(dns_rdata_in_apl_t *apl) {
324 	uint32_t length;
325 
326 	REQUIRE(apl != NULL);
327 	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
328 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
329 	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
330 
331 	/*
332 	 * If no APL return ISC_R_NOMORE.
333 	 */
334 	if (apl->apl == NULL) {
335 		return ISC_R_NOMORE;
336 	}
337 
338 	/*
339 	 * Sanity check data.
340 	 */
341 	INSIST(apl->apl_len > 3U);
342 	length = apl->apl[apl->offset + 3] & 0x7f;
343 	INSIST(4 + length <= apl->apl_len);
344 
345 	apl->offset = 0;
346 	return ISC_R_SUCCESS;
347 }
348 
349 isc_result_t
350 dns_rdata_apl_next(dns_rdata_in_apl_t *apl) {
351 	uint32_t length;
352 
353 	REQUIRE(apl != NULL);
354 	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
355 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
356 	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
357 
358 	/*
359 	 * No APL or have already reached the end return ISC_R_NOMORE.
360 	 */
361 	if (apl->apl == NULL || apl->offset == apl->apl_len) {
362 		return ISC_R_NOMORE;
363 	}
364 
365 	/*
366 	 * Sanity check data.
367 	 */
368 	INSIST(apl->offset < apl->apl_len);
369 	INSIST(apl->apl_len > 3U);
370 	INSIST(apl->offset <= apl->apl_len - 4U);
371 	length = apl->apl[apl->offset + 3] & 0x7f;
372 	/*
373 	 * 16 to 32 bits promotion as 'length' is 32 bits so there is
374 	 * no overflow problems.
375 	 */
376 	INSIST(4 + length + apl->offset <= apl->apl_len);
377 
378 	apl->offset += 4 + length;
379 	return (apl->offset < apl->apl_len) ? ISC_R_SUCCESS : ISC_R_NOMORE;
380 }
381 
382 isc_result_t
383 dns_rdata_apl_current(dns_rdata_in_apl_t *apl, dns_rdata_apl_ent_t *ent) {
384 	uint32_t length;
385 
386 	REQUIRE(apl != NULL);
387 	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
388 	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
389 	REQUIRE(ent != NULL);
390 	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
391 	REQUIRE(apl->offset <= apl->apl_len);
392 
393 	if (apl->offset == apl->apl_len) {
394 		return ISC_R_NOMORE;
395 	}
396 
397 	/*
398 	 * Sanity check data.
399 	 */
400 	INSIST(apl->apl_len > 3U);
401 	INSIST(apl->offset <= apl->apl_len - 4U);
402 	length = (apl->apl[apl->offset + 3] & 0x7f);
403 	/*
404 	 * 16 to 32 bits promotion as 'length' is 32 bits so there is
405 	 * no overflow problems.
406 	 */
407 	INSIST(4 + length + apl->offset <= apl->apl_len);
408 
409 	ent->family = (apl->apl[apl->offset] << 8) + apl->apl[apl->offset + 1];
410 	ent->prefix = apl->apl[apl->offset + 2];
411 	ent->length = length;
412 	ent->negative = (apl->apl[apl->offset + 3] & 0x80);
413 	if (ent->length != 0) {
414 		ent->data = &apl->apl[apl->offset + 4];
415 	} else {
416 		ent->data = NULL;
417 	}
418 	return ISC_R_SUCCESS;
419 }
420 
421 unsigned int
422 dns_rdata_apl_count(const dns_rdata_in_apl_t *apl) {
423 	return apl->apl_len;
424 }
425 
426 static isc_result_t
427 additionaldata_in_apl(ARGS_ADDLDATA) {
428 	REQUIRE(rdata->type == dns_rdatatype_apl);
429 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
430 
431 	UNUSED(rdata);
432 	UNUSED(owner);
433 	UNUSED(add);
434 	UNUSED(arg);
435 
436 	return ISC_R_SUCCESS;
437 }
438 
439 static isc_result_t
440 digest_in_apl(ARGS_DIGEST) {
441 	isc_region_t r;
442 
443 	REQUIRE(rdata->type == dns_rdatatype_apl);
444 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
445 
446 	dns_rdata_toregion(rdata, &r);
447 
448 	return (digest)(arg, &r);
449 }
450 
451 static bool
452 checkowner_in_apl(ARGS_CHECKOWNER) {
453 	REQUIRE(type == dns_rdatatype_apl);
454 	REQUIRE(rdclass == dns_rdataclass_in);
455 
456 	UNUSED(name);
457 	UNUSED(type);
458 	UNUSED(rdclass);
459 	UNUSED(wildcard);
460 
461 	return true;
462 }
463 
464 static bool
465 checknames_in_apl(ARGS_CHECKNAMES) {
466 	REQUIRE(rdata->type == dns_rdatatype_apl);
467 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
468 
469 	UNUSED(rdata);
470 	UNUSED(owner);
471 	UNUSED(bad);
472 
473 	return true;
474 }
475 
476 static int
477 casecompare_in_apl(ARGS_COMPARE) {
478 	return compare_in_apl(rdata1, rdata2);
479 }
480 
481 #endif /* RDATA_IN_1_APL_42_C */
482