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