xref: /netbsd/external/mpl/bind/dist/lib/dns/rdata/in_1/a6_38.c (revision c0b5d9fb)
1 /*	$NetBSD: a6_38.c,v 1.8 2022/09/23 12:15:31 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 /* RFC2874 */
17 
18 #ifndef RDATA_IN_1_A6_28_C
19 #define RDATA_IN_1_A6_28_C
20 
21 #include <isc/net.h>
22 
23 #define RRTYPE_A6_ATTRIBUTES (0)
24 
25 static isc_result_t
fromtext_in_a6(ARGS_FROMTEXT)26 fromtext_in_a6(ARGS_FROMTEXT) {
27 	isc_token_t token;
28 	unsigned char addr[16];
29 	unsigned char prefixlen;
30 	unsigned char octets;
31 	unsigned char mask;
32 	dns_name_t name;
33 	isc_buffer_t buffer;
34 	bool ok;
35 
36 	REQUIRE(type == dns_rdatatype_a6);
37 	REQUIRE(rdclass == dns_rdataclass_in);
38 
39 	UNUSED(type);
40 	UNUSED(rdclass);
41 	UNUSED(callbacks);
42 
43 	/*
44 	 * Prefix length.
45 	 */
46 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
47 				      false));
48 	if (token.value.as_ulong > 128U) {
49 		RETTOK(ISC_R_RANGE);
50 	}
51 
52 	prefixlen = (unsigned char)token.value.as_ulong;
53 	RETERR(mem_tobuffer(target, &prefixlen, 1));
54 
55 	/*
56 	 * Suffix.
57 	 */
58 	if (prefixlen != 128) {
59 		/*
60 		 * Prefix 0..127.
61 		 */
62 		octets = prefixlen / 8;
63 		/*
64 		 * Octets 0..15.
65 		 */
66 		RETERR(isc_lex_getmastertoken(lexer, &token,
67 					      isc_tokentype_string, false));
68 		if (inet_pton(AF_INET6, DNS_AS_STR(token), addr) != 1) {
69 			RETTOK(DNS_R_BADAAAA);
70 		}
71 		mask = 0xff >> (prefixlen % 8);
72 		addr[octets] &= mask;
73 		RETERR(mem_tobuffer(target, &addr[octets], 16 - octets));
74 	}
75 
76 	if (prefixlen == 0) {
77 		return (ISC_R_SUCCESS);
78 	}
79 
80 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
81 				      false));
82 	dns_name_init(&name, NULL);
83 	buffer_fromregion(&buffer, &token.value.as_region);
84 	if (origin == NULL) {
85 		origin = dns_rootname;
86 	}
87 	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
88 	ok = true;
89 	if ((options & DNS_RDATA_CHECKNAMES) != 0) {
90 		ok = dns_name_ishostname(&name, false);
91 	}
92 	if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) {
93 		RETTOK(DNS_R_BADNAME);
94 	}
95 	if (!ok && callbacks != NULL) {
96 		warn_badname(&name, lexer, callbacks);
97 	}
98 	return (ISC_R_SUCCESS);
99 }
100 
101 static isc_result_t
totext_in_a6(ARGS_TOTEXT)102 totext_in_a6(ARGS_TOTEXT) {
103 	isc_region_t sr, ar;
104 	unsigned char addr[16];
105 	unsigned char prefixlen;
106 	unsigned char octets;
107 	unsigned char mask;
108 	char buf[sizeof("128")];
109 	dns_name_t name;
110 	dns_name_t prefix;
111 	bool sub;
112 
113 	REQUIRE(rdata->type == dns_rdatatype_a6);
114 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
115 	REQUIRE(rdata->length != 0);
116 
117 	dns_rdata_toregion(rdata, &sr);
118 	prefixlen = sr.base[0];
119 	INSIST(prefixlen <= 128);
120 	isc_region_consume(&sr, 1);
121 	snprintf(buf, sizeof(buf), "%u", prefixlen);
122 	RETERR(str_totext(buf, target));
123 	RETERR(str_totext(" ", target));
124 
125 	if (prefixlen != 128) {
126 		octets = prefixlen / 8;
127 		memset(addr, 0, sizeof(addr));
128 		memmove(&addr[octets], sr.base, 16 - octets);
129 		mask = 0xff >> (prefixlen % 8);
130 		addr[octets] &= mask;
131 		ar.base = addr;
132 		ar.length = sizeof(addr);
133 		RETERR(inet_totext(AF_INET6, tctx->flags, &ar, target));
134 		isc_region_consume(&sr, 16 - octets);
135 	}
136 
137 	if (prefixlen == 0) {
138 		return (ISC_R_SUCCESS);
139 	}
140 
141 	RETERR(str_totext(" ", target));
142 	dns_name_init(&name, NULL);
143 	dns_name_init(&prefix, NULL);
144 	dns_name_fromregion(&name, &sr);
145 	sub = name_prefix(&name, tctx->origin, &prefix);
146 	return (dns_name_totext(&prefix, sub, target));
147 }
148 
149 static isc_result_t
fromwire_in_a6(ARGS_FROMWIRE)150 fromwire_in_a6(ARGS_FROMWIRE) {
151 	isc_region_t sr;
152 	unsigned char prefixlen;
153 	unsigned char octets;
154 	unsigned char mask;
155 	dns_name_t name;
156 
157 	REQUIRE(type == dns_rdatatype_a6);
158 	REQUIRE(rdclass == dns_rdataclass_in);
159 
160 	UNUSED(type);
161 	UNUSED(rdclass);
162 
163 	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
164 
165 	isc_buffer_activeregion(source, &sr);
166 	/*
167 	 * Prefix length.
168 	 */
169 	if (sr.length < 1) {
170 		return (ISC_R_UNEXPECTEDEND);
171 	}
172 	prefixlen = sr.base[0];
173 	if (prefixlen > 128) {
174 		return (ISC_R_RANGE);
175 	}
176 	isc_region_consume(&sr, 1);
177 	RETERR(mem_tobuffer(target, &prefixlen, 1));
178 	isc_buffer_forward(source, 1);
179 
180 	/*
181 	 * Suffix.
182 	 */
183 	if (prefixlen != 128) {
184 		octets = 16 - prefixlen / 8;
185 		if (sr.length < octets) {
186 			return (ISC_R_UNEXPECTEDEND);
187 		}
188 		mask = 0xff >> (prefixlen % 8);
189 		if ((sr.base[0] & ~mask) != 0) {
190 			return (DNS_R_FORMERR);
191 		}
192 		RETERR(mem_tobuffer(target, sr.base, octets));
193 		isc_buffer_forward(source, octets);
194 	}
195 
196 	if (prefixlen == 0) {
197 		return (ISC_R_SUCCESS);
198 	}
199 
200 	dns_name_init(&name, NULL);
201 	return (dns_name_fromwire(&name, source, dctx, options, target));
202 }
203 
204 static isc_result_t
towire_in_a6(ARGS_TOWIRE)205 towire_in_a6(ARGS_TOWIRE) {
206 	isc_region_t sr;
207 	dns_name_t name;
208 	dns_offsets_t offsets;
209 	unsigned char prefixlen;
210 	unsigned char octets;
211 
212 	REQUIRE(rdata->type == dns_rdatatype_a6);
213 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
214 	REQUIRE(rdata->length != 0);
215 
216 	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
217 	dns_rdata_toregion(rdata, &sr);
218 	prefixlen = sr.base[0];
219 	INSIST(prefixlen <= 128);
220 
221 	octets = 1 + 16 - prefixlen / 8;
222 	RETERR(mem_tobuffer(target, sr.base, octets));
223 	isc_region_consume(&sr, octets);
224 
225 	if (prefixlen == 0) {
226 		return (ISC_R_SUCCESS);
227 	}
228 
229 	dns_name_init(&name, offsets);
230 	dns_name_fromregion(&name, &sr);
231 	return (dns_name_towire(&name, cctx, target));
232 }
233 
234 static int
compare_in_a6(ARGS_COMPARE)235 compare_in_a6(ARGS_COMPARE) {
236 	int order;
237 	unsigned char prefixlen1, prefixlen2;
238 	unsigned char octets;
239 	dns_name_t name1;
240 	dns_name_t name2;
241 	isc_region_t region1;
242 	isc_region_t region2;
243 
244 	REQUIRE(rdata1->type == rdata2->type);
245 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
246 	REQUIRE(rdata1->type == dns_rdatatype_a6);
247 	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
248 	REQUIRE(rdata1->length != 0);
249 	REQUIRE(rdata2->length != 0);
250 
251 	dns_rdata_toregion(rdata1, &region1);
252 	dns_rdata_toregion(rdata2, &region2);
253 	prefixlen1 = region1.base[0];
254 	prefixlen2 = region2.base[0];
255 	isc_region_consume(&region1, 1);
256 	isc_region_consume(&region2, 1);
257 	if (prefixlen1 < prefixlen2) {
258 		return (-1);
259 	} else if (prefixlen1 > prefixlen2) {
260 		return (1);
261 	}
262 	/*
263 	 * Prefix lengths are equal.
264 	 */
265 	octets = 16 - prefixlen1 / 8;
266 
267 	if (octets > 0) {
268 		order = memcmp(region1.base, region2.base, octets);
269 		if (order < 0) {
270 			return (-1);
271 		} else if (order > 0) {
272 			return (1);
273 		}
274 		/*
275 		 * Address suffixes are equal.
276 		 */
277 		if (prefixlen1 == 0) {
278 			return (order);
279 		}
280 		isc_region_consume(&region1, octets);
281 		isc_region_consume(&region2, octets);
282 	}
283 
284 	dns_name_init(&name1, NULL);
285 	dns_name_init(&name2, NULL);
286 	dns_name_fromregion(&name1, &region1);
287 	dns_name_fromregion(&name2, &region2);
288 	return (dns_name_rdatacompare(&name1, &name2));
289 }
290 
291 static isc_result_t
fromstruct_in_a6(ARGS_FROMSTRUCT)292 fromstruct_in_a6(ARGS_FROMSTRUCT) {
293 	dns_rdata_in_a6_t *a6 = source;
294 	isc_region_t region;
295 	int octets;
296 	uint8_t bits;
297 	uint8_t first;
298 	uint8_t mask;
299 
300 	REQUIRE(type == dns_rdatatype_a6);
301 	REQUIRE(rdclass == dns_rdataclass_in);
302 	REQUIRE(a6 != NULL);
303 	REQUIRE(a6->common.rdtype == type);
304 	REQUIRE(a6->common.rdclass == rdclass);
305 
306 	UNUSED(type);
307 	UNUSED(rdclass);
308 
309 	if (a6->prefixlen > 128) {
310 		return (ISC_R_RANGE);
311 	}
312 
313 	RETERR(uint8_tobuffer(a6->prefixlen, target));
314 
315 	/* Suffix */
316 	if (a6->prefixlen != 128) {
317 		octets = 16 - a6->prefixlen / 8;
318 		bits = a6->prefixlen % 8;
319 		if (bits != 0) {
320 			mask = 0xffU >> bits;
321 			first = a6->in6_addr.s6_addr[16 - octets] & mask;
322 			RETERR(uint8_tobuffer(first, target));
323 			octets--;
324 		}
325 		if (octets > 0) {
326 			RETERR(mem_tobuffer(target,
327 					    a6->in6_addr.s6_addr + 16 - octets,
328 					    octets));
329 		}
330 	}
331 
332 	if (a6->prefixlen == 0) {
333 		return (ISC_R_SUCCESS);
334 	}
335 	dns_name_toregion(&a6->prefix, &region);
336 	return (isc_buffer_copyregion(target, &region));
337 }
338 
339 static isc_result_t
tostruct_in_a6(ARGS_TOSTRUCT)340 tostruct_in_a6(ARGS_TOSTRUCT) {
341 	dns_rdata_in_a6_t *a6 = target;
342 	unsigned char octets;
343 	dns_name_t name;
344 	isc_region_t r;
345 
346 	REQUIRE(rdata->type == dns_rdatatype_a6);
347 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
348 	REQUIRE(a6 != NULL);
349 	REQUIRE(rdata->length != 0);
350 
351 	a6->common.rdclass = rdata->rdclass;
352 	a6->common.rdtype = rdata->type;
353 	ISC_LINK_INIT(&a6->common, link);
354 
355 	dns_rdata_toregion(rdata, &r);
356 
357 	a6->prefixlen = uint8_fromregion(&r);
358 	isc_region_consume(&r, 1);
359 	memset(a6->in6_addr.s6_addr, 0, sizeof(a6->in6_addr.s6_addr));
360 
361 	/*
362 	 * Suffix.
363 	 */
364 	if (a6->prefixlen != 128) {
365 		octets = 16 - a6->prefixlen / 8;
366 		INSIST(r.length >= octets);
367 		memmove(a6->in6_addr.s6_addr + 16 - octets, r.base, octets);
368 		isc_region_consume(&r, octets);
369 	}
370 
371 	/*
372 	 * Prefix.
373 	 */
374 	dns_name_init(&a6->prefix, NULL);
375 	if (a6->prefixlen != 0) {
376 		dns_name_init(&name, NULL);
377 		dns_name_fromregion(&name, &r);
378 		RETERR(name_duporclone(&name, mctx, &a6->prefix));
379 	}
380 	a6->mctx = mctx;
381 	return (ISC_R_SUCCESS);
382 }
383 
384 static void
freestruct_in_a6(ARGS_FREESTRUCT)385 freestruct_in_a6(ARGS_FREESTRUCT) {
386 	dns_rdata_in_a6_t *a6 = source;
387 
388 	REQUIRE(a6 != NULL);
389 	REQUIRE(a6->common.rdclass == dns_rdataclass_in);
390 	REQUIRE(a6->common.rdtype == dns_rdatatype_a6);
391 
392 	if (a6->mctx == NULL) {
393 		return;
394 	}
395 
396 	if (dns_name_dynamic(&a6->prefix)) {
397 		dns_name_free(&a6->prefix, a6->mctx);
398 	}
399 	a6->mctx = NULL;
400 }
401 
402 static isc_result_t
additionaldata_in_a6(ARGS_ADDLDATA)403 additionaldata_in_a6(ARGS_ADDLDATA) {
404 	REQUIRE(rdata->type == dns_rdatatype_a6);
405 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
406 
407 	UNUSED(rdata);
408 	UNUSED(add);
409 	UNUSED(arg);
410 
411 	return (ISC_R_SUCCESS);
412 }
413 
414 static isc_result_t
digest_in_a6(ARGS_DIGEST)415 digest_in_a6(ARGS_DIGEST) {
416 	isc_region_t r1, r2;
417 	unsigned char prefixlen, octets;
418 	isc_result_t result;
419 	dns_name_t name;
420 
421 	REQUIRE(rdata->type == dns_rdatatype_a6);
422 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
423 
424 	dns_rdata_toregion(rdata, &r1);
425 	r2 = r1;
426 	prefixlen = r1.base[0];
427 	octets = 1 + 16 - prefixlen / 8;
428 
429 	r1.length = octets;
430 	result = (digest)(arg, &r1);
431 	if (result != ISC_R_SUCCESS) {
432 		return (result);
433 	}
434 	if (prefixlen == 0) {
435 		return (ISC_R_SUCCESS);
436 	}
437 
438 	isc_region_consume(&r2, octets);
439 	dns_name_init(&name, NULL);
440 	dns_name_fromregion(&name, &r2);
441 	return (dns_name_digest(&name, digest, arg));
442 }
443 
444 static bool
checkowner_in_a6(ARGS_CHECKOWNER)445 checkowner_in_a6(ARGS_CHECKOWNER) {
446 	REQUIRE(type == dns_rdatatype_a6);
447 	REQUIRE(rdclass == dns_rdataclass_in);
448 
449 	UNUSED(type);
450 	UNUSED(rdclass);
451 
452 	return (dns_name_ishostname(name, wildcard));
453 }
454 
455 static bool
checknames_in_a6(ARGS_CHECKNAMES)456 checknames_in_a6(ARGS_CHECKNAMES) {
457 	isc_region_t region;
458 	dns_name_t name;
459 	unsigned int prefixlen;
460 
461 	REQUIRE(rdata->type == dns_rdatatype_a6);
462 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
463 
464 	UNUSED(owner);
465 
466 	dns_rdata_toregion(rdata, &region);
467 	prefixlen = uint8_fromregion(&region);
468 	if (prefixlen == 0) {
469 		return (true);
470 	}
471 	isc_region_consume(&region, 1 + 16 - prefixlen / 8);
472 	dns_name_init(&name, NULL);
473 	dns_name_fromregion(&name, &region);
474 	if (!dns_name_ishostname(&name, false)) {
475 		if (bad != NULL) {
476 			dns_name_clone(&name, bad);
477 		}
478 		return (false);
479 	}
480 	return (true);
481 }
482 
483 static int
casecompare_in_a6(ARGS_COMPARE)484 casecompare_in_a6(ARGS_COMPARE) {
485 	return (compare_in_a6(rdata1, rdata2));
486 }
487 
488 #endif /* RDATA_IN_1_A6_38_C */
489